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 //                    Raymond Clay III, j.k.rofling@gmail.com, Lawrence Livermore National Laboratory
9 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
10 //
11 // File created by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
12 //////////////////////////////////////////////////////////////////////////////////////
13 
14 
15 #include "RMCUpdatePbyP.h"
16 #include "QMCDrivers/DriftOperators.h"
17 #include "Message/OpenMP.h"
18 #include "Configuration.h"
19 #include "Particle/Reptile.h"
20 #include <cmath>
21 //////////////////////////////////////////////////////////////////////////
22 //  This driver is strongly based off the method used by Lucas Wagner in QWalk.
23 //
24 //  This driver proposes an "all-electron" configuration by performing N single particle moves,
25 //  accepting or rejecting at each step.  Umrigar's scaled drift is used to generate the VMC configurations.
26 //
27 //  The configuration is then accepted/rejected based only on the symmetrized DMC action, which
28 //  amounts to Maroni/Baroni's method.  Note that energy filtering (like in DMC) is used here as well.
29 //
30 //  Until serious discrepencies are detected, it is strongly advised that this driver be used over the
31 //  RMCUpdateAll, as the time step errors seem to be really reduced using this method.
32 //////////////////////////////////////////////////////////////////////////////
33 
34 
35 namespace qmcplusplus
36 {
37 using WP = WalkerProperties::Indexes;
38 
39 /// Constructor.
RMCUpdatePbyPWithDrift(MCWalkerConfiguration & w,TrialWaveFunction & psi,QMCHamiltonian & h,RandomGenerator_t & rg,std::vector<int> act,std::vector<int> tp)40 RMCUpdatePbyPWithDrift::RMCUpdatePbyPWithDrift(MCWalkerConfiguration& w,
41                                                TrialWaveFunction& psi,
42                                                QMCHamiltonian& h,
43                                                RandomGenerator_t& rg,
44                                                std::vector<int> act,
45                                                std::vector<int> tp)
46     : QMCUpdateBase(w, psi, h, rg),
47       Action(act),
48       TransProb(tp),
49       advance_timer_(*timer_manager.createTimer("RMCUpdatePbyP::advance", timer_level_medium)),
50       movepbyp_timer_(*timer_manager.createTimer("RMCUpdatePbyP::movePbyP", timer_level_medium)),
51       update_mbo_timer_(*timer_manager.createTimer("RMCUpdatePbyP::updateMBO", timer_level_medium)),
52       energy_timer_(*timer_manager.createTimer("RMCUpdatePbyP::energy", timer_level_medium))
53 {
54   scaleDrift = false;
55   actionType = SYM_ACTION;
56 }
57 
~RMCUpdatePbyPWithDrift()58 RMCUpdatePbyPWithDrift::~RMCUpdatePbyPWithDrift() {}
59 
60 
initWalkersForPbyP(WalkerIter_t it,WalkerIter_t it_end)61 void RMCUpdatePbyPWithDrift::initWalkersForPbyP(WalkerIter_t it, WalkerIter_t it_end)
62 {
63   UpdatePbyP = true;
64 
65   for (; it != it_end; ++it)
66   {
67     Walker_t& awalker = **it; //W.reptile->getHead();
68     W.R               = awalker.R;
69     W.update(true);
70     W.donePbyP();
71     if (awalker.DataSet.size())
72       awalker.DataSet.clear();
73     awalker.DataSet.rewind();
74     Psi.registerData(W, awalker.DataSet);
75     awalker.DataSet.allocate();
76     Psi.copyFromBuffer(W, awalker.DataSet);
77     Psi.evaluateLog(W);
78     RealType logpsi = Psi.updateBuffer(W, awalker.DataSet, false);
79     awalker.G       = W.G;
80     awalker.L       = W.L;
81     RealType eloc   = H.evaluate(W);
82     awalker.resetProperty(logpsi, Psi.getPhase(), eloc);
83   }
84 }
85 
put(xmlNodePtr cur)86 bool RMCUpdatePbyPWithDrift::put(xmlNodePtr cur)
87 {
88   QMCUpdateBase::put(cur);
89 
90   ParameterSet m_param;
91   bool usedrift      = true;
92   std::string action = "SLA";
93   m_param.add(usedrift, "useDrift");
94   m_param.add(action, "Action");
95   m_param.add(equilSteps, "equilsteps");
96   m_param.add(equilSteps, "equilSteps");
97   m_param.put(cur);
98 
99   if (usedrift == true)
100   {
101     if (omp_get_thread_num() == 0)
102       app_log() << "  Using Umrigar scaled drift\n";
103   }
104   else
105   {
106     if (omp_get_thread_num() == 0)
107       app_log() << "  Using non-scaled drift\n";
108   }
109 
110   if (action == "DMC")
111   {
112     actionType = DMC_ACTION;
113     if (omp_get_thread_num() == 0)
114       app_log() << "  Using DMC link-action\n";
115   }
116   else
117   {
118     if (omp_get_thread_num() == 0)
119       app_log() << "  Using Symmetrized Link-Action\n";
120   }
121 
122   return true;
123 }
advanceWalkersVMC()124 void RMCUpdatePbyPWithDrift::advanceWalkersVMC()
125 {
126   advance_timer_.start();
127   Walker_t& curhead = W.reptile->getHead();
128   Walker_t prophead(curhead);
129   Walker_t::WFBuffer_t& w_buffer(prophead.DataSet);
130   W.loadWalker(prophead, true);
131   Psi.copyFromBuffer(W, w_buffer);
132   //create a 3N-Dimensional Gaussian with variance=1
133   makeGaussRandomWithEngine(deltaR, RandomGen);
134   int nAcceptTemp(0);
135   int nRejectTemp(0);
136   //copy the old energy and scale factor of drift
137   RealType eold(prophead.Properties(WP::LOCALENERGY));
138   RealType vqold(prophead.Properties(WP::DRIFTSCALE));
139   RealType enew(eold);
140   RealType rr_proposed = 0.0;
141   RealType rr_accepted = 0.0;
142   RealType gf_acc      = 1.0;
143   movepbyp_timer_.start();
144   for (int ig = 0; ig < W.groups(); ++ig) //loop over species
145   {
146     RealType tauovermass = Tau * MassInvS[ig];
147     RealType oneover2tau = 0.5 / (tauovermass);
148     RealType sqrttau     = std::sqrt(tauovermass);
149     for (int iat = W.first(ig); iat < W.last(ig); ++iat)
150     {
151       //get the displacement
152       GradType grad_iat = Psi.evalGrad(W, iat);
153       PosType dr;
154       DriftModifier->getDrift(tauovermass, grad_iat, dr);
155       dr += sqrttau * deltaR[iat];
156       bool is_valid = W.makeMoveAndCheck(iat, dr);
157       RealType rr   = tauovermass * dot(deltaR[iat], deltaR[iat]);
158       rr_proposed += rr;
159       if (!is_valid || rr > m_r2max)
160       {
161         ++nRejectTemp;
162         W.accept_rejectMove(iat, false);
163         continue;
164       }
165       ValueType ratio = Psi.calcRatioGrad(W, iat, grad_iat);
166       //node is crossed reject the move
167       if (branchEngine->phaseChanged(Psi.getPhaseDiff()))
168       {
169         ++nRejectTemp;
170         ++nNodeCrossing;
171         W.accept_rejectMove(iat, false);
172         Psi.rejectMove(iat);
173       }
174       else
175       {
176         RealType logGf = -0.5 * dot(deltaR[iat], deltaR[iat]);
177         //Use the force of the particle iat
178         DriftModifier->getDrift(tauovermass, grad_iat, dr);
179         dr               = W.R[iat] - W.activePos - dr;
180         RealType logGb   = -oneover2tau * dot(dr, dr);
181         RealType prob    = std::norm(ratio) * std::exp(logGb - logGf);
182         bool is_accepted = false;
183         if (RandomGen() < prob)
184         {
185           is_accepted = true;
186           ++nAcceptTemp;
187           Psi.acceptMove(W, iat, true);
188           rr_accepted += rr;
189           gf_acc *= prob; //accumulate the ratio
190         }
191         else
192         {
193           ++nRejectTemp;
194           Psi.rejectMove(iat);
195         }
196         W.accept_rejectMove(iat, is_accepted);
197       }
198     }
199   }
200   movepbyp_timer_.stop();
201   Psi.completeUpdates();
202   W.donePbyP();
203 
204   if (nAcceptTemp > 0)
205   {
206     //need to overwrite the walker properties
207     MCWalkerConfiguration::Walker_t& newhead(W.reptile->getNewHead());
208     update_mbo_timer_.start();
209     prophead.Age    = 0;
210     prophead.R      = W.R;
211     RealType logpsi = Psi.updateBuffer(W, w_buffer, false);
212     W.saveWalker(prophead);
213     update_mbo_timer_.stop();
214     energy_timer_.start();
215     enew = H.evaluate(W);
216     energy_timer_.stop();
217     prophead.resetProperty(logpsi, Psi.getPhase(), enew, rr_accepted, rr_proposed, 0.0);
218     prophead.Weight = 1.0;
219     H.auxHevaluate(W, prophead, true, false); //evaluate properties but not collectables.
220     H.saveProperty(prophead.getPropertyBase());
221     newhead = prophead;
222     nAccept++;
223   }
224   else
225   {
226     //all moves are rejected: does not happen normally with reasonable wavefunctions
227     curhead.Age++;
228     curhead.Properties(WP::R2ACCEPTED) = 0.0;
229     //weight is set to 0 for traces
230     // consistent w/ no evaluate/auxHevaluate
231     RealType wtmp  = prophead.Weight;
232     curhead.Weight = 0.0;
233     H.rejectedMove(W, curhead);
234     curhead.Weight = wtmp;
235     ++nAllRejected;
236     gf_acc = 1.0;
237     nReject++;
238   }
239   Walker_t& centerbead = W.reptile->getCenter();
240   W.loadWalker(centerbead, true);
241   W.update();
242   H.auxHevaluate(W, centerbead); //evaluate collectables but not properties.
243   // Traces->buffer_sample();
244 }
245 
246 
initWalkers(WalkerIter_t it,WalkerIter_t it_end)247 void RMCUpdatePbyPWithDrift::initWalkers(WalkerIter_t it, WalkerIter_t it_end)
248 {
249   IndexType initsteps = W.reptile->nbeads * 2;
250 
251   vmcSteps = W.reptile->nbeads + 1;
252 
253   for (int n = 0; n < initsteps; n++)
254     advanceWalkersVMC();
255 }
256 
advanceWalkersRMC()257 void RMCUpdatePbyPWithDrift::advanceWalkersRMC()
258 {
259   Walker_t& curhead = W.reptile->getHead();
260   Walker_t prophead(curhead);
261   Walker_t::WFBuffer_t& w_buffer(prophead.DataSet);
262   W.loadWalker(prophead, true);
263   Psi.copyFromBuffer(W, w_buffer);
264 
265   makeGaussRandomWithEngine(deltaR, RandomGen);
266   int nAcceptTemp(0);
267   int nRejectTemp(0);
268   //copy the old energy and scale factor of drift
269   RealType eold(prophead.Properties(WP::LOCALENERGY));
270   RealType vqold(prophead.Properties(WP::DRIFTSCALE));
271   RealType rr_proposed = 0.0;
272   RealType rr_accepted = 0.0;
273   RealType gf_acc      = 1.0;
274   movepbyp_timer_.start();
275   for (int ig = 0; ig < W.groups(); ++ig) //loop over species
276   {
277     RealType tauovermass = Tau * MassInvS[ig];
278     RealType oneover2tau = 0.5 / (tauovermass);
279     RealType sqrttau     = std::sqrt(tauovermass);
280     for (int iat = W.first(ig); iat < W.last(ig); ++iat)
281     {
282       //get the displacement
283       GradType grad_iat = Psi.evalGrad(W, iat);
284       PosType dr;
285       DriftModifier->getDrift(tauovermass, grad_iat, dr);
286       dr += sqrttau * deltaR[iat];
287       bool is_valid = W.makeMoveAndCheck(iat, dr);
288       RealType rr   = tauovermass * dot(deltaR[iat], deltaR[iat]);
289       rr_proposed += rr;
290       if (!is_valid || rr > m_r2max)
291       {
292         ++nRejectTemp;
293         W.accept_rejectMove(iat, false);
294         continue;
295       }
296       ValueType ratio = Psi.calcRatioGrad(W, iat, grad_iat);
297       //node is crossed reject the move
298       if (branchEngine->phaseChanged(Psi.getPhaseDiff()))
299       {
300         ++nRejectTemp;
301         ++nNodeCrossing;
302         W.accept_rejectMove(iat, false);
303         Psi.rejectMove(iat);
304       }
305       else
306       {
307         RealType logGf = -0.5 * dot(deltaR[iat], deltaR[iat]);
308         //Use the force of the particle iat
309         DriftModifier->getDrift(tauovermass, grad_iat, dr);
310         dr               = W.R[iat] - W.activePos - dr;
311         RealType logGb   = -oneover2tau * dot(dr, dr);
312         RealType prob    = std::norm(ratio) * std::exp(logGb - logGf);
313         bool is_accepted = false;
314         if (RandomGen() < prob)
315         {
316           is_accepted = true;
317           ++nAcceptTemp;
318           Psi.acceptMove(W, iat, true);
319           rr_accepted += rr;
320           gf_acc *= prob; //accumulate the ratio
321         }
322         else
323         {
324           ++nRejectTemp;
325           Psi.rejectMove(iat);
326         }
327         W.accept_rejectMove(iat, is_accepted);
328       }
329     }
330   }
331   movepbyp_timer_.stop();
332   Psi.completeUpdates();
333   W.donePbyP();
334   // In the rare case that all proposed moves fail, we bounce.
335   if (nAcceptTemp == 0)
336   {
337     ++nReject;
338     H.rejectedMove(W, prophead);
339     curhead.Age += 1;
340     W.reptile->flip();
341   }
342   prophead.R      = W.R;
343   RealType logpsi = Psi.updateBuffer(W, w_buffer, false);
344   W.saveWalker(prophead);
345   Walker_t &lastbead(W.reptile->getTail()), nextlastbead(W.reptile->getNext());
346   RealType eloc = H.evaluate(W);
347   RealType dS   = branchEngine->DMCLinkAction(eloc, curhead.Properties(WP::LOCALENERGY)) -
348       branchEngine->DMCLinkAction(lastbead.Properties(WP::LOCALENERGY), nextlastbead.Properties(WP::LOCALENERGY));
349   RealType acceptProb = std::min((RealType)1.0, std::exp(-dS));
350   if ((RandomGen() <= acceptProb) || (prophead.Age >= MaxAge || lastbead.Age >= MaxAge))
351   {
352     MCWalkerConfiguration::Walker_t& overwriteWalker(W.reptile->getNewHead());
353     if (curhead.Age >= MaxAge || lastbead.Age >= MaxAge)
354       app_log() << "\tForce Acceptance...\n";
355 
356     prophead.Properties(WP::LOCALENERGY) = eloc;
357     prophead.Properties(WP::R2ACCEPTED)  = rr_accepted;
358     prophead.Properties(WP::R2PROPOSED)  = rr_proposed;
359     H.auxHevaluate(W, prophead, true, false); //evaluate properties? true.  collectables?  false.
360     H.saveProperty(prophead.getPropertyBase());
361     prophead.Age    = 0;
362     overwriteWalker = prophead;
363     ++nAccept;
364   }
365   else
366   {
367     ++nReject;
368     H.rejectedMove(W, prophead);
369     curhead.Properties(WP::R2ACCEPTED) = 0;
370     curhead.Properties(WP::R2PROPOSED) = rr_proposed;
371     curhead.Age += 1;
372     W.reptile->flip();
373     // return;
374   }
375   //Collectables should be evaluated on center bead.  Here we go.
376   Walker_t& centerbead = W.reptile->getCenter();
377   W.loadWalker(centerbead, true);
378   W.update();                                 //Called to recompute S(k) and distance tables.
379   H.auxHevaluate(W, centerbead, false, true); //evaluate properties?  false.  Collectables?  true.
380 }
381 
advanceWalker(Walker_t & thisWalker,bool recompute)382 void RMCUpdatePbyPWithDrift::advanceWalker(Walker_t& thisWalker, bool recompute)
383 {
384   //empty function to
385 }
386 
advanceWalkers(WalkerIter_t it,WalkerIter_t it_end,bool init)387 void RMCUpdatePbyPWithDrift::advanceWalkers(WalkerIter_t it, WalkerIter_t it_end, bool init)
388 {
389   if (init == true)
390     advanceWalkersVMC();
391   else
392     advanceWalkersRMC();
393 }
394 
accumulate(WalkerIter_t it,WalkerIter_t it_end)395 void RMCUpdatePbyPWithDrift::accumulate(WalkerIter_t it, WalkerIter_t it_end) { Estimators->accumulate(W, it, it_end); }
396 
397 } // namespace qmcplusplus
398