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 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
11 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
12 //
13 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15 
16 
17 /**@file QMCHamiltonian.h
18  *@brief Declaration of QMCHamiltonian
19  */
20 #ifndef QMCPLUSPLUS_HAMILTONIAN_H
21 #define QMCPLUSPLUS_HAMILTONIAN_H
22 #include "QMCHamiltonians/NonLocalECPotential.h"
23 #include "QMCHamiltonians/L2Potential.h"
24 #include "Configuration.h"
25 #include "QMCDrivers/WalkerProperties.h"
26 #include "QMCHamiltonians/OperatorBase.h"
27 #if !defined(REMOVE_TRACEMANAGER)
28 #include "Estimators/TraceManager.h"
29 #endif
30 #include "QMCWaveFunctions/OrbitalSetTraits.h"
31 
32 namespace qmcplusplus
33 {
34 class MCWalkerConfiguration;
35 class HamiltonianFactory;
36 class NonLocalECPotential;
37 
38 /**  Collection of Local Energy Operators
39  *
40  * Note that QMCHamiltonian is not derived from QMCHmailtonianBase.
41  */
42 class QMCHamiltonian
43 {
44   friend class HamiltonianFactory;
45 
46 public:
47   typedef OperatorBase::Return_t Return_t;
48   typedef OperatorBase::PosType PosType;
49   typedef OperatorBase::TensorType TensorType;
50   typedef OperatorBase::RealType RealType;
51   typedef OperatorBase::ValueType ValueType;
52   using FullPrecRealType = QMCTraits::FullPrecRealType;
53   typedef OperatorBase::PropertySetType PropertySetType;
54   typedef OperatorBase::BufferType BufferType;
55   typedef OperatorBase::Walker_t Walker_t;
56   using WP = WalkerProperties::Indexes;
57   enum
58   {
59     DIM = OHMMS_DIM
60   };
61 
62   ///constructor
63   QMCHamiltonian(const std::string& aname = "psi0");
64 
65   ///destructor
66   ~QMCHamiltonian();
67 
68   ///add an operator
69   void addOperator(OperatorBase* h, const std::string& aname, bool physical = true);
70 
71   ///record the name-type pair of an operator
72   void addOperatorType(const std::string& name, const std::string& type);
73 
74   ///return type of named H element or fail
75   const std::string& getOperatorType(const std::string& name);
76 
77   ///return the number of Hamiltonians
size()78   inline int size() const { return H.size(); }
79 
80   ///return the total number of Hamiltonians (physical + aux)
total_size()81   inline int total_size() const { return H.size() + auxH.size(); }
82 
83   /** return OperatorBase with the name aname
84    * @param aname name of a OperatorBase
85    * @return 0 if aname is not found.
86    */
87   OperatorBase* getHamiltonian(const std::string& aname);
88 
89   /** return i-th OperatorBase
90    * @param i index of the OperatorBase
91    * @return H[i]
92    */
getHamiltonian(int i)93   OperatorBase* getHamiltonian(int i) { return H[i]; }
94 
95 #if !defined(REMOVE_TRACEMANAGER)
96   ///initialize trace data
97   void initialize_traces(TraceManager& tm, ParticleSet& P);
98 
99   // ///collect scalar trace data
100   //void collect_scalar_traces();
101 
102   ///collect walker trace data
103   void collect_walker_traces(Walker_t& walker, int step);
104 
105   ///finalize trace data
106   void finalize_traces();
107 #endif
108 
109   /**
110    * \defgroup Functions to get/put observables
111    */
112   /**@{*/
113   /** add each term to the PropertyList for averages
114    * @param plist a set of properties to which this Hamiltonian add the observables
115    */
116   //void addObservables(PropertySetType& plist);
117 
118   /** add each term to P.PropertyList and P.mcObservables
119    * @param P particle set to which observables are added
120    * @return the number of observables
121    */
122   int addObservables(ParticleSet& P);
123 
124   /** register obsevables so that their averages can be dumped to hdf5
125    * @param h5desc has observable_helper* for each h5 group
126    * @param gid h5 group id to which the observable groups are added.
127    */
128   void registerObservables(std::vector<observable_helper*>& h5desc, hid_t gid) const;
129   /** register collectables so that their averages can be dumped to hdf5
130    * @param h5desc has observable_helper* for each h5 group
131    * @param gid h5 group id to which the observable groups are added.
132    *
133    * Add observable_helper information for the data stored in ParticleSet::mcObservables.
134    */
135   void registerCollectables(std::vector<observable_helper*>& h5desc, hid_t gid) const;
136   ///retrun the starting index
startIndex()137   inline int startIndex() const { return myIndex; }
138   ///return the size of observables
sizeOfObservables()139   inline int sizeOfObservables() const { return Observables.size(); }
140   ///return the size of collectables
sizeOfCollectables()141   inline int sizeOfCollectables() const { return numCollectables; }
142   ///return the value of the i-th observable
getObservable(int i)143   inline RealType getObservable(int i) const { return Observables.Values[i]; }
144   ///return the value of the observable with a set name if it exists
getObservable(std::string Oname)145   inline int getObservable(std::string Oname) const
146   {
147     int rtval(-1);
148     for (int io = 0; io < Observables.size(); io++)
149     {
150       if (Observables.Names[io] == Oname)
151         return io;
152     }
153     return rtval;
154   }
155   ///return the name of the i-th observable
getObservableName(int i)156   inline std::string getObservableName(int i) const { return Observables.Names[i]; }
157 
158   /** save the values of Hamiltonian elements to the Properties
159    *
160    *  This creates a hard dependence on Walker using WalkerProperties to index its Properties.
161    *  It also assumes no one else is sticking things into Walker's Properties and that
162    *  It can access into it as if it were a raw FullPrecRealType array.
163    *
164    */
165   template<class IT, typename = std::enable_if_t<std::is_same<std::add_pointer<FullPrecRealType>::type, IT>::value>>
saveProperty(IT first)166   inline void saveProperty(IT first)
167   {
168     first[WP::LOCALPOTENTIAL] = LocalEnergy - KineticEnergy;
169     copy(Observables.begin(), Observables.end(), first + myIndex);
170   }
171   /**@}*/
172 
173   template<class IT, typename = std::enable_if_t<std::is_same<std::add_pointer<FullPrecRealType>::type, IT>::value>>
setProperty(IT first)174   inline void setProperty(IT first)
175   {
176     //       LocalEnergy=first[WP::LOCALENERGY];
177     //       KineticEnergy=LocalEnergy-first[LOCALPOTENTIAL];
178     copy(first + myIndex, first + myIndex + Observables.size(), Observables.begin());
179   }
180 
181   void update_source(ParticleSet& s);
182 
183   ////return the LocalEnergy \f$=\sum_i H^{qmc}_{i}\f$
getLocalEnergy()184   inline FullPrecRealType getLocalEnergy() { return LocalEnergy; }
185   ////return the LocalPotential \f$=\sum_i H^{qmc}_{i} - KE\f$
getLocalPotential()186   inline FullPrecRealType getLocalPotential() { return LocalEnergy - KineticEnergy; }
getKineticEnergy()187   inline FullPrecRealType getKineticEnergy() { return KineticEnergy; }
188   void auxHevaluate(ParticleSet& P);
189   void auxHevaluate(ParticleSet& P, Walker_t& ThisWalker);
190   void auxHevaluate(ParticleSet& P, Walker_t& ThisWalker, bool do_properties, bool do_collectables);
191   void rejectedMove(ParticleSet& P, Walker_t& ThisWalker);
192   ///** set Tau for each Hamiltonian
193   // */
194   //inline void setTau(RealType tau)
195   //{
196   //  for(int i=0; i< H.size();i++)H[i]->setTau(tau);
197   //}
198 
199   /** set PRIMARY bit of all the components
200    */
setPrimary(bool primary)201   inline void setPrimary(bool primary)
202   {
203     for (int i = 0; i < H.size(); i++)
204       H[i]->UpdateMode.set(OperatorBase::PRIMARY, primary);
205   }
206 
207   /////Set Tau inside each of the Hamiltonian elements
208   //void setTau(Return_t tau)
209   //{
210   //  for(int i=0; i<H.size(); i++) H[i]->setTau(tau);
211   //  for(int i=0; i<auxH.size(); i++) auxH[i]->setTau(tau);
212   //}
213 
214   ///** return if WaveFunction Ratio needs to be evaluated
215   // *
216   // * This is added to handle orbital-dependent OperatorBase during
217   // * orbital optimizations.
218   // */
219   //inline bool needRatio() {
220   //  bool dependOnOrbital=false;
221   //  for(int i=0; i< H.size();i++)
222   //    if(H[i]->UpdateMode[OperatorBase::RATIOUPDATE]) dependOnOrbital=true;
223   //  return dependOnOrbital;
224   //}
225 
226   /** evaluate Local Energy
227    * @param P ParticleSet
228    * @return the local energy
229    *
230    * P.R, P.G and P.L are used to evaluate the LocalEnergy.
231    */
232   FullPrecRealType evaluate(ParticleSet& P);
233 
234   /** evaluate Local Energy deterministically.  Defaults to evaluate(P) for operators
235    * without a stochastic component. For the nonlocal PP, the quadrature grid is not rerandomized.
236    * @param P ParticleSet
237    * @return Local energy.
238    */
239   FullPrecRealType evaluateDeterministic(ParticleSet& P);
240   /** batched version of evaluate for LocalEnergy
241    *
242    *  Encapsulation is ignored for ham_list hamiltonians method uses its status as QMCHamiltonian to break encapsulation.
243    *  ParticleSet is also updated.
244    *  Bugs could easily be created by accessing this scope.
245    *  This should be set to static and fixed.
246    */
247   static std::vector<QMCHamiltonian::FullPrecRealType> mw_evaluate(const RefVectorWithLeader<QMCHamiltonian>& ham_list,
248                                                                    const RefVectorWithLeader<ParticleSet>& p_list);
249 
250   /** evaluate Local energy with Toperators updated.
251    * @param P ParticleSEt
252    * @return Local energy
253    */
254   FullPrecRealType evaluateWithToperator(ParticleSet& P);
255 
256   /** batched version of evaluate Local energy with Toperators updated.
257    */
258   static std::vector<QMCHamiltonian::FullPrecRealType> mw_evaluateWithToperator(
259       const RefVectorWithLeader<QMCHamiltonian>& ham_list,
260       const RefVectorWithLeader<ParticleSet>& p_list);
261 
262 
263   /** evaluate energy and derivatives wrt to the variables
264    * @param P ParticleSet
265    * @param optvars current optimiable variables
266    * @param dlogpsi \f$\partial \ln \Psi({\bf R})/\partial \alpha \f$
267    * @param dhpsioverpsi \f$\partial(\hat{h}\Psi({\bf R})/\Psi({\bf R})) /\partial \alpha \f$
268    * @param compute_deriv if true, compute dhpsioverpsi of the non-local potential component
269    */
270   FullPrecRealType evaluateValueAndDerivatives(ParticleSet& P,
271                                                const opt_variables_type& optvars,
272                                                std::vector<ValueType>& dlogpsi,
273                                                std::vector<ValueType>& dhpsioverpsi,
274                                                bool compute_deriv);
275 
276   static std::vector<QMCHamiltonian::FullPrecRealType> mw_evaluateValueAndDerivatives(
277       const RefVectorWithLeader<QMCHamiltonian>& ham_list,
278       const RefVectorWithLeader<ParticleSet>& p_list,
279       const opt_variables_type& optvars,
280       RecordArray<ValueType>& dlogpsi,
281       RecordArray<ValueType>& dhpsioverpsi,
282       bool compute_deriv);
283 
284   static std::vector<QMCHamiltonian::FullPrecRealType> mw_evaluateValueAndDerivativesInner(
285       const RefVectorWithLeader<QMCHamiltonian>& ham_list,
286       const RefVectorWithLeader<ParticleSet>& p_list,
287       const opt_variables_type& optvars,
288       RecordArray<ValueType>& dlogpsi,
289       RecordArray<ValueType>& dhpsioverpsi);
290 
291 
292   /** Evaluate the electron gradient of the local energy.
293   * @param psi Trial Wave Function
294   * @param P electron particle set
295   * @param EGrad an Nelec x 3 real array which corresponds to d/d[r_i]_j E_L
296   * @param A finite difference step size if applicable.  Default is to use finite diff with delta=1e-5.
297   * @return EGrad.  Function itself returns nothing.
298   */
299   void evaluateElecGrad(ParticleSet& P,
300                         TrialWaveFunction& psi,
301                         ParticleSet::ParticlePos_t& EGrad,
302                         RealType delta = 1e-5);
303 
304   /** evaluate local energy and derivatives w.r.t ionic coordinates.
305   * @param P target particle set (electrons)
306   * @param ions source particle set (ions)
307   * @param psi Trial wave function
308   * @param hf_terms  Re [(dH)Psi]/Psi
309   * @param pulay_terms Re [(H-E_L)dPsi]/Psi
310   * @param wf_grad  Re (dPsi/Psi)
311   * @return Local Energy.
312   */
313   FullPrecRealType evaluateIonDerivs(ParticleSet& P,
314                                      ParticleSet& ions,
315                                      TrialWaveFunction& psi,
316                                      ParticleSet::ParticlePos_t& hf_terms,
317                                      ParticleSet::ParticlePos_t& pulay_terms,
318                                      ParticleSet::ParticlePos_t& wf_grad);
319   /** set non local moves options
320    * @param cur the xml input
321    */
322   void setNonLocalMoves(xmlNodePtr cur);
323 
324   void setNonLocalMoves(const std::string& non_local_move_option,
325                         const double tau,
326                         const double alpha,
327                         const double gamma);
328 
329   /** make non local moves
330    * @param P particle set
331    * @return the number of accepted moves
332    */
333   int makeNonLocalMoves(ParticleSet& P);
334 
335   /** determine if L2 potential is present
336    */
has_L2()337   bool has_L2() { return l2_ptr != nullptr; }
338 
339   /** compute D matrix and K vector for L2 potential propagator
340     * @param r single particle coordinate
341     * @param D diffusion matrix (outputted)
342     * @param K drift modification vector (outputted)
343     */
computeL2DK(ParticleSet & P,int iel,TensorType & D,PosType & K)344   void computeL2DK(ParticleSet& P, int iel, TensorType& D, PosType& K)
345   {
346     if (l2_ptr != nullptr)
347       l2_ptr->evaluateDK(P, iel, D, K);
348   }
349 
350   /** compute D matrix for L2 potential propagator
351     * @param r single particle coordinate
352     * @param D diffusion matrix (outputted)
353     */
computeL2D(ParticleSet & P,int iel,TensorType & D)354   void computeL2D(ParticleSet& P, int iel, TensorType& D)
355   {
356     if (l2_ptr != nullptr)
357       l2_ptr->evaluateD(P, iel, D);
358   }
359 
360   static std::vector<int> mw_makeNonLocalMoves(const RefVectorWithLeader<QMCHamiltonian>& ham_list,
361                                                const RefVectorWithLeader<ParticleSet>& p_list);
362   /** evaluate energy
363    * @param P quantum particleset
364    * @param free_nlpp if true, non-local PP is a variable
365    * @return KE + NonLocal potential
366    */
367   FullPrecRealType evaluateVariableEnergy(ParticleSet& P, bool free_nlpp);
368 
369   /** return an average value of the LocalEnergy
370    *
371    * Introduced to get a collective value
372    */
373   FullPrecRealType getEnsembleAverage();
374 
375   void resetTargetParticleSet(ParticleSet& P);
376 
getName()377   const std::string& getName() const { return myName; }
378 
379   bool get(std::ostream& os) const;
380 
get_LocalEnergy()381   RealType get_LocalEnergy() const { return LocalEnergy; }
382 
383   void setRandomGenerator(RandomGenerator_t* rng);
384 
385   static void updateNonKinetic(OperatorBase& op, QMCHamiltonian& ham, ParticleSet& pset);
386   static void updateKinetic(OperatorBase& op, QMCHamiltonian& ham, ParticleSet& pset);
387 
388 
389   /// initialize a shared resource and hand it to a collection
390   void createResource(ResourceCollection& collection) const;
391   /** acquire external resource
392    * Note: use RAII ResourceCollectionLock whenever possible
393    */
394   void acquireResource(ResourceCollection& collection);
395   /** release external resource
396    * Note: use RAII ResourceCollectionLock whenever possible
397    */
398   void releaseResource(ResourceCollection& collection);
399 
400   /** return a clone */
401   QMCHamiltonian* makeClone(ParticleSet& qp, TrialWaveFunction& psi);
402 
403 #ifdef QMC_CUDA
404   ////////////////////////////////////////////
405   // Vectorized evaluation routines for GPU //
406   ////////////////////////////////////////////
407   void evaluate(MCWalkerConfiguration& W, std::vector<RealType>& LocalEnergy);
408   void evaluate(MCWalkerConfiguration& W,
409                 std::vector<RealType>& energyVector,
410                 std::vector<std::vector<NonLocalData>>& Txy);
411 
412 private:
413   /////////////////////
414   // Vectorized data //
415   /////////////////////
416   std::vector<QMCHamiltonian::FullPrecRealType> LocalEnergyVector, KineticEnergyVector, AuxEnergyVector;
417 #endif
418 
419 private:
420   ///starting index
421   int myIndex;
422   ///starting index
423   int numCollectables;
424   ///Current Local Energy
425   FullPrecRealType LocalEnergy;
426   ///Current Kinetic Energy
427   FullPrecRealType KineticEnergy;
428   ///Current Local Energy for the proposed move
429   FullPrecRealType NewLocalEnergy;
430   ///getName is in the way
431   const std::string myName;
432   ///vector of Hamiltonians
433   std::vector<OperatorBase*> H;
434   ///pointer to NonLocalECP
435   NonLocalECPotential* nlpp_ptr;
436   ///pointer to L2Potential
437   L2Potential* l2_ptr;
438   ///vector of Hamiltonians
439   std::vector<OperatorBase*> auxH;
440   /// Total timer for H evaluation
441   NewTimer& ham_timer_;
442   /// timers for H components
443   TimerList_t my_timers_;
444   ///types of component operators
445   std::map<std::string, std::string> operator_types;
446   ///data
447   PropertySetType Observables;
448   /** reset Observables and counters
449    * @param start starting index within PropertyList
450    * @param ncollects number of collectables
451    */
452   void resetObservables(int start, int ncollects);
453 
454   // helper function for extracting a list of Hamiltonian components from a list of QMCHamiltonian::H.
455   static RefVectorWithLeader<OperatorBase> extract_HC_list(const RefVectorWithLeader<QMCHamiltonian>& ham_list, int id);
456 
457 #if !defined(REMOVE_TRACEMANAGER)
458   ///traces variables
459   TraceRequest request;
460   bool streaming_position;
461   Array<TraceInt, 1>* id_sample;
462   Array<TraceInt, 1>* pid_sample;
463   Array<TraceInt, 1>* step_sample;
464   Array<TraceInt, 1>* gen_sample;
465   Array<TraceInt, 1>* age_sample;
466   Array<TraceInt, 1>* mult_sample;
467   Array<TraceReal, 1>* weight_sample;
468   Array<TraceReal, 2>* position_sample;
469 #endif
470 };
471 } // namespace qmcplusplus
472 #endif
473