Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pathak-Wagner Regularizer to ACForce #4477

Merged
merged 19 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/hamiltonianobservable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,8 @@ Both of these methods are accessible with appropraite flags.
+--------------------------------+--------------+-----------------+-------------+--------------------------------------------------------------+
| ``name``:math:`^o` | text | *Anything* | ForceBase | Unique name for this estimator |
+--------------------------------+--------------+-----------------+-------------+--------------------------------------------------------------+
| ``epsilon``:math:`^o` | real | :math:`>=0 | 0 | Epsilon parameter for Pathak-Wagner regularizer. |
+--------------------------------+--------------+-----------------+-------------+--------------------------------------------------------------+
| ``spacewarp``:math:`^o` | text | yes/no | no | Add space-warp variance reduction terms |
+--------------------------------+--------------+-----------------+-------------+--------------------------------------------------------------+
| ``fast_derivatives``:math:`^o` | text | yes/no | no | Use Filippi fast derivative algorithm |
Expand Down
69 changes: 59 additions & 10 deletions src/QMCHamiltonians/ACForce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
#include "ACForce.h"
#include "OhmmsData/AttributeSet.h"
#include "ParticleBase/ParticleAttribOps.h"

namespace qmcplusplus
{
Expand All @@ -27,7 +28,9 @@ ACForce::ACForce(ParticleSet& source, ParticleSet& target, TrialWaveFunction& ps
first_force_index_(-1),
useSpaceWarp_(false),
fastDerivatives_(false),
swt_(target, source)
swt_(target, source),
reg_epsilon_(0.0),
f_epsilon_(1.0)
{
setName("ACForce");

Expand All @@ -52,6 +55,8 @@ std::unique_ptr<OperatorBase> ACForce::makeClone(ParticleSet& qp, TrialWaveFunct
myclone->fastDerivatives_ = fastDerivatives_;
myclone->useSpaceWarp_ = useSpaceWarp_;
myclone->first_force_index_ = first_force_index_;
myclone->reg_epsilon_ = reg_epsilon_;
myclone->delta_ = delta_;
return myclone;
}

Expand All @@ -63,9 +68,11 @@ bool ACForce::put(xmlNodePtr cur)
attr.add(useSpaceWarp_, "spacewarp", {false}); //"yes" or "no"
attr.add(swpow, "swpow"); //Real number"
attr.add(delta_, "delta"); //Real number"
attr.add(reg_epsilon_, "epsilon");
attr.add(fastDerivatives_, "fast_derivatives", {false});
attr.put(cur);

if (reg_epsilon_ < 0)
throw std::runtime_error("ACForce::put(): epsilon<0 not allowed.");
if (fastDerivatives_)
app_log() << "ACForce is using the fast force algorithm\n";
else
Expand Down Expand Up @@ -98,6 +105,8 @@ ACForce::Return_t ACForce::evaluate(ParticleSet& P)
wf_grad_ = 0;
sw_pulay_ = 0;
sw_grad_ = 0;


//This function returns d/dR of the sum of all observables in the physical hamiltonian.
//Note that the sign will be flipped based on definition of force = -d/dR.
if (fastDerivatives_)
Expand All @@ -114,6 +123,14 @@ ACForce::Return_t ACForce::evaluate(ParticleSet& P)
ham_.evaluateElecGrad(P, psi_, el_grad, delta_);
swt_.computeSWT(P, ions_, el_grad, P.G, sw_pulay_, sw_grad_);
}

//Now we compute the regularizer.
//WE ASSUME THAT psi_.evaluateLog(P) HAS ALREADY BEEN CALLED AND Grad(logPsi)
//IS ALREADY UP TO DATE FOR THIS CONFIGURATION.

f_epsilon_ = compute_regularizer_f(psi_.G, reg_epsilon_);


return 0.0;
};

Expand Down Expand Up @@ -154,10 +171,10 @@ void ACForce::setObservables(PropertySetType& plist)
{
//Flipping the sign, since these terms currently store d/dR values.
// add the minus one to be a force.
plist[myindex++] = -hf_force_[iat][iondim];
plist[myindex++] = -(pulay_force_[iat][iondim] + sw_pulay_[iat][iondim]);
plist[myindex++] = -value_ * (wf_grad_[iat][iondim] + sw_grad_[iat][iondim]);
plist[myindex++] = -(wf_grad_[iat][iondim] + sw_grad_[iat][iondim]);
plist[myindex++] = -hf_force_[iat][iondim] * f_epsilon_;
plist[myindex++] = -(pulay_force_[iat][iondim] + sw_pulay_[iat][iondim]) * f_epsilon_;
plist[myindex++] = -value_ * (wf_grad_[iat][iondim] + sw_grad_[iat][iondim]) * f_epsilon_;
plist[myindex++] = -(wf_grad_[iat][iondim] + sw_grad_[iat][iondim]) * f_epsilon_;
}
}
};
Expand All @@ -168,12 +185,44 @@ void ACForce::setParticlePropertyList(PropertySetType& plist, int offset)
{
for (int iondim = 0; iondim < OHMMS_DIM; iondim++)
{
plist[myindex++] = -hf_force_[iat][iondim];
plist[myindex++] = -(pulay_force_[iat][iondim] + sw_pulay_[iat][iondim]);
plist[myindex++] = -value_ * (wf_grad_[iat][iondim] + sw_grad_[iat][iondim]);
plist[myindex++] = -(wf_grad_[iat][iondim] + sw_grad_[iat][iondim]);
plist[myindex++] = -hf_force_[iat][iondim] * f_epsilon_;
plist[myindex++] = -(pulay_force_[iat][iondim] + sw_pulay_[iat][iondim]) * f_epsilon_;
plist[myindex++] = -value_ * (wf_grad_[iat][iondim] + sw_grad_[iat][iondim]) * f_epsilon_;
plist[myindex++] = -(wf_grad_[iat][iondim] + sw_grad_[iat][iondim]) * f_epsilon_;
}
}
};

ACForce::RealType ACForce::compute_regularizer_f(const ParticleSet::ParticleGradient& G, const RealType epsilon)
{
//epsilon=0 corresponds to no regularization. However, since
//epsilon ends up in denominators, return 1 here.
if (std::abs(epsilon) < 1e-6)
return 1.0;

RealType gdotg = 0.0;
#if defined(QMC_COMPLEX)
gdotg = Dot_CC(G, G);
#else
gdotg = Dot(G, G);
#endif

RealType gmag = std::sqrt(gdotg);
RealType x;

RealType regvalue = 0.0;
//x = grad(logpsi)/|grad(logpsi)|^2 = 1/|grad(logpsi)|.
//
//Argument of polynomial is x/epsilon=1/(epsilon*|grad(logpsi)|)
double xovereps = 1.0 / (epsilon * gmag);
if (xovereps >= 1.0)
regvalue = 1.0;
else
{
//There's a discrepancy between AIP Advances 10, 085213 (2020) and arXiv:2002.01434 for polynomial.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting

//We choose the arXiv, because f(x=1)=1, as opposed to f(x=1)=-4.
regvalue = 7.0 * std::pow(xovereps, 6.0) - 15.0 * std::pow(xovereps, 4.0) + 9.0 * std::pow(xovereps, 2.0);
}
return regvalue;
};
} // namespace qmcplusplus
29 changes: 22 additions & 7 deletions src/QMCHamiltonians/ACForce.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ namespace qmcplusplus
class ACForce : public OperatorBase
{
public:
using Forces = ParticleSet::ParticlePos;

using Forces = ParticleSet::ParticlePos;
using ParticleGradient = ParticleSet::ParticleGradient;
/** Constructor **/
ACForce(ParticleSet& source, ParticleSet& target, TrialWaveFunction& psi, QMCHamiltonian& H);

Expand Down Expand Up @@ -62,6 +62,14 @@ class ACForce : public OperatorBase
* isn't sufficient. We override it here. **/
void add2Hamiltonian(ParticleSet& qp, TrialWaveFunction& psi, QMCHamiltonian& targetH) final;

/** Computes multiplicative regularizer f(G,epsilon) according to Pathak-Wagner arXiv:2002.01434 .
* G estimates proximity to node, and f(G,epsilon) in that paper is used to scale all values.
* \param[in] G, nabla_i ln(Psi), so vector of all electron gradients.
* \param[in] epsilon, regularizer parameter.
* \return Value of regularizer f(G,epsilon).
*/
static RealType compute_regularizer_f(const ParticleGradient& G, const RealType epsilon);

/** Evaluate **/
Return_t evaluate(ParticleSet& P) final;

Expand All @@ -80,19 +88,26 @@ class ACForce : public OperatorBase
///For indexing observables
IndexType first_force_index_;

///Algorithm/feature switches
bool useSpaceWarp_;
bool fastDerivatives_;

///The space warp transformation class.
SpaceWarpTransformation swt_;

//Pathak-Wagner regularizer parameters.
RealType reg_epsilon_;
RealType f_epsilon_;

///Temporary Nion x 3 dimensional arrays for force storage.
Forces hf_force_;
Forces pulay_force_;
Forces wf_grad_;
Forces sw_pulay_;
Forces sw_grad_;

bool useSpaceWarp_;
bool fastDerivatives_;


TWFFastDerivWrapper psi_wrapper_;
///The space warp transformation class.
SpaceWarpTransformation swt_;
};

} // namespace qmcplusplus
Expand Down
17 changes: 17 additions & 0 deletions src/QMCHamiltonians/tests/test_force.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ TEST_CASE("Ion-ion Force", "[hamiltonian]")

TEST_CASE("AC Force", "[hamiltonian]")
{
using Real = QMCTraits::RealType;
const SimulationCell simulation_cell;
ParticleSet ions(simulation_cell);
ParticleSet elec(simulation_cell);
Expand Down Expand Up @@ -483,6 +484,22 @@ TEST_CASE("AC Force", "[hamiltonian]")
</tmp>
)";

ParticleSet::ParticleGradient g(elec.getTotalNum());
//Let magnitude be 1
g[0][0] = std::sqrt(1.0 / 2.0);
g[1][2] = std::sqrt(1.0 / 2.0);

//Epsilon = 2 places this within the regularizer threshold of x < 1.
Real regval = ACForce::compute_regularizer_f(g, 2);
CHECK(regval == Approx(1.421875));
//Epsilon = 0.001 places this way outside of regularizer threshold.
//Should return 1.
regval = ACForce::compute_regularizer_f(g, 0.001);
CHECK(regval == Approx(1.0));
//Epsilon = 0.0 indicates the regularizer is not used. Return 1.
regval = ACForce::compute_regularizer_f(g, 0.0);
CHECK(regval == Approx(1.0));

Libxml2Document olddoc;
Libxml2Document newdoc;
bool oldokay = olddoc.parseFromString(acforceXMLold);
Expand Down