QMCPACK
DriftOperators.h
Go to the documentation of this file.
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 // Raymond Clay III, j.k.rofling@gmail.com, Lawrence Livermore 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 #ifndef QMCPLUSPLUS_QMCDRIFTOPERATORS_H
17 #define QMCPLUSPLUS_QMCDRIFTOPERATORS_H
21 namespace qmcplusplus
22 {
23 template<class T, class TG, unsigned D>
24 inline T getDriftScale(T tau, const ParticleAttrib<TinyVector<TG, D>>& ga)
25 {
26  T vsq = Dot(ga, ga);
27  return (vsq < std::numeric_limits<T>::epsilon()) ? tau : ((-1.0 + std::sqrt(1.0 + 2.0 * tau * vsq)) / vsq);
28 }
29 
30 /** evaluate a drift with a real force
31  * @param tau timestep
32  * @param qf quantum force
33  * @param drift
34  */
35 template<class Tt, class TG, class T, unsigned D>
36 inline void getScaledDrift(Tt tau, const TinyVector<TG, D>& qf, TinyVector<T, D>& drift)
37 {
38  //We convert the complex gradient to real and temporarily store in drift.
39  convertToReal(qf, drift);
40  T vsq = dot(drift, drift);
41  T sc = (vsq < std::numeric_limits<T>::epsilon()) ? tau : ((-1.0 + std::sqrt(1.0 + 2.0 * tau * vsq)) / vsq);
42  //Apply the umrigar scaled drift.
43  drift *= sc;
44 }
45 
46 /** evaluate a drift with a real force with rescaling for an L2 potential
47  * @param tau timestep
48  * @param qf quantum force
49  * @param drift
50  */
51 template<class Tt, class TG, class T, unsigned D>
52 inline void getScaledDriftL2(Tt tau, const TinyVector<TG, D>& qf, const Tensor<T, D>& Dmat, TinyVector<T, D>& Kvec, TinyVector<T, D>& drift)
53 {
54  //We convert the complex gradient to real and temporarily store in drift.
55  convertToReal(qf, drift);
56  //modify the bare drift in the presence of L2 potentials
57  drift = dot(Dmat, drift) - Kvec;
58  T vsq = dot(drift, drift);
59  T sc = (vsq < std::numeric_limits<T>::epsilon()) ? tau : ((-1.0 + std::sqrt(1.0 + 2.0 * tau * vsq)) / vsq);
60  //Apply the umrigar scaled drift.
61  drift *= sc;
62 }
63 
64 /** evaluate a drift with a real force and no rescaling
65  * @param tau timestep
66  * @param qf quantum force
67  * @param drift
68  */
69 template<class Tt, class TG, class T, unsigned D>
70 inline void getUnscaledDrift(Tt tau, const TinyVector<TG, D>& qf, TinyVector<T, D>& drift)
71 {
72  //We convert the complex gradient to real and temporarily store in drift.
73  convertToReal(qf, drift);
74  drift *= tau;
75 }
76 
77 /** scale drift
78  * @param tau_au timestep au
79  * @param qf quantum forces
80  * @param drift scaled quantum forces
81  * @param return correction term
82  *
83  * Assume, mass=1
84  */
85 template<class T, class T1, unsigned D>
89 {
90  T norm = 0.0, norm_scaled = 0.0, tau2 = tau * tau;
91  for (int iat = 0; iat < qf.size(); ++iat)
92  {
93  convertToReal(qf[iat], drift[iat]);
94  T vsq = dot(drift[iat], drift[iat]);
95  T sc = (vsq < std::numeric_limits<T>::epsilon()) ? tau : ((-1.0 + std::sqrt(1.0 + 2.0 * tau * vsq)) / vsq);
96  norm_scaled += vsq * sc * sc;
97  norm += vsq * tau2;
98  drift[iat] *= sc;
99  }
100  return std::sqrt(norm_scaled / norm);
101 }
102 
103 /** scale drift
104  * @param tau_au timestep au
105  * @param massinv 1/m per particle
106  * @param qf quantum forces, i.e. grad_psi_over_psi
107  * @param drift scaled importance-sampling drift
108  * @param return correction term
109  *
110  * Fill the drift vector one particle at a time (pbyp).
111  *
112  * The naive drift is tau/mass*|grad_psi_over_psi|,
113  * grad_psi_over_psi the log derivative of the guiding wavefunction;
114  * tau is timestep; mass is particle mass
115  * The naive drift diverges at a node and is large near a nucleus.
116  * Both cases may cause persistent configurations, because the
117  * reverse proposal probability is virtually zero.
118  *
119  * The norm of the drift vector should be limited in two ways:
120  * 1. Umrigar: suppress drift divergence with a sclaing factor
121  * 2. Ceperley: limit max drift rate to diffusion rate -> set Umrigar "a" parameter
122  * The choice of drift vector does not affect VMC correctness
123  * so long as the proposal probabilities are correctly calculated.
124  * The choice of drift vector changes the DMC Green's function. BE CAREFUL!
125  *
126  * T should be either float or double
127  * T1 may be real (float or double) or complex<float or double>
128  * D should be the number of spatial dimensions (int)
129  */
130 template<class T, class T1, unsigned D>
132  const std::vector<T>& massinv,
135 {
136  // Umrigar eq. (34) "a" parameter is set to 1.0
137  T norm = 0.0, norm_scaled = 0.0; // variables to be accumulated
138  for (int iat = 0; iat < massinv.size(); ++iat)
139  {
140  // !!!! assume timestep is scaled by mass
141  T tau_over_mass = tau_au * massinv[iat];
142  // save real part of wf log derivative in drift
143  convertToReal(qf[iat], drift[iat]);
144  T vsq = dot(drift[iat], drift[iat]);
145  // calculate drift scalar "sc" of Umrigar, JCP 99, 2865 (1993); eq. (34) * tau
146  // use naive drift if vsq may cause numerical instability in the denominator
147  T sc = (vsq < std::numeric_limits<T>::epsilon()) ? tau_over_mass
148  : (-1.0 + std::sqrt(1.0 + 2.0 * tau_over_mass * vsq)) / vsq;
149  drift[iat] *= sc;
150 
151  norm_scaled += vsq * sc * sc;
152  norm += vsq * tau_over_mass * tau_over_mass;
153  }
154  return std::sqrt(norm_scaled / norm);
155 }
156 
157 //NOTE: While poorly named, setScaledDrift is the all-electron analogue of
158 // getScaledDrift.
159 
160 /** da = scaled(tau)*ga
161  * @param tau time step
162  * @param qf real quantum forces
163  * @param drift drift
164  */
165 template<class T, class TG, unsigned D>
167 {
168  T s = getDriftScale(tau, qf);
169  PAOps<T, D, TG>::scale(s, qf, drift);
170 }
171 
172 /** da = scaled(tau)*ga
173  * @param tau time step
174  * @param qf real quantum forces
175  * @param drift drift
176  */
177 template<class T, unsigned D>
178 inline void setScaledDrift(T tau, ParticleAttrib<TinyVector<T, D>>& drift)
179 {
180  T s = getDriftScale(tau, drift);
181  drift *= s;
182 }
183 
184 
185 /** da = scaled(tau)*ga
186  * @param tau time step
187  * @param qf complex quantum forces
188  * @param drift drift
189  */
190 template<class T, class TG, unsigned D>
191 inline void setScaledDrift(T tau,
192  const ParticleAttrib<TinyVector<std::complex<TG>, D>>& qf,
194 {
195  for (int iat = 0; iat < qf.size(); ++iat)
196  convertToReal(qf[iat], drift[iat]);
197 
198  T s = getDriftScale(tau, drift);
199  drift *= s;
200 }
201 
202 template<class T, class TG, unsigned D>
204 {
205  PAOps<T, D, TG>::scale(s, ga, da);
206 }
207 
208 template<class T, class TG, unsigned D>
209 inline void assignDrift(T s,
210  const ParticleAttrib<TinyVector<std::complex<TG>, D>>& ga,
212 {
213  //This operation does s*ga, and takes the real part.
214  PAOps<T, D, TG>::scale(s, ga, da);
215 }
216 
217 //Assign drift does pbyp calculation of the scaled drift on all drift components.
218 template<class T, class T1, unsigned D>
219 inline void assignDrift(T tau_au,
220  const std::vector<T>& massinv,
223 {
224  for (int iat = 0; iat < massinv.size(); ++iat)
225  {
226  T tau_over_mass = tau_au * massinv[iat];
227  // naive drift "tau/mass*qf" can diverge
228  getScaledDrift(tau_over_mass, qf[iat], drift[iat]);
229  }
230 }
231 
232 } // namespace qmcplusplus
233 #endif
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
void convertToReal(const T1 &in, T2 &out)
generic conversion from type T1 to type T2 using implicit conversion
Definition: ConvertToReal.h:32
void assignDrift(T s, const ParticleAttrib< TinyVector< TG, D >> &ga, ParticleAttrib< TinyVector< T, D >> &da)
Attaches a unit to a Vector for IO.
T Dot(const ParticleAttrib< TinyVector< T, D >> &pa, const ParticleAttrib< TinyVector< T, D >> &pb)
T getDriftScale(T tau, const ParticleAttrib< TinyVector< TG, D >> &ga)
T setScaledDriftPbyPandNodeCorr(T tau, const ParticleAttrib< TinyVector< T1, D >> &qf, ParticleAttrib< TinyVector< T, D >> &drift)
scale drift
double norm(const zVec &c)
Definition: VectorOps.h:118
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
void getScaledDriftL2(Tt tau, const TinyVector< TG, D > &qf, const Tensor< T, D > &Dmat, TinyVector< T, D > &Kvec, TinyVector< T, D > &drift)
evaluate a drift with a real force with rescaling for an L2 potential
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
Declaraton of ParticleAttrib<T>
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
void getScaledDrift(Tt tau, const TinyVector< TG, D > &qf, TinyVector< T, D > &drift)
evaluate a drift with a real force
void getUnscaledDrift(Tt tau, const TinyVector< TG, D > &qf, TinyVector< T, D > &drift)
evaluate a drift with a real force and no rescaling
void setScaledDrift(T tau, const ParticleAttrib< TinyVector< TG, D >> &qf, ParticleAttrib< TinyVector< T, D >> &drift)
da = scaled(tau)*ga