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