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