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: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 //                    Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 //                    Cynthia Gu, zg1@ornl.gov, Oak Ridge National Laboratory
11 //                    Paul R. C. Kent, kentpr@ornl.gov, Oak Ridge National Laboratory
12 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
13 //                    Ye Luo, yeluo@anl.gov, Argonne National Laboratory
14 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
15 //
16 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
17 //////////////////////////////////////////////////////////////////////////////////////
18 
19 
20 #include "DMC.h"
21 #include "QMCDrivers/DMC/DMCUpdatePbyP.h"
22 #include "QMCDrivers/DMC/DMCUpdatePbyPL2.h"
23 #include "QMCDrivers/DMC/SODMCUpdatePbyP.h"
24 #include "QMCDrivers/DMC/DMCUpdateAll.h"
25 #include "QMCHamiltonians/HamiltonianPool.h"
26 #include "Message/Communicate.h"
27 #include "Message/CommOperators.h"
28 #include "Message/OpenMP.h"
29 #include "Utilities/Timer.h"
30 #include "Utilities/RunTimeManager.h"
31 #include "OhmmsApp/RandomNumberControl.h"
32 #include "Utilities/ProgressReportEngine.h"
33 #include "Utilities/qmc_common.h"
34 #include "Utilities/FairDivide.h"
35 #if !defined(REMOVE_TRACEMANAGER)
36 #include "Estimators/TraceManager.h"
37 #else
38 typedef int TraceManager;
39 #endif
40 
41 namespace qmcplusplus
42 {
43 /// Constructor.
DMC(MCWalkerConfiguration & w,TrialWaveFunction & psi,QMCHamiltonian & h,Communicate * comm,bool enable_profiling)44 DMC::DMC(MCWalkerConfiguration& w, TrialWaveFunction& psi, QMCHamiltonian& h, Communicate* comm, bool enable_profiling)
45     : QMCDriver(w, psi, h, comm, "DMC", enable_profiling),
46       KillNodeCrossing(0),
47       BranchInterval(-1),
48       L2("no"),
49       Reconfiguration("no"),
50       mover_MaxAge(-1)
51 {
52   RootName = "dmc";
53   qmc_driver_mode.set(QMC_UPDATE_MODE, 1);
54   m_param.add(KillWalker, "killnode");
55   m_param.add(Reconfiguration, "reconfiguration");
56   //m_param.add(BranchInterval,"branchInterval");
57   m_param.add(NonLocalMove, "nonlocalmove");
58   m_param.add(NonLocalMove, "nonlocalmoves");
59   m_param.add(mover_MaxAge, "MaxAge");
60   m_param.add(L2, "L2_diffusion");
61 }
62 
resetUpdateEngines()63 void DMC::resetUpdateEngines()
64 {
65   ReportEngine PRE("DMC", "resetUpdateEngines");
66   bool fixW = (Reconfiguration == "runwhileincorrect");
67   if (Reconfiguration != "no" && Reconfiguration != "runwhileincorrect")
68     APP_ABORT("Reconfiguration is currently broken and gives incorrect results. Set reconfiguration=\"no\" or remove "
69               "the reconfiguration option from the DMC input section. To run performance tests, please set "
70               "reconfiguration to \"runwhileincorrect\" instead of \"yes\" to restore consistent behaviour.")
71   makeClones(W, Psi, H);
72   Timer init_timer;
73   if (Movers.empty())
74   {
75     W.loadEnsemble(wClones);
76     setWalkerOffsets();
77     int nw_multi = branchEngine->initWalkerController(W, fixW, false);
78     if (nw_multi > 1)
79     {
80       W.createWalkers((nw_multi - 1) * W.getActiveWalkers());
81       setWalkerOffsets();
82     }
83     //if(qmc_driver_mode[QMC_UPDATE_MODE]) W.clearAuxDataSet();
84     Movers.resize(NumThreads, 0);
85     Rng.resize(NumThreads, 0);
86     estimatorClones.resize(NumThreads, 0);
87     traceClones.resize(NumThreads, 0);
88     FairDivideLow(W.getActiveWalkers(), NumThreads, wPerRank);
89 
90     {
91       //log file
92       std::ostringstream o;
93       o << "  Initial partition of walkers on a node: ";
94       copy(wPerRank.begin(), wPerRank.end(), std::ostream_iterator<int>(o, " "));
95       o << "\n";
96       if (qmc_driver_mode[QMC_UPDATE_MODE])
97       {
98         o << "  Updates by particle-by-particle moves";
99         if (L2 == "yes")
100           app_log() << "Using DMCUpdatePbyPL2" << std::endl;
101         else
102           app_log() << "Using DMCUpdatePbyPWithRejectionFast" << std::endl;
103       }
104       else
105         o << "  Updates by walker moves";
106       // Appears to be set in constructor reported here and used nowhere
107       if (KillNodeCrossing)
108         o << "\n  Walkers are killed when a node crossing is detected";
109       else
110         o << "\n  DMC moves are rejected when a node crossing is detected";
111       if (SpinMoves == "yes")
112         o << "\n  Spins treated as dynamic variable with SpinMass: " << SpinMass;
113       app_log() << o.str() << std::endl;
114     }
115 #pragma omp parallel for
116     for (int ip = 0; ip < NumThreads; ++ip)
117     {
118       estimatorClones[ip] = new EstimatorManagerBase(*Estimators);
119       estimatorClones[ip]->setCollectionMode(false);
120 #if !defined(REMOVE_TRACEMANAGER)
121       traceClones[ip] = Traces->makeClone();
122 #endif
123 #ifdef USE_FAKE_RNG
124       Rng[ip] = new FakeRandom();
125 #else
126       Rng[ip] = new RandomGenerator_t(*RandomNumberControl::Children[ip]);
127       hClones[ip]->setRandomGenerator(Rng[ip]);
128 #endif
129       if (SpinMoves == "yes")
130       {
131         if (qmc_driver_mode[QMC_UPDATE_MODE])
132         {
133           Movers[ip] = new SODMCUpdatePbyPWithRejectionFast(*wClones[ip], *psiClones[ip], *hClones[ip], *Rng[ip]);
134           Movers[ip]->setSpinMass(SpinMass);
135           Movers[ip]->put(qmcNode);
136           Movers[ip]->resetRun(branchEngine.get(), estimatorClones[ip], traceClones[ip], DriftModifier);
137           Movers[ip]->initWalkersForPbyP(W.begin() + wPerRank[ip], W.begin() + wPerRank[ip + 1]);
138         }
139         else
140         {
141           APP_ABORT("SODMC Driver Mode must be PbyP\n");
142         }
143       }
144       else
145       {
146         if (qmc_driver_mode[QMC_UPDATE_MODE])
147         {
148           if (L2 == "yes")
149             Movers[ip] = new DMCUpdatePbyPL2(*wClones[ip], *psiClones[ip], *hClones[ip], *Rng[ip]);
150           else
151             Movers[ip] = new DMCUpdatePbyPWithRejectionFast(*wClones[ip], *psiClones[ip], *hClones[ip], *Rng[ip]);
152 
153           Movers[ip]->put(qmcNode);
154           Movers[ip]->resetRun(branchEngine.get(), estimatorClones[ip], traceClones[ip], DriftModifier);
155           Movers[ip]->initWalkersForPbyP(W.begin() + wPerRank[ip], W.begin() + wPerRank[ip + 1]);
156         }
157         else
158         {
159           if (KillNodeCrossing)
160             Movers[ip] = new DMCUpdateAllWithKill(*wClones[ip], *psiClones[ip], *hClones[ip], *Rng[ip]);
161           else
162             Movers[ip] = new DMCUpdateAllWithRejection(*wClones[ip], *psiClones[ip], *hClones[ip], *Rng[ip]);
163           Movers[ip]->put(qmcNode);
164           Movers[ip]->resetRun(branchEngine.get(), estimatorClones[ip], traceClones[ip], DriftModifier);
165           Movers[ip]->initWalkers(W.begin() + wPerRank[ip], W.begin() + wPerRank[ip + 1]);
166         }
167       }
168     }
169   }
170 #if !defined(REMOVE_TRACEMANAGER)
171   else
172   {
173 #pragma omp parallel for
174     for (int ip = 0; ip < NumThreads; ++ip)
175     {
176       traceClones[ip]->transfer_state_from(*Traces);
177     }
178   }
179 #endif
180   branchEngine->checkParameters(W);
181   int mxage = mover_MaxAge;
182   if (fixW)
183   {
184     if (BranchInterval < 0)
185       BranchInterval = 1;
186     mxage = (mover_MaxAge < 0) ? 0 : mover_MaxAge;
187     for (int ip = 0; ip < Movers.size(); ++ip)
188       Movers[ip]->MaxAge = mxage;
189   }
190   else
191   {
192     if (BranchInterval < 0)
193       BranchInterval = 1;
194     int miage = (qmc_driver_mode[QMC_UPDATE_MODE]) ? 1 : 5;
195     mxage     = (mover_MaxAge < 0) ? miage : mover_MaxAge;
196     for (int i = 0; i < NumThreads; ++i)
197       Movers[i]->MaxAge = mxage;
198   }
199   {
200     std::ostringstream o;
201     if (fixW)
202       o << "  Fixed population using reconfiguration method\n";
203     else
204       o << "  Fluctuating population\n";
205     o << "  Persistent walkers are killed after " << mxage << " MC sweeps\n";
206     o << "  BranchInterval = " << BranchInterval << "\n";
207     o << "  Steps per block = " << nSteps << "\n";
208     o << "  Number of blocks = " << nBlocks << "\n";
209     app_log() << o.str() << std::endl;
210   }
211   app_log() << "  DMC Engine Initialization = " << init_timer.elapsed() << " secs" << std::endl;
212 }
213 
run()214 bool DMC::run()
215 {
216   LoopTimer<> dmc_loop;
217 
218   bool variablePop = (Reconfiguration == "no");
219   resetUpdateEngines();
220   //estimator does not need to collect data
221   Estimators->setCollectionMode(true);
222   Estimators->start(nBlocks);
223   for (int ip = 0; ip < NumThreads; ip++)
224     Movers[ip]->startRun(nBlocks, false);
225 #if !defined(REMOVE_TRACEMANAGER)
226   Traces->startRun(nBlocks, traceClones);
227 #endif
228   IndexType block        = 0;
229   IndexType updatePeriod = (qmc_driver_mode[QMC_UPDATE_MODE]) ? Period4CheckProperties : (nBlocks + 1) * nSteps;
230   int sample             = 0;
231 
232   RunTimeControl<> runtimeControl(run_time_manager, MaxCPUSecs, myComm->getName(), myComm->rank() == 0);
233 
234   do // block
235   {
236     dmc_loop.start();
237     Estimators->startBlock(nSteps);
238     for (int ip = 0; ip < NumThreads; ip++)
239       Movers[ip]->startBlock(nSteps);
240 
241     for (IndexType step = 0; step < nSteps; ++step, CurrentStep += BranchInterval)
242     {
243       //         if(storeConfigs && (CurrentStep%storeConfigs == 0)) {
244       //           ForwardWalkingHistory.storeConfigsForForwardWalking(W);
245       //           W.resetWalkerParents();
246       //         }
247 
248 #pragma omp parallel
249       {
250         int ip = omp_get_thread_num();
251         Movers[ip]->set_step(sample);
252         bool recompute = (step + 1 == nSteps && nBlocksBetweenRecompute && (1 + block) % nBlocksBetweenRecompute == 0 &&
253                           qmc_driver_mode[QMC_UPDATE_MODE]);
254         wClones[ip]->resetCollectables();
255         const size_t nw = W.getActiveWalkers();
256 #pragma omp for nowait
257         for (size_t iw = 0; iw < nw; ++iw)
258         {
259           Walker_t& thisWalker(*W[iw]);
260           Movers[ip]->advanceWalker(thisWalker, recompute);
261         }
262       }
263 
264       //Collectables are weighted but not yet normalized
265       if (W.Collectables.size())
266       {
267         // only when collectable is not empty, need to generalize for W != wClones[0]
268         for (int ip = 1; ip < NumThreads; ++ip)
269           W.Collectables += wClones[ip]->Collectables;
270       }
271       branchEngine->branch(CurrentStep, W);
272       //         if(storeConfigs && (CurrentStep%storeConfigs == 0)) {
273       //           ForwardWalkingHistory.storeConfigsForForwardWalking(W);
274       //           W.resetWalkerParents();
275       //         }
276       if (variablePop)
277         FairDivideLow(W.getActiveWalkers(), NumThreads, wPerRank);
278       sample++;
279     }
280     //       branchEngine->debugFWconfig();
281     Estimators->stopBlock(acceptRatio());
282 #if !defined(REMOVE_TRACEMANAGER)
283     Traces->write_buffers(traceClones, block);
284 #endif
285     block++;
286     if (DumpConfig && block % Period4CheckPoint == 0)
287     {
288 #ifndef USE_FAKE_RNG
289       for (int ip = 0; ip < NumThreads; ip++)
290         *(RandomNumberControl::Children[ip]) = *(Rng[ip]);
291 #endif
292     }
293     recordBlock(block);
294     dmc_loop.stop();
295 
296     bool stop_requested = false;
297     // Rank 0 decides whether the time limit was reached
298     if (!myComm->rank())
299       stop_requested = runtimeControl.checkStop(dmc_loop);
300     myComm->bcast(stop_requested);
301 
302     if (stop_requested)
303     {
304       if (!myComm->rank())
305         app_log() << runtimeControl.generateStopMessage("DMC", block - 1);
306       run_time_manager.markStop();
307       break;
308     }
309 
310   } while (block < nBlocks);
311 
312 #ifndef USE_FAKE_RNG
313   for (int ip = 0; ip < NumThreads; ip++)
314     *(RandomNumberControl::Children[ip]) = *(Rng[ip]);
315 #endif
316   Estimators->stop();
317   for (int ip = 0; ip < NumThreads; ++ip)
318     Movers[ip]->stopRun2();
319 #if !defined(REMOVE_TRACEMANAGER)
320   Traces->stopRun();
321 #endif
322   return finalize(nBlocks);
323 }
324 
325 
put(xmlNodePtr q)326 bool DMC::put(xmlNodePtr q)
327 {
328   BranchInterval = -1;
329   ParameterSet p;
330   p.add(BranchInterval, "branchInterval");
331   p.add(BranchInterval, "branchinterval");
332   p.add(BranchInterval, "substeps");
333   p.add(BranchInterval, "subSteps");
334   p.add(BranchInterval, "sub_steps");
335   p.put(q);
336 
337   //app_log() << "\n DMC::put qmc_counter=" << qmc_common.qmc_counter << "  my_counter=" << MyCounter<< std::endl;
338   //app_log() << "  timestep       = " << Tau << std::endl;
339   //app_log() << "  blocks         = " << nBlocks << std::endl;
340   //app_log() << "  steps          = " << nSteps << std::endl;
341   //app_log() << "  current        = " << CurrentStep << std::endl;
342   //app_log() << "  walkers/mpi    = " << W.getActiveWalkers() << std::endl << std::endl;
343   //app_log().flush();
344   return true;
345 }
346 } // namespace qmcplusplus
347