diff --git a/src/QMCHamiltonians/ACForce.cpp b/src/QMCHamiltonians/ACForce.cpp index e1a7bcae6f..b3dc1d8dd8 100644 --- a/src/QMCHamiltonians/ACForce.cpp +++ b/src/QMCHamiltonians/ACForce.cpp @@ -15,18 +15,29 @@ */ #include "ACForce.h" #include +#include "OhmmsData/AttributeSet.h" namespace qmcplusplus { ACForce::ACForce(ParticleSet& source, ParticleSet& target, TrialWaveFunction& psi_in, QMCHamiltonian& H) - : ions(source), elns(target), psi(psi_in), ham(H), FirstForceIndex(-1), Nions(0) + : ions(source), + elns(target), + psi(psi_in), + ham(H), + FirstForceIndex(-1), + Nions(ions.getTotalNum()), + useSpaceWarp(false), + swt(target, source) { prefix = "ACForce"; myName = prefix; - Nions = ions.getTotalNum(); + hf_force.resize(Nions); pulay_force.resize(Nions); wf_grad.resize(Nions); + sw_pulay.resize(Nions); + sw_grad.resize(Nions); + delta = 1e-4; }; OperatorBase* ACForce::makeClone(ParticleSet& qp, TrialWaveFunction& psi) @@ -37,9 +48,32 @@ OperatorBase* ACForce::makeClone(ParticleSet& qp, TrialWaveFunction& psi) OperatorBase* ACForce::makeClone(ParticleSet& qp, TrialWaveFunction& psi_in, QMCHamiltonian& ham_in) { - OperatorBase* myclone = new ACForce(qp, ions, psi_in, ham_in); + OperatorBase* myclone = new ACForce(ions, qp, psi_in, ham_in); return myclone; } + +bool ACForce::put(xmlNodePtr cur) +{ + std::string useSpaceWarpString("no"); + std::string ionionforce("yes"); + RealType swpow(4); + OhmmsAttributeSet attr; + attr.add(useSpaceWarpString, "spacewarp"); //"yes" or "no" + attr.add(swpow, "swpow"); //Real number" + attr.add(delta, "delta"); //Real number" + attr.put(cur); + + useSpaceWarp = (useSpaceWarpString == "yes") || (useSpaceWarpString == "true"); + swt.setPow(swpow); + + if (useSpaceWarp) + app_log() << "ACForce is using space warp with power=" << swpow << std::endl; + else + app_log() << "ACForce is not using space warp\n"; + + return true; +} + void ACForce::add2Hamiltonian(ParticleSet& qp, TrialWaveFunction& psi, QMCHamiltonian& ham_in) { //The following line is modified @@ -52,10 +86,21 @@ ACForce::Return_t ACForce::evaluate(ParticleSet& P) hf_force = 0; pulay_force = 0; 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. Value = ham.evaluateIonDerivs(P, ions, psi, hf_force, pulay_force, wf_grad); + + if (useSpaceWarp) + { + Force_t el_grad; + el_grad.resize(P.getTotalNum()); + el_grad = 0; + + ham.evaluateElecGrad(P, psi, el_grad, delta); + swt.computeSWT(P, ions, el_grad, P.G, sw_pulay, sw_grad); + } return 0.0; }; @@ -75,10 +120,25 @@ void ACForce::addObservables(PropertySetType& plist, BufferType& collectables) pulayname << prefix << "_pulay_" << iat << "_" << x; wfgradname1 << prefix << "_Ewfgrad_" << iat << "_" << x; wfgradname2 << prefix << "_wfgrad_" << iat << "_" << x; + plist.add(hfname.str()); plist.add(pulayname.str()); plist.add(wfgradname1.str()); plist.add(wfgradname2.str()); + + //TODO: Remove when ACForce is production ready. + // if(useSpaceWarp) + // { + // std::ostringstream swctname1; + // std::ostringstream swctname2; + // std::ostringstream swctname3; + // swctname1 << prefix << "_swct1_" << iat << "_" << x; + // swctname2 << prefix << "_swct2_" << iat << "_" << x; + // swctname3 << prefix << "_swct3_" << iat << "_" << x; + // plist.add(swctname1.str()); + // plist.add(swctname2.str()); + // plist.add(swctname3.str()); + // } } } }; @@ -92,9 +152,17 @@ 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]; - plist[myindex++] = -Value * wf_grad[iat][iondim]; - plist[myindex++] = -wf_grad[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]); + + //TODO: Remove when ACForce is production ready + // if(useSpaceWarp) + // { + // plist[myindex++] = -sw_pulay[iat][iondim]; + // plist[myindex++] = -Value*sw_grad[iat][iondim]; + // plist[myindex++] = -sw_grad[iat][iondim]; + // } } } }; @@ -106,9 +174,16 @@ 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]; - plist[myindex++] = -Value * wf_grad[iat][iondim]; - plist[myindex++] = -wf_grad[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]); + //TODO: Remove when ACForce is production ready + // if(useSpaceWarp) + // { + // plist[myindex++] = -sw_pulay[iat][iondim]; + // plist[myindex++] = -Value*sw_grad[iat][iondim]; + // plist[myindex++] = -sw_grad[iat][iondim]; + // } } } }; diff --git a/src/QMCHamiltonians/ACForce.h b/src/QMCHamiltonians/ACForce.h index 990bc7e2bd..27fbb787fe 100644 --- a/src/QMCHamiltonians/ACForce.h +++ b/src/QMCHamiltonians/ACForce.h @@ -19,6 +19,7 @@ #include "QMCHamiltonians/OperatorBase.h" #include "QMCWaveFunctions/TrialWaveFunction.h" #include "QMCHamiltonians/QMCHamiltonian.h" +#include "QMCHamiltonians/SpaceWarpTransformation.h" namespace qmcplusplus { @@ -33,7 +34,7 @@ struct ACForce : public OperatorBase //ACForce(const ACForce& ac) {}; /** I/O Routines */ - bool put(xmlNodePtr cur) { return true; }; + bool put(xmlNodePtr cur); bool get(std::ostream& os) const { return true; }; /** Cloning **/ @@ -54,6 +55,9 @@ struct ACForce : public OperatorBase /** Evaluate **/ Return_t evaluate(ParticleSet& P); + ///Finite difference timestep + RealType delta; + //** Internal variables **/ // I'm assuming that psi, ions, elns, and the hamiltonian are bound to this // instantiation. Making sure no crosstalk happens is the job of whatever clones this. @@ -62,14 +66,21 @@ struct ACForce : public OperatorBase TrialWaveFunction& psi; QMCHamiltonian& ham; - //For indexing observables + ///For indexing observables IndexType FirstForceIndex; - IndexType Nions; + const IndexType Nions; - //Temporary Nion x 3 dimensional arrays for force storage. + ///Temporary Nion x 3 dimensional arrays for force storage. Force_t hf_force; Force_t pulay_force; Force_t wf_grad; + Force_t sw_pulay; + Force_t sw_grad; + + bool useSpaceWarp; + + ///The space warp transformation class. + SpaceWarpTransformation swt; //Class info. std::string prefix; diff --git a/src/QMCHamiltonians/CMakeLists.txt b/src/QMCHamiltonians/CMakeLists.txt index c67775208f..c18c6f7367 100644 --- a/src/QMCHamiltonians/CMakeLists.txt +++ b/src/QMCHamiltonians/CMakeLists.txt @@ -42,6 +42,7 @@ SET(HAMSRCS SpinDensity.cpp SpeciesKineticEnergy.cpp LatticeDeviationEstimator.cpp + SpaceWarpTransformation.cpp ) IF(OHMMS_DIM MATCHES 3) diff --git a/src/QMCHamiltonians/CoulombPotentialFactory.cpp b/src/QMCHamiltonians/CoulombPotentialFactory.cpp index 9cf6b81fea..4d61412354 100644 --- a/src/QMCHamiltonians/CoulombPotentialFactory.cpp +++ b/src/QMCHamiltonians/CoulombPotentialFactory.cpp @@ -211,6 +211,7 @@ void HamiltonianFactory::addForceHam(xmlNodePtr cur) } TrialWaveFunction& psi = *psi_it->second->getTWF(); ACForce* acforce = new ACForce(*source, *target, psi, *targetH); + acforce->put(cur); targetH->addOperator(acforce, title, false); } else diff --git a/src/QMCHamiltonians/NonLocalECPotential.cpp b/src/QMCHamiltonians/NonLocalECPotential.cpp index 0102b83a03..fe75bf9d02 100644 --- a/src/QMCHamiltonians/NonLocalECPotential.cpp +++ b/src/QMCHamiltonians/NonLocalECPotential.cpp @@ -93,6 +93,12 @@ NonLocalECPotential::Return_t NonLocalECPotential::evaluate(ParticleSet& P) return Value; } +NonLocalECPotential::Return_t NonLocalECPotential::evaluateDeterministic(ParticleSet& P) +{ + evaluateImpl(P, false, true); + return Value; +} + void NonLocalECPotential::mw_evaluate(const RefVector& O_list, const RefVector& P_list) { mw_evaluateImpl(O_list, P_list, false); @@ -116,7 +122,7 @@ void NonLocalECPotential::mw_evaluateWithToperator(const RefVector mw_evaluateImpl(O_list, P_list, false); } -void NonLocalECPotential::evaluateImpl(ParticleSet& P, bool Tmove) +void NonLocalECPotential::evaluateImpl(ParticleSet& P, bool Tmove, bool keepGrid) { if (Tmove) nonLocalOps.reset(); @@ -133,7 +139,8 @@ void NonLocalECPotential::evaluateImpl(ParticleSet& P, bool Tmove) #endif for (int ipp = 0; ipp < PPset.size(); ipp++) if (PPset[ipp]) - PPset[ipp]->randomize_grid(*myRNG); + if (!keepGrid) + PPset[ipp]->randomize_grid(*myRNG); //loop over all the ions const auto& myTable = P.getDistTable(myTableIndex); // clear all the electron and ion neighbor lists diff --git a/src/QMCHamiltonians/NonLocalECPotential.h b/src/QMCHamiltonians/NonLocalECPotential.h index 0059cfba82..33f51608a6 100644 --- a/src/QMCHamiltonians/NonLocalECPotential.h +++ b/src/QMCHamiltonians/NonLocalECPotential.h @@ -43,7 +43,7 @@ class NonLocalECPotential : public OperatorBase, public ForceBase #endif Return_t evaluate(ParticleSet& P) override; - + Return_t evaluateDeterministic(ParticleSet& P) override; void mw_evaluate(const RefVector& O_list, const RefVector& P_list) override; Return_t evaluateWithToperator(ParticleSet& P) override; @@ -151,8 +151,9 @@ class NonLocalECPotential : public OperatorBase, public ForceBase /** the actual implementation, used by evaluate and evaluateWithToperator * @param P particle set * @param Tmove whether Txy for Tmove is updated + * @param keepGrid. If true, does not randomize the quadrature grid before evaluation. */ - void evaluateImpl(ParticleSet& P, bool Tmove); + void evaluateImpl(ParticleSet& P, bool Tmove, bool keepGrid = false); /** the actual implementation for batched walkers, used by mw_evaluate and mw_evaluateWithToperator * @param O_list the list of NonLocalECPotential in a walker batch diff --git a/src/QMCHamiltonians/OperatorBase.cpp b/src/QMCHamiltonians/OperatorBase.cpp index 2721a74dcd..2cf7ee0e74 100644 --- a/src/QMCHamiltonians/OperatorBase.cpp +++ b/src/QMCHamiltonians/OperatorBase.cpp @@ -35,6 +35,10 @@ OperatorBase::OperatorBase() : myIndex(-1), Dependants(0), Value(0.0), tWalker(0 UpdateMode.set(PRIMARY, 1); } +/** The correct behavior of this routine requires estimators with non-deterministic components + * in their evaluate() function to override this function. + */ +OperatorBase::Return_t OperatorBase::evaluateDeterministic(ParticleSet& P) { return evaluate(P); } /** Take o_list and p_list update evaluation result variables in o_list? * * really should reduce vector of local_energies. matching the ordering and size of o list diff --git a/src/QMCHamiltonians/OperatorBase.h b/src/QMCHamiltonians/OperatorBase.h index 1c42f3c9f7..ea7f8c4550 100644 --- a/src/QMCHamiltonians/OperatorBase.h +++ b/src/QMCHamiltonians/OperatorBase.h @@ -246,6 +246,11 @@ struct OperatorBase : public QMCTraits *@return the value of the Hamiltonian component */ virtual Return_t evaluate(ParticleSet& P) = 0; + /** Evaluate the local energy contribution of this component, deterministically based on current state. + *@param P input configuration containing N particles + *@return the value of the Hamiltonian component + */ + virtual Return_t evaluateDeterministic(ParticleSet& P); /** Evaluate the contribution of this component of multiple walkers */ virtual void mw_evaluate(const RefVector& O_list, const RefVector& P_list); diff --git a/src/QMCHamiltonians/QMCHamiltonian.cpp b/src/QMCHamiltonians/QMCHamiltonian.cpp index bc5d557bd3..d8caf547df 100644 --- a/src/QMCHamiltonians/QMCHamiltonian.cpp +++ b/src/QMCHamiltonians/QMCHamiltonian.cpp @@ -501,6 +501,29 @@ QMCHamiltonian::FullPrecRealType QMCHamiltonian::evaluate(ParticleSet& P) return LocalEnergy; } +QMCHamiltonian::FullPrecRealType QMCHamiltonian::evaluateDeterministic(ParticleSet& P) +{ + ScopedTimer local_timer(ham_timer_); + LocalEnergy = 0.0; + for (int i = 0; i < H.size(); ++i) + { + ScopedTimer h_timer(my_timers_[i]); + const auto LocalEnergyComponent = H[i]->evaluateDeterministic(P); + if (std::isnan(LocalEnergyComponent)) + APP_ABORT("QMCHamiltonian::evaluate component " + H[i]->myName + " returns NaN\n"); + LocalEnergy += LocalEnergyComponent; + H[i]->setObservables(Observables); +#if !defined(REMOVE_TRACEMANAGER) + H[i]->collect_scalar_traces(); +#endif + H[i]->setParticlePropertyList(P.PropertyList, myIndex); + } + KineticEnergy = H[0]->Value; + P.PropertyList[WP::LOCALENERGY] = LocalEnergy; + P.PropertyList[WP::LOCALPOTENTIAL] = LocalEnergy - KineticEnergy; + // auxHevaluate(P); + return LocalEnergy; +} void QMCHamiltonian::updateNonKinetic(OperatorBase& op, QMCHamiltonian& ham, ParticleSet& pset) { if (std::isnan(op.Value)) @@ -794,7 +817,43 @@ std::vector QMCHamiltonian::flex_evaluateWithT } return local_energies; } - +void QMCHamiltonian::evaluateElecGrad(ParticleSet& P, + TrialWaveFunction& psi, + ParticleSet::ParticlePos_t& Egrad, + RealType delta) +{ + int nelec = P.getTotalNum(); + RealType ep(0.0); + RealType em(0.0); + RealType e0(0.0); + for (int iel = 0; iel < nelec; iel++) + { + for (int dim = 0; dim < OHMMS_DIM; dim++) + { + RealType r0 = P.R[iel][dim]; + ep = 0; + em = 0; + //Plus + RealType rp = r0 + delta; + P.R[iel][dim] = rp; + P.update(); + psi.evaluateLog(P); + ep = evaluateDeterministic(P); + + //minus + RealType rm = r0 - delta; + P.R[iel][dim] = rm; + P.update(); + psi.evaluateLog(P); + em = evaluateDeterministic(P); + + Egrad[iel][dim] = (ep - em) / (2.0 * delta); + P.R[iel][dim] = r0; + P.update(); + psi.evaluateLog(P); + } + } +} QMCHamiltonian::FullPrecRealType QMCHamiltonian::evaluateIonDerivs(ParticleSet& P, ParticleSet& ions, TrialWaveFunction& psi, diff --git a/src/QMCHamiltonians/QMCHamiltonian.h b/src/QMCHamiltonians/QMCHamiltonian.h index 07eb40a93b..e1f5fe3cef 100644 --- a/src/QMCHamiltonians/QMCHamiltonian.h +++ b/src/QMCHamiltonians/QMCHamiltonian.h @@ -231,6 +231,12 @@ class QMCHamiltonian */ FullPrecRealType evaluate(ParticleSet& P); + /** evaluate Local Energy deterministically. Defaults to evaluate(P) for operators + * without a stochastic component. For the nonlocal PP, the quadrature grid is not rerandomized. + * @param P ParticleSet + * @return Local energy. + */ + FullPrecRealType evaluateDeterministic(ParticleSet& P); /** batched version of evaluate for LocalEnergy * * Encapsulation is ignored for H_list hamiltonians method uses its status as QMCHamiltonian to break encapsulation. @@ -282,6 +288,18 @@ class QMCHamiltonian RecordArray& dhpsioverpsi); + /** Evaluate the electron gradient of the local energy. + * @param psi Trial Wave Function + * @param P electron particle set + * @param EGrad an Nelec x 3 real array which corresponds to d/d[r_i]_j E_L + * @param A finite difference step size if applicable. Default is to use finite diff with delta=1e-5. + * @return EGrad. Function itself returns nothing. + */ + void evaluateElecGrad(ParticleSet& P, + TrialWaveFunction& psi, + ParticleSet::ParticlePos_t& EGrad, + RealType delta = 1e-5); + /** evaluate local energy and derivatives w.r.t ionic coordinates. * @param P target particle set (electrons) * @param ions source particle set (ions) diff --git a/src/QMCHamiltonians/SpaceWarpTransformation.cpp b/src/QMCHamiltonians/SpaceWarpTransformation.cpp new file mode 100644 index 0000000000..e064a7c107 --- /dev/null +++ b/src/QMCHamiltonians/SpaceWarpTransformation.cpp @@ -0,0 +1,98 @@ +#include "QMCHamiltonians/SpaceWarpTransformation.h" +#include "Particle/DistanceTableData.h" +#include "type_traits/scalar_traits.h" +namespace qmcplusplus +{ +SpaceWarpTransformation::SpaceWarpTransformation(ParticleSet& elns, const ParticleSet& ions) + : myTableIndex(elns.addTable(ions)), Nelec(elns.getTotalNum()), Nions(ions.getTotalNum()), swpow(4.0) +{ + warpval.resize(Nelec, Nions); + gradval.resize(Nelec, Nions); +} + +SpaceWarpTransformation::RealType SpaceWarpTransformation::f(RealType r) { return std::pow(r, -swpow); } + +SpaceWarpTransformation::RealType SpaceWarpTransformation::df(RealType r) { return -swpow * std::pow(r, -(swpow + 1)); } +//Space warp functions have the form w_I(r_i) = F(|r_i-R_I)/Sum_J F(|r_i-R_J|). Hence the intermediate we will +//precompute is the matrix "warpval[i][J] = F(|r_i-R_J|) and gradval[i][J]=Grad(F(|r_i-R_J|)). +//This allows the calculation of any space warp value or gradient by a matrix lookup, combined with a sum over columns. +void SpaceWarpTransformation::computeSWTIntermediates(ParticleSet& P, const ParticleSet& ions) +{ + const DistanceTableData& d_ab(P.getDistTable(myTableIndex)); + for (size_t iel = 0; iel < Nelec; ++iel) + { + const auto& dist = d_ab.getDistRow(iel); + const auto& dr = d_ab.getDisplRow(iel); + for (size_t ionid = 0; ionid < Nions; ++ionid) + { + warpval[iel][ionid] = f(dist[ionid]); + gradval[iel][ionid] = -dr[ionid] * + (df(dist[ionid]) / dist[ionid]); //because there's a -1 in distance table displacement definition. R-r :(. + } + } +} + +//This function handles parsing of the intermediate matrices and construction of the w_I(r_i) and Grad_i(w_I(r_i)) functions +// that appear in the space warp transformation formulas. +void SpaceWarpTransformation::getSWT(int iat, ParticleScalar_t& w, Force_t& grad_w) +{ + for (size_t iel = 0; iel < Nelec; iel++) + { + RealType warpdenom = 0.0; + PosType denomgrad = 0.0; + for (size_t ionid = 0; ionid < Nions; ionid++) + { + warpdenom += warpval[iel][ionid]; + denomgrad += gradval[iel][ionid]; + } + w[iel] = warpval[iel][iat] / warpdenom; + grad_w[iel] = gradval[iel][iat] / warpdenom - w[iel] * denomgrad / warpdenom; + } +} +//This function returns Sum_i w_I(r_i) Grad_i(E_L) (as el_contribution) and Sum_i[ w_I(r_i)Grad_i(logpsi)+0.5*Grad_i(w_I(r_i)) (as psi_contribution). See Eq (15) and (16) respectively. +void SpaceWarpTransformation::computeSWT(ParticleSet& P, + const ParticleSet& ions, + Force_t& dEl, + ParticleGradient_t& dlogpsi, + Force_t& el_contribution, + Force_t& psi_contribution) +{ + el_contribution = 0; + psi_contribution = 0; + ParticleScalar_t w; + Force_t gradw; + w.resize(Nelec); + gradw.resize(Nelec); + + PosType gwfn = 0; + computeSWTIntermediates(P, ions); + + for (size_t iat = 0; iat < Nions; iat++) + { + w = 0; + gradw = 0; + getSWT(iat, w, gradw); + for (size_t iel = 0; iel < Nelec; iel++) + { + el_contribution[iat] += w[iel] * dEl[iel]; + +#if defined(QMC_COMPLEX) + convert(dlogpsi[iel], gwfn); +#else + gwfn = dlogpsi[iel]; +#endif + psi_contribution[iat] += w[iel] * gwfn + 0.5 * gradw[iel]; + } + } + //REMOVE ME + //app_log()<<"FINAL SPACE WARP TRANSFORM\n"; + //app_log()<<" Using dEl="< warpval; + /// Nelec x Nion matrix of \nabla_i F(|r_i-R_J|) + Matrix gradval; +}; +} // namespace qmcplusplus +#endif diff --git a/src/QMCHamiltonians/tests/CMakeLists.txt b/src/QMCHamiltonians/tests/CMakeLists.txt index 31bca07eed..b87faf2287 100644 --- a/src/QMCHamiltonians/tests/CMakeLists.txt +++ b/src/QMCHamiltonians/tests/CMakeLists.txt @@ -31,6 +31,7 @@ SET(SRCS test_bare_kinetic.cpp test_force.cpp test_force_ewald.cpp test_stress.cpp + test_spacewarp.cpp test_ecp.cpp test_hamiltonian_pool.cpp test_hamiltonian_factory.cpp @@ -45,6 +46,12 @@ IF(QMC_CUDA) ) ENDIF() +SET(FILES_TO_COPY Na2.structure.xml) + +FOREACH(fname ${FILES_TO_COPY}) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${fname}" ${UTEST_DIR}) +ENDFOREACH() + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E make_directory "${UTEST_DIR}") EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/simple.txt" ${UTEST_DIR}) EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy "${qmcpack_SOURCE_DIR}/tests/pseudopotentials_for_tests/C.BFD.xml" ${UTEST_DIR}) diff --git a/src/QMCHamiltonians/tests/Na2.structure.xml b/src/QMCHamiltonians/tests/Na2.structure.xml new file mode 100644 index 0000000000..a2c45ab636 --- /dev/null +++ b/src/QMCHamiltonians/tests/Na2.structure.xml @@ -0,0 +1,31 @@ + + + + + 1 + 1 + 11 + + + 0.0000000000e+00 0.0000000000e+00 0.0000000000e+00 + 5.9999995664e+00 0.0000000000e+00 0.0000000000e+00 + + + Na Na + + + + + -1 + + 5.6362539350e-01 9.5600940368e-01 -1.1525504049e+00 + + + + -1 + + 5.7820981934e+00 -1.0984181325e+00 1.1428020817e+00 + + + + diff --git a/src/QMCHamiltonians/tests/test_spacewarp.cpp b/src/QMCHamiltonians/tests/test_spacewarp.cpp new file mode 100644 index 0000000000..8359562285 --- /dev/null +++ b/src/QMCHamiltonians/tests/test_spacewarp.cpp @@ -0,0 +1,127 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2016 Jeongnim Kim and QMCPACK developers. +// +// File developed by: Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign +// +// File created by: Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign +////////////////////////////////////////////////////////////////////////////////////// + + +#include "catch.hpp" + +#include "OhmmsData/Libxml2Doc.h" +#include "OhmmsPETE/OhmmsMatrix.h" +#include "Particle/ParticleSet.h" +#include "Particle/ParticleSetPool.h" +#include "ParticleIO/XMLParticleIO.h" +#include "QMCHamiltonians/SpaceWarpTransformation.h" +//#include "QMCWaveFunctions/SPOSetBuilderFactory.h" +//#include "QMCHamiltonians/ForceChiesaPBCAA.h" +//#include "QMCHamiltonians/ForceCeperley.h" +//#include "QMCHamiltonians/CoulombPotential.h" +//#include "QMCHamiltonians/CoulombPBCAA.h" +//#include "QMCHamiltonians/CoulombPBCAB.h" +//#include "QMCWaveFunctions/TrialWaveFunction.h" +//#include "QMCWaveFunctions/Fermion/DiracDeterminant.h" +//#include "QMCWaveFunctions/Fermion/SlaterDet.h" + +#include +#include + +using std::string; + +namespace qmcplusplus +{ +using RealType = QMCTraits::RealType; +TEST_CASE("SpaceWarp", "[hamiltonian]") +{ + Communicate* c = OHMMS::Controller; + + Libxml2Document doc; + bool okay = doc.parse("Na2.structure.xml"); + REQUIRE(okay); + xmlNodePtr root = doc.getRoot(); + Tensor tmat; + tmat(0, 0) = 1; + tmat(1, 1) = 1; + tmat(2, 2) = 1; + + ParticleSet ions; + XMLParticleParser parse_ions(ions, tmat); + OhmmsXPathObject particleset_ion("//particleset[@name='ion0']", doc.getXPathContext()); + REQUIRE(particleset_ion.size() == 1); + parse_ions.put(particleset_ion[0]); + + REQUIRE(ions.groups() == 1); + REQUIRE(ions.R.size() == 2); + ions.update(); + + ParticleSet elec; + XMLParticleParser parse_elec(elec, tmat); + OhmmsXPathObject particleset_elec("//particleset[@name='e']", doc.getXPathContext()); + REQUIRE(particleset_elec.size() == 1); + parse_elec.put(particleset_elec[0]); + + REQUIRE(elec.groups() == 2); + REQUIRE(elec.R.size() == 2); + + elec.addTable(ions); + elec.update(); + + //Now build the wavefunction. This will be needed to test \Nabla_i E_L and \Nabla_i logPsi contributions. + //For now, just take them from a reference calculation. + + using Force_t = ParticleSet::ParticlePos_t; + Force_t dE_L; + Force_t el_contribution; + Force_t psi_contribution; + + dE_L.resize(elec.getTotalNum()); + el_contribution.resize(ions.getTotalNum()); + psi_contribution.resize(ions.getTotalNum()); + + dE_L[0][0] = -0.0328339806050; + dE_L[0][1] = -0.0834441565340; + dE_L[0][2] = 0.0997813066140; + dE_L[1][0] = -0.0140597469190; + dE_L[1][1] = 0.0591827022730; + dE_L[1][2] = -0.0622852142310; + + elec.G[0][0] = 0.4167938814700; + elec.G[0][1] = 0.2878426639600; + elec.G[0][2] = -0.3470187402100; + elec.G[1][0] = -0.2946265813200; + elec.G[1][1] = -0.3606166249000; + elec.G[1][2] = 0.3751881159300; + + SpaceWarpTransformation swt(elec, ions); + swt.setPow(3.0); + + REQUIRE(swt.f(2.0) == Approx(0.125)); + REQUIRE(swt.df(2.0) == Approx(-0.1875)); + + swt.setPow(4.0); + REQUIRE(swt.f(2.0) == Approx(0.0625)); + REQUIRE(swt.df(2.0) == Approx(-0.125)); + + swt.computeSWT(elec, ions, dE_L, elec.G, el_contribution, psi_contribution); + app_log() << "EL_Contribution: " << el_contribution << std::endl; + app_log() << "PSi_Contribution: " << psi_contribution << std::endl; + REQUIRE(el_contribution[0][0] == Approx(-0.0326934696861)); + REQUIRE(el_contribution[0][1] == Approx(-0.0826080664130)); + REQUIRE(el_contribution[0][2] == Approx(0.0988243408507)); + REQUIRE(el_contribution[1][0] == Approx(-0.0142002578379)); + REQUIRE(el_contribution[1][1] == Approx(0.0583466121520)); + REQUIRE(el_contribution[1][2] == Approx(-0.0613282484677)); + + REQUIRE(psi_contribution[0][0] == Approx(0.4051467191368)); + REQUIRE(psi_contribution[0][1] == Approx(0.2757724717133)); + REQUIRE(psi_contribution[0][2] == Approx(-0.3334287440127)); + REQUIRE(psi_contribution[1][0] == Approx(-0.2829794189868)); + REQUIRE(psi_contribution[1][1] == Approx(-0.3485464326533)); + REQUIRE(psi_contribution[1][2] == Approx(0.3615981197327)); +} +} //namespace qmcplusplus