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