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 #include "Split_sample.h"
22 #include "qmc_io.h"
23 
allocate(vector<string> & words,Dynamics_generator * & sam)24 int allocate(vector <string> & words, Dynamics_generator *& sam) {
25   if(caseless_eq(words[0],"SPLIT"))
26     sam=new Split_sampler;
27   else if(caseless_eq(words[0],"RUNGE"))
28     sam=new SRK_dmc;
29   else if(caseless_eq(words[0],"UNR"))
30     sam=new UNR_sampler;
31   else
32     error("unknown type of sampler: ", words[0]);
33 
34   sam->read(words);
35   return 1;
36 }
37 
38 //----------------------------------------------------------------------
39 
limDrift(Array1<doublevar> & drift,doublevar tau,drift_type dtype)40 void limDrift(Array1 <doublevar> & drift, doublevar tau, drift_type dtype)
41 {
42   doublevar drift2=0;
43   doublevar drifta=0;
44 
45 
46   if(dtype==drift_cutoff) {
47     const doublevar drmax=4;
48 
49     for(int d=0; d<3; d++)
50         drift2+=drift(d)*drift(d);
51 
52     drifta=drmax/max( (doublevar) sqrt(drift2), drmax);
53     //cout << "drifta " << drifta*tau << endl;
54     for(int d=0; d<3; d++) {
55         drift(d)*= tau*drifta;
56       }
57   }
58   else if(dtype==drift_cyrus) {
59 
60     const doublevar acyrus=0.25;
61 
62     doublevar tau2=tau*2.;
63 
64     for(int d=0; d<3; d++)
65       {
66         drift2+=drift(d)*drift(d);
67       }
68 
69     drift2*=acyrus;
70     if(drift2 > 1e-8)
71       drifta=(sqrt(1.+tau2*drift2)-1)/(drift2);
72     else drifta=tau;
73 
74     //cout << "drifta " << drifta << endl;
75     for(int d=0; d<3; d++)
76       drift(d)*=drifta;
77 
78   }
79   else {
80     error("Unknown drift_type in limDrift");
81   }
82 
83 }
84 
85 //-------------------------------------------------------------------
86 
87 /*!
88 returns the exponent of the transition probability for
89 going from point1 to point2
90  */
transition_prob(int point1,int point2,doublevar timestep,drift_type dtype)91 doublevar Split_sampler::transition_prob(int point1, int point2,
92                                          doublevar timestep,
93                                          drift_type dtype) {
94   doublevar prob=0;
95   static Array1 <doublevar> drift(3);
96   //cout << "transition probability" << endl;
97 
98   drift=trace(point1).drift;
99 
100   limDrift(drift, timestep, dtype);
101 
102   for(int d=0; d< 3; d++) {
103 
104     prob-=(trace(point2).pos(d)-trace(point1).pos(d)-drift(d))
105       *(trace(point2).pos(d)-trace(point1).pos(d)-drift(d));
106   }
107   prob/=(2.0*timestep);
108 
109   return prob;
110 }
111 
transition_prob(Point & point1,Point & point2,doublevar timestep,drift_type dtype)112 doublevar transition_prob(Point &  point1, Point & point2,
113                           doublevar timestep, drift_type dtype) {
114   doublevar prob=0;
115   Array1 <doublevar> drift(3);
116   //cout << "transition probability" << endl;
117 
118   drift=point1.drift;
119 
120 
121   limDrift(drift, timestep, dtype);
122 
123   for(int d=0; d< 3; d++) {
124     prob-=(point2.pos(d)-point1.pos(d)-drift(d))
125       *(point2.pos(d)-point1.pos(d)-drift(d));
126   }
127   prob/=(2.0*timestep);
128   return prob;
129 }
130 
131 //---------------------------------------------------------------------
132 
133 
runge_kutta_resamp(Point & p1,Point & p2,doublevar timestep,drift_type dtype,int ndim=3)134 doublevar runge_kutta_resamp(Point & p1, Point & p2,
135                                doublevar timestep, drift_type dtype,
136                           int ndim=3) {
137   Array1 <doublevar> dr1(3), dr2(3);
138   dr1=p1.drift; dr2=p2.drift;
139 
140   limDrift(dr1, timestep, dtype);
141   limDrift(dr2, timestep, dtype);
142   Array1 <doublevar> avg(3);
143   for(int d=0; d< 3; d++) {
144     avg(d)=(dr1(d)+dr2(d))/2.0;
145   }
146   doublevar green_forward=0;
147   for(int d=0; d< ndim; d++) {
148     green_forward+=(p2.pos(d)-p1.pos(d)-avg(d))*(p2.pos(d)-p1.pos(d)-avg(d));
149     //green_forward+=(p2.pos(d)-p1.pos(d))*(p2.pos(d)-p1.pos(d))+avg(d)*avg(d);
150   }
151   return -green_forward/(2*timestep);
152 }
153 
154 
runge_kutta_symm(Point & p1,Point & p2,doublevar timestep,drift_type dtype,int ndim=3)155 doublevar runge_kutta_symm(Point & p1, Point & p2,
156                                doublevar timestep, drift_type dtype,
157                           int ndim=3) {
158   Array1 <doublevar> dr1(3), dr2(3);
159   dr1=p1.drift; dr2=p2.drift;
160 
161   limDrift(dr1, timestep, dtype);
162   limDrift(dr2, timestep, dtype);
163   Array1 <doublevar> avg(3);
164   for(int d=0; d< 3; d++) {
165     avg(d)=(dr1(d)+dr2(d))/2.0;
166   }
167   //limDrift(avg,timestep, dtype);
168   doublevar green_forward=0;
169   for(int d=0; d< ndim; d++) {
170     //green_forward+=(p2.pos(d)-p1.pos(d)-avg(d))*(p2.pos(d)-p1.pos(d)-avg(d));
171     green_forward+=(p2.pos(d)-p1.pos(d))*(p2.pos(d)-p1.pos(d))+avg(d)*avg(d);
172   }
173   return -green_forward/(2*timestep);
174 }
175 
176 
linear_symm(Point & p1,Point & p2,doublevar timestep,drift_type dtype,int ndim=3)177 doublevar linear_symm(Point & p1, Point & p2,
178 		      doublevar timestep, drift_type dtype,
179 		      int ndim=3) {
180   Array1 <doublevar> dr1(3), dr2(3);
181   dr1=p1.drift; dr2=p2.drift;
182 
183   limDrift(dr1, timestep,dtype);
184   limDrift(dr2, timestep, dtype);
185 
186   doublevar green_forward=0;
187   for(int d=0; d< ndim; d++) {
188 
189     green_forward+=(p2.pos(d)-p1.pos(d))*(p2.pos(d)-p1.pos(d))
190       +(p2.pos(d)-p1.pos(d))*(dr2(d)-dr1(d))
191       +.5*(dr2(d)*dr2(d)+dr1(d)*dr1(d));
192 
193     // Runge-kutta move
194     //doublevar tmp=p2.pos(d)-p1.pos(d)-.5*(dr2(d)+dr1(d));
195     //green_forward+=tmp*tmp;
196     //green_forward+=(p2.pos(d)-p1.pos(d))*(p2.pos(d)-p1.pos(d))
197     //      +.25*(dr2(d)+dr1(d))*(dr2(d)+dr1(d));
198   }
199   return -green_forward/(2*timestep);
200 }
201 
202 //----------------------------------------------------------------------
203 
read(vector<string> & words)204 void Split_sampler::read(vector <string> & words) {
205   unsigned int pos=0;
206 
207   readvalue(words, pos=0, divide_, "DIVIDER");
208   if(haskeyword(words, pos=0, "RESTRICT_NODES"))
209     restrict_nodes=1;
210 
211   int depth;
212   if(readvalue(words, pos=0, depth, "DEPTH"))
213     setRecursionDepth(depth);
214 
215   string drifttype;
216   if(readvalue(words, pos=0, drifttype, "DRIFT_TYPE")) {
217     if(drifttype=="CYRUS")
218       setDriftType(drift_cyrus);
219     else if(drifttype=="CUTOFF")
220       setDriftType(drift_cutoff);
221     else error("Didn't understand DRIFT_TYPE ", drifttype);
222   }
223 
224 
225 }
226 
227 
greenFunction(Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,int e,Array1<doublevar> & newpos,doublevar timestep,Dynamics_info & info,Dynamics_info & oldinfo)228 doublevar Dynamics_generator::greenFunction(Sample_point * sample, Wavefunction * wf,
229                                   Wavefunction_data * wfdata,
230                                   Guiding_function * guidingwf,
231                                   int e,
232                                   Array1 <doublevar> & newpos,
233                                   doublevar timestep,
234                                   Dynamics_info & info, Dynamics_info & oldinfo) {
235 
236   //cout << "auxillary " << endl;
237   drift_type dtype=drift_cyrus;
238   assert(newpos.GetDim(0) >= 3);
239   wf->updateLap(wfdata, sample);
240   Point p1; p1.lap.Resize(wf->nfunc(), 5);
241   p1.sign=sample->overallSign();
242   int ndim=sample->ndim();
243 
244   sample->getElectronPos(e,p1.pos);
245   wf->getLap(wfdata, e, p1.lap);
246   guidingwf->getLap(p1.lap, p1.drift);
247 
248 
249   for(int d=0; d< ndim; d++)
250     p1.translation(d)=newpos(d)-p1.pos(d);
251 
252   sample->translateElectron(e,p1.translation);
253   wf->updateLap(wfdata, sample);
254   Point p2; p2.lap.Resize(wf->nfunc(), 5);
255   p2.sign=sample->overallSign();
256   p2.pos=newpos;
257   wf->getLap(wfdata, e, p2.lap);
258   guidingwf->getLap(p2.lap, p2.drift);
259 
260 
261   info.green_forward=exp(::transition_prob(p1, p2, timestep, dtype));
262   info.green_backward=::transition_prob(p2,p1, timestep, dtype);
263   info.symm_gf=exp(linear_symm(p1, p2, timestep, dtype));
264 
265   //cout << "gf:elec " << e << " new wfval " << p2.lap.amp(0,0) << endl;
266   info.diffuse_start=p1.drift;
267   limDrift(info.diffuse_start, timestep, dtype);
268   for(int d=0; d< ndim; d++) {
269     //cout << "secondary drift " << info.drift_pos(d) << endl;
270     info.diffuse_start(d)+=p1.pos(d);
271   }
272   info.diffuse_end=newpos;
273   info.orig_pos=p1.pos;
274   info.new_pos=newpos;
275   info.diffusion_rate=0;
276   for(int d=0; d< ndim; d++)
277     info.diffusion_rate+=(info.diffuse_end(d)-info.diffuse_start(d))
278                         *(info.diffuse_end(d)-info.diffuse_start(d));
279 
280   info.acceptance=min(1.0, (exp(info.green_backward)/info.green_forward)
281                            *guidingwf->getTrialRatio(p2.lap, p1.lap)
282                            *guidingwf->getTrialRatio(p2.lap, p1.lap));
283 
284 
285   //trying a better gf
286   //info.green_forward*=info.acceptance;///oldinfo.acceptance;
287   //--------
288 
289 
290   info.accepted=0;
291   doublevar ratio=guidingwf->getTrialRatio(p1.lap,p2.lap)*p1.sign*p2.sign;
292   if(ratio < 0) cout << "crossed node " << endl;
293 
294   return info.acceptance;
295 }
296 
297 
298 //----------------------------------------------------------------------
299 /*!
300 From x to y in the trace
301  */
get_acceptance(Guiding_function * guidingwf,int x,int y)302 doublevar Split_sampler::get_acceptance(Guiding_function * guidingwf,
303                                         int x, int y) {
304   //indent = indent + "  ";
305 
306   doublevar ratio=guidingwf->getTrialRatio(trace(y).lap,
307                                            trace(x).lap)*trace(x).sign
308         *trace(y).sign;
309 
310   if(restrict_nodes && ratio < 0) return 0;
311 
312   ratio=ratio*ratio;
313   //cout << indent << "*********" << endl;
314   //cout << indent << "ratio x " << x << " y " << y << " : "  << ratio << endl;
315 
316   int dir=1;
317   if(y-x < 0) {
318     dir=-1;
319   }
320 
321 
322   doublevar prob_transition=0; //exponent of transition probability
323   //We use the current move as well(thus y+1 or x-1)
324   for(int i=x+dir; i != y+dir; i+= dir ) {
325     int dist=abs(x-i);
326     //cout << indent << "transition from " << y << " to " << y-dir*dist
327     //     << " and " << x << " to " << x+dir*dist << " using " << dist
328     //     << " (timestep " << timesteps(dist)
329     //     <<  endl;
330 
331     doublevar num=transition_prob(y,y-dir*dist,timesteps(dist), dtype);
332     doublevar den=transition_prob(x,x+dir*dist,timesteps(dist), dtype);
333     prob_transition+=num-den;
334     //cout << indent <<  "num " << num << " den " << den << " num-den " << num-den << endl;
335   }
336 
337   doublevar reject_prob_den=1; //denominator(forward rejections)
338   doublevar reject_prob_num=1; //numerator(backward rejection)
339   for(int i=x+dir; i != y; i+=dir) {
340     int dist=abs(x-i);
341     //cout << indent << "->acceptance from " << y << " to " << y-dir*dist
342     //     << endl;
343     reject_prob_num*=1-get_acceptance(guidingwf, y, y-dir*dist);
344     //cout << indent << "->over " << x << " to " << x+dir*dist << endl;
345     reject_prob_den*=1-get_acceptance(guidingwf, x,x+dir*dist);
346   }
347 
348   doublevar acc=0;
349 
350   const doublevar tiny=1e-10;
351   if(fabs(reject_prob_den) < tiny) {
352     if(fabs(reject_prob_num) < tiny) acc=0;
353     else {
354       //If we have a zero on the denominator, we know that
355       //alpha(y->x)=1/alpha(x->y) must be zero, so therefore the acceptance is 1
356       acc=1;
357       //cout << indent << "warn:denominator zero : " << reject_prob_den << "   num "
358       //     << reject_prob_num << endl;
359       //error("problem in split_sample; denominator zero");
360     }
361   }
362   else {
363     //cout << indent << "prob_transition " << prob_transition
364     //    << "   " << reject_prob_num << "   " <<  reject_prob_den << endl;
365     acc=ratio*exp(prob_transition)*reject_prob_num/reject_prob_den;
366   }
367   //cout << indent << "acceptance " << acc << endl;
368   //indent.erase(indent.end()-1);
369   //indent.erase(indent.end()-1);
370 
371   return min(1.0,acc);
372 
373 }
374 
375 #include "ulec.h"
376 #include "Wavefunction_data.h"
377 
378 
379 //----------------------------------------------------------------------
split_driver(int e,Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,int depth,Dynamics_info & info,doublevar & efftimestep)380 int Split_sampler::split_driver(int e,
381                                 Sample_point * sample,
382                                 Wavefunction * wf,
383                                 Wavefunction_data * wfdata,
384                                 Guiding_function * guidingwf,
385                                 int depth,
386                                 Dynamics_info & info,
387                                 doublevar & efftimestep) {
388 
389   //cout << "primary " << endl;
390   assert(trace.GetDim(0) >= depth);
391   assert(recursion_depth_ <= timesteps.GetDim(0));
392 
393   if(depth > recursion_depth_) return 0;
394 
395   static Array1 <doublevar> c_olddrift(3);
396   static Array1 <doublevar> c_newdrift(3);
397 
398   c_olddrift=trace(0).drift;
399   limDrift(c_olddrift, timesteps(depth), dtype);
400 
401   int ndim=sample->ndim();
402 
403   //cout << "drift " << c_olddrift(0) << "  "
404   //     << c_olddrift(1) << "  " << c_olddrift(2) << endl;
405   //info.drift_pos.Resize(3);
406 
407   for(int d=0; d< ndim; d++) {
408     trace(depth).gauss(d)=rng.gasdev();
409     trace(depth).translation(d)=trace(depth).gauss(d)*sqrt(timesteps(depth))
410         + c_olddrift(d);
411     trace(depth).pos(d)=trace(0).pos(d)
412         + trace(depth).translation(d);
413 
414 
415   }
416 
417   doublevar diffusion_rate=0;
418   for(int d=0; d< ndim; d++)
419     diffusion_rate+=trace(depth).gauss(d)*timesteps(depth)*trace(depth).gauss(d);;
420 
421 
422   sample->translateElectron(e, trace(depth).translation);
423   trace(depth).sign=sample->overallSign();
424 
425   if(wfdata->supports(laplacian_update) ) {
426     wf->updateLap(wfdata, sample);
427     wf->getLap(wfdata, e, trace(depth).lap);
428   }
429   else {
430     wf->updateForceBias(wfdata, sample);
431     wf->getForceBias(wfdata, e, trace(depth).lap);
432   }
433 
434   guidingwf->getLap(trace(depth).lap, trace(depth).drift);
435 
436   //indent="";
437   //cout << "#######################acceptance for " << depth << endl;
438   doublevar acc=get_acceptance(guidingwf, 0,depth);
439   //cout << "acceptance for " << depth << " : " <<  acc << endl;
440 
441   info.green_forward=exp(transition_prob(0,depth,timesteps(depth), dtype));
442   //cout << "green_forward " << info.green_forward << endl;
443   info.green_backward=exp(transition_prob(depth,0,timesteps(depth),dtype));
444   info.diffusion_rate=diffusion_rate;
445   info.acceptance=acc;
446   info.orig_pos=trace(0).pos;
447   info.diffuse_start.Resize(3);
448   for(int d=0; d< ndim; d++)
449     info.diffuse_start(d)=trace(0).pos(d)+c_olddrift(d);
450   info.diffuse_end=trace(depth).pos;
451   info.new_pos=trace(depth).pos;
452   info.gauss=trace(depth).gauss;
453 
454   info.symm_gf=exp(linear_symm(trace(0), trace(depth), timesteps(depth), dtype));
455   info.resample_gf=info.symm_gf;
456   //trying a better gf
457   //info.green_forward*=info.acceptance;
458   //--------
459 
460 
461   if (acc+rng.ulec() > 1.0) {
462     info.accepted=1;
463     return depth;
464   }
465   else {
466     info.accepted=0;
467 
468     static Array1 <doublevar> rev(3,0.0);
469     for(int d=0; d< 3; d++) rev(d)=-trace(depth).translation(d);
470     sample->translateElectron(e,rev);
471 
472     depth++;
473 
474     return split_driver(e,sample, wf, wfdata, guidingwf,
475                         depth, info, efftimestep);
476   }
477 
478 }
479 
480 
481 //----------------------------------------------------------------------
482 
sample(int e,Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,Dynamics_info & info,doublevar & efftimestep)483 int Split_sampler::sample(int e,
484                           Sample_point * sample,
485                           Wavefunction * wf,
486                           Wavefunction_data * wfdata,
487                           Guiding_function * guidingwf,
488                           Dynamics_info & info,
489                           doublevar & efftimestep) {
490 
491   if(! wfStore.isInitialized())
492     wfStore.initialize(sample, wf);
493 
494   wf->updateLap(wfdata, sample);
495   wfStore.saveUpdate(sample, wf, e);
496   trace.Resize(recursion_depth_+1);
497 
498   for(int i=0; i < recursion_depth_+1; i++) {
499     trace(i).lap.Resize(wf->nfunc(), 5);
500   }
501 
502   timesteps.Resize(recursion_depth_+1);
503   timesteps=efftimestep;
504 
505 
506   for(int i=2; i< recursion_depth_+1; i++) {
507     timesteps(i)=efftimestep/pow(divide_,i-1);
508   }
509 
510   int depth=0;
511 
512   sample->getElectronPos(e,trace(depth).pos);
513   wf->getLap(wfdata, e, trace(depth).lap);
514   trace(depth).sign=sample->overallSign();
515 
516   guidingwf->getLap(trace(depth).lap, trace(depth).drift);
517   depth++;
518 
519 
520   int acc=split_driver(e, sample, wf, wfdata, guidingwf, depth,
521                       info, efftimestep);
522 
523   if(acc > 0) {
524     acceptances(acc-1)++;
525     for(int i=0; i< acc; i++) {
526       tries(i)++;
527     }
528   }
529   else {
530     for(int i=0; i< recursion_depth_; i++) {
531       tries(i)++;
532     }
533   }
534 
535   if(!acc) {
536     wfStore.restoreUpdate(sample, wf, e);
537   }
538   //cout << "-----------split done" << endl;
539   return acc;
540 }
541 
542 
543 //----------------------------------------------------------------------
544 
545 
showStats(ostream & os)546 void Split_sampler::showStats(ostream & os) {
547   doublevar totacc=0;
548   for(int i=0; i< recursion_depth_; i++) {
549     totacc+=acceptances(i);
550   }
551 
552   os << "Total acceptance " << totacc/tries(0) << endl;
553   for(int i=0; i< recursion_depth_; i++) {
554     os << "accept_level" << i << "   " << acceptances(i)/tries(i)
555        << " tries " << tries(i) <<  endl;
556   }
557 }
558 
559 //----------------------------------------------------------------------
560 
561 
resetStats()562 void Split_sampler::resetStats() {
563   acceptances=0;
564   tries=0;
565 }
566 //----------------------------------------------------------------------
567 //######################################################################
568 
showStats(ostream & os)569 void UNR_sampler::showStats(ostream & os) {
570   os << "acceptance " << acceptance/tries << endl;
571 }
572 
resetStats()573 void UNR_sampler::resetStats() {
574   acceptance=0;
575   tries=0;
576 }
577 
578 
getDriftEtc(Point & pt,Sample_point * sample,doublevar tstep,int e,doublevar & exponent,doublevar & probability,Array1<doublevar> & rnuc)579 void UNR_sampler::getDriftEtc(Point & pt, Sample_point * sample,
580 			      doublevar tstep, int e,
581 			      doublevar & exponent,
582 			      //!< exponent at which to do an exponential move
583 			      doublevar & probability,
584 			      //!< probability to do an exponential move
585 			      Array1 <doublevar> & rnuc
586 			      //!< distance array for closest ion
587 			      ) {
588   Array1 <doublevar> z(5);
589   Array1 <doublevar> dist(5);
590   int closest_ion=-1;
591   z(0)=1e8;
592   int nions=sample->ionSize();
593   sample->updateEIDist();
594   for(int at=0; at< nions; at++) {
595     sample->getEIDist(e,at,dist);
596     //cout << "dist " << dist(0) << endl;
597     if(dist(0) < z(0)) {
598       z=dist;
599       closest_ion=at;
600     }
601   }
602 
603   assert(closest_ion!=-1);
604   doublevar charge=sample->getIonCharge(closest_ion);
605   rnuc.Resize(3);
606   //Here we back out the nucleus position from the distance,
607   //which is the best way to do it for periodic systems.
608   //There may be a small bug here if the periodic cell is really
609   //small and we can traverse it in one step..there may be extra
610   //rejections.  It shouldn't generally be a concern, though.
611   for(int d=0; d< 3; d++) {
612     rnuc(d)=pt.pos(d)-z(d+2);
613   }
614 
615   //the exponent for the exponential moves
616   exponent=sqrt(charge*charge+1/tstep);
617 
618   doublevar vhatdotzhat=0;
619   doublevar driftmag=0;
620   for(int d=0; d< 3; d++) driftmag+=pt.drift(d)*pt.drift(d);
621   driftmag=sqrt(driftmag);
622   if(fabs(driftmag) > 1e-16) {
623     for(int d=0;d < 3; d++) {
624       vhatdotzhat+=z(d+2)*pt.drift(d)/(driftmag*z(0));
625       //cout << "vhat " << vhatdotzhat << endl;
626     }
627 
628     //cout << "driftmag " << driftmag << endl;
629     //magic numbers!!  taken from UNR as usual
630     doublevar a=.5*(1+vhatdotzhat)
631       +charge*charge*z(0)*z(0)/(10*(4+charge*charge*z(0)*z(0)));
632 
633     doublevar prefac=(-1+sqrt(1+2*a*driftmag*driftmag*tstep))
634       /(a*driftmag*driftmag*tstep);
635 
636     driftmag=0;
637     for(int d=0;d < 3; d++) {
638       pt.drift(d)*=prefac;
639       driftmag+=pt.drift(d)*pt.drift(d);
640     }
641     driftmag=sqrt(driftmag);
642     //cout << "driftmag " << driftmag << endl;
643   }
644 
645   doublevar vz=vhatdotzhat*driftmag;
646   Array1 <doublevar> rho(3);
647   rho=0;
648   doublevar rhomag=0;
649   for(int d=0; d< 3; d++) {
650     rho(d)=pt.drift(d)-vz*z(d+2)/z(0);
651     rhomag+=rho(d)*rho(d);
652   }
653   rhomag=sqrt(rhomag);
654   doublevar zpp=max(z(0)+vz*tstep,0.0);
655   doublevar rhoscale=2*tstep*zpp/(z(0)+zpp);
656   for(int d=0;d < 3; d++) {
657     pt.drift(d)=rnuc(d)+rhoscale*rho(d)+zpp*z(d+2)/z(0);
658   }
659 
660 
661   probability=0.5*erfc((z(0)+vz*tstep)/sqrt(2*tstep));
662 
663 }
664 
665 //----------------------------------------------------------------------
666 
UNRgreenfunc(Point & pt1,Point & pt2,doublevar tstep,doublevar exponent,doublevar prob,Array1<doublevar> & rnuc)667 doublevar UNRgreenfunc(Point & pt1, Point & pt2,
668 		       doublevar tstep,
669 		       doublevar exponent, doublevar prob,
670 		       Array1 <doublevar> & rnuc) {
671   assert(rnuc.GetDim(0)==3);
672   doublevar gaussmov=0;
673   doublevar expmov=0;
674   for(int d=0; d< 3; d++) {
675     gaussmov+=(pt2.pos(d)-pt1.drift(d))*(pt2.pos(d)-pt1.drift(d));
676     expmov+=(pt2.pos(d)-rnuc(d))*(pt2.pos(d)-rnuc(d));
677     //cout << "rnuc " << rnuc(d) << "  pt2 " << pt2.pos(d) << " pt1 " << pt1.drift(d) << endl;
678   }
679   doublevar gaussnorm=sqrt(8*pi*pi*pi*tstep*tstep*tstep);
680   gaussnorm=1/gaussnorm;
681 
682 
683   return prob*exponent*exponent*exponent*exp(-2*exponent*sqrt(expmov))/pi
684     + (1-prob)*exp(-gaussmov/(2*tstep))*gaussnorm;
685 }
686 //----------------------------------------------------------------------
687 
sample(int e,Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidewf,Dynamics_info & info,doublevar & tstep)688 int UNR_sampler::sample(int e, Sample_point * sample,
689 			Wavefunction * wf, Wavefunction_data * wfdata,
690 			Guiding_function * guidewf,
691 			Dynamics_info & info,
692 			doublevar & tstep) {
693 
694   tries++;
695   Point p1; p1.lap.Resize(wf->nfunc(), 5);
696 
697   wf->updateLap(wfdata, sample);
698   sample->getElectronPos(e,p1.pos);
699   wf->getLap(wfdata, e, p1.lap);
700   p1.sign=sample->overallSign();
701   guidewf->getLap(p1.lap, p1.drift);
702 
703   //Starting determination of move..
704   //using (close to) the notation of UNR
705   Array1 <doublevar> rnuc(3);
706   doublevar prob,exponent;
707 
708   //cout << "p1.drift "; write_array(cout,p1.drift); cout << endl;
709   getDriftEtc(p1,sample,tstep,e, exponent,prob,rnuc);
710 
711   //cout << "p1.pos ";
712   //write_array(cout, p1.pos);
713   //cout << endl;
714   //cout << "p1.drift "; write_array(cout,p1.drift); cout << endl;
715 
716 
717   Point p2; p2.lap.Resize(wf->nfunc(),5);
718   //cout << "prob " << prob << endl;
719   if(prob+rng.ulec() > 1.0) {
720     //cout << "doing exponential move "<< endl;
721     doublevar r=ranr2exponential()/(2*exponent);
722     doublevar theta=rancos();
723     doublevar phi=2*pi*rng.ulec();
724     p2.pos=rnuc;
725     p2.pos(0)+=r*sin(theta)*cos(phi);
726     p2.pos(1)+=r*sin(theta)*sin(phi);
727     p2.pos(2)+=r*cos(theta);
728 
729   }
730   else {
731     //cout << " do a gaussian move." << endl;
732     for(int d=0; d< 3; d++) {
733       p2.pos(d)=p1.drift(d)+sqrt(tstep)*rng.gasdev();
734     }
735   }
736 
737   //cout << "p2.pos "; write_array(cout,p2.pos); cout << endl;
738 
739   Array1 <doublevar> translate(3);
740   for(int d=0; d< 3; d++) translate(d)=p2.pos(d)-p1.pos(d);
741   sample->translateElectron(e,translate);
742   wf->updateLap(wfdata, sample);
743   wf->getLap(wfdata, e, p2.lap);
744   p2.sign=sample->overallSign();
745   guidewf->getLap(p2.lap, p2.drift);
746 
747   Array1 <doublevar> rnucp(3);
748   doublevar probp,exponentp;
749   getDriftEtc(p2,sample,tstep,e,exponentp,probp,rnucp);
750 
751   //cout << "p2.drift "; write_array(cout,p2.drift); cout << endl;
752 
753 
754   doublevar ratio=guidewf->getTrialRatio(p2.lap,p1.lap)
755     *p2.sign*p1.sign;
756 
757   doublevar acc=ratio*ratio*UNRgreenfunc(p2,p1,tstep,exponentp,probp,rnucp)
758     /UNRgreenfunc(p1,p2,tstep,exponent,prob,rnuc);
759 
760   //cout << "forward " << UNRgreenfunc(p2,p1,tstep,exponentp,probp,rnucp) << endl;
761   //cout << "acceptance " << acc << " ratio " << ratio
762   //  << "forward " << UNRgreenfunc(p2,p1,tstep,exponentp,probp,rnucp)
763    // << " backward " << UNRgreenfunc(p1,p2,tstep,exponent,prob,rnuc) << endl;
764 
765   if(restrict_nodes && ratio < 0) {
766     //cout << "stopping nodal crossing " << endl;
767     acc=0;
768   }
769 
770   //cout << "acceptance " << acc << endl;
771   //cout <<"##############################\n";
772 
773   info.diffusion_rate=0;
774   for(int d=0;d < 3; d++) {
775     info.diffusion_rate+=(p2.pos(d)-p1.drift(d))*(p2.pos(d)-p1.drift(d))*tstep;
776   }
777   info.acceptance=acc;
778   info.orig_pos=p1.pos;
779   info.diffuse_start=p1.drift;
780   info.diffuse_end=p2.pos;
781   info.new_pos=p2.pos;
782 
783   if(acc+rng.ulec()>1.0) {
784     info.accepted=1;
785     acceptance++;
786     return 1;
787   }
788   else {
789     sample->setElectronPos(e,p1.pos);
790     info.accepted=0;
791     return 0;
792   }
793 
794 
795 }
796 
797 //----------------------------------------------------------------------
798 //######################################################################
read(vector<string> & words)799 void SRK_dmc::read(vector <string> & words) {
800   unsigned int pos=0;
801   if(haskeyword(words, pos=0, "RESAMPLE"))
802     resample=1;
803   else resample=0;
804 
805   readvalue(words, pos=0, resample_tol, "RESAMPLE_TOL");
806 
807   string drifttype;
808   setDriftType(drift_cyrus);
809   if(readvalue(words, pos=0, drifttype, "DRIFT_TYPE")) {
810     if(drifttype=="CYRUS")
811       setDriftType(drift_cyrus);
812     else if(drifttype=="CUTOFF")
813       setDriftType(drift_cutoff);
814     else error("Didn't understand DRIFT_TYPE ", drifttype);
815   }
816 
817   diagnostics=false;
818   if(haskeyword(words,pos=0,"DIAGNOSTICS")) diagnostics=true;
819   third_move=false;
820   if(haskeyword(words,pos=0, "THIRD_MOVE")) third_move=true;
821 
822   if(diagnostics) {
823     string basename="srk_diagnostics";
824     canonical_filename(basename,mpi_info.node);
825     diagnostics_print.open(basename.c_str(), ios::app);
826     for(int i=0; i< 3; i++)
827       for(int j=0; j< 3; j++)
828         diagnostics_print  << "r"<<i<<j << " ";
829     for(int i=0; i< 3; i++) diagnostics_print << "g"<<i <<" ";
830     for(int i=0; i< 3; i++)  {
831       for(int j=0; j< 5; j++)
832         diagnostics_print << "p"<<i<<j << " ";
833       diagnostics_print << "p_phase" << i <<" ";
834     }
835 
836     diagnostics_print << endl;
837 
838   }
839 
840 }
841 
842 
843 
844 
greenFunction(Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,int e,Array1<doublevar> & newpos,doublevar timestep,Dynamics_info & info,Dynamics_info & oldinfo)845 doublevar SRK_dmc::greenFunction(Sample_point * sample, Wavefunction * wf,
846                                   Wavefunction_data * wfdata,
847                                   Guiding_function * guidingwf,
848                                   int e,
849                                   Array1 <doublevar> & newpos,
850                                   doublevar timestep,
851                                   Dynamics_info & info, Dynamics_info & oldinfo) {
852 
853   //cout << "auxillary " << endl;
854   //drift_type dtype=drift_cyrus;
855   assert(newpos.GetDim(0) >= 3);
856   wf->updateLap(wfdata, sample);
857   Point p1; p1.lap.Resize(wf->nfunc(), 5);
858   p1.sign=sample->overallSign();
859   int ndim=sample->ndim();
860 
861   sample->getElectronPos(e,p1.pos);
862   wf->getLap(wfdata, e, p1.lap);
863   guidingwf->getLap(p1.lap, p1.drift);
864 
865 
866   for(int d=0; d< ndim; d++)
867     p1.translation(d)=newpos(d)-p1.pos(d);
868 
869   sample->translateElectron(e,p1.translation);
870   wf->updateLap(wfdata, sample);
871   Point p2; p2.lap.Resize(wf->nfunc(), 5);
872   p2.sign=sample->overallSign();
873   p2.pos=newpos;
874   wf->getLap(wfdata, e, p2.lap);
875   guidingwf->getLap(p2.lap, p2.drift);
876 
877 
878   info.green_forward=exp(runge_kutta_resamp(p1, p2, timestep, dtype));
879 
880   info.symm_gf=exp(runge_kutta_symm(p1, p2, timestep, dtype));
881   info.green_backward=exp(transition_prob(p2,p1, timestep, dtype));
882 
883   //cout << "gf:elec " << e << " new wfval " << p2.lap.amp(0,0) << endl;
884   info.diffuse_start=p1.drift;
885   limDrift(info.diffuse_start, timestep, dtype);
886   for(int d=0; d< ndim; d++) {
887     //cout << "secondary drift " << info.drift_pos(d) << endl;
888     info.diffuse_start(d)+=p1.pos(d);
889   }
890   info.diffuse_end=newpos;
891   info.orig_pos=p1.pos;
892   info.new_pos=newpos;
893   info.diffusion_rate=0;
894   for(int d=0; d< ndim; d++)
895     info.diffusion_rate+=(info.diffuse_end(d)-info.diffuse_start(d))
896                         *(info.diffuse_end(d)-info.diffuse_start(d));
897 
898   info.acceptance=min(1.0, (exp(info.green_backward)/info.green_forward)
899                            *guidingwf->getTrialRatio(p2.lap, p1.lap)
900                            *guidingwf->getTrialRatio(p2.lap, p1.lap));
901   info.accepted=0;
902   doublevar ratio=guidingwf->getTrialRatio(p1.lap,p2.lap)*p1.sign*p2.sign;
903   if(ratio < 0) cout << "crossed node " << endl;
904 
905   return info.acceptance;
906 }
907 
908 //----------------------------------------------------------
909 
rk_step(int e,Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,Dynamics_info & info,doublevar & timestep,Array1<Point> & trace)910 int SRK_dmc::rk_step(int e,
911                           Sample_point * sample,
912                           Wavefunction * wf,
913                           Wavefunction_data * wfdata,
914                           Guiding_function * guidingwf,
915                           Dynamics_info & info,
916                           doublevar & timestep, Array1 <Point> & trace
917                           ) {
918 
919 
920   //drift_type dtype=drift_cyrus;
921   assert(trace.GetDim(0)==3);
922 
923   Array1 <doublevar> c_olddrift=trace(0).drift;
924   limDrift(c_olddrift,timestep, dtype);
925   int ndim=sample->ndim();
926   //Calculate first move
927   for(int d=0; d< ndim; d++) {
928     trace(1).translation(d)=trace(0).gauss(d)*sqrt(timestep)
929         + c_olddrift(d);
930     trace(1).pos(d)=trace(0).pos(d)
931         + trace(1).translation(d);
932   }
933 
934   info.diffusion_rate=0;
935   for(int d=0; d< ndim; d++)
936     info.diffusion_rate+=trace(0).gauss(d)*timestep*trace(0).gauss(d);;
937 
938   sample->translateElectron(e, trace(1).translation);
939   trace(1).sign=sample->overallSign();
940 
941   wf->updateLap(wfdata, sample);
942   wf->getLap(wfdata, e, trace(1).lap);
943   guidingwf->getLap(trace(1).lap, trace(1).drift);
944 
945   //Calculate second move
946   Array1 <doublevar> c_newdrift=trace(1).drift;
947   limDrift(c_newdrift,timestep, dtype);
948 
949   for(int d=0; d< 3; d++) {
950     trace(2).gauss(d)=trace(0).gauss(d);
951     trace(2).translation(d)=.5*(c_newdrift(d)+c_olddrift(d))
952         +trace(0).gauss(d)*sqrt(timestep)-trace(1).translation(d);
953     trace(2).pos(d)=trace(1).pos(d)+trace(2).translation(d);
954   }
955 
956   sample->translateElectron(e,trace(2).translation);
957   trace(2).sign=sample->overallSign();
958   wf->updateLap(wfdata, sample);
959   wf->getLap(wfdata, e, trace(2).lap);
960   guidingwf->getLap(trace(2).lap, trace(2).drift);
961 
962   int last_point=2;
963   if(third_move) {
964     last_point=3;
965     Array1 <doublevar> c_newnewdrift=trace(2).drift;
966     limDrift(c_newnewdrift,timestep,dtype);
967     for(int d=0; d< 3; d++) {
968       trace(3).gauss(d)=trace(0).gauss(d);
969       trace(3).translation(d)=.5*(c_newnewdrift(d)+c_olddrift(d))
970         +trace(0).gauss(d)*sqrt(timestep)
971         -trace(1).translation(d)-trace(2).translation(d);
972       trace(3).pos(d)=trace(1).pos(d)+trace(3).translation(d);
973     }
974 
975     sample->translateElectron(e,trace(3).translation);
976     trace(3).sign=sample->overallSign();
977     wf->updateLap(wfdata, sample);
978     wf->getLap(wfdata, e, trace(3).lap);
979     guidingwf->getLap(trace(3).lap, trace(3).drift);
980 
981 
982   }
983 
984   info.symm_gf=exp(runge_kutta_symm(trace(0), trace(last_point), timestep, dtype));
985   info.resample_gf=exp(runge_kutta_resamp(trace(0), trace(last_point), timestep, dtype));
986   info.green_forward=exp(-info.diffusion_rate/(2*timestep));
987   //cout << "symm " << info.symm_gf << "  forward " << info.green_forward
988   //      << " ratio " << info.symm_gf/info.green_forward << endl;
989   info.green_backward=transition_prob(trace(last_point),trace(0),timestep,dtype);
990   info.acceptance=1.0;
991   info.orig_pos=trace(0).pos;
992   info.new_pos=trace(last_point).pos;
993 
994   if(diagnostics) {
995     for(int i=0; i< 3; i++)
996       for(int j=0; j< 3; j++)
997         diagnostics_print  << trace(i).pos(j) << " ";
998     for(int i=0; i< 3; i++) diagnostics_print << trace(0).gauss(i) << " ";
999     for(int i=0; i< 3; i++)  {
1000       for(int j=0; j< 5; j++)
1001         diagnostics_print << trace(i).lap.amp(0,j) << " ";
1002       diagnostics_print << trace(i).lap.phase(0,0) << " ";
1003     }
1004 
1005     diagnostics_print << endl;
1006   }
1007 
1008   return 1;
1009 
1010  }
1011 
1012 
1013 //----------------------------------------------------------------------
1014 
sample(int e,Sample_point * sample,Wavefunction * wf,Wavefunction_data * wfdata,Guiding_function * guidingwf,Dynamics_info & info,doublevar & timestep)1015 int SRK_dmc::sample(int e,
1016                           Sample_point * sample,
1017                           Wavefunction * wf,
1018                           Wavefunction_data * wfdata,
1019                           Guiding_function * guidingwf,
1020                           Dynamics_info & info,
1021                           doublevar & timestep
1022                           ) {
1023 
1024   //drift_type dtype=drift_cyrus;
1025   tries++;
1026   int ntrace=40;
1027   Array1 <Point> trace(ntrace);
1028   for(int i=0; i < ntrace; i++) {
1029     trace(i).lap.Resize(wf->nfunc(), 5);
1030   }
1031   for(int d=0; d< 3; d++) {
1032     trace(0).gauss(d)=rng.gasdev();
1033   }
1034 
1035 
1036   wf->updateLap(wfdata, sample);
1037   sample->getElectronPos(e,trace(0).pos);
1038   wf->getLap(wfdata, e, trace(0).lap);
1039   trace(0).sign=sample->overallSign();
1040   guidingwf->getLap(trace(0).lap, trace(0).drift);
1041 
1042   //cout << "initial rk step " << endl;
1043   rk_step(e,sample, wf, wfdata, guidingwf, info, timestep, trace);
1044 
1045   /*
1046   int pos=3;
1047   Array1 <doublevar> err(ntrace,0.0);
1048   err(2)=fabs(info.resample_gf/info.green_forward -1);
1049   while(resample &&
1050         fabs(info.resample_gf/info.green_forward-1) > resample_tol &&
1051         pos < ntrace) {
1052     //cout << "big error " << info.symm_gf/info.green_forward << endl;
1053     Array1 <doublevar> newdrift(3), orig_drift(3);
1054     orig_drift=trace(0).drift;
1055     newdrift=trace(pos-1).drift;
1056     limDrift(orig_drift, timestep, dtype);
1057     limDrift(newdrift, timestep, dtype);
1058     for(int d=0; d< 3; d++) {
1059       trace(pos).gauss(d)=trace(0).gauss(d);
1060       trace(pos).translation(d)=.5*(newdrift(d)+orig_drift(d))
1061           +trace(0).gauss(d)*sqrt(timestep);//-trace(pos-1).translation(d);
1062       trace(pos).pos(d)=trace(0).pos(d)+trace(pos).translation(d);
1063     }
1064 
1065     sample->setElectronPos(e,trace(pos).pos);
1066     trace(pos).sign=sample->overallSign();
1067     wf->updateLap(wfdata, sample);
1068     wf->getLap(wfdata, e, trace(pos).lap);
1069     guidingwf->getLap(trace(pos).lap, trace(pos).drift);
1070 
1071     info.symm_gf=exp(runge_kutta_symm(trace(0), trace(pos), timestep, dtype));
1072     info.resample_gf=exp(runge_kutta_resamp(trace(0), trace(pos),
1073                                             timestep, dtype));
1074     info.new_pos=trace(pos).pos;
1075 
1076     err(pos)=fabs(info.resample_gf/info.green_forward-1);
1077     pos++;
1078   }
1079 
1080   if(pos==ntrace) {
1081     nbottom++;
1082     int bestindex=2; doublevar bestratio=err(bestindex);
1083     for(int i=2; i < ntrace; i++) {
1084       if(err(i) < bestratio) { bestindex=i; bestratio=err(i); }
1085     }
1086     if(bestindex!=pos-1) {
1087       //cout << " large remaining error "; write_array(cout, err); cout << endl;
1088       //cout << "best index " << bestindex << endl;
1089 
1090 
1091       info.symm_gf=exp(runge_kutta_symm(trace(0), trace(bestindex),
1092                                         timestep, dtype));
1093       info.resample_gf=exp(runge_kutta_resamp(trace(0), trace(bestindex),
1094                                         timestep, dtype));
1095       info.new_pos=trace(bestindex).pos;
1096       sample->setElectronPos(e,trace(bestindex).pos);
1097       pos=bestindex+1;
1098     }
1099   }
1100   */
1101   //if(pos > 3) cout << "final ratio " << info.symm_gf/info.green_forward << endl;
1102 
1103   doublevar ratio=guidingwf->getTrialRatio(trace(2).lap,
1104                                            trace(0).lap)
1105     *trace(0).sign*trace(2).sign;
1106 
1107 
1108   info.diffuse_start.Resize(3);
1109   for(int d=0; d< 3; d++)
1110     info.diffuse_start(d)=trace(2).pos(d)-sqrt(timestep)*trace(0).gauss(d);
1111 
1112   info.diffuse_end=trace(2).pos;
1113 
1114   //retries+=pos-3;
1115   if(ratio < 0) {
1116     //cout << "rejecting node crossing " <<  endl;
1117     info.accepted=0;
1118     sample->setElectronPos(e, trace(0).pos);
1119     wf->updateLap(wfdata, sample);
1120     return 0;
1121   }
1122   acceptances++;
1123   info.accepted=1;
1124   return 1;
1125 }
1126 
1127 
1128