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