1 /*
2 
3 Copyright (C) 2007 Lucas K. Wagner
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 
19 */
20 
21 
22 
23 #include "Rndmc_method.h"
24 #include "qmc_io.h"
25 #include "ulec.h"
26 #include "Program_options.h"
27 #include "average.h"
28 
29 
read(vector<string> words,unsigned int & pos,Program_options & options)30 void Rndmc_method::read(vector <string> words,
31                       unsigned int & pos,
32                       Program_options & options)
33 {
34   ndim=3;
35 
36   have_read_options=1;
37 
38   vector <string> offsetwords;
39 
40   //required options
41 
42 
43   if(!readvalue(words, pos=0, nblock, "NBLOCK"))
44     error("Need NBLOCK in METHOD section");
45 
46   if(!readvalue(words, pos=0, nconfig, "NCONFIG"))
47     error("Need NCONFIG in METHOD section");
48 
49   if(!readvalue(words, pos=0, nstep, "NSTEP"))
50     error("Need NSTEP in METHOD section");
51 
52   if(!readvalue(words, pos=0, timestep, "TIMESTEP"))
53     error("Need TIMESTEP in METHOD section");
54 
55   if(readvalue(words, pos=0, readconfig, "READCONFIG"))
56     canonical_filename(readconfig);
57   else
58     error("Must give READCONFIG for DMC");
59 
60   //optional options
61 
62   if(!readvalue(words, pos=0, eref, "EREF"))
63     eref=0.0;
64 
65   if(haskeyword(words, pos=0, "CDMC")) do_cdmc=1;
66   else do_cdmc=0;
67   if(haskeyword(words, pos=0, "TMOVES")) tmoves=1;
68   else tmoves=0;
69 
70   if(!readvalue(words, pos=0, nhist, "CORR_HIST"))
71     nhist=-1;
72 
73   if(readvalue(words, pos=0, storeconfig, "STORECONFIG"))
74     canonical_filename(storeconfig);
75 
76   if(!readvalue(words, pos=0, log_label, "LABEL"))
77     log_label="dmc";
78 
79   if(!readvalue(words, pos=0, start_feedback, "START_FEEDBACK"))
80     start_feedback=1;
81 
82   if(readvalue(words, pos=0, feedback_interval, "FEEDBACK_INTERVAL")) {
83     if(feedback_interval < 1)
84       error("FEEDBACK_INTERVAL must be greater than or equal to 1");
85   }
86   else feedback_interval=5;
87 
88   if(!readvalue(words, pos=0, feedback, "FEEDBACK"))
89     feedback=1.0;
90 
91   if(!readvalue(words, pos=0, branch_start_cutoff, "BRANCH_START_CUTOFF"))
92     branch_start_cutoff=10;
93 
94 
95   branch_stop_cutoff=branch_start_cutoff*1.5;
96 
97 
98   vector <string> proptxt;
99   if(readsection(words, pos=0, proptxt, "PROPERTIES"))
100     //    myprop.read(proptxt, options.systemtext[0], options.twftext[0]);
101     mygather.read(proptxt);
102 
103   vector<string> tmp_dens;
104   pos=0;
105   while(readsection(words, pos, tmp_dens, "DENSITY")) {
106     dens_words.push_back(tmp_dens);
107   }
108 
109   pos=0;
110   while(readsection(words, pos, tmp_dens, "NONLOCAL_DENSITY")) {
111     nldens_words.push_back(tmp_dens);
112   }
113 
114   pos=0;
115   while(readsection(words, pos, tmp_dens, "AVERAGE")) {
116     avg_words.push_back(tmp_dens);
117   }
118 
119   vector <string> dynamics_words;
120   if(!readsection(words, pos=0, dynamics_words, "DYNAMICS") )
121     dynamics_words.push_back("SPLIT");
122 
123   low_io=0;
124   if(haskeyword(words, pos=0,"LOW_IO")) low_io=1;
125 
126 
127   //MB: reading in the alpha relative value
128   if(!readvalue(words, pos=0, alpha, "ALPHA"))
129     error("supply value of ALPHA for node release ");
130 
131   //MB: needs to be possitive
132   if(alpha<0 && alpha >1 )
133     error("need positive value of ALPHA for node release");
134 
135   allocate(dynamics_words, dyngen);
136 
137   //MB: by default enforceNodes(0) so if
138   //MB: alpha =0 we want the fixed node
139   if(alpha==0.0){
140     dyngen->enforceNodes(1);
141   }
142 }
143 
144 //----------------------------------------------------------------------
145 
generateVariables(Program_options & options)146 int Rndmc_method::generateVariables(Program_options & options) {
147 
148   if(!have_read_options)
149     error("need to call Dmc_method::read before generateVariables");
150   if(have_allocated_variables)
151     error("already allocated variables in Dmc_method");
152 
153   have_allocated_variables=1;
154   allocate(options.systemtext[0], mysys);
155   mysys->generatePseudo(options.pseudotext, mypseudo);
156   allocate(options.twftext[0], mysys, mywfdata);
157 
158   densplt.Resize(dens_words.size());
159   for(int i=0; i< densplt.GetDim(0); i++) {
160     allocate(dens_words[i], mysys, options.runid,densplt(i));
161   }
162   nldensplt.Resize(nldens_words.size());
163   for(int i=0; i< nldensplt.GetDim(0); i++) {
164     allocate(nldens_words[i], mysys, options.runid,nldensplt(i));
165   }
166 
167   return 1;
168 }
169 
170 //----------------------------------------------------------------------
171 
172 
173 
allocateIntermediateVariables(System * sys,Wavefunction_data * wfdata)174 int Rndmc_method::allocateIntermediateVariables(System * sys,
175                                               Wavefunction_data * wfdata) {
176 
177   if(wf) delete wf;
178   wf=NULL;
179   if(sample) delete sample;
180   sample=NULL;
181   nelectrons=sys->nelectrons(0)+sys->nelectrons(1);
182   wfdata->generateWavefunction(wf);
183   sys->generateSample(sample);
184   sample->attachObserver(wf);
185   nwf=wf->nfunc();
186 
187   if(wf->nfunc() >1)
188     error("DMC doesn't support more than one guiding wave function");
189 
190   //MB: new node release guiding function defined in Guiding_wavefunction.h
191   guidingwf= new Primary_noderelease;
192   doublevar tmp_alpha=0.0;
193   guidingwf->set_alpha_for_noderelease(tmp_alpha);
194   //MB: allocating the rndm points
195   pts.Resize(nconfig);
196   pts_unbiased.Resize(nconfig, nstep);
197   for(int i=0; i < nconfig; i++) {
198     pts(i).age.Resize(nelectrons);
199     pts(i).age=0;
200     for(int s=0; s < nstep; s++){
201       pts_unbiased(i,s).age.Resize(nelectrons);
202       pts_unbiased(i,s).age=0;
203     }
204   }
205 
206   average_var.Resize(avg_words.size());
207   average_var=NULL;
208   for(int i=0; i< average_var.GetDim(0); i++) {
209     allocate(avg_words[i], sys, wfdata, average_var(i));
210   }
211 
212   return 1;
213 }
214 
215 //----------------------------------------------------------------------
216 
showinfo(ostream & os)217 int Rndmc_method::showinfo(ostream & os)
218 {
219 
220   if(have_allocated_variables) {
221     mysys->showinfo(os);
222     mypseudo->showinfo(os);
223     mywfdata->showinfo(os);
224   }
225   os << "###########################################################\n";
226   os << "Release Node Diffusion Monte Carlo:\n";
227   os << "Number of processors " <<           mpi_info.nprocs << endl;
228   os << "Blocks: " <<                        nblock    << endl;
229   os << "Steps per block: " <<               nstep     << endl;
230   os << "Timestep: " <<                      timestep  << endl;
231   if(tmoves)
232     os << "T-moves turned on" << endl;
233   os << "Alpha: "<< alpha << endl;
234   string indent="  ";
235 
236   dyngen->showinfo(indent, os);
237 
238   os << "###########################################################" << endl;
239   return 1;
240 }
241 
242 //----------------------------------------------------------------------
243 
find_cutoffs()244 void Rndmc_method::find_cutoffs() {
245   doublevar eaverage=0;
246 
247   doublevar totweight=0;
248   for(int i=0; i< nconfig; i++) {
249       //eaverage+=(prop.trace(step,i).energy(w)+offset(w))
250       //  *guidingwf->getOperatorWeight(prop.trace(step,i).wf_val,w);
251     eaverage+=pts(i).prop.energy(0)*pts(i).weight;
252     totweight+=pts(i).weight;
253     //cout << "en " << pts(i).prop.energy(0) << endl;
254   }
255   //cout << mpi_info.node << "par sum " << nconfig << endl;
256   totweight=parallel_sum(totweight);
257   //cout << mpi_info.node << "eaverage " << endl;
258   eaverage=parallel_sum(eaverage)/totweight;
259 
260   eref=eaverage;
261   single_write(cout, " setting eref= ", eref, "\n");
262   int totconf=parallel_sum(nconfig);
263   doublevar eaverage2=0;
264   for(int i=0; i < nconfig; i++){
265     doublevar effenergy=pts[i].prop.energy(0);
266     eaverage2+=(effenergy-eaverage)
267                *(effenergy-eaverage);
268   }
269 
270   eaverage2=parallel_sum(eaverage2)/totconf;
271 
272   //The variance of the starting distribution.
273   doublevar sigmac=sqrt(eaverage2);
274 
275   branchcut_start=branch_start_cutoff*sigmac; //start of cutoff region for branching
276   branchcut_stop=branch_stop_cutoff*sigmac; //end of cutoff region
277 
278   single_write(cout, " start branch cut at ", branchcut_start, "\n");
279   single_write(cout, " stop branch cut at ", branchcut_stop, "\n");
280 
281 
282 }
283 
284 //----------------------------------------------------------------------
285 
run(Program_options & options,ostream & output)286 void Rndmc_method::run(Program_options & options, ostream & output) {
287   if(!have_allocated_variables)
288     error("Must generate variables to use Dmc_method::run");
289   string logfile=options.runid+".log";
290   string logfile2=options.runid+"_unbiased.log";
291   string logfile3=options.runid+"_abs_weights.log";
292 
293   //MB: adding 2 new log files
294   //MB: one with unbiased weights according to lubos
295   //MB: one with absolute weights to calculate the efficiency
296   if(mpi_info.node==0 ) {
297     ofstream logout(logfile.c_str(), ios::app);
298     logout << "#-------------------------------------------------\n";
299     logout << "#RN-DMC run: biased weights, timestep " << timestep
300            << endl;
301     logout << "#-------------------------------------------------\n\n\n";
302     logout.close();
303     ofstream logout2(logfile2.c_str(), ios::app);
304     logout2 << "#-------------------------------------------------\n";
305     logout2 << "#RN-DMC run: unbiased weights, timestep " << timestep
306            << endl;
307     logout2 << "#-------------------------------------------------\n\n\n";
308     logout2.close();
309 
310     ofstream logout3(logfile3.c_str(), ios::app);
311     logout3 << "#-------------------------------------------------\n";
312     logout3 << "#RN-DMC run: absolute weights, timestep " << timestep
313            << endl;
314     logout3 << "#-------------------------------------------------\n\n\n";
315     logout3.close();
316   }
317 
318   //MB: setting up the property managers
319   myprop.setLog(logfile, log_label);
320   myprop_unbiased.setLog(logfile2, log_label);
321   myprop_absolute.setLog(logfile3, log_label);
322   runWithVariables(myprop, mysys, mywfdata, mypseudo, output);
323 }
324 
325 //----------------------------------------------------------------------
326 
327 /*!
328 
329 
330  */
331 
332 //MB: takes the weights inthe array of pts and finds all negatives
333 //MB: and cancel them out with some positive weights
334 //MB: only the components of energy and energy are properly adjusted
335 //MB: for all the other properties you will neeed to fill in
336 
produce_positive_weights(Array2<Dmc_point> & pts)337 void produce_positive_weights( Array2 <Dmc_point> & pts){
338   int nconfig=pts.GetDim(0);
339   int npsteps=pts.GetDim(1);
340   int nfunc=pts(0,0).prop.weight.GetSize();
341 
342   for(int p=0; p < npsteps; p++) {
343     Array1 <Properties_point> prop_original(nconfig);
344     Properties_point new_effective;
345     doublevar ave_pos_weight=0.0;
346     doublevar sum_neg_weights=0.0;
347 
348     vector <int>  chosen_neg_walker;
349     vector <int>  all_pos_walker;
350     for(int walker=0; walker < nconfig; walker++) {
351       prop_original(walker)=pts(walker,p).prop;
352       if( pts(walker,p).prop.weight(0)>0 ){
353 	ave_pos_weight+=pts(walker,p).prop.weight(0);
354 	all_pos_walker.push_back(walker);
355       }
356       else if(pts(walker,p).prop.weight(0)<0){
357 	sum_neg_weights+=abs(pts(walker,p).prop.weight(0));
358 	chosen_neg_walker.push_back(walker);
359       }
360     }//walker
361 
362     new_effective=prop_original(0);
363     new_effective.kinetic=0;
364     new_effective.potential=0;
365     new_effective.nonlocal=0;
366     new_effective.weight=0;
367 
368     if(all_pos_walker.size())
369       ave_pos_weight/=all_pos_walker.size();
370     else{
371       error("All weight are negative, not able to the unbiased reweighting");
372     }
373     if(ave_pos_weight*all_pos_walker.size() < sum_neg_weights){
374       cout << "node: "<< mpi_info.node <<" sum of possitive weights= "<<ave_pos_weight*all_pos_walker.size()<<" |sum of negative weights|= "<< sum_neg_weights<<endl;
375       error("not able to the unbiased reweighting !");
376     }
377     //cout <<"sum of possitive weights= "<<ave_pos_weight*all_pos_walker.size()<<" |sum of negative weights|= "<< sum_neg_weights<<endl;
378     if(sum_neg_weights>0){
379       cout << "node: "<<mpi_info.node <<" ave_pos_weight "<<ave_pos_weight<<endl;
380       cout << "node: "<<mpi_info.node <<" sum_neg_weights "<<sum_neg_weights<<endl;
381     }
382 
383     vector <int>  chosen_pos_walker;
384     Array1 <int> notselected(nconfig);
385     notselected=1;
386     doublevar residual_weight=0;
387     if(sum_neg_weights > 0.0){
388 
389       doublevar sum_chosen_pos_weights=0;
390       int tries=0;
391       while(sum_chosen_pos_weights< sum_neg_weights+ave_pos_weight){
392 	int walker=int(nconfig*rng.ulec());
393 	//cout <<"randomly chosen walker: "<<walker<<" with weight "<<pts(walker,p).prop.weight(0)<<" notselected? "<<notselected(walker)<<endl;
394 	if(pts(walker,p).prop.weight(0)>0 && notselected(walker)){
395 	  //cout <<"accepted "<< walker <<endl;
396 	  sum_chosen_pos_weights+=pts(walker,p).prop.weight(0);
397 	  chosen_pos_walker.push_back(walker);
398 	  notselected(walker)=0;
399 	}
400 	//cout <<" tried "<<tries<<endl;
401 	if(tries > 2*nconfig){
402 	  error("too many tries to match the negative weights");
403 	}
404 	tries++;
405       }//while
406       cout << "node: "<<mpi_info.node << " tries "<<tries<<endl;
407 
408       residual_weight=sum_chosen_pos_weights-sum_neg_weights;
409       //cout <<" residual_weight "<<residual_weight<<endl;
410 
411       /*
412 	will need to get new effective values for these
413       Array1 <doublevar> kinetic;
414       Array1 <doublevar> potential;
415       Array1 <doublevar> nonlocal;
416       Array1 <doublevar> weight; //!< averaging weight
417       Wf_return wf_val; //!< wavefunction value
418       Array1 <dcomplex> z_pol; //!< =exp(i G dot sum x_j)
419       Array2 <doublevar> aux_energy;
420       Array2 <doublevar> aux_weight;
421       Array1 <doublevar> aux_jacobian;
422       Array1 <Wf_return> aux_wf_val;
423       Array2 <dcomplex> aux_z_pol;
424       doublevar gf_weight; //weight of green's function between this and the last point(used in DMC)
425       Array1 <doublevar> aux_gf_weight;
426       Array1 <Average_return> avgrets;
427       */
428 
429 
430 
431 
432       for(int k=0;k<chosen_pos_walker.size();k++){
433 	int w=chosen_pos_walker[k];
434 	doublevar weight=abs(prop_original(w).weight(0));
435        	for(int f=0;f<nfunc;f++){
436 	  new_effective.kinetic(f)+=weight*prop_original(w).kinetic(f);
437 	  new_effective.potential(f)+=weight*prop_original(w).potential(f);
438 	  new_effective.nonlocal(f)+=weight*prop_original(w).nonlocal(f);
439 	}
440       }
441       for(int k=0;k<chosen_neg_walker.size();k++){
442 	int w=chosen_neg_walker[k];
443 	doublevar weight=abs(prop_original(w).weight(0));
444 	for(int f=0;f<nfunc;f++){
445 	  new_effective.kinetic(f)-=weight*prop_original(w).kinetic(f);
446 	  new_effective.potential(f)-=weight*prop_original(w).potential(f);
447 	  new_effective.nonlocal(f)-=weight*prop_original(w).nonlocal(f);
448 	}
449       }
450       for(int f=0;f<nfunc;f++){
451 	new_effective.kinetic(f)/=residual_weight;
452 	new_effective.potential(f)/=residual_weight;
453 	new_effective.nonlocal(f)/=residual_weight;
454 	new_effective.weight(f)=residual_weight;
455       }
456       //cout <<"new_effective.energy(0) "<< new_effective.energy(0)<<endl;
457       //cout <<"new_effective.weight(0) "<< new_effective.weight(0)<<endl;
458 
459     }//sum_neg_weight > 0.0
460 
461 
462     int counter=0;
463     //coping all not chosen
464     for(int walker=0; walker < nconfig; walker++) {
465       //cout <<"notselected array "<<notselected(walker)<<endl;
466       if(notselected(walker) && prop_original(walker).weight(0) >0 ){
467 	pts(counter++,p).prop=prop_original(walker);
468       }
469     }
470     //coping 1 new effective positive walker
471     if(counter<nconfig)
472       pts(counter++,p).prop=new_effective;
473 
474     //making the rest all zeros
475     while(counter<nconfig){
476       pts(counter,p).prop.kinetic=0;
477       pts(counter,p).prop.potential=0;
478       pts(counter,p).prop.nonlocal=0;
479       pts(counter,p).prop.weight=0;
480       counter++;
481     }
482   }//p
483 }
484 
485 
486 
487 
runWithVariables(Properties_manager & prop,System * sys,Wavefunction_data * wfdata,Pseudopotential * pseudo,ostream & output)488 void Rndmc_method::runWithVariables(Properties_manager & prop,
489 				    System * sys,
490 				    Wavefunction_data * wfdata,
491 				    Pseudopotential * pseudo,
492 				    ostream & output)
493 {
494 
495   allocateIntermediateVariables(sys, wfdata);
496 
497   if(!wfdata->supports(laplacian_update))
498     error("RNDMC doesn't support all-electron moves..please"
499           " change your wave function to use the new Jastrow");
500 
501   cout.precision(15);
502   output.precision(10);
503 
504 
505   prop.setSize(wf->nfunc(), nblock, nstep, nconfig, sys,
506 	       wfdata);
507 
508   //MB: setting things for the myprop_unbiased and myprop_absolute
509   myprop_unbiased.setSize(wf->nfunc(), nblock, nstep, nconfig, sys,
510 	       wfdata);
511 
512   myprop_absolute.setSize(wf->nfunc(), nblock, nstep, nconfig, sys,
513 	       wfdata);
514   restorecheckpoint(readconfig, sys, wfdata, pseudo);
515 
516   prop.initializeLog(average_var);
517 
518   myprop_unbiased.initializeLog(average_var);
519 
520   myprop_absolute.initializeLog(average_var);
521 
522   //MB: setting initial sign for each walker and getting the average value;
523   doublevar tmp_value=0.0;
524   Wf_return wf_val(nwf,1);
525   for(int walker=0; walker < nconfig; walker++) {
526     pts(walker).config_pos.restorePos(sample);
527     wf->updateVal(wfdata, sample);
528     wf->getVal(wfdata,0,wf_val);
529     pts(walker).sign=wf_val.sign(0);
530     tmp_value+=exp(2*wf_val.amp(0,0));
531     //cout <<"value "<<exp(wf_val.amp(0,0))<<endl;
532   }
533   //MB: rescaling the alpha for the average value
534   doublevar average_value=sqrt(tmp_value)/nconfig;
535   average_value=parallel_sum(average_value)/parallel_sum(1);
536   if( mpi_info.node==0 )
537     cout <<" average_value: " << average_value<<endl;
538 
539   alpha*=average_value;
540 
541   if( mpi_info.node==0 )
542     cout <<" rescaled alpha: "<<alpha<<endl;
543   //MB: seting it in the guidingwf
544   guidingwf->set_alpha_for_noderelease(alpha);
545 
546 
547 
548 
549 
550   nhist=1;
551   //setting the projection time for auxillary walkers to 1 a.u.
552 
553   doublevar teff=timestep;
554 
555   for(int block=0; block < nblock; block++) {
556 
557     int totkilled=0;
558     int totbranch=0;
559     int totpoints=0;
560     for(int step=0; step < nstep; ) {
561       //cout <<"step: "<<step<<endl;
562       int npsteps=min(feedback_interval, nstep-step);
563 
564       Dynamics_info dinfo;
565       doublevar acsum=0;
566       doublevar deltar2=0;
567       Array1 <doublevar> epos(3);
568 
569       doublevar avg_acceptance=0;
570 
571       doublevar rf_diffusion=0; //diffusion rate without rejection
572 
573       Wf_return wf_val(nwf,5);
574       for(int walker=0; walker < nconfig; walker++) {
575 
576         pts(walker).config_pos.restorePos(sample);
577         wf->updateLap(wfdata, sample);
578 	//------Do several steps without branching
579         for(int p=0; p < npsteps; p++) {
580           pseudo->randomize();
581 
582           for(int e=0; e< nelectrons; e++) {
583             int acc;
584             acc=dyngen->sample(e, sample, wf, wfdata, guidingwf,
585                                dinfo, timestep);
586 
587             if(dinfo.accepted)
588               deltar2+=dinfo.diffusion_rate/(nconfig*nelectrons*npsteps);
589 
590 
591             if(dinfo.accepted) {
592               rf_diffusion+=dinfo.diffusion_rate/(nconfig*nelectrons*npsteps);
593 
594               pts(walker).age(e)=0;
595             }
596             else {
597               pts(walker).age(e)++;
598             }
599             avg_acceptance+=dinfo.acceptance/(nconfig*nelectrons*npsteps);
600 
601             if(acc>0) acsum++;
602           }
603 
604           totpoints++;
605           Properties_point pt;
606           vector <Tmove> tmov;
607           doublevar subtract_out_enwt=0;
608           if(tmoves) {  //------------------T-moves
609             pt.setSize(nwf);
610             wf->getVal(wfdata,0,pt.wf_val);
611             sys->calcKinetic(wfdata,sample,wf,pt.kinetic);
612             pt.potential=sys->calcLoc(sample);
613             pt.weight=1.0; //this gets set later anyway
614             pt.count=1;
615             pseudo->calcNonlocTmove(wfdata,sys,sample,wf,pt.nonlocal,tmov);
616             //cout << "choosing among " <<  tmov.size() << " tmoves " << endl;
617             //Now we do the t-move
618             doublevar sum=1;
619             for(vector<Tmove>::iterator mov=tmov.begin(); mov!=tmov.end(); mov++) {
620               assert(mov->vxx < 0);
621               sum-=timestep*mov->vxx;
622             }
623             pt.nonlocal(0)-=(sum-1)/timestep;
624             subtract_out_enwt=-(sum-1)/timestep;
625             //cout << "sum " << sum <<  " nonlocal " << pt.nonlocal(0) << " ratio " << sum/pt.nonlocal(0) << endl;
626             assert(sum >= 0);
627             doublevar rand=rng.ulec()*sum;
628             sum=1; //reset to choose the move
629             if(rand > sum) {
630               for(vector<Tmove>::iterator mov=tmov.begin(); mov!=tmov.end(); mov++) {
631                 sum-=timestep*mov->vxx;
632                 if(rand < sum) {
633                   Array1 <doublevar> epos(3);
634                   sample->getElectronPos(mov->e, epos);
635                   //cout << "moving electron " << mov->e << " from " << epos(0) << " " << epos(1)
636                   //  << " " << epos(2) << " to " << mov->pos(0) << " " << mov->pos(1)
637                   //  << " " << mov->pos(2) << endl;
638                   sample->setElectronPos(mov->e,mov->pos);
639                   break;
640                 }
641               }
642             }
643             //wf->updateLap(wfdata, sample);
644           } ///---------------------------------done with the T-moves
645           else {
646 	    //MB: this is where all the properties at the new step are evaluated
647             mygather.gatherData(pt, pseudo, sys, wfdata, wf,
648                                 sample, guidingwf);
649 
650 	  }
651 
652           Dmc_history new_hist;
653           new_hist.main_en=pts(walker).prop.energy(0);
654           pts(walker).past_energies.push_front(new_hist);
655           deque<Dmc_history> & past(pts(walker).past_energies);
656           if(past.size() > nhist)
657             past.erase(past.begin()+nhist, past.end());
658 
659 	  //copy pt to pts(walker).prop
660           pts(walker).prop=pt;
661 
662 	  //MB: this is how we track the sign
663           //MB: pts(walker).sign is before the step and the pts(walker).prop.sign(0) is after
664           //MB: if they change weight will change the sign as well
665 	  if(pts(walker).sign!=pts(walker).prop.wf_val.sign(0)){
666 	    cout <<"node: "<<mpi_info.node <<" walker "<<walker<<" changed the sign "<<endl;
667 	    //cout <<" pts(walker).weight "<<pts(walker).weight<<" pts(walker).prop.weight(0) "<<pts(walker).prop.weight(0)<<
668 	    // " pts(walker).sign "<<pts(walker).sign<<" pts(walker).prop.sign "<<pts(walker).prop.sign<<endl;
669 	    pts(walker).sign*=-1;
670 	    pts(walker).weight*=-1;
671 	  }
672 
673 	  //MB: this is part of normal DMC run
674           //MB: because we do not branch adjusting the weights according
675           //MB: to etrial makes no sence, but disscuss this with lubos, I am leaving this out
676 
677 	  //pts(walker).weight*=getWeight(pts(walker),teff,etrial);
678 
679           if(pts(walker).ignore_walker) {
680             pts(walker).ignore_walker=0;
681             pts(walker).weight=1;
682             pts(walker).prop.count=0;
683           }
684 
685 	  //MB: this is new, since in DMC pts(walker).prop.weight(0)=1, this was not needed
686           //MB: because alpha>0 it is no longer true
687 	  pts(walker).weight*=pts(walker).prop.weight(0);
688 	  //keep total weight in pts(walker).weight
689 
690 	  //MB: finnaly everything is put to pts(walker).prop for averaging
691           pts(walker).prop.weight=pts(walker).weight;
692     //LKW: prop.sign() is redundant information..either the sign should be in
693           //the weight or in wf_val.
694 	  //pts(walker).prop.sign=pts(walker).sign;
695 
696 	  //cout <<"final weight is "<<pts(walker).prop.weight(0)<<endl;
697 
698           //This is somewhat inaccurate..will need to change it later
699           //For the moment, the autocorrelation will be slightly
700           //underestimated
701           pts(walker).prop.parent=walker;
702           pts(walker).prop.nchildren=1;
703           pts(walker).prop.children(0)=walker;
704           pts(walker).prop.avgrets.Resize(1,average_var.GetDim(0));
705           for(int i=0; i< average_var.GetDim(0); i++) {
706             average_var(i)->evaluate(wfdata, wf, sys, sample, pts(walker).prop.avgrets(0,i));
707           }
708 
709 	  //MB: after evaluating the properties all are stored in the prop
710           prop.insertPoint(step+p, walker, pts(walker).prop);
711 
712        	  //MB: copy pts for the calculation of unbiased walker
713 	  pts_unbiased(walker, p).prop=pts(walker).prop;
714 
715 	  //MB: copy another pts for absolute weights
716 	  Dmc_point  pts_absolute;
717 	  pts_absolute=pts(walker);
718 	  pts_absolute.prop.weight=fabs(pts_absolute.prop.weight(0));
719 	  myprop_absolute.insertPoint(step+p, walker, pts_absolute.prop);
720 
721 
722           for(int i=0; i< densplt.GetDim(0); i++)
723             densplt(i)->accumulate(sample,pts(walker).prop.weight(0));
724 	  for(int i=0; i< nldensplt.GetDim(0); i++)
725 	    nldensplt(i)->accumulate(sample,pts(walker).prop.weight(0),
726 				     wfdata,wf);
727         }//p
728 
729         pts(walker).config_pos.savePos(sample);
730       }//walker
731       //---Finished moving all walkers
732 
733       /*
734       just debug printout
735       cout <<"before produce_positive_weights"<<endl;
736       for(int p=0; p < npsteps; p++) {
737 	for(int walker=0; walker < nconfig; walker++) {
738 	  cout <<"energy: "<<pts_unbiased(walker,p).prop.energy(0)<<" weight "<<pts_unbiased(walker,p).prop.weight(0)<<endl;
739 	}
740 	cout <<endl;
741       }
742       */
743 
744       //MB: this makes unbiased positive  weights according the to lubos scheme
745       //MB: current drawback is that happens on each node separately so meake sure you have enough walkers per node!
746       produce_positive_weights(pts_unbiased);
747 
748       //cout <<"after produce_positive_weights"<<endl;
749       //MB: store unbiased prop for averaging
750       for(int p=0; p < npsteps; p++) {
751 	for(int walker=0; walker < nconfig; walker++) {
752 	  //cout <<"energy: "<<pts_unbiased(walker,p).prop.energy(0)<<" weight "<<pts_unbiased(walker,p).prop.weight(0)<<endl;
753 	  myprop_unbiased.insertPoint(step+p, walker, pts_unbiased(walker,p).prop);
754 	 }
755 	//cout <<endl;
756        }
757 
758       doublevar accept_ratio=acsum/(nconfig*nelectrons*npsteps);
759       teff=timestep*accept_ratio; //deltar2/rf_diffusion;
760 
761       updateEtrial(feedback);
762 
763       step+=npsteps;
764 
765       //MB: turnning off branching
766       int nkilled=0; //calcBranch();
767       totkilled+=nkilled;
768       totbranch+=nkilled;
769     }//step
770     //cout <<"Finished block "<<endl;
771     ///----Finished block
772 
773     if(!low_io || block==nblock-1) {
774       savecheckpoint(storeconfig,sample);
775       for(int i=0; i< densplt.GetDim(0); i++)
776         densplt(i)->write();
777       for(int i=0; i< nldensplt.GetDim(0); i++)
778         nldensplt(i)->write(log_label);
779     }
780 
781 
782     prop.endBlock();
783     //MB: averaging over block for the unbiased and absolute weights
784     myprop_unbiased.endBlock();
785     myprop_absolute.endBlock();
786 
787     totbranch=parallel_sum(totbranch);
788     totkilled=parallel_sum(totkilled);
789     totpoints=parallel_sum(totpoints);
790 
791     Properties_final_average finavg;
792     Properties_final_average finavg2;
793     Properties_final_average finavg3;
794 
795     prop.getFinal(finavg);
796     myprop_unbiased.getFinal(finavg2);
797     myprop_absolute.getFinal(finavg3);
798 
799 
800     Properties_block lastblock;
801     Properties_block lastblock2;
802     Properties_block lastblock3;
803 
804     prop.getLastBlock(lastblock);
805     myprop_unbiased.getLastBlock(lastblock2);
806     myprop_absolute.getLastBlock(lastblock3);
807 
808 
809     //MB: finalavg: total average value over all blocks up to this time
810     //MB: lastblock: average value for last block
811 
812     //MB: original DMC had eref as this:
813     eref=finavg2.avg(Properties_types::total_energy,0);
814     //MB: not sure this makes sence for the release node
815     //MB: maybe it should be only over the last block
816     //eref=lastblock2.avg(Properties_types::total_energy,0);
817 
818     updateEtrial(feedback);
819 
820     //MB: this is lubos's effectivity, which is ratio of averaged signed
821     //MB: weights to averaged absolute weights
822     //MB: bellow is the value for each block
823 
824     doublevar effectivity;
825     doublevar weight_biased=lastblock.avg(Properties_types::weight,0);
826     doublevar weight_abs=lastblock3.avg(Properties_types::weight,0);
827 
828     effectivity=weight_biased/weight_abs;
829 
830     doublevar maxage=0;
831     doublevar avgage=0;
832     for(int w=0;w < nconfig; w++) {
833       for(int e=0; e< nelectrons; e++) {
834         if(maxage<pts(w).age(e)) maxage=pts(w).age(e);
835         avgage+=pts(w).age(e);
836       }
837     }
838     avgage/=(nconfig*nelectrons);
839 
840     if(output) {
841       //cout << "Block " << block
842       //       << " nconfig " << totconfig
843       //       << " etrial " << etrial << endl;
844       if(global_options::rappture ) {
845 	    ofstream rapout("rappture.log");
846         rapout << "=RAPPTURE-PROGRESS=>" << int(100.0*doublevar(block+1)/doublevar(nblock))
847                << "  Diffusion Monte Carlo" << endl;
848         cout << "=RAPPTURE-PROGRESS=>" << int(100.0*doublevar(block+1)/doublevar(nblock))
849              << "  Diffusion Monte Carlo" << endl;
850         rapout.close();
851       }
852       output << "***" << endl;
853       output << "Block " << block
854              << " etrial " << etrial << endl;
855       output << "maximum age " << maxage
856 	     << " average age " << avgage << endl;
857       dyngen->showStats(output);
858 
859       output<<"\n ---- biased weights ---- \n";
860       prop.printBlockSummary(output);
861       output<<"\n ---- unbiased weights ---- \n";
862       myprop_unbiased.printBlockSummary(output);
863 
864       output<<"\n ---- absolute weights ---- \n";
865       myprop_absolute.printBlockSummary(output);
866       output<<"\n effectivity  "<<effectivity<<" signed weight "<<weight_biased<<" absolute weight "<<weight_abs<<endl;
867 
868       output << "Branched "
869 	     << totbranch << " times.  So a branch every "
870 	     << doublevar(totpoints)/doublevar(totbranch)
871 	     << " steps " << endl;
872     }
873 
874     dyngen->resetStats();
875 
876   }//block
877 
878   if(output) {
879     output << "\n ----------Finished RN-DMC------------\n\n";
880     output<<"\n ---- biased weights ---- \n";
881     prop.printSummary(output,average_var);
882     output<<"\n ---- unbiased weights ---- \n";
883     myprop_unbiased.printSummary(output,average_var);
884     output<<"\n ---- absolute weights ---- \n";
885     myprop_absolute.printSummary(output,average_var);
886   }
887   wfdata->clearObserver();
888   deallocateIntermediateVariables();
889 }
890 
891 
892 //----------------------------------------------------------------------
893 
894 
savecheckpoint(string & filename,Sample_point * config)895 void Rndmc_method::savecheckpoint(string & filename,
896                                  Sample_point * config) {
897   if(filename=="") return;
898   ofstream checkfile(filename.c_str());
899   if(!checkfile) error("Couldn't open", filename );
900   checkfile.precision(15);
901 
902   long int is1, is2;
903   rng.getseed(is1, is2);
904   checkfile << "RANDNUM " << is1 << "  " << is2 << endl;
905 
906   checkfile.precision(15);
907   for(int i=0; i< nconfig; i++) {
908     Dmc_point & mypt(pts(i));
909     checkfile << "SAMPLE_POINT { \n";
910     mypt.config_pos.restorePos(config);
911     write_config(checkfile, config);
912     checkfile << "   DMC { \n";
913     checkfile << "DMCWEIGHT " << mypt.weight << endl;
914     checkfile << "VALEN " << nwf << endl;
915     for(int w=0; w< nwf; w++) {
916       checkfile << mypt.prop.wf_val.phase(w,0) << "  "
917 		<< mypt.prop.wf_val.amp(w,0) << "  "
918 		<< mypt.prop.energy(w)
919 		<< endl;
920     }
921 
922     checkfile << "   } \n";
923     checkfile << "}\n\n";
924   }
925 
926   checkfile.close();
927 }
928 
929 
930 //----------------------------------------------------------------------
931 
932 
933 
restorecheckpoint(string & filename,System * sys,Wavefunction_data * wfdata,Pseudopotential * pseudo)934 void Rndmc_method::restorecheckpoint(string & filename, System * sys,
935                                     Wavefunction_data * wfdata,
936                                     Pseudopotential * pseudo) {
937 
938 
939   ifstream checkfile(filename.c_str());
940   if(!checkfile)
941     error("Couldn't open ", filename);
942   long int is1, is2;
943   string dummy;
944   checkfile >> dummy;
945   if(dummy != "RANDNUM") error("Expected RANDNUM in checkfile");
946   checkfile >> is1 >> is2;
947   rng.seed(is1, is2);
948 
949   Array1 <Wf_return > value_temp(nconfig);
950   Array2 <doublevar> energy_temp(nconfig, nwf);
951 
952 
953   int ncread=0; //Number of configs read
954   int nwread=0; //number of weights read
955   while(checkfile >> dummy &&
956 	( ncread < nconfig && nwread < nconfig) ) {
957 
958 
959     if(read_config(dummy, checkfile, sample)) {
960       pts(ncread++).config_pos.savePos(sample);
961 
962     }
963 
964     if(dummy=="DMC") {
965       checkfile >> dummy;
966       if(dummy != "{") error("Need a { after DMC");
967       checkfile >> dummy >> pts(nwread).weight;
968       if(dummy != "DMCWEIGHT") {
969         error("expected DMCWEIGHT, got ", dummy);
970       }
971       int nwf_temp;
972       checkfile >> dummy >> nwf_temp;
973       if(dummy != "VALEN") {
974         error("expected VALEN, got ", dummy);
975       }
976       if(nwf_temp != nwf) {
977         error("Wrong number of wavefunctions in the checkpoint file");
978       }
979 
980       //Retrieve the old values and energies from the file
981       value_temp(nwread).Resize(nwf, 2);
982 
983       for(int w=0; w< nwf; w++) {
984         checkfile >> value_temp(nwread).phase(w,0)
985 		  >> value_temp(nwread).amp(w,0)
986                   >> energy_temp(nwread,w);
987       }
988       nwread++;
989 
990     }
991 
992   }
993 
994   //cout << "ncread " << ncread << "  nwread " << nwread << endl;
995   if(nconfig!=ncread) {
996     error("nconfig doesn't match the number of walkers in the config file");
997   }
998 
999 
1000   for(int walker=0; walker < nconfig; walker++) {
1001     pts(walker).config_pos.restorePos(sample);
1002     mygather.gatherData(pts(walker).prop, pseudo, sys,
1003                         wfdata, wf, sample,
1004                         guidingwf);
1005   }
1006 
1007   find_cutoffs();
1008 
1009   updateEtrial(start_feedback);
1010 
1011   if(do_cdmc) {
1012     if(ncread!=nwread) {
1013       cout << "WARNING! do_cdmc and ncread!=nwread " << endl;
1014     }
1015     cdmcReWeight(energy_temp, value_temp);
1016   }
1017 
1018 
1019 }
1020 
1021 
1022 //----------------------------------------------------------------------
1023 
cdmcReWeight(Array2<doublevar> & energy_temp,Array1<Wf_return> & value_temp)1024 void Rndmc_method::cdmcReWeight(Array2 <doublevar> & energy_temp,
1025                               Array1 < Wf_return > & value_temp
1026                               ) {
1027   //The following is for C-DMC(from Jeff)  It shouldn't
1028   //do anything unless the atomic coordinates have moved
1029   //It's commented out for the moment from the rewrite.
1030   //It's viewed as experimental code, so watch out!
1031 
1032   //Get the energies for the old ionic configurations and
1033   //this configuration
1034   /*
1035   Array1 <doublevar> effenergy_temp(nconfig, 0.0);
1036   Array1 <doublevar> effoldenergy(nconfig,0.0);
1037 
1038   for(int i=0; i< nconfig; i++) {
1039     for(int w=0; w< nwf; w++) {
1040       effenergy_temp(i)+=(energy_temp(i,w)+offset(w))
1041         *guidingwf->getOperatorWeight(value_temp(i),w);
1042 
1043       doublevar olden=trace[0][i].energy(w);
1044       effoldenergy(i)+=(olden+offset(w))
1045         *guidingwf->getOperatorWeight(trace[0][i].wf_val, w);
1046     }
1047   }
1048 
1049 
1050 
1051   doublevar average_temp, variance_temp;
1052 
1053   average(0, nconfig, effenergy_temp,
1054           dmcweight, average_temp, variance_temp, 1);
1055 
1056   doublevar sigma_temp;
1057   if(variance_temp >0) {
1058     sigma_temp=sqrt(variance_temp);
1059   }
1060   else {
1061     sigma_temp=0;
1062     error("negative variance when reading in weights");
1063   }
1064 
1065   debug_write(cout, "average_temp ", average_temp, "\n");
1066   debug_write(cout, "sigma_temp ", sigma_temp, "\n");
1067 
1068   //Reweight and check whether we had a sign flip
1069   //(overlap will be either positive or negative
1070 
1071   if(do_cdmc) {
1072     doublevar norm1=0, norm2=0;
1073     for(int i=0; i< nconfig; i++) {
1074       //norm1+=exp(prop.trace(0,i).wf_val(0,1)*2.0);
1075       norm1+=exp(trace[0][i].wf_val.amp(0,0)*2.0);
1076 
1077       norm2+=exp(2.0*value_temp(i).amp(0,0));
1078     }
1079 
1080     int totconfig=parallel_sum(nconfig);
1081     norm1=parallel_sum(norm1)/totconfig;
1082     norm2=parallel_sum(norm2)/totconfig;
1083 
1084     //Removed the normalization(norm2/norm1), because it causes problems
1085     //for bigger systems
1086 
1087     doublevar overlap=0;
1088     for(int i=0; i < nconfig; i++) {
1089       doublevar ratio;
1090       ratio=guidingwf->getTrialRatio(trace[0][i].wf_val, value_temp(i));
1091       overlap+=ratio/nconfig; //check if there's an overall sign change
1092 
1093       //cout << "walker " << i << " new val " << trace[0][i].wf_val(0,1)
1094       //     << " old one " << value_temp(i)(0,1) << endl;
1095 
1096       dmcweight(i)*= ratio*ratio//  *norm2/norm1
1097         *exp(-(effoldenergy(i)-effenergy_temp(i))*timestep/2);
1098     }
1099 
1100     single_write(cout, "overlap between old and new ", overlap);
1101     doublevar average_old=0.0, diff_sigma=0.0;
1102 
1103     for(int w=0; w< nconfig; w++)  {
1104        average_old+=effoldenergy(w)/nconfig;
1105        diff_sigma+=(effoldenergy(w)-effenergy_temp(w))*(effoldenergy(w)-effenergy_temp(w))/nconfig;
1106     }
1107     //cout << "difference " << average_temp-average_old <<"  +/-  " << diff_sigma/nconfig << endl;
1108 
1109     //We ignore walkers that either a)cross a node, or
1110     //b) are outside of 10 sigmas(for the first move)
1111     //ofstream diffout("diff_en.dat");
1112     int ncross=0, nsigma=0;
1113     for(int i=0; i< nconfig; i++) {
1114       doublevar ratio;
1115       ratio=guidingwf->getTrialRatio(trace[0][i].wf_val, value_temp(i));
1116       //cout << "ratio " << i << "   " << ratio << endl;
1117       if(ratio*overlap < 0) {
1118         debug_write(cout, "crossed node ", i , "\n");
1119         ncross++;
1120         trace[0][i].count=0;
1121         dmcweight(i)=1;
1122         ignore_walker(i)=1;
1123       }
1124       else if(fabs(effenergy_temp(i)-average_temp) > 10*sigma_temp) {
1125         debug_write(cout, "walker out of 10 sigmas ", i, "\n");
1126 
1127         nsigma++;
1128         trace[0][i].count=0;
1129         dmcweight(i)=1;
1130         ignore_walker(i)=1;
1131       }
1132       // diffout << i << "   " << effenergy_temp(i)-effoldenergy(i) << endl;
1133     }
1134     //diffout.close();
1135 
1136     single_write(cout, "nsigma ", parallel_sum(nsigma));
1137     single_write(cout, "  ncross  ", parallel_sum(ncross), "\n");
1138 
1139   }
1140 
1141   */
1142 
1143 
1144 }
1145 
1146 
1147 //----------------------------------------------------------------------
1148 
updateEtrial(doublevar feed)1149 void Rndmc_method::updateEtrial(doublevar feed) {
1150 
1151   doublevar totweight=0;
1152   for(int walker=0; walker < nconfig; walker++)
1153     totweight+=pts(walker).weight;
1154 
1155   etrial=eref-feed*log(totweight/double(nconfig));
1156 
1157 #ifdef USE_MPI
1158   doublevar mpitot=0;
1159   MPI_Allreduce(&totweight,&mpitot, 1,
1160                 MPI_DOUBLE, MPI_SUM, MPI_Comm_grp);
1161   etrial=eref-feed*log(mpitot/double(mpi_info.nprocs*nconfig));
1162 #endif
1163 
1164   //cout << "etrial " << etrial << " total weight " << totweight << endl;
1165 
1166 }
1167 
1168 //----------------------------------------------------------------------
1169 
getWeight(Dmc_point & pt,doublevar teff,doublevar etr)1170 doublevar Rndmc_method::getWeight(Dmc_point & pt,
1171                                 doublevar teff, doublevar etr) {
1172   doublevar teffac=teff/2.0;
1173 
1174   doublevar effenergy=0, effoldenergy=0;
1175 
1176   effenergy=pt.prop.energy(0);
1177   effoldenergy=pt.past_energies[0].main_en;
1178 
1179   doublevar fbet=max(etr-effenergy, etr-effoldenergy);
1180 
1181   if(fbet > branchcut_stop) {
1182     teffac=0;
1183   }
1184   else if(fbet > branchcut_start) {
1185     teffac=teffac*(1.-(fbet-branchcut_start)
1186                    /(branchcut_stop-branchcut_start));
1187   }
1188 
1189   doublevar return_weight;
1190   //if(tmoves) return_weight=exp(teffac*2.0*(etr-effenergy));
1191   //else
1192   return_weight=exp(teffac*(etr*2-effenergy-effoldenergy));
1193 
1194   return return_weight;
1195 }
1196 
1197 //----------------------------------------------------------------------
1198 
1199 
1200 //----------------------------------------------------------------------
1201 struct Queue_element {
1202   int from_node;
1203   int to_node;
Queue_elementQueue_element1204   Queue_element() { }
Queue_elementQueue_element1205   Queue_element(int from, int to) { from_node=from; to_node=to; }
1206 };
1207 
1208 struct Walker_sort {
1209   int node;
1210   int index; //on the node
1211   int branch; //how many copies to make
1212   doublevar weight;
1213 };
1214 
1215 
1216 
calcBranch()1217 int Rndmc_method::calcBranch() {
1218   int totwalkers=mpi_info.nprocs*nconfig;
1219   Array1 <doublevar> weights(totwalkers);
1220   Array1 <doublevar> my_weights(nconfig);
1221 
1222   for(int walker=0; walker < nconfig; walker++)
1223     my_weights(walker)=pts(walker).weight;
1224 #ifdef USE_MPI
1225   MPI_Allgather(my_weights.v,nconfig, MPI_DOUBLE, weights.v,nconfig,MPI_DOUBLE, MPI_Comm_grp);
1226 #else
1227   weights=my_weights;
1228 #endif
1229   Array1 <int> my_branch(nconfig);
1230   Array1 <int> nwalkers(mpi_info.nprocs);
1231   nwalkers=0;
1232   int root=0;
1233   if(mpi_info.node==root) {  //this if/else clause may be refactored out
1234 
1235     Array1 <int> branch(totwalkers);
1236     //----Find which walkers branch/die
1237     //we do it on one node since otherwise we'll have different random numbers!
1238     //we'll assign the weight for each copy that will be produced
1239     //this is the core of the branching algorithm..
1240     //my homegrown algo, based on Umrigar, Nightingale, and Runge
1241     branch=-1;
1242     const doublevar split_threshold=1.8;
1243     for(int w=0; w< totwalkers; w++) {
1244       if(weights(w) > split_threshold && branch(w)==-1) {
1245         //find branching partner
1246         doublevar smallestwt=100;
1247         int smallest=-1;
1248         for(int w2=0; w2 < totwalkers; w2++) {
1249           if(branch(w2)==-1 && w2!= w && weights(w2) < smallestwt) {
1250             smallest=w2;
1251             smallestwt=weights(w2);
1252           }
1253         }
1254         if(smallest != -1) {
1255           doublevar weight1=weights(w)/(weights(w)+weights(smallest));
1256           if(weight1+rng.ulec() >= 1.0) {
1257             branch(w)=2;
1258             branch(smallest)=0;
1259             weights(w)+=weights(smallest);
1260             weights(w)/=2.0;
1261           }
1262           else {
1263             branch(w)=0;
1264             branch(smallest)=2;
1265             weights(smallest)+=weights(w);
1266             weights(smallest)/=2.0;
1267           }
1268         }
1269       }
1270     }
1271     for(int w=0; w< totwalkers; w++) {
1272       if(branch(w)==-1) branch(w)=1;
1273     }
1274     //----end homegrown algo
1275     //count how many walkers each node will have
1276     //without balancing
1277     int walk=0;
1278     for(int n=0; n< mpi_info.nprocs; n++) {
1279       for(int i=0; i< nconfig; i++) {
1280         nwalkers(n)+=branch(walk);
1281         walk++;
1282       }
1283       //cout << "nwalkers " << n << " " << nwalkers(n) << endl;
1284     }
1285     //now send nwalkers and which to branch to all processors
1286     for(int i=0; i< nconfig; i++) {
1287       my_branch(i)=branch(i);
1288       my_weights(i)=weights(i);
1289     }
1290 #ifdef USE_MPI
1291     MPI_Bcast(nwalkers.v, mpi_info.nprocs, MPI_INT, mpi_info.node, MPI_Comm_grp);
1292     for(int i=1; i< mpi_info.nprocs; i++) {
1293       MPI_Send(branch.v+i*nconfig,nconfig,MPI_INT,i,0,MPI_Comm_grp);
1294       MPI_Send(weights.v+i*nconfig, nconfig, MPI_DOUBLE, i,0,MPI_Comm_grp);
1295     }
1296 #endif
1297 
1298   }
1299   else {
1300 #ifdef USE_MPI
1301     MPI_Bcast(nwalkers.v, mpi_info.nprocs, MPI_INT, root, MPI_Comm_grp);
1302     MPI_Status status;
1303     MPI_Recv(my_branch.v,nconfig, MPI_INT,root,0,MPI_Comm_grp, &status);
1304     MPI_Recv(my_weights.v,nconfig, MPI_DOUBLE,root,0,MPI_Comm_grp, &status);
1305 #endif
1306   }
1307   //--end if/else clause
1308 
1309   for(int i=0; i< nconfig; i++) {
1310     pts(i).weight=my_weights(i);
1311   }
1312 
1313   //Now we all have my_branch and nwalkers..we need to figure out who
1314   //needs to send walkers to whom--after this, nwalkers should be a flat array equal to
1315   //nconfig(so don't try to use it for anything useful afterwards)
1316   vector <Queue_element> send_queue;
1317   int curr_needs_walker=0;
1318   int nnwalkers=nwalkers(mpi_info.node); //remember how many total we should have
1319   for(int i=0; i< mpi_info.nprocs; i++) {
1320     while(nwalkers(i) > nconfig) {
1321       if(nwalkers(curr_needs_walker) < nconfig) {
1322         nwalkers(curr_needs_walker)++;
1323         nwalkers(i)--;
1324         send_queue.push_back(Queue_element(i,curr_needs_walker));
1325         //cout << mpi_info.node << ":nwalkers " << nwalkers(i) << "  " << nwalkers(curr_needs_walker) << endl;
1326         //cout << mpi_info.node << ":send " << i << "  " << curr_needs_walker << endl;
1327       }
1328       else {
1329         curr_needs_walker++;
1330       }
1331     }
1332   }
1333 
1334   for(int i=0; i< mpi_info.nprocs; i++) assert(nwalkers(i)==nconfig);
1335   int killsize=0;
1336   for(int i=0; i< nconfig; i++) {
1337     //cout << mpi_info.node << ":branch " << i << "  " << my_branch(i) << " weight " << pts(i).weight <<  endl;
1338     if(my_branch(i)==0) killsize++;
1339   }
1340   //cout << mpi_info.node << ": send queue= " << send_queue.size() << endl;
1341   //now do branching for the walkers that we get to keep
1342   Array1 <Dmc_point> savepts=pts;
1343   int curr=0; //what walker we're currently copying from
1344   int curr_copy=0; //what walker we're currently copying to
1345   while(curr_copy < min(nnwalkers,nconfig)) {
1346     if(my_branch(curr)>0) {
1347       //cout << mpi_info.node << ": copying " << curr << " to " << curr_copy << " branch " << my_branch(curr) << endl;
1348       my_branch(curr)--;
1349       pts(curr_copy)=savepts(curr);
1350       //pts(curr_copy).weight=1;
1351       curr_copy++;
1352     }
1353     else curr++;
1354   }
1355 
1356   //Finally, send or receive spillover walkers
1357   if(nnwalkers > nconfig) {
1358     vector<Queue_element>::iterator queue_pos=send_queue.begin();
1359     while(curr < nconfig) {
1360       if(my_branch(curr) > 0) {
1361         my_branch(curr)--;
1362         while(queue_pos->from_node != mpi_info.node) {
1363           queue_pos++;
1364         }
1365         //cout << mpi_info.node << ":curr " << curr << " my_branch " << my_branch(curr) << endl;
1366         //cout << mpi_info.node << ":sending " << queue_pos->from_node << " to " << queue_pos->to_node << endl;
1367         savepts(curr).mpiSend(queue_pos->to_node);
1368         queue_pos++;
1369       }
1370       else curr++;
1371     }
1372 
1373   }
1374   else { //if nnwalkers == nconfig, then this will just get skipped immediately
1375     vector <Queue_element>::iterator queue_pos=send_queue.begin();
1376     while(curr_copy < nconfig) {
1377       while(queue_pos->to_node != mpi_info.node) queue_pos++;
1378       //cout << mpi_info.node <<":receiving from " << queue_pos->from_node << " to " << curr_copy << endl;
1379       pts(curr_copy).mpiReceive(queue_pos->from_node);
1380       //pts(curr_copy).weight=1;
1381       curr_copy++;
1382       queue_pos++;
1383     }
1384   }
1385   return killsize;
1386   //exit(0);
1387 }
1388 //----------------------------------------------------------------------
1389 
1390