1 /*
2
3 Copyright (C) 2007 Lucas K. Wagner
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 */
20
21 #ifndef MO_MATRIX_H_INCLUDED
22 #define MO_MATRIX_H_INCLUDED
23
24 #include "Array.h"
25 #include "Qmc_std.h"
26 #include "Basis_function.h"
27 #include "Center_set.h"
28 #include <algorithm>
29
30 class System;
31 class Sample_point;
32
33 class General_MO_matrix {
34 public:
35 /*!
36 Build several sets of MO's to be evaluated in updateVal and updateLap.
37 Each element in occupations should be a list of the MO's that should
38 be evaluated. For example, one can create a list of spin up and spin
39 down MO's, and only evaluate up when an up electron is moved.
40 */
41 virtual void buildLists(Array1 <Array1 <int> > & occupations)=0;
42
43 /*!
44 get the number of molecular orbitals
45 */
46 virtual int getNmo()=0;
47 virtual int showinfo(ostream & os)=0;
48 virtual int writeinput(string &, ostream &)=0;
49 virtual void read(vector <string> & words, unsigned int & startpos,
50 System * sys)=0;
51
~General_MO_matrix()52 virtual ~General_MO_matrix() { }
53
54 };
55
56 //----------------------------------------------------------------------
57
58
59 template <class T> class Templated_MO_matrix: public General_MO_matrix {
60 protected:
61 Center_set centers;
62 Array1 <Basis_function *> basis;
63 int nmo;
64 doublevar magnification_factor;
65 string orbfile;
66 int totbasis;
67 int maxbasis;
init()68 virtual void init() { } ;
69
70 string oldsofile;
71
72 Array1 <doublevar> kpoint; //!< the k-point of the orbitals in fractional units(1 0 0) is X, etc..
73 public:
74
75 /*!
76 Build several sets of MO's to be evaluated in updateVal and updateLap.
77 Each element in occupations should be a list of the MO's that should
78 be evaluated. For example, one can create a list of spin up and spin
79 down MO's, and only evaluate up when an up electron is moved.
80 */
81 virtual void buildLists(Array1 <Array1 <int> > & occupations)=0;
setOrbfile(string & x)82 virtual void setOrbfile(string & x) {
83 orbfile=x;
84 }
85 /*!
86 get the number of molecular orbitals
87 */
getNmo()88 int getNmo() {
89 return nmo;
90 }
91
92 virtual int showinfo(ostream & os)=0;
93
94 virtual int writeinput(string &, ostream &)=0;
95 virtual void read(vector <string> & words, unsigned int & startpos,
96 System * sys);
97
writeorb(ostream &,Array2<doublevar> & rotation,Array1<int> &)98 virtual void writeorb(ostream &, Array2 <doublevar> & rotation, Array1 <int> &)
99 { error("writeorb not implemented"); }
100
101 /*!
102 Get the molecular orbital coefficients
103 */
getMoCoeff(Array2<T> & coeff)104 virtual void getMoCoeff(Array2 <T> & coeff) {
105 error("getMoCoeff not implemented");
106 }
107
108 /*!
109
110 */
setMoCoeff(Array2<T> & coeff)111 virtual void setMoCoeff(Array2 <T> & coeff){
112 error("setMoCoeff not implemented");
113 }
nMoCoeff()114 virtual int nMoCoeff() {
115 error("nMoCoeff not implemented");
116 return 0;
117 }
118
119
120 virtual void updateVal(
121 Sample_point * sample,
122 int e,
123 //!< electron number
124 int listnum,
125 Array2 <T> & newvals
126 //!< The return: in form (MO)
127 )=0;
128
getBasisVal(Sample_point * sample,int e,Array1<T> & newvals)129 virtual void getBasisVal(
130 Sample_point * sample,
131 int e,
132 //!< electron number
133 Array1 <T> & newvals
134 ) {
135 error("getBasisVal not implemented");
136 }
137
138 virtual void updateLap(
139 Sample_point * sample,
140 int e,
141 //!< electron number
142 int listnum,
143 //!< Choose the list that was built in buildLists
144 Array2 <T> & newvals
145 //!< The return: in form (MO,[value gradient lap])
146 )=0;
147
updateHessian(Sample_point * sample,int e,int listnum,Array2<T> & newvals)148 virtual void updateHessian(Sample_point * sample,
149 int e,
150 int listnum,
151 Array2 <T>& newvals
152 //!< in form (MO, [value gradient, dxx,dyy,dzz,dxy,dxz,dyz])
153 ) {
154 error("this MO_matrix doesn't support Hessians");
155 }
156
Templated_MO_matrix()157 Templated_MO_matrix()
158 {}
159
~Templated_MO_matrix()160 virtual ~Templated_MO_matrix()
161 {
162 //doublevar totcalls=0;
163 //for(int i=0; i< nmo; i++) {
164 // cout << "mo_counter " << mo_counter(i)/n_calls << endl;
165 // totcalls+=mo_counter(i)/n_calls;
166 //}
167 //cout << " average # of basis functions evaluated " << totcalls/nmo << endl;
168 for(int i=0; i< basis.GetDim(0); i++)
169 deallocate(basis(i));
170 }
171
172 };
173
174 typedef Templated_MO_matrix<doublevar> MO_matrix;
175 typedef Templated_MO_matrix<dcomplex> Complex_MO_matrix;
176 //----------------------------------------------------------------------------
177
178
179 int allocate(vector <string> & words, System * sys, MO_matrix *& moptr);
180 int allocate(vector <string> & words, System * sys,
181 Complex_MO_matrix *& moptr);
182
183 void rotate_orb(istream & orbin, ostream & orbout,
184 Array2 <doublevar> & rotation,
185 Array1 <int> & moList, int nfunctions);
186 void rotate_Corb(istream & orbin, ostream & orbout,
187 Array2 <doublevar> & rotation,
188 Array1 <int> & moList, int nfunctions);
189
190
191 /*
192 Gets the coefficients and sets everything up from a formatted
193 input file(ORB). The file should look like: <br>
194 MO# AO#(for center) Center# Coeff# <br>
195 for all MO's, then a listing of the coefficients in sequential order
196
197 */
198 /*!
199
200 */
201 //------------------------------------------------------------------------------------------
202 #ifdef USE_MPI
overloaded_broadcast(Array1<doublevar> & v)203 inline void overloaded_broadcast(Array1 <doublevar> & v) {
204 MPI_Bcast(v.v,v.GetDim(0), MPI_DOUBLE,0,MPI_Comm_grp);
205 }
overloaded_broadcast(Array1<dcomplex> & v)206 inline void overloaded_broadcast(Array1 <dcomplex> & v) {
207 MPI_Bcast(v.v,v.GetDim(0), MPI_DOUBLE_COMPLEX,0,MPI_Comm_grp);
208 }
209 #endif
210
readorb(istream & input,Center_set & centers,int nmo,int maxbasis,Array1<doublevar> & kpoint,Array3<int> & coeffmat,Array1<T> & coeff)211 template <class T> int readorb(istream & input, Center_set & centers,
212 int nmo, int maxbasis, Array1 <doublevar> & kpoint,
213 Array3 <int> & coeffmat, Array1 <T> & coeff) {
214 int nmo_read=0;
215 int maxlabel=0;
216 coeffmat.clear(); //important to do this so that we know exactly how big the array v will be
217 //This enables us to use relatively fast Bcast() operations.
218 coeff.clear();
219 if(mpi_info.node==0) {
220 string dummy;
221 vector <int> mo,center,basis,label;
222 while(true) {
223 input >> dummy;
224 if(dummy=="COEFFICIENTS") break;
225 int currmo=atoi(dummy.c_str())-1;
226 if(currmo > nmo) {
227 input.ignore(300,'\n');
228 }
229 else {
230 mo.push_back(currmo);
231 input >> dummy;
232 basis.push_back(atoi(dummy.c_str())-1);
233 if(basis.back() >= maxbasis)
234 error("Basis function greater than maxbasis requested:",basis.back()+1);
235 else if(basis.back() < 0)
236 error("Basis function cannot be less than 1:",basis.back()+1);
237 input >> dummy;
238 center.push_back(atoi(dummy.c_str())-1);
239 if(center.back() > centers.equiv_centers.GetDim(0) )
240 error("Center number in orb file greater than maximum number ",
241 centers.equiv_centers.GetDim(0));
242
243 input >> dummy;
244 label.push_back(atoi(dummy.c_str())-1);
245 }
246 if(!input)
247 error("Unexpected end of file; did not find COEFFICIENTS while reading orbitals");
248 }
249 nmo_read=*std::max_element(mo.begin(),mo.end())+1;
250 coeffmat.Resize(nmo_read, centers.size(), maxbasis);
251 coeffmat=-1;
252 {
253 vector<int>::iterator m=mo.begin(),
254 c=center.begin(),
255 b=basis.begin(),
256 l=label.begin();
257
258 for( ; m!=mo.end() && c!=center.end() && b!=basis.end() && l!=label.end();
259 m++,c++,b++,l++) {
260 // coeffmat(*m,*c,*b)=*l;
261 for(int c_eq=0; c_eq < centers.ncenters_atom(*c); c_eq++) {
262 int cen2=centers.equiv_centers(*c, c_eq);
263 coeffmat(*m, cen2,*b)=*l;
264 }
265
266 }
267 }
268
269 maxlabel=*std::max_element(label.begin(),label.end())+1;
270 coeff.Resize(maxlabel);
271 for(int i=0; i< maxlabel; i++) {
272 if(! (input >> coeff(i) ) )
273 error("unexpected end of file when reading orbital coefficients");
274 }
275 }
276 #ifdef USE_MPI
277 MPI_Bcast(&nmo_read,1,MPI_INT,0,MPI_Comm_grp);
278 MPI_Bcast(&maxlabel,1,MPI_INT,0,MPI_Comm_grp);
279 int coeffmatsize;
280
281 if(mpi_info.node!=0) {
282 coeffmat.Resize(nmo_read,centers.size(),maxbasis);
283 coeff.Resize(maxlabel);
284 }
285 MPI_Bcast(coeffmat.v,coeffmat.size,MPI_INT,0,MPI_Comm_grp);
286 overloaded_broadcast(coeff);
287 #endif
288 return nmo_read;
289 }
290
291
292
293 //----------------------------------------------------------------------
294 //A simple templated function to evaluate the k-point when it is real versus
295 //when it is complex.
eval_kpoint_fac(doublevar & dot)296 template <class T> inline T eval_kpoint_fac(doublevar & dot) {
297 error("Not a general class.");
298 }
299
300 template <> inline doublevar eval_kpoint_fac<doublevar>(doublevar & dot) {
301 return cos(dot*pi);
302 }
303 template <> inline dcomplex eval_kpoint_fac<dcomplex>(doublevar & dot) {
304 return exp(dcomplex(0.0,1.0)*dot*pi);
305 }
306
eval_kpoint_deriv(Array1<doublevar> & kpoint,doublevar kr,T & val,Array1<T> & grad,Array2<T> & hess)307 template <class T> inline void eval_kpoint_deriv(Array1 <doublevar> & kpoint,
308 doublevar kr,
309 T & val, Array1 <T> & grad, Array2 <T> & hess) {
310 error("kpoint_deriv not implemented in general");
311 }
312
313 template <> inline void eval_kpoint_deriv<dcomplex>(Array1 <doublevar> & kpoint,
314 doublevar kr,
315 dcomplex & val, Array1 <dcomplex> & grad, Array2 <dcomplex> & hess) {
316 int ndim=grad.GetDim(0);
317 assert(ndim==hess.GetDim(0));
318 assert(ndim==hess.GetDim(1));
319 const dcomplex I(0,1.0);
320 dcomplex eikr=eval_kpoint_fac<dcomplex>(kr);
321 for(int d1=0; d1 < ndim; d1++)
322 for(int d2=0; d2< ndim; d2++)
323 hess(d1,d2)=eikr*(hess(d1,d2)
324 +I*pi*kpoint(d1)*grad(d2)
325 +I*pi*kpoint(d2)*grad(d1)
326 -pi*pi*kpoint(d1)*kpoint(d2)*val);
327 for (int d=0; d< ndim; d++)
328 grad(d)=eikr*(I*pi*kpoint(d)*val+grad(d));
329 val*=eikr;
330 }
331
332 template <> inline void eval_kpoint_deriv<doublevar>(Array1 <doublevar> & kpoint,
333 doublevar kr,
334 doublevar & val, Array1 <doublevar> & grad, Array2 <doublevar> & hess) {
335 //still not clear how to do this exactly, so we'll ignore it for now.
336 assert(abs(kpoint(0)) < 1e-14);
337 assert(abs(kpoint(1)) < 1e-14);
338 assert(abs(kpoint(2)) < 1e-14);
339 }
340
341
342
343 //----------------------------------------------------------------------------
344 #include "qmc_io.h"
345 //template<> inline void Complex_MO_matrix::read(vector <string> & words,
346 // unsigned int & startpos,
347 // System * sys) {
348 //}
349
read(vector<string> & words,unsigned int & startpos,System * sys)350 template<class T> inline void Templated_MO_matrix<T>::read(vector <string> & words,
351 unsigned int & startpos,
352 System * sys)
353 {
354
355
356 unsigned int pos=startpos;
357
358 if(!readvalue(words, pos, nmo, "NMO")) {
359 error("Need NMO in molecular orbital section");
360 }
361
362 if(nmo > 40000)
363 error("You have entered more than 40,000 for NMO. This seems a bit big; we most likely"
364 " can't handle it.");
365
366
367 pos=0;
368 if(!readvalue(words, pos, magnification_factor, "MAGNIFY")) {
369 magnification_factor=1;
370 }
371
372
373 //Basis functions
374 vector <vector <string> > basistext;
375 vector < string > basissec;
376 pos=0;
377 while( readsection(words, pos, basissec, "BASIS") != 0) {
378 basistext.insert(basistext.end(), basissec);
379 }
380 basis.Resize(basistext.size());
381 basis=NULL;
382
383 if(basistext.size() == 0 )
384 error("Didn't find a BASIS section");
385 for(unsigned int i=0; i<basistext.size(); i++) {
386 allocate(basistext[i], basis(i));
387 }
388
389 sys->kpoint(kpoint);
390 //------------------------------Centers
391 vector <string> centertext;
392 pos=startpos;
393 if(!readsection(words, pos, centertext, "CENTERS")) {
394 single_write(cout, "Defaulting to using the atoms as centers\n");
395 string temp="USEATOMS";
396 centertext.push_back(temp);
397 }
398
399
400 unsigned int newpos=0;
401 centers.read(centertext, newpos, sys);
402 centers.assignBasis(basis);
403
404 //cout << "number of centers " << centers.size() << endl;
405 totbasis=0;
406 maxbasis=0;
407 for(int i=0; i< centers.size(); i++)
408 {
409 int basiscent=0;
410 for(int j=0; j< centers.nbasis(i); j++)
411 {
412 basiscent+=basis(centers.basis(i,j))->nfunc();
413 //cout << "basiscent " << basiscent << endl;
414 }
415 totbasis+=basiscent;
416 if(maxbasis < basiscent)
417 maxbasis=basiscent;
418 }
419
420 //cout << "maxbasis " << maxbasis << endl;
421 //single_write(cout, nmo, " molecular orbitals requested.\n");
422
423 pos=0;
424 if(! readvalue(words, pos, orbfile, "ORBFILE"))
425 {
426 error("Must specify ORBFILE for MO matrix");
427 }
428 init();
429
430 }
431 //----------------------------------------------------------------------------
432
433 #endif // MO_MATRIX_H_INCLUDED
434
435 //----------------------------------------------------------------------------
436