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