From 82f39543f3e467998d6e11c7fb365d12c9965529 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:40:46 -0600 Subject: [PATCH 01/19] Save bspline coefficients to allow global rotation --- .../BsplineFactory/SplineR2R.cpp | 34 ++++++++++++++++--- .../BsplineFactory/SplineR2R.h | 4 +++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/QMCWaveFunctions/BsplineFactory/SplineR2R.cpp b/src/QMCWaveFunctions/BsplineFactory/SplineR2R.cpp index e932fbde52..414ad18c7b 100644 --- a/src/QMCWaveFunctions/BsplineFactory/SplineR2R.cpp +++ b/src/QMCWaveFunctions/BsplineFactory/SplineR2R.cpp @@ -51,6 +51,20 @@ bool SplineR2R::write_splines(hdf_archive& h5f) return h5f.writeEntry(bigtable, o.str().c_str()); //"spline_0"); } +template +void SplineR2R::storeParamsBeforeRotation() +{ + const auto spline_ptr = SplineInst->getSplinePtr(); + const auto spl_coefs = spline_ptr->coefs; + const auto coefs_tot_size = spline_ptr->coefs_size; + coef_copy = std::make_shared>(coefs_tot_size); + for (size_t i = 0; i < coefs_tot_size; i++) + { + (*coef_copy)[i] = spl_coefs[i]; + } +} + + /* ~~ Notes for rotation ~~ spl_coefs = Raw pointer of spline coefficients @@ -87,6 +101,16 @@ void SplineR2R::applyRotation(const ValueMatrix& rot_mat, bool use_stored_co const auto TrueNOrbs = rot_mat.size1(); // == Nsplines - padding assert(OrbitalSetSize >= TrueNOrbs); + if (!use_stored_copy) + { + if (!coef_copy) + coef_copy = std::make_shared>(coefs_tot_size); + for (size_t i = 0; i < coefs_tot_size; i++) + { + (*coef_copy)[i] = spl_coefs[i]; + } + } + // Fill top left corner of tmpU with rot_mat ValueMatrix tmpU; tmpU.resize(Nsplines, Nsplines); @@ -100,7 +124,7 @@ void SplineR2R::applyRotation(const ValueMatrix& rot_mat, bool use_stored_co } // Apply rotation the dumb way b/c I can't get BLAS::gemm to work... - std::vector new_coefs(coefs_tot_size, 0); + //std::vector new_coefs(coefs_tot_size, 0); for (auto i = 0; i < BasisSetSize; i++) { for (auto j = 0; j < Nsplines; j++) @@ -110,14 +134,16 @@ void SplineR2R::applyRotation(const ValueMatrix& rot_mat, bool use_stored_co for (auto k = 0; k < Nsplines; k++) { const auto index = i * Nsplines + k; - newval += *(spl_coefs + index) * tmpU[k][j]; + //newval += *(spl_coefs + index) * tmpU[k][j]; + newval += *(coef_copy->data() + index) * tmpU[k][j]; } - new_coefs[cur_elem] = newval; + //new_coefs[cur_elem] = newval; + spl_coefs[cur_elem] = newval; } } // Update the coefs - std::copy(new_coefs.begin(), new_coefs.end(), spl_coefs); + //std::copy(new_coefs.begin(), new_coefs.end(), spl_coefs); /* // Here is my attempt to use gemm but it doesn't work... diff --git a/src/QMCWaveFunctions/BsplineFactory/SplineR2R.h b/src/QMCWaveFunctions/BsplineFactory/SplineR2R.h index 71ce5458fe..e6ee97299d 100644 --- a/src/QMCWaveFunctions/BsplineFactory/SplineR2R.h +++ b/src/QMCWaveFunctions/BsplineFactory/SplineR2R.h @@ -58,6 +58,8 @@ class SplineR2R : public BsplineSet ///multi bspline set std::shared_ptr> SplineInst; + // Copy of original splines for orbital rotation + std::shared_ptr> coef_copy; ///thread private ratios for reduction when using nested threading, numVP x numThread Matrix ratios_private; @@ -83,6 +85,8 @@ class SplineR2R : public BsplineSet std::unique_ptr makeClone() const override { return std::make_unique(*this); } + + void storeParamsBeforeRotation() override; /* Implements orbital rotations via [1,2]. Should be called by RotatedSPOs::apply_rotation() From a7e680419461e26c2b3b71386b8c954bc360d744 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:42:43 -0600 Subject: [PATCH 02/19] Add code to save/read extra WF parameter info --- src/QMCDrivers/WFOpt/QMCCostFunctionBase.cpp | 8 +++++++- src/QMCWaveFunctions/VariableSet.cpp | 8 +++----- src/QMCWaveFunctions/VariableSet.h | 9 +++++++-- src/QMCWaveFunctions/tests/test_variable_set.cpp | 7 +++++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/QMCDrivers/WFOpt/QMCCostFunctionBase.cpp b/src/QMCDrivers/WFOpt/QMCCostFunctionBase.cpp index 94f2b31c32..06f1e8e125 100644 --- a/src/QMCDrivers/WFOpt/QMCCostFunctionBase.cpp +++ b/src/QMCDrivers/WFOpt/QMCCostFunctionBase.cpp @@ -215,7 +215,13 @@ void QMCCostFunctionBase::reportParameters() { std::ostringstream vp_filename; vp_filename << RootName << ".vp.h5"; - OptVariables.saveAsHDF(vp_filename.str()); + hdf_archive hout; + OptVariables.saveAsHDF(vp_filename.str(), hout); + + UniqueOptObjRefs opt_obj_refs = Psi.extractOptimizableObjectRefs(); + for (auto opt_obj : opt_obj_refs) + opt_obj.get().saveExtraParameters(hout); + char newxml[128]; sprintf(newxml, "%s.opt.xml", RootName.c_str()); diff --git a/src/QMCWaveFunctions/VariableSet.cpp b/src/QMCWaveFunctions/VariableSet.cpp index 50757fa9fe..01064fdf6e 100644 --- a/src/QMCWaveFunctions/VariableSet.cpp +++ b/src/QMCWaveFunctions/VariableSet.cpp @@ -231,11 +231,10 @@ void VariableSet::print(std::ostream& os, int leftPadSpaces, bool printHeader) c } } -void VariableSet::saveAsHDF(const std::string& filename) const +void VariableSet::saveAsHDF(const std::string& filename, qmcplusplus::hdf_archive& hout) const { - qmcplusplus::hdf_archive hout; hout.create(filename); - std::vector vp_file_version{1, 0, 0}; + std::vector vp_file_version{1, 1, 0}; hout.write(vp_file_version, "version"); std::string timestamp(getDateAndTime("%Y-%m-%d %H:%M:%S %Z")); @@ -256,9 +255,8 @@ void VariableSet::saveAsHDF(const std::string& filename) const hout.pop(); } -void VariableSet::readFromHDF(const std::string& filename) +void VariableSet::readFromHDF(const std::string& filename, qmcplusplus::hdf_archive& hin) { - qmcplusplus::hdf_archive hin; if (!hin.open(filename, H5F_ACC_RDONLY)) { std::ostringstream err_msg; diff --git a/src/QMCWaveFunctions/VariableSet.h b/src/QMCWaveFunctions/VariableSet.h index f9c9f674d6..981deed420 100644 --- a/src/QMCWaveFunctions/VariableSet.h +++ b/src/QMCWaveFunctions/VariableSet.h @@ -22,6 +22,11 @@ #include #include "Configuration.h" +namespace qmcplusplus +{ + class hdf_archive; +} + namespace optimize { /** An enum useful for determining the type of parameter is being optimized. @@ -334,11 +339,11 @@ struct VariableSet void print(std::ostream& os, int leftPadSpaces = 0, bool printHeader = false) const; // Save variational parameters to an HDF file - void saveAsHDF(const std::string& filename) const; + void saveAsHDF(const std::string& filename, qmcplusplus::hdf_archive& hout) const; /// Read variational parameters from an HDF file. /// This assumes VariableSet is already set up. - void readFromHDF(const std::string& filename); + void readFromHDF(const std::string& filename, qmcplusplus::hdf_archive& hin); }; } // namespace optimize diff --git a/src/QMCWaveFunctions/tests/test_variable_set.cpp b/src/QMCWaveFunctions/tests/test_variable_set.cpp index 32a79c374b..caf44eb8ef 100644 --- a/src/QMCWaveFunctions/tests/test_variable_set.cpp +++ b/src/QMCWaveFunctions/tests/test_variable_set.cpp @@ -14,6 +14,7 @@ #include "complex_approx.hpp" #include "VariableSet.h" +#include "io/hdf/hdf_archive.h" #include #include @@ -120,12 +121,14 @@ TEST_CASE("VariableSet HDF output and input", "[optimize]") vs.insert("s", first_val); vs.insert("second", second_val); vs.insert("really_really_really_long_name", third_val); - vs.saveAsHDF("vp.h5"); + qmcplusplus::hdf_archive hout; + vs.saveAsHDF("vp.h5", hout); VariableSet vs2; vs2.insert("s", 0.0); vs2.insert("second", 0.0); - vs2.readFromHDF("vp.h5"); + qmcplusplus::hdf_archive hin; + vs2.readFromHDF("vp.h5", hin); CHECK(vs2.find("s")->second == ValueApprox(first_val)); CHECK(vs2.find("second")->second == ValueApprox(second_val)); // This value as in the file, but not in the VariableSet that loaded the file, From e6eb032a747757bafd5ea63caa3fe31320f1154a Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:43:59 -0600 Subject: [PATCH 03/19] Use shared copy for global rotation copy --- src/QMCWaveFunctions/LCAO/LCAOrbitalSet.cpp | 6 ++++-- src/QMCWaveFunctions/LCAO/LCAOrbitalSet.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.cpp b/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.cpp index 772b528e3c..f99ba4b470 100644 --- a/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.cpp +++ b/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.cpp @@ -690,9 +690,11 @@ void LCAOrbitalSet::evaluateThirdDeriv(const ParticleSet& P, int first, int last void LCAOrbitalSet::applyRotation(const ValueMatrix& rot_mat, bool use_stored_copy) { if (!use_stored_copy) - C_copy = *C; + { + *C_copy = *C; + } //gemm is out-of-place - BLAS::gemm('N', 'T', BasisSetSize, OrbitalSetSize, OrbitalSetSize, RealType(1.0), C_copy.data(), BasisSetSize, + BLAS::gemm('N', 'T', BasisSetSize, OrbitalSetSize, OrbitalSetSize, RealType(1.0), C_copy->data(), BasisSetSize, rot_mat.data(), OrbitalSetSize, RealType(0.0), C->data(), BasisSetSize); /* debugging code diff --git a/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.h b/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.h index 02945a6a50..21f34caf96 100644 --- a/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.h +++ b/src/QMCWaveFunctions/LCAO/LCAOrbitalSet.h @@ -55,7 +55,7 @@ struct LCAOrbitalSet : public SPOSet std::unique_ptr makeClone() const override; - void storeParamsBeforeRotation() override { C_copy = *C; } + void storeParamsBeforeRotation() override { C_copy = std::make_unique(*C); } void applyRotation(const ValueMatrix& rot_mat, bool use_stored_copy) override; @@ -195,7 +195,7 @@ struct LCAOrbitalSet : public SPOSet ///number of Single-particle orbitals const IndexType BasisSetSize; /// a copy of the original C before orbital rotation is applied; - ValueMatrix C_copy; + std::shared_ptr C_copy; ///true if C is an identity matrix bool Identity; From 3a505e5c2aac2d8d8b0cbd25f6f8cf37eb6df778 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:44:55 -0600 Subject: [PATCH 04/19] Add two methods for handling orbital rotation --- src/QMCWaveFunctions/OptimizableObject.h | 18 ++ src/QMCWaveFunctions/RotatedSPOs.cpp | 298 ++++++++++++++++++++++- src/QMCWaveFunctions/RotatedSPOs.h | 42 ++-- 3 files changed, 338 insertions(+), 20 deletions(-) diff --git a/src/QMCWaveFunctions/OptimizableObject.h b/src/QMCWaveFunctions/OptimizableObject.h index cfb66cbd94..b8aac29baf 100644 --- a/src/QMCWaveFunctions/OptimizableObject.h +++ b/src/QMCWaveFunctions/OptimizableObject.h @@ -22,6 +22,7 @@ namespace qmcplusplus { using opt_variables_type = optimize::VariableSet; +class hdf_archive; class OptimizableObject { @@ -72,6 +73,23 @@ class OptimizableObject virtual void reportStatus(std::ostream& os) {} void setOptimization(bool state) { is_optimized_ = state; } + + /** save extra parameters for wavefunction state + * + * The hdf archive is expected to be created in VariableSet::saveAsHDF + */ + virtual void saveExtraParameters(hdf_archive& hout) + { + } + + /** read extra parameters for wavefunction state + * + * The hdf archive is expected to be opened in VariableSet::readFromHDF + */ + virtual void readExtraParameters(hdf_archive& hin) + { + } + }; class UniqueOptObjRefs : public RefVector diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 45c576d378..0687766219 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -14,12 +14,18 @@ #include "Numerics/MatrixOperators.h" #include "Numerics/DeterminantOperators.h" #include "CPU/BLAS.hpp" - +#include "io/hdf/hdf_archive.h" namespace qmcplusplus { RotatedSPOs::RotatedSPOs(const std::string& my_name, std::unique_ptr&& spos) - : SPOSet(my_name), OptimizableObject(my_name), Phi(std::move(spos)), nel_major_(0), params_supplied(false) + : SPOSet(my_name), + OptimizableObject(my_name), + Phi(std::move(spos)), + nel_major_(0), + params_supplied(false), + use_this_copy_to_apply_rotation_(false), + use_global_rot_(false) { OrbitalSetSize = Phi->getOrbitalSetSize(); } @@ -40,6 +46,25 @@ void RotatedSPOs::createRotationIndices(int nel, int nmo, RotationIndices& rot_i rot_indices.emplace_back(i, j); } +void RotatedSPOs::createRotationIndicesFull(int nel, int nmo, RotationIndices& rot_indices) +{ + // start with active-inactive rotations + for (int i = 0; i < nel; i++) + for (int j = nel; j < nmo; j++) + rot_indices.emplace_back(i, j); + + // Allow active-active rotations - put them at the end of the list + for (int i = 0; i < nel; i++) + for (int j = i + 1; j < nel; j++) + rot_indices.emplace_back(i, j); + + // Allow inactive-inactive rotations - put them at the end of the list + for (int i = nel; i < nmo; i++) + for (int j = i + 1; j < nmo; j++) + rot_indices.emplace_back(i, j); +} + + void RotatedSPOs::constructAntiSymmetricMatrix(const RotationIndices& rot_indices, const std::vector& param, ValueMatrix& rot_mat) @@ -73,6 +98,174 @@ void RotatedSPOs::extractParamsFromAntiSymmetricMatrix(const RotationIndices& ro } } +void RotatedSPOs::resetParametersExclusive(const opt_variables_type& active) +{ + std::vector delta_param(m_act_rot_inds.size()); + + size_t psize = m_full_rot_inds.size(); + + if (use_global_rot_) + { + assert(psize >= m_act_rot_inds.size()); + } + else + { + psize = m_act_rot_inds.size(); + } + + std::vector old_param(psize); + std::vector new_param(psize); + + for (int i = 0; i < m_act_rot_inds.size(); i++) + { + int loc = myVars.where(i); + delta_param[i] = active[loc] - myVars[i]; + if (use_global_rot_) + { + old_param[i] = myVars[i]; + } + else + { + myVars[i] = active[loc]; + } + } + + if (use_global_rot_) + { + for (int i = m_act_rot_inds.size(); i < m_full_rot_inds.size(); i++) + { + old_param[i] = myVarsFull[i]; + } + + apply_delta_rotation(delta_param, old_param, new_param); + + // Save the active params + for (int i = 0; i < m_act_rot_inds.size(); i++) + { + myVars[i] = new_param[i]; + myVarsFull[i] = new_param[i]; + } + + // Save the rest of the params + for (int i = m_act_rot_inds.size(); i < m_full_rot_inds.size(); i++) + { + myVarsFull[i] = new_param[i]; + } + } + else + { + if (use_this_copy_to_apply_rotation_) + { + apply_rotation(delta_param, false); + } + + history_params_.push_back(delta_param); + } +} + +void RotatedSPOs::saveExtraParameters(hdf_archive& hout) +{ + if (use_global_rot_) + { + hid_t grp = hout.push("rotation_global"); + std::string rot_global_name = std::string("rotation_global_") + Phi->getName(); + + int nparam = myVarsFull.size(); + std::vector full_params(nparam); + for (int i = 0; i < nparam; i++) + { + full_params[i] = myVarsFull[i]; + } + + hout.write(full_params, rot_global_name); + } + else + { + hid_t grp = hout.push("rotation_history"); + size_t rows = history_params_.size(); + size_t cols = 0; + if (rows > 0) + cols = history_params_[0].size(); + + Matrix tmp(rows, cols); + for (size_t i = 0; i < rows; i++) + { + for (size_t j = 0; j < cols; j++) + { + tmp(i, j) = history_params_[i][j]; + } + } + + std::string rot_hist_name = std::string("rotation_history_") + Phi->getName(); + hout.write(tmp, rot_hist_name); + } + + hout.pop(); +} + +void RotatedSPOs::readExtraParameters(hdf_archive& hin) +{ + hid_t grp_hist = hin.push("rotation_history"); + hid_t grp_global = hin.push("rotation_global"); + if (grp_hist < 0 && grp_global < 0) + throw std::runtime_error("Expecting rotation parameters in VP file"); + + if (grp_global >= 0) + { + std::string rot_global_name = std::string("rotation_global_") + Phi->getName(); + + std::vector sizes(1); + if (!hin.getShape(rot_global_name, sizes)) + throw std::runtime_error("Failed to read rotation_global in VP file"); + + int nparam_actual = sizes[0]; + + int nparam = myVarsFull.size(); + + if (nparam != nparam_actual) + { + std::ostringstream tmp_err; + tmp_err << "Expected number of full rotation parameters (" << nparam << ") does not match number in file (" + << nparam_actual << ")"; + throw std::runtime_error(tmp_err.str()); + } + + std::vector full_params(nparam); + hin.read(full_params, rot_global_name); + for (int i = 0; i < nparam; i++) + { + myVarsFull[i] = full_params[i]; + } + for (int i = 0; i < m_act_rot_inds.size(); i++) + { + myVars[i] = full_params[i]; + } + + hin.pop(); + + apply_full_rotation(full_params, true); + } + else + { + std::string rot_hist_name = std::string("rotation_history_") + Phi->getName(); + std::vector sizes(2); + if (!hin.getShape(rot_hist_name, sizes)) + throw std::runtime_error("Failed to read rotation history in VP file"); + + int rows = sizes[0]; + int cols = sizes[1]; + Matrix tmp(rows, cols); + hin.read(tmp, rot_hist_name); + for (size_t i = 0; i < rows; i++) + for (size_t j = 0; j < cols; j++) + history_params_[i][j] = tmp(i, j); + + hin.pop(); + + apply_rotation_history(); + } +} + void RotatedSPOs::buildOptVariables(const size_t nel) { #if !defined(QMC_COMPLEX) @@ -94,6 +287,8 @@ void RotatedSPOs::buildOptVariables(const size_t nel) createRotationIndices(nel, nmo, created_m_act_rot_inds); + createRotationIndicesFull(nel, nmo, m_full_rot_inds); + buildOptVariables(created_m_act_rot_inds); } #endif @@ -107,6 +302,15 @@ void RotatedSPOs::buildOptVariables(const RotationIndices& rotations) // create active rotations m_act_rot_inds = rotations; + if (use_global_rot_) + { + app_log() << "Orbital rotation using global rotation" << std::endl; + } + else + { + app_log() << "Orbital rotation using history" << std::endl; + } + // This will add the orbital rotation parameters to myVars // and will also read in initial parameter values supplied in input file int p, q; @@ -139,6 +343,23 @@ void RotatedSPOs::buildOptVariables(const RotationIndices& rotations) } } + if (use_global_rot_) + { + myVarsFull.clear(); + for (int i = 0; i < m_full_rot_inds.size(); i++) + { + p = m_full_rot_inds[i].first; + q = m_full_rot_inds[i].second; + std::stringstream sstr; + sstr << my_name_ << "_orb_rot_" << (p < 10 ? "0" : "") << (p < 100 ? "0" : "") << (p < 1000 ? "0" : "") << p + << "_" << (q < 10 ? "0" : "") << (q < 100 ? "0" : "") << (q < 1000 ? "0" : "") << q; + + // No user input parameters for now + myVarsFull.insert(sstr.str(), 0.0); + } + } + + //Printing the parameters if (true) { @@ -153,6 +374,67 @@ void RotatedSPOs::buildOptVariables(const RotationIndices& rotations) #endif } +void RotatedSPOs::apply_delta_rotation(const std::vector& delta_param, + const std::vector& old_param, + std::vector& new_param) +{ + assert(delta_param.size() == m_act_rot_inds.size()); + assert(old_param.size() == m_full_rot_inds.size()); + assert(new_param.size() == m_full_rot_inds.size()); + + const size_t nmo = Phi->getOrbitalSetSize(); + ValueMatrix old_rot_mat(nmo, nmo); + old_rot_mat = ValueType(0); + + constructAntiSymmetricMatrix(m_full_rot_inds, old_param, old_rot_mat); + exponentiate_antisym_matrix(old_rot_mat); + + ValueMatrix delta_rot_mat(nmo, nmo); + delta_rot_mat = ValueType(0); + + constructAntiSymmetricMatrix(m_act_rot_inds, delta_param, delta_rot_mat); + exponentiate_antisym_matrix(delta_rot_mat); + + // Apply delta rotation to old rotation. + ValueMatrix new_rot_mat(nmo, nmo); + BLAS::gemm('N', 'N', nmo, nmo, nmo, 1.0, delta_rot_mat.data(), nmo, old_rot_mat.data(), nmo, 0.0, new_rot_mat.data(), + nmo); + + Phi->applyRotation(new_rot_mat, true); + + log_antisym_matrix(new_rot_mat); + extractParamsFromAntiSymmetricMatrix(m_full_rot_inds, new_rot_mat, new_param); +} + +void RotatedSPOs::apply_full_rotation(const std::vector& full_param, bool use_stored_copy) +{ + assert(full_param.size() == m_full_rot_inds.size()); + + const size_t nmo = Phi->getOrbitalSetSize(); + ValueMatrix rot_mat(nmo, nmo); + rot_mat = ValueType(0); + + constructAntiSymmetricMatrix(m_full_rot_inds, full_param, rot_mat); + + /* + rot_mat is now an anti-hermitian matrix. Now we convert + it into a unitary matrix via rot_mat = exp(-rot_mat). + Finally, apply unitary matrix to orbs. + */ + exponentiate_antisym_matrix(rot_mat); + Phi->applyRotation(rot_mat, use_stored_copy); +} + + +void RotatedSPOs::apply_rotation_history() +{ + for (auto delta_param : history_params_) + { + apply_rotation(delta_param, false); + } +} + + void RotatedSPOs::apply_rotation(const std::vector& param, bool use_stored_copy) { assert(param.size() == m_act_rot_inds.size()); @@ -401,9 +683,9 @@ void RotatedSPOs::evaluateDerivatives(ParticleSet& P, for (int i = 0; i < m_act_rot_inds.size(); i++) { - int kk = myVars.where(i); - const int p = m_act_rot_inds.at(i).first; - const int q = m_act_rot_inds.at(i).second; + int kk = myVars.where(i); + const int p = m_act_rot_inds.at(i).first; + const int q = m_act_rot_inds.at(i).second; dlogpsi[kk] = T(p, q); dhpsioverpsi[kk] = ValueType(-0.5) * Y4(p, q); } @@ -1139,7 +1421,13 @@ std::unique_ptr RotatedSPOs::makeClone() const myclone->params = this->params; myclone->params_supplied = this->params_supplied; myclone->m_act_rot_inds = this->m_act_rot_inds; + myclone->m_full_rot_inds = this->m_full_rot_inds; myclone->myVars = this->myVars; + myclone->history_params_ = this->history_params_; + myclone->myVarsFull = this->myVarsFull; + + // use_this_copy_to_apply_rotation_ is not copied + return myclone; } diff --git a/src/QMCWaveFunctions/RotatedSPOs.h b/src/QMCWaveFunctions/RotatedSPOs.h index dd5d33f1c9..61a8d2dd28 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.h +++ b/src/QMCWaveFunctions/RotatedSPOs.h @@ -37,11 +37,16 @@ class RotatedSPOs : public SPOSet, public OptimizableObject // Active orbital rotation parameter indices RotationIndices m_act_rot_inds; + RotationIndices m_full_rot_inds; + // Construct a list of the matrix indices for non-zero rotation parameters. // (The structure for a sparse representation of the matrix) // Only core->active rotations are created. static void createRotationIndices(int nel, int nmo, RotationIndices& rot_indices); + static void createRotationIndicesFull(int nel, int nmo, RotationIndices& rot_indices); + + // Fill in antisymmetric matrix from the list of rotation parameter indices // and a list of parameter values. // This function assumes rot_mat is properly sized upon input and is set to zero. @@ -58,6 +63,15 @@ class RotatedSPOs : public SPOSet, public OptimizableObject //function to perform orbital rotations void apply_rotation(const std::vector& param, bool use_stored_copy); + void apply_delta_rotation(const std::vector& delta_param, + const std::vector& old_param, + std::vector& new_param); + + void apply_rotation_history(); + + void apply_full_rotation(const std::vector& param, bool use_stored_copy); + + // Compute matrix exponential of an antisymmetric matrix (result is rotation matrix) static void exponentiate_antisym_matrix(ValueMatrix& mat); @@ -197,28 +211,18 @@ class RotatedSPOs : public SPOSet, public OptimizableObject void checkInVariablesExclusive(opt_variables_type& active) override { - //reset parameters to zero after coefficient matrix has been updated - for (int k = 0; k < myVars.size(); ++k) - myVars[k] = 0.0; - + use_this_copy_to_apply_rotation_ = true; if (myVars.size()) active.insertFrom(myVars); - Phi->storeParamsBeforeRotation(); } void checkOutVariables(const opt_variables_type& active) override { myVars.getIndex(active); } ///reset - void resetParametersExclusive(const opt_variables_type& active) override - { - std::vector param(m_act_rot_inds.size()); - for (int i = 0; i < m_act_rot_inds.size(); i++) - { - int loc = myVars.where(i); - param[i] = myVars[i] = active[loc]; - } - apply_rotation(param, true); - } + void resetParametersExclusive(const opt_variables_type& active) override; + + void saveExtraParameters(hdf_archive& hout) override; + void readExtraParameters(hdf_archive& hin) override; //********************************************************************************* //the following functions simply call Phi's corresponding functions @@ -330,6 +334,14 @@ class RotatedSPOs : public SPOSet, public OptimizableObject bool params_supplied; /// list of supplied orbital rotation parameters std::vector params; + + bool use_this_copy_to_apply_rotation_; + + std::vector> history_params_; + + opt_variables_type myVarsFull; + + bool use_global_rot_; }; } //namespace qmcplusplus From e0b9f9992f2542aed0b0f58da53fc4fcdb60e419 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:45:42 -0600 Subject: [PATCH 05/19] Save coefficients if doing rotation --- src/QMCWaveFunctions/SPOSetBuilder.cpp | 1 + src/QMCWaveFunctions/WaveFunctionFactory.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/QMCWaveFunctions/SPOSetBuilder.cpp b/src/QMCWaveFunctions/SPOSetBuilder.cpp index 96d4c85201..72a447e295 100644 --- a/src/QMCWaveFunctions/SPOSetBuilder.cpp +++ b/src/QMCWaveFunctions/SPOSetBuilder.cpp @@ -95,6 +95,7 @@ std::unique_ptr SPOSetBuilder::createSPOSet(xmlNodePtr cur) app_error() << "Orbital optimization via rotation doesn't support complex wavefunction yet.\n"; abort(); #else + sposet->storeParamsBeforeRotation(); // create sposet with rotation auto& sposet_ref = *sposet; app_log() << " SPOSet " << sposet_ref.getName() << " is optimizable\n"; diff --git a/src/QMCWaveFunctions/WaveFunctionFactory.cpp b/src/QMCWaveFunctions/WaveFunctionFactory.cpp index 1cddae31af..32348de92a 100644 --- a/src/QMCWaveFunctions/WaveFunctionFactory.cpp +++ b/src/QMCWaveFunctions/WaveFunctionFactory.cpp @@ -162,7 +162,16 @@ std::unique_ptr WaveFunctionFactory::buildTWF(xmlNodePtr cur) if (!vp_file_to_load.empty()) { app_log() << " Reading variational parameters from " << vp_file_to_load << std::endl; - dummy.readFromHDF(vp_file_to_load); + + hdf_archive hin; + dummy.readFromHDF(vp_file_to_load, hin); + UniqueOptObjRefs opt_obj_refs = targetPsi->extractOptimizableObjectRefs(); + for (auto opt_obj : opt_obj_refs) + opt_obj.get().readExtraParameters(hin); + + // Get the latest values of the parameters for dummy so the following resetParameters + // doesn't mess up the rotation + targetPsi->checkInVariables(dummy); } targetPsi->resetParameters(dummy); From 98c2706abbde470a6fc5a3ccfb91e726975c59f6 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 18:48:41 -0600 Subject: [PATCH 06/19] Only apply rotation on one thread Now the stored coefficient are a shared pointer, only perform the rotation on a single thread. --- src/QMCWaveFunctions/RotatedSPOs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 0687766219..04f5d10c59 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -137,7 +137,10 @@ void RotatedSPOs::resetParametersExclusive(const opt_variables_type& active) old_param[i] = myVarsFull[i]; } - apply_delta_rotation(delta_param, old_param, new_param); + if (use_this_copy_to_apply_rotation_) + { + apply_delta_rotation(delta_param, old_param, new_param); + } // Save the active params for (int i = 0; i < m_act_rot_inds.size(); i++) From c8077c325ab5d0e5583b79d51894ec55fbe3be52 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 30 Nov 2022 20:37:29 -0600 Subject: [PATCH 07/19] Allow global rotation method in input file Hack to specify the rotation method in the input file. Default is history list. Use 'optimize="global"' to use global rotation. --- src/QMCWaveFunctions/RotatedSPOs.cpp | 1 + src/QMCWaveFunctions/RotatedSPOs.h | 5 ++++- src/QMCWaveFunctions/SPOSetBuilder.cpp | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 04f5d10c59..de8a237529 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -1428,6 +1428,7 @@ std::unique_ptr RotatedSPOs::makeClone() const myclone->myVars = this->myVars; myclone->history_params_ = this->history_params_; myclone->myVarsFull = this->myVarsFull; + myclone->use_global_rot_ = this->use_global_rot_; // use_this_copy_to_apply_rotation_ is not copied diff --git a/src/QMCWaveFunctions/RotatedSPOs.h b/src/QMCWaveFunctions/RotatedSPOs.h index 61a8d2dd28..b2d7a1e245 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.h +++ b/src/QMCWaveFunctions/RotatedSPOs.h @@ -36,7 +36,6 @@ class RotatedSPOs : public SPOSet, public OptimizableObject // Active orbital rotation parameter indices RotationIndices m_act_rot_inds; - RotationIndices m_full_rot_inds; // Construct a list of the matrix indices for non-zero rotation parameters. @@ -328,6 +327,10 @@ class RotatedSPOs : public SPOSet, public OptimizableObject // void evaluateThirdDeriv(const ParticleSet& P, int first, int last, GGGMatrix& grad_grad_grad_logdet) // {Phi->evaluateThridDeriv(P, first, last, grad_grad_grad_logdet); } + // + void set_use_global_rotation() { + use_global_rot_ = true; + } private: /// true if SPO parameters (orbital rotation parameters) have been supplied by input diff --git a/src/QMCWaveFunctions/SPOSetBuilder.cpp b/src/QMCWaveFunctions/SPOSetBuilder.cpp index 72a447e295..31c6992977 100644 --- a/src/QMCWaveFunctions/SPOSetBuilder.cpp +++ b/src/QMCWaveFunctions/SPOSetBuilder.cpp @@ -89,7 +89,7 @@ std::unique_ptr SPOSetBuilder::createSPOSet(xmlNodePtr cur) if (!sposet) myComm->barrier_and_abort("SPOSetBuilder::createSPOSet sposet creation failed"); - if (optimize == "rotation" || optimize == "yes") + if (optimize == "rotation" || optimize == "yes" || optimize == "global") { #ifdef QMC_COMPLEX app_error() << "Orbital optimization via rotation doesn't support complex wavefunction yet.\n"; @@ -103,6 +103,8 @@ std::unique_ptr SPOSetBuilder::createSPOSet(xmlNodePtr cur) myComm->barrier_and_abort("Orbital rotation not supported with '" + sposet_ref.getName() + "' of type '" + sposet_ref.getClassName() + "'."); auto rot_spo = std::make_unique(sposet_ref.getName(), std::move(sposet)); + if (optimize=="global") + rot_spo->set_use_global_rotation(); xmlNodePtr tcur = cur->xmlChildrenNode; while (tcur != NULL) { From 714237e3611bf321cfa502bff12056effb48a758 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Sun, 4 Dec 2022 17:09:00 +0000 Subject: [PATCH 08/19] Set up full rotation matrix for multi-det Otherwise an assert triggers with global rotation and multi-det. --- .../Fermion/MultiDiracDeterminant.cpp | 14 +++++++++++++- src/QMCWaveFunctions/RotatedSPOs.cpp | 8 +++++--- src/QMCWaveFunctions/RotatedSPOs.h | 2 +- src/QMCWaveFunctions/SPOSet.h | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/QMCWaveFunctions/Fermion/MultiDiracDeterminant.cpp b/src/QMCWaveFunctions/Fermion/MultiDiracDeterminant.cpp index 4519289cef..0c8471d756 100644 --- a/src/QMCWaveFunctions/Fermion/MultiDiracDeterminant.cpp +++ b/src/QMCWaveFunctions/Fermion/MultiDiracDeterminant.cpp @@ -787,6 +787,7 @@ void MultiDiracDeterminant::buildOptVariables(std::vector& C2node) // create active rotation parameter indices std::vector> m_act_rot_inds; + std::vector> other_rot_inds; for (int i = 0; i < nmo; i++) for (int j = i + 1; j < nmo; j++) @@ -802,10 +803,21 @@ void MultiDiracDeterminant::buildOptVariables(std::vector& C2node) int, int>(i, j)); // orbital rotation parameter accepted as long as rotation isn't core-core or virtual-virtual + } else { + other_rot_inds.push_back(std::pair(i,j)); } } - Phi->buildOptVariables(m_act_rot_inds); + std::vector> full_rot_inds; + // copy the adjustable rotations first + full_rot_inds = m_act_rot_inds; + // add the other rotations later + full_rot_inds = m_act_rot_inds; + for (int i = 0; i < other_rot_inds.size(); i++) { + full_rot_inds.push_back(other_rot_inds[i]); + } + + Phi->buildOptVariables(m_act_rot_inds, full_rot_inds); } int MultiDiracDeterminant::build_occ_vec(const OffloadVector& data, diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index de8a237529..c7cd96b9d4 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -290,20 +290,22 @@ void RotatedSPOs::buildOptVariables(const size_t nel) createRotationIndices(nel, nmo, created_m_act_rot_inds); - createRotationIndicesFull(nel, nmo, m_full_rot_inds); + RotationIndices created_full_rot_inds; + createRotationIndicesFull(nel, nmo, created_full_rot_inds); - buildOptVariables(created_m_act_rot_inds); + buildOptVariables(created_m_act_rot_inds, created_full_rot_inds); } #endif } -void RotatedSPOs::buildOptVariables(const RotationIndices& rotations) +void RotatedSPOs::buildOptVariables(const RotationIndices& rotations, const RotationIndices& full_rotations) { #if !defined(QMC_COMPLEX) const size_t nmo = Phi->getOrbitalSetSize(); // create active rotations m_act_rot_inds = rotations; + m_full_rot_inds = full_rotations; if (use_global_rot_) { diff --git a/src/QMCWaveFunctions/RotatedSPOs.h b/src/QMCWaveFunctions/RotatedSPOs.h index b2d7a1e245..7f22500a02 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.h +++ b/src/QMCWaveFunctions/RotatedSPOs.h @@ -107,7 +107,7 @@ class RotatedSPOs : public SPOSet, public OptimizableObject void buildOptVariables(size_t nel) override; // For the MSD case rotations must be created in MultiSlaterDetTableMethod class - void buildOptVariables(const RotationIndices& rotations) override; + void buildOptVariables(const RotationIndices& rotations, const RotationIndices& full_rotations) override; void evaluateDerivatives(ParticleSet& P, diff --git a/src/QMCWaveFunctions/SPOSet.h b/src/QMCWaveFunctions/SPOSet.h index a4ec7042c3..74c6a25171 100644 --- a/src/QMCWaveFunctions/SPOSet.h +++ b/src/QMCWaveFunctions/SPOSet.h @@ -114,7 +114,7 @@ class SPOSet : public QMCTraits // Single Slater creation virtual void buildOptVariables(const size_t nel) {} // For the MSD case rotations must be created in MultiSlaterDetTableMethod class - virtual void buildOptVariables(const std::vector>& rotations) {} + virtual void buildOptVariables(const std::vector>& rotations, const std::vector>& full_rotations) {} /// return true if this SPOSet can be wrappered by RotatedSPO virtual bool isRotationSupported() const { return false; } /// store parameters before getting destroyed by rotation. From 53d2506e1f388ca185c6136b6e7efc3d05fae930 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 21 Dec 2022 17:00:59 -0600 Subject: [PATCH 09/19] Enable orbital rotation derivatives for single det This is a copy and paste to get *something* working for the single determinant case. --- .../Fermion/DiracDeterminant.cpp | 8 ++ .../Fermion/DiracDeterminant.h | 5 + src/QMCWaveFunctions/RotatedSPOs.cpp | 98 +++++++++++++++++++ src/QMCWaveFunctions/RotatedSPOs.h | 6 ++ src/QMCWaveFunctions/SPOSet.cpp | 12 +++ src/QMCWaveFunctions/SPOSet.h | 6 ++ 6 files changed, 135 insertions(+) diff --git a/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp b/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp index 57da4f81e0..547ad4366f 100644 --- a/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp +++ b/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp @@ -673,6 +673,14 @@ void DiracDeterminant::evaluateDerivatives(ParticleSet& P, Phi->evaluateDerivatives(P, active, dlogpsi, dhpsioverpsi, FirstIndex, LastIndex); } +template +void DiracDeterminant::evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& active, + Vector& dlogpsi) +{ + Phi->evaluateDerivativesWF(P, active, dlogpsi, FirstIndex, LastIndex); +} + template std::unique_ptr DiracDeterminant::makeCopy(std::unique_ptr&& spo) const { diff --git a/src/QMCWaveFunctions/Fermion/DiracDeterminant.h b/src/QMCWaveFunctions/Fermion/DiracDeterminant.h index 981c3f05f8..436909876c 100644 --- a/src/QMCWaveFunctions/Fermion/DiracDeterminant.h +++ b/src/QMCWaveFunctions/Fermion/DiracDeterminant.h @@ -77,6 +77,11 @@ class DiracDeterminant : public DiracDeterminantBase Vector& dlogpsi, Vector& dhpsioverpsi) override; + void evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi) override; + + void registerData(ParticleSet& P, WFBufferType& buf) override; void updateAfterSweep(const ParticleSet& P, ParticleSet::ParticleGradient& G, ParticleSet::ParticleLaplacian& L); diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index de8a237529..db6fd6ca3b 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -694,6 +694,104 @@ void RotatedSPOs::evaluateDerivatives(ParticleSet& P, } } +void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) +{ + const size_t nel = LastIndex - FirstIndex; + const size_t nmo = Phi->getOrbitalSetSize(); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART1 + myG_temp.resize(nel); + myG_J.resize(nel); + myL_temp.resize(nel); + myL_J.resize(nel); + + myG_temp = 0; + myG_J = 0; + myL_temp = 0; + myL_J = 0; + + Bbar.resize(nel, nmo); + psiM_inv.resize(nel, nel); + psiM_all.resize(nel, nmo); + dpsiM_all.resize(nel, nmo); + d2psiM_all.resize(nel, nmo); + + Bbar = 0; + psiM_inv = 0; + psiM_all = 0; + dpsiM_all = 0; + d2psiM_all = 0; + + + Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all); + + for (int i = 0; i < nel; i++) + for (int j = 0; j < nel; j++) + psiM_inv(i, j) = psiM_all(i, j); + + Invert(psiM_inv.data(), nel, nel); + + //current value of Gradient and Laplacian + // gradient components + for (int a = 0; a < nel; a++) + for (int i = 0; i < nel; i++) + for (int k = 0; k < 3; k++) + myG_temp[a][k] += psiM_inv(i, a) * dpsiM_all(a, i)[k]; + // laplacian components + for (int a = 0; a < nel; a++) + { + for (int i = 0; i < nel; i++) + myL_temp[a] += psiM_inv(i, a) * d2psiM_all(a, i); + } + + // calculation of myG_J which will be used to represent \frac{\nabla\psi_{J}}{\psi_{J}} + // calculation of myL_J will be used to represent \frac{\nabla^2\psi_{J}}{\psi_{J}} + // IMPORTANT NOTE: The value of P.L holds \nabla^2 ln[\psi] but we need \frac{\nabla^2 \psi}{\psi} and this is what myL_J will hold + for (int a = 0, iat = FirstIndex; a < nel; a++, iat++) + { + myG_J[a] = (P.G[iat] - myG_temp[a]); + myL_J[a] = (P.L[iat] + dot(P.G[iat], P.G[iat]) - myL_temp[a]); + } + //possibly replace wit BLAS calls + for (int i = 0; i < nel; i++) + for (int j = 0; j < nmo; j++) + Bbar(i, j) = d2psiM_all(i, j) + 2 * dot(myG_J[i], dpsiM_all(i, j)) + myL_J[i] * psiM_all(i, j); + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART2 + const ValueType* const A(psiM_all.data()); + const ValueType* const Ainv(psiM_inv.data()); + const ValueType* const B(Bbar.data()); + SPOSet::ValueMatrix T; + SPOSet::ValueMatrix Y1; + SPOSet::ValueMatrix Y2; + SPOSet::ValueMatrix Y3; + SPOSet::ValueMatrix Y4; + T.resize(nel, nmo); + Y1.resize(nel, nel); + Y2.resize(nel, nmo); + Y3.resize(nel, nmo); + Y4.resize(nel, nmo); + + + BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo); + + //possibly replace with BLAS call + Y4 = Y3 - Y2; + + for (int i = 0; i < m_act_rot_inds.size(); i++) + { + int kk = myVars.where(i); + const int p = m_act_rot_inds.at(i).first; + const int q = m_act_rot_inds.at(i).second; + dlogpsi[kk] = T(p, q); + } +} + void RotatedSPOs::evaluateDerivatives(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi, diff --git a/src/QMCWaveFunctions/RotatedSPOs.h b/src/QMCWaveFunctions/RotatedSPOs.h index b2d7a1e245..96b4f8d3f8 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.h +++ b/src/QMCWaveFunctions/RotatedSPOs.h @@ -117,6 +117,12 @@ class RotatedSPOs : public SPOSet, public OptimizableObject const int& FirstIndex, const int& LastIndex) override; + void evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) override; + void evaluateDerivatives(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi, diff --git a/src/QMCWaveFunctions/SPOSet.cpp b/src/QMCWaveFunctions/SPOSet.cpp index 447d262015..2a68502acb 100644 --- a/src/QMCWaveFunctions/SPOSet.cpp +++ b/src/QMCWaveFunctions/SPOSet.cpp @@ -266,6 +266,18 @@ void SPOSet::evaluateDerivatives(ParticleSet& P, "must be overloaded when the SPOSet is optimizable."); } +void SPOSet::evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) +{ + if (isOptimizable()) + throw std::logic_error("Bug!! " + getClassName() + + "::evaluateDerivativesWF " + "must be overloaded when the SPOSet is optimizable."); +} + /** Evaluate the derivative of the optimized orbitals with respect to the parameters * this is used only for MSD, to be refined for better serving both single and multi SD */ diff --git a/src/QMCWaveFunctions/SPOSet.h b/src/QMCWaveFunctions/SPOSet.h index a4ec7042c3..760b122da9 100644 --- a/src/QMCWaveFunctions/SPOSet.h +++ b/src/QMCWaveFunctions/SPOSet.h @@ -129,6 +129,12 @@ class SPOSet : public QMCTraits const int& FirstIndex, const int& LastIndex); + virtual void evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex); + /** Evaluate the derivative of the optimized orbitals with respect to the parameters * this is used only for MSD, to be refined for better serving both single and multi SD */ From 6096261562500b644a142572295e20af5cb337d8 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 11 Jan 2023 15:41:59 -0600 Subject: [PATCH 10/19] Add Hamiltonian parameter derivative test --- src/QMCHamiltonians/tests/CMakeLists.txt | 4 + .../tests/test_RotatedSPOs_NLPP.cpp | 693 ++++++++++++++++++ 2 files changed, 697 insertions(+) create mode 100644 src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp diff --git a/src/QMCHamiltonians/tests/CMakeLists.txt b/src/QMCHamiltonians/tests/CMakeLists.txt index b51cfa9233..4278e2b62d 100644 --- a/src/QMCHamiltonians/tests/CMakeLists.txt +++ b/src/QMCHamiltonians/tests/CMakeLists.txt @@ -27,6 +27,7 @@ set(HAM_SRCS test_SkAllEstimator.cpp test_QMCHamiltonian.cpp test_ObservableHelper.cpp + test_RotatedSPOs_NLPP.cpp test_Listener.cpp) @@ -51,6 +52,9 @@ foreach(fname C.BFD.xml Na.BFD.xml so_ecp_test.xml C.ccECP.xml N.ccECP.xml) maybe_symlink(${qmcpack_SOURCE_DIR}/tests/pseudopotentials_for_tests/${fname} ${UTEST_DIR}/${fname}) endforeach() +maybe_symlink(${qmcpack_SOURCE_DIR}/tests/solids/hcpBe_1x1x1_pp/Be.BFD.xml ${UTEST_DIR}/Be.BFD.xml) +maybe_symlink(${qmcpack_SOURCE_DIR}/tests/solids/hcpBe_1x1x1_pp/pwscf.pwscf.h5 ${UTEST_DIR}/hcpBe.pwscf.h5) + foreach(CATEGORY coulomb force ham ewald2d) set(UTEST_EXE test_${SRC_DIR}_${CATEGORY}) set(UTEST_NAME deterministic-unit_${UTEST_EXE}) diff --git a/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp b/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp new file mode 100644 index 0000000000..2132729760 --- /dev/null +++ b/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp @@ -0,0 +1,693 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2022 QMCPACK developers. +// +// File developed by: Joshua Townsend, jptowns@sandia.gov, Sandia National Laboratories +// +// File created by: Joshua Townsend, jptowns@sandia.gov, Sandia National Laboratories +////////////////////////////////////////////////////////////////////////////////////// + +#include "catch.hpp" + +#include "type_traits/template_types.hpp" +#include "type_traits/ConvertToReal.h" +#include "OhmmsData/Libxml2Doc.h" +#include "OhmmsPETE/OhmmsMatrix.h" +#include "Particle/ParticleSet.h" +#include "Particle/ParticleSetPool.h" +#include "QMCWaveFunctions/WaveFunctionPool.h" +#include "QMCWaveFunctions/WaveFunctionComponent.h" +#include "QMCWaveFunctions/EinsplineSetBuilder.h" +#include "QMCWaveFunctions/RotatedSPOs.h" + +#include "QMCHamiltonians/HamiltonianFactory.h" + +#include +#include +#include + +using std::string; + +namespace qmcplusplus +{ + + + +TEST_CASE("RotatedSPOs SplineR2R hcpBe values single det", "[wavefunction]") +{ + using RealType = QMCTraits::RealType; + + /* + BEGIN Boilerplate stuff to make a simple SPOSet. Copied from test_einset.cpp + */ + + Communicate* c = OHMMS::Controller; + + ParticleSetPool pp(c); + + //setupParticleSetPoolHe(pp); + + ParticleSet::ParticleLayout lattice; + lattice.R(0, 0) = 4.32747284; + lattice.R(0, 1) = 0.00000000; + lattice.R(0, 2) = 0.00000000; + lattice.R(1, 0) = -2.16373642; + lattice.R(1, 1) = 3.74770142; + lattice.R(1, 2) = 0.00000000; + lattice.R(2, 0) = 0.00000000; + lattice.R(2, 1) = 0.00000000; + lattice.R(2, 2) = 6.78114995; + + lattice.BoxBConds = false; + lattice.reset(); + + + + + const SimulationCell simulation_cell(lattice); + pp.setSimulationCell(simulation_cell); + auto elec_ptr = std::make_unique(pp.getSimulationCell()); + auto& elec(*elec_ptr); + auto ions_uptr = std::make_unique(pp.getSimulationCell()); + ParticleSet& ions(*ions_uptr); + //LRCoulombSingleton::CoulombHandler = std::make_unique(ions); + //LRCoulombSingleton::CoulombHandler->initBreakup(elec); + + elec.setName("e"); + elec.create({1,1}); + elec.R[0] = {0.1, 0.2, 0.3}; + elec.R[1] = {1.0, 1.0, 1.0}; + + SpeciesSet& especies = elec.getSpeciesSet(); + int upIdx = especies.addSpecies("u"); + int chargeIdx = especies.addAttribute("charge"); + int massIdx = especies.addAttribute("mass"); + especies(chargeIdx, upIdx) = -1; + especies(massIdx, upIdx) = 1.0; + int dnIdx = especies.addSpecies("d"); + especies(chargeIdx, dnIdx) = -1; + especies(massIdx, dnIdx) = 1.0; + elec.resetGroups(); // need to set Mass so + + + elec.createSK(); + pp.addParticleSet(std::move(elec_ptr)); + + ions.setName("ion0"); + ions.create({1}); + ions.R[0][0] = 0.0; + ions.R[0][1] = 0.0; + ions.R[0][2] = 0.0; + + SpeciesSet& tspecies = ions.getSpeciesSet(); + int CIdx = tspecies.addSpecies("Be"); + int CchargeIdx = tspecies.addAttribute("charge"); + int CatomicnumberIdx = tspecies.addAttribute("atomicnumber"); + tspecies(CchargeIdx, CIdx) = 2; + tspecies(CatomicnumberIdx, CIdx) = 4; + + ions.createSK(); + + pp.addParticleSet(std::move(ions_uptr)); + + WaveFunctionPool wp(pp, c); + REQUIRE(wp.empty() == true); + + const char* wf_input = R"( + + + + + + + + + + + + + + + + + )"; + + Libxml2Document doc; + bool okay = doc.parseFromString(wf_input); + REQUIRE(okay); + + xmlNodePtr root = doc.getRoot(); + + wp.put(root); + TrialWaveFunction* psi = wp.getWaveFunction("psi0"); + REQUIRE(psi != nullptr); + REQUIRE(psi->getOrbitals().size() == 1); + + const char *ham_input = R"( + + + + + + )"; + + + //HamiltonianFactory::PSetMap particle_set_map; + //particle_set_map.emplace(ions.getName(), std::move(ions_uptr)); + //particle_set_map.emplace(elec.getName(), std::move(elec_ptr)); + + //HamiltonianFactory::PsiPoolType psi_map; + //psi_map.emplace("psi0", psi); + + //HamiltonianFactory hf("h0", elec, particle_set_map, psi_map, c); + HamiltonianFactory hf("h0", elec, pp.getPool(), wp.getPool(), c); + + Libxml2Document doc2; + bool okay2 = doc2.parseFromString(ham_input); + REQUIRE(okay2); + + xmlNodePtr root2 = doc2.getRoot(); + hf.put(root2); + + opt_variables_type opt_vars; + psi->checkInVariables(opt_vars); + opt_vars.resetIndex(); + psi->checkOutVariables(opt_vars); + psi->resetParameters(opt_vars); + + elec.update(); + ions.update(); + + double logval = psi->evaluateLog(elec); + CHECK(logval == Approx(-1.2865633501081344)); + + + CHECK(elec.G[0][0] == ValueApprox(0.54752651)); + CHECK(elec.L[0] == ValueApprox(11.066512459947848)); + CHECK(elec.L[1] == ValueApprox(-0.4831061477045371)); + + using ValueType = QMCTraits::ValueType; + Vector dlogpsi(2); + Vector dhpsioverpsi(2); + psi->evaluateDerivatives(elec, opt_vars, dlogpsi, dhpsioverpsi); + + CHECK(dlogpsi[0] == ValueApprox(-2.97750823)); + CHECK(dlogpsi[1] == ValueApprox(-1.06146356)); + CHECK(dhpsioverpsi[0] == ValueApprox(-36.71707483)); + CHECK(dhpsioverpsi[1] == ValueApprox(-0.35274333)); + + QMCHamiltonian* h = hf.getH(); + RandomGenerator myrng; + h->setRandomGenerator(&myrng); + + app_log() << "H size = " << h->size() << std::endl; + h->evaluate(elec); + double loc_e = h->getLocalEnergy(); + double ke = h->getKineticEnergy(); + double loc_pot = h->getLocalPotential(); + std::cout << std::setprecision(16) << std::endl; + std::cout << "local e = " << loc_e << std::endl; + std::cout << "kinetic e = " << ke << std::endl; + std::cout << "local potential = " << loc_pot << std::endl; + // without e-n or pp + CHECK(ke == Approx(-6.818620576308302)); + CHECK(loc_e == Approx(-3.562354739253797)); + + Vector dlogpsi2(2); + Vector dhpsioverpsi2(2); + + h->evaluateValueAndDerivatives(elec, opt_vars, dlogpsi2, dhpsioverpsi2); + CHECK(dlogpsi2[0] == ValueApprox(-2.97750823)); + CHECK(dlogpsi2[1] == ValueApprox(-1.06146356)); + + // No NLPP + //CHECK(dhpsioverpsi2[0] == ValueApprox(-0.00043764)); + //CHECK(dhpsioverpsi2[1] == ValueApprox(-0.35274333)); + // With NLPP + CHECK(dhpsioverpsi2[0] == ValueApprox(-5.45054261)); + CHECK(dhpsioverpsi2[1] == ValueApprox(-0.34818307)); +} + +TEST_CASE("RotatedSPOs SplineR2R hcpBe values multi det", "[wavefunction]") +{ + using RealType = QMCTraits::RealType; + + /* + BEGIN Boilerplate stuff to make a simple SPOSet. Copied from test_einset.cpp + */ + + Communicate* c = OHMMS::Controller; + + ParticleSetPool pp(c); + + //setupParticleSetPoolHe(pp); + + ParticleSet::ParticleLayout lattice; + lattice.R(0, 0) = 4.32747284; + lattice.R(0, 1) = 0.00000000; + lattice.R(0, 2) = 0.00000000; + lattice.R(1, 0) = -2.16373642; + lattice.R(1, 1) = 3.74770142; + lattice.R(1, 2) = 0.00000000; + lattice.R(2, 0) = 0.00000000; + lattice.R(2, 1) = 0.00000000; + lattice.R(2, 2) = 6.78114995; + + + const SimulationCell simulation_cell(lattice); + pp.setSimulationCell(simulation_cell); + auto elec_ptr = std::make_unique(pp.getSimulationCell()); + auto& elec(*elec_ptr); + auto ions_uptr = std::make_unique(pp.getSimulationCell()); + ParticleSet& ions(*ions_uptr); + + elec.setName("e"); + elec.create({1,1}); + elec.R[0] = {0.1, 0.2, 0.3}; + elec.R[1] = {1.0, 1.0, 1.0}; + + SpeciesSet& especies = elec.getSpeciesSet(); + int upIdx = especies.addSpecies("u"); + int chargeIdx = especies.addAttribute("charge"); + int massIdx = especies.addAttribute("mass"); + especies(chargeIdx, upIdx) = -1; + especies(massIdx, upIdx) = 1.0; + int dnIdx = especies.addSpecies("d"); + especies(chargeIdx, dnIdx) = -1; + especies(massIdx, dnIdx) = 1.0; + elec.resetGroups(); // need to set Mass so + + + pp.addParticleSet(std::move(elec_ptr)); + + ions.setName("ion0"); + ions.create({1}); + ions.R[0][0] = 0.0; + ions.R[0][1] = 0.0; + ions.R[0][2] = 0.0; + + SpeciesSet& tspecies = ions.getSpeciesSet(); + int CIdx = tspecies.addSpecies("Be"); + int CchargeIdx = tspecies.addAttribute("charge"); + int CatomicnumberIdx = tspecies.addAttribute("atomicnumber"); + tspecies(CchargeIdx, CIdx) = 2; + tspecies(CatomicnumberIdx, CIdx) = 4; + + + pp.addParticleSet(std::move(ions_uptr)); + + WaveFunctionPool wp(pp, c); + REQUIRE(wp.empty() == true); + + const char* wf_input = R"( + + + + + + + + + + + + + + + + + + )"; + + Libxml2Document doc; + bool okay = doc.parseFromString(wf_input); + REQUIRE(okay); + + xmlNodePtr root = doc.getRoot(); + + wp.put(root); + TrialWaveFunction* psi = wp.getWaveFunction("psi0"); + REQUIRE(psi != nullptr); + REQUIRE(psi->getOrbitals().size() == 1); + + + const char *ham_input = R"( + + + + + + )"; + + + HamiltonianFactory hf("h0", elec, pp.getPool(), wp.getPool(), c); + + Libxml2Document doc2; + bool okay2 = doc2.parseFromString(ham_input); + REQUIRE(okay2); + + xmlNodePtr root2 = doc2.getRoot(); + hf.put(root2); + + opt_variables_type opt_vars; + psi->checkInVariables(opt_vars); + opt_vars.resetIndex(); + psi->checkOutVariables(opt_vars); + psi->resetParameters(opt_vars); + + elec.update(); + + double logval = psi->evaluateLog(elec); + CHECK(logval == Approx(-1.2865633501081344)); + + CHECK(elec.G[0][0] == ValueApprox(0.54752651)); + CHECK(elec.L[0] == ValueApprox(11.066512459947848)); + CHECK(elec.L[1] == ValueApprox(-0.4831061477045371)); + + + using ValueType = QMCTraits::ValueType; + Vector dlogpsi(2); + Vector dhpsioverpsi(2); + psi->evaluateDerivatives(elec, opt_vars, dlogpsi, dhpsioverpsi); + + CHECK(dlogpsi[0] == ValueApprox(-2.97750823)); + CHECK(dlogpsi[1] == ValueApprox(-1.06146356)); + CHECK(dhpsioverpsi[0] == ValueApprox(-36.71707483)); + CHECK(dhpsioverpsi[1] == ValueApprox(-0.35274333)); + + RefVectorWithLeader wf_list(*psi, {*psi}); + RefVectorWithLeader p_list(elec, {elec}); + + // Test list with one wavefunction + + int nparam = 2; + int nentry = 1; + RecordArray dlogpsi_list(nentry, nparam); + RecordArray dhpsi_over_psi_list(nentry, nparam); + + TrialWaveFunction::mw_evaluateParameterDerivatives(wf_list, p_list, opt_vars, dlogpsi_list, dhpsi_over_psi_list); + + CHECK(dlogpsi_list[0][0] == dlogpsi[0]); + CHECK(dlogpsi_list[0][1] == dlogpsi[1]); + CHECK(dhpsi_over_psi_list[0][0] == dhpsioverpsi[0]); + CHECK(dhpsi_over_psi_list[0][1] == dhpsioverpsi[1]); + + + QMCHamiltonian* h = hf.getH(); + RandomGenerator myrng; + h->setRandomGenerator(&myrng); + + app_log() << "H size = " << h->size() << std::endl; + h->evaluate(elec); + double loc_e = h->getLocalEnergy(); + double ke = h->getKineticEnergy(); + double loc_pot = h->getLocalPotential(); + std::cout << std::setprecision(16) << std::endl; + std::cout << "local e = " << loc_e << std::endl; + std::cout << "kinetic e = " << ke << std::endl; + std::cout << "local potential = " << loc_pot << std::endl; + // without e-n or pp + CHECK(ke == Approx(-6.818620576308302)); + CHECK(loc_e == Approx(-3.562354739253797)); + + auto *localECP_H = h->getHamiltonian("LocalECP"); + double local_pp = localECP_H->evaluate(elec); + std::cout << "local pp = " << local_pp << std::endl; + + Vector dlogpsi2(2); + Vector dhpsioverpsi2(2); + + h->evaluateValueAndDerivatives(elec, opt_vars, dlogpsi2, dhpsioverpsi2); + //CHECK(dlogpsi2[0] == ValueApprox(-2.97750823)); + //CHECK(dlogpsi2[1] == ValueApprox(-1.06146356)); + CHECK(dlogpsi2[0] == dlogpsi[0]); + CHECK(dlogpsi2[1] == dlogpsi[1]); + + // With NLPP + CHECK(dhpsioverpsi2[0] == ValueApprox(-5.45054261)); + CHECK(dhpsioverpsi2[1] == ValueApprox(-0.34818307)); + + // batched interface + RefVectorWithLeader h_list(*h, {*h}); + + RecordArray dlogpsi_list2(nentry, nparam); + RecordArray dhpsi_over_psi_list2(nentry, nparam); + + h->mw_evaluateValueAndDerivatives(h_list, wf_list, p_list, opt_vars, dlogpsi_list2, dhpsi_over_psi_list2); + + CHECK(dlogpsi_list2[0][0] == ValueApprox(-2.97750823)); + CHECK(dlogpsi_list2[0][1] == ValueApprox(-1.06146356)); + + CHECK(dhpsi_over_psi_list2[0][0] == ValueApprox(-5.45054261)); + CHECK(dhpsi_over_psi_list2[0][1] == ValueApprox(-0.34818307)); + + +#if 0 + elec.R[0] = {2.0, 2.0, 4.0}; + + elec.R[1] = {2.0, 4.0, 4.0}; + elec.update(); + h->evaluate(elec); + ke = h->getKineticEnergy(); + std::cout << "second ke = " << ke << std::endl; + local_pp = localECP_H->evaluate(elec); + std::cout << "second local pp = " << local_pp << std::endl; +#endif +} + +TEST_CASE("RotatedSPOs SplineR2R hcpBe rot1 values multi det", "[wavefunction]") +{ + using RealType = QMCTraits::RealType; + + /* + BEGIN Boilerplate stuff to make a simple SPOSet. Copied from test_einset.cpp + */ + + Communicate* c = OHMMS::Controller; + + ParticleSetPool pp(c); + + //setupParticleSetPoolHe(pp); + + ParticleSet::ParticleLayout lattice; + lattice.R(0, 0) = 4.32747284; + lattice.R(0, 1) = 0.00000000; + lattice.R(0, 2) = 0.00000000; + lattice.R(1, 0) = -2.16373642; + lattice.R(1, 1) = 3.74770142; + lattice.R(1, 2) = 0.00000000; + lattice.R(2, 0) = 0.00000000; + lattice.R(2, 1) = 0.00000000; + lattice.R(2, 2) = 6.78114995; + + + const SimulationCell simulation_cell(lattice); + pp.setSimulationCell(simulation_cell); + auto elec_ptr = std::make_unique(pp.getSimulationCell()); + auto& elec(*elec_ptr); + auto ions_uptr = std::make_unique(pp.getSimulationCell()); + ParticleSet& ions(*ions_uptr); + + elec.setName("e"); + elec.create({1,1}); + elec.R[0] = {0.1, 0.2, 0.3}; + elec.R[1] = {1.0, 1.0, 1.0}; + + SpeciesSet& especies = elec.getSpeciesSet(); + int upIdx = especies.addSpecies("u"); + int chargeIdx = especies.addAttribute("charge"); + int massIdx = especies.addAttribute("mass"); + especies(chargeIdx, upIdx) = -1; + especies(massIdx, upIdx) = 1.0; + int dnIdx = especies.addSpecies("d"); + especies(chargeIdx, dnIdx) = -1; + especies(massIdx, dnIdx) = 1.0; + elec.resetGroups(); // need to set Mass so + + + pp.addParticleSet(std::move(elec_ptr)); + + ions.setName("ion0"); + ions.create({1}); + ions.R[0][0] = 0.0; + ions.R[0][1] = 0.0; + ions.R[0][2] = 0.0; + + SpeciesSet& tspecies = ions.getSpeciesSet(); + int CIdx = tspecies.addSpecies("Be"); + int CchargeIdx = tspecies.addAttribute("charge"); + int CatomicnumberIdx = tspecies.addAttribute("atomicnumber"); + tspecies(CchargeIdx, CIdx) = 2; + tspecies(CatomicnumberIdx, CIdx) = 4; + + + pp.addParticleSet(std::move(ions_uptr)); + + WaveFunctionPool wp(pp, c); + REQUIRE(wp.empty() == true); + + const char* wf_input = R"( + + + + 0.1 + + + 0.1 + + + + + + + + + + + + + )"; + + Libxml2Document doc; + bool okay = doc.parseFromString(wf_input); + REQUIRE(okay); + + xmlNodePtr root = doc.getRoot(); + + wp.put(root); + TrialWaveFunction* psi = wp.getWaveFunction("psi0"); + REQUIRE(psi != nullptr); + REQUIRE(psi->getOrbitals().size() == 1); + + + const char *ham_input = R"( + + + + + + )"; + + + HamiltonianFactory hf("h0", elec, pp.getPool(), wp.getPool(), c); + + Libxml2Document doc2; + bool okay2 = doc2.parseFromString(ham_input); + REQUIRE(okay2); + + xmlNodePtr root2 = doc2.getRoot(); + hf.put(root2); + + opt_variables_type opt_vars; + psi->checkInVariables(opt_vars); + opt_vars.resetIndex(); + psi->checkOutVariables(opt_vars); + psi->resetParameters(opt_vars); + + elec.update(); + + double logval = psi->evaluateLog(elec); + CHECK(logval == Approx(-1.7640777829734315)); + + using ValueType = QMCTraits::ValueType; + Vector dlogpsi(2); + Vector dhpsioverpsi(2); + psi->evaluateDerivatives(elec, opt_vars, dlogpsi, dhpsioverpsi); + + CHECK(dlogpsi[0] == ValueApprox(-4.38906396)); + CHECK(dlogpsi[1] == ValueApprox(-1.30028015)); + CHECK(dhpsioverpsi[0] == ValueApprox(-75.41699062082654)); + CHECK(dhpsioverpsi[1] == ValueApprox(-0.446294418102374)); + + RefVectorWithLeader wf_list(*psi, {*psi}); + RefVectorWithLeader p_list(elec, {elec}); + + // Test list with one wavefunction + + int nparam = 2; + int nentry = 1; + RecordArray dlogpsi_list(nentry, nparam); + RecordArray dhpsi_over_psi_list(nentry, nparam); + + TrialWaveFunction::mw_evaluateParameterDerivatives(wf_list, p_list, opt_vars, dlogpsi_list, dhpsi_over_psi_list); + + CHECK(dlogpsi_list[0][0] == Approx(dlogpsi[0])); + CHECK(dlogpsi_list[0][1] == Approx(dlogpsi[1])); + CHECK(dhpsi_over_psi_list[0][0] == Approx(dhpsioverpsi[0])); + CHECK(dhpsi_over_psi_list[0][1] == Approx(dhpsioverpsi[1])); + + + QMCHamiltonian* h = hf.getH(); + RandomGenerator myrng; + h->setRandomGenerator(&myrng); + + app_log() << "H size = " << h->size() << std::endl; + h->evaluate(elec); + double loc_e = h->getLocalEnergy(); + double ke = h->getKineticEnergy(); + double loc_pot = h->getLocalPotential(); + std::cout << std::setprecision(16) << std::endl; + std::cout << "local e = " << loc_e << std::endl; + std::cout << "kinetic e = " << ke << std::endl; + std::cout << "local potential = " << loc_pot << std::endl; + // without e-n or pp + CHECK(ke == Approx(-12.111681211640777)); + CHECK(loc_e == Approx(-4.381316707074211)); + + auto *localECP_H = h->getHamiltonian("LocalECP"); + double local_pp = localECP_H->evaluate(elec); + std::cout << "local pp = " << local_pp << std::endl; + + Vector dlogpsi2(2); + Vector dhpsioverpsi2(2); + + h->evaluateValueAndDerivatives(elec, opt_vars, dlogpsi2, dhpsioverpsi2); + CHECK(dlogpsi2[0] == Approx(dlogpsi[0])); + CHECK(dlogpsi2[1] == Approx(dlogpsi[1])); + CHECK(dhpsioverpsi2[0] == Approx(-11.195432172121736)); + CHECK(dhpsioverpsi2[1] == Approx(-0.440524726136756)); + + // batched interface + RefVectorWithLeader h_list(*h, {*h}); + + RecordArray dlogpsi_list2(nentry, nparam); + RecordArray dhpsi_over_psi_list2(nentry, nparam); + + h->mw_evaluateValueAndDerivatives(h_list, wf_list, p_list, opt_vars, dlogpsi_list2, dhpsi_over_psi_list2); + + CHECK(dlogpsi_list2[0][0] == Approx(dlogpsi2[0])); + CHECK(dlogpsi_list2[0][1] == Approx(dlogpsi2[1])); + CHECK(dhpsi_over_psi_list2[0][0] == Approx(dhpsioverpsi2[0])); + CHECK(dhpsi_over_psi_list2[0][1] == Approx(dhpsioverpsi2[1])); + +} + + +} // namespace qmcplusplus From 962194925fd0bb46ec704b1db9b76c092e69b0cd Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 11 Jan 2023 15:45:39 -0600 Subject: [PATCH 11/19] Add evaluateDerivRatios and add parameters --- .../Fermion/DiracDeterminant.cpp | 15 +++++++++++ .../Fermion/DiracDeterminant.h | 12 ++++++--- .../Fermion/MultiSlaterDetTableMethod.cpp | 2 ++ .../Fermion/MultiSlaterDetTableMethod.h | 10 +++---- src/QMCWaveFunctions/Fermion/SlaterDet.cpp | 11 ++++++++ src/QMCWaveFunctions/Fermion/SlaterDet.h | 8 ++++++ src/QMCWaveFunctions/Jastrow/J1OrbitalSoA.h | 2 ++ src/QMCWaveFunctions/Jastrow/JeeIOrbitalSoA.h | 2 ++ .../Jastrow/TwoBodyJastrow.cpp | 2 ++ src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.h | 2 ++ src/QMCWaveFunctions/SPOSet.cpp | 26 ++++++++++++++++--- src/QMCWaveFunctions/SPOSet.h | 24 +++++++++++++---- src/QMCWaveFunctions/TrialWaveFunction.cpp | 4 ++- src/QMCWaveFunctions/TrialWaveFunction.h | 4 ++- .../WaveFunctionComponent.cpp | 2 ++ src/QMCWaveFunctions/WaveFunctionComponent.h | 2 ++ .../tests/test_multi_slater_determinant.cpp | 2 +- .../tests/test_polynomial_eeI_jastrow.cpp | 2 +- 18 files changed, 110 insertions(+), 22 deletions(-) diff --git a/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp b/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp index 547ad4366f..96e700ad49 100644 --- a/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp +++ b/src/QMCWaveFunctions/Fermion/DiracDeterminant.cpp @@ -456,6 +456,21 @@ void DiracDeterminant::mw_evaluateRatios(const RefVectorWithLeader +void DiracDeterminant::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + std::vector& ratios, + Matrix& dratios) +{ + const int WorkingIndex = VP.refPtcl - FirstIndex; + assert(WorkingIndex >= 0); + std::copy_n(psiM[WorkingIndex], invRow.size(), invRow.data()); + Phi->evaluateDerivRatios(VP, P, iel, optvars, psiV, invRow, ratios, dratios, FirstIndex, LastIndex); +} + + template void DiracDeterminant::evaluateRatiosAlltoOne(ParticleSet& P, std::vector& ratios) { diff --git a/src/QMCWaveFunctions/Fermion/DiracDeterminant.h b/src/QMCWaveFunctions/Fermion/DiracDeterminant.h index 436909876c..3e676e3cc3 100644 --- a/src/QMCWaveFunctions/Fermion/DiracDeterminant.h +++ b/src/QMCWaveFunctions/Fermion/DiracDeterminant.h @@ -77,9 +77,7 @@ class DiracDeterminant : public DiracDeterminantBase Vector& dlogpsi, Vector& dhpsioverpsi) override; - void evaluateDerivativesWF(ParticleSet& P, - const opt_variables_type& optvars, - Vector& dlogpsi) override; + void evaluateDerivativesWF(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi) override; void registerData(ParticleSet& P, WFBufferType& buf) override; @@ -114,6 +112,14 @@ class DiracDeterminant : public DiracDeterminantBase const RefVectorWithLeader& vp_list, std::vector>& ratios) const override; + void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + std::vector& ratios, + Matrix& dratios) override; + + PsiValueType ratioGrad(ParticleSet& P, int iat, GradType& grad_iat) override; PsiValueType ratioGradWithSpin(ParticleSet& P, int iat, GradType& grad_iat, ComplexType& spingrad) final; diff --git a/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.cpp b/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.cpp index a99dc72525..41ff996f4d 100644 --- a/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.cpp +++ b/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.cpp @@ -1016,6 +1016,8 @@ void MultiSlaterDetTableMethod::evaluateDerivativesMSD(const PsiValueType& multi } void MultiSlaterDetTableMethod::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) diff --git a/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.h b/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.h index b7a3fc7b82..f7eece0d59 100644 --- a/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.h +++ b/src/QMCWaveFunctions/Fermion/MultiSlaterDetTableMethod.h @@ -184,11 +184,11 @@ class MultiSlaterDetTableMethod : public WaveFunctionComponent, public Optimizab Vector& dlogpsi, Vector& dhpsioverpsi) override; - void evaluateDerivativesWF(ParticleSet& P, - const opt_variables_type& optvars, - Vector& dlogpsi) override; + void evaluateDerivativesWF(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi) override; void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) override; @@ -265,9 +265,7 @@ class MultiSlaterDetTableMethod : public WaveFunctionComponent, public Optimizab * @param dlogpsi saved derivatives * @param det_id provide this argument to affect determinant group id for virtual moves */ - void evaluateDerivativesMSD(const PsiValueType& multi_det_to_ref, - Vector& dlogpsi, - int det_id = -1) const; + void evaluateDerivativesMSD(const PsiValueType& multi_det_to_ref, Vector& dlogpsi, int det_id = -1) const; /// determinant collection std::vector> Dets; diff --git a/src/QMCWaveFunctions/Fermion/SlaterDet.cpp b/src/QMCWaveFunctions/Fermion/SlaterDet.cpp index f8907bc872..8264f2c060 100644 --- a/src/QMCWaveFunctions/Fermion/SlaterDet.cpp +++ b/src/QMCWaveFunctions/Fermion/SlaterDet.cpp @@ -88,6 +88,17 @@ void SlaterDet::evaluateRatiosAlltoOne(ParticleSet& P, std::vector& r Dets[i]->evaluateRatiosAlltoOne(P, ratios); } +void SlaterDet::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + std::vector& ratios, + Matrix& dratios) +{ + return Dets[getDetID(VP.refPtcl)]->evaluateDerivRatios(VP, P, iel, optvars, ratios, dratios); +} + + SlaterDet::LogValueType SlaterDet::evaluateLog(const ParticleSet& P, ParticleSet::ParticleGradient& G, ParticleSet::ParticleLaplacian& L) diff --git a/src/QMCWaveFunctions/Fermion/SlaterDet.h b/src/QMCWaveFunctions/Fermion/SlaterDet.h index 3bd2102e18..2cb654fdc6 100644 --- a/src/QMCWaveFunctions/Fermion/SlaterDet.h +++ b/src/QMCWaveFunctions/Fermion/SlaterDet.h @@ -109,6 +109,14 @@ class SlaterDet : public WaveFunctionComponent return Dets[getDetID(VP.refPtcl)]->evaluateRatios(VP, ratios); } + void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + std::vector& ratios, + Matrix& dratios) override; + + inline void mw_evaluateRatios(const RefVectorWithLeader& wfc_list, const RefVectorWithLeader& vp_list, std::vector>& ratios) const override diff --git a/src/QMCWaveFunctions/Jastrow/J1OrbitalSoA.h b/src/QMCWaveFunctions/Jastrow/J1OrbitalSoA.h index 7d016c375f..63dc0729ab 100644 --- a/src/QMCWaveFunctions/Jastrow/J1OrbitalSoA.h +++ b/src/QMCWaveFunctions/Jastrow/J1OrbitalSoA.h @@ -561,6 +561,8 @@ class J1OrbitalSoA : public WaveFunctionComponent /**@} */ void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) override diff --git a/src/QMCWaveFunctions/Jastrow/JeeIOrbitalSoA.h b/src/QMCWaveFunctions/Jastrow/JeeIOrbitalSoA.h index ebab63a416..5bfe0d7af4 100644 --- a/src/QMCWaveFunctions/Jastrow/JeeIOrbitalSoA.h +++ b/src/QMCWaveFunctions/Jastrow/JeeIOrbitalSoA.h @@ -948,6 +948,8 @@ class JeeIOrbitalSoA : public WaveFunctionComponent } void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) override diff --git a/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.cpp b/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.cpp index d308e4755e..2e24fc67e6 100644 --- a/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.cpp +++ b/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.cpp @@ -969,6 +969,8 @@ void TwoBodyJastrow::evaluateDerivativesWF(ParticleSet& P, template void TwoBodyJastrow::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) diff --git a/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.h b/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.h index 01301adcfa..940bc703ac 100644 --- a/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.h +++ b/src/QMCWaveFunctions/Jastrow/TwoBodyJastrow.h @@ -259,6 +259,8 @@ class TwoBodyJastrow : public WaveFunctionComponent void evaluateDerivativesWF(ParticleSet& P, const opt_variables_type& active, Vector& dlogpsi) override; void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios) override; diff --git a/src/QMCWaveFunctions/SPOSet.cpp b/src/QMCWaveFunctions/SPOSet.cpp index 2a68502acb..b11afcfe2f 100644 --- a/src/QMCWaveFunctions/SPOSet.cpp +++ b/src/QMCWaveFunctions/SPOSet.cpp @@ -266,11 +266,29 @@ void SPOSet::evaluateDerivatives(ParticleSet& P, "must be overloaded when the SPOSet is optimizable."); } -void SPOSet::evaluateDerivativesWF(ParticleSet& P, +void SPOSet::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, - Vector& dlogpsi, - const int& FirstIndex, - const int& LastIndex) + ValueVector& psi, + const ValueVector& psiinv, + std::vector& ratios, + Matrix& dratios, + int FirstIndex, + int LastIndex) +{ + if (isOptimizable()) + throw std::logic_error("Bug!! " + getClassName() + + "::evaluateDerivRatios " + "must be overloaded when the SPOSet is optimizable."); +} + + +void SPOSet::evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) { if (isOptimizable()) throw std::logic_error("Bug!! " + getClassName() + diff --git a/src/QMCWaveFunctions/SPOSet.h b/src/QMCWaveFunctions/SPOSet.h index 07cfcf3708..8e69406aad 100644 --- a/src/QMCWaveFunctions/SPOSet.h +++ b/src/QMCWaveFunctions/SPOSet.h @@ -114,7 +114,9 @@ class SPOSet : public QMCTraits // Single Slater creation virtual void buildOptVariables(const size_t nel) {} // For the MSD case rotations must be created in MultiSlaterDetTableMethod class - virtual void buildOptVariables(const std::vector>& rotations, const std::vector>& full_rotations) {} + virtual void buildOptVariables(const std::vector>& rotations, + const std::vector>& full_rotations) + {} /// return true if this SPOSet can be wrappered by RotatedSPO virtual bool isRotationSupported() const { return false; } /// store parameters before getting destroyed by rotation. @@ -130,10 +132,10 @@ class SPOSet : public QMCTraits const int& LastIndex); virtual void evaluateDerivativesWF(ParticleSet& P, - const opt_variables_type& optvars, - Vector& dlogpsi, - const int& FirstIndex, - const int& LastIndex); + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex); /** Evaluate the derivative of the optimized orbitals with respect to the parameters * this is used only for MSD, to be refined for better serving both single and multi SD @@ -222,6 +224,18 @@ class SPOSet : public QMCTraits const std::vector& invRow_ptr_list, std::vector>& ratios_list) const; + virtual void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + ValueVector& psi, + const ValueVector& psiinv, + std::vector& ratios, + Matrix& dratios, + int FirstIndex, + int LastIndex); + + /** evaluate the values, gradients and laplacians of this single-particle orbital set * @param P current ParticleSet * @param iat active particle diff --git a/src/QMCWaveFunctions/TrialWaveFunction.cpp b/src/QMCWaveFunctions/TrialWaveFunction.cpp index 0fafb2263d..712739d601 100644 --- a/src/QMCWaveFunctions/TrialWaveFunction.cpp +++ b/src/QMCWaveFunctions/TrialWaveFunction.cpp @@ -1037,6 +1037,8 @@ void TrialWaveFunction::mw_evaluateRatios(const RefVectorWithLeader& ratios, Matrix& dratio) @@ -1047,7 +1049,7 @@ void TrialWaveFunction::evaluateDerivRatios(const VirtualParticleSet& VP, for (int i = 0; i < Z.size(); ++i) { ScopedTimer z_timer(WFC_timers_[DERIVS_TIMER + TIMER_SKIP * i]); - Z[i]->evaluateDerivRatios(VP, optvars, t, dratio); + Z[i]->evaluateDerivRatios(VP, P, iel, optvars, t, dratio); for (int j = 0; j < ratios.size(); ++j) ratios[j] *= t[j]; } diff --git a/src/QMCWaveFunctions/TrialWaveFunction.h b/src/QMCWaveFunctions/TrialWaveFunction.h index 78fbebf629..50b2f5b577 100644 --- a/src/QMCWaveFunctions/TrialWaveFunction.h +++ b/src/QMCWaveFunctions/TrialWaveFunction.h @@ -312,7 +312,9 @@ class TrialWaveFunction ComputeType ct = ComputeType::ALL); /** compute both ratios and deriatives of ratio with respect to the optimizables*/ - void evaluateDerivRatios(const VirtualParticleSet& P, + void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratio); diff --git a/src/QMCWaveFunctions/WaveFunctionComponent.cpp b/src/QMCWaveFunctions/WaveFunctionComponent.cpp index 0853e9916f..621a8a0784 100644 --- a/src/QMCWaveFunctions/WaveFunctionComponent.cpp +++ b/src/QMCWaveFunctions/WaveFunctionComponent.cpp @@ -248,6 +248,8 @@ void WaveFunctionComponent::mw_evaluateRatios(const RefVectorWithLeader& ratios, Matrix& dratios) diff --git a/src/QMCWaveFunctions/WaveFunctionComponent.h b/src/QMCWaveFunctions/WaveFunctionComponent.h index 2cc34fe9e7..31abf9851d 100644 --- a/src/QMCWaveFunctions/WaveFunctionComponent.h +++ b/src/QMCWaveFunctions/WaveFunctionComponent.h @@ -535,6 +535,8 @@ class WaveFunctionComponent : public QMCTraits * @param dratios Nq x Num_param matrix. \f$\partial_{\alpha}(\ln \Psi ({\bf R}^{\prime}) - \ln \Psi ({\bf R})) \f$ */ virtual void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, std::vector& ratios, Matrix& dratios); diff --git a/src/QMCWaveFunctions/tests/test_multi_slater_determinant.cpp b/src/QMCWaveFunctions/tests/test_multi_slater_determinant.cpp index 15449a26b3..d3fcfdc3b2 100644 --- a/src/QMCWaveFunctions/tests/test_multi_slater_determinant.cpp +++ b/src/QMCWaveFunctions/tests/test_multi_slater_determinant.cpp @@ -182,7 +182,7 @@ void test_LiH_msd(const std::string& spo_xml_string, std::fill(ratios2.begin(), ratios2.end(), 0); Matrix dratio(2, nparam); - twf.evaluateDerivRatios(VP, active, ratios2, dratio); + twf.evaluateDerivRatios(VP, elec_, 1, active, ratios2, dratio); CHECK(std::real(ratios2[0]) == Approx(-0.8544310407)); CHECK(std::real(ratios2[1]) == Approx(-1.0830708458)); diff --git a/src/QMCWaveFunctions/tests/test_polynomial_eeI_jastrow.cpp b/src/QMCWaveFunctions/tests/test_polynomial_eeI_jastrow.cpp index 49def8719c..60c26181a0 100644 --- a/src/QMCWaveFunctions/tests/test_polynomial_eeI_jastrow.cpp +++ b/src/QMCWaveFunctions/tests/test_polynomial_eeI_jastrow.cpp @@ -196,7 +196,7 @@ void test_J3_polynomial3D(const DynamicCoordinateKind kind_selected) std::fill(ratios2.begin(), ratios2.end(), 0); Matrix dratio(2, NumOptimizables); - j3->evaluateDerivRatios(VP, optvars, ratios2, dratio); + j3->evaluateDerivRatios(VP, elec_, 0, optvars, ratios2, dratio); REQUIRE(std::real(ratios2[0]) == Approx(1.0357541137)); REQUIRE(std::real(ratios2[1]) == Approx(1.0257141422)); From 82138e54ef7b65208cba590ddced0897419e6b0c Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 11 Jan 2023 15:46:20 -0600 Subject: [PATCH 12/19] Add evaluateDerivRatios --- src/QMCWaveFunctions/RotatedSPOs.cpp | 155 ++++++++++++++++----------- src/QMCWaveFunctions/RotatedSPOs.h | 24 +++-- 2 files changed, 110 insertions(+), 69 deletions(-) diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 4802679f36..208b590884 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -304,7 +304,7 @@ void RotatedSPOs::buildOptVariables(const RotationIndices& rotations, const Rota const size_t nmo = Phi->getOrbitalSetSize(); // create active rotations - m_act_rot_inds = rotations; + m_act_rot_inds = rotations; m_full_rot_inds = full_rotations; if (use_global_rot_) @@ -593,40 +593,32 @@ void RotatedSPOs::log_antisym_matrix(ValueMatrix& mat) } } -void RotatedSPOs::evaluateDerivatives(ParticleSet& P, +void RotatedSPOs::evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, const opt_variables_type& optvars, - Vector& dlogpsi, - Vector& dhpsioverpsi, - const int& FirstIndex, - const int& LastIndex) + ValueVector& psi, + const ValueVector& psiinv, + std::vector& ratios, + Matrix& dratios, + int FirstIndex, + int LastIndex) { + Phi->evaluateDetRatios(VP, psi, psiinv, ratios); + const size_t nel = LastIndex - FirstIndex; const size_t nmo = Phi->getOrbitalSetSize(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART1 - myG_temp.resize(nel); - myG_J.resize(nel); - myL_temp.resize(nel); - myL_J.resize(nel); - - myG_temp = 0; - myG_J = 0; - myL_temp = 0; - myL_J = 0; - - Bbar.resize(nel, nmo); psiM_inv.resize(nel, nel); psiM_all.resize(nel, nmo); dpsiM_all.resize(nel, nmo); d2psiM_all.resize(nel, nmo); - Bbar = 0; psiM_inv = 0; psiM_all = 0; dpsiM_all = 0; d2psiM_all = 0; - Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all); for (int i = 0; i < nel; i++) @@ -635,70 +627,104 @@ void RotatedSPOs::evaluateDerivatives(ParticleSet& P, Invert(psiM_inv.data(), nel, nel); - //current value of Gradient and Laplacian - // gradient components - for (int a = 0; a < nel; a++) - for (int i = 0; i < nel; i++) - for (int k = 0; k < 3; k++) - myG_temp[a][k] += psiM_inv(i, a) * dpsiM_all(a, i)[k]; - // laplacian components - for (int a = 0; a < nel; a++) + const ValueType* const A(psiM_all.data()); + const ValueType* const Ainv(psiM_inv.data()); + SPOSet::ValueMatrix T_orig; + T_orig.resize(nel, nmo); + + BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T_orig.data(), nmo); + + SPOSet::ValueMatrix T; + T.resize(nel, nmo); + + ValueVector tmp_psi; + tmp_psi.resize(nmo); + + + for (int iat = 0; iat < VP.getTotalNum(); iat++) { + Phi->evaluateValue(VP, iat, tmp_psi); + + for (int j = 0; j < nmo; j++) + psiM_all(iel - FirstIndex, j) = tmp_psi[j]; + for (int i = 0; i < nel; i++) - myL_temp[a] += psiM_inv(i, a) * d2psiM_all(a, i); - } + for (int j = 0; j < nel; j++) + psiM_inv(i, j) = psiM_all(i, j); - // calculation of myG_J which will be used to represent \frac{\nabla\psi_{J}}{\psi_{J}} - // calculation of myL_J will be used to represent \frac{\nabla^2\psi_{J}}{\psi_{J}} - // IMPORTANT NOTE: The value of P.L holds \nabla^2 ln[\psi] but we need \frac{\nabla^2 \psi}{\psi} and this is what myL_J will hold - for (int a = 0, iat = FirstIndex; a < nel; a++, iat++) - { - myG_J[a] = (P.G[iat] - myG_temp[a]); - myL_J[a] = (P.L[iat] + dot(P.G[iat], P.G[iat]) - myL_temp[a]); + Invert(psiM_inv.data(), nel, nel); + + const ValueType* const A(psiM_all.data()); + const ValueType* const Ainv(psiM_inv.data()); + + + BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo); + + for (int i = 0; i < m_act_rot_inds.size(); i++) + { + int kk = myVars.where(i); + const int p = m_act_rot_inds.at(i).first; + const int q = m_act_rot_inds.at(i).second; + //app_log() << "kk = " << kk << " iat = " << iat << " T_orig = " << T_orig(p,q) << " T = " << T(p,q) << std::endl; + dratios(iat, kk) = T(p, q) - T_orig(p, q); // dratio size is (nknot, num_vars) + //dratios(iat, kk) = T(p, q); // dratio size is (nknot, num_vars) + } } - //possibly replace wit BLAS calls +} + +void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) +{ + const size_t nel = LastIndex - FirstIndex; + const size_t nmo = Phi->getOrbitalSetSize(); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART1 + + + psiM_inv.resize(nel, nel); + psiM_all.resize(nel, nmo); + dpsiM_all.resize(nel, nmo); + d2psiM_all.resize(nel, nmo); + + psiM_inv = 0; + psiM_all = 0; + dpsiM_all = 0; + d2psiM_all = 0; + + Phi->evaluate_notranspose(P, FirstIndex, LastIndex, psiM_all, dpsiM_all, d2psiM_all); + for (int i = 0; i < nel; i++) - for (int j = 0; j < nmo; j++) - Bbar(i, j) = d2psiM_all(i, j) + 2 * dot(myG_J[i], dpsiM_all(i, j)) + myL_J[i] * psiM_all(i, j); + for (int j = 0; j < nel; j++) + psiM_inv(i, j) = psiM_all(i, j); + Invert(psiM_inv.data(), nel, nel); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PART2 const ValueType* const A(psiM_all.data()); const ValueType* const Ainv(psiM_inv.data()); - const ValueType* const B(Bbar.data()); SPOSet::ValueMatrix T; - SPOSet::ValueMatrix Y1; - SPOSet::ValueMatrix Y2; - SPOSet::ValueMatrix Y3; - SPOSet::ValueMatrix Y4; T.resize(nel, nmo); - Y1.resize(nel, nel); - Y2.resize(nel, nmo); - Y3.resize(nel, nmo); - Y4.resize(nel, nmo); BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo); - BLAS::gemm('N', 'N', nel, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y1.data(), nel); - BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), T.data(), nmo, Y1.data(), nel, ValueType(0.0), Y2.data(), nmo); - BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y3.data(), nmo); - - //possibly replace with BLAS call - Y4 = Y3 - Y2; for (int i = 0; i < m_act_rot_inds.size(); i++) { - int kk = myVars.where(i); - const int p = m_act_rot_inds.at(i).first; - const int q = m_act_rot_inds.at(i).second; - dlogpsi[kk] = T(p, q); - dhpsioverpsi[kk] = ValueType(-0.5) * Y4(p, q); + int kk = myVars.where(i); + const int p = m_act_rot_inds.at(i).first; + const int q = m_act_rot_inds.at(i).second; + dlogpsi[kk] = T(p, q); } } -void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, + +void RotatedSPOs::evaluateDerivatives(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi, + Vector& dhpsioverpsi, const int& FirstIndex, const int& LastIndex) { @@ -781,6 +807,9 @@ void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), A, nmo, Ainv, nel, ValueType(0.0), T.data(), nmo); + BLAS::gemm('N', 'N', nel, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y1.data(), nel); + BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), T.data(), nmo, Y1.data(), nel, ValueType(0.0), Y2.data(), nmo); + BLAS::gemm('N', 'N', nmo, nel, nel, ValueType(1.0), B, nmo, Ainv, nel, ValueType(0.0), Y3.data(), nmo); //possibly replace with BLAS call Y4 = Y3 - Y2; @@ -791,9 +820,11 @@ void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, const int p = m_act_rot_inds.at(i).first; const int q = m_act_rot_inds.at(i).second; dlogpsi[kk] = T(p, q); + dhpsioverpsi[kk] = ValueType(-0.5) * Y4(p, q); } } + void RotatedSPOs::evaluateDerivatives(ParticleSet& P, const opt_variables_type& optvars, Vector& dlogpsi, @@ -1528,7 +1559,7 @@ std::unique_ptr RotatedSPOs::makeClone() const myclone->myVars = this->myVars; myclone->history_params_ = this->history_params_; myclone->myVarsFull = this->myVarsFull; - myclone->use_global_rot_ = this->use_global_rot_; + myclone->use_global_rot_ = this->use_global_rot_; // use_this_copy_to_apply_rotation_ is not copied diff --git a/src/QMCWaveFunctions/RotatedSPOs.h b/src/QMCWaveFunctions/RotatedSPOs.h index b47abfb428..f3fbee255f 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.h +++ b/src/QMCWaveFunctions/RotatedSPOs.h @@ -118,10 +118,10 @@ class RotatedSPOs : public SPOSet, public OptimizableObject const int& LastIndex) override; void evaluateDerivativesWF(ParticleSet& P, - const opt_variables_type& optvars, - Vector& dlogpsi, - const int& FirstIndex, - const int& LastIndex) override; + const opt_variables_type& optvars, + Vector& dlogpsi, + const int& FirstIndex, + const int& LastIndex) override; void evaluateDerivatives(ParticleSet& P, const opt_variables_type& optvars, @@ -256,6 +256,18 @@ class RotatedSPOs : public SPOSet, public OptimizableObject Phi->evaluateDetRatios(VP, psi, psiinv, ratios); } + void evaluateDerivRatios(const VirtualParticleSet& VP, + ParticleSet& P, + int iel, + const opt_variables_type& optvars, + ValueVector& psi, + const ValueVector& psiinv, + std::vector& ratios, + Matrix& dratios, + int FirstIndex, + int LastIndex) override; + + void evaluateVGH(const ParticleSet& P, int iat, ValueVector& psi, @@ -334,9 +346,7 @@ class RotatedSPOs : public SPOSet, public OptimizableObject // void evaluateThirdDeriv(const ParticleSet& P, int first, int last, GGGMatrix& grad_grad_grad_logdet) // {Phi->evaluateThridDeriv(P, first, last, grad_grad_grad_logdet); } // - void set_use_global_rotation() { - use_global_rot_ = true; - } + void set_use_global_rotation() { use_global_rot_ = true; } private: /// true if SPO parameters (orbital rotation parameters) have been supplied by input From 8f429b614c1525dbc55c58d457f8d972276f15f4 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 11 Jan 2023 15:47:25 -0600 Subject: [PATCH 13/19] Add flag to disable grid randomization --- src/QMCHamiltonians/ECPotentialBuilder.cpp | 5 +++ src/QMCHamiltonians/NonLocalECPComponent.cpp | 34 ++++++++++++++----- src/QMCHamiltonians/NonLocalECPComponent.h | 4 +++ .../NonLocalECPotential.deriv.cpp | 5 +-- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/QMCHamiltonians/ECPotentialBuilder.cpp b/src/QMCHamiltonians/ECPotentialBuilder.cpp index efab963a88..9d8eca6f68 100644 --- a/src/QMCHamiltonians/ECPotentialBuilder.cpp +++ b/src/QMCHamiltonians/ECPotentialBuilder.cpp @@ -220,6 +220,7 @@ void ECPotentialBuilder::useXmlFormat(xmlNodePtr cur) std::string format("xml"); int nrule = -1; int llocal = -1; + bool disable_randomize_grid; //RealType rc(2.0);//use 2 Bohr OhmmsAttributeSet hAttrib; hAttrib.add(href, "href"); @@ -228,6 +229,7 @@ void ECPotentialBuilder::useXmlFormat(xmlNodePtr cur) hAttrib.add(format, "format"); hAttrib.add(nrule, "nrule"); hAttrib.add(llocal, "l-local"); + hAttrib.add(disable_randomize_grid, "disable_randomize_grid", {false, true}); //hAttrib.add(rc,"cutoff"); hAttrib.put(cur); SpeciesSet& ion_species(IonConfig.getSpeciesSet()); @@ -271,6 +273,9 @@ void ECPotentialBuilder::useXmlFormat(xmlNodePtr cur) if (ecp.pp_nonloc) { hasNonLocalPot = true; + if (disable_randomize_grid) + app_warning() << "NLPP grid randomization is turned off. This setting should only be used for testing." << std::endl; + ecp.pp_nonloc->set_randomize_grid(!disable_randomize_grid); nonLocalPot[speciesIndex] = std::move(ecp.pp_nonloc); } if (ecp.pp_so) diff --git a/src/QMCHamiltonians/NonLocalECPComponent.cpp b/src/QMCHamiltonians/NonLocalECPComponent.cpp index 074e4dc991..b139ffa4f1 100644 --- a/src/QMCHamiltonians/NonLocalECPComponent.cpp +++ b/src/QMCHamiltonians/NonLocalECPComponent.cpp @@ -22,7 +22,7 @@ namespace qmcplusplus { -NonLocalECPComponent::NonLocalECPComponent() : lmax(0), nchannel(0), nknot(0), Rmax(-1), VP(nullptr) {} +NonLocalECPComponent::NonLocalECPComponent() : lmax(0), nchannel(0), nknot(0), Rmax(-1), VP(nullptr), do_randomize_grid_(true) {} // unfortunately we continue the sloppy use of the default copy constructor followed by reassigning pointers. // This prevents use of smart pointers and concievably sets us up for trouble with double frees and the destructor. @@ -43,6 +43,11 @@ NonLocalECPComponent::~NonLocalECPComponent() delete VP; } +void NonLocalECPComponent::set_randomize_grid(bool do_randomize_grid) +{ + do_randomize_grid_ = do_randomize_grid; +} + void NonLocalECPComponent::initVirtualParticle(const ParticleSet& qp) { assert(VP == 0); @@ -165,8 +170,9 @@ NonLocalECPComponent::RealType NonLocalECPComponent::calculateProjector(RealType psiratio[j] *= sgridweight_m[j]; // Compute radial potential, multiplied by (2l+1) factor. - for (int ip = 0; ip < nchannel; ip++) + for (int ip = 0; ip < nchannel; ip++) { vrad[ip] = nlpp_m[ip]->splint(r) * wgt_angpp_m[ip]; + } constexpr RealType czero(0); constexpr RealType cone(1); @@ -186,9 +192,11 @@ NonLocalECPComponent::RealType NonLocalECPComponent::calculateProjector(RealType lpolprev = lpol[l]; } + RealType lsum = 0.0; - for (int l = 0; l < nchannel; l++) + for (int l = 0; l < nchannel; l++) { lsum += vrad[l] * lpol[angpp_m[l]]; + } knot_pots[j] = lsum * std::real(psiratio[j]); pairpot += knot_pots[j]; } @@ -873,19 +881,26 @@ void NonLocalECPComponent::evaluateOneBodyOpMatrixdRContribution(ParticleSet& W, ///Randomly rotate sgrid_m void NonLocalECPComponent::randomize_grid(RandomGenerator& myRNG) { - RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(myRNG() - 0.5); + RealType rng1 = myRNG(); + RealType rng2 = myRNG(); + RealType rng3 = myRNG(); + RealType phi(TWOPI * rng1), psi(TWOPI * rng2), cth(1.0-2*rng3); + //RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(1.0-2*myRNG()); RealType sph(std::sin(phi)), cph(std::cos(phi)), sth(std::sqrt(1.0 - cth * cth)), sps(std::sin(psi)), cps(std::cos(psi)); TensorType rmat(cph * cth * cps - sph * sps, sph * cth * cps + cph * sps, -sth * cps, -cph * cth * sps - sph * cps, -sph * cth * sps + cph * cps, sth * sps, cph * sth, sph * sth, cth); - for (int i = 0; i < sgridxyz_m.size(); i++) - rrotsgrid_m[i] = dot(rmat, sgridxyz_m[i]); + for (int i = 0; i < sgridxyz_m.size(); i++) + if (do_randomize_grid_) + rrotsgrid_m[i] = dot(rmat, sgridxyz_m[i]); + else + rrotsgrid_m[i] = sgridxyz_m[i]; } template void NonLocalECPComponent::randomize_grid(std::vector& sphere, RandomGenerator& myRNG) { - RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(myRNG() - 0.5); + RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(1.0-2*myRNG()); RealType sph(std::sin(phi)), cph(std::cos(phi)), sth(std::sqrt(1.0 - cth * cth)), sps(std::sin(psi)), cps(std::cos(psi)); TensorType rmat(cph * cth * cps - sph * sps, sph * cth * cps + cph * sps, -sth * cps, -cph * cth * sps - sph * cps, @@ -895,7 +910,10 @@ void NonLocalECPComponent::randomize_grid(std::vector& sphere, RandomGenerato SpherGridType::iterator jt(rrotsgrid_m.begin()); while (it != it_end) { - *jt = dot(rmat, *it); + if (do_randomize_grid_) + *jt = dot(rmat, *it); + else + *jt = *it; ++it; ++jt; } diff --git a/src/QMCHamiltonians/NonLocalECPComponent.h b/src/QMCHamiltonians/NonLocalECPComponent.h index cda53d5521..b46633b5c1 100644 --- a/src/QMCHamiltonians/NonLocalECPComponent.h +++ b/src/QMCHamiltonians/NonLocalECPComponent.h @@ -120,6 +120,8 @@ class NonLocalECPComponent : public QMCTraits */ RealType calculateProjector(RealType r, const PosType& dr); + bool do_randomize_grid_; + public: NonLocalECPComponent(); @@ -138,6 +140,8 @@ class NonLocalECPComponent : public QMCTraits sgridweight_m.push_back(weight); } + void set_randomize_grid(bool do_randomize_grid); + void resize_warrays(int n, int m, int l); void randomize_grid(RandomGenerator& myRNG); diff --git a/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp b/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp index 420050366d..5ce5497a47 100644 --- a/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp +++ b/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp @@ -82,7 +82,7 @@ NonLocalECPComponent::RealType NonLocalECPComponent::evaluateValueAndDerivatives { // Compute ratios with VP VP->makeMoves(iel, W.R[iel], deltaV, true, iat); - psi.evaluateDerivRatios(*VP, optvars, psiratio, dratio); + psi.evaluateDerivRatios(*VP, W, iel, optvars, psiratio, dratio); } else { @@ -97,8 +97,9 @@ NonLocalECPComponent::RealType NonLocalECPComponent::evaluateValueAndDerivatives //use existing methods std::fill(dlogpsi_vp.begin(), dlogpsi_vp.end(), 0.0); psi.evaluateDerivativesWF(W, optvars, dlogpsi_vp); - for (int v = 0; v < dlogpsi_vp.size(); ++v) + for (int v = 0; v < dlogpsi_vp.size(); ++v) { dratio(j, v) = dlogpsi_vp[v] - dlogpsi[v]; + } W.makeMove(iel, -deltaV[j]); psi.calcRatio(W, iel); From f4f93051ad35ae7c28ebc3c18c87cf2f399d74e4 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Fri, 13 Jan 2023 15:48:55 +0000 Subject: [PATCH 14/19] Fixes for global rotation. In order to compute the delta rotation properly, myVars needs to stay in sync with the values in the driver. It always must be set to the value passed in to resetParametersExclusive. Also set initial values to match testing. --- src/QMCWaveFunctions/RotatedSPOs.cpp | 32 +++++++++++----------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 208b590884..7891f95055 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -120,19 +120,12 @@ void RotatedSPOs::resetParametersExclusive(const opt_variables_type& active) { int loc = myVars.where(i); delta_param[i] = active[loc] - myVars[i]; - if (use_global_rot_) - { - old_param[i] = myVars[i]; - } - else - { - myVars[i] = active[loc]; - } + myVars[i] = active[loc]; } if (use_global_rot_) { - for (int i = m_act_rot_inds.size(); i < m_full_rot_inds.size(); i++) + for (int i = 0; i < m_full_rot_inds.size(); i++) { old_param[i] = myVarsFull[i]; } @@ -142,15 +135,8 @@ void RotatedSPOs::resetParametersExclusive(const opt_variables_type& active) apply_delta_rotation(delta_param, old_param, new_param); } - // Save the active params - for (int i = 0; i < m_act_rot_inds.size(); i++) - { - myVars[i] = new_param[i]; - myVarsFull[i] = new_param[i]; - } - - // Save the rest of the params - for (int i = m_act_rot_inds.size(); i < m_full_rot_inds.size(); i++) + // Save the the params + for (int i = 0; i < m_full_rot_inds.size(); i++) { myVarsFull[i] = new_param[i]; } @@ -359,8 +345,14 @@ void RotatedSPOs::buildOptVariables(const RotationIndices& rotations, const Rota sstr << my_name_ << "_orb_rot_" << (p < 10 ? "0" : "") << (p < 100 ? "0" : "") << (p < 1000 ? "0" : "") << p << "_" << (q < 10 ? "0" : "") << (q < 100 ? "0" : "") << (q < 1000 ? "0" : "") << q; - // No user input parameters for now - myVarsFull.insert(sstr.str(), 0.0); + if (params_supplied && i < m_act_rot_inds.size()) + { + myVarsFull.insert(sstr.str(), params[i]); + } + else + { + myVarsFull.insert(sstr.str(), 0.0); + } } } From eb263de0d424fc1bb61c0d333f8878ff5c3ab62f Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Fri, 13 Jan 2023 12:10:36 -0600 Subject: [PATCH 15/19] Fix call --- src/QMCHamiltonians/NonLocalECPotential.deriv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp b/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp index 796e28c24c..fa48e4187d 100644 --- a/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp +++ b/src/QMCHamiltonians/NonLocalECPotential.deriv.cpp @@ -81,7 +81,7 @@ NonLocalECPComponent::RealType NonLocalECPComponent::evaluateValueAndDerivatives if (VP) { // Compute ratios with VP - VP->makeMoves(iel, W.R[iel], deltaV, true, iat); + VP->makeMoves(W, iel, deltaV, true, iat); psi.evaluateDerivRatios(*VP, W, iel, optvars, psiratio, dratio); } else From 421c4d358cf6a78c83ad522391807844708f28d3 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Tue, 17 Jan 2023 22:17:52 -0600 Subject: [PATCH 16/19] Add fallback implementation. At least compute the det ratios if evaluateDerivRatios is not implemented. This matches the implementation in WaveFunctionComponent. This fixes the deterministic test failure in diamondC_1x1x1_pp-param-grad. --- src/QMCWaveFunctions/SPOSet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/QMCWaveFunctions/SPOSet.cpp b/src/QMCWaveFunctions/SPOSet.cpp index d06b644495..19bc87d947 100644 --- a/src/QMCWaveFunctions/SPOSet.cpp +++ b/src/QMCWaveFunctions/SPOSet.cpp @@ -275,6 +275,9 @@ void SPOSet::evaluateDerivRatios(const VirtualParticleSet& VP, int FirstIndex, int LastIndex) { + // Match the fallback in WaveFunctionComponent that evaluates just the ratios + evaluateDetRatios(VP, psi, psiinv, ratios); + if (isOptimizable()) throw std::logic_error("Bug!! " + getClassName() + "::evaluateDerivRatios " From 58a69c9ac7da0d47d01ac2959d06a4d3d0ed92fa Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 18 Jan 2023 09:02:03 -0600 Subject: [PATCH 17/19] Fix complex build --- .../tests/test_RotatedSPOs_NLPP.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp b/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp index b703d28f01..bebc2155f7 100644 --- a/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp +++ b/src/QMCHamiltonians/tests/test_RotatedSPOs_NLPP.cpp @@ -191,10 +191,10 @@ TEST_CASE("RotatedSPOs SplineR2R hcpBe values multi det", "[wavefunction]") TrialWaveFunction::mw_evaluateParameterDerivatives(wf_list, p_list, opt_vars, dlogpsi_list, dhpsi_over_psi_list); - CHECK(dlogpsi_list[0][0] == Approx(dlogpsi[0])); - CHECK(dlogpsi_list[0][1] == Approx(dlogpsi[1])); - CHECK(dhpsi_over_psi_list[0][0] == Approx(dhpsioverpsi[0])); - CHECK(dhpsi_over_psi_list[0][1] == Approx(dhpsioverpsi[1])); + CHECK(dlogpsi_list[0][0] == ValueApprox(dlogpsi[0])); + CHECK(dlogpsi_list[0][1] == ValueApprox(dlogpsi[1])); + CHECK(dhpsi_over_psi_list[0][0] == ValueApprox(dhpsioverpsi[0])); + CHECK(dhpsi_over_psi_list[0][1] == ValueApprox(dhpsioverpsi[1])); QMCHamiltonian* h = hf.getH(); @@ -215,8 +215,8 @@ TEST_CASE("RotatedSPOs SplineR2R hcpBe values multi det", "[wavefunction]") h->evaluateValueAndDerivatives(elec, opt_vars, dlogpsi2, dhpsioverpsi2); // Derivative the wavefunction is unchanged by NLPP - CHECK(dlogpsi2[0] == Approx(dlogpsi[0])); - CHECK(dlogpsi2[1] == Approx(dlogpsi[1])); + CHECK(dlogpsi2[0] == ValueApprox(dlogpsi[0])); + CHECK(dlogpsi2[1] == ValueApprox(dlogpsi[1])); // Derivative of H is different with NLPP included CHECK(dhpsioverpsi2[0] == ValueApprox(-5.45054261)); @@ -230,11 +230,11 @@ TEST_CASE("RotatedSPOs SplineR2R hcpBe values multi det", "[wavefunction]") h->mw_evaluateValueAndDerivatives(h_list, wf_list, p_list, opt_vars, dlogpsi_list2, dhpsi_over_psi_list2); - CHECK(dlogpsi_list2[0][0] == Approx(dlogpsi2[0])); - CHECK(dlogpsi_list2[0][1] == Approx(dlogpsi2[1])); + CHECK(dlogpsi_list2[0][0] == ValueApprox(dlogpsi2[0])); + CHECK(dlogpsi_list2[0][1] == ValueApprox(dlogpsi2[1])); - CHECK(dhpsi_over_psi_list2[0][0] == Approx(dhpsioverpsi2[0])); - CHECK(dhpsi_over_psi_list2[0][1] == Approx(dhpsioverpsi2[1])); + CHECK(dhpsi_over_psi_list2[0][0] == ValueApprox(dhpsioverpsi2[0])); + CHECK(dhpsi_over_psi_list2[0][1] == ValueApprox(dhpsioverpsi2[1])); } } // namespace qmcplusplus From 80b1bbef6aefdcce0d35029c775c3adb7b0c46be Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Wed, 18 Jan 2023 09:56:53 -0600 Subject: [PATCH 18/19] Remove orb rot test in complex build --- src/QMCHamiltonians/tests/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QMCHamiltonians/tests/CMakeLists.txt b/src/QMCHamiltonians/tests/CMakeLists.txt index 37dffca8fc..6310badff3 100644 --- a/src/QMCHamiltonians/tests/CMakeLists.txt +++ b/src/QMCHamiltonians/tests/CMakeLists.txt @@ -27,7 +27,6 @@ set(HAM_SRCS test_SkAllEstimator.cpp test_QMCHamiltonian.cpp test_ObservableHelper.cpp - test_RotatedSPOs_NLPP.cpp test_Listener.cpp) if(NOT QMC_CUDA) From 57e047a7a32b52ca49e7272fcedc4397b4803bd0 Mon Sep 17 00:00:00 2001 From: Mark Dewing Date: Thu, 26 Jan 2023 00:04:09 +0000 Subject: [PATCH 19/19] Parameter derivatives with RHF Accumulate the parameter derivatives correctly in the case where multiple wavefunction components use the same parameter. --- src/QMCWaveFunctions/RotatedSPOs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/QMCWaveFunctions/RotatedSPOs.cpp b/src/QMCWaveFunctions/RotatedSPOs.cpp index 7891f95055..722e621fea 100644 --- a/src/QMCWaveFunctions/RotatedSPOs.cpp +++ b/src/QMCWaveFunctions/RotatedSPOs.cpp @@ -708,7 +708,7 @@ void RotatedSPOs::evaluateDerivativesWF(ParticleSet& P, int kk = myVars.where(i); const int p = m_act_rot_inds.at(i).first; const int q = m_act_rot_inds.at(i).second; - dlogpsi[kk] = T(p, q); + dlogpsi[kk] += T(p, q); } } @@ -811,8 +811,8 @@ void RotatedSPOs::evaluateDerivatives(ParticleSet& P, int kk = myVars.where(i); const int p = m_act_rot_inds.at(i).first; const int q = m_act_rot_inds.at(i).second; - dlogpsi[kk] = T(p, q); - dhpsioverpsi[kk] = ValueType(-0.5) * Y4(p, q); + dlogpsi[kk] += T(p, q); + dhpsioverpsi[kk] += ValueType(-0.5) * Y4(p, q); } }