File: test_hf.py

package info (click to toggle)
libint2 2.7.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 63,776 kB
  • sloc: ansic: 842,934; cpp: 47,846; sh: 3,139; makefile: 1,017; f90: 676; perl: 482; python: 334
file content (121 lines) | stat: -rw-r--r-- 3,456 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import libint2

import numpy as np
import scipy.linalg

def compute_1body_ints(oper, basis, params = None):
  engine = libint2.Engine(oper)
  if params: engine.set_params(params)
  return engine.compute_1body_ints(basis)

  # h = np.zeros([basis.nbf,basis.nbf])
  # bf = basis.functions
  # for i,p in enumerate(bf):
  #   for j,q in enumerate(bf):
  #     h[p,q] = engine.compute(*basis.shells(i,j))
  # return h


def compute_2body_fock(D, basis):
  engine = libint2.Engine(libint2.Operator.coulomb)
  return engine.compute_2body_fock(D, basis)

  # F = np.zeros([basis.nbf,basis.nbf])
  # bf = basis.functions
  # for i in range(len(basis)):
  #   for j in range(0,i+1):
  #     for k in range(len(basis)):
  #       for l in range(0,k+1):

  #         p,q,r,s = [bf[idx] for idx in (i,j,k,l)]
  #         eri = engine.compute(*basis.shells(i,j,k,l))
  #         if eri is None: continue

  #         symm = 1.0
  #         if i == j: symm /= 2
  #         if k == l: symm /= 2

  #         F[p,q] += 2*np.einsum('pqrs,rs->pq', eri, D[r,s])*2*symm

  #         F[p,r] -= np.einsum('pqrs,qs->pr', eri, D[q,s])/2*symm
  #         F[q,r] -= np.einsum('pqrs,ps->qr', eri, D[p,s])/2*symm

  #         F[p,s] -= np.einsum('pqrs,qr->ps', eri, D[q,r])/2*symm
  #         F[q,s] -= np.einsum('pqrs,pr->qs', eri, D[p,r])/2*symm

  #         # J = engine.compute(*basis.shells(i,k,j,l))
  #         # F[p,q] += 2*np.einsum('pqrs,rs->pq', J, D[r,s])
  #         # K = engine.compute(*basis.shells(i,k,j,l))
  #         # F[p,q] -= np.einsum('prqs,rs->pq', K, D[r,s])

  # return F+F.T

class RHF:

  def __init__(self, basis, atoms):
    if not isinstance(basis, libint2.BasisSet):
      basis = libint2.BasisSet(basis, atoms)
    assert basis and basis.nbf
    self.basis = basis

    self.nelec = sum([z for z,r in atoms])
    self.ndocc = self.nelec//2
    self.enuc = 0
    for i,(qi,ri) in enumerate(atoms):
      for j,(qj,rj) in enumerate(atoms[:i]):
        self.enuc += qi*qj/np.linalg.norm(np.array(ri)-np.array(rj), ord=2)

    self.S = compute_1body_ints(libint2.Operator.overlap, basis)
    self.T = compute_1body_ints(libint2.Operator.kinetic, basis)
    self.V = compute_1body_ints(libint2.Operator.nuclear, basis, atoms)
    self.H = self.V + self.T
    self.compute_density(self.H)
    self.converged = False
    self.F = None
    self.ehf = None

  def compute_density(self, F):
    ndocc = self.ndocc
    eig, C = scipy.linalg.eigh(F,self.S)
    D = np.matmul(C[:,:ndocc], C[:,:ndocc].T)
    self.C = C
    self.D = D

  def energy(self):
    if not self.converged:
      self.converge()
    return (self.enuc + self.ehf)

  def converge(self, iterations=30, tol=1e-6):
    self.converged = False
    for i in range(iterations):
      F = compute_2body_fock(self.D, self.basis)
      F += self.H
      ehf = self.ehf or 0.0
      self.compute_density(F)
      self.F = F
      self.ehf = np.sum(np.multiply(self.D, self.H+F))
      ediff = ehf-self.ehf
      #print("%i  %f  %f"%(i, (self.enuc + self.ehf), ediff))
      if abs(ediff) < tol:
        self.converged = True
        break


import unittest

h2o = [
  (8, [  0.00000, -0.07579, 0.00000 ]),
  (1, [  0.86681,  0.60144, 0.00000 ]),
  (1, [ -0.86681,  0.60144, 0.00000 ]),
]

class TestHF(unittest.TestCase):
  def test_hf(self):
    basis = '6-31g'
    rhf = RHF(basis, h2o)
    self.assertAlmostEqual(rhf.energy(), -75.1903033978)

if __name__ == '__main__':
  unittest.main()