Kindfield
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Friends Pages
unrestrictedhartreefocksolver.cpp
Go to the documentation of this file.
3 
4 #include <iomanip>
5 
6 using std::setprecision;
7 using std::fixed;
8 
15  HartreeFockSolver(system),
16  m_initialCoefficientMatricesSetManually(false),
17  m_diisSampleCount(10),
18  m_diisStartingIteration(20),
19  m_isDiisEnabled(true)
20 {
21 }
22 
27 {
29  resetCoefficientMatrices();
30  resetFockMatrices();
31  setupDensityMatrices();
32  if(m_densityMatrixUp.n_rows > 0 && m_densityMatrixUp.n_cols > 1) {
33  m_densityMatrixUp(0,1) = 0.1; // Added asymmetry between the spin up and spin down orbitals
34  }
35  setupFockMatrices();
36 }
37 
38 void UnrestrictedHartreeFockSolver::resetFockMatrices() {
39  uint n = electronSystem()->nBasisFunctions();
40  m_fockMatrixUp = zeros(n,n);
41  m_fockMatrixDown = zeros(n,n);
42 }
43 
44 void UnrestrictedHartreeFockSolver::resetCoefficientMatrices() {
46 
47  if(!m_initialCoefficientMatricesSetManually
48  || m_initialCoefficientMatrixUp.n_rows != f->nBasisFunctions()
49  || m_initialCoefficientMatrixUp.n_cols != f->nParticlesUp()
50  || m_initialCoefficientMatrixDown.n_rows != f->nBasisFunctions()
51  || m_initialCoefficientMatrixDown.n_cols != f->nParticlesDown()) {
52  m_initialCoefficientMatrixUp = zeros(f->nBasisFunctions(), f->nParticlesUp());
53  m_initialCoefficientMatrixDown = zeros(f->nBasisFunctions(), f->nParticlesDown());
54  }
55 
56  m_coefficientMatrixUp = m_initialCoefficientMatrixUp;
57  m_coefficientMatrixDown = m_initialCoefficientMatrixDown;
58 }
59 
60 void UnrestrictedHartreeFockSolver::randomizeCoefficientMatrices() {
62  m_coefficientMatrixUp = randn(f->nBasisFunctions(), f->nParticlesUp());
63  m_coefficientMatrixDown = randn(f->nBasisFunctions(), f->nParticlesDown());
64 }
65 
66 void UnrestrictedHartreeFockSolver::setupFockMatrices() {
68  uint n = f->nBasisFunctions();
69 
70  mat &Fu = m_fockMatrixUp;
71  mat &Fd = m_fockMatrixDown;
72  const mat &Pu = m_densityMatrixUp;
73  const mat &Pd = m_densityMatrixDown;
74  const mat &h = uncoupledMatrix();
75  const field<mat> &Q = coupledMatrix();
76  for(uint p = 0; p < n; p++) {
77  for(uint q = p; q < n; q++) {
78  double hpq = h(p,q);
79  double Fupq = hpq;
80  double Fdpq = hpq;
81  // TODO: Apply the symmetry in Q for increased performance
82  for(uint r = 0; r < n; r++) {
83  for(uint s = 0; s < n; s++) {
84  double Qprqs = Q(p,r)(q,s);
85  double Qprsq = Q(p,r)(s,q);
86  double QprqsMinusQprsq = Qprqs - Qprsq;
87  double Pusr = Pu(s,r);
88  double Pdsr = Pd(s,r);
89  Fupq += Pusr * QprqsMinusQprsq + Pdsr * Qprqs;
90  Fdpq += Pdsr * QprqsMinusQprsq + Pusr * Qprqs;
91  }
92  }
93  // Set elements and apply symmetry
94  Fu(p,q) = Fupq;
95  Fu(q,p) = Fupq;
96  Fd(p,q) = Fdpq;
97  Fd(q,p) = Fdpq;
98  }
99  }
100 }
101 
102 void UnrestrictedHartreeFockSolver::setupDensityMatrices() {
103  mat &Pu = m_densityMatrixUp;
104  mat &Pd = m_densityMatrixDown;
105  mat &Cu = m_coefficientMatrixUp;
106  mat &Cd = m_coefficientMatrixDown;
107  mat tempPu = Cu * Cu.t();
108  mat tempPd = Cd * Cd.t();
109  double mixFactor = densityMixFactor();
110  if(Pu.n_elem > 0 && Pd.n_elem > 0) {
111  Pu = mixFactor * Pu + (1 - mixFactor) * tempPu; // smoothing
112  Pd = mixFactor * Pd + (1 - mixFactor) * tempPd; // smoothing
113  } else {
114  Pu = tempPu;
115  Pd = tempPd;
116  }
117 }
118 
122  uint no = f->nBasisFunctions();
123  uint nkUp = f->nParticlesUp();
124  uint nkDn = f->nParticlesDown();
125 
126  mat &Fu = m_fockMatrixUp;
127  mat &Fd = m_fockMatrixDown;
128  mat &Cu = m_coefficientMatrixUp;
129  mat &Cd = m_coefficientMatrixDown;
130  vec &fockEnergiesUp = m_fockEnergiesUp;
131  vec &fockEnergiesDn = m_fockEnergiesDown;
132 
133  const mat &V = transformationMatrix();
134 
135  mat FprimeUp = V.t() * Fu * V;
136  mat FprimeDn = V.t() * Fd * V;
137 
138  mat CprimeUp;
139  mat CprimeDn;
140 
141  eig_sym(fockEnergiesUp, CprimeUp, FprimeUp);
142  eig_sym(fockEnergiesDn, CprimeDn, FprimeDn);
143 
144  if(nkUp > 0) {
145  Cu = V*CprimeUp.submat(0, 0, no - 1, nkUp - 1);
146  }
147  if(nkDn > 0) {
148  Cd = V*CprimeDn.submat(0, 0, no - 1, nkDn - 1);
149  }
150 
151  normalizeCoefficientMatrix(f->nParticlesUp(), m_coefficientMatrixUp);
152  normalizeCoefficientMatrix(f->nParticlesDown(), m_coefficientMatrixDown);
153 
154  setupDensityMatrices();
155  setupFockMatrices();
156 }
157 
160  for(int i = 0; i < nIterationsMax(); i++) {
161  m_iterationsUsed = i + 1;
162  vec previousFockEnergies = m_fockEnergiesUp;
163  if(m_isDiisEnabled && i > m_diisStartingIteration) {
164  performDIIS();
165  }
166  advance();
167  if(i > 0) {
168  double stdDeviation = sum(abs(m_fockEnergiesUp - previousFockEnergies)) / m_fockEnergiesUp.n_elem;
169  if(stdDeviation < convergenceTreshold()) {
170  break;
171  }
172  }
173  }
174  calculateEnergy();
175 }
176 
177 void UnrestrictedHartreeFockSolver::calculateEnergy()
178 {
179  double energy = 0;
180  mat &Pu = m_densityMatrixUp;
181  mat &Pd = m_densityMatrixDown;
182  mat &Fu = m_fockMatrixUp;
183  mat &Fd = m_fockMatrixDown;
184 
185  const mat& h = uncoupledMatrix();
186  energy += 0.5 * accu( (Pu + Pd) % h + Fu % Pu + Fd % Pd);
187  energy += electronSystem()->additionalEnergyTerms();
188  m_energyUHF = energy;
189 }
190 
191 
193 {
194  return m_coefficientMatrixUp;
195 }
196 
198 {
199  return m_coefficientMatrixDown;
200 }
201 
203 {
204  return m_densityMatrixUp;
205 }
206 
208 {
209  return m_densityMatrixDown;
210 }
211 
213 {
214  m_initialCoefficientMatricesSetManually = true;
215  m_initialCoefficientMatrixUp = up;
216  m_initialCoefficientMatrixDown = down;
217 }
218 
220 {
221  return m_energyUHF;
222 }
223 
230 void UnrestrictedHartreeFockSolver::performDIIS()
231 {
232  mat &Fu = m_fockMatrixUp;
233  mat &Fd = m_fockMatrixDown;
234  mat &Pu = m_densityMatrixUp;
235  mat &Pd = m_densityMatrixDown;
236  const mat &S = overlapMatrix();
237 
238  m_errorsU.push_back(Fu*Pu*S - S*Pu*Fu);
239  m_fockMatricesU.push_back(m_fockMatrixUp);
240 
241  m_errorsD.push_back(Fd*Pd*S - S*Pd*Fd);
242  m_fockMatricesD.push_back(m_fockMatrixDown);
243 
244  if(signed(m_errorsU.size()) > m_diisSampleCount){
245  m_errorsU.erase(m_errorsU.begin());
246  m_fockMatricesU.erase(m_fockMatricesU.begin());
247 
248  m_errorsD.erase(m_errorsD.begin());
249  m_fockMatricesD.erase(m_fockMatricesD.begin());
250 
251  mat Au = zeros(m_errorsU.size()+1, m_errorsU.size()+1);
252  mat Ad = zeros(m_errorsD.size()+1, m_errorsD.size()+1);
253 
254  for(uint i = 0; i < m_errorsU.size(); i++){
255  Au(i, m_errorsU.size()) = -1;
256  Au(m_errorsU.size(), i) = -1;
257 
258  Ad(i, m_errorsD.size()) = -1;
259  Ad(m_errorsD.size(), i) = -1;
260 
261  for(uint j = 0; j < m_errorsU.size(); j++){
262  Au(i,j) = trace(m_errorsU.at(i) * m_errorsU.at(j));
263  Ad(i,j) = trace(m_errorsD.at(i) * m_errorsD.at(j));
264  }
265  }
266 
267  vec bu = zeros(Au.n_rows);
268  vec bd = zeros(Ad.n_rows);
269 
270  bu(bu.n_elem -1) = -1.0;
271  bd(bd.n_elem -1) = -1.0;
272  bu = inv(Au) * bu;
273  bd = inv(Ad) * bd;
274 
275  for(uint i = 0; i < bu.n_elem - 1; i++){
276  m_fockMatrixUp += bu(i) * m_fockMatricesU.at(i);
277  m_fockMatrixDown += bd(i) * m_fockMatricesD.at(i);
278  }
279  }
280 }
282 {
283  return m_diisStartingIteration;
284 }
285 
287 {
288  m_diisStartingIteration = diisStartingIteration;
289 }
290 
292 {
293  return m_diisSampleCount;
294 }
295 
297 {
298  m_diisSampleCount = diisIterationCount;
299 }
300 
302 {
303  return m_isDiisEnabled;
304 }
305 
307 {
308  m_isDiisEnabled = useDIIS;
309 }
310