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) 2020 QMCPACK developers.
6 //
7 // File developed by: Bryan Clark, bclark@Princeton.edu, Princeton University
8 //                    Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
9 //                    Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
10 //                    Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
11 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
12 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
13 //                    Raymond Clay III, j.k.rofling@gmail.com, Lawrence Livermore 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 #include <stdexcept>
20 
21 #include "TrialWaveFunction.h"
22 #include "ResourceCollection.h"
23 #include "Utilities/IteratorUtility.h"
24 #include "Concurrency/Info.hpp"
25 
26 namespace qmcplusplus
27 {
28 typedef enum
29 {
30   V_TIMER = 0,
31   VGL_TIMER,
32   ACCEPT_TIMER,
33   NL_TIMER,
34   RECOMPUTE_TIMER,
35   BUFFER_TIMER,
36   DERIVS_TIMER,
37   PREPAREGROUP_TIMER,
38   TIMER_SKIP
39 } TimerEnum;
40 
41 static const std::vector<std::string> suffixes{"V",         "VGL",    "accept", "NLratio",
42                                                "recompute", "buffer", "derivs", "preparegroup"};
43 
TrialWaveFunction(const std::string & aname,bool tasking,bool create_local_resource)44 TrialWaveFunction::TrialWaveFunction(const std::string& aname, bool tasking, bool create_local_resource)
45     : myName(aname),
46       BufferCursor(0),
47       BufferCursor_scalar(0),
48       PhaseValue(0.0),
49       PhaseDiff(0.0),
50       LogValue(0.0),
51       OneOverM(1.0),
52       use_tasking_(tasking)
53 {
54   if (suffixes.size() != TIMER_SKIP)
55     throw std::runtime_error("TrialWaveFunction::TrialWaveFunction mismatched timer enums and suffixes");
56 
57   for (auto& suffix : suffixes)
58   {
59     std::string timer_name = "WaveFunction:" + myName + "::" + suffix;
60     TWF_timers_.push_back(*timer_manager.createTimer(timer_name, timer_level_medium));
61   }
62 }
63 
64 /** Destructor
65 *
66 *@warning Have not decided whether Z is cleaned up by TrialWaveFunction
67 *  or not. It will depend on I/O implementation.
68 */
~TrialWaveFunction()69 TrialWaveFunction::~TrialWaveFunction() { delete_iter(Z.begin(), Z.end()); }
70 
startOptimization()71 void TrialWaveFunction::startOptimization()
72 {
73   for (int i = 0; i < Z.size(); i++)
74     Z[i]->IsOptimizing = true;
75 }
76 
stopOptimization()77 void TrialWaveFunction::stopOptimization()
78 {
79   for (int i = 0; i < Z.size(); i++)
80   {
81     Z[i]->finalizeOptimization();
82     Z[i]->IsOptimizing = false;
83   }
84 }
85 
86 /** Takes owndership of aterm
87  */
addComponent(WaveFunctionComponent * aterm)88 void TrialWaveFunction::addComponent(WaveFunctionComponent* aterm)
89 {
90   Z.push_back(aterm);
91 
92   std::string aname = aterm->ClassName;
93   if (!aterm->myName.empty())
94     aname += ":" + aterm->myName;
95 
96   if (aterm->is_fermionic)
97     app_log() << "  Added a fermionic WaveFunctionComponent " << aname << std::endl;
98 
99   for (auto& suffix : suffixes)
100     WFC_timers_.push_back(*timer_manager.createTimer(aname + "::" + suffix));
101 }
102 
103 
104 /** return log(|psi|)
105 *
106 * PhaseValue is the phase for the complex wave function
107 */
evaluateLog(ParticleSet & P)108 TrialWaveFunction::RealType TrialWaveFunction::evaluateLog(ParticleSet& P)
109 {
110   ScopedTimer local_timer(TWF_timers_[RECOMPUTE_TIMER]);
111   P.G = 0.0;
112   P.L = 0.0;
113   LogValueType logpsi(0.0);
114   for (int i = 0; i < Z.size(); ++i)
115   {
116     ScopedTimer z_timer(WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
117 #ifndef NDEBUG
118     // Best way I've found yet to quickly see if WFC made it over the wire successfully
119     auto subterm = Z[i]->evaluateLog(P, P.G, P.L);
120     // std::cerr << "evaluate log Z element:" <<  i << "  value: " << subterm << '\n';
121     logpsi += subterm;
122 #else
123     logpsi += Z[i]->evaluateLog(P, P.G, P.L);
124 #endif
125   }
126 
127   G = P.G;
128   L = P.L;
129 
130   LogValue   = std::real(logpsi);
131   PhaseValue = std::imag(logpsi);
132   return LogValue;
133 }
134 
mw_evaluateLog(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list)135 void TrialWaveFunction::mw_evaluateLog(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
136                                        const RefVectorWithLeader<ParticleSet>& p_list)
137 {
138   auto& wf_leader = wf_list.getLeader();
139   auto& p_leader  = p_list.getLeader();
140   ScopedTimer local_timer(wf_leader.TWF_timers_[RECOMPUTE_TIMER]);
141 
142   constexpr RealType czero(0);
143   const auto g_list(TrialWaveFunction::extractGRefList(wf_list));
144   const auto l_list(TrialWaveFunction::extractLRefList(wf_list));
145 
146   // due to historic design issue, ParticleSet holds G and L instead of TrialWaveFunction.
147   // TrialWaveFunction now also holds G and L to move forward but they need to be copied to P.G and P.L
148   // to be compatiable with legacy use pattern.
149   const int num_particles = p_leader.getTotalNum();
150   auto initGandL          = [num_particles, czero](TrialWaveFunction& twf, ParticleSet::ParticleGradient_t& grad,
151                                           ParticleSet::ParticleLaplacian_t& lapl) {
152     grad.resize(num_particles);
153     lapl.resize(num_particles);
154     grad           = czero;
155     lapl           = czero;
156     twf.LogValue   = czero;
157     twf.PhaseValue = czero;
158   };
159   for (int iw = 0; iw < wf_list.size(); iw++)
160     initGandL(wf_list[iw], g_list[iw], l_list[iw]);
161 
162   auto& wavefunction_components = wf_leader.Z;
163   const int num_wfc             = wf_leader.Z.size();
164   for (int i = 0; i < num_wfc; ++i)
165   {
166     ScopedTimer z_timer(wf_leader.WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
167     const auto wfc_list(extractWFCRefList(wf_list, i));
168     wavefunction_components[i]->mw_evaluateLog(wfc_list, p_list, g_list, l_list);
169   }
170 
171   for (int iw = 0; iw < wf_list.size(); iw++)
172   {
173     ParticleSet& pset      = p_list[iw];
174     TrialWaveFunction& twf = wf_list[iw];
175 
176     for (int i = 0; i < num_wfc; ++i)
177     {
178       twf.LogValue += std::real(twf.Z[i]->LogValue);
179       twf.PhaseValue += std::imag(twf.Z[i]->LogValue);
180     }
181 
182     // Ye: temporal workaround to have P.G/L always defined.
183     // remove when KineticEnergy use WF.G/L instead of P.G/L
184     pset.G = twf.G;
185     pset.L = twf.L;
186   }
187 }
188 
recompute(const ParticleSet & P)189 void TrialWaveFunction::recompute(const ParticleSet& P)
190 {
191   ScopedTimer local_timer(TWF_timers_[RECOMPUTE_TIMER]);
192   for (int i = 0; i < Z.size(); ++i)
193   {
194     ScopedTimer z_timer(WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
195     Z[i]->recompute(P);
196   }
197 }
198 
mw_recompute(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,const std::vector<bool> & recompute)199 void TrialWaveFunction::mw_recompute(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
200                                      const RefVectorWithLeader<ParticleSet>& p_list,
201                                      const std::vector<bool>& recompute)
202 {
203   auto& wf_leader = wf_list.getLeader();
204   auto& p_leader  = p_list.getLeader();
205   ScopedTimer local_timer(wf_leader.TWF_timers_[RECOMPUTE_TIMER]);
206 
207   auto& wavefunction_components = wf_leader.Z;
208   const int num_wfc             = wf_leader.Z.size();
209   for (int i = 0; i < num_wfc; ++i)
210   {
211     ScopedTimer z_timer(wf_leader.WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
212     const auto wfc_list(extractWFCRefList(wf_list, i));
213     wavefunction_components[i]->mw_recompute(wfc_list, p_list, recompute);
214   }
215 }
216 
evaluateDeltaLog(ParticleSet & P,bool recomputeall)217 TrialWaveFunction::RealType TrialWaveFunction::evaluateDeltaLog(ParticleSet& P, bool recomputeall)
218 {
219   ScopedTimer local_timer(TWF_timers_[RECOMPUTE_TIMER]);
220   P.G = 0.0;
221   P.L = 0.0;
222   LogValueType logpsi(0.0);
223   for (int i = 0; i < Z.size(); ++i)
224   {
225     ScopedTimer z_timer(WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
226     if (Z[i]->Optimizable)
227       logpsi += Z[i]->evaluateLog(P, P.G, P.L);
228   }
229   LogValue   = std::real(logpsi);
230   PhaseValue = std::imag(logpsi);
231 
232   //In case we need to recompute orbitals, initialize dummy vectors for G and L.
233   //evaluateLog dumps into these variables, and logPsi contribution is discarded.
234   //Only called for non-optimizable orbitals.
235   if (recomputeall)
236   {
237     ParticleSet::ParticleGradient_t dummyG(P.G);
238     ParticleSet::ParticleLaplacian_t dummyL(P.L);
239 
240     for (int i = 0; i < Z.size(); ++i)
241     {
242       //update orbitals if its not flagged optimizable, AND recomputeall is true
243       if (!Z[i]->Optimizable)
244         Z[i]->evaluateLog(P, dummyG, dummyL);
245     }
246   }
247   return LogValue;
248 }
249 
evaluateDeltaLog(ParticleSet & P,RealType & logpsi_fixed_r,RealType & logpsi_opt_r,ParticleSet::ParticleGradient_t & fixedG,ParticleSet::ParticleLaplacian_t & fixedL)250 void TrialWaveFunction::evaluateDeltaLog(ParticleSet& P,
251                                          RealType& logpsi_fixed_r,
252                                          RealType& logpsi_opt_r,
253                                          ParticleSet::ParticleGradient_t& fixedG,
254                                          ParticleSet::ParticleLaplacian_t& fixedL)
255 {
256   ScopedTimer local_timer(TWF_timers_[RECOMPUTE_TIMER]);
257   P.G    = 0.0;
258   P.L    = 0.0;
259   fixedL = 0.0;
260   fixedG = 0.0;
261   LogValueType logpsi_fixed(0.0);
262   LogValueType logpsi_opt(0.0);
263 
264   for (int i = 0; i < Z.size(); ++i)
265   {
266     ScopedTimer z_timer(WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
267     if (Z[i]->Optimizable)
268       logpsi_opt += Z[i]->evaluateLog(P, P.G, P.L);
269     else
270       logpsi_fixed += Z[i]->evaluateLog(P, fixedG, fixedL);
271   }
272   P.G += fixedG;
273   P.L += fixedL;
274   convert(logpsi_fixed, logpsi_fixed_r);
275   convert(logpsi_opt, logpsi_opt_r);
276 }
277 
278 
mw_evaluateDeltaLogSetup(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,std::vector<RealType> & logpsi_fixed_list,std::vector<RealType> & logpsi_opt_list,RefVector<ParticleSet::ParticleGradient_t> & fixedG_list,RefVector<ParticleSet::ParticleLaplacian_t> & fixedL_list)279 void TrialWaveFunction::mw_evaluateDeltaLogSetup(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
280                                                  const RefVectorWithLeader<ParticleSet>& p_list,
281                                                  std::vector<RealType>& logpsi_fixed_list,
282                                                  std::vector<RealType>& logpsi_opt_list,
283                                                  RefVector<ParticleSet::ParticleGradient_t>& fixedG_list,
284                                                  RefVector<ParticleSet::ParticleLaplacian_t>& fixedL_list)
285 {
286   auto& wf_leader = wf_list.getLeader();
287   auto& p_leader  = p_list.getLeader();
288   ScopedTimer local_timer(wf_leader.TWF_timers_[RECOMPUTE_TIMER]);
289   constexpr RealType czero(0);
290   const int num_particles = p_leader.getTotalNum();
291   const auto g_list(TrialWaveFunction::extractGRefList(wf_list));
292   const auto l_list(TrialWaveFunction::extractLRefList(wf_list));
293 
294   auto initGandL = [num_particles, czero](TrialWaveFunction& twf, ParticleSet::ParticleGradient_t& grad,
295                                           ParticleSet::ParticleLaplacian_t& lapl) {
296     grad.resize(num_particles);
297     lapl.resize(num_particles);
298     grad           = czero;
299     lapl           = czero;
300     twf.LogValue   = czero;
301     twf.PhaseValue = czero;
302   };
303   for (int iw = 0; iw < wf_list.size(); iw++)
304     initGandL(wf_list[iw], g_list[iw], l_list[iw]);
305   auto& wavefunction_components = wf_leader.Z;
306   const int num_wfc             = wf_leader.Z.size();
307   for (int i = 0; i < num_wfc; ++i)
308   {
309     ScopedTimer z_timer(wf_leader.WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
310     const auto wfc_list(extractWFCRefList(wf_list, i));
311     if (wavefunction_components[i]->Optimizable)
312     {
313       wavefunction_components[i]->mw_evaluateLog(wfc_list, p_list, g_list, l_list);
314       for (int iw = 0; iw < wf_list.size(); iw++)
315         logpsi_opt_list[iw] += std::real(wfc_list[iw].LogValue);
316     }
317     else
318     {
319       wavefunction_components[i]->mw_evaluateLog(wfc_list, p_list, fixedG_list, fixedL_list);
320       for (int iw = 0; iw < wf_list.size(); iw++)
321         logpsi_fixed_list[iw] += std::real(wfc_list[iw].LogValue);
322     }
323   }
324 
325   // Temporary workaround to have P.G/L always defined.
326   // remove when KineticEnergy use WF.G/L instead of P.G/L
327   auto addAndCopyToP = [](ParticleSet& pset, TrialWaveFunction& twf, ParticleSet::ParticleGradient_t& grad,
328                           ParticleSet::ParticleLaplacian_t& lapl) {
329     pset.G = twf.G + grad;
330     pset.L = twf.L + lapl;
331   };
332   for (int iw = 0; iw < wf_list.size(); iw++)
333     addAndCopyToP(p_list[iw], wf_list[iw], fixedG_list[iw], fixedL_list[iw]);
334 }
335 
336 
mw_evaluateDeltaLog(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,std::vector<RealType> & logpsi_list,RefVector<ParticleSet::ParticleGradient_t> & dummyG_list,RefVector<ParticleSet::ParticleLaplacian_t> & dummyL_list,bool recompute)337 void TrialWaveFunction::mw_evaluateDeltaLog(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
338                                             const RefVectorWithLeader<ParticleSet>& p_list,
339                                             std::vector<RealType>& logpsi_list,
340                                             RefVector<ParticleSet::ParticleGradient_t>& dummyG_list,
341                                             RefVector<ParticleSet::ParticleLaplacian_t>& dummyL_list,
342                                             bool recompute)
343 {
344   auto& p_leader  = p_list.getLeader();
345   auto& wf_leader = wf_list.getLeader();
346   ScopedTimer local_timer(wf_leader.TWF_timers_[RECOMPUTE_TIMER]);
347   constexpr RealType czero(0);
348   int num_particles = p_leader.getTotalNum();
349   const auto g_list(TrialWaveFunction::extractGRefList(wf_list));
350   const auto l_list(TrialWaveFunction::extractLRefList(wf_list));
351 
352   // Initialize various members of the wavefunction, grad, and laplacian
353   auto initGandL = [num_particles, czero](TrialWaveFunction& twf, ParticleSet::ParticleGradient_t& grad,
354                                           ParticleSet::ParticleLaplacian_t& lapl) {
355     grad.resize(num_particles);
356     lapl.resize(num_particles);
357     grad           = czero;
358     lapl           = czero;
359     twf.LogValue   = czero;
360     twf.PhaseValue = czero;
361   };
362   for (int iw = 0; iw < wf_list.size(); iw++)
363     initGandL(wf_list[iw], g_list[iw], l_list[iw]);
364 
365   // Get wavefunction components (assumed the same for every WF in the list)
366   auto& wavefunction_components = wf_leader.Z;
367   const int num_wfc             = wf_leader.Z.size();
368 
369   // Loop over the wavefunction components
370   for (int i = 0; i < num_wfc; ++i)
371     if (wavefunction_components[i]->Optimizable)
372     {
373       ScopedTimer z_timer(wf_leader.WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
374       const auto wfc_list(extractWFCRefList(wf_list, i));
375       wavefunction_components[i]->mw_evaluateLog(wfc_list, p_list, g_list, l_list);
376       for (int iw = 0; iw < wf_list.size(); iw++)
377         logpsi_list[iw] += std::real(wfc_list[iw].LogValue);
378     }
379 
380   // Temporary workaround to have P.G/L always defined.
381   // remove when KineticEnergy use WF.G/L instead of P.G/L
382   auto copyToP = [](ParticleSet& pset, TrialWaveFunction& twf) {
383     pset.G = twf.G;
384     pset.L = twf.L;
385   };
386   for (int iw = 0; iw < wf_list.size(); iw++)
387     copyToP(p_list[iw], wf_list[iw]);
388 
389   // Recompute is usually used to prepare the wavefunction for NLPP derivatives.
390   // (e.g compute the matrix inverse for determinants)
391   // Call mw_evaluateLog for the wavefunction components that were skipped previously.
392   // Ignore logPsi, G and L.
393   if (recompute)
394     for (int i = 0; i < num_wfc; ++i)
395       if (!wavefunction_components[i]->Optimizable)
396       {
397         ScopedTimer z_timer(wf_leader.WFC_timers_[RECOMPUTE_TIMER + TIMER_SKIP * i]);
398         const auto wfc_list(extractWFCRefList(wf_list, i));
399         wavefunction_components[i]->mw_evaluateLog(wfc_list, p_list, dummyG_list, dummyL_list);
400       }
401 }
402 
403 
404 /*void TrialWaveFunction::evaluateHessian(ParticleSet & P, int iat, HessType& grad_grad_psi)
405 {
406   std::vector<WaveFunctionComponent*>::iterator it(Z.begin());
407   std::vector<WaveFunctionComponent*>::iterator it_end(Z.end());
408 
409   grad_grad_psi=0.0;
410 
411   for (; it!=it_end; ++it)
412   {
413 	  HessType tmp_hess;
414 	  (*it)->evaluateHessian(P, iat, tmp_hess);
415 	  grad_grad_psi+=tmp_hess;
416   }
417 }*/
418 
evaluateHessian(ParticleSet & P,HessVector_t & grad_grad_psi)419 void TrialWaveFunction::evaluateHessian(ParticleSet& P, HessVector_t& grad_grad_psi)
420 {
421   std::vector<WaveFunctionComponent*>::iterator it(Z.begin());
422   std::vector<WaveFunctionComponent*>::iterator it_end(Z.end());
423 
424   grad_grad_psi.resize(P.getTotalNum());
425 
426   for (int i = 0; i < Z.size(); i++)
427   {
428     HessVector_t tmp_hess(grad_grad_psi);
429     tmp_hess = 0.0;
430     Z[i]->evaluateHessian(P, tmp_hess);
431     grad_grad_psi += tmp_hess;
432     //  app_log()<<"TrialWavefunction::tmp_hess = "<<tmp_hess<< std::endl;
433     //  app_log()<< std::endl<< std::endl;
434   }
435   // app_log()<<" TrialWavefunction::Hessian = "<<grad_grad_psi<< std::endl;
436 }
437 
calcRatio(ParticleSet & P,int iat,ComputeType ct)438 TrialWaveFunction::ValueType TrialWaveFunction::calcRatio(ParticleSet& P, int iat, ComputeType ct)
439 {
440   ScopedTimer local_timer(TWF_timers_[V_TIMER]);
441   PsiValueType r(1.0);
442   for (int i = 0; i < Z.size(); i++)
443     if (ct == ComputeType::ALL || (Z[i]->is_fermionic && ct == ComputeType::FERMIONIC) ||
444         (!Z[i]->is_fermionic && ct == ComputeType::NONFERMIONIC))
445     {
446       ScopedTimer z_timer(WFC_timers_[V_TIMER + TIMER_SKIP * i]);
447       r *= Z[i]->ratio(P, iat);
448     }
449   return static_cast<ValueType>(r);
450 }
451 
mw_calcRatio(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,int iat,std::vector<PsiValueType> & ratios,ComputeType ct)452 void TrialWaveFunction::mw_calcRatio(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
453                                      const RefVectorWithLeader<ParticleSet>& p_list,
454                                      int iat,
455                                      std::vector<PsiValueType>& ratios,
456                                      ComputeType ct)
457 {
458   const int num_wf = wf_list.size();
459   ratios.resize(num_wf);
460   std::fill(ratios.begin(), ratios.end(), PsiValueType(1));
461 
462   auto& wf_leader = wf_list.getLeader();
463   ScopedTimer local_timer(wf_leader.TWF_timers_[V_TIMER]);
464   const int num_wfc             = wf_leader.Z.size();
465   auto& wavefunction_components = wf_leader.Z;
466 
467   std::vector<PsiValueType> ratios_z(num_wf);
468   for (int i = 0; i < num_wfc; i++)
469   {
470     if (ct == ComputeType::ALL || (wavefunction_components[i]->is_fermionic && ct == ComputeType::FERMIONIC) ||
471         (!wavefunction_components[i]->is_fermionic && ct == ComputeType::NONFERMIONIC))
472     {
473       ScopedTimer z_timer(wf_leader.WFC_timers_[V_TIMER + TIMER_SKIP * i]);
474       const auto wfc_list(extractWFCRefList(wf_list, i));
475       wavefunction_components[i]->mw_calcRatio(wfc_list, p_list, iat, ratios_z);
476       for (int iw = 0; iw < wf_list.size(); iw++)
477         ratios[iw] *= ratios_z[iw];
478     }
479   }
480   for (int iw = 0; iw < wf_list.size(); iw++)
481     wf_list[iw].PhaseDiff = std::imag(std::arg(ratios[iw]));
482 }
483 
prepareGroup(ParticleSet & P,int ig)484 void TrialWaveFunction::prepareGroup(ParticleSet& P, int ig)
485 {
486   for (int i = 0; i < Z.size(); ++i)
487     Z[i]->prepareGroup(P, ig);
488 }
489 
mw_prepareGroup(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,int ig)490 void TrialWaveFunction::mw_prepareGroup(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
491                                         const RefVectorWithLeader<ParticleSet>& p_list,
492                                         int ig)
493 {
494   auto& wf_leader = wf_list.getLeader();
495   ScopedTimer local_timer(wf_leader.TWF_timers_[PREPAREGROUP_TIMER]);
496   const int num_wfc             = wf_leader.Z.size();
497   auto& wavefunction_components = wf_leader.Z;
498 
499   for (int i = 0; i < num_wfc; i++)
500   {
501     ScopedTimer z_timer(wf_leader.WFC_timers_[PREPAREGROUP_TIMER + TIMER_SKIP * i]);
502     const auto wfc_list(extractWFCRefList(wf_list, i));
503     wavefunction_components[i]->mw_prepareGroup(wfc_list, p_list, ig);
504   }
505 }
506 
evalGrad(ParticleSet & P,int iat)507 TrialWaveFunction::GradType TrialWaveFunction::evalGrad(ParticleSet& P, int iat)
508 {
509   ScopedTimer local_timer(TWF_timers_[VGL_TIMER]);
510   GradType grad_iat;
511   for (int i = 0; i < Z.size(); ++i)
512   {
513     ScopedTimer z_timer(WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
514     grad_iat += Z[i]->evalGrad(P, iat);
515   }
516   return grad_iat;
517 }
518 
evalGradWithSpin(ParticleSet & P,int iat,ComplexType & spingrad)519 TrialWaveFunction::GradType TrialWaveFunction::evalGradWithSpin(ParticleSet& P, int iat, ComplexType& spingrad)
520 {
521   ScopedTimer local_timer(TWF_timers_[VGL_TIMER]);
522   GradType grad_iat;
523   spingrad = 0;
524   for (int i = 0; i < Z.size(); ++i)
525   {
526     ScopedTimer z_timer(WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
527     grad_iat += Z[i]->evalGradWithSpin(P, iat, spingrad);
528   }
529   return grad_iat;
530 }
531 
mw_evalGrad(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,int iat,std::vector<GradType> & grad_now)532 void TrialWaveFunction::mw_evalGrad(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
533                                     const RefVectorWithLeader<ParticleSet>& p_list,
534                                     int iat,
535                                     std::vector<GradType>& grad_now)
536 {
537   const int num_wf = wf_list.size();
538   grad_now.resize(num_wf);
539   std::fill(grad_now.begin(), grad_now.end(), GradType(0));
540 
541   auto& wf_leader = wf_list.getLeader();
542   ScopedTimer local_timer(wf_leader.TWF_timers_[VGL_TIMER]);
543   // Right now mw_evalGrad can only be called through an concrete instance of a wavefunctioncomponent
544   const int num_wfc             = wf_leader.Z.size();
545   auto& wavefunction_components = wf_leader.Z;
546 
547   std::vector<GradType> grad_now_z(num_wf);
548   for (int i = 0; i < num_wfc; ++i)
549   {
550     ScopedTimer localtimer(wf_leader.WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
551     const auto wfc_list(extractWFCRefList(wf_list, i));
552     wavefunction_components[i]->mw_evalGrad(wfc_list, p_list, iat, grad_now_z);
553     for (int iw = 0; iw < wf_list.size(); iw++)
554       grad_now[iw] += grad_now_z[iw];
555   }
556 }
557 
558 
559 // Evaluates the gradient w.r.t. to the source of the Laplacian
560 // w.r.t. to the electrons of the wave function.
evalGradSource(ParticleSet & P,ParticleSet & source,int iat)561 TrialWaveFunction::GradType TrialWaveFunction::evalGradSource(ParticleSet& P, ParticleSet& source, int iat)
562 {
563   GradType grad_iat = GradType();
564   for (int i = 0; i < Z.size(); ++i)
565     grad_iat += Z[i]->evalGradSource(P, source, iat);
566   return grad_iat;
567 }
568 
evalGradSource(ParticleSet & P,ParticleSet & source,int iat,TinyVector<ParticleSet::ParticleGradient_t,OHMMS_DIM> & grad_grad,TinyVector<ParticleSet::ParticleLaplacian_t,OHMMS_DIM> & lapl_grad)569 TrialWaveFunction::GradType TrialWaveFunction::evalGradSource(
570     ParticleSet& P,
571     ParticleSet& source,
572     int iat,
573     TinyVector<ParticleSet::ParticleGradient_t, OHMMS_DIM>& grad_grad,
574     TinyVector<ParticleSet::ParticleLaplacian_t, OHMMS_DIM>& lapl_grad)
575 {
576   GradType grad_iat = GradType();
577   for (int dim = 0; dim < OHMMS_DIM; dim++)
578     for (int i = 0; i < grad_grad[0].size(); i++)
579     {
580       grad_grad[dim][i] = GradType();
581       lapl_grad[dim][i] = 0.0;
582     }
583   for (int i = 0; i < Z.size(); ++i)
584     grad_iat += Z[i]->evalGradSource(P, source, iat, grad_grad, lapl_grad);
585   return grad_iat;
586 }
587 
calcRatioGrad(ParticleSet & P,int iat,GradType & grad_iat)588 TrialWaveFunction::ValueType TrialWaveFunction::calcRatioGrad(ParticleSet& P, int iat, GradType& grad_iat)
589 {
590   ScopedTimer local_timer(TWF_timers_[VGL_TIMER]);
591   grad_iat = 0.0;
592   PsiValueType r(1.0);
593   if (use_tasking_)
594   {
595     std::vector<GradType> grad_components(Z.size(), GradType(0.0));
596     std::vector<PsiValueType> ratio_components(Z.size(), 0.0);
597 #pragma omp taskloop default(shared)
598     for (int i = 0; i < Z.size(); ++i)
599     {
600       ScopedTimer z_timer(WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
601       ratio_components[i] = Z[i]->ratioGrad(P, iat, grad_components[i]);
602     }
603 
604     for (int i = 0; i < Z.size(); ++i)
605     {
606       grad_iat += grad_components[i];
607       r *= ratio_components[i];
608     }
609   }
610   else
611     for (int i = 0; i < Z.size(); ++i)
612     {
613       ScopedTimer z_timer(WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
614       r *= Z[i]->ratioGrad(P, iat, grad_iat);
615     }
616   LogValueType logratio = convertValueToLog(r);
617   PhaseDiff             = std::imag(logratio);
618   return static_cast<ValueType>(r);
619 }
620 
calcRatioGradWithSpin(ParticleSet & P,int iat,GradType & grad_iat,ComplexType & spingrad_iat)621 TrialWaveFunction::ValueType TrialWaveFunction::calcRatioGradWithSpin(ParticleSet& P,
622                                                                       int iat,
623                                                                       GradType& grad_iat,
624                                                                       ComplexType& spingrad_iat)
625 {
626   ScopedTimer local_timer(TWF_timers_[VGL_TIMER]);
627   grad_iat     = 0.0;
628   spingrad_iat = 0.0;
629   PsiValueType r(1.0);
630   for (int i = 0; i < Z.size(); ++i)
631   {
632     ScopedTimer z_timer(WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
633     r *= Z[i]->ratioGradWithSpin(P, iat, grad_iat, spingrad_iat);
634   }
635 
636   LogValueType logratio = convertValueToLog(r);
637   PhaseDiff             = std::imag(logratio);
638   return static_cast<ValueType>(r);
639 }
640 
mw_calcRatioGrad(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,int iat,std::vector<PsiValueType> & ratios,std::vector<GradType> & grad_new)641 void TrialWaveFunction::mw_calcRatioGrad(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
642                                          const RefVectorWithLeader<ParticleSet>& p_list,
643                                          int iat,
644                                          std::vector<PsiValueType>& ratios,
645                                          std::vector<GradType>& grad_new)
646 {
647   const int num_wf = wf_list.size();
648   grad_new.resize(num_wf);
649   std::fill(grad_new.begin(), grad_new.end(), GradType(0));
650   ratios.resize(num_wf);
651   std::fill(ratios.begin(), ratios.end(), PsiValueType(1));
652 
653   auto& wf_leader = wf_list.getLeader();
654   ScopedTimer local_timer(wf_leader.TWF_timers_[VGL_TIMER]);
655   const int num_wfc             = wf_leader.Z.size();
656   auto& wavefunction_components = wf_leader.Z;
657 
658   if (wf_leader.use_tasking_)
659   {
660     std::vector<std::vector<PsiValueType>> ratios_components(num_wfc, std::vector<PsiValueType>(wf_list.size()));
661     std::vector<std::vector<GradType>> grads_components(num_wfc, std::vector<GradType>(wf_list.size()));
662 #pragma omp taskloop default(shared)
663     for (int i = 0; i < num_wfc; ++i)
664     {
665       ScopedTimer z_timer(wf_leader.WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
666       const auto wfc_list(extractWFCRefList(wf_list, i));
667       wavefunction_components[i]->mw_ratioGrad(wfc_list, p_list, iat, ratios_components[i], grads_components[i]);
668     }
669 
670     for (int i = 0; i < num_wfc; ++i)
671       for (int iw = 0; iw < wf_list.size(); iw++)
672       {
673         ratios[iw] *= ratios_components[i][iw];
674         grad_new[iw] += grads_components[i][iw];
675       }
676   }
677   else
678   {
679     std::vector<PsiValueType> ratios_z(wf_list.size());
680     for (int i = 0; i < num_wfc; ++i)
681     {
682       ScopedTimer z_timer(wf_leader.WFC_timers_[VGL_TIMER + TIMER_SKIP * i]);
683       const auto wfc_list(extractWFCRefList(wf_list, i));
684       wavefunction_components[i]->mw_ratioGrad(wfc_list, p_list, iat, ratios_z, grad_new);
685       for (int iw = 0; iw < wf_list.size(); iw++)
686         ratios[iw] *= ratios_z[iw];
687     }
688   }
689   for (int iw = 0; iw < wf_list.size(); iw++)
690     wf_list[iw].PhaseDiff = std::imag(std::arg(ratios[iw]));
691 }
692 
printGL(ParticleSet::ParticleGradient_t & G,ParticleSet::ParticleLaplacian_t & L,std::string tag)693 void TrialWaveFunction::printGL(ParticleSet::ParticleGradient_t& G,
694                                 ParticleSet::ParticleLaplacian_t& L,
695                                 std::string tag)
696 {
697   std::ostringstream o;
698   o << "---  reporting " << tag << std::endl << "  ---" << std::endl;
699   for (int iat = 0; iat < L.size(); iat++)
700     o << "index: " << std::fixed << iat << std::scientific << "   G: " << G[iat][0] << "  " << G[iat][1] << "  "
701       << G[iat][2] << "   L: " << L[iat] << std::endl;
702   o << "---  end  ---" << std::endl;
703   std::cout << o.str();
704 }
705 
706 /** restore to the original state
707  * @param iat index of the particle with a trial move
708  *
709  * The proposed move of the iath particle is rejected.
710  * All the temporary data should be restored to the state prior to the move.
711  */
rejectMove(int iat)712 void TrialWaveFunction::rejectMove(int iat)
713 {
714   for (int i = 0; i < Z.size(); i++)
715     Z[i]->restore(iat);
716   PhaseDiff = 0;
717 }
718 
719 /** update the state with the new data
720  * @param P ParticleSet
721  * @param iat index of the particle with a trial move
722  *
723  * The proposed move of the iath particle is accepted.
724  * All the temporary data should be incorporated so that the next move is valid.
725  */
acceptMove(ParticleSet & P,int iat,bool safe_to_delay)726 void TrialWaveFunction::acceptMove(ParticleSet& P, int iat, bool safe_to_delay)
727 {
728   ScopedTimer local_timer(TWF_timers_[ACCEPT_TIMER]);
729 #pragma omp taskloop default(shared) if (use_tasking_)
730   for (int i = 0; i < Z.size(); i++)
731   {
732     ScopedTimer z_timer(WFC_timers_[ACCEPT_TIMER + TIMER_SKIP * i]);
733     Z[i]->acceptMove(P, iat, safe_to_delay);
734   }
735   PhaseValue += PhaseDiff;
736   PhaseDiff = 0.0;
737   LogValue  = 0;
738   for (int i = 0; i < Z.size(); i++)
739     LogValue += std::real(Z[i]->LogValue);
740 }
741 
mw_accept_rejectMove(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,int iat,const std::vector<bool> & isAccepted,bool safe_to_delay)742 void TrialWaveFunction::mw_accept_rejectMove(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
743                                              const RefVectorWithLeader<ParticleSet>& p_list,
744                                              int iat,
745                                              const std::vector<bool>& isAccepted,
746                                              bool safe_to_delay)
747 {
748   auto& wf_leader = wf_list.getLeader();
749   ScopedTimer local_timer(wf_leader.TWF_timers_[ACCEPT_TIMER]);
750   const int num_wfc             = wf_leader.Z.size();
751   auto& wavefunction_components = wf_leader.Z;
752 
753   for (int iw = 0; iw < wf_list.size(); iw++)
754     if (isAccepted[iw])
755     {
756       wf_list[iw].LogValue   = 0;
757       wf_list[iw].PhaseValue = 0;
758     }
759 
760 #pragma omp taskloop default(shared) if (wf_leader.use_tasking_)
761   for (int i = 0; i < num_wfc; i++)
762   {
763     ScopedTimer z_timer(wf_leader.WFC_timers_[ACCEPT_TIMER + TIMER_SKIP * i]);
764     const auto wfc_list(extractWFCRefList(wf_list, i));
765     wavefunction_components[i]->mw_accept_rejectMove(wfc_list, p_list, iat, isAccepted, safe_to_delay);
766     for (int iw = 0; iw < wf_list.size(); iw++)
767       if (isAccepted[iw])
768       {
769         wf_list[iw].LogValue += std::real(wfc_list[iw].LogValue);
770         wf_list[iw].PhaseValue += std::imag(wfc_list[iw].LogValue);
771       }
772   }
773 }
774 
completeUpdates()775 void TrialWaveFunction::completeUpdates()
776 {
777   ScopedTimer local_timer(TWF_timers_[ACCEPT_TIMER]);
778   for (int i = 0; i < Z.size(); i++)
779   {
780     ScopedTimer z_timer(WFC_timers_[ACCEPT_TIMER + TIMER_SKIP * i]);
781     Z[i]->completeUpdates();
782   }
783 }
784 
mw_completeUpdates(const RefVectorWithLeader<TrialWaveFunction> & wf_list)785 void TrialWaveFunction::mw_completeUpdates(const RefVectorWithLeader<TrialWaveFunction>& wf_list)
786 {
787   auto& wf_leader = wf_list.getLeader();
788   ScopedTimer local_timer(wf_leader.TWF_timers_[ACCEPT_TIMER]);
789   const int num_wfc             = wf_leader.Z.size();
790   auto& wavefunction_components = wf_leader.Z;
791 
792   for (int i = 0; i < num_wfc; i++)
793   {
794     ScopedTimer z_timer(wf_leader.WFC_timers_[ACCEPT_TIMER + TIMER_SKIP * i]);
795     const auto wfc_list(extractWFCRefList(wf_list, i));
796     wavefunction_components[i]->mw_completeUpdates(wfc_list);
797   }
798 }
799 
evaluateGL(ParticleSet & P,bool fromscratch)800 TrialWaveFunction::LogValueType TrialWaveFunction::evaluateGL(ParticleSet& P, bool fromscratch)
801 {
802   ScopedTimer local_timer(TWF_timers_[BUFFER_TIMER]);
803   P.G = 0.0;
804   P.L = 0.0;
805   LogValueType logpsi(0.0);
806   for (int i = 0; i < Z.size(); ++i)
807   {
808     ScopedTimer z_timer(WFC_timers_[BUFFER_TIMER + TIMER_SKIP * i]);
809     logpsi += Z[i]->evaluateGL(P, P.G, P.L, fromscratch);
810   }
811 
812   // Ye: temporal workaround to have WF.G/L always defined.
813   // remove when KineticEnergy use WF.G/L instead of P.G/L
814   G          = P.G;
815   L          = P.L;
816   LogValue   = std::real(logpsi);
817   PhaseValue = std::imag(logpsi);
818   return logpsi;
819 }
820 
mw_evaluateGL(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,bool fromscratch)821 void TrialWaveFunction::mw_evaluateGL(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
822                                       const RefVectorWithLeader<ParticleSet>& p_list,
823                                       bool fromscratch)
824 {
825   auto& p_leader  = p_list.getLeader();
826   auto& wf_leader = wf_list.getLeader();
827   ScopedTimer local_timer(wf_leader.TWF_timers_[BUFFER_TIMER]);
828 
829   constexpr RealType czero(0);
830   const auto g_list(TrialWaveFunction::extractGRefList(wf_list));
831   const auto l_list(TrialWaveFunction::extractLRefList(wf_list));
832 
833   const int num_particles = p_leader.getTotalNum();
834   for (TrialWaveFunction& wfs : wf_list)
835   {
836     wfs.G.resize(num_particles);
837     wfs.L.resize(num_particles);
838     wfs.G          = czero;
839     wfs.L          = czero;
840     wfs.LogValue   = czero;
841     wfs.PhaseValue = czero;
842   }
843 
844   auto& wavefunction_components = wf_leader.Z;
845   const int num_wfc             = wf_leader.Z.size();
846 
847   for (int i = 0; i < num_wfc; ++i)
848   {
849     ScopedTimer z_timer(wf_leader.WFC_timers_[BUFFER_TIMER + TIMER_SKIP * i]);
850     const auto wfc_list(extractWFCRefList(wf_list, i));
851     wavefunction_components[i]->mw_evaluateGL(wfc_list, p_list, g_list, l_list, fromscratch);
852   }
853 
854   for (int iw = 0; iw < wf_list.size(); iw++)
855   {
856     ParticleSet& pset      = p_list[iw];
857     TrialWaveFunction& twf = wf_list[iw];
858 
859     for (int i = 0; i < num_wfc; ++i)
860     {
861       twf.LogValue += std::real(twf.Z[i]->LogValue);
862       twf.PhaseValue += std::imag(twf.Z[i]->LogValue);
863     }
864 
865     // Ye: temporal workaround to have P.G/L always defined.
866     // remove when KineticEnergy use WF.G/L instead of P.G/L
867     pset.G = twf.G;
868     pset.L = twf.L;
869   }
870 }
871 
872 
checkInVariables(opt_variables_type & active)873 void TrialWaveFunction::checkInVariables(opt_variables_type& active)
874 {
875   for (int i = 0; i < Z.size(); i++)
876     Z[i]->checkInVariables(active);
877 }
878 
checkOutVariables(const opt_variables_type & active)879 void TrialWaveFunction::checkOutVariables(const opt_variables_type& active)
880 {
881   for (int i = 0; i < Z.size(); i++)
882     Z[i]->checkOutVariables(active);
883 }
884 
resetParameters(const opt_variables_type & active)885 void TrialWaveFunction::resetParameters(const opt_variables_type& active)
886 {
887   for (int i = 0; i < Z.size(); i++)
888     Z[i]->resetParameters(active);
889 }
890 
reportStatus(std::ostream & os)891 void TrialWaveFunction::reportStatus(std::ostream& os)
892 {
893   for (int i = 0; i < Z.size(); i++)
894     Z[i]->reportStatus(os);
895 }
896 
getLogs(std::vector<RealType> & lvals)897 void TrialWaveFunction::getLogs(std::vector<RealType>& lvals)
898 {
899   lvals.resize(Z.size(), 0);
900   for (int i = 0; i < Z.size(); i++)
901   {
902     lvals[i] = std::real(Z[i]->LogValue);
903   }
904 }
905 
getPhases(std::vector<RealType> & pvals)906 void TrialWaveFunction::getPhases(std::vector<RealType>& pvals)
907 {
908   pvals.resize(Z.size(), 0);
909   for (int i = 0; i < Z.size(); i++)
910   {
911     pvals[i] = std::imag(Z[i]->LogValue);
912   }
913 }
914 
registerData(ParticleSet & P,WFBufferType & buf)915 void TrialWaveFunction::registerData(ParticleSet& P, WFBufferType& buf)
916 {
917   ScopedTimer local_timer(TWF_timers_[BUFFER_TIMER]);
918   //save the current position
919   BufferCursor        = buf.current();
920   BufferCursor_scalar = buf.current_scalar();
921   for (int i = 0; i < Z.size(); ++i)
922   {
923     ScopedTimer z_timer(WFC_timers_[BUFFER_TIMER + TIMER_SKIP * i]);
924     Z[i]->registerData(P, buf);
925   }
926   buf.add(PhaseValue);
927   buf.add(LogValue);
928 }
929 
debugOnlyCheckBuffer(WFBufferType & buffer)930 void TrialWaveFunction::debugOnlyCheckBuffer(WFBufferType& buffer)
931 {
932 #ifndef NDEBUG
933   if (buffer.size() < buffer.current() + buffer.current_scalar() * sizeof(FullPrecRealType))
934   {
935     std::ostringstream assert_message;
936     assert_message << "On thread:" << Concurrency::getWorkerId<>() << "  buf_list[iw].get().size():" << buffer.size()
937                    << " < buf_list[iw].get().current():" << buffer.current()
938                    << " + buf.current_scalar():" << buffer.current_scalar()
939                    << " * sizeof(FullPrecRealType):" << sizeof(FullPrecRealType) << '\n';
940     throw std::runtime_error(assert_message.str());
941   }
942 #endif
943 }
944 
updateBuffer(ParticleSet & P,WFBufferType & buf,bool fromscratch)945 TrialWaveFunction::RealType TrialWaveFunction::updateBuffer(ParticleSet& P, WFBufferType& buf, bool fromscratch)
946 {
947   ScopedTimer local_timer(TWF_timers_[BUFFER_TIMER]);
948   P.G = 0.0;
949   P.L = 0.0;
950   buf.rewind(BufferCursor, BufferCursor_scalar);
951   LogValueType logpsi(0.0);
952   for (int i = 0; i < Z.size(); ++i)
953   {
954     ScopedTimer z_timer(WFC_timers_[BUFFER_TIMER + TIMER_SKIP * i]);
955     logpsi += Z[i]->updateBuffer(P, buf, fromscratch);
956   }
957 
958   G = P.G;
959   L = P.L;
960 
961   LogValue   = std::real(logpsi);
962   PhaseValue = std::imag(logpsi);
963   //printGL(P.G,P.L);
964   buf.put(PhaseValue);
965   buf.put(LogValue);
966   // Ye: temperal added check, to be removed
967   debugOnlyCheckBuffer(buf);
968   return LogValue;
969 }
970 
copyFromBuffer(ParticleSet & P,WFBufferType & buf)971 void TrialWaveFunction::copyFromBuffer(ParticleSet& P, WFBufferType& buf)
972 {
973   ScopedTimer local_timer(TWF_timers_[BUFFER_TIMER]);
974   buf.rewind(BufferCursor, BufferCursor_scalar);
975   for (int i = 0; i < Z.size(); ++i)
976   {
977     ScopedTimer z_timer(WFC_timers_[BUFFER_TIMER + TIMER_SKIP * i]);
978     Z[i]->copyFromBuffer(P, buf);
979   }
980   //get the gradients and laplacians from the buffer
981   buf.get(PhaseValue);
982   buf.get(LogValue);
983   debugOnlyCheckBuffer(buf);
984 }
985 
evaluateRatios(const VirtualParticleSet & VP,std::vector<ValueType> & ratios,ComputeType ct)986 void TrialWaveFunction::evaluateRatios(const VirtualParticleSet& VP, std::vector<ValueType>& ratios, ComputeType ct)
987 {
988   ScopedTimer local_timer(TWF_timers_[NL_TIMER]);
989   assert(VP.getTotalNum() == ratios.size());
990   std::vector<ValueType> t(ratios.size());
991   std::fill(ratios.begin(), ratios.end(), 1.0);
992   for (int i = 0; i < Z.size(); ++i)
993     if (ct == ComputeType::ALL || (Z[i]->is_fermionic && ct == ComputeType::FERMIONIC) ||
994         (!Z[i]->is_fermionic && ct == ComputeType::NONFERMIONIC))
995     {
996       ScopedTimer z_timer(WFC_timers_[NL_TIMER + TIMER_SKIP * i]);
997       Z[i]->evaluateRatios(VP, t);
998       for (int j = 0; j < ratios.size(); ++j)
999         ratios[j] *= t[j];
1000     }
1001 }
1002 
mw_evaluateRatios(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVector<const VirtualParticleSet> & vp_list,const RefVector<std::vector<ValueType>> & ratios_list,ComputeType ct)1003 void TrialWaveFunction::mw_evaluateRatios(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
1004                                           const RefVector<const VirtualParticleSet>& vp_list,
1005                                           const RefVector<std::vector<ValueType>>& ratios_list,
1006                                           ComputeType ct)
1007 {
1008   auto& wf_leader = wf_list.getLeader();
1009   ScopedTimer local_timer(wf_leader.TWF_timers_[NL_TIMER]);
1010   auto& wavefunction_components = wf_leader.Z;
1011   std::vector<std::vector<ValueType>> t(ratios_list.size());
1012   for (int iw = 0; iw < wf_list.size(); iw++)
1013   {
1014     std::vector<ValueType>& ratios = ratios_list[iw];
1015     assert(vp_list[iw].get().getTotalNum() == ratios.size());
1016     std::fill(ratios.begin(), ratios.end(), 1.0);
1017     t[iw].resize(ratios.size());
1018   }
1019 
1020   for (int i = 0; i < wavefunction_components.size(); i++)
1021     if (ct == ComputeType::ALL || (wavefunction_components[i]->is_fermionic && ct == ComputeType::FERMIONIC) ||
1022         (!wavefunction_components[i]->is_fermionic && ct == ComputeType::NONFERMIONIC))
1023     {
1024       ScopedTimer z_timer(wf_leader.WFC_timers_[NL_TIMER + TIMER_SKIP * i]);
1025       const auto wfc_list(extractWFCRefList(wf_list, i));
1026       wavefunction_components[i]->mw_evaluateRatios(wfc_list, vp_list, t);
1027       for (int iw = 0; iw < wf_list.size(); iw++)
1028       {
1029         std::vector<ValueType>& ratios = ratios_list[iw];
1030         for (int j = 0; j < ratios.size(); ++j)
1031           ratios[j] *= t[iw][j];
1032       }
1033     }
1034 }
1035 
evaluateDerivRatios(VirtualParticleSet & VP,const opt_variables_type & optvars,std::vector<ValueType> & ratios,Matrix<ValueType> & dratio)1036 void TrialWaveFunction::evaluateDerivRatios(VirtualParticleSet& VP,
1037                                             const opt_variables_type& optvars,
1038                                             std::vector<ValueType>& ratios,
1039                                             Matrix<ValueType>& dratio)
1040 {
1041 #if defined(QMC_COMPLEX)
1042   APP_ABORT("TrialWaveFunction::evaluateDerivRatios not available for complex wavefunctions");
1043 #else
1044   std::fill(ratios.begin(), ratios.end(), 1.0);
1045   std::vector<ValueType> t(ratios.size());
1046   for (int i = 0; i < Z.size(); ++i)
1047   {
1048     Z[i]->evaluateDerivRatios(VP, optvars, t, dratio);
1049     for (int j = 0; j < ratios.size(); ++j)
1050       ratios[j] *= t[j];
1051   }
1052 #endif
1053 }
1054 
put(xmlNodePtr cur)1055 bool TrialWaveFunction::put(xmlNodePtr cur) { return true; }
1056 
reset()1057 void TrialWaveFunction::reset() {}
1058 
makeClone(ParticleSet & tqp) const1059 TrialWaveFunction* TrialWaveFunction::makeClone(ParticleSet& tqp) const
1060 {
1061   TrialWaveFunction* myclone   = new TrialWaveFunction(myName, use_tasking_, false);
1062   myclone->BufferCursor        = BufferCursor;
1063   myclone->BufferCursor_scalar = BufferCursor_scalar;
1064   for (int i = 0; i < Z.size(); ++i)
1065     myclone->addComponent(Z[i]->makeClone(tqp));
1066   myclone->OneOverM = OneOverM;
1067   return myclone;
1068 }
1069 
1070 /** evaluate derivatives of KE wrt optimizable varibles
1071  *
1072  * @todo WaveFunctionComponent objects should take the mass into account.
1073  */
evaluateDerivatives(ParticleSet & P,const opt_variables_type & optvars,std::vector<ValueType> & dlogpsi,std::vector<ValueType> & dhpsioverpsi,bool project)1074 void TrialWaveFunction::evaluateDerivatives(ParticleSet& P,
1075                                             const opt_variables_type& optvars,
1076                                             std::vector<ValueType>& dlogpsi,
1077                                             std::vector<ValueType>& dhpsioverpsi,
1078                                             bool project)
1079 {
1080   //     // First, zero out derivatives
1081   //  This should only be done for some variables.
1082   //     for (int j=0; j<dlogpsi.size(); j++)
1083   //       dlogpsi[j] = dhpsioverpsi[j] = 0.0;
1084   for (int i = 0; i < Z.size(); i++)
1085   {
1086     if (Z[i]->dPsi)
1087       (Z[i]->dPsi)->evaluateDerivatives(P, optvars, dlogpsi, dhpsioverpsi);
1088     else
1089       Z[i]->evaluateDerivatives(P, optvars, dlogpsi, dhpsioverpsi);
1090   }
1091   //orbitals do not know about mass of particle.
1092   for (int i = 0; i < dhpsioverpsi.size(); i++)
1093     dhpsioverpsi[i] *= OneOverM;
1094 
1095   if (project)
1096   {
1097     for (int i = 0; i < Z.size(); i++)
1098     {
1099       if (Z[i]->dPsi)
1100         (Z[i]->dPsi)->multiplyDerivsByOrbR(dlogpsi);
1101       else
1102         Z[i]->multiplyDerivsByOrbR(dlogpsi);
1103     }
1104     RealType psiValue = std::exp(-LogValue) * std::cos(PhaseValue);
1105     for (int i = 0; i < dlogpsi.size(); i++)
1106       dlogpsi[i] *= psiValue;
1107   }
1108 }
1109 
mw_evaluateParameterDerivatives(const RefVectorWithLeader<TrialWaveFunction> & wf_list,const RefVectorWithLeader<ParticleSet> & p_list,const opt_variables_type & optvars,RecordArray<ValueType> & dlogpsi,RecordArray<ValueType> & dhpsioverpsi)1110 void TrialWaveFunction::mw_evaluateParameterDerivatives(const RefVectorWithLeader<TrialWaveFunction>& wf_list,
1111                                                         const RefVectorWithLeader<ParticleSet>& p_list,
1112                                                         const opt_variables_type& optvars,
1113                                                         RecordArray<ValueType>& dlogpsi,
1114                                                         RecordArray<ValueType>& dhpsioverpsi)
1115 {
1116   const int nparam = dlogpsi.nparam();
1117   for (int iw = 0; iw < wf_list.size(); iw++)
1118   {
1119     std::vector<ValueType> tmp_dlogpsi(nparam);
1120     std::vector<ValueType> tmp_dhpsioverpsi(nparam);
1121     TrialWaveFunction& twf = wf_list[iw];
1122     for (int i = 0; i < twf.Z.size(); i++)
1123     {
1124       if (twf.Z[i]->dPsi)
1125         (twf.Z[i]->dPsi)->evaluateDerivatives(p_list[iw], optvars, tmp_dlogpsi, tmp_dhpsioverpsi);
1126       else
1127         twf.Z[i]->evaluateDerivatives(p_list[iw], optvars, tmp_dlogpsi, tmp_dhpsioverpsi);
1128     }
1129 
1130     RealType OneOverM = twf.getReciprocalMass();
1131     for (int i = 0; i < nparam; i++)
1132     {
1133       dlogpsi.setValue(i, iw, tmp_dlogpsi[i]);
1134       //orbitals do not know about mass of particle.
1135       dhpsioverpsi.setValue(i, iw, tmp_dhpsioverpsi[i] * OneOverM);
1136     }
1137   }
1138 }
1139 
1140 
evaluateDerivativesWF(ParticleSet & P,const opt_variables_type & optvars,std::vector<ValueType> & dlogpsi)1141 void TrialWaveFunction::evaluateDerivativesWF(ParticleSet& P,
1142                                               const opt_variables_type& optvars,
1143                                               std::vector<ValueType>& dlogpsi)
1144 {
1145   for (int i = 0; i < Z.size(); i++)
1146   {
1147     if (Z[i]->dPsi)
1148       (Z[i]->dPsi)->evaluateDerivativesWF(P, optvars, dlogpsi);
1149     else
1150       Z[i]->evaluateDerivativesWF(P, optvars, dlogpsi);
1151   }
1152 }
1153 
evaluateGradDerivatives(const ParticleSet::ParticleGradient_t & G_in,std::vector<ValueType> & dgradlogpsi)1154 void TrialWaveFunction::evaluateGradDerivatives(const ParticleSet::ParticleGradient_t& G_in,
1155                                                 std::vector<ValueType>& dgradlogpsi)
1156 {
1157   for (int i = 0; i < Z.size(); i++)
1158   {
1159     Z[i]->evaluateGradDerivatives(G_in, dgradlogpsi);
1160   }
1161 }
1162 
KECorrection() const1163 TrialWaveFunction::RealType TrialWaveFunction::KECorrection() const
1164 {
1165   RealType sum = 0.0;
1166   for (int i = 0; i < Z.size(); ++i)
1167     sum += Z[i]->KECorrection();
1168   return sum;
1169 }
1170 
evaluateRatiosAlltoOne(ParticleSet & P,std::vector<ValueType> & ratios)1171 void TrialWaveFunction::evaluateRatiosAlltoOne(ParticleSet& P, std::vector<ValueType>& ratios)
1172 {
1173   ScopedTimer local_timer(TWF_timers_[V_TIMER]);
1174   std::fill(ratios.begin(), ratios.end(), 1.0);
1175   std::vector<ValueType> t(ratios.size());
1176   for (int i = 0; i < Z.size(); ++i)
1177   {
1178     ScopedTimer local_timer(WFC_timers_[V_TIMER + TIMER_SKIP * i]);
1179     Z[i]->evaluateRatiosAlltoOne(P, t);
1180     for (int j = 0; j < t.size(); ++j)
1181       ratios[j] *= t[j];
1182   }
1183 }
1184 
createResource(ResourceCollection & collection) const1185 void TrialWaveFunction::createResource(ResourceCollection& collection) const
1186 {
1187   for (int i = 0; i < Z.size(); ++i)
1188     Z[i]->createResource(collection);
1189 }
1190 
acquireResource(ResourceCollection & collection)1191 void TrialWaveFunction::acquireResource(ResourceCollection& collection)
1192 {
1193   for (int i = 0; i < Z.size(); ++i)
1194     Z[i]->acquireResource(collection);
1195 }
1196 
releaseResource(ResourceCollection & collection)1197 void TrialWaveFunction::releaseResource(ResourceCollection& collection)
1198 {
1199   for (int i = 0; i < Z.size(); ++i)
1200     Z[i]->releaseResource(collection);
1201 }
1202 
extractWFCRefList(const RefVectorWithLeader<TrialWaveFunction> & wf_list,int id)1203 RefVectorWithLeader<WaveFunctionComponent> TrialWaveFunction::extractWFCRefList(
1204     const RefVectorWithLeader<TrialWaveFunction>& wf_list,
1205     int id)
1206 {
1207   RefVectorWithLeader<WaveFunctionComponent> wfc_list(*wf_list.getLeader().Z[id]);
1208   wfc_list.reserve(wf_list.size());
1209   for (TrialWaveFunction& wf : wf_list)
1210     wfc_list.push_back(*wf.Z[id]);
1211   return wfc_list;
1212 }
1213 
extractWFCPtrList(const UPtrVector<TrialWaveFunction> & g,int id)1214 std::vector<WaveFunctionComponent*> TrialWaveFunction::extractWFCPtrList(const UPtrVector<TrialWaveFunction>& g, int id)
1215 {
1216   std::vector<WaveFunctionComponent*> WFC_list;
1217   WFC_list.reserve(g.size());
1218   for (auto& WF : g)
1219     WFC_list.push_back(WF->Z[id]);
1220   return WFC_list;
1221 }
1222 
extractGRefList(const RefVectorWithLeader<TrialWaveFunction> & wf_list)1223 RefVector<ParticleSet::ParticleGradient_t> TrialWaveFunction::extractGRefList(
1224     const RefVectorWithLeader<TrialWaveFunction>& wf_list)
1225 {
1226   RefVector<ParticleSet::ParticleGradient_t> g_list;
1227   for (TrialWaveFunction& wf : wf_list)
1228     g_list.push_back(wf.G);
1229   return g_list;
1230 }
1231 
extractLRefList(const RefVectorWithLeader<TrialWaveFunction> & wf_list)1232 RefVector<ParticleSet::ParticleLaplacian_t> TrialWaveFunction::extractLRefList(
1233     const RefVectorWithLeader<TrialWaveFunction>& wf_list)
1234 {
1235   RefVector<ParticleSet::ParticleLaplacian_t> l_list;
1236   for (TrialWaveFunction& wf : wf_list)
1237     l_list.push_back(wf.L);
1238   return l_list;
1239 }
1240 
1241 
1242 } // namespace qmcplusplus
1243