1 /*
2
3 Copyright (C) 2007 Lucas K. Wagner
4 addition of the PURE DMC: Michal Bajdich and Fernando A. Reboredo
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 */
21
22
23
24 #include "Dmc_method.h"
25 #include "qmc_io.h"
26 #include "ulec.h"
27 #include "Program_options.h"
28 #include "average.h"
29 #include "Generate_sample.h"
30 #include <algorithm>
31 #include <ctime>
32 #include <cstdio>
read(vector<string> words,unsigned int & pos,Program_options & options)33 void Dmc_method::read(vector <string> words,
34 unsigned int & pos,
35 Program_options & options)
36 {
37 ndim=3;
38
39 have_read_options=1;
40
41 //vector <string> offsetwords;
42
43 //required options
44 if(!readvalue(words, pos=0, timestep, "TIMESTEP"))
45 error("Need TIMESTEP in METHOD section");
46
47 //optional options
48
49 if(!readvalue(words, pos=0, nblock, "NBLOCK"))
50 nblock=100;
51
52 int target_config;
53 if(!readvalue(words,pos=0,target_config,"TARGET_CONFIG"))
54 target_config=2048;
55
56 if(!readvalue(words, pos=0, nconfig, "NCONFIG"))
57 nconfig=max(target_config/mpi_info.nprocs,1);
58
59 if(!readvalue(words, pos=0, nstep, "NSTEP"))
60 nstep=max(int(1.0/timestep+0.5),1);
61
62 if(!readvalue(words, pos=0, readconfig, "READCONFIG"))
63 readconfig=options.runid+".config";
64
65 if(!readvalue(words, pos=0, eref, "EREF"))
66 eref=0.0;
67
68 if(!readvalue(words,pos=0, max_poss_weight, "MAX_POSS_WEIGHT"))
69 max_poss_weight=7.0;
70 if(haskeyword(words, pos=0, "TMOVES")) tmoves=1;
71 else tmoves=0;
72 if(haskeyword(words, pos=0, "TMOVESSC")) tmoves_sizeconsistent=1;
73 else tmoves_sizeconsistent=0;
74
75
76 readvalue(words,pos=0,save_trace,"SAVE_TRACE");
77
78 if(!readvalue(words, pos=0, nhist, "CORR_HIST"))
79 nhist=-1;
80
81 if(haskeyword(words, pos=0, "PURE_DMC")) {
82 pure_dmc=1;
83 if( nhist < 1 )
84 error("CORR_HIST must be > 1 when PURE_DMC is on");
85 }
86 else pure_dmc=0;
87
88 if(!readvalue(words, pos=0, storeconfig, "STORECONFIG"))
89 storeconfig=options.runid+".config";
90
91 if(!readvalue(words, pos=0, log_label, "LABEL"))
92 log_label="dmc";
93
94 if(!readvalue(words, pos=0, start_feedback, "START_FEEDBACK"))
95 start_feedback=1;
96
97 if(readvalue(words, pos=0, feedback_interval, "FEEDBACK_INTERVAL")) {
98 if(feedback_interval < 1)
99 error("FEEDBACK_INTERVAL must be greater than or equal to 1");
100 }
101 else feedback_interval=5;
102
103 if(!readvalue(words, pos=0, feedback, "FEEDBACK"))
104 feedback=1.0;
105
106 if(!readvalue(words, pos=0, branch_start_cutoff, "BRANCH_START_CUTOFF"))
107 branch_start_cutoff=10;
108
109 branch_stop_cutoff=branch_start_cutoff*1.5;
110
111
112 vector <string> proptxt;
113 if(readsection(words, pos=0, proptxt, "PROPERTIES"))
114 mygather.read(proptxt);
115
116 vector<string> tmp_dens;
117 pos=0;
118 while(readsection(words, pos, tmp_dens, "DENSITY")) {
119 dens_words.push_back(tmp_dens);
120 }
121
122 pos=0;
123 while(readsection(words, pos, tmp_dens, "NONLOCAL_DENSITY")) {
124 nldens_words.push_back(tmp_dens);
125 }
126
127 pos=0;
128 while(readsection(words, pos, tmp_dens, "AVERAGE")) {
129 avg_words.push_back(tmp_dens);
130 }
131
132 vector <string> dynamics_words;
133 if(!readsection(words, pos=0, dynamics_words, "DYNAMICS") )
134 dynamics_words.push_back("SPLIT");
135
136 low_io=0;
137 if(haskeyword(words, pos=0,"LOW_IO")) low_io=1;
138
139 allocate(dynamics_words, dyngen);
140 dyngen->enforceNodes(1);
141
142 //MB: forwark walking lengths
143 fw_length.Resize(0);
144 fw_length=0;
145 vector <string> fw_words;
146 max_fw_length=0;
147 if(readsection(words, pos=0, fw_words, "fw_length")){
148 fw_length.Resize(fw_words.size());
149 for(int i=0;i<fw_words.size();i++){
150 fw_length(i)=atoi(fw_words[i].c_str());
151 if(fw_length(i) > max_fw_length)
152 max_fw_length=fw_length(i);
153 }
154 }
155 //cout <<" Maximum forward walking history is "<<max_fw_length<<" steps"<<endl;
156
157 }
158
159 //----------------------------------------------------------------------
160
generateVariables(Program_options & options)161 int Dmc_method::generateVariables(Program_options & options) {
162
163 if(!have_read_options)
164 error("need to call Dmc_method::read before generateVariables");
165 if(have_allocated_variables)
166 error("already allocated variables in Dmc_method");
167
168 have_allocated_variables=1;
169 allocate(options.systemtext[0], mysys);
170 mysys->generatePseudo(options.pseudotext, mypseudo);
171 allocate(options.twftext[0], mysys, mywfdata);
172
173 densplt.Resize(dens_words.size());
174 for(int i=0; i< densplt.GetDim(0); i++) {
175 allocate(dens_words[i], mysys, options.runid,densplt(i));
176 }
177 nldensplt.Resize(nldens_words.size());
178 for(int i=0; i< nldensplt.GetDim(0); i++) {
179 allocate(nldens_words[i], mysys, options.runid,nldensplt(i));
180 }
181
182 return 1;
183 }
184
185 //----------------------------------------------------------------------
186
187
188
allocateIntermediateVariables(System * sys,Wavefunction_data * wfdata)189 int Dmc_method::allocateIntermediateVariables(System * sys,
190 Wavefunction_data * wfdata) {
191 if(wf) delete wf;
192 wf=NULL;
193 if(sample) delete sample;
194 sample=NULL;
195 nelectrons=sys->nelectrons(0)+sys->nelectrons(1);
196 wfdata->generateWavefunction(wf);
197 sys->generateSample(sample);
198 sample->attachObserver(wf);
199 nwf=wf->nfunc();
200
201 if(wf->nfunc() >1)
202 error("DMC doesn't support more than one guiding wave function");
203
204 guidingwf=new Primary;
205
206 pts.Resize(nconfig);
207 for(int i=0; i < nconfig; i++) {
208 pts(i).age.Resize(nelectrons);
209 pts(i).age=0;
210 }
211
212 average_var.Resize(avg_words.size());
213 average_var=NULL;
214 for(int i=0; i< average_var.GetDim(0); i++) {
215 allocate(avg_words[i], sys, wfdata, average_var(i));
216 }
217
218
219 return 1;
220 }
221
222 //----------------------------------------------------------------------
223
showinfo(ostream & os)224 int Dmc_method::showinfo(ostream & os)
225 {
226
227 if(have_allocated_variables) {
228 mysys->showinfo(os);
229 mypseudo->showinfo(os);
230 mywfdata->showinfo(os);
231 }
232 os << "###########################################################\n";
233 os << "Diffusion Monte Carlo:\n";
234 os << "Number of processors " << mpi_info.nprocs << endl;
235 os << "Blocks: " << nblock << endl;
236 os << "Steps per block: " << nstep << endl;
237 os << "Timestep: " << timestep << endl;
238 if(tmoves)
239 os << "T-moves turned on" << endl;
240 if(tmoves_sizeconsistent)
241 os << "Size-consistent T-moves turned on" << endl;
242
243 string indent=" ";
244
245 if(max_fw_length){
246 os << "Forward walking averaging over lengths ";
247 for(int s=0;s<fw_length.GetSize();s++)
248 os<<fw_length(s)<<" ";
249 os<< endl;
250 }
251 dyngen->showinfo(indent, os);
252
253 os << "###########################################################" << endl;
254 return 1;
255 }
256
257 //----------------------------------------------------------------------
258
find_cutoffs()259 void Dmc_method::find_cutoffs() {
260 doublevar eaverage=0;
261
262 doublevar totweight=0;
263 for(int i=0; i< nconfig; i++) {
264 //eaverage+=(prop.trace(step,i).energy(w)+offset(w))
265 // *guidingwf->getOperatorWeight(prop.trace(step,i).wf_val,w);
266 eaverage+=pts(i).prop.energy(0)*pts(i).weight;
267 totweight+=pts(i).weight;
268 //cout << "en " << pts(i).prop.energy(0) << endl;
269 }
270 //cout << mpi_info.node << "par sum " << nconfig << endl;
271 totweight=parallel_sum(totweight);
272 //cout << mpi_info.node << "eaverage " << endl;
273 eaverage=parallel_sum(eaverage)/totweight;
274
275 eref=eaverage;
276 single_write(cout, " setting eref= ", eref, "\n");
277 int totconf=parallel_sum(nconfig);
278 doublevar eaverage2=0;
279 for(int i=0; i < nconfig; i++){
280 doublevar effenergy=pts[i].prop.energy(0);
281 eaverage2+=(effenergy-eaverage)
282 *(effenergy-eaverage);
283 }
284
285 eaverage2=parallel_sum(eaverage2)/totconf;
286
287 //The variance of the starting distribution.
288 doublevar sigmac=sqrt(eaverage2);
289
290 branchcut_start=branch_start_cutoff*sigmac; //start of cutoff region for branching
291 branchcut_stop=branch_stop_cutoff*sigmac; //end of cutoff region
292
293 single_write(cout, " start branch cut at ", branchcut_start, "\n");
294 single_write(cout, " stop branch cut at ", branchcut_stop, "\n");
295
296
297 }
298
299 //----------------------------------------------------------------------
300
run(Program_options & options,ostream & output)301 void Dmc_method::run(Program_options & options, ostream & output) {
302 if(!have_allocated_variables)
303 error("Must generate variables to use Dmc_method::run");
304 string logfile=options.runid+".log";
305
306 if(mpi_info.node==0 ) {
307 ofstream logout(logfile.c_str(), ios::app);
308 logout << "#-------------------------------------------------\n";
309 logout << "#DMC run: timestep " << timestep
310 << endl;
311 logout << "#-------------------------------------------------\n\n\n";
312 logout.close();
313 }
314
315 myprop.setLog(logfile, log_label);
316 runWithVariables(myprop, mysys, mywfdata, mypseudo,output);
317 }
318
319 //----------------------------------------------------------------------
320
321 /*!
322
323 */
runWithVariables(Properties_manager & prop,System * sys,Wavefunction_data * wfdata,Pseudopotential * pseudo,ostream & output)324 void Dmc_method::runWithVariables(Properties_manager & prop,
325 System * sys,
326 Wavefunction_data * wfdata,
327 Pseudopotential * pseudo,
328 ostream & output)
329 {
330
331 allocateIntermediateVariables(sys, wfdata);
332 if(!wfdata->supports(laplacian_update))
333 error("DMC doesn't support all-electron moves..please"
334 " change your wave function to use the new Jastrow");
335
336 cout.precision(15);
337 output.precision(10);
338
339
340 prop.setSize(wf->nfunc(), nblock, nstep, nconfig, sys,
341 wfdata);
342
343 restorecheckpoint(readconfig, sys, wfdata, pseudo);
344 prop.initializeLog(average_var);
345
346 //MB: new properties manager for forward walking (one per each length)
347 Array1 <Properties_manager> prop_fw;
348 prop_fw.Resize(fw_length.GetSize());
349 if(max_fw_length){
350 for(int s=0;s<fw_length.GetSize();s++){
351 string logfile, label_temp;
352 prop.getLog(logfile, label_temp);
353 char strbuff[40];
354 sprintf(strbuff, "%d", fw_length(s));
355 label_temp+="_fw";
356 label_temp+=strbuff;
357 prop_fw(s).setLog(logfile, label_temp);
358 prop_fw(s).setSize(wf->nfunc(), nblock, nstep, nconfig, sys,
359 wfdata);
360 prop_fw(s).initializeLog(average_var);
361 }
362 }
363
364
365 if(nhist==-1)
366 nhist=1;
367
368 doublevar teff=timestep;
369 for(int block=0; block < nblock; block++) {
370
371 int totkilled=0;
372 int totbranch=0;
373 int totpoints=0;
374 for(int step=0; step < nstep; ) {
375 int npsteps=min(feedback_interval, nstep-step);
376
377 Dynamics_info dinfo;
378 doublevar acsum=0;
379 doublevar deltar2=0;
380 Array1 <doublevar> epos(3);
381
382 doublevar avg_acceptance=0;
383
384 for(int walker=0; walker < nconfig; walker++) {
385 pts(walker).config_pos.restorePos(sample);
386 wf->updateLap(wfdata, sample);
387 //------Do several steps without branching
388 for(int p=0; p < npsteps; p++) {
389 pseudo->randomize();
390
391 for(int e=0; e< nelectrons; e++) {
392 int acc;
393 acc=dyngen->sample(e, sample, wf, wfdata, guidingwf,
394 dinfo, timestep);
395
396 if(dinfo.accepted)
397 deltar2+=dinfo.diffusion_rate/(nconfig*nelectrons*npsteps);
398 if(dinfo.accepted) {
399 pts(walker).age(e)=0;
400 }
401 else {
402 pts(walker).age(e)++;
403 }
404 avg_acceptance+=dinfo.acceptance/(nconfig*nelectrons*npsteps);
405
406 if(acc>0) acsum++;
407 }
408 totpoints++;
409 Properties_point pt;
410 if(tmoves or tmoves_sizeconsistent) { //------------------T-moves
411 doTmove(pt,pseudo,sys,wfdata,wf,sample,guidingwf);
412 } ///---------------------------------done with the T-moves
413 else {
414 mygather.gatherData(pt, pseudo, sys, wfdata, wf,
415 sample, guidingwf);
416 }
417 Dmc_history new_hist;
418 new_hist.main_en=pts(walker).prop.energy(0);
419 pts(walker).past_energies.push_front(new_hist);
420 deque<Dmc_history> & past(pts(walker).past_energies);
421 if(past.size() > nhist)
422 past.erase(past.begin()+nhist, past.end());
423
424 pts(walker).prop=pt;
425 if(!pure_dmc) {
426 pts(walker).weight*=getWeight(pts(walker),teff,etrial);
427 //Introduce potentially a small bias to avoid instability.
428 if(pts(walker).weight>max_poss_weight) pts(walker).weight=max_poss_weight;
429 }
430 else
431 pts(walker).weight=getWeightPURE_DMC(pts(walker),teff,etrial);
432
433 if(pts(walker).ignore_walker) {
434 pts(walker).ignore_walker=0;
435 pts(walker).weight=1;
436 pts(walker).prop.count=0;
437 }
438 pts(walker).prop.weight=pts(walker).weight;
439 //This is somewhat inaccurate..will need to change it later
440 //For the moment, the autocorrelation will be slightly
441 //underestimated
442 pts(walker).prop.parent=walker;
443 pts(walker).prop.nchildren=1;
444 pts(walker).prop.children(0)=walker;
445 pts(walker).prop.avgrets.Resize(1,average_var.GetDim(0));
446 for(int i=0; i< average_var.GetDim(0); i++) {
447 average_var(i)->randomize(wfdata,wf,sys,sample);
448 average_var(i)->evaluate(wfdata, wf, sys, pseudo, sample, pts(walker).prop, pts(walker).prop.avgrets(0,i));
449 }
450 prop.insertPoint(step+p, walker, pts(walker).prop);
451 for(int i=0; i< densplt.GetDim(0); i++)
452 densplt(i)->accumulate(sample,pts(walker).prop.weight(0));
453 for(int i=0; i< nldensplt.GetDim(0); i++)
454 nldensplt(i)->accumulate(sample,pts(walker).prop.weight(0),
455 wfdata,wf);
456
457
458 //MB: making the history of prop.avgrets for forward walking
459 if(max_fw_length){
460 forwardWalking(walker, step+p,prop_fw);
461 }//if FW
462
463 }
464
465 pts(walker).config_pos.savePos(sample);
466 }
467 //---Finished moving all walkers
468
469 doublevar accept_ratio=acsum/(nconfig*nelectrons*npsteps);
470 teff=timestep*accept_ratio; //deltar2/rf_diffusion;
471
472 updateEtrial(feedback);
473
474 step+=npsteps;
475
476 int nkilled;
477 if(!pure_dmc)
478 nkilled=calcBranch();
479 else
480 nkilled=0;
481
482 totkilled+=nkilled;
483 totbranch+=nkilled;
484 }
485
486 ///----Finished block
487
488 if(!low_io || block==nblock-1) {
489 savecheckpoint(storeconfig,sample);
490 for(int i=0; i< densplt.GetDim(0); i++)
491 densplt(i)->write();
492 for(int i=0; i< nldensplt.GetDim(0); i++)
493 nldensplt(i)->write(log_label);
494 }
495 if(!pure_dmc){
496 prop.endBlock();
497 }
498 else
499 prop.endBlockSHDMC();
500
501 if(max_fw_length){
502 for(int s=0;s<fw_length.GetSize();s++){
503 //prop_fw(s).endBlock();
504 prop_fw(s).endBlock_per_step();
505 }
506 }
507
508 totbranch=parallel_sum(totbranch);
509 totkilled=parallel_sum(totkilled);
510 totpoints=parallel_sum(totpoints);
511
512 Properties_final_average finavg;
513 prop.getFinal(finavg);
514 eref=finavg.avg(Properties_types::total_energy,0);
515 updateEtrial(feedback);
516
517 doublevar maxage=0;
518 doublevar avgage=0;
519 for(int w=0;w < nconfig; w++) {
520 for(int e=0; e< nelectrons; e++) {
521 if(maxage<pts(w).age(e)) maxage=pts(w).age(e);
522 avgage+=pts(w).age(e);
523 }
524 }
525 avgage/=(nconfig*nelectrons);
526
527 if(output) {
528 //cout << "Block " << block
529 // << " nconfig " << totconfig
530 // << " etrial " << etrial << endl;
531 if(global_options::rappture ) {
532 ofstream rapout("rappture.log");
533 rapout << "=RAPPTURE-PROGRESS=>" << int(100.0*doublevar(block+1)/doublevar(nblock))
534 << " Diffusion Monte Carlo" << endl;
535 cout << "=RAPPTURE-PROGRESS=>" << int(100.0*doublevar(block+1)/doublevar(nblock))
536 << " Diffusion Monte Carlo" << endl;
537 rapout.close();
538 }
539 output << "***" << endl;
540 output << "Block " << block
541 << " etrial " << etrial << endl;
542 output << "maximum age " << maxage
543 << " average age " << avgage << endl;
544 dyngen->showStats(output);
545
546 prop.printBlockSummary(output);
547
548 output << "Branched "
549 << totbranch << " times. So a branch every "
550 << doublevar(totpoints)/doublevar(totbranch)
551 << " steps " << endl;
552 }
553 dyngen->resetStats();
554 }
555
556 if(output) {
557 output << "\n ----------Finished DMC------------\n\n";
558 prop.printSummary(output,average_var);
559
560 //MB: final printout for FW
561 if(max_fw_length){
562 for(int s=0;s<fw_length.GetSize();s++)
563 prop_fw(s).printSummary(output,average_var);
564 }
565
566 }
567 wfdata->clearObserver();
568 deallocateIntermediateVariables();
569 }
570
571
572 //----------------------------------------------------------------------
573
574
savecheckpoint(string & filename,Sample_point * config)575 void Dmc_method::savecheckpoint(string & filename,
576 Sample_point * config) {
577
578 if(save_trace!="") {
579 if(mpi_info.node==0) {
580 cout << "entering trace write" << endl;
581 long int time_ent=clock();
582 FILE * f=fopen(save_trace.c_str(),"a");
583 for(int i=0;i<nconfig; i++) {
584 pts(i).config_pos.writeBinary(f,pts(i).weight);
585 // fwrite(&pts(i).weight, sizeof(doublevar),1, f);
586 }
587
588 #ifdef USE_MPI
589 Dmc_point tmppt;
590 for(int p=1; p < mpi_info.nprocs; p++) {
591 int nconfigthis;
592 MPI_Recv(nconfigthis,p);
593 for(int i=0; i < nconfigthis; i++) {
594 tmppt.config_pos.mpiReceive(p);
595 MPI_Recv(tmppt.weight,p);
596 tmppt.config_pos.writeBinary(f,tmppt.weight);
597 }
598 }
599 #endif
600 long int time_b=clock();
601 single_write(cout,"writing to trace : ",double(time_b-time_ent)/CLOCKS_PER_SEC,"\n");
602 fclose(f);
603 }
604 #ifdef USE_MPI
605 else {
606 MPI_Send(nconfig,0);
607 for(int i=0; i< nconfig; i++) {
608 pts(i).config_pos.mpiSend(0);
609 MPI_Send(pts(i).weight,0);
610 }
611 }
612 #endif
613 }
614 if(filename=="") return;
615 write_configurations(filename, pts);
616
617
618 return;
619 }
620
621
622 //----------------------------------------------------------------------
623
624
625
restorecheckpoint(string & filename,System * sys,Wavefunction_data * wfdata,Pseudopotential * pseudo)626 void Dmc_method::restorecheckpoint(string & filename, System * sys,
627 Wavefunction_data * wfdata,
628 Pseudopotential * pseudo) {
629
630 ifstream is(filename.c_str());
631 if(is) {
632 is.close();
633 read_configurations(filename, pts);
634 }
635 else {
636 Array1 <Config_save_point> configs;
637 generate_sample(sample,wf,wfdata,guidingwf,nconfig,configs);
638 pts.Resize(nconfig);
639 for(int i=0; i< nconfig; i++)
640 pts(i).config_pos=configs(i);
641 }
642 int ncread=pts.GetDim(0);
643
644 //cout << "ncread " << ncread << " nwread " << nwread << endl;
645 if(nconfig < ncread) {
646 Array1 <Dmc_point> tmp_pts(nconfig);
647 for(int i=0; i< nconfig; i++) tmp_pts(i)=pts(i);
648 pts=tmp_pts;
649 }
650 else if(nconfig > ncread) {
651 error("Not enough configurations in ", filename);
652 }
653
654 for(int walker=0; walker < nconfig; walker++) {
655 pts(walker).config_pos.restorePos(sample);
656 mygather.gatherData(pts(walker).prop, pseudo, sys,
657 wfdata, wf, sample,
658 guidingwf);
659 pts(walker).age.Resize(sys->nelectrons(0)+sys->nelectrons(1));
660 pts(walker).age=0;
661 }
662 find_cutoffs();
663
664 updateEtrial(start_feedback);
665
666 }
667
668
669
670
671 //----------------------------------------------------------------------
672
updateEtrial(doublevar feed)673 void Dmc_method::updateEtrial(doublevar feed) {
674
675 doublevar totweight=0;
676 for(int walker=0; walker < nconfig; walker++)
677 totweight+=pts(walker).weight;
678
679 etrial=eref-feed*log(totweight/double(nconfig));
680
681 #ifdef USE_MPI
682 doublevar mpitot=0;
683 MPI_Allreduce(&totweight,&mpitot, 1,
684 MPI_DOUBLE, MPI_SUM, MPI_Comm_grp);
685 etrial=eref-feed*log(mpitot/double(mpi_info.nprocs*nconfig));
686 #endif
687
688 //cout << "etrial " << etrial << " total weight " << totweight << endl;
689
690 }
691
692 //----------------------------------------------------------------------
693
getWeight(Dmc_point & pt,doublevar teff,doublevar etr)694 doublevar Dmc_method::getWeight(Dmc_point & pt,
695 doublevar teff, doublevar etr) {
696 doublevar teffac=teff/2.0;
697
698 doublevar effenergy=0, effoldenergy=0;
699
700 effenergy=pt.prop.energy(0);
701 effoldenergy=pt.past_energies[0].main_en;
702
703 doublevar fbet=max(etr-effenergy, etr-effoldenergy);
704
705 if(fbet > branchcut_stop) {
706 teffac=0;
707 }
708 else if(fbet > branchcut_start) {
709 teffac=teffac*(1.-(fbet-branchcut_start)
710 /(branchcut_stop-branchcut_start));
711 }
712
713 doublevar return_weight;
714 return_weight=exp(teffac*(etr*2-effenergy-effoldenergy));
715
716 return return_weight;
717 }
718
719 //----------------------------------------------------------------------
720 //using the pure DMC weight from last N steps in history
getWeightPURE_DMC(Dmc_point & pt,doublevar teff,doublevar etr)721 doublevar Dmc_method::getWeightPURE_DMC(Dmc_point & pt,
722 doublevar teff, doublevar etr) {
723 doublevar teffac=teff;
724
725 int history=pt.past_energies.size();
726 assert(history>0);
727 doublevar sum=0;
728 for(int i=0;i<history;i++){
729 sum+=pt.past_energies[i].main_en;
730 }
731 sum/=history;
732
733 doublevar return_weight;
734 return_weight=exp(teffac*history*(etr-sum));
735
736 //cout <<"SHDDMC weight "<<return_weight<<" energy average "<<sum<<endl;
737 //cout<<"current history size "<<history<<endl;
738 return return_weight;
739 }
740
741 //----------------------------------------------------------------------
742
doTmove(Properties_point & pt,Pseudopotential * pseudo,System * sys,Wavefunction_data * wfdata,Wavefunction * wf,Sample_point * sample,Guiding_function * guideingwf)743 void Dmc_method::doTmove(Properties_point & pt,Pseudopotential * pseudo, System * sys,
744 Wavefunction_data * wfdata, Wavefunction * wf, Sample_point * sample,
745 Guiding_function * guideingwf) {
746 vector <Tmove> tmov;
747 pt.setSize(nwf);
748 wf->getVal(wfdata,0,pt.wf_val);
749 sys->calcKinetic(wfdata,sample,wf,pt.kinetic);
750 pt.potential=sys->calcLoc(sample);
751 pt.weight=1.0; //this gets set later anyway
752 pt.count=1;
753 pseudo->calcNonlocTmove(wfdata,sys,sample,wf,pt.nonlocal,tmov);
754 doublevar sum=1;
755 for(vector<Tmove>::iterator mov=tmov.begin(); mov!=tmov.end(); mov++) {
756 assert(mov->vxx < 0);
757 sum-=timestep*mov->vxx;
758 }
759 pt.nonlocal(0)-=(sum-1)/timestep;
760 //subtract_out_enwt=-(sum-1)/timestep;
761 assert(sum >= 0);
762 if(tmoves) { ///Non-size consistent
763 doublevar rand=rng.ulec()*sum;
764 sum=1; //reset to choose the move
765 if(rand > sum) {
766 for(vector<Tmove>::iterator mov=tmov.begin(); mov!=tmov.end(); mov++) {
767 sum-=timestep*mov->vxx;
768 if(rand < sum) {
769 sample->translateElectron(mov->e,mov->pos);
770 break;
771 }
772 }
773 }
774 }
775 else { // Size-consistent
776 vector < vector<Tmove> > tmv_by_e(nelectrons);
777 for(vector<Tmove>::iterator mov=tmov.begin(); mov!=tmov.end(); mov++) {
778 tmv_by_e[mov->e].push_back(*mov);
779 }
780 for(int e=0; e< nelectrons; e++) {
781 doublevar sum_e=1.0;
782 for(vector<Tmove>::iterator mov=tmv_by_e[e].begin(); mov!=tmv_by_e[e].end(); mov++) {
783 sum_e-=timestep*mov->vxx;
784 }
785 doublevar rand=rng.ulec()*sum_e;
786 doublevar sel_sum=1;
787 if(rand > sel_sum) {
788 for(vector<Tmove>::iterator mov=tmv_by_e[e].begin(); mov!=tmv_by_e[e].end(); mov++) {
789 sel_sum-=timestep*mov->vxx;
790 if(rand < sel_sum) {
791 sample->translateElectron(e,mov->pos);
792 break;
793 }
794 }
795 }
796 }
797 }
798
799 }
800 //----------------------------------------------------------------------
forwardWalking(int walker,int step,Array1<Properties_manager> & prop_fw)801 void Dmc_method::forwardWalking(int walker, int step, Array1<Properties_manager> & prop_fw) {
802
803 //store the observables
804 Dmc_history_avgrets new_avgrets;
805 new_avgrets.avgrets=pts(walker).prop.avgrets;
806 new_avgrets.weight=pts(walker).prop.weight(0);
807
808
809 pts(walker).past_properties.push_front(new_avgrets);
810
811 //tailor the array if larger than max_fw_length
812 deque<Dmc_history_avgrets> & past_avgrets(pts(walker).past_properties);
813 if(past_avgrets.size() > max_fw_length)
814 past_avgrets.erase(past_avgrets.begin()+max_fw_length, past_avgrets.end());
815
816 int size=pts(walker).past_properties.size();
817
818 //find the element from the past
819 doublevar oldweight;
820 for(int s=0;s<fw_length.GetSize();s++){
821 if(fw_length(s)>size){
822 pts(walker).prop.avgrets=pts(walker).past_properties[size-1].avgrets;
823 oldweight=pts(walker).past_properties[size-1].weight;
824 }
825 else{
826 //call the prop.avgrets from fw_length(s) steps a go
827 pts(walker).prop.avgrets=pts(walker).past_properties[fw_length(s)-1].avgrets;
828 oldweight=pts(walker).past_properties[fw_length(s)-1].weight;
829 }
830
831 //insert it into observables
832 prop_fw(s).insertPoint(step, walker, pts(walker).prop);
833 }
834 }
835
836
837 //----------------------------------------------------------------------
838 //Auxilliary functions for branching
839 struct Queue_element {
840 int from_node;
841 int to_node;
Queue_elementQueue_element842 Queue_element() { }
Queue_elementQueue_element843 Queue_element(int from, int to) { from_node=from; to_node=to; }
844 };
845
846 struct weight_obj {
847 double w;
848 int i;
849 };
850
operator <(const weight_obj & a,const weight_obj & b)851 bool operator<(const weight_obj & a,const weight_obj & b) {
852 return a.w < b.w;
853 }
match_walkers(Array1<double> & weights,Array1<int> & branch)854 void match_walkers(Array1<double> & weights, Array1 <int> & branch) {
855 const double split_threshold=1.8;
856 branch=-1;
857 int totwalkers=weights.GetDim(0);
858 Array1<weight_obj> walkers(totwalkers);
859 for(int i=0; i< totwalkers; i++) {
860 walkers(i).w=weights(i);
861 walkers(i).i=i;
862 }
863 sort(walkers.v,walkers.v+totwalkers);
864 int currsmallest=0;
865 for(int i=totwalkers-1; i > 1; i--) {
866 if(walkers(i).w < split_threshold) break;
867 int w=walkers(i).i;
868 int smallest=walkers(currsmallest).i;
869 double weight1=weights(w)/(weights(w)+weights(smallest));
870 if(weight1+rng.ulec() >= 1.0) {
871 branch(w)=2;
872 branch(smallest)=0;
873 weights(w)+=weights(smallest);
874 weights(w)/=2.0;
875 }
876 else {
877 branch(w)=0;
878 branch(smallest)=2;
879 weights(smallest)+=weights(w);
880 weights(smallest)/=2.0;
881 }
882 currsmallest++;
883 }
884 //for(int i=0; i< totwalkers; i++) {
885 // cout << walkers(i).w << endl;
886 //}
887
888 }
889
890 //----------------------------------------------------------------------
891
calcBranch()892 int Dmc_method::calcBranch() {
893 int totwalkers=mpi_info.nprocs*nconfig;
894 Array1 <doublevar> weights(totwalkers);
895 Array1 <doublevar> my_weights(nconfig);
896
897 for(int walker=0; walker < nconfig; walker++)
898 my_weights(walker)=pts(walker).weight;
899 #ifdef USE_MPI
900 MPI_Allgather(my_weights.v,nconfig, MPI_DOUBLE, weights.v,nconfig,MPI_DOUBLE, MPI_Comm_grp);
901 #else
902 weights=my_weights;
903 #endif
904 Array1 <int> my_branch(nconfig);
905 Array1 <int> nwalkers(mpi_info.nprocs);
906 nwalkers=0;
907 int root=0;
908 if(mpi_info.node==root) { //this if/else clause may be refactored out
909
910 Array1 <int> branch(totwalkers);
911 //----Find which walkers branch/die
912 //we do it on one node since otherwise we'll have different random numbers!
913 //we'll assign the weight for each copy that will be produced
914 //this is the core of the branching algorithm..
915 //my homegrown algo, based on Umrigar, Nightingale, and Runge
916 branch=-1;
917
918 long int time_a=clock();
919 match_walkers(weights,branch);
920 long int time_b=clock();
921 single_write(cout,"matching: ",double(time_b-time_a)/CLOCKS_PER_SEC,"\n");
922 for(int w=0; w< totwalkers; w++) {
923 if(branch(w)==-1) branch(w)=1;
924 }
925 //----end homegrown algo
926 //count how many walkers each node will have
927 //without balancing
928 int walk=0;
929 for(int n=0; n< mpi_info.nprocs; n++) {
930 for(int i=0; i< nconfig; i++) {
931 nwalkers(n)+=branch(walk);
932 walk++;
933 }
934 //cout << "nwalkers " << n << " " << nwalkers(n) << endl;
935 }
936 //now send nwalkers and which to branch to all processors
937 for(int i=0; i< nconfig; i++) {
938 my_branch(i)=branch(i);
939 my_weights(i)=weights(i);
940 }
941 time_a=clock();
942 #ifdef USE_MPI
943 MPI_Bcast(nwalkers.v, mpi_info.nprocs, MPI_INT, mpi_info.node, MPI_Comm_grp);
944 for(int i=1; i< mpi_info.nprocs; i++) {
945 MPI_Send(branch.v+i*nconfig,nconfig,MPI_INT,i,0,MPI_Comm_grp);
946 MPI_Send(weights.v+i*nconfig, nconfig, MPI_DOUBLE, i,0,MPI_Comm_grp);
947 }
948 #endif
949 time_b=clock();
950 single_write(cout,"sending branch: ",double(time_b-time_a)/CLOCKS_PER_SEC,"\n");
951
952
953 }
954 else {
955 #ifdef USE_MPI
956 MPI_Bcast(nwalkers.v, mpi_info.nprocs, MPI_INT, root, MPI_Comm_grp);
957 MPI_Status status;
958 MPI_Recv(my_branch.v,nconfig, MPI_INT,root,0,MPI_Comm_grp, &status);
959 MPI_Recv(my_weights.v,nconfig, MPI_DOUBLE,root,0,MPI_Comm_grp, &status);
960 #endif
961 }
962 //--end if/else clause
963
964 long int time_a=clock();
965 for(int i=0; i< nconfig; i++) {
966 pts(i).weight=my_weights(i);
967 }
968
969 //Now we all have my_branch and nwalkers..we need to figure out who
970 //needs to send walkers to whom--after this, nwalkers should be a flat array equal to
971 //nconfig(so don't try to use it for anything useful afterwards)
972 vector <Queue_element> send_queue;
973 int curr_needs_walker=0;
974 int nnwalkers=nwalkers(mpi_info.node); //remember how many total we should have
975 for(int i=0; i< mpi_info.nprocs; i++) {
976 while(nwalkers(i) > nconfig) {
977 if(nwalkers(curr_needs_walker) < nconfig) {
978 nwalkers(curr_needs_walker)++;
979 nwalkers(i)--;
980 send_queue.push_back(Queue_element(i,curr_needs_walker));
981 //cout << mpi_info.node << ":nwalkers " << nwalkers(i) << " " << nwalkers(curr_needs_walker) << endl;
982 //cout << mpi_info.node << ":send " << i << " " << curr_needs_walker << endl;
983 }
984 else {
985 curr_needs_walker++;
986 }
987 }
988 }
989
990 for(int i=0; i< mpi_info.nprocs; i++) assert(nwalkers(i)==nconfig);
991 int killsize=0;
992 for(int i=0; i< nconfig; i++) {
993 //cout << mpi_info.node << ":branch " << i << " " << my_branch(i) << " weight " << pts(i).weight << endl;
994 if(my_branch(i)==0) killsize++;
995 }
996 //cout << mpi_info.node << ": send queue= " << send_queue.size() << endl;
997 //now do branching for the walkers that we get to keep
998 Array1 <Dmc_point> savepts=pts;
999 int curr=0; //what walker we're currently copying from
1000 int curr_copy=0; //what walker we're currently copying to
1001 while(curr_copy < min(nnwalkers,nconfig)) {
1002 if(my_branch(curr)>0) {
1003 //cout << mpi_info.node << ": copying " << curr << " to " << curr_copy << " branch " << my_branch(curr) << endl;
1004 my_branch(curr)--;
1005 pts(curr_copy)=savepts(curr);
1006 //pts(curr_copy).weight=1;
1007 curr_copy++;
1008 }
1009 else curr++;
1010 }
1011 long int time_b=clock();
1012 single_write(cout,"Finding out where to send: ",double(time_b-time_a)/CLOCKS_PER_SEC,"\n");
1013
1014 time_a=clock();
1015 //Finally, send or receive spillover walkers
1016 if(nnwalkers > nconfig) {
1017 vector<Queue_element>::iterator queue_pos=send_queue.begin();
1018 while(curr < nconfig) {
1019 if(my_branch(curr) > 0) {
1020 my_branch(curr)--;
1021 while(queue_pos->from_node != mpi_info.node) {
1022 queue_pos++;
1023 }
1024 //cout << mpi_info.node << ":curr " << curr << " my_branch " << my_branch(curr) << endl;
1025 //cout << mpi_info.node << ":sending " << queue_pos->from_node << " to " << queue_pos->to_node << endl;
1026 savepts(curr).mpiSend(queue_pos->to_node);
1027 queue_pos++;
1028 }
1029 else curr++;
1030 }
1031
1032 }
1033 else { //if nnwalkers == nconfig, then this will just get skipped immediately
1034 vector <Queue_element>::iterator queue_pos=send_queue.begin();
1035 while(curr_copy < nconfig) {
1036 while(queue_pos->to_node != mpi_info.node) queue_pos++;
1037 //cout << mpi_info.node <<":receiving from " << queue_pos->from_node << " to " << curr_copy << endl;
1038 pts(curr_copy).mpiReceive(queue_pos->from_node);
1039 //pts(curr_copy).weight=1;
1040 curr_copy++;
1041 queue_pos++;
1042 }
1043 }
1044 time_b=clock();
1045 single_write(cout,"sending walkers:",double(time_b-time_a)/CLOCKS_PER_SEC,"\n");
1046
1047 return killsize;
1048 //exit(0);
1049 }
1050 //----------------------------------------------------------------------
1051
1052 //----------------------------------------------------------------------
1053
1054
mpiSend(int node)1055 void Dmc_point::mpiSend(int node) {
1056 #ifdef USE_MPI
1057 prop.mpiSend(node);
1058 config_pos.mpiSend(node);
1059 int n=past_energies.size();
1060 MPI_Send(&n,1, MPI_INT,node,0,MPI_Comm_grp);
1061 for(deque<Dmc_history>::iterator i=past_energies.begin();
1062 i!= past_energies.end(); i++) {
1063 i->mpiSend(node);
1064 }
1065
1066 //MB: sending the past_properties for the forward walking
1067 int m=past_properties.size();
1068 MPI_Send(&m,1, MPI_INT,node,0,MPI_Comm_grp);
1069 for(deque<Dmc_history_avgrets>::iterator i=past_properties.begin();
1070 i!= past_properties.end(); i++) {
1071 i->mpiSend(node);
1072 }
1073
1074 MPI_Send(&weight,1,MPI_DOUBLE,node,0,MPI_Comm_grp);
1075 MPI_Send(&ignore_walker,1, MPI_INT,node,0,MPI_Comm_grp);
1076
1077 int nelectrons=age.GetDim(0);
1078 MPI_Send(&nelectrons,1, MPI_INT,node,0,MPI_Comm_grp);
1079 MPI_Send(age.v,nelectrons, MPI_DOUBLE, node,0,MPI_Comm_grp);
1080 #endif
1081 }
1082
1083 //----------------------------------------------------------------------
1084
mpiReceive(int node)1085 void Dmc_point::mpiReceive(int node) {
1086 #ifdef USE_MPI
1087 prop.mpiReceive(node);
1088 config_pos.mpiReceive(node);
1089 int n;
1090 MPI_Status status;
1091 MPI_Recv(&n,1,MPI_INT,node,0,MPI_Comm_grp, &status);
1092 Dmc_history tmp_hist;
1093 past_energies.clear();
1094 for(int i=0; i< n; i++) {
1095 tmp_hist.mpiReceive(node);
1096 past_energies.push_back(tmp_hist);
1097 }
1098
1099 //MB: receiving the past_properties for the forward walking
1100 int m;
1101 MPI_Recv(&m,1,MPI_INT,node,0,MPI_Comm_grp, &status);
1102 Dmc_history_avgrets tmp_prop;
1103 past_properties.clear();
1104 for(int i=0; i< m; i++) {
1105 tmp_prop.mpiReceive(node);
1106 past_properties.push_back(tmp_prop);
1107 }
1108
1109
1110 MPI_Recv(&weight,1,MPI_DOUBLE,node,0,MPI_Comm_grp, &status);
1111 MPI_Recv(&ignore_walker,1,MPI_INT,node,0,MPI_Comm_grp, &status);
1112
1113 int nelectrons;
1114 MPI_Recv(&nelectrons,1,MPI_INT,node,0,MPI_Comm_grp,&status);
1115 age.Resize(nelectrons);
1116 MPI_Recv(age.v,nelectrons,MPI_DOUBLE, node,0,MPI_Comm_grp,&status);
1117 #endif
1118 }
1119 //----------------------------------------------------------------------
1120
write(ostream & os)1121 void Dmc_point::write(ostream & os) {
1122 string indent="";
1123 config_pos.write(os);
1124 os << "DMC { \n";
1125 //prop.write(indent,os);
1126 os << "weight " << weight<< endl;
1127 os << "sign " << sign << endl;
1128 /*
1129 for(deque<Dmc_history>::iterator i=past_energies.begin();
1130 i!=past_energies.end(); i++) {
1131 os << "past_energies { ";
1132 i->write(os);
1133 os << "}\n";
1134 }
1135 for(deque<Dmc_history_avgrets>::iterator i=past_properties.begin();
1136 i!=past_properties.end(); i++) {
1137 os << "past_properties { ";
1138 i->write(os);
1139 os << "}\n";
1140 }
1141 */
1142 os << "}\n";
1143 }
1144
read(istream & is)1145 void Dmc_point::read(istream & is) {
1146 config_pos.read(is);
1147 int filepos=is.tellg();
1148 string dum;
1149 is >> dum;
1150 if(!caseless_eq(dum, "DMC")) {
1151 is.seekg(filepos);
1152 return;
1153 }
1154
1155 is >> dum; //the {
1156 //prop.read(is);
1157 is >> dum >> weight;
1158 is >> dum >> sign;
1159 //ignoring the past stuff for the moment..
1160 }
1161
1162
1163 //----------------------------------------------------------------------
write(ostream & os)1164 void Dmc_history_avgrets::write(ostream & os) {
1165 os << "weight " << weight << endl;
1166 for(int i=0; i< avgrets.GetDim(0); i++) {
1167 os << "avgret { ";
1168 }
1169
1170 }
1171
read(istream & is)1172 void Dmc_history_avgrets::read(istream & is) {
1173 }
1174
1175 //----------------------------------------------------------------------
1176
mpiSend(int node)1177 void Dmc_history::mpiSend(int node) {
1178 #ifdef USE_MPI
1179 MPI_Send(&main_en,1,MPI_DOUBLE,node,0,MPI_Comm_grp);
1180 #endif
1181 }
1182
1183
mpiReceive(int node)1184 void Dmc_history::mpiReceive(int node) {
1185 #ifdef USE_MPI
1186 MPI_Status status;
1187 int n1,n2;
1188 MPI_Recv(&main_en,1,MPI_DOUBLE,node,0,MPI_Comm_grp,&status);
1189 #endif
1190 }
1191
1192
mpiSend(int node)1193 void Dmc_history_avgrets::mpiSend(int node) {
1194 #ifdef USE_MPI
1195 MPI_Send(&weight,1,MPI_DOUBLE,node,0,MPI_Comm_grp);
1196 int n1=avgrets.GetDim(1);
1197 MPI_Send(&n1,1,MPI_INT,node,0,MPI_Comm_grp);
1198 for(int j=0;j<n1;j++){
1199 int n2=avgrets(0,j).vals.GetDim(0);
1200 MPI_Send(&n2,1,MPI_INT,node,0,MPI_Comm_grp);
1201 MPI_Send(avgrets(0,j).vals.v,n2,MPI_DOUBLE,node,0,MPI_Comm_grp);
1202 }
1203 #endif
1204 }
1205
mpiReceive(int node)1206 void Dmc_history_avgrets::mpiReceive(int node) {
1207 #ifdef USE_MPI
1208 MPI_Status status;
1209 int n1,n2;
1210 MPI_Recv(&weight,1,MPI_DOUBLE,node,0,MPI_Comm_grp,&status);
1211 MPI_Recv(&n1,1,MPI_INT,node,0,MPI_Comm_grp,&status);
1212 avgrets.Resize(1,n1);
1213 for(int j=0;j<n1;j++){
1214 MPI_Recv(&n2,1,MPI_INT,node,0,MPI_Comm_grp,&status);
1215 avgrets(0,j).vals.Resize(n2);
1216 MPI_Recv(avgrets(0,j).vals.v,n2,MPI_DOUBLE,node,0,MPI_Comm_grp,&status);
1217 }
1218 #endif
1219 }
1220