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 
22 #include "Molecular_system.h"
23 #include "Array.h"
24 #include "Wavefunction.h"
25 #include "Sample_point.h"
26 #include "Molecular_sample.h"
27 #include "qmc_io.h"
28 
notify(change_type change,int n)29 void Molecular_system::notify(change_type change, int n)
30 {
31   switch(change) {
32   default:
33     cout << "WARNING: Molecular system got a signal that it doesn't know: "
34     << change << endl;
35   }
36 }
37 
38 
generateSample(Sample_point * & samptr)39 int Molecular_system::generateSample(Sample_point *& samptr)
40 {
41   assert(samptr==NULL);
42   samptr=new Molecular_sample;
43   samptr->init(this);
44   return 1;
45 }
46 
showinfo(ostream & os)47 int Molecular_system::showinfo(ostream & os)
48 {
49   ions.showinfo(os);
50   return 1;
51 }
52 
read(vector<string> & words,unsigned int & pos)53 int Molecular_system::read(vector <string> & words,
54                            unsigned int & pos)
55 {
56   nspin.Resize(2);
57   unsigned int startpos=pos;
58   vector <string> spintxt;
59   if(!readsection(words, pos, spintxt, "NSPIN")) {
60     error("Need NSPIN in molecular system");
61   }
62   nspin(0)=atoi(spintxt[0].c_str());
63   nspin(1)=atoi(spintxt[1].c_str());
64 
65   //restrcit initial walkers to a given range
66   vector <string> inirangetxt;
67   if(readsection(words, pos=0, inirangetxt, "INIRANGE")) {
68     cout << "You are using a range of initial walkers other than default." << endl;
69     if(inirangetxt.size()==0){
70       error("You want to restrict the range of initial walkers, but you didn't give a range");
71     }
72     inirange=atof(inirangetxt[0].c_str());
73   }
74   else {
75     inirange=3.0;
76   }
77 
78   //use a bounding box if it's given
79   vector <string> boxtxt;
80   if(readsection(words, pos=0, boxtxt, "BOUNDING_BOX")) {
81     const int ndim=3;
82     if(boxtxt.size() != ndim*ndim) {
83       error("need ", ndim*ndim," elements in BOUNDING_BOX");
84     }
85     Array2 <doublevar> latVec(ndim, ndim);
86     for(int i=0; i< ndim; i++) {
87       for(int j=0; j< ndim; j++) {
88         latVec(i,j)=atof(boxtxt[i*ndim+j].c_str());
89       }
90     }
91     Array1 <doublevar> origin(ndim);
92     origin=0;
93     vector <string> origintxt;
94     if(readsection(words, pos=0, origintxt, "ORIGIN")) {
95       for(int i=0; i < ndim; i++) origin(i)=atof(origintxt[i].c_str());
96     }
97     bounding_box.init(latVec);
98     bounding_box.setOrigin(origin);
99     use_bounding_box=1;
100   }
101   else {
102     use_bounding_box=0;
103   }
104 
105 
106 
107   ions.read(words, pos=0);
108   int natoms=ions.size();
109   for(int i=0; i< natoms; i++) {
110     atomLabels.push_back(ions.getLabel(i));
111   }
112 
113 
114   electric_field.Resize(3);
115   electric_field=0;
116   vector <string> electxt;
117   if(readsection(words, pos=0, electxt, "ELECTRIC_FIELD")) {
118     if(electxt.size()!=3) error("ELECTRIC_FIELD must have 3 components");
119     for(int d=0; d< 3; d++) {
120       electric_field(d)=atof(electxt[d].c_str());
121       //cout << "efield " << electric_field(d) << endl;
122     }
123   }
124 
125 
126   //---Pseudopotential
127   pos=startpos;
128   vector < vector <string> > pseudotext;
129   vector <string> pseudotexttmp;
130   if(readsection(words, pos, pseudotexttmp, "PSEUDO") != 0) {
131     error("PSEUDO should go in the global space");
132     pseudotext.push_back(pseudotexttmp);
133   }
134 
135   //pseudo.read(pseudotext, this);
136   return 1;
137 }
138 
139 //----------------------------------------------------------------------
140 
setIonPos(int ion,Array1<doublevar> & r)141 void Molecular_system::setIonPos(int ion, Array1 <doublevar> & r)
142 {
143   assert(r.GetDim(0) >=3);
144   Array1 <doublevar> temp(r.GetDim(0));
145   temp=r;
146   if(use_bounding_box) {
147     bounding_box.enforcePbc(temp);
148   }
149 
150 
151   for(int i=0; i< 3; i++) {
152 
153     ions.r(i,ion)=temp(i);
154   }
155 }
156 
157 
158 
159 //------------------------------------------------------------------------
160 
161 
162 
calcLocWithTestPos(Sample_point * sample,Array1<doublevar> & tpos,Array1<doublevar> & Vtest)163 void Molecular_system::calcLocWithTestPos(Sample_point * sample,
164                                           Array1 <doublevar> & tpos,
165                                           Array1 <doublevar> & Vtest) {
166 
167   int nions=sample->ionSize();
168   int nelectrons=sample->electronSize();
169   Vtest.Resize(nelectrons + 1);
170   Vtest = 0;
171   Array1 <doublevar> oldpos(3);
172   //cout << "Calculating local energy\n";
173   sample->getElectronPos(0, oldpos);
174   sample->setElectronPosNoNotify(0, tpos);
175 
176   Array1 <doublevar> R(5);
177 
178   sample->updateEIDist();
179   sample->updateEEDist();
180 
181   for(int i=0; i < nions; i++) {
182     sample->getEIDist(0, i, R);
183     Vtest(nelectrons)+=-sample->getIonCharge(i)/R(0);
184   }
185   doublevar dist = 0.0;
186   for(int d=0; d<3; d++)  {
187     dist += (oldpos(d) - tpos(d))*(oldpos(d) - tpos(d));
188   }
189   dist = sqrt(dist);
190   Vtest(0) = 1/dist;
191   Array1 <doublevar> R2(5);
192   for(int i=1; i< nelectrons; i++) {
193     sample->getEEDist(0,i,R2);
194     Vtest(i)= 1/R2(0);
195   }
196   sample->setElectronPosNoNotify(0, oldpos);
197   sample->updateEIDist();
198   sample->updateEEDist();
199   //cout << "elec-elec: " << elecElec << endl;
200   //cout << "pot " << pot << endl;
201 
202   for(int d=0; d< 3; d++)
203     Vtest(nelectrons) -=electric_field(d)*tpos(d);
204 }
205 
206 
207 //------------------------------------------------------------------------
208 
calcLoc(Sample_point * sample)209 doublevar Molecular_system::calcLoc(Sample_point * sample) {
210   int nions=sample->ionSize();
211   int nelectrons=sample->electronSize();
212 
213   //cout << "Calculating local energy\n";
214 
215   Array1 <doublevar> R(5);
216   doublevar pot=0;
217 
218   doublevar elecIon=0;
219   sample->updateEIDist();
220   sample->updateEEDist();
221 
222   for(int e=0; e< nelectrons; e++)
223   {
224     for(int i=0; i < nions; i++)
225     {
226 
227       sample->getEIDist(e,i, R);
228       elecIon+=sample->getIonCharge(i)/R(0);
229     }
230   }
231   elecIon*=-1;
232   pot+=elecIon;
233 
234   //cout << "elec-ion: " << elecIon << endl;
235   Array1 <doublevar> r1(3), r2(3);
236   doublevar IonIon=0;
237   for(int i=0; i< nions; i++)
238   {
239     sample->getIonPos(i,r1);
240     //cout << i << "   " << r1(2) << endl;
241     for(int j=0; j<i; j++)
242     {
243       sample->getIonPos(j,r2);
244       doublevar r=sqrt( (r1(0)-r2(0))*(r1(0)-r2(0))
245                         + (r1(1)-r2(1))*(r1(1)-r2(1))
246                         + (r1(2)-r2(2))*(r1(2)-r2(2)));
247       IonIon+=sample->getIonCharge(i)*sample->getIonCharge(j)/r;
248     }
249   }
250   pot+=IonIon;
251 
252   //cout << "Ion-ion: " << IonIon << endl;
253 
254   doublevar elecElec=0;
255   Array1 <doublevar> R2(5);
256   for(int i=0; i< nelectrons; i++)
257   {
258     for(int j=0; j<i; j++)
259     {
260       sample->getEEDist(j,i,R2);
261       elecElec+= 1/R2(0);
262     }
263   }
264   pot+=elecElec;
265   //cout << "elec-elec: " << elecElec << endl;
266   //cout << "pot " << pot << endl;
267 
268   doublevar fieldPot=0;
269   Array1 <doublevar> pos(3);
270   for(int e=0; e< nelectrons; e++) {
271     sample->getElectronPos(e,pos);
272     for(int d=0; d< 3; d++)
273       fieldPot-=electric_field(d)*pos(d);
274   }
275   for(int i=0; i< nions; i++) {
276     sample->getIonPos(i,pos);
277     for(int d=0; d< 3; d++)
278       fieldPot+=sample->getIonCharge(i)*electric_field(d)*pos(d);
279   }
280 
281   pot+=fieldPot;
282 
283   return pot;
284 }
285 
286 
287 
288 
calcLocSeparated(Sample_point * sample,Array1<doublevar> & PotLoc)289 void Molecular_system::calcLocSeparated(Sample_point * sample, Array1<doublevar> & PotLoc)
290 {
291   Array1 <doublevar> onebody;
292   Array2 <doublevar> twobody;
293   separatedLocal(sample, onebody, twobody);
294   int nelectrons = sample->electronSize();
295   PotLoc = 0.0;
296   for (int e = 0; e < nelectrons; e++) {
297     PotLoc(e) += onebody(e);
298     for (int ep =e+1; ep < nelectrons; ep ++) {
299       PotLoc(e) += twobody(e, ep);
300       PotLoc(ep) += twobody(e, ep);
301     }
302   }
303   /*
304   int nions=sample->ionSize();
305   int nelectrons=sample->electronSize();
306 
307   //cout << "Calculating local energy\n";
308 
309   Array1 <doublevar> R(5);
310   doublevar pot=0;
311 
312   doublevar elecIon=0;
313   sample->updateEIDist();
314   sample->updateEEDist();
315   PotLoc = 0.0;
316   for(int e=0; e< nelectrons; e++)
317   {
318 
319     // Electron-ion interaction
320     for(int i=0; i < nions; i++)
321     {
322       sample->getEIDist(e,i, R);
323       PotLoc(e) += -sample->getIonCharge(i)/R(0);
324     }
325     // Electron-electron interaction
326     for(int i=0; i<e; i++) {
327       sample->getEEDist(i,e, R); // noted that the first index should be smaller than the second index
328       PotLoc(e) += 1/R(0);
329       PotLoc(i) += 1/R(0);
330     }
331 
332     // Local external field
333     Array1 <doublevar> pos(3);
334     sample->getElectronPos(e,pos);
335     for(int d=0; d< 3; d++)
336       PotLoc(e) += -electric_field(d)*pos(d);
337   }
338   */
339 }
340 
341 //----------------------------------------------------------------------
342 //Keeping this separate from calcLoc for efficiency reasons..
343 //It's most likely faster to add to a double than fill matrices..
344 //We also don't need to calculate the ion-ion interaction for this
separatedLocal(Sample_point * sample,Array1<doublevar> & onebody,Array2<doublevar> & twobody)345 void Molecular_system::separatedLocal(Sample_point * sample,Array1 <doublevar> & onebody,
346     Array2 <doublevar> & twobody)
347 {
348   int nions=sample->ionSize();
349   int nelectrons=sample->electronSize();
350   onebody.Resize(nelectrons);
351   twobody.Resize(nelectrons,nelectrons);
352   onebody=0.0; twobody=0.0;
353   Array1 <doublevar> R(5);
354   sample->updateEIDist();
355   sample->updateEEDist();
356 
357   for(int e=0; e< nelectrons; e++) {
358     for(int i=0; i < nions; i++) {
359       sample->getEIDist(e,i, R);
360       onebody(e)-=sample->getIonCharge(i)/R(0);
361     }
362   }
363   Array1 <doublevar> R2(5);
364   for(int i=0; i< nelectrons; i++) {
365     for(int j=i+1; j<nelectrons; j++) {
366       sample->getEEDist(i,j,R2);
367       twobody(i,j)+= 1/R2(0);
368     }
369   }
370 
371   Array1 <doublevar> pos(3);
372   for(int e=0; e< nelectrons; e++) {
373     sample->getElectronPos(e,pos);
374     for(int d=0; d< 3; d++)
375       onebody(e)-=electric_field(d)*pos(d);
376   }
377 }
378 
379 //----------------------------------------------------------------------
380 
locDerivative(int ion,Sample_point * sample,Force_fitter & fitter,Array1<doublevar> & der)381 void Molecular_system::locDerivative(int ion, Sample_point * sample,
382                                      Force_fitter & fitter,
383                                      Array1 <doublevar> & der) {
384 
385   sample->updateEIDist();
386   der.Resize(3);
387   der=0;
388   Array1 <doublevar> R(5);
389   int ne=sample->electronSize();
390   Array1 <doublevar> tmpder(3), tmpder_fit(3);
391   for(int e=0; e< ne; e++) {
392     sample->getEIDist(e,ion, R);
393     for(int d=0; d< 3; d++)
394       //der(d)-=sample->getIonCharge(ion)*R(d+2)/(R(1)*R(0));
395       tmpder(d)=-sample->getIonCharge(ion)*R(d+2)/(R(1)*R(0));
396     fitter.fit_force(R,tmpder, tmpder_fit);
397     for(int d=0; d< 3; d++)
398       der(d)+=tmpder_fit(d);
399   }
400 
401   Array1 <doublevar> vec(3);
402   Array1 <doublevar> r_ion(3);
403   sample->getIonPos(ion, r_ion);
404 
405   int nIon=sample->ionSize();
406 
407   for(int j=0; j< nIon; j++) {
408     if(j!=ion) {
409     sample->getIonPos(j,R);
410     doublevar r2=0;
411     for(int d=0; d <3; d++)
412       vec(d)=r_ion(d)-R(d);
413 
414     for(int d=0; d< 3; d++)
415       r2+=vec(d)*vec(d);
416     doublevar r=sqrt(r2);
417 
418     for(int d=0; d< 3; d++)
419       der(d)-=sample->getIonCharge(ion)*sample->getIonCharge(j)*vec(d)/(r2*r);
420     }
421   }
422 
423 }
424 
425 //------------------------------------------------------------------------
426 
427 
getBounds(Array2<doublevar> & latticevec,Array1<doublevar> & origin)428 int Molecular_system::getBounds(Array2 <doublevar> & latticevec,Array1<doublevar> & origin) {
429   cout << "getBounds()" << endl;
430   latticevec.Resize(3,3);
431   latticevec=0.0;
432   Array1 <doublevar> minmax(6);
433   for(int d=0; d< 3; d++) {
434     minmax(2*d)=minmax(2*d+1)=0.0;
435   }
436 
437   int nions=nIons();
438   Array1 <doublevar> ionpos(3);
439   for(int i=0; i< nions; i++) {
440     getIonPos(i,ionpos);
441     for(int d=0; d< 3; d++) {
442       if(ionpos(d) < minmax(2*d)) minmax(2*d) = ionpos(d);
443       if(ionpos(d) > minmax(2*d+1)) minmax(2*d+1)=ionpos(d);
444     }
445   }
446 
447   for(int d=0; d< 3; d++) {
448     origin(d)=minmax(2*d)-8.0;
449     latticevec(d,d)=minmax(2*d+1)-origin(d)+8.0;
450   }
451   return 1;
452 }
453