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 #include "Periodic_sample.h"
22 #include "ulec.h"
23 #include "Wavefunction.h"
24 #include "Periodic_system.h"
25 
26 //----------------------------------------------------------------------
27 
generateStorage(Sample_storage * & store)28 void Periodic_sample::generateStorage(Sample_storage * & store)
29 {
30   int nions=parent->ions.size();
31   store=new Sample_storage;
32   store->iondist_temp.Resize(nions,5);
33   store->pointdist_temp.Resize(nelectrons,5);
34   store->pos_temp.Resize(3);
35 }
36 
saveUpdate(int e,Sample_storage * store)37 void Periodic_sample::saveUpdate(int e, Sample_storage * store)
38 {
39   getElectronPos(e, store->pos_temp);
40   int nions=parent->ions.size();
41   for(int d=0; d< 5; d++) {
42     for(int i=0; i< nions; i++)
43     {
44       store->iondist_temp(i,d)=iondist(i,e,d);
45     }
46     for(int i=0; i<e; i++)
47     {
48       store->pointdist_temp(i,d)=pointdist(i,e,d);
49     }
50     for(int j=e; j < nelectrons; j++)
51     {
52       store->pointdist_temp(j,d)=pointdist(e,j,d);
53     }
54   }
55 }
56 
restoreUpdate(int e,Sample_storage * store)57 void Periodic_sample::restoreUpdate(int e, Sample_storage * store){
58   for(int i=0; i<3; i++)
59     elecpos(e,i)=store->pos_temp(i);
60 
61   int nions=parent->ions.size();
62   for(int d=0; d< 5; d++)  {
63     for(int i=0; i< nions; i++)
64       iondist(i,e,d)=store->iondist_temp(i,d);
65 
66     for(int i=0; i<e; i++)
67       pointdist(i,e,d)=store->pointdist_temp(i,d);
68 
69     for(int j=e; j < nelectrons; j++)
70       pointdist(e,j,d)=store->pointdist_temp(j,d);
71   }
72   cenDistStale(e)=1; //Let's not save the center distances, but that means
73                      //we have to recalculate when we reject.
74 }
75 
76 
77 //----------------------------------------------------------------------
78 
79 
updateEIDist()80 void Periodic_sample::updateEIDist() {
81   //cout << "Periodic::updateEIDist" << endl;
82   //Array1 <doublevar> eivec(3);
83   for(int e=0; e< nelectrons; e++) {
84     if(ionDistStale(e)) {
85       ionDistStale(e)=0;
86       int nions=parent->ions.size();
87 
88       for(int ion=0; ion< nions; ion++) {
89         Array1 <doublevar> dr(3);
90         for(int d=0; d< 3; d++) dr(d)=elecpos(e,d)-parent->ions.r(d,ion);
91         doublevar dis=minimum_image(dr);
92 
93         for(int d=0; d< 3; d++) iondist(ion,e,d+2)=dr(d);
94         iondist(ion,e,1)=dis;
95 
96       }
97       for(int j=0; j<nions; j++)
98         iondist(j, e,0)=sqrt(iondist(j, e,1));
99     }
100   }
101 
102   //cout << "done " << endl;
103 
104 }
105 
106 
107 //----------------------------------------------------------------------
108 
109 /*!
110 
111  */
updateEEDist()112 void Periodic_sample::updateEEDist() {
113   const int ndim=3;
114   for(int e=0; e< nelectrons; e++) {
115     if(elecDistStale(e)==1) {
116 
117       elecDistStale(e)=0;
118       Array1 <doublevar> dr(3);
119       for(int j=0; j< e; j++) {
120         for(int d=0; d< 3; d++) dr(d)=elecpos(j,d)-elecpos(e,d);
121         doublevar dist=minimum_image(dr);
122         for(int d=0; d< 3; d++) pointdist(j,e,d+2)=dr(d);
123         pointdist(j,e,1)=dist;
124         pointdist(j,e,0)=sqrt(dist);
125       }
126       for(int k=e+1; k < nelectrons; k++) {
127         for(int d=0; d< 3; d++) dr(d)=elecpos(e,d)-elecpos(k,d);
128         doublevar dist=minimum_image(dr);
129         for(int d=0; d< 3; d++) pointdist(e,k,d+2)=dr(d);
130         pointdist(e,k,1)=dist;
131         pointdist(e,k,0)=sqrt(dist);
132       }
133 
134     }
135   }
136   //cout << "done" << endl;
137 }
138 
139 
140 
minDist(Array1<doublevar> pos1,Array1<doublevar> pos2,Array1<doublevar> & rmin)141 void Periodic_sample::minDist(Array1 <doublevar> pos1 , Array1 <doublevar> pos2, Array1<doublevar> &rmin) {
142   Array1 <doublevar> rminc(3);
143   for(int d=0; d<3; d++) rminc(d)=pos2(d) - pos1(d);
144   doublevar dist=minimum_image(rminc);
145   for(int d=0; d<3; d++) rmin(d) = rminc(d);
146   //cout << "done" << endl;
147 }
148 
149 //----------------------------------------------------------------------
updateECDist()150 void Periodic_sample::updateECDist() {
151   //cout << "periodic_sample::updateECDist() " << endl;
152   for(int e=0; e< nelectrons; e++)  {
153     if(cenDistStale(e)) {
154       cenDistStale(e)=0;
155       int ncenters=parent->centerpos.GetDim(0);
156       for(int j=0; j<ncenters; j++)
157       {
158         cendist(e,j,1)=0;
159       }
160 
161       for(int i=0; i<3; i++)
162       {
163         for(int j=0; j<ncenters; j++)
164         {
165           cendist(e,j, i+2)=elecpos(e,i)-parent->centerpos(j,i);
166           cendist(e,j,1)+=cendist(e,j, i+2) * cendist(e,j, i+2);
167         }
168       }
169 
170       for(int j=0; j<ncenters; j++)
171         cendist(e,j,0)=sqrt(cendist(e,j,1));
172     }
173   }
174   //cout << "done" << endl;
175 }
176 //----------------------------------------------------------------------
177 #include "qmc_io.h"
init(System * sys)178 void Periodic_sample::init(System * sys) {
179   assert(sys != NULL);
180   recast(sys, parent); //assign sys to parent
181 
182 
183   int nions=parent->ions.size();
184   nelectrons=parent->nelectrons(0)+parent->nelectrons(1);
185 
186   elecpos.Resize(nelectrons, 3);
187   iondist.Resize(nions,nelectrons,5);
188   pointdist.Resize(nelectrons, nelectrons,5);
189 
190   int ncenters=parent->centerpos.GetDim(0);
191   cendist.Resize(nelectrons,ncenters, 5);
192 
193 
194   elecDistStale.Resize(nelectrons);
195   ionDistStale.Resize(nelectrons);
196   cenDistStale.Resize(nelectrons);
197   cenDistStale=1;
198   elecDistStale=1;
199   ionDistStale=1;
200 
201   // update_overall_sign is false for complex-valued wavefunctions,
202   // i.e., for non-integer k-points
203   update_overall_sign=true;
204   for (int d=0; d<3; d++) {
205     doublevar intpart;
206     modf(parent->kpt(d),&intpart);
207     if ( parent->kpt(d) != intpart ) update_overall_sign=false;
208   }
209 
210   /*
211   if ( update_overall_sign ) {
212     cout << "Sample_point detects real-valued wave function." << endl;
213   } else {
214     cout << "Sample_point detects complex-valued wave function." << endl;
215   }
216   */
217 
218   //bool orthorhombic=true;
219   //for(int i=0; i< 3; i++) {
220   //  for(int j=i+1; j < 3; j++) {
221   //    doublevar dot=0.0;
222   //    for(int d=0; d< 3; d++) {
223   //      dot+=parent->latVec(i,d)*parent->latVec(j,d);
224   //    }
225   //    if(dot > 1e-10) orthorhombic=false;
226   //  }
227   //}
228   //if(orthorhombic) {
229   //  single_write(cout,"Detected orthorhombic cell");
230   //}
231   //else {
232     int counter=0;
233     int nsearch=1;
234     int nl=2*nsearch+1;
235     lattice_basis.Resize(nl*nl*nl,3);
236     lattice_basis=0.0;
237 
238     for(int aa=-nsearch; aa <= nsearch; aa++) {
239       for(int bb=-nsearch; bb <= nsearch; bb++) {
240         for(int cc=-nsearch; cc <= nsearch; cc++) {
241             for(int d=0; d< 3; d++) {
242               //For some bizarre reason, GCC misoptimizes this loop
243               //unless I put this (or some other meaningless) statement here
244               if(counter >-100) {
245               lattice_basis(counter,d)=aa*parent->latVec(0,d)
246                 +bb*parent->latVec(1,d)
247                 +cc*parent->latVec(2,d);
248               }
249             }
250             counter++;
251           }
252       }
253     }
254 
255 }
256 
257 //----------------------------------------------------------------------
258 
minimum_image(Array1<doublevar> & r)259 doublevar Periodic_sample::minimum_image(Array1 <doublevar> & r) {
260 
261   doublevar height2=parent->smallestheight*parent->smallestheight*.25;
262   int nlat=lattice_basis.GetDim(0);
263   //static Array1 <doublevar> tmpvec(3),rmin(3);
264   doublevar tmpvec[3],rmin[3];
265   doublevar tmpdis=0,dismin=1e99;
266   for(int d=0;d < 3; d++)
267     tmpdis+=r[d]*r[d];
268   if(tmpdis < height2) return tmpdis;
269 
270   for(int a=0; a < nlat; a++) {
271     tmpdis=0;
272     for(int d=0; d < 3; d++) {
273       tmpvec[d]=r(d)+lattice_basis(a,d);
274       tmpdis+=tmpvec[d]*tmpvec[d];
275     }
276     if(tmpdis < dismin) {
277       for(int d=0; d< 3; d++) rmin[d]=tmpvec[d];
278       dismin=tmpdis;
279       //cout << "dismin " << dismin << endl;
280       if(tmpdis< height2)
281         break;
282     }
283     if(tmpdis < height2) break;
284   }
285   for(int d=0; d< 3; d++) r[d]=rmin[d];
286   return dismin;
287 }
288 
289 
290 //----------------------------------------------------------------------
291 
randomGuess()292 void Periodic_sample::randomGuess()
293 {
294   const doublevar range=2.0;  //range of the cube around atoms to fill
295   Array1 <doublevar> trialPos(3);
296 
297   int e=0;
298   //Try to put them around the ions
299   //cout << "nions " << ions.size() << endl;
300   Array1 <doublevar> ioncenter(3); ioncenter=0;
301   for(int ion=0; ion < parent->ions.size(); ion++) {
302     for(int d=0;d < 3; d++) ioncenter(d)+=parent->ions.r(d,ion)/parent->ions.size();
303   }
304 
305   for(int spin=0; spin < 2; spin++) {
306     for(int ion=0; ion< parent->ions.size(); ion++)
307     {
308       //cout << "charge " << ions.charge(ion) << endl;
309       int laste=e;
310 
311       //putting half electrons, rounded up for the first iteration
312       //and rounded down for the second one.
313 
314       for(;
315           e-laste < int(parent->ions.charge(ion)/2)+(1-spin)*int(parent->ions.charge(ion))%2;
316           e++)
317       {
318         if(e< nelectrons) {
319           for(int d=0; d< 3; d++)
320           {
321             trialPos(d)=parent->ions.r(d,ion)+2*range*(rng.ulec()-.5);
322           }
323           setElectronPos(e,trialPos);
324         }
325       }
326     }
327   }
328 
329   //if(e > nelectrons)
330   //  error("internal:  electrons overflowed in Periodic_sample::randomGuess");
331 
332   //Throw the rest randomly around the center of the ions
333   for(;e<nelectrons; e++)
334   {
335     for(int d=0; d< 3; d++)
336     {
337       trialPos(d)=4*range*(rng.ulec()-.5)+ioncenter(d);
338     }
339     setElectronPos(e, trialPos);
340   }
341 
342   ionDistStale=1;
343   elecDistStale=1;
344   cenDistStale=1;
345 
346   if(wfObserver)
347   {
348     wfObserver->notify(all_electrons_move, 0);
349   }
350 
351 }
352 
353 
354 //----------------------------------------------------------------------
355 
setElectronPosNoNotify(const int e,const Array1<doublevar> & position)356 void Periodic_sample::setElectronPosNoNotify(const int e,
357                                    const Array1 <doublevar> & position)
358 {
359 
360   assert( position.GetDim(0) == 3 );
361   Array1 <doublevar> temp(position.GetDim(0));
362   temp=position;
363   Array1 <int> nshift;
364   parent->enforcePbc(temp, nshift);
365 
366   for(int i=0; i<3; i++)
367   {
368     //points.r(i,e) = temp(i);
369     elecpos(e,i)=temp(i);
370   }
371   ionDistStale(e)=1;
372   elecDistStale(e)=1;
373   cenDistStale(e)=1;
374 }
375 
setElectronPos(const int e,const Array1<doublevar> & position)376 void Periodic_sample::setElectronPos(const int e,
377     const Array1 <doublevar> & position) {
378   setElectronPosNoNotify(e,position);
379 
380   if(wfObserver)
381   {
382     wfObserver->notify(electron_move, e);
383   }
384 
385 }
386 
387 
translateElectron(const int e,const Array1<doublevar> & trans)388 void Periodic_sample::translateElectron(const int e, const Array1 <doublevar> & trans) {
389   Array1 <doublevar> temp(trans.GetDim(0));
390 
391   for(int d=0; d< 3; d++)
392     temp(d)=elecpos(e,d)+trans(d);
393   Array1<int> nshift;
394   parent->enforcePbc(temp, nshift);
395   doublevar kdotr=0;
396   for(int d=0; d< 3; d++)
397     kdotr+=parent->kpt(d)*nshift(d);
398   if ( update_overall_sign ) overall_sign*=cos(pi*kdotr);
399   // the sign of the phase here is critical for correct evaluation of
400   // pseudopotentials (and density matrices)
401   overall_phase-=pi*kdotr;
402   // I suppose the value of overall_phase averages around zero, no
403   // "modulo" operation should be needed
404   //overall_phase=overall_phase - 2*pi * (int) (overall_phase/pi/2);
405 
406   //if(fabs(kdotr) > 1e-8)
407   //  cout << "shift " << nshift(0) << "   "
408   //      << nshift(1) << "   " << nshift(2) << endl;
409 
410   for(int i=0; i<3; i++)
411     elecpos(e,i)=temp(i);
412 
413   ionDistStale(e)=1;
414   elecDistStale(e)=1;
415   cenDistStale(e)=1;
416 
417   if(wfObserver)
418     wfObserver->notify(electron_move, e);
419 
420 }
421 
422 //----------------------------------------------------------------------
423 
424 /*!
425 \bug
426 This can possibly screw up if we have more than one sample_point for a system,
427 and are moving ions for each.  We shouldn't be keeping more than one sample_point
428 in memory, eventually, anyway, but for now, be careful.  We shouldn't move this
429 to sys, because we're eventually going to treat the ions as quantum particles..
430 The solution is to move the ion positions to the sample_point and generalize the
431 Periodic_system calculation of energies..  Also keep in mind k-points!!
432 */
moveIon(const int ion,const Array1<doublevar> & r)433 void Periodic_sample::moveIon(const int ion, const Array1 <doublevar> & r) {
434   assert(r.GetDim(0) >= 3);
435 
436 
437   Array1 <doublevar> temp(r.GetDim(0));
438   temp=r;
439   Array1<int> nshift;
440   parent->enforcePbc(temp, nshift);
441 
442   Array1 <doublevar> oldr(3);
443   getIonPos(ion, oldr);
444   Array1 <doublevar> deltar(3);
445   for(int i=0; i< 3; i++) {
446     deltar(i)=temp(i)-oldr(i);
447   }
448 
449   for(int d=0; d< 3; d++) {
450     parent->ions.r(d,ion)=temp(d);
451     for(int n=0; n< parent->ncenters_atom(ion); n++) {
452       parent->centerpos(parent->equiv_centers(ion, n), d)+=deltar(d);
453     }
454   }
455 
456   //int ncenters=parent->centerpos.GetDim(0);
457   //for(int c=0; c< ncenters; c++) {
458   //  for(int d=0; d< 3; d++)
459   //    cout << parent->centerpos(c,d) << "  ";
460   //  cout << endl;
461   //}
462 
463   parent->ion_ewald=parent->ewaldIon();
464   //cout << "ewaldIon_done" << endl;
465   ionDistStale=1;
466   elecDistStale=1;
467   cenDistStale=1;
468 
469   //cout << "notify " << endl;
470   if(wfObserver)
471     wfObserver->notify(ion_move, ion);
472 
473   //cout << "done " << endl;
474 }
475 
476 
477 //----------------------------------------------------------------------
478 
479 #include <iomanip>
480 
rawOutput(ostream & os)481 void Periodic_sample::rawOutput(ostream & os)
482 {
483   os << "Periodic_sample\n";
484   os << "numIons  " << parent->ions.size() << endl;
485   for(int i=0; i< parent->ions.size(); i++)
486   {
487     for(int d=0; d< 3; d++)
488     {
489       os << setw(20) << setprecision(12) << parent->ions.r(d,i);
490     }
491     os << "\n";
492   }
493   os << "   numElectrons   " << nelectrons << endl;
494   for(int e=0; e< nelectrons; e++)
495   {
496     for(int d=0; d< 3; d++)
497     {
498       os << setw(20) << setprecision(12) << elecpos(e,d);
499     }
500     os << "\n";
501   }
502 }
503 
504 
rawInput(istream & is)505 void Periodic_sample::rawInput(istream & is)
506 {
507   string text;
508   int nions;
509   is >> text;
510   if(text != "Periodic_sample")
511     error("expected Periodic_sample, got ", text);
512 
513   is >> text;
514         //cout << "distance " << dis << " " << iondist(ion,e,1) << endl;
515   if(text != "numIons")
516     error("expected numIons, got ", text);
517 
518   is >> nions;
519   //cout << "ions" << endl;
520   Array2 <doublevar> old_ionpos(nions,3);
521   for(int i=0; i< nions; i++)  {
522     for(int d=0; d< 3; d++)    {
523       is >> old_ionpos(i,d);
524     }
525     //cout << endl;
526   }
527 
528   is >> text;
529   if(text != "numElectrons")
530     error("expected numElectrons, got ", text);
531   //cout << "electrons " << endl;
532   is >> nelectrons;
533   for(int e=0; e< nelectrons; e++)
534         //cout << "distance " << dis << " " << iondist(ion,e,1) << endl;
535   {
536     for(int d=0; d< 3; d++)
537     {
538       is >> elecpos(e,d);
539 
540     }
541   }
542 
543   //shift the electronic positions if the ions have moved
544   updateEIDist();
545   for(int e=0; e< nelectrons; e++) {
546     Array1 <doublevar> displace(3,0.0);
547     doublevar norm=0.0;
548     Array1 <doublevar> dist(5);
549     for(int at=0; at < nions; at++) {
550       getEIDist(e,at, dist);
551       doublevar z=getIonCharge(at);
552       doublevar func=z/(dist(1)*dist(1));
553       norm+=func;
554       //cout << "func " << func << "  dist " << dist(1) <<
555       //  "  z " << z << endl;
556       for(int d=0; d< 3; d++)
557 	displace(d) += func*(parent->ions.r(d,at)-old_ionpos(at,d));
558     }
559     //cout << "norm = " << norm << endl;
560     if(norm>1e-14) {
561       for(int d=0; d< 3; d++)
562         elecpos(e,d)+=displace(d)/norm;
563       //cout << "displacing electron " << e << " by "
564       //     << displace(0)/norm << "   " << displace(1)/norm
565       //     << "   " << displace(2)/norm << endl;
566     }
567   }
568   ionDistStale=1;
569   elecDistStale=1;
570   cenDistStale=1;
571 
572 }
573 
574 //-------------------------------------------------------------------------
575