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