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 //src/Md_method.cpp
22 //Author:Lucas Wagner
23 
24 
25 
26 #include "Md_method.h"
27 #include "qmc_io.h"
28 
29 #include <iomanip>
30 
31 #include "Program_options.h"
32 #include "System.h"
33 
34 #include "Properties.h"
35 
36 //----------------------------------------------------------------------
37 
read(vector<string> words,unsigned int & pos,Program_options & options)38 void Md_method::read(vector <string> words,
39                       unsigned int & pos,
40                       Program_options & options)
41 {
42   pos=0;
43   vector <string> vmcsec;
44   if(!readsection(words, pos=0, vmcsec, "EMBED")) {
45     error("Need EMBED section");
46   }
47   allocate(vmcsec,options, qmc_avg);
48 
49   if(!readvalue(words, pos=0, nstep, "NSTEP")) {
50     error("Need NSTEP");
51   }
52 
53   if(!readvalue(words, pos=0, tstep, "TIMESTEP")) {
54     error("Need TIMESTEP in MD method");
55   }
56 
57   readvalue(words, pos=0, readcheckfile, "READCHECK");
58   readvalue(words, pos=0, writecheckfile, "STORECHECK");
59 
60   if(!readvalue(words, pos=0, log_label, "LABEL"))
61     log_label="md";
62 
63 
64   if(readvalue(words, pos=0, damp, "DAMP")) {
65     if(damp > 1 || damp < 0) error("DAMP must be in [0,1]");
66   }
67   else damp=0.0;
68 
69   string resdim;
70   pos=0;
71   restrict_dimension.Resize(3);
72   restrict_dimension=0;
73   if(readvalue(words, pos, resdim, "RESTRICT")) {
74     if(caseless_eq(resdim, "X")) restrict_dimension(0)=1;
75     else if(caseless_eq(resdim, "Y")) restrict_dimension(1)=1;
76     else if(caseless_eq(resdim, "Z")) restrict_dimension(2)=1;
77     else error("Unknown argument to RESTRICT:", resdim);
78   }
79 
80   vector <string> weighttxt;
81   if(!readsection(words, pos=0, weighttxt, "ATOMIC_WEIGHTS") ) {
82     error("Need ATOMIC_WEIGHTS in MD method");
83   }
84   atomic_weights.Resize(weighttxt.size());
85   for(int i=0; i< atomic_weights.GetDim(0); i++) {
86     atomic_weights(i)=atof(weighttxt[i].c_str());
87   }
88 
89 }
90 
91 
92 //----------------------------------------------------------------------
93 
generateVariables(Program_options & options)94 int Md_method::generateVariables(Program_options & options) {
95 
96 
97   allocate(options.systemtext[0], sys );
98   allocate(options.twftext[0], sys, wfdata);
99 
100   sys->generatePseudo(options.pseudotext, pseudo);
101 
102   return 1;
103 }
104 
105 //----------------------------------------------------------------------
106 
107 
108 
showinfo(ostream & os)109 int Md_method::showinfo(ostream & os)
110 {
111 
112   if(os)
113   {
114 
115     sys->showinfo(os);
116     os << endl << endl;
117     os << "                               Wavefunction  "
118        << endl << endl;
119     wfdata->showinfo(os);
120     pseudo->showinfo(os);
121     os << endl;
122 
123     os << "Embedded QMC" << endl;
124     qmc_avg->showinfo(os);
125 
126 
127     return 1;
128   }
129   else
130     return 0;
131 }
132 
133 //----------------------------------------------------------------------
134 
135 
recenter(Array2<doublevar> & pos,Array1<doublevar> & mass)136 void recenter(Array2 <doublevar> & pos, Array1 <doublevar> & mass) {
137   int natoms=pos.GetDim(0);
138   assert(pos.GetDim(0)==mass.GetDim(0));
139   assert(pos.GetDim(1)==3);
140 
141   Array1 <doublevar> center(3,0.0); //center of mass
142   doublevar tot=0.0;
143   for(int at=0; at< natoms; at++) {
144     for(int d=0; d< 3; d++) {
145       center(d)+=mass(at)*pos(at,d);
146     }
147     tot+=mass(at);
148   }
149 
150   for(int d=0; d< 3; d++) {
151     center(d)/=tot;
152   }
153 
154   for(int at=0; at< natoms; at++) {
155     for(int d=0; d< 3; d++) {
156      pos(at,d)-=center(d);
157      }
158   }
159 
160 }
161 
162 /*!
163 
164 */
run(Program_options & options,ostream & output)165 void Md_method::run(Program_options & options, ostream & output)
166 {
167 
168   output.precision(10);
169 
170 
171   string logfile=options.runid+".log";
172   prop.setLog(logfile, log_label);
173 
174   int natoms=sys->nIons();
175 
176   Array1 < Array1 <int> > atom_move;
177   Array1 < Array2 <doublevar> > displace;
178 
179   //Even numbered displacements are in + direction, odd are in
180   // - direction
181 
182   if(natoms==2) {
183     //For a dimer, assume they are oriented in the z
184     //direction and only move in that direction.
185     atom_move.Resize(4);
186     displace.Resize(4);
187     int count=0;
188     for(int at=0; at < natoms; at++) {
189       for(int s=0; s< 2; s++) {
190         atom_move(count).Resize(1);
191         displace(count).Resize(1,3);
192         atom_move(count)(0)=at;
193         displace(count)=0;
194           if(s==0)
195             displace(count)(0,2)=0.00025;
196           else
197             displace(count)(0,2)=-0.00025;
198           count++;
199       }
200     }
201 
202   }
203   else {
204     int ndim=0;
205     for(int d=0; d< 3; d++) {
206       if(restrict_dimension(d) ==0) ndim++;
207     }
208     atom_move.Resize(2*ndim*natoms);
209     displace.Resize(2*ndim*natoms);
210     int count=0;
211     for(int at=0; at< natoms; at++) {
212       for(int d=0; d< 3; d++) {
213         if(!restrict_dimension(d) ) {
214         for(int s=0; s< 2; s++) {
215           atom_move(count).Resize(1);
216           displace(count).Resize(1,3);
217           atom_move(count)(0)=at;
218           displace(count)=0;
219           if(s==0)
220             displace(count)(0,d)=0.00025;
221           else
222             displace(count)(0,d)=-0.00025;
223           count++;
224         }
225       }
226       }
227     }
228   }
229 
230   prop.setDisplacement(atom_move, displace);
231   Properties_final_average curravg;
232 
233   string vmcout=options.runid+".embed";
234   ofstream vmcoutput;
235   if(output)
236 	vmcoutput.open(vmcout.c_str());
237 
238 
239   Array3 <doublevar> ionpos(nstep+2, natoms, 3, 0.0);
240   Array1 <doublevar> temppos(3);
241 
242 
243   for(int s=0; s< 2; s++) {
244     for(int at=0; at< natoms; at++) {
245       sys->getIonPos(at, temppos);
246       for(int d=0; d< 3; d++) {
247         ionpos(s,at,d)=temppos(d);
248       }
249     }
250   }
251 
252   if(readcheckfile != "") {
253     read_check(ionpos);
254   }
255 
256 
257   for(int s=0; s< 2; s++) {
258     Array2 <doublevar> pos(ionpos(s));
259     recenter(pos, atomic_weights);
260   }
261 
262   for(int step=0; step < nstep; step++) {
263 
264     int currt=step+1; //current time
265 
266     for(int at=0; at< natoms; at++) {
267       for(int d=0; d< 3; d++) {
268         temppos(d)=ionpos(currt, at, d);
269       }
270       sys->setIonPos(at, temppos);
271     }
272 
273     qmc_avg->runWithVariables(prop, sys, wfdata, pseudo, vmcoutput);
274     prop.getFinal(curravg);
275 
276     if(output)
277       output << "*****Step " << step << endl;
278     Array2 <doublevar> force(natoms, 3, 0.0);
279     Array2 <doublevar> force_err(natoms, 3, 0.0);
280 
281     for(int f=0; f< atom_move.GetDim(0); f+=2 ) {
282       for(int m=0; m < atom_move(f).GetDim(0); m++) {
283         int at=atom_move(f)(m);
284         for(int d=0; d< 3; d++) {
285           //Take a finite difference between the two forces
286           doublevar prop=fabs(displace(f)(m,d)/curravg.aux_size(f));
287           doublevar fin_diff=(curravg.aux_diff(f,0)-curravg.aux_diff(f+1,0))
288             /(2*curravg.aux_size(f));
289           force(at,d)+= -prop*fin_diff;
290 
291           force_err(at,d)+=prop*(curravg.aux_differr(f,0)
292                                  +curravg.aux_differr(f+1,0))
293             /(2*curravg.aux_size(f))/(2*curravg.aux_size(f));
294         }
295       }
296     }
297 
298 
299 
300     for(int at=0; at< natoms; at++) {
301       for(int d=0; d< 3; d++)
302         force_err(at,d)=sqrt(force_err(at,d));
303     }
304 
305 
306     //Make sure that Newton's laws are actually followed for
307     //two atoms; we can do this for more, as well.
308     if(natoms==2) {
309       doublevar average=(force(0,2)-force(1,2))/2.0;
310       force(0,2)=average;
311       force(1,2)=-average;
312     }
313 
314     //Verlet algorithm..
315     for(int at=0; at< natoms; at++) {
316       for(int d=0; d< 3; d++) {
317         ionpos(currt+1, at, d)=ionpos(currt, at,d)
318           +(1-damp)*(ionpos(currt, at, d)-ionpos(currt-1, at,d))
319           +tstep*tstep*force(at,d)/atomic_weights(at);
320         //cout << "pos " << ionpos(currt, at,d)
321         //     << "  last " <<  ionpos(currt-1, at,d)
322         //     << "  weight " << atomic_weights(at) << endl;
323       }
324     }
325 
326     Array2 <doublevar> currpos(ionpos(currt+1));
327     recenter(currpos, atomic_weights);
328 
329     doublevar kinen=0;
330     int field=output.precision() + 15;
331 
332     for(int at=0; at < natoms; at++) {
333       if(output)
334 
335         output << "position" << at << " "
336              << setw(field)  << ionpos(currt+1, at, 0)
337              << setw(field) << ionpos(currt+1, at, 1)
338              << setw(field) << ionpos(currt+1, at, 2) << endl;
339 
340       Array1 <doublevar> velocity(3);
341       for(int d=0; d< 3; d++) {
342         velocity(d)=(ionpos(currt+1, at, d)-ionpos(currt-1, at,d))/(2*tstep);
343       }
344 
345       for(int d=0;d < 3; d++) {
346         kinen+=.5*atomic_weights(at)*velocity(d)*velocity(d);
347       }
348       if(output ) {
349         output << "velocity" << at << " "
350                << setw(field) << velocity(0)
351                << setw(field) << velocity(1)
352                << setw(field) << velocity(2) << endl;
353 
354         output << "force" << at << "    "
355                << setw(field) << force(at,0)
356                << setw(field) << force(at, 1)
357                << setw(field) << force(at,2) << endl;
358         output << "force_err" << at
359                << setw(field) << force_err(at, 0)
360                << setw(field) << force_err(at, 1)
361                << setw(field) << force_err(at, 2) << endl;
362       //output << "force" << at << "z  " << force(at,2) << " +/- "
363       //      << force_err(at,2) << endl;
364       }
365 
366     }
367     if(output ) {
368     output << "kinetic_energy " << kinen << endl;
369     output << "electronic_energy " << curravg.total_energy(0) << " +/- "
370            << sqrt(curravg.total_energyerr(0)) << endl;
371 
372     output << "total_energy " << curravg.total_energy(0)+kinen << " +/- "
373            << sqrt(curravg.total_energyerr(0)) <<  endl;
374 
375     if(writecheckfile != "")
376       if(output)
377          write_check(ionpos, currt+1);
378     }
379 
380   }
381   if(output)
382     vmcoutput.close();
383 
384 
385 }
386 
387 //------------------------------------------------------------------------
388 
read_check(Array3<doublevar> & last_pos)389 void Md_method::read_check(Array3 <doublevar> & last_pos) {
390   ifstream is(readcheckfile.c_str());
391   if(!is) error("Couldn't open ", readcheckfile);
392   is.precision(15);
393   string dummy;
394   is >> dummy;
395   assert(dummy=="natoms");
396   int natoms; is >> natoms;
397   assert(last_pos.GetDim(1)==natoms);
398   assert(last_pos.GetDim(2)==3);
399   is >> dummy; //current_pos
400   for(int at=0; at< natoms; at++) {
401     for(int d=0; d < 3; d++)
402       is >> last_pos(1,at,d);
403   }
404   is >> dummy; //last_pos
405   for(int at=0; at< natoms; at++) {
406     for(int d=0; d < 3; d++)
407       is >> last_pos(0,at,d);
408   }
409   is.close();
410 }
411 
write_check(Array3<doublevar> & pos,int step)412 void Md_method::write_check(Array3 <doublevar> & pos, int step) {
413   assert(step > 0);
414 
415   ofstream os(writecheckfile.c_str());
416   os.precision(15);
417   if(!os) error("Couldn't open ", writecheckfile);
418   assert(pos.GetDim(2)==3);
419   int natoms=pos.GetDim(1);
420   os << "natoms " << natoms << endl;
421   os << "current_pos" << endl;
422   for(int at=0; at< natoms; at++) {
423     for(int d=0; d < 3; d++) {
424       os << pos(step, at, d) << "  ";
425     }
426     os << endl;
427   }
428   os << "last_pos" << endl;
429   for(int at=0; at< natoms; at++) {
430     for(int d=0; d < 3; d++) {
431       os << pos(step-1, at, d) << "  ";
432     }
433     os << endl;
434   }
435   os.close();
436 }
437 
438 //----------------------------------------------------------------------
439