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