1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
8 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
9 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #include "QMCDrivers/DMC/DMCUpdatePbyPL2.h"
17 #include "Particle/MCWalkerConfiguration.h"
18 // #include "Particle/DistanceTable.h"
19 #include "Particle/HDFWalkerIO.h"
20 #include "ParticleBase/ParticleUtility.h"
21 #include "ParticleBase/RandomSeqGenerator.h"
22 #include "QMCDrivers/DriftOperators.h"
23 #if !defined(REMOVE_TRACEMANAGER)
24 #include "Estimators/TraceManager.h"
25 #else
26 typedef int TraceManager;
27 #endif
28 //#define TEST_INNERBRANCH
29 #include "QMCDrivers/DMC/DMCUpdatePbyP.h"
30 
31 namespace qmcplusplus
32 {
33 using WP = WalkerProperties::Indexes;
34 
35 /// Constructor.
DMCUpdatePbyPL2(MCWalkerConfiguration & w,TrialWaveFunction & psi,QMCHamiltonian & h,RandomGenerator_t & rg)36 DMCUpdatePbyPL2::DMCUpdatePbyPL2(MCWalkerConfiguration& w,
37                                  TrialWaveFunction& psi,
38                                  QMCHamiltonian& h,
39                                  RandomGenerator_t& rg)
40     : QMCUpdateBase(w, psi, h, rg)
41 {
42   setup_timers(myTimers, DMCTimerNames, timer_level_medium);
43 }
44 
45 /// destructor
~DMCUpdatePbyPL2()46 DMCUpdatePbyPL2::~DMCUpdatePbyPL2() {}
47 
advanceWalker(Walker_t & thisWalker,bool recompute)48 void DMCUpdatePbyPL2::advanceWalker(Walker_t& thisWalker, bool recompute)
49 {
50   Walker_t::WFBuffer_t& w_buffer(thisWalker.DataSet);
51   {
52     ScopedTimer local_timer(myTimers[DMC_buffer]);
53     W.loadWalker(thisWalker, true);
54     Psi.copyFromBuffer(W, w_buffer);
55   }
56   //create a 3N-Dimensional Gaussian with variance=1
57   makeGaussRandomWithEngine(deltaR, RandomGen);
58   int nAcceptTemp(0);
59   int nRejectTemp(0);
60   //copy the old energy and scale factor of drift
61   //EstimatorRealType eold(thisWalker.Properties(LOCALENERGY));
62   //EstimatorRealType enew(eold);
63   FullPrecRealType eold(thisWalker.Properties(WP::LOCALENERGY));
64   FullPrecRealType enew(eold);
65   RealType rr_proposed = 0.0;
66   RealType rr_accepted = 0.0;
67   RealType gf_acc      = 1.0;
68   mPosType K;
69   mTensorType D;
70   mTensorType Dchol;
71   PosType Ktmp, drtmp;
72   TensorType Dtmp;
73   bool L2_proj = H.has_L2();
74   if (L2_proj)
75   {
76     Ktmp = 0.0;
77     Dtmp = 0.0;
78     for (int d = 0; d < DIM; d++)
79       Dtmp(d, d) = 1.0;
80   }
81   {
82     ScopedTimer local_timer(myTimers[DMC_movePbyP]);
83     for (int ig = 0; ig < W.groups(); ++ig) //loop over species
84     {
85       RealType tauovermass = Tau * MassInvS[ig];
86       RealType oneover2tau = 0.5 / (tauovermass);
87       RealType sqrttau     = std::sqrt(tauovermass);
88       RealType rr;
89       for (int iat = W.first(ig); iat < W.last(ig); ++iat)
90       {
91         //W.setActive(iat);
92         //get the displacement
93         GradType grad_iat = Psi.evalGrad(W, iat);
94         mPosType dr;
95         mPosType dr_diff = deltaR[iat];
96         if (!L2_proj) // normal projector
97         {
98           getScaledDrift(tauovermass, grad_iat, dr);
99           dr += sqrttau * dr_diff;
100           rr = tauovermass * dot(dr_diff, dr_diff);
101           rr_proposed += rr;
102           if (rr > m_r2max)
103           {
104             ++nRejectTemp;
105             W.accept_rejectMove(iat, false);
106             continue;
107           }
108           if (!W.makeMoveAndCheck(iat, dr))
109           {
110             W.accept_rejectMove(iat, false);
111             continue;
112           }
113         }
114         else // projector including L2 potential
115         {
116           // do a fake move (zero distance)
117           // this ensures the temporary distance data is correct
118           // will need to remove this later, but requires reimplementation of computeL2DK
119           dr = 0.0;
120           if (!W.makeMoveAndCheck(iat, dr))
121           {
122             W.accept_rejectMove(iat, false);
123             continue;
124           }
125 
126           H.computeL2DK(W, iat, Dtmp, Ktmp);
127           D = Dtmp; // upcast for mixed precision
128           K = Ktmp;
129           getScaledDriftL2(tauovermass, grad_iat, D, K, dr);
130 
131           W.accept_rejectMove(iat, false);
132           rr = tauovermass * dot(dr_diff, dr_diff);
133           rr_proposed += rr;
134           if (rr > m_r2max)
135           {
136             ++nRejectTemp;
137             W.accept_rejectMove(iat, false);
138             continue;
139           }
140 
141           // move with just drift to update distance tables
142           if (!W.makeMoveAndCheck(iat, dr))
143           {
144             W.accept_rejectMove(iat, false);
145             continue;
146           }
147 
148           // compute diffusion step
149           H.computeL2D(W, iat, Dtmp);
150           D       = Dtmp; // upcast for mixed precision
151           Dchol   = cholesky(D);
152           dr_diff = dot(Dchol, dr_diff);
153           dr += sqrttau * dr_diff;
154 
155           // reverse the intermediate drift move
156           W.accept_rejectMove(iat, false);
157           // move with drift and diffusion together
158           if (!W.makeMoveAndCheck(iat, dr))
159           {
160             W.accept_rejectMove(iat, false);
161             continue;
162           }
163         }
164         ValueType ratio = Psi.calcRatioGrad(W, iat, grad_iat);
165         //node is crossed reject the move
166         if (branchEngine->phaseChanged(Psi.getPhaseDiff()))
167         {
168           ++nRejectTemp;
169           ++nNodeCrossing;
170           W.accept_rejectMove(iat, false);
171           Psi.rejectMove(iat);
172         }
173         else
174         {
175           FullPrecRealType logGf = -0.5 * dot(deltaR[iat], deltaR[iat]);
176           //Use the force of the particle iat
177           DriftModifier->getDrift(tauovermass, grad_iat, drtmp);
178           dr                     = drtmp; // upcast for mixed precision
179           dr                     = W.R[iat] - W.activePos - dr;
180           FullPrecRealType logGb = -oneover2tau * dot(dr, dr);
181           RealType prob          = std::norm(ratio) * std::exp(logGb - logGf);
182           bool is_accepted       = false;
183 
184           if (RandomGen() < prob)
185           {
186             is_accepted = true;
187 
188             ++nAcceptTemp;
189             Psi.acceptMove(W, iat, true);
190             rr_accepted += rr;
191             gf_acc *= prob; //accumulate the ratio
192           }
193           else
194           {
195             ++nRejectTemp;
196             Psi.rejectMove(iat);
197           }
198           W.accept_rejectMove(iat, is_accepted);
199         }
200       }
201     }
202     Psi.completeUpdates();
203     W.donePbyP();
204   }
205 
206   if (nAcceptTemp > 0)
207   {
208     //need to overwrite the walker properties
209     RealType logpsi(0);
210     {
211       ScopedTimer local_timer(myTimers[DMC_buffer]);
212       thisWalker.Age = 0;
213       logpsi         = Psi.updateBuffer(W, w_buffer, recompute);
214       W.saveWalker(thisWalker);
215     }
216     {
217       ScopedTimer local_timer(myTimers[DMC_hamiltonian]);
218       enew = H.evaluateWithToperator(W);
219     }
220     thisWalker.resetProperty(logpsi, Psi.getPhase(), enew, rr_accepted, rr_proposed, 1.0);
221     thisWalker.Weight *= branchEngine->branchWeight(enew, eold);
222     {
223       ScopedTimer local_timer(myTimers[DMC_collectables]);
224       H.auxHevaluate(W, thisWalker);
225       H.saveProperty(thisWalker.getPropertyBase());
226     }
227   }
228   else
229   {
230     //all moves are rejected: does not happen normally with reasonable wavefunctions
231     thisWalker.Age++;
232     thisWalker.Properties(WP::R2ACCEPTED) = 0.0;
233     //weight is set to 0 for traces
234     // consistent w/ no evaluate/auxHevaluate
235     RealType wtmp     = thisWalker.Weight;
236     thisWalker.Weight = 0.0;
237     H.rejectedMove(W, thisWalker);
238     thisWalker.Weight = wtmp;
239     ++nAllRejected;
240     enew   = eold; //copy back old energy
241     gf_acc = 1.0;
242     thisWalker.Weight *= branchEngine->branchWeight(enew, eold);
243   }
244 #if !defined(REMOVE_TRACEMANAGER)
245   Traces->buffer_sample(W.current_step);
246 #endif
247   {
248     ScopedTimer local_timer(myTimers[DMC_tmoves]);
249     const int NonLocalMoveAcceptedTemp = H.makeNonLocalMoves(W);
250     if (NonLocalMoveAcceptedTemp > 0)
251     {
252       RealType logpsi = Psi.updateBuffer(W, w_buffer, false);
253       W.saveWalker(thisWalker);
254       NonLocalMoveAccepted += NonLocalMoveAcceptedTemp;
255     }
256   }
257   nAccept += nAcceptTemp;
258   nReject += nRejectTemp;
259 
260   setMultiplicity(thisWalker);
261 }
262 
263 } // namespace qmcplusplus
264