1 /*
2 
3 Copyright (C) 2007 Lucas K. Wagner, Jindrich Kolorenc
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 
23 #include "HEG_sample.h"
24 #include "ulec.h"
25 #include "Wavefunction.h"
26 #include "HEG_system.h"
27 
28 //----------------------------------------------------------------------
29 
generateStorage(Sample_storage * & store)30 void HEG_sample::generateStorage(Sample_storage * & store)
31 {
32   store=new Sample_storage;
33   store->pointdist_temp.Resize(nelectrons,5);
34   store->pos_temp.Resize(3);
35 }
36 
saveUpdate(int e,Sample_storage * store)37 void HEG_sample::saveUpdate(int e, Sample_storage * store)
38 {
39   getElectronPos(e, store->pos_temp);
40   for(int d=0; d< 5; d++) {
41     for(int i=0; i<e; i++)
42     {
43       store->pointdist_temp(i,d)=pointdist(i,e,d);
44     }
45     for(int j=e; j < nelectrons; j++)
46     {
47       store->pointdist_temp(j,d)=pointdist(e,j,d);
48     }
49   }
50 }
51 
restoreUpdate(int e,Sample_storage * store)52 void HEG_sample::restoreUpdate(int e, Sample_storage * store){
53   for(int i=0; i<3; i++) {
54     elecpos(e,i)=store->pos_temp(i);
55   }
56   for(int d=0; d< 5; d++)  {
57 
58     for(int i=0; i<e; i++)
59       pointdist(i,e,d)=store->pointdist_temp(i,d);
60 
61     for(int j=e; j < nelectrons; j++)
62       pointdist(e,j,d)=store->pointdist_temp(j,d);
63   }
64 }
65 
66 
67 
68 //----------------------------------------------------------------------
69 
70 /*!
71 
72  */
updateEEDist()73 void HEG_sample::updateEEDist() {
74 
75 #define ORTHOGONAL_CELL 1
76 
77 #ifdef ORTHOGONAL_CELL
78 
79   // Fast evaluation of electron electron distances. Unfortunately,
80   // it REQUIRES simple ORTHOGONAL simulation cell and thus cannot
81   // be used in general crystalline environment (for homogeneous
82   // gas such a loss of generality does not matter, does it?). It
83   // is tempting to replace 1/latVec with recipLatVec and do proper
84   // matrix multiplications, but as noted above, it is flawed as
85   // a general concept.
86   Array1 <doublevar> dist_lc(3);
87   for(int e=0; e< nelectrons; e++) {
88     if(elecDistStale(e)==1) {
89       for (int d=0; d<3; d++)
90 	elecpos_lc(e,d)=elecpos(e,d)/parent->latVec(d,d);
91     }
92   }
93 
94   for(int e=0; e< nelectrons; e++) {
95     if(elecDistStale(e)==1) {
96 
97       elecDistStale(e)=0;
98 
99       for(int j=0; j< e; j++) {
100         for(int d=0; d< 3; d++) {
101           dist_lc(d)=elecpos_lc(j,d)-elecpos_lc(e,d);
102 	  dist_lc(d)-=floor(dist_lc(d)+0.5);
103 	}
104 	pointdist(j,e,1)=0.0;
105 	for (int d=0; d<3; d++) {
106 	  pointdist(j,e,d+2)=parent->latVec(d,d)*dist_lc(d);
107 	  pointdist(j,e,1)+=pointdist(j,e,d+2)*pointdist(j,e,d+2);
108 	}
109 	pointdist(j,e,0)=sqrt(pointdist(j,e,1));
110       }
111 
112       for(int k=e+1; k< nelectrons; k++) {
113 	for(int d=0; d< 3; d++) {
114 	  dist_lc(d)=elecpos_lc(e,d)-elecpos_lc(k,d);
115 	  dist_lc(d)-=floor(dist_lc(d)+0.5);
116 	}
117 	pointdist(e,k,1)=0.0;
118 	for (int d=0; d<3; d++) {
119 	  pointdist(e,k,d+2)=parent->latVec(d,d)*dist_lc(d);
120 	  pointdist(e,k,1)+=pointdist(e,k,d+2)*pointdist(e,k,d+2);
121 	}
122 	pointdist(e,k,0)=sqrt(pointdist(e,k,1));
123       }
124 
125     } // if(elecDistStale(e)==1) {
126   }  // loop over electrons
127 
128 #else
129   // Original Lucas version from Periodic_sample
130   for(int e=0; e< nelectrons; e++) {
131     if(elecDistStale(e)==1) {
132 
133       elecDistStale(e)=0;
134       for(int j=0; j<e; j++) {
135         pointdist(j, e,1)=0.0;
136       }
137       for(int k=e+1; k<nelectrons; k++) {
138         pointdist(e,k,1)=0.0;
139       }
140 
141       //Find the closest image
142       Array1 <doublevar> tmpvec(3);
143       doublevar tmpdis;
144       doublevar height2=parent->smallestheight*parent->smallestheight*.25;
145 
146       for(int j=0; j< e; j++) {
147         //first try within the primitive cell
148         for(int d=0; d< 3; d++)
149           pointdist(j,e,d+2)=elecpos(j,d)-elecpos(e,d);
150         for(int d=0; d< 3; d++)
151           pointdist(j,e,1)+=pointdist(j,e,d+2)*pointdist(j,e,d+2);
152 
153         //then check outside if we haven't found the minimum image
154         if(pointdist(j,e,1) > height2) {
155           for(int a=0; a< 26; a++) {
156             for(int d=0; d< 3; d++)
157               tmpvec(d)=elecpos(j,d)-elecpos(e,d)+tmplat(a,d);
158 
159             tmpdis=0;
160             for(int d=0; d<3; d++) tmpdis+=tmpvec(d)*tmpvec(d);
161 
162             if(tmpdis < pointdist(j,e,1)) {
163               pointdist(j,e,1)=tmpdis;
164               for(int d=0; d< 3; d++) {
165                 pointdist(j, e, d+2)=tmpvec(d);
166               }
167             }
168             if(tmpdis < height2)
169               break;
170           }
171         }
172       }
173 
174       for(int k=e+1; k< nelectrons; k++) {
175         //first try within the primitive cell
176         for(int d=0; d< 3; d++)
177           pointdist(e,k,d+2)=elecpos(e,d)-elecpos(k,d);
178         for(int d=0; d< 3; d++)
179           pointdist(e,k,1)+=pointdist(e,k,d+2)*pointdist(e,k,d+2);
180 
181         //then check outside if we haven't found the minimum image
182         if(pointdist(e,k,1) > height2) {
183           for(int a=0; a< 26; a++) {
184             for(int d=0; d< 3; d++)
185               tmpvec(d)=elecpos(e,d)-elecpos(k,d)+tmplat(a,d);
186 
187             tmpdis=0;
188             for(int d=0; d<3; d++) tmpdis+=tmpvec(d)*tmpvec(d);
189 
190             if(tmpdis < pointdist(e,k,1)) {
191               pointdist(e,k,1)=tmpdis;
192               for(int d=0; d< 3; d++) {
193                 pointdist(e, k, d+2)=tmpvec(d);
194               }
195             }
196             if(tmpdis < height2)
197               break;
198           }
199         }
200       }
201 
202       //---------------------------
203       for(int j=0; j<e; j++) {
204         pointdist(j, e,0)=sqrt(pointdist(j, e,1));
205 	//cout << j << " " << e << " " << pointdist(j,e,2) << endl;
206       }
207       for(int k=e+1; k<nelectrons; k++) {
208         pointdist(e, k,0)=sqrt(pointdist(e, k,1));
209 	//cout << e << " " << k << " " << pointdist(e,k,2) << endl;
210       }
211 
212     } // if(elecDistStale(e)==1) {
213   }  // loop over electrons
214 
215 #endif
216 
217 }
218 
219 
220 //----------------------------------------------------------------------
221 
init(System * sys)222 void HEG_sample::init(System * sys) {
223   assert(sys != NULL);
224   recast(sys, parent); //assign sys to parent
225 
226   nelectrons=parent->nelectrons(0)+parent->nelectrons(1);
227 
228   elecpos.Resize(nelectrons, 3);
229   pointdist.Resize(nelectrons, nelectrons,5);
230   elecpos_lc.Resize(nelectrons, 3);
231 
232   elecDistStale.Resize(nelectrons);
233   elecDistStale=1;
234 
235   tmplat.Resize(26,3);
236   int counter=0;
237   for(int aa=-1; aa <= 1; aa++) {
238     for(int bb=-1; bb <= 1; bb++) {
239       for(int cc=-1; cc <= 1; cc++) {
240 	if(aa!=0 || bb !=0 || cc!=0) {
241 	  for(int d=0; d< 3; d++) {
242 	    tmplat(counter,d)=aa*parent->latVec(0,d)
243 	      +bb*parent->latVec(1,d)
244 	      +cc*parent->latVec(2,d);
245 	  }
246 	  counter++;
247 	}
248       }
249     }
250   }
251 
252   // update_overall_sign is false for complex-valued wavefunctions,
253   // i.e., for non-integer k-points
254   update_overall_sign=true;
255   for (int d=0; d<3; d++) {
256     doublevar intpart;
257     modf(parent->kpt(d),&intpart);
258     if ( parent->kpt(d) != intpart ) update_overall_sign=false;
259   }
260 
261 }
262 
263 
264 //----------------------------------------------------------------------
265 
randomGuess()266 void HEG_sample::randomGuess()
267 {
268   Array1 <doublevar> trialPos(3);
269 
270   // homogeneous distribution of electrons in the simulation cell
271   for(int e=0; e<nelectrons; e++)
272   {
273     doublevar rn0=rng.ulec();
274     doublevar rn1=rng.ulec();
275     doublevar rn2=rng.ulec();
276     for(int d=0; d< 3; d++)
277     {
278       trialPos(d)=rn0*parent->latVec(0,d) +
279 	rn1*parent->latVec(1,d) + rn2*parent->latVec(2,d);
280     }
281     setElectronPos(e, trialPos);
282   }
283 
284   elecDistStale=1;
285 
286   if(wfObserver)
287   {
288     wfObserver->notify(all_electrons_move, 0);
289   }
290 
291 }
292 
293 
294 //----------------------------------------------------------------------
295 
setElectronPos(const int e,const Array1<doublevar> & position)296 void HEG_sample::setElectronPos(const int e,
297                                    const Array1 <doublevar> & position)
298 {
299 
300   assert( position.GetDim(0) == 3 );
301   Array1 <doublevar> temp(position.GetDim(0));
302   temp=position;
303   Array1 <int> nshift;
304   parent->enforcePbc(temp, nshift);
305 
306   for(int i=0; i<3; i++)
307   {
308     //points.r(i,e) = temp(i);
309     elecpos(e,i)=temp(i);
310   }
311   elecDistStale(e)=1;
312 
313   if(wfObserver)
314   {
315     wfObserver->notify(electron_move, e);
316   }
317 
318 }
319 
320 
translateElectron(const int e,const Array1<doublevar> & trans)321 void HEG_sample::translateElectron(const int e, const Array1 <doublevar> & trans) {
322   Array1 <doublevar> temp(trans.GetDim(0));
323 
324   for(int d=0; d< 3; d++)
325     temp(d)=elecpos(e,d)+trans(d);
326   Array1<int> nshift;
327   parent->enforcePbc(temp, nshift);
328   doublevar kdotr=0;
329   for(int d=0; d< 3; d++)
330     kdotr+=parent->kpt(d)*nshift(d);
331   if ( update_overall_sign ) overall_sign*=cos(pi*kdotr);
332   // the sign of the phase here is critical for correct evaluation of
333   // density matrices
334   overall_phase-=pi*kdotr;
335   // I suppose the value of overall_phase averages around zero, no
336   // "modulo" operation should be needed
337   //overall_phase=overall_phase - 2*pi * (int) (overall_phase/pi/2);
338 
339   //if(fabs(kdotr) > 1e-8)
340   //  cout << "shift " << nshift(0) << "   "
341   //      << nshift(1) << "   " << nshift(2) << endl;
342 
343   for(int i=0; i<3; i++)
344     elecpos(e,i)=temp(i);
345 
346   elecDistStale(e)=1;
347 
348   if(wfObserver)
349     wfObserver->notify(electron_move, e);
350 
351 }
352 
353 //----------------------------------------------------------------------
354 
355 #include <iomanip>
356 
rawOutput(ostream & os)357 void HEG_sample::rawOutput(ostream & os)
358 {
359   os << "HEG_sample\n";
360   os << "   numElectrons   " << nelectrons << endl;
361   for(int e=0; e< nelectrons; e++)
362   {
363     for(int d=0; d< 3; d++)
364     {
365       os << setw(20) << setprecision(12) << elecpos(e,d);
366     }
367     os << "\n";
368   }
369 }
370 
371 
rawInput(istream & is)372 void HEG_sample::rawInput(istream & is)
373 {
374   string text;
375   is >> text;
376   if(text != "HEG_sample")
377     error("expected HEG_sample, got ", text);
378 
379   is >> text;
380   if(text != "numElectrons")
381     error("expected numElectrons, got ", text);
382   //cout << "electrons " << endl;
383   is >> nelectrons;
384   for(int e=0; e< nelectrons; e++)
385   {
386     for(int d=0; d< 3; d++)
387     {
388       is >> elecpos(e,d);
389 
390     }
391   }
392 
393   elecDistStale=1;
394 
395 }
396 
397 //-------------------------------------------------------------------------
398