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) 2019 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Raymond Clay, Sandia National Laboratories
8 //
9 // File created by: Raymond Clay, rclay@sandia.gov, Sandia National Laboratories
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 /**@file ACForce.cpp
14  *@brief Implementation of ACForce, Assaraf-Caffarel ZVZB style force estimation.
15  */
16 #include "ACForce.h"
17 #include <sstream>
18 #include "OhmmsData/AttributeSet.h"
19 
20 namespace qmcplusplus
21 {
ACForce(ParticleSet & source,ParticleSet & target,TrialWaveFunction & psi_in,QMCHamiltonian & H)22 ACForce::ACForce(ParticleSet& source, ParticleSet& target, TrialWaveFunction& psi_in, QMCHamiltonian& H)
23     : ions(source),
24       elns(target),
25       psi(psi_in),
26       ham(H),
27       FirstForceIndex(-1),
28       Nions(ions.getTotalNum()),
29       useSpaceWarp(false),
30       swt(target, source)
31 {
32   prefix = "ACForce";
33   myName = prefix;
34 
35   hf_force.resize(Nions);
36   pulay_force.resize(Nions);
37   wf_grad.resize(Nions);
38   sw_pulay.resize(Nions);
39   sw_grad.resize(Nions);
40   delta = 1e-4;
41 };
42 
makeClone(ParticleSet & qp,TrialWaveFunction & psi)43 OperatorBase* ACForce::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
44 {
45   APP_ABORT("ACForce::makeClone(ParticleSet&,TrialWaveFunction&) shouldn't be called");
46   return nullptr;
47 }
48 
makeClone(ParticleSet & qp,TrialWaveFunction & psi_in,QMCHamiltonian & ham_in)49 OperatorBase* ACForce::makeClone(ParticleSet& qp, TrialWaveFunction& psi_in, QMCHamiltonian& ham_in)
50 {
51   OperatorBase* myclone = new ACForce(ions, qp, psi_in, ham_in);
52   return myclone;
53 }
54 
put(xmlNodePtr cur)55 bool ACForce::put(xmlNodePtr cur)
56 {
57   std::string useSpaceWarpString("no");
58   std::string ionionforce("yes");
59   RealType swpow(4);
60   OhmmsAttributeSet attr;
61   attr.add(useSpaceWarpString, "spacewarp"); //"yes" or "no"
62   attr.add(swpow, "swpow");                  //Real number"
63   attr.add(delta, "delta");                  //Real number"
64   attr.put(cur);
65 
66   useSpaceWarp = (useSpaceWarpString == "yes") || (useSpaceWarpString == "true");
67   swt.setPow(swpow);
68 
69   if (useSpaceWarp)
70     app_log() << "ACForce is using space warp with power=" << swpow << std::endl;
71   else
72     app_log() << "ACForce is not using space warp\n";
73 
74   return true;
75 }
76 
add2Hamiltonian(ParticleSet & qp,TrialWaveFunction & psi,QMCHamiltonian & ham_in)77 void ACForce::add2Hamiltonian(ParticleSet& qp, TrialWaveFunction& psi, QMCHamiltonian& ham_in)
78 {
79   //The following line is modified
80   OperatorBase* myclone = makeClone(qp, psi, ham_in);
81   if (myclone)
82     ham_in.addOperator(myclone, myName, UpdateMode[PHYSICAL]);
83 }
evaluate(ParticleSet & P)84 ACForce::Return_t ACForce::evaluate(ParticleSet& P)
85 {
86   hf_force    = 0;
87   pulay_force = 0;
88   wf_grad     = 0;
89   sw_pulay    = 0;
90   sw_grad     = 0;
91   //This function returns d/dR of the sum of all observables in the physical hamiltonian.
92   //Note that the sign will be flipped based on definition of force = -d/dR.
93   Value = ham.evaluateIonDerivs(P, ions, psi, hf_force, pulay_force, wf_grad);
94 
95   if (useSpaceWarp)
96   {
97     Force_t el_grad;
98     el_grad.resize(P.getTotalNum());
99     el_grad = 0;
100 
101     ham.evaluateElecGrad(P, psi, el_grad, delta);
102     swt.computeSWT(P, ions, el_grad, P.G, sw_pulay, sw_grad);
103   }
104   return 0.0;
105 };
106 
addObservables(PropertySetType & plist,BufferType & collectables)107 void ACForce::addObservables(PropertySetType& plist, BufferType& collectables)
108 {
109   if (FirstForceIndex < 0)
110     FirstForceIndex = plist.size();
111   for (int iat = 0; iat < Nions; iat++)
112   {
113     for (int x = 0; x < OHMMS_DIM; x++)
114     {
115       std::ostringstream hfname;
116       std::ostringstream pulayname;
117       std::ostringstream wfgradname1;
118       std::ostringstream wfgradname2;
119       hfname << prefix << "_hf_" << iat << "_" << x;
120       pulayname << prefix << "_pulay_" << iat << "_" << x;
121       wfgradname1 << prefix << "_Ewfgrad_" << iat << "_" << x;
122       wfgradname2 << prefix << "_wfgrad_" << iat << "_" << x;
123 
124       plist.add(hfname.str());
125       plist.add(pulayname.str());
126       plist.add(wfgradname1.str());
127       plist.add(wfgradname2.str());
128 
129       //TODO: Remove when ACForce is production ready.
130       //      if(useSpaceWarp)
131       //      {
132       //        std::ostringstream swctname1;
133       //        std::ostringstream swctname2;
134       //        std::ostringstream swctname3;
135       //        swctname1 << prefix << "_swct1_" << iat << "_" << x;
136       //        swctname2 << prefix << "_swct2_" << iat << "_" << x;
137       //        swctname3 << prefix << "_swct3_" << iat << "_" << x;
138       //        plist.add(swctname1.str());
139       //        plist.add(swctname2.str());
140       //        plist.add(swctname3.str());
141       //      }
142     }
143   }
144 };
setObservables(PropertySetType & plist)145 void ACForce::setObservables(PropertySetType& plist)
146 {
147   int myindex = FirstForceIndex;
148   for (int iat = 0; iat < Nions; iat++)
149   {
150     for (int iondim = 0; iondim < OHMMS_DIM; iondim++)
151     {
152       //Flipping the sign, since these terms currently store d/dR values.
153       // add the minus one to be a force.
154       plist[myindex++] = -hf_force[iat][iondim];
155       plist[myindex++] = -(pulay_force[iat][iondim] + sw_pulay[iat][iondim]);
156       plist[myindex++] = -Value * (wf_grad[iat][iondim] + sw_grad[iat][iondim]);
157       plist[myindex++] = -(wf_grad[iat][iondim] + sw_grad[iat][iondim]);
158 
159       //TODO: Remove when ACForce is production ready
160       //      if(useSpaceWarp)
161       //      {
162       //        plist[myindex++] = -sw_pulay[iat][iondim];
163       //        plist[myindex++] = -Value*sw_grad[iat][iondim];
164       //        plist[myindex++] = -sw_grad[iat][iondim];
165       //      }
166     }
167   }
168 };
setParticlePropertyList(PropertySetType & plist,int offset)169 void ACForce::setParticlePropertyList(PropertySetType& plist, int offset)
170 {
171   int myindex = FirstForceIndex + offset;
172   for (int iat = 0; iat < Nions; iat++)
173   {
174     for (int iondim = 0; iondim < OHMMS_DIM; iondim++)
175     {
176       plist[myindex++] = -hf_force[iat][iondim];
177       plist[myindex++] = -(pulay_force[iat][iondim] + sw_pulay[iat][iondim]);
178       plist[myindex++] = -Value * (wf_grad[iat][iondim] + sw_grad[iat][iondim]);
179       plist[myindex++] = -(wf_grad[iat][iondim] + sw_grad[iat][iondim]);
180       //TODO: Remove when ACForce is production ready
181       //      if(useSpaceWarp)
182       //      {
183       //        plist[myindex++] = -sw_pulay[iat][iondim];
184       //        plist[myindex++] = -Value*sw_grad[iat][iondim];
185       //        plist[myindex++] = -sw_grad[iat][iondim];
186       //      }
187     }
188   }
189 };
190 
191 } // namespace qmcplusplus
192