1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
8 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
9 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 /**@file OperatorBase.cpp
17  *@brief Definition of OperatorBase
18  */
19 #include "Message/Communicate.h"
20 #include "OperatorBase.h"
21 #include "QMCHamiltonians/QMCHamiltonian.h"
22 
23 namespace qmcplusplus
24 {
OperatorBase()25 OperatorBase::OperatorBase() : myIndex(-1), Dependants(0), Value(0.0), tWalker(0)
26 {
27   quantum_domain = no_quantum_domain;
28   energy_domain  = no_energy_domain;
29 
30 #if !defined(REMOVE_TRACEMANAGER)
31   streaming_scalars    = false;
32   streaming_particles  = false;
33   have_required_traces = false;
34 #endif
35   UpdateMode.set(PRIMARY, 1);
36 }
37 
38 /** The correct behavior of this routine requires estimators with non-deterministic components
39  * in their evaluate() function to override this function.
40  */
evaluateDeterministic(ParticleSet & P)41 OperatorBase::Return_t OperatorBase::evaluateDeterministic(ParticleSet& P) { return evaluate(P); }
42 /** Take o_list and p_list update evaluation result variables in o_list?
43  *
44  * really should reduce vector of local_energies. matching the ordering and size of o list
45  * the this can be call for 1 or more QMCHamiltonians
46  */
mw_evaluate(const RefVectorWithLeader<OperatorBase> & O_list,const RefVectorWithLeader<ParticleSet> & P_list) const47 void OperatorBase::mw_evaluate(const RefVectorWithLeader<OperatorBase>& O_list,
48                                const RefVectorWithLeader<ParticleSet>& P_list) const
49 {
50   assert(this == &O_list.getLeader());
51 /**  Temporary raw omp pragma for simple thread parallelism
52    *   ignoring the driver level concurrency
53    *
54    *  \todo replace this with a proper abstraction. It should adequately describe the behavior
55    *  and strictly limit the activation of this level concurrency to when it is intended.
56    *  It is unlikely to belong in this function.
57    *
58    *  This implicitly depends on openmp work division logic. Essentially adhoc runtime
59    *  crowds over which we have given up control of thread/global scope.
60    *  How many walkers per thread? How to handle their data movement if any of these
61    *  hamiltonians should be accelerated? We can neither reason about or describe it in C++
62    *
63    *  As I understand it it should only be required for as long as the AMD openmp offload
64    *  compliler is incapable of running multiple threads. They should/must fix their compiler
65    *  before delivery of frontier and it should be removed at that point at latest
66    *
67    *  If you want 16 threads of 1 walker that should be 16 crowds of 1
68    *  not one crowd of 16 with openmp thrown in at hamiltonian level.
69    *  If this must be different from the other crowd batching. Make this a reasoned about
70    *  and controlled level of concurency blocking at the driver level.
71    *
72    *  This is only thread safe only if each walker has a complete
73    *  set of anything involved in an Operator.evaluate.
74    */
75 #pragma omp parallel for
76   for (int iw = 0; iw < O_list.size(); iw++)
77     O_list[iw].evaluate(P_list[iw]);
78 }
79 
mw_evaluateWithParameterDerivatives(const RefVectorWithLeader<OperatorBase> & O_list,const RefVectorWithLeader<ParticleSet> & P_list,const opt_variables_type & optvars,RecordArray<ValueType> & dlogpsi,RecordArray<ValueType> & dhpsioverpsi) const80 void OperatorBase::mw_evaluateWithParameterDerivatives(const RefVectorWithLeader<OperatorBase>& O_list,
81                                                        const RefVectorWithLeader<ParticleSet>& P_list,
82                                                        const opt_variables_type& optvars,
83                                                        RecordArray<ValueType>& dlogpsi,
84                                                        RecordArray<ValueType>& dhpsioverpsi) const
85 {
86   const int nparam = dlogpsi.nparam();
87   std::vector<ValueType> tmp_dlogpsi(nparam);
88   std::vector<ValueType> tmp_dhpsioverpsi(nparam);
89   for (int iw = 0; iw < O_list.size(); iw++)
90   {
91     for (int j = 0; j < nparam; j++)
92     {
93       tmp_dlogpsi[j] = dlogpsi.getValue(j, iw);
94     }
95 
96     O_list[iw].evaluateValueAndDerivatives(P_list[iw], optvars, tmp_dlogpsi, tmp_dhpsioverpsi);
97 
98     for (int j = 0; j < nparam; j++)
99     {
100       dhpsioverpsi.setValue(j, iw, dhpsioverpsi.getValue(j, iw) + tmp_dhpsioverpsi[j]);
101     }
102   }
103 }
104 
105 
set_energy_domain(energy_domains edomain)106 void OperatorBase::set_energy_domain(energy_domains edomain)
107 {
108   if (energy_domain_valid(edomain))
109     energy_domain = edomain;
110   else
111     APP_ABORT("QMCHamiltonainBase::set_energy_domain\n  input energy domain is invalid");
112 }
113 
set_quantum_domain(quantum_domains qdomain)114 void OperatorBase::set_quantum_domain(quantum_domains qdomain)
115 {
116   if (quantum_domain_valid(qdomain))
117     quantum_domain = qdomain;
118   else
119     APP_ABORT("QMCHamiltonainBase::set_quantum_domain\n  input quantum domain is invalid");
120 }
121 
one_body_quantum_domain(const ParticleSet & P)122 void OperatorBase::one_body_quantum_domain(const ParticleSet& P)
123 {
124   if (P.is_classical())
125     quantum_domain = classical;
126   else if (P.is_quantum())
127     quantum_domain = quantum;
128   else
129     APP_ABORT("OperatorBase::one_body_quantum_domain\n  quantum domain of input particles is invalid");
130 }
131 
two_body_quantum_domain(const ParticleSet & P)132 void OperatorBase::two_body_quantum_domain(const ParticleSet& P)
133 {
134   if (P.is_classical())
135     quantum_domain = classical_classical;
136   else if (P.is_quantum())
137     quantum_domain = quantum_quantum;
138   else
139     APP_ABORT("OperatorBase::two_body_quantum_domain(P)\n  quantum domain of input particles is invalid");
140 }
141 
two_body_quantum_domain(const ParticleSet & P1,const ParticleSet & P2)142 void OperatorBase::two_body_quantum_domain(const ParticleSet& P1, const ParticleSet& P2)
143 {
144   bool c1 = P1.is_classical();
145   bool c2 = P2.is_classical();
146   bool q1 = P1.is_quantum();
147   bool q2 = P2.is_quantum();
148   if (c1 && c2)
149     quantum_domain = classical_classical;
150   else if ((q1 && c2) || (c1 && q2))
151     quantum_domain = quantum_classical;
152   else if (q1 && q2)
153     quantum_domain = quantum_quantum;
154   else
155     APP_ABORT("OperatorBase::two_body_quantum_domain(P1,P2)\n  quantum domain of input particles is invalid");
156 }
157 
quantum_domain_valid(quantum_domains qdomain)158 bool OperatorBase::quantum_domain_valid(quantum_domains qdomain) { return qdomain != no_quantum_domain; }
159 
add2Hamiltonian(ParticleSet & qp,TrialWaveFunction & psi,QMCHamiltonian & targetH)160 void OperatorBase::add2Hamiltonian(ParticleSet& qp, TrialWaveFunction& psi, QMCHamiltonian& targetH)
161 {
162   OperatorBase* myclone = makeClone(qp, psi);
163   if (myclone)
164     targetH.addOperator(myclone, myName, UpdateMode[PHYSICAL]);
165 }
166 
registerObservables(std::vector<observable_helper * > & h5desc,hid_t gid) const167 void OperatorBase::registerObservables(std::vector<observable_helper*>& h5desc, hid_t gid) const
168 {
169   bool collect = UpdateMode.test(COLLECTABLE);
170   //exclude collectables
171   if (!collect)
172   {
173     int loc = h5desc.size();
174     h5desc.push_back(new observable_helper(myName));
175     std::vector<int> onedim(1, 1);
176     h5desc[loc]->set_dimensions(onedim, myIndex);
177     h5desc[loc]->open(gid);
178   }
179 }
180 
addEnergy(MCWalkerConfiguration & W,std::vector<RealType> & LocalEnergy)181 void OperatorBase::addEnergy(MCWalkerConfiguration& W, std::vector<RealType>& LocalEnergy)
182 {
183   APP_ABORT("Need specialization for " + myName +
184             "::addEnergy(MCWalkerConfiguration &W).\n Required functionality not implemented\n");
185 }
186 
187 } // namespace qmcplusplus
188