├── Hartree_Fock_Program.ipynb ├── LICENSE └── README.md /Hartree_Fock_Program.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 31, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys\n", 10 | "import math\n", 11 | "import numpy as np\n", 12 | "from scipy import special\n", 13 | "from scipy import linalg" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 32, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "class primitive_gaussian():\n", 23 | "\n", 24 | " def __init__(self, alpha, coeff, coordinates, l1, l2, l3):\n", 25 | " \n", 26 | " self.alpha = alpha\n", 27 | " self.coeff = coeff\n", 28 | " self.coordinates = np.array(coordinates)\n", 29 | " self.A = ( 2.0 * alpha / math.pi ) ** 0.75 # + other terms for l1, l2, l3 > 0\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 33, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "def overlap(molecule):\n", 39 | " \n", 40 | " nbasis = len(molecule)\n", 41 | " \n", 42 | " S = np.zeros([nbasis, nbasis])\n", 43 | " \n", 44 | " for i in range(nbasis):\n", 45 | " for j in range(nbasis):\n", 46 | " \n", 47 | " nprimitives_i = len(molecule[i])\n", 48 | " nprimitives_j = len(molecule[j])\n", 49 | " \n", 50 | " for k in range(nprimitives_i):\n", 51 | " for l in range(nprimitives_j):\n", 52 | " \n", 53 | " N = molecule[i][k].A * molecule[j][l].A\n", 54 | " p = molecule[i][k].alpha + molecule[j][l].alpha\n", 55 | " q = molecule[i][k].alpha * molecule[j][l].alpha / p\n", 56 | " Q = molecule[i][k].coordinates - molecule[j][l].coordinates\n", 57 | " Q2 = np.dot(Q,Q)\n", 58 | " \n", 59 | " S[i,j] += N * molecule[i][k].coeff * molecule[j][l].coeff * math.exp(-q*Q2) * (math.pi/p)**(3/2) \n", 60 | " \n", 61 | " return S\n", 62 | " " 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 34, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "def kinetic(molecule):\n", 72 | " \n", 73 | " nbasis = len(molecule)\n", 74 | " \n", 75 | " T = np.zeros([nbasis, nbasis])\n", 76 | " \n", 77 | " for i in range(nbasis):\n", 78 | " for j in range(nbasis):\n", 79 | "\n", 80 | " nprimitives_i = len(molecule[i])\n", 81 | " nprimitives_j = len(molecule[j])\n", 82 | " \n", 83 | " for k in range(nprimitives_i):\n", 84 | " for l in range(nprimitives_j):\n", 85 | "\n", 86 | " N = molecule[i][k].A * molecule[j][l].A\n", 87 | " cacb = molecule[i][k].coeff * molecule[j][l].coeff\n", 88 | " \n", 89 | " p = molecule[i][k].alpha + molecule[j][l].alpha\n", 90 | " P = molecule[i][k].alpha*molecule[i][k].coordinates + molecule[j][l].alpha*molecule[j][l].coordinates\n", 91 | " Pp = P/p\n", 92 | " PG = Pp - molecule[j][l].coordinates\n", 93 | " PGx2 = PG[0]*PG[0]\n", 94 | " PGy2 = PG[1]*PG[1]\n", 95 | " PGz2 = PG[2]*PG[2]\n", 96 | "\n", 97 | " q = molecule[i][k].alpha * molecule[j][l].alpha / p\n", 98 | " Q = molecule[i][k].coordinates - molecule[j][l].coordinates\n", 99 | " Q2 = np.dot(Q,Q)\n", 100 | " \n", 101 | " s = math.exp(-q*Q2) * (math.pi/p)**(3/2) * N * cacb\n", 102 | " \n", 103 | " T[i,j] += 3.0 * molecule[j][l].alpha * s\n", 104 | " T[i,j] -= 2.0 * molecule[j][l].alpha * molecule[j][l].alpha * s * (PGx2 + 0.5/p)\n", 105 | " T[i,j] -= 2.0 * molecule[j][l].alpha * molecule[j][l].alpha * s * (PGy2 + 0.5/p)\n", 106 | " T[i,j] -= 2.0 * molecule[j][l].alpha * molecule[j][l].alpha * s * (PGz2 + 0.5/p)\n", 107 | "\n", 108 | " return T \n", 109 | " \n", 110 | " " 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 35, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "def boys(x,n):\n", 120 | " if x == 0:\n", 121 | " return 1.0/(2*n+1)\n", 122 | " else:\n", 123 | " return special.gammainc(n+0.5,x) * special.gamma(n+0.5) * (1.0/(2*x**(n+0.5)))\n", 124 | " \n", 125 | "\n", 126 | "def electron_nuclear_attraction(molecule, Z):\n", 127 | " \n", 128 | " natoms = len(Z)\n", 129 | " nbasis = len(molecule) \n", 130 | " \n", 131 | " coordinates = []\n", 132 | " for i in range(nbasis):\n", 133 | " nprimitives_i = len(molecule[i])\n", 134 | " for j in range(nprimitives_i):\n", 135 | " coordinates.append(molecule[i][j].coordinates )\n", 136 | "\n", 137 | " coordinates = np.array(coordinates)\n", 138 | " coordinates = np.unique(coordinates, axis=0)\n", 139 | " \n", 140 | " V_ne = np.zeros([nbasis, nbasis])\n", 141 | " \n", 142 | " for atom in range(natoms):\n", 143 | " for i in range(nbasis):\n", 144 | " for j in range(nbasis):\n", 145 | "\n", 146 | " nprimitives_i = len(molecule[i])\n", 147 | " nprimitives_j = len(molecule[j])\n", 148 | " \n", 149 | " for k in range(nprimitives_i):\n", 150 | " for l in range(nprimitives_j):\n", 151 | "\n", 152 | " N = molecule[i][k].A * molecule[j][l].A\n", 153 | " cacb = molecule[i][k].coeff * molecule[j][l].coeff\n", 154 | " \n", 155 | " p = molecule[i][k].alpha + molecule[j][l].alpha\n", 156 | " P = molecule[i][k].alpha*molecule[i][k].coordinates + molecule[j][l].alpha*molecule[j][l].coordinates\n", 157 | " Pp = P/p\n", 158 | " \n", 159 | " PG = P/p - coordinates[atom]\n", 160 | " \n", 161 | " PG2 = np.dot(PG,PG)\n", 162 | "\n", 163 | " q = molecule[i][k].alpha * molecule[j][l].alpha / p\n", 164 | " Q = molecule[i][k].coordinates - molecule[j][l].coordinates\n", 165 | " Q2 = np.dot(Q,Q)\n", 166 | " \n", 167 | " V_ne[i,j] += N * cacb * -Z[atom] * (2.0*math.pi/p) * math.exp(-q*Q2) * boys(p*PG2,0) \n", 168 | " \n", 169 | "\n", 170 | " return V_ne \n", 171 | " \n", 172 | " " 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": 36, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "def electron_electron_repulsion(molecule):\n", 182 | " \n", 183 | " nbasis = len(molecule) \n", 184 | " \n", 185 | " V_ee = np.zeros([nbasis, nbasis, nbasis, nbasis])\n", 186 | " \n", 187 | " for i in range(nbasis):\n", 188 | " for j in range(nbasis):\n", 189 | " for k in range(nbasis):\n", 190 | " for l in range(nbasis):\n", 191 | "\n", 192 | " nprimitives_i = len(molecule[i])\n", 193 | " nprimitives_j = len(molecule[j])\n", 194 | " nprimitives_k = len(molecule[k])\n", 195 | " nprimitives_l = len(molecule[l])\n", 196 | " \n", 197 | " for ii in range(nprimitives_i):\n", 198 | " for jj in range(nprimitives_j):\n", 199 | " for kk in range(nprimitives_k):\n", 200 | " for ll in range(nprimitives_l):\n", 201 | "\n", 202 | " N = molecule[i][ii].A * molecule[j][jj].A * molecule[k][kk].A * molecule[l][ll].A\n", 203 | " cicjckcl = molecule[i][ii].coeff * molecule[j][jj].coeff * \\\n", 204 | " molecule[k][kk].coeff * molecule[l][ll].coeff\n", 205 | " \n", 206 | " pij = molecule[i][ii].alpha + molecule[j][jj].alpha\n", 207 | " pkl = molecule[k][kk].alpha + molecule[l][ll].alpha\n", 208 | " \n", 209 | " Pij = molecule[i][ii].alpha*molecule[i][ii].coordinates +\\\n", 210 | " molecule[j][jj].alpha*molecule[j][jj].coordinates\n", 211 | " Pkl = molecule[k][kk].alpha*molecule[k][kk].coordinates +\\\n", 212 | " molecule[l][ll].alpha*molecule[l][ll].coordinates\n", 213 | " \n", 214 | " Ppij = Pij/pij\n", 215 | " Ppkl = Pkl/pkl\n", 216 | " \n", 217 | " PpijPpkl = Ppij - Ppkl\n", 218 | " PpijPpkl2 = np.dot(PpijPpkl,PpijPpkl)\n", 219 | " denom = 1.0/pij + 1.0/pkl\n", 220 | " \n", 221 | " qij = molecule[i][ii].alpha * molecule[j][jj].alpha / pij\n", 222 | " qkl = molecule[k][kk].alpha * molecule[l][ll].alpha / pkl\n", 223 | "\n", 224 | " Qij = molecule[i][ii].coordinates - molecule[j][jj].coordinates\n", 225 | " Qkl = molecule[k][kk].coordinates - molecule[l][ll].coordinates\n", 226 | " \n", 227 | " Q2ij = np.dot(Qij,Qij)\n", 228 | " Q2kl = np.dot(Qkl,Qkl)\n", 229 | " \n", 230 | " term1 = 2.0*math.pi*math.pi/(pij*pkl)\n", 231 | " term2 = math.sqrt( math.pi/(pij+pkl) )\n", 232 | " term3 = math.exp(-qij*Q2ij) \n", 233 | " term4 = math.exp(-qkl*Q2kl)\n", 234 | " \n", 235 | " V_ee[i,j,k,l] += N * cicjckcl * term1 * term2 * term3 * term4 * boys(PpijPpkl2/denom,0) # 3 more \n", 236 | " \n", 237 | "\n", 238 | " return V_ee \n" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 37, 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "def nuclear_nuclear_repulsion_energy(atom_coords, zlist):\n", 248 | " \n", 249 | " assert (len(atom_coords) == len(zlist))\n", 250 | " natoms = len(zlist)\n", 251 | " E_NN = 0\n", 252 | " for i in range(natoms):\n", 253 | " Zi = zlist[i]\n", 254 | " for j in range(natoms):\n", 255 | " if j > i:\n", 256 | " Zj = zlist[j]\n", 257 | " Rijx = atom_coords[i][0] - atom_coords[j][0]\n", 258 | " Rijy = atom_coords[i][1] - atom_coords[j][1]\n", 259 | " Rijz = atom_coords[i][2] - atom_coords[j][2]\n", 260 | " Rijx_squared = Rijx*Rijx\n", 261 | " Rijy_squared = Rijy*Rijy\n", 262 | " Rijz_squared = Rijz*Rijz \n", 263 | " Rij = math.sqrt(Rijx_squared + Rijy_squared + Rijz_squared) \n", 264 | " E_NN += (Zi*Zj)/Rij\n", 265 | " \n", 266 | " return E_NN\n", 267 | " " 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 38, 273 | "metadata": { 274 | "scrolled": true 275 | }, 276 | "outputs": [], 277 | "source": [ 278 | "# # STO-3G basis for 1s orbital on hydrogen\n", 279 | "# H1_pg1a = primitive_gaussian(0.3425250914E+01, 0.1543289673E+00, [0,0,0], 0, 0, 0)\n", 280 | "# H1_pg1b = primitive_gaussian(0.6239137298E+00, 0.5353281423E+00, [0,0,0], 0, 0, 0)\n", 281 | "# H1_pg1c = primitive_gaussian(0.1688554040E+00, 0.4446345422E+00, [0,0,0], 0, 0, 0)\n", 282 | "\n", 283 | "# H2_pg1a = primitive_gaussian(0.3425250914E+01, 0.1543289673E+00, [0,0,1.4], 0, 0, 0)\n", 284 | "# H2_pg1b = primitive_gaussian(0.6239137298E+00, 0.5353281423E+00, [0,0,1.4], 0, 0, 0)\n", 285 | "# H2_pg1c = primitive_gaussian(0.1688554040E+00, 0.4446345422E+00, [0,0,1.4], 0, 0, 0)\n", 286 | "\n", 287 | "# zlist = [1.0, 1.0]\n", 288 | "# atom_coords = [np.array([0.0, 0.0, 0.0]), np.array([0.0, 0.0, 1.4])]\n", 289 | "\n", 290 | "# H1_1s = [H1_pg1a, H1_pg1b, H1_pg1c]\n", 291 | "# H2_1s = [H2_pg1a, H2_pg1b, H2_pg1c]\n", 292 | "\n", 293 | "# molecule = [H1_1s, H2_1s]\n", 294 | "# print(\"\\n\")\n", 295 | "# print(\"overlap matrix of H2 molecule in STO-3G basis\\n\", overlap(molecule))\n", 296 | "# print(\"\\nkinetic energy matrix of H2 molecule in STO-3G basis\\n\", kinetic(molecule))\n", 297 | "# print(\"\\nelectron nuclear attraction matrix of H2 molecule in STO-3G basis\\n\", electron_nuclear_attraction(molecule,[1.0,1.0]))\n", 298 | "# print(\"\\nelectron electron repulsion matrix of H2 molecule in STO-3G basis\\n\", electron_electron_repulsion(molecule))\n", 299 | "# print(\"\\nnuclear nuclear repulsion term of H2 molecule in STO-3G basis\\n\", nuclear_nuclear_repulsion_energy(atom_coords, zlist))\n", 300 | "\n", 301 | "\n", 302 | "# 6-31G basis for 1s orbital on hydrogen\n", 303 | "# H1_pg1a = primitive_gaussian(0.1873113696E+02, 0.3349460434E-01, [0,0,0], 0, 0, 0)\n", 304 | "# H1_pg1b = primitive_gaussian(0.2825394365E+01, 0.2347269535E+00, [0,0,0], 0, 0, 0)\n", 305 | "# H1_pg1c = primitive_gaussian(0.6401216923E+00, 0.8137573261E+00, [0,0,0], 0, 0, 0)\n", 306 | "# H1_pg2a = primitive_gaussian(0.1612777588E+00, 1.0000000, [0,0,0], 0, 0, 0)\n", 307 | "# H2_pg1a = primitive_gaussian(0.1873113696E+02, 0.3349460434E-01, [0,0,1.4], 0, 0, 0)\n", 308 | "# H2_pg1b = primitive_gaussian(0.2825394365E+01, 0.2347269535E+00, [0,0,1.4], 0, 0, 0)\n", 309 | "# H2_pg1c = primitive_gaussian(0.6401216923E+00, 0.8137573261E+00, [0,0,1.4], 0, 0, 0)\n", 310 | "# H2_pg2a = primitive_gaussian(0.1612777588E+00, 1.0000000, [0,0,1.4], 0, 0, 0)\n", 311 | "\n", 312 | "# zlist = [1.0, 1.0]\n", 313 | "# atom_coords = [np.array([0.0, 0.0, 0.0]), np.array([0.0, 0.0, 1.4])]\n", 314 | "\n", 315 | "# H1_1s = [H1_pg1a, H1_pg1b, H1_pg1c]\n", 316 | "# H1_2s = [H1_pg2a]\n", 317 | "# H2_1s = [H2_pg1a, H2_pg1b, H2_pg1c]\n", 318 | "# H2_2s = [H2_pg2a]\n", 319 | "# molecule = [H1_1s, H1_2s, H2_1s, H2_2s]\n", 320 | "# print(\"\\n\")\n", 321 | "# print(\"overlap matrix of H2 molecule in 6-31G basis\\n\", overlap(molecule))\n", 322 | "# print(\"\\nkinetic energy matrix of H2 molecule in 6-31G basis\\n\", kinetic(molecule))\n", 323 | "# print(\"\\nelectron nuclear attraction matrix of H2 molecule in 6-31G basis\\n\", electron_nuclear_attraction(molecule,[1.0,1.0]))\n", 324 | "# print(\"\\nelectron electron repulsion matrix of H2 molecule in 6-31G basis\\n\", electron_electron_repulsion(molecule))\n", 325 | "# print(\"\\nnuclear nuclear repulsion term of H2 molecule in STO-3G basis\\n\", nuclear_nuclear_repulsion_energy(atom_coords, zlist))\n" 326 | ] 327 | }, 328 | { 329 | "cell_type": "code", 330 | "execution_count": 39, 331 | "metadata": {}, 332 | "outputs": [], 333 | "source": [ 334 | "def compute_G(density_matrix, Vee):\n", 335 | " nbasis_functions = density_matrix.shape[0]\n", 336 | " G = np.zeros((nbasis_functions, nbasis_functions))\n", 337 | " for i in range(nbasis_functions):\n", 338 | " for j in range(nbasis_functions):\n", 339 | " for k in range(nbasis_functions):\n", 340 | " for l in range(nbasis_functions):\n", 341 | " density = density_matrix[k,l]\n", 342 | " J = Vee[i,j,k,l]\n", 343 | " K = Vee[i,l,k,j]\n", 344 | " G[i,j] += density*(J-0.5*K)\n", 345 | " return G\n", 346 | "\n", 347 | "\n", 348 | "def compute_density_matrix(mos):\n", 349 | " nbasis_functions = mos.shape[0]\n", 350 | " density_matrix = np.zeros((nbasis_functions, nbasis_functions))\n", 351 | " # P = occ*CC_dagger\n", 352 | " occupation = 2.0\n", 353 | " for i in range(nbasis_functions):\n", 354 | " for j in range(nbasis_functions):\n", 355 | " # mo is (natomic_orbtials x nMOs)\n", 356 | " for oo in range(number_occupied_orbitals):\n", 357 | " C = mos[i, oo]\n", 358 | " C_dagger = mos[j, oo]\n", 359 | " density_matrix[i,j] += occupation * C * C_dagger \n", 360 | " return density_matrix\n", 361 | "\n", 362 | "\n", 363 | "def compute_electronic_energy_expectation_value(density_matrix, T, Vne, G):\n", 364 | " \n", 365 | " Hcore = T + Vne\n", 366 | " electronic_energy = 0.0\n", 367 | " nbasis_functions = density_matrix.shape[0]\n", 368 | " for i in range(nbasis_functions):\n", 369 | " for j in range(nbasis_functions):\n", 370 | " electronic_energy += density_matrix[i,j] * (Hcore[i,j] + 0.5*G[i,j])\n", 371 | " return electronic_energy\n", 372 | "\n", 373 | "\n", 374 | "def scf_cycle(molecular_terms, scf_parameters, molecule):\n", 375 | " \n", 376 | " S, T, Vne, G = molecular_terms\n", 377 | " tolerance, max_scf_steps = scf_parameters\n", 378 | " electronic_energy = 0.0\n", 379 | " nbasis_functions = len(molecule)\n", 380 | " density_matrix = np.zeros((nbasis_functions, nbasis_functions))\n", 381 | " \n", 382 | " # 1. Enter into the SCF cycles\n", 383 | " for scf_step in range(max_scf_steps):\n", 384 | " \n", 385 | " electronic_energy_old = electronic_energy\n", 386 | " \n", 387 | " # 2. Compute the 2 electron term, and add it to the 1 electron term\n", 388 | " G = compute_G(density_matrix, Vee)\n", 389 | " \n", 390 | " # 3. Form F, make S unit, then get eigenvalues and eigenvectors - transform eigenvectors back (w.o unitS)\n", 391 | " F = T + Vne + G\n", 392 | " # S^{-1/2} S S^{-1/2}\n", 393 | " S_inverse = linalg.inv(S)\n", 394 | " S_inverse_sqrt = linalg.sqrtm(S_inverse)\n", 395 | " # S^{-1/2} F S^{-1/2}\n", 396 | " F_unitS = np.dot(S_inverse_sqrt, np.dot(F, S_inverse_sqrt))\n", 397 | " eigenvalues, eigenvectors = linalg.eigh(F_unitS)\n", 398 | " mos = np.dot(S_inverse_sqrt, eigenvectors)\n", 399 | "\n", 400 | " # 4. Form new density matrix using MOs\n", 401 | " density_matrix = compute_density_matrix(mos)\n", 402 | " \n", 403 | " # 5. Compute electronic_energy expectation value\n", 404 | " electronic_energy = compute_electronic_energy_expectation_value(density_matrix, T, Vne, G)\n", 405 | " \n", 406 | " # 6. Check convergence\n", 407 | " if abs(electronic_energy-electronic_energy_old) < tolerance:\n", 408 | " return electronic_energy\n", 409 | " \n", 410 | " print(\"Warning: Convergence not met\")\n", 411 | " return electronic_energy" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": 40, 417 | "metadata": {}, 418 | "outputs": [ 419 | { 420 | "data": { 421 | "text/plain": [ 422 | "[]" 423 | ] 424 | }, 425 | "execution_count": 40, 426 | "metadata": {}, 427 | "output_type": "execute_result" 428 | }, 429 | { 430 | "data": { 431 | "image/png": "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\n", 432 | "text/plain": [ 433 | "
" 434 | ] 435 | }, 436 | "metadata": { 437 | "needs_background": "light" 438 | }, 439 | "output_type": "display_data" 440 | } 441 | ], 442 | "source": [ 443 | "# create many H2 molecules\n", 444 | "distances = [round(i*0.1,3) for i in range(4,61)] # in unit = bohr (a.u of position)\n", 445 | "molecule_coordinates = [ [[0.0, 0.0, 0.0], [0.0, 0.0, distance]] for distance in distances]\n", 446 | "total_energies = []\n", 447 | "for molecule_coordinate in molecule_coordinates:\n", 448 | "\n", 449 | " # create H2 molecule - sto-3g basis\n", 450 | " H1_pg1a = primitive_gaussian(0.3425250914E+01, 0.1543289673E+00, molecule_coordinate[0], 0, 0, 0)\n", 451 | " H1_pg1b = primitive_gaussian(0.6239137298E+00, 0.5353281423E+00, molecule_coordinate[0], 0, 0, 0)\n", 452 | " H1_pg1c = primitive_gaussian(0.1688554040E+00, 0.4446345422E+00, molecule_coordinate[0], 0, 0, 0)\n", 453 | " H2_pg1a = primitive_gaussian(0.3425250914E+01, 0.1543289673E+00, molecule_coordinate[1], 0, 0, 0)\n", 454 | " H2_pg1b = primitive_gaussian(0.6239137298E+00, 0.5353281423E+00, molecule_coordinate[1], 0, 0, 0)\n", 455 | " H2_pg1c = primitive_gaussian(0.1688554040E+00, 0.4446345422E+00, molecule_coordinate[1], 0, 0, 0)\n", 456 | " number_occupied_orbitals = 1\n", 457 | " zlist = [1.0, 1.0]\n", 458 | " atom_coords = [np.array(molecule_coordinate[0]), np.array(molecule_coordinate[1])]\n", 459 | " H1_1s = [H1_pg1a, H1_pg1b, H1_pg1c]\n", 460 | " H2_1s = [H2_pg1a, H2_pg1b, H2_pg1c]\n", 461 | " molecule = [H1_1s, H2_1s]\n", 462 | " \n", 463 | " # compute scf energy (electronic energy)\n", 464 | " S = overlap(molecule)\n", 465 | " T = kinetic(molecule)\n", 466 | " Vne = electron_nuclear_attraction(molecule, [1.0, 1.0])\n", 467 | " Vee = electron_electron_repulsion(molecule)\n", 468 | " Enn = nuclear_nuclear_repulsion_energy(atom_coords, zlist)\n", 469 | " molecular_terms = [S, T, Vne, Vee]\n", 470 | " scf_parameters = [1e-5, 20]\n", 471 | " electronic_energy = scf_cycle(molecular_terms, scf_parameters, molecule)\n", 472 | " # compute total energy - electronic_energy + Enn\n", 473 | " total_energy = electronic_energy + Enn\n", 474 | " total_energies.append(total_energy)\n", 475 | " \n", 476 | "# plot bond dissociation curve\n", 477 | "import matplotlib.pyplot as plt\n", 478 | "plt.xlabel(\"Bond distance, Angstrom\")\n", 479 | "plt.ylabel(\"Total Energy, Hartree\")\n", 480 | "plt.plot(np.array(distances)*0.529, total_energies)" 481 | ] 482 | } 483 | ], 484 | "metadata": { 485 | "kernelspec": { 486 | "display_name": "Python 3 (ipykernel)", 487 | "language": "python", 488 | "name": "python3" 489 | }, 490 | "language_info": { 491 | "codemirror_mode": { 492 | "name": "ipython", 493 | "version": 3 494 | }, 495 | "file_extension": ".py", 496 | "mimetype": "text/x-python", 497 | "name": "python", 498 | "nbconvert_exporter": "python", 499 | "pygments_lexer": "ipython3", 500 | "version": "3.8.6" 501 | } 502 | }, 503 | "nbformat": 4, 504 | "nbformat_minor": 4 505 | } 506 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Nickel and Copper YouTube's Github 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HartreeFockPythonProgram --------------------------------------------------------------------------------