From 51b70ce168c5dee8f7a1c323a8c8454e51dcef0d Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 1 Mar 2023 15:12:11 -0600 Subject: [PATCH 01/12] Introduce SizeLimitedDataQueue --- src/Estimators/SizeLimitedDataQueue.hpp | 76 +++++++++++++++++++ src/Estimators/tests/CMakeLists.txt | 1 + .../tests/test_SizeLimitedDataQueue.cpp | 53 +++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/Estimators/SizeLimitedDataQueue.hpp create mode 100644 src/Estimators/tests/test_SizeLimitedDataQueue.cpp diff --git a/src/Estimators/SizeLimitedDataQueue.hpp b/src/Estimators/SizeLimitedDataQueue.hpp new file mode 100644 index 0000000000..0703ea2ed4 --- /dev/null +++ b/src/Estimators/SizeLimitedDataQueue.hpp @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2023 QMCPACK developers. +// +// File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +// +// File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +////////////////////////////////////////////////////////////////////////////////////// +// -*- C++ -*- +#ifndef QMCPLUSPLUS_SIZELIMITEDDATAQUEUE_H +#define QMCPLUSPLUS_SIZELIMITEDDATAQUEUE_H + +#include +#include +#include + +namespace qmcplusplus +{ +template +class SizeLimitedDataQueue +{ +private: + enum + { + WEIGHT = 0, + FIRST_PROPERTY = 1, + NUM_FIELDS = NUM_DATA_FIELDS + 1 + }; + using value_type = std::array; + std::deque data; + const size_t size_limit_; + +public: + SizeLimitedDataQueue(size_t size_limit) : size_limit_(size_limit) {} + + void push(const value_type& val) + { + if (data.size() == size_limit_) + data.pop_front(); + assert(data.size() < size_limit_); + data.push_back(val); + } + + void push(value_type&& val) + { + if (data.size() == size_limit_) + data.pop_front(); + assert(data.size() < size_limit_); + data.push_back(val); + } + + value_type weighted_avg() const + { + value_type avg; + std::fill(avg.begin(), avg.end(), T(0)); + for (auto& element : data) + { + T weight = element[WEIGHT]; + avg[WEIGHT] += weight; + for (size_t i = FIRST_PROPERTY; i < element.size(); i++) + avg[i] += element[i] * weight; + } + T total_weight = avg[WEIGHT]; + avg[WEIGHT] /= data.size(); + for (size_t i = FIRST_PROPERTY; i < avg.size(); i++) + avg[i] /= total_weight; + return avg; + } + + auto size() const { return data.size(); } +}; + +} // namespace qmcplusplus +#endif diff --git a/src/Estimators/tests/CMakeLists.txt b/src/Estimators/tests/CMakeLists.txt index f4e7bcce25..b19b2370d0 100644 --- a/src/Estimators/tests/CMakeLists.txt +++ b/src/Estimators/tests/CMakeLists.txt @@ -33,6 +33,7 @@ set(SRCS test_InputSection.cpp test_EstimatorManagerInput.cpp test_ScalarEstimatorInputs.cpp + test_SizeLimitedDataQueue.cpp test_MomentumDistribution.cpp test_OneBodyDensityMatricesInput.cpp test_OneBodyDensityMatrices.cpp diff --git a/src/Estimators/tests/test_SizeLimitedDataQueue.cpp b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp new file mode 100644 index 0000000000..04f250e278 --- /dev/null +++ b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2023 QMCPACK developers. +// +// File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +// +// File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +////////////////////////////////////////////////////////////////////////////////////// + +#include "catch.hpp" +#include "SizeLimitedDataQueue.hpp" + +namespace qmcplusplus +{ + +TEST_CASE("SizeLimitedDataQueue", "[estimators]") +{ + SizeLimitedDataQueue weight_and_energy(3); + CHECK(weight_and_energy.size() == 0); + { + weight_and_energy.push({1.0, 2.0}); + CHECK(weight_and_energy.size() == 1); + auto avg = weight_and_energy.weighted_avg(); + CHECK(Approx(avg[0]) == 1.0); + CHECK(Approx(avg[1]) == 2.0); + } + { + weight_and_energy.push({3.0, 1.0}); + CHECK(weight_and_energy.size() == 2); + auto avg = weight_and_energy.weighted_avg(); + CHECK(Approx(avg[0]) == 2.0); + CHECK(Approx(avg[1]) == 1.25); + } + { + std::array temp{0.5, 3.0}; + weight_and_energy.push(std::move(temp)); + CHECK(weight_and_energy.size() == 3); + auto avg = weight_and_energy.weighted_avg(); + CHECK(Approx(avg[0]) == 1.5); + CHECK(Approx(avg[1]) == 1.444444444); + } + { + weight_and_energy.push({0.5, 3.0}); + CHECK(weight_and_energy.size() == 3); + auto avg = weight_and_energy.weighted_avg(); + CHECK(Approx(avg[0]) == 1.333333333); + CHECK(Approx(avg[1]) == 1.5); + } +} + +} // namespace qmcplusplus From 593bda3c60698ff71b9c1d7f6ce17b4347a13f1b Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 1 Mar 2023 15:12:49 -0600 Subject: [PATCH 02/12] Add DMCRefEnergy --- src/QMCDrivers/CMakeLists.txt | 1 + src/QMCDrivers/DMC/DMCRefEnergy.cpp | 56 ++++++++++++++++++++++++++ src/QMCDrivers/DMC/DMCRefEnergy.h | 62 +++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 src/QMCDrivers/DMC/DMCRefEnergy.cpp create mode 100644 src/QMCDrivers/DMC/DMCRefEnergy.h diff --git a/src/QMCDrivers/CMakeLists.txt b/src/QMCDrivers/CMakeLists.txt index 80cda7e478..5e6ef66f66 100644 --- a/src/QMCDrivers/CMakeLists.txt +++ b/src/QMCDrivers/CMakeLists.txt @@ -64,6 +64,7 @@ set(QMCDRIVERS DMC/DMCFactoryNew.cpp DMC/DMCBatched.cpp DMC/DMCDriverInput.cpp + DMC/DMCRefEnergy.cpp DMC/WalkerControlFactory.cpp DMC/WalkerReconfiguration.cpp DMC/WalkerControl.cpp diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.cpp b/src/QMCDrivers/DMC/DMCRefEnergy.cpp new file mode 100644 index 0000000000..14d94cc552 --- /dev/null +++ b/src/QMCDrivers/DMC/DMCRefEnergy.cpp @@ -0,0 +1,56 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2023 QMCPACK developers. +// +// File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +// +// File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +////////////////////////////////////////////////////////////////////////////////////// + +#include +#include "DMCRefEnergy.h" + +namespace qmcplusplus +{ + +using FullPrecRealType = DMCRefEnergy::FullPrecRealType; + +DMCRefEnergy::DMCRefEnergy(Scheme scheme, size_t memory_limit) + : scheme_(scheme), energy_and_variance_(memory_limit) {} + +std::tuple DMCRefEnergy::getEnergyVariance() const +{ + if (scheme_ == LIMITED_MEMORY) + { + auto avg = energy_and_variance_.weighted_avg(); + return {avg[WEIGHT], avg[VARIANCE]}; + } + else + return {energy_hist_.mean(), variance_hist_.mean()}; +} + + void DMCRefEnergy::pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var) +{ + if (scheme_ == LIMITED_MEMORY) + energy_and_variance_.push({weight, ene, var}); + else + { + energy_hist_(ene); + variance_hist_(var); + } +} + +size_t DMCRefEnergy::count() const + { + if (scheme_ == LIMITED_MEMORY) + return energy_and_variance_.size(); + else + { + assert(energy_hist_.count() == variance_hist_.count()); + return energy_hist_.count(); + } + } + +} // namespace qmcplusplus diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.h b/src/QMCDrivers/DMC/DMCRefEnergy.h new file mode 100644 index 0000000000..e1f0acdd1c --- /dev/null +++ b/src/QMCDrivers/DMC/DMCRefEnergy.h @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2023 QMCPACK developers. +// +// File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +// +// File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +////////////////////////////////////////////////////////////////////////////////////// +// -*- C++ -*- +#ifndef QMCPLUSPLUS_DMCREFENERGY_H +#define QMCPLUSPLUS_DMCREFENERGY_H + +#include +#include +#include +#include + +namespace qmcplusplus +{ +class DMCRefEnergy +{ +public: + using FullPrecRealType = QMCTraits::FullPrecRealType; +enum Scheme +{ + LEGACY, + LIMITED_MEMORY +} scheme_; + +enum DataLayout +{ + WEIGHT = 0, + ENERGY, + VARIANCE, + DATA_SIZE +}; + +private: + // legacy scheme + ///a simple accumulator for energy + accumulator_set energy_hist_; + ///a simple accumulator for variance + accumulator_set variance_hist_; + + // limited memory scheme + SizeLimitedDataQueue energy_and_variance_; + + public: + DMCRefEnergy(Scheme scheme, size_t memory_limit); + + std::tuple getEnergyVariance() const; + + void pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var); + + size_t count() const; + +}; + +} // namespace qmcplusplus +#endif From fafb54093cfbe548dca284cd864d064706c2d12f Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 1 Mar 2023 16:40:53 -0600 Subject: [PATCH 03/12] Connect DMCRefEnergy. --- src/QMCDrivers/DMC/DMCBatched.cpp | 2 +- src/QMCDrivers/DMC/DMCDriverInput.cpp | 1 + src/QMCDrivers/DMC/DMCDriverInput.h | 3 +++ src/QMCDrivers/SFNBranch.cpp | 32 ++++++++++++------------- src/QMCDrivers/SFNBranch.h | 9 ++++--- src/QMCDrivers/tests/test_SFNBranch.cpp | 2 +- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/QMCDrivers/DMC/DMCBatched.cpp b/src/QMCDrivers/DMC/DMCBatched.cpp index 6935034035..c738df579a 100644 --- a/src/QMCDrivers/DMC/DMCBatched.cpp +++ b/src/QMCDrivers/DMC/DMCBatched.cpp @@ -394,7 +394,7 @@ void DMCBatched::process(xmlNodePtr node) // I'd like to do away with this method in DMCBatched. app_log() << " Creating the branching engine and walker controler" << std::endl; - branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), population_.get_num_global_walkers()); + branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback()); branch_engine_->put(node); walker_controller_ = std::make_unique(myComm, Random, dmcdriver_input_.get_reconfiguration()); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.cpp b/src/QMCDrivers/DMC/DMCDriverInput.cpp index 820645d960..15c9ba1a9e 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.cpp +++ b/src/QMCDrivers/DMC/DMCDriverInput.cpp @@ -23,6 +23,7 @@ void DMCDriverInput::readXML(xmlNodePtr node) parameter_set_.add(NonLocalMove, "nonlocalmove", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(NonLocalMove, "nonlocalmoves", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(max_age_, "MaxAge"); + parameter_set_.add(feedback_, "feedback"); // from DMC.cpp put(xmlNodePtr) parameter_set_.add(branch_interval_, "branchInterval"); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.h b/src/QMCDrivers/DMC/DMCDriverInput.h index f357e6da41..b44fff0e14 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.h +++ b/src/QMCDrivers/DMC/DMCDriverInput.h @@ -32,6 +32,7 @@ class DMCDriverInput bool get_reconfiguration() const { return reconfiguration_; } IndexType get_max_age() const { return max_age_; } IndexType get_branch_interval() const { return branch_interval_; } + double get_feedback() const { return feedback_; } const std::string& get_non_local_move() const { return NonLocalMove; } double get_alpha() const { return alpha_; } double get_gamma() const { return gamma_; } @@ -46,6 +47,8 @@ class DMCDriverInput */ ///Interval between branching IndexType branch_interval_ = 1; + ///feed back parameter for population control + double feedback_ = 1.0; ///input std::string to determine kill walkers or not std::string KillWalker; ///input std::string to determine swap walkers among mpi processors diff --git a/src/QMCDrivers/SFNBranch.cpp b/src/QMCDrivers/SFNBranch.cpp index 6696827d5f..39b7d49740 100644 --- a/src/QMCDrivers/SFNBranch.cpp +++ b/src/QMCDrivers/SFNBranch.cpp @@ -31,7 +31,11 @@ enum DUMMYOPT }; -SFNBranch::SFNBranch(RealType tau, int nideal) : WarmUpToDoSteps(0), EtrialUpdateToDoSteps(0), myNode(NULL) +SFNBranch::SFNBranch(RealType tau, RealType feedback) + : WarmUpToDoSteps(0), + EtrialUpdateToDoSteps(0), + myNode(NULL), + ref_energy_collector(DMCRefEnergy::Scheme::LEGACY, std::max(1, static_cast(1.0 / (feedback * tau)))) { BranchMode.set(B_DMCSTAGE, 0); //warmup stage BranchMode.set(B_POPCONTROL, 1); //use standard DMC @@ -41,7 +45,7 @@ SFNBranch::SFNBranch(RealType tau, int nideal) : WarmUpToDoSteps(0), EtrialUpdat vParam.fill(1.0); vParam[SBVP::TAU] = tau; vParam[SBVP::TAUEFF] = tau; - vParam[SBVP::FEEDBACK] = 1.0; + vParam[SBVP::FEEDBACK] = feedback; vParam[SBVP::FILTERSCALE] = 10; vParam[SBVP::SIGMA_BOUND] = 10; R2Accepted(1.0e-10); @@ -80,8 +84,6 @@ void SFNBranch::registerParameters() m_param.add(vParam[SBVP::TAU], "TimeStep"); //filterscale: sets the filtercutoff to sigma*filterscale m_param.add(vParam[SBVP::FILTERSCALE], "filterscale"); - //feed back parameter for population control - m_param.add(vParam[SBVP::FEEDBACK], "feedback"); m_param.add(vParam[SBVP::SIGMA_BOUND], "sigmaBound"); //turn on/off effective tau onl for time-step error comparisons m_param.add(sParam[USETAUOPT], "useBareTau"); @@ -106,8 +108,7 @@ int SFNBranch::initParam(const MCPopulation& population, vParam[SBVP::SIGMA2] = var; vParam[SBVP::TAUEFF] = vParam[SBVP::TAU] * R2Accepted.result() / R2Proposed.result(); /// FIXME, magic number 50 - setBranchCutoff(vParam[SBVP::SIGMA2], vParam[SBVP::SIGMA_BOUND], 50, - population.get_golden_electrons().getTotalNum()); + setBranchCutoff(vParam[SBVP::SIGMA2], vParam[SBVP::SIGMA_BOUND], 50, population.get_golden_electrons().getTotalNum()); int nwtot_now = population.get_num_global_walkers(); if (iParam[B_TARGETWALKERS] == 0) @@ -149,12 +150,13 @@ void SFNBranch::updateParamAfterPopControl(int pop_int, const MCDataType namespace qmcplusplus @@ -148,7 +149,7 @@ class SFNBranch : public QMCTraits using VParamType = VParams; ///Constructor - SFNBranch(RealType tau, int nideal); + SFNBranch(RealType tau, RealType feedback); ///copy constructor SFNBranch(const SFNBranch& abranch) = delete; @@ -305,10 +306,8 @@ class SFNBranch : public QMCTraits int EtrialUpdateToDoSteps; ///save xml element xmlNodePtr myNode; - ///a simple accumulator for energy - accumulator_set EnergyHist; - ///a simple accumulator for variance - accumulator_set VarianceHist; + /// collect energy and variance history + DMCRefEnergy ref_energy_collector; ///a simple accumulator for energy accumulator_set R2Accepted; ///a simple accumulator for energy diff --git a/src/QMCDrivers/tests/test_SFNBranch.cpp b/src/QMCDrivers/tests/test_SFNBranch.cpp index 292ec54e81..72ac2492e7 100644 --- a/src/QMCDrivers/tests/test_SFNBranch.cpp +++ b/src/QMCDrivers/tests/test_SFNBranch.cpp @@ -49,7 +49,7 @@ class SetupSFNBranch walkers[0].get().R[0] = 1.0; walkers[1].get().R[0] = 0.5; - auto sfnb = std::make_unique(tau_, num_global_walkers_); + auto sfnb = std::make_unique(tau_, 1.0); createMyNode(*sfnb, valid_dmc_input_sections[valid_dmc_input_dmc_batch_index]); From 2d30af73185bc5604bd95f4ddd939d59e6bf7bbd Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 1 Mar 2023 21:51:25 -0600 Subject: [PATCH 04/12] Add refenergy_update_scheme input option. --- src/QMCDrivers/DMC/DMCBatched.cpp | 6 +++++- src/QMCDrivers/DMC/DMCDriverInput.cpp | 1 + src/QMCDrivers/DMC/DMCDriverInput.h | 3 +++ src/QMCDrivers/SFNBranch.cpp | 6 +++--- src/QMCDrivers/SFNBranch.h | 2 +- src/QMCDrivers/tests/test_SFNBranch.cpp | 2 +- 6 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/QMCDrivers/DMC/DMCBatched.cpp b/src/QMCDrivers/DMC/DMCBatched.cpp index c738df579a..fd70b562f5 100644 --- a/src/QMCDrivers/DMC/DMCBatched.cpp +++ b/src/QMCDrivers/DMC/DMCBatched.cpp @@ -394,7 +394,11 @@ void DMCBatched::process(xmlNodePtr node) // I'd like to do away with this method in DMCBatched. app_log() << " Creating the branching engine and walker controler" << std::endl; - branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback()); + const DMCRefEnergy::Scheme refenergy_update_scheme = dmcdriver_input_.get_refenergy_update_scheme() == "legacy" + ? DMCRefEnergy::Scheme::LEGACY + : DMCRefEnergy::Scheme::LIMITED_MEMORY; + branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback(), + refenergy_update_scheme); branch_engine_->put(node); walker_controller_ = std::make_unique(myComm, Random, dmcdriver_input_.get_reconfiguration()); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.cpp b/src/QMCDrivers/DMC/DMCDriverInput.cpp index 15c9ba1a9e..37b5dc8529 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.cpp +++ b/src/QMCDrivers/DMC/DMCDriverInput.cpp @@ -24,6 +24,7 @@ void DMCDriverInput::readXML(xmlNodePtr node) parameter_set_.add(NonLocalMove, "nonlocalmoves", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(max_age_, "MaxAge"); parameter_set_.add(feedback_, "feedback"); + parameter_set_.add(refenergy_update_scheme_, "refenergy_update_scheme", {"legacy", "limited_memory"}); // from DMC.cpp put(xmlNodePtr) parameter_set_.add(branch_interval_, "branchInterval"); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.h b/src/QMCDrivers/DMC/DMCDriverInput.h index b44fff0e14..aecdd8e1ca 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.h +++ b/src/QMCDrivers/DMC/DMCDriverInput.h @@ -33,6 +33,7 @@ class DMCDriverInput IndexType get_max_age() const { return max_age_; } IndexType get_branch_interval() const { return branch_interval_; } double get_feedback() const { return feedback_; } + const std::string& get_refenergy_update_scheme() const { return refenergy_update_scheme_; } const std::string& get_non_local_move() const { return NonLocalMove; } double get_alpha() const { return alpha_; } double get_gamma() const { return gamma_; } @@ -49,6 +50,8 @@ class DMCDriverInput IndexType branch_interval_ = 1; ///feed back parameter for population control double feedback_ = 1.0; + ///input std::string to determine reference energy update scheme + std::string refenergy_update_scheme_; ///input std::string to determine kill walkers or not std::string KillWalker; ///input std::string to determine swap walkers among mpi processors diff --git a/src/QMCDrivers/SFNBranch.cpp b/src/QMCDrivers/SFNBranch.cpp index 39b7d49740..14a4a1b120 100644 --- a/src/QMCDrivers/SFNBranch.cpp +++ b/src/QMCDrivers/SFNBranch.cpp @@ -31,11 +31,11 @@ enum DUMMYOPT }; -SFNBranch::SFNBranch(RealType tau, RealType feedback) +SFNBranch::SFNBranch(RealType tau, RealType feedback, DMCRefEnergy::Scheme refenergy_update_scheme) : WarmUpToDoSteps(0), EtrialUpdateToDoSteps(0), myNode(NULL), - ref_energy_collector(DMCRefEnergy::Scheme::LEGACY, std::max(1, static_cast(1.0 / (feedback * tau)))) + ref_energy_collector(refenergy_update_scheme, std::max(1, static_cast(1.0 / (feedback * tau)))) { BranchMode.set(B_DMCSTAGE, 0); //warmup stage BranchMode.set(B_POPCONTROL, 1); //use standard DMC @@ -153,7 +153,7 @@ void SFNBranch::updateParamAfterPopControl(int pop_int, const MCDataType; ///Constructor - SFNBranch(RealType tau, RealType feedback); + SFNBranch(RealType tau, RealType feedback, DMCRefEnergy::Scheme); ///copy constructor SFNBranch(const SFNBranch& abranch) = delete; diff --git a/src/QMCDrivers/tests/test_SFNBranch.cpp b/src/QMCDrivers/tests/test_SFNBranch.cpp index 72ac2492e7..cf7fb7ef3e 100644 --- a/src/QMCDrivers/tests/test_SFNBranch.cpp +++ b/src/QMCDrivers/tests/test_SFNBranch.cpp @@ -49,7 +49,7 @@ class SetupSFNBranch walkers[0].get().R[0] = 1.0; walkers[1].get().R[0] = 0.5; - auto sfnb = std::make_unique(tau_, 1.0); + auto sfnb = std::make_unique(tau_, 1.0, DMCRefEnergy::Scheme::LIMITED_MEMORY); createMyNode(*sfnb, valid_dmc_input_sections[valid_dmc_input_dmc_batch_index]); From f14115c1fb7ae7aa586fbfe29814d09694126ad9 Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 1 Mar 2023 22:14:06 -0600 Subject: [PATCH 05/12] Update refenergy_update_scheme name. --- src/QMCDrivers/DMC/DMCBatched.cpp | 4 +++- src/QMCDrivers/DMC/DMCDriverInput.cpp | 2 +- src/QMCDrivers/DMC/DMCRefEnergy.cpp | 12 ++++++------ src/QMCDrivers/DMC/DMCRefEnergy.h | 4 ++-- src/QMCDrivers/tests/test_SFNBranch.cpp | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/QMCDrivers/DMC/DMCBatched.cpp b/src/QMCDrivers/DMC/DMCBatched.cpp index fd70b562f5..7b70b4f7d0 100644 --- a/src/QMCDrivers/DMC/DMCBatched.cpp +++ b/src/QMCDrivers/DMC/DMCBatched.cpp @@ -394,9 +394,11 @@ void DMCBatched::process(xmlNodePtr node) // I'd like to do away with this method in DMCBatched. app_log() << " Creating the branching engine and walker controler" << std::endl; + app_log() << " Reference energy is updated using the \"" << dmcdriver_input_.get_refenergy_update_scheme() + << "\" scheme" << std::endl; const DMCRefEnergy::Scheme refenergy_update_scheme = dmcdriver_input_.get_refenergy_update_scheme() == "legacy" ? DMCRefEnergy::Scheme::LEGACY - : DMCRefEnergy::Scheme::LIMITED_MEMORY; + : DMCRefEnergy::Scheme::LIMITED_HISTORY; branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback(), refenergy_update_scheme); branch_engine_->put(node); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.cpp b/src/QMCDrivers/DMC/DMCDriverInput.cpp index 37b5dc8529..11efc4bdd7 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.cpp +++ b/src/QMCDrivers/DMC/DMCDriverInput.cpp @@ -24,7 +24,7 @@ void DMCDriverInput::readXML(xmlNodePtr node) parameter_set_.add(NonLocalMove, "nonlocalmoves", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(max_age_, "MaxAge"); parameter_set_.add(feedback_, "feedback"); - parameter_set_.add(refenergy_update_scheme_, "refenergy_update_scheme", {"legacy", "limited_memory"}); + parameter_set_.add(refenergy_update_scheme_, "refenergy_update_scheme", {"legacy", "limited_history"}); // from DMC.cpp put(xmlNodePtr) parameter_set_.add(branch_interval_, "branchInterval"); diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.cpp b/src/QMCDrivers/DMC/DMCRefEnergy.cpp index 14d94cc552..9398a5530c 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.cpp +++ b/src/QMCDrivers/DMC/DMCRefEnergy.cpp @@ -17,15 +17,15 @@ namespace qmcplusplus using FullPrecRealType = DMCRefEnergy::FullPrecRealType; -DMCRefEnergy::DMCRefEnergy(Scheme scheme, size_t memory_limit) - : scheme_(scheme), energy_and_variance_(memory_limit) {} +DMCRefEnergy::DMCRefEnergy(Scheme scheme, size_t history_limit) + : scheme_(scheme), energy_and_variance_(history_limit) {} std::tuple DMCRefEnergy::getEnergyVariance() const { - if (scheme_ == LIMITED_MEMORY) + if (scheme_ == LIMITED_HISTORY) { auto avg = energy_and_variance_.weighted_avg(); - return {avg[WEIGHT], avg[VARIANCE]}; + return {avg[ENERGY], avg[VARIANCE]}; } else return {energy_hist_.mean(), variance_hist_.mean()}; @@ -33,7 +33,7 @@ std::tuple DMCRefEnergy::getEnergyVariance() void DMCRefEnergy::pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var) { - if (scheme_ == LIMITED_MEMORY) + if (scheme_ == LIMITED_HISTORY) energy_and_variance_.push({weight, ene, var}); else { @@ -44,7 +44,7 @@ std::tuple DMCRefEnergy::getEnergyVariance() size_t DMCRefEnergy::count() const { - if (scheme_ == LIMITED_MEMORY) + if (scheme_ == LIMITED_HISTORY) return energy_and_variance_.size(); else { diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.h b/src/QMCDrivers/DMC/DMCRefEnergy.h index e1f0acdd1c..477b0996c8 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.h +++ b/src/QMCDrivers/DMC/DMCRefEnergy.h @@ -26,7 +26,7 @@ class DMCRefEnergy enum Scheme { LEGACY, - LIMITED_MEMORY + LIMITED_HISTORY } scheme_; enum DataLayout @@ -48,7 +48,7 @@ enum DataLayout SizeLimitedDataQueue energy_and_variance_; public: - DMCRefEnergy(Scheme scheme, size_t memory_limit); + DMCRefEnergy(Scheme scheme, size_t history_limit); std::tuple getEnergyVariance() const; diff --git a/src/QMCDrivers/tests/test_SFNBranch.cpp b/src/QMCDrivers/tests/test_SFNBranch.cpp index cf7fb7ef3e..e7d8c53d21 100644 --- a/src/QMCDrivers/tests/test_SFNBranch.cpp +++ b/src/QMCDrivers/tests/test_SFNBranch.cpp @@ -49,7 +49,7 @@ class SetupSFNBranch walkers[0].get().R[0] = 1.0; walkers[1].get().R[0] = 0.5; - auto sfnb = std::make_unique(tau_, 1.0, DMCRefEnergy::Scheme::LIMITED_MEMORY); + auto sfnb = std::make_unique(tau_, 1.0, DMCRefEnergy::Scheme::LIMITED_HISTORY); createMyNode(*sfnb, valid_dmc_input_sections[valid_dmc_input_dmc_batch_index]); From f090c99af1dd26949db7ca0b25c3050461ae231c Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Thu, 2 Mar 2023 13:22:06 -0600 Subject: [PATCH 06/12] document refenergy_update_scheme in batched DMC. --- docs/methods.rst | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/methods.rst b/docs/methods.rst index 44bd5943c2..e76bb124c5 100644 --- a/docs/methods.rst +++ b/docs/methods.rst @@ -1758,6 +1758,41 @@ Batched ``dmc`` driver (experimental) - ``spin_mass`` Optional parameter to allow the user to change the rate of spin sampling. If spin sampling is on using ``spinor`` == yes in the electron ParticleSet input, the spin mass determines the rate of spin sampling, resulting in an effective spin timestep :math:`\tau_s = \frac{\tau}{\mu_s}`. The algorithm is described in detail in :cite:`Melton2016-1` and :cite:`Melton2016-2`. +- ``warmupsteps``: These are the steps at the beginning of a DMC run in + which the instantaneous population average energy is used to update the trial + energy and updates happen at every step. The aim is to rapidly equilibrate the population while avoiding overly large population fluctuations. + Unlike VMC, these warmupsteps are included in the requested DMC step count. + +.. math:: + + E_\text{trial} = E_\text{pop_avg}+(\ln \texttt{targetwalkers}-\ln N_\text{pop}) / \texttt{timestep} + +where :math:`E_\text{pop_avg}` is the local energy average over the walker population at the current step +and :math:`N_\text{pop}` is the current walker population size. +After the warm-up phase, the trial energy is updated as + +.. math:: + + E_\text{trial} = E_\text{ref}+\texttt{feedback}\cdot(\ln\texttt{targetWalkers}-\ln N_\text{pop}) + +where :math:`E_\text{ref}` is the :math:`E_\text{pop_avg}` average over all the post warm-up steps up to the current step. The update frequency is controlled by ``energyUpdateInterval``. + +- ``energyUpdateInterval``: Post warm-up, the trial energy is updated every + ``energyUpdateInterval`` steps. Default value is 1 (every step). + +- ``refEnergy``: The default reference energy is taken from the VMC run + that precedes the DMC run. This value is updated to the current mean + whenever branching happens. + +- ``feedback``: This variable is used to determine how strong to react + to population fluctuations when doing population control. Default value is 1. See the + equation in ``warmupsteps`` for more details. + +- ``refenergy_update_scheme``: choose a scheme for updating :math:`E_\text{ref}` used in calculating :math:`E_\text{trial}`. + 'legacy' uses unweighted average of :math:`E_\text{pop_avg}` of all the steps collected post warm-up. + 'limited_history' uses weighted average of :math:`E_\text{pop_avg}` of the latest at maximum + min(1, int(1.0 / (feedback * tau))) steps collected post warm-up. Default 'legacy'. + .. code-block:: :caption: The following is an example of a minimal DMC section using the batched ``dmc`` driver :name: Listing 48b From 36bb958cc75a6b18498693a0bbc0a8c3bab021c9 Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Thu, 2 Mar 2023 13:32:29 -0600 Subject: [PATCH 07/12] Add minimal documentation. --- src/Estimators/SizeLimitedDataQueue.hpp | 8 ++++++++ src/QMCDrivers/DMC/DMCRefEnergy.h | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Estimators/SizeLimitedDataQueue.hpp b/src/Estimators/SizeLimitedDataQueue.hpp index 0703ea2ed4..8622a37574 100644 --- a/src/Estimators/SizeLimitedDataQueue.hpp +++ b/src/Estimators/SizeLimitedDataQueue.hpp @@ -18,6 +18,10 @@ namespace qmcplusplus { + +/** collect data with a history limit. + * data stored in std::deque> + */ template class SizeLimitedDataQueue { @@ -35,6 +39,7 @@ class SizeLimitedDataQueue public: SizeLimitedDataQueue(size_t size_limit) : size_limit_(size_limit) {} + /// add a new record void push(const value_type& val) { if (data.size() == size_limit_) @@ -43,6 +48,7 @@ class SizeLimitedDataQueue data.push_back(val); } + /// add a new record void push(value_type&& val) { if (data.size() == size_limit_) @@ -51,6 +57,7 @@ class SizeLimitedDataQueue data.push_back(val); } + /// return weighted average value_type weighted_avg() const { value_type avg; @@ -69,6 +76,7 @@ class SizeLimitedDataQueue return avg; } + /// return the number of records auto size() const { return data.size(); } }; diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.h b/src/QMCDrivers/DMC/DMCRefEnergy.h index 477b0996c8..9d14bc41ba 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.h +++ b/src/QMCDrivers/DMC/DMCRefEnergy.h @@ -19,6 +19,8 @@ namespace qmcplusplus { +/** Handle updating Eref used for calculating the trial energy. + */ class DMCRefEnergy { public: @@ -38,24 +40,26 @@ enum DataLayout }; private: - // legacy scheme + // legacy scheme data ///a simple accumulator for energy accumulator_set energy_hist_; ///a simple accumulator for variance accumulator_set variance_hist_; - // limited memory scheme + // limited memory scheme data SizeLimitedDataQueue energy_and_variance_; public: DMCRefEnergy(Scheme scheme, size_t history_limit); + /// return energy and variance std::tuple getEnergyVariance() const; + /// record weight, energy and variance. void pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var); + /// return record count. size_t count() const; - }; } // namespace qmcplusplus From d34d4ef63848c51d477db39378ec73c35369745f Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Sat, 4 Mar 2023 13:19:34 -0600 Subject: [PATCH 08/12] Adjust data structure in SizeLimitedDataQueue. --- src/Estimators/SizeLimitedDataQueue.hpp | 39 +++++++++---------- .../tests/test_SizeLimitedDataQueue.cpp | 18 ++++----- src/QMCDrivers/DMC/DMCRefEnergy.h | 25 ++++++------ 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/Estimators/SizeLimitedDataQueue.hpp b/src/Estimators/SizeLimitedDataQueue.hpp index 8622a37574..3d0bc0a519 100644 --- a/src/Estimators/SizeLimitedDataQueue.hpp +++ b/src/Estimators/SizeLimitedDataQueue.hpp @@ -22,21 +22,18 @@ namespace qmcplusplus /** collect data with a history limit. * data stored in std::deque> */ -template +template class SizeLimitedDataQueue { -private: - enum +public: + struct HistoryElement { - WEIGHT = 0, - FIRST_PROPERTY = 1, - NUM_FIELDS = NUM_DATA_FIELDS + 1 + T weight; + std::array properties; }; - using value_type = std::array; - std::deque data; - const size_t size_limit_; -public: + using value_type = HistoryElement; + SizeLimitedDataQueue(size_t size_limit) : size_limit_(size_limit) {} /// add a new record @@ -58,26 +55,28 @@ class SizeLimitedDataQueue } /// return weighted average - value_type weighted_avg() const + auto weighted_avg() const { - value_type avg; + std::array avg; std::fill(avg.begin(), avg.end(), T(0)); + T weight_sum = 0; for (auto& element : data) { - T weight = element[WEIGHT]; - avg[WEIGHT] += weight; - for (size_t i = FIRST_PROPERTY; i < element.size(); i++) - avg[i] += element[i] * weight; + weight_sum += element.weight; + for (size_t i = 0; i < NUM_FIELDS; i++) + avg[i] += element.properties[i] * element.weight; } - T total_weight = avg[WEIGHT]; - avg[WEIGHT] /= data.size(); - for (size_t i = FIRST_PROPERTY; i < avg.size(); i++) - avg[i] /= total_weight; + for (size_t i = 0; i < NUM_FIELDS; i++) + avg[i] /= weight_sum; return avg; } /// return the number of records auto size() const { return data.size(); } + +private: + std::deque data; + const size_t size_limit_; }; } // namespace qmcplusplus diff --git a/src/Estimators/tests/test_SizeLimitedDataQueue.cpp b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp index 04f250e278..c06f6d5507 100644 --- a/src/Estimators/tests/test_SizeLimitedDataQueue.cpp +++ b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp @@ -20,33 +20,29 @@ TEST_CASE("SizeLimitedDataQueue", "[estimators]") SizeLimitedDataQueue weight_and_energy(3); CHECK(weight_and_energy.size() == 0); { - weight_and_energy.push({1.0, 2.0}); + weight_and_energy.push({1.0, {2.0}}); CHECK(weight_and_energy.size() == 1); auto avg = weight_and_energy.weighted_avg(); - CHECK(Approx(avg[0]) == 1.0); - CHECK(Approx(avg[1]) == 2.0); + CHECK(Approx(avg[0]) == 2.0); } { - weight_and_energy.push({3.0, 1.0}); + weight_and_energy.push({3.0, {1.0}}); CHECK(weight_and_energy.size() == 2); auto avg = weight_and_energy.weighted_avg(); - CHECK(Approx(avg[0]) == 2.0); - CHECK(Approx(avg[1]) == 1.25); + CHECK(Approx(avg[0]) == 1.25); } { - std::array temp{0.5, 3.0}; + SizeLimitedDataQueue::HistoryElement temp{0.5, {3.0}}; weight_and_energy.push(std::move(temp)); CHECK(weight_and_energy.size() == 3); auto avg = weight_and_energy.weighted_avg(); - CHECK(Approx(avg[0]) == 1.5); - CHECK(Approx(avg[1]) == 1.444444444); + CHECK(Approx(avg[0]) == 1.444444444); } { weight_and_energy.push({0.5, 3.0}); CHECK(weight_and_energy.size() == 3); auto avg = weight_and_energy.weighted_avg(); - CHECK(Approx(avg[0]) == 1.333333333); - CHECK(Approx(avg[1]) == 1.5); + CHECK(Approx(avg[0]) == 1.5); } } diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.h b/src/QMCDrivers/DMC/DMCRefEnergy.h index 9d14bc41ba..28991e321e 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.h +++ b/src/QMCDrivers/DMC/DMCRefEnergy.h @@ -25,19 +25,18 @@ class DMCRefEnergy { public: using FullPrecRealType = QMCTraits::FullPrecRealType; -enum Scheme -{ - LEGACY, - LIMITED_HISTORY -} scheme_; + enum Scheme + { + LEGACY, + LIMITED_HISTORY + } scheme_; -enum DataLayout -{ - WEIGHT = 0, - ENERGY, - VARIANCE, - DATA_SIZE -}; + enum DataLayout + { + ENERGY = 0, + VARIANCE, + DATA_SIZE + }; private: // legacy scheme data @@ -49,7 +48,7 @@ enum DataLayout // limited memory scheme data SizeLimitedDataQueue energy_and_variance_; - public: +public: DMCRefEnergy(Scheme scheme, size_t history_limit); /// return energy and variance From e6e45ddaf9ac3f12e1d805234754c6e19c86843e Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Sat, 4 Mar 2023 16:42:24 -0600 Subject: [PATCH 09/12] Add standalone DMCRefEnergyScheme. --- src/QMCDrivers/DMC/DMCBatched.cpp | 13 +++--- src/QMCDrivers/DMC/DMCDriverInput.cpp | 8 +++- src/QMCDrivers/DMC/DMCDriverInput.h | 5 ++- src/QMCDrivers/DMC/DMCRefEnergy.cpp | 53 +++++++++++++------------ src/QMCDrivers/DMC/DMCRefEnergy.h | 23 +++++------ src/QMCDrivers/DMC/DMCRefEnergyScheme.h | 25 ++++++++++++ src/QMCDrivers/SFNBranch.cpp | 2 +- src/QMCDrivers/SFNBranch.h | 2 +- src/QMCDrivers/tests/test_SFNBranch.cpp | 2 +- 9 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 src/QMCDrivers/DMC/DMCRefEnergyScheme.h diff --git a/src/QMCDrivers/DMC/DMCBatched.cpp b/src/QMCDrivers/DMC/DMCBatched.cpp index 7b70b4f7d0..5e265bb1c2 100644 --- a/src/QMCDrivers/DMC/DMCBatched.cpp +++ b/src/QMCDrivers/DMC/DMCBatched.cpp @@ -394,13 +394,12 @@ void DMCBatched::process(xmlNodePtr node) // I'd like to do away with this method in DMCBatched. app_log() << " Creating the branching engine and walker controler" << std::endl; - app_log() << " Reference energy is updated using the \"" << dmcdriver_input_.get_refenergy_update_scheme() - << "\" scheme" << std::endl; - const DMCRefEnergy::Scheme refenergy_update_scheme = dmcdriver_input_.get_refenergy_update_scheme() == "legacy" - ? DMCRefEnergy::Scheme::LEGACY - : DMCRefEnergy::Scheme::LIMITED_HISTORY; - branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback(), - refenergy_update_scheme); + const auto refE_update_scheme = dmcdriver_input_.get_refenergy_update_scheme(); + app_log() << " Reference energy is updated using the " + << (refE_update_scheme == DMCRefEnergyScheme::LEGACY ? "legacy" : "history limited") << " scheme" + << std::endl; + branch_engine_ = + std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback(), refE_update_scheme); branch_engine_->put(node); walker_controller_ = std::make_unique(myComm, Random, dmcdriver_input_.get_reconfiguration()); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.cpp b/src/QMCDrivers/DMC/DMCDriverInput.cpp index 11efc4bdd7..b4cab5512f 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.cpp +++ b/src/QMCDrivers/DMC/DMCDriverInput.cpp @@ -19,12 +19,13 @@ void DMCDriverInput::readXML(xmlNodePtr node) { ParameterSet parameter_set_; std::string reconfig_str; + std::string refE_update_scheme_str; parameter_set_.add(reconfig_str, "reconfiguration", {"no", "yes", "runwhileincorrect"}); parameter_set_.add(NonLocalMove, "nonlocalmove", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(NonLocalMove, "nonlocalmoves", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(max_age_, "MaxAge"); parameter_set_.add(feedback_, "feedback"); - parameter_set_.add(refenergy_update_scheme_, "refenergy_update_scheme", {"legacy", "limited_history"}); + parameter_set_.add(refE_update_scheme_str, "refenergy_update_scheme", {"legacy", "limited_history"}); // from DMC.cpp put(xmlNodePtr) parameter_set_.add(branch_interval_, "branchInterval"); @@ -66,6 +67,11 @@ void DMCDriverInput::readXML(xmlNodePtr node) if (reserve_ < 1.0) throw std::runtime_error("You can only reserve walkers above the target walker count"); + + if (refE_update_scheme_str == "legacy") + refenergy_update_scheme_ = DMCRefEnergyScheme::LEGACY; + else + refenergy_update_scheme_ = DMCRefEnergyScheme::LIMITED_HISTORY; } std::ostream& operator<<(std::ostream& o_stream, const DMCDriverInput& dmci) { return o_stream; } diff --git a/src/QMCDrivers/DMC/DMCDriverInput.h b/src/QMCDrivers/DMC/DMCDriverInput.h index aecdd8e1ca..d729d48ead 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.h +++ b/src/QMCDrivers/DMC/DMCDriverInput.h @@ -14,6 +14,7 @@ #include "Configuration.h" #include "OhmmsData/ParameterSet.h" +#include "DMC/DMCRefEnergyScheme.h" namespace qmcplusplus { @@ -33,7 +34,7 @@ class DMCDriverInput IndexType get_max_age() const { return max_age_; } IndexType get_branch_interval() const { return branch_interval_; } double get_feedback() const { return feedback_; } - const std::string& get_refenergy_update_scheme() const { return refenergy_update_scheme_; } + DMCRefEnergyScheme get_refenergy_update_scheme() const { return refenergy_update_scheme_; } const std::string& get_non_local_move() const { return NonLocalMove; } double get_alpha() const { return alpha_; } double get_gamma() const { return gamma_; } @@ -51,7 +52,7 @@ class DMCDriverInput ///feed back parameter for population control double feedback_ = 1.0; ///input std::string to determine reference energy update scheme - std::string refenergy_update_scheme_; + DMCRefEnergyScheme refenergy_update_scheme_; ///input std::string to determine kill walkers or not std::string KillWalker; ///input std::string to determine swap walkers among mpi processors diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.cpp b/src/QMCDrivers/DMC/DMCRefEnergy.cpp index 9398a5530c..a71bb207ea 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.cpp +++ b/src/QMCDrivers/DMC/DMCRefEnergy.cpp @@ -15,42 +15,43 @@ namespace qmcplusplus { -using FullPrecRealType = DMCRefEnergy::FullPrecRealType; +using FullPrecReal = DMCRefEnergy::FullPrecReal; -DMCRefEnergy::DMCRefEnergy(Scheme scheme, size_t history_limit) - : scheme_(scheme), energy_and_variance_(history_limit) {} +DMCRefEnergy::DMCRefEnergy(DMCRefEnergyScheme scheme, size_t history_limit) + : scheme_(scheme), energy_and_variance_(history_limit) +{} -std::tuple DMCRefEnergy::getEnergyVariance() const +std::tuple DMCRefEnergy::getEnergyVariance() const { - if (scheme_ == LIMITED_HISTORY) - { - auto avg = energy_and_variance_.weighted_avg(); - return {avg[ENERGY], avg[VARIANCE]}; - } - else - return {energy_hist_.mean(), variance_hist_.mean()}; + if (scheme_ == DMCRefEnergyScheme::LIMITED_HISTORY) + { + auto avg = energy_and_variance_.weighted_avg(); + return {avg[ENERGY], avg[VARIANCE]}; + } + else + return {energy_hist_.mean(), variance_hist_.mean()}; } - void DMCRefEnergy::pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var) +void DMCRefEnergy::pushWeightEnergyVariance(FullPrecReal weight, FullPrecReal ene, FullPrecReal var) { - if (scheme_ == LIMITED_HISTORY) - energy_and_variance_.push({weight, ene, var}); - else - { - energy_hist_(ene); - variance_hist_(var); - } + if (scheme_ == DMCRefEnergyScheme::LIMITED_HISTORY) + energy_and_variance_.push({weight, ene, var}); + else + { + energy_hist_(ene); + variance_hist_(var); + } } size_t DMCRefEnergy::count() const +{ + if (scheme_ == DMCRefEnergyScheme::LIMITED_HISTORY) + return energy_and_variance_.size(); + else { - if (scheme_ == LIMITED_HISTORY) - return energy_and_variance_.size(); - else - { - assert(energy_hist_.count() == variance_hist_.count()); - return energy_hist_.count(); - } + assert(energy_hist_.count() == variance_hist_.count()); + return energy_hist_.count(); } +} } // namespace qmcplusplus diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.h b/src/QMCDrivers/DMC/DMCRefEnergy.h index 28991e321e..cb122ea508 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.h +++ b/src/QMCDrivers/DMC/DMCRefEnergy.h @@ -16,6 +16,7 @@ #include #include #include +#include "DMCRefEnergyScheme.h" namespace qmcplusplus { @@ -24,12 +25,7 @@ namespace qmcplusplus class DMCRefEnergy { public: - using FullPrecRealType = QMCTraits::FullPrecRealType; - enum Scheme - { - LEGACY, - LIMITED_HISTORY - } scheme_; + using FullPrecReal = QMCTraits::FullPrecRealType; enum DataLayout { @@ -39,23 +35,26 @@ class DMCRefEnergy }; private: + /// scheme + DMCRefEnergyScheme scheme_; + // legacy scheme data ///a simple accumulator for energy - accumulator_set energy_hist_; + accumulator_set energy_hist_; ///a simple accumulator for variance - accumulator_set variance_hist_; + accumulator_set variance_hist_; // limited memory scheme data - SizeLimitedDataQueue energy_and_variance_; + SizeLimitedDataQueue energy_and_variance_; public: - DMCRefEnergy(Scheme scheme, size_t history_limit); + DMCRefEnergy(DMCRefEnergyScheme scheme, size_t history_limit); /// return energy and variance - std::tuple getEnergyVariance() const; + std::tuple getEnergyVariance() const; /// record weight, energy and variance. - void pushWeightEnergyVariance(FullPrecRealType weight, FullPrecRealType ene, FullPrecRealType var); + void pushWeightEnergyVariance(FullPrecReal weight, FullPrecReal ene, FullPrecReal var); /// return record count. size_t count() const; diff --git a/src/QMCDrivers/DMC/DMCRefEnergyScheme.h b/src/QMCDrivers/DMC/DMCRefEnergyScheme.h new file mode 100644 index 0000000000..efef598fa8 --- /dev/null +++ b/src/QMCDrivers/DMC/DMCRefEnergyScheme.h @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////////////////////////// +// This file is distributed under the University of Illinois/NCSA Open Source License. +// See LICENSE file in top directory for details. +// +// Copyright (c) 2023 QMCPACK developers. +// +// File developed by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +// +// File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory +////////////////////////////////////////////////////////////////////////////////////// +// -*- C++ -*- +#ifndef QMCPLUSPLUS_DMCREFENERGYSCHEME_H +#define QMCPLUSPLUS_DMCREFENERGYSCHEME_H + +namespace qmcplusplus +{ +/** DMCRefEnergy schemes + */ +enum class DMCRefEnergyScheme +{ + LEGACY, + LIMITED_HISTORY +}; +} // namespace qmcplusplus +#endif diff --git a/src/QMCDrivers/SFNBranch.cpp b/src/QMCDrivers/SFNBranch.cpp index 14a4a1b120..1860030397 100644 --- a/src/QMCDrivers/SFNBranch.cpp +++ b/src/QMCDrivers/SFNBranch.cpp @@ -31,7 +31,7 @@ enum DUMMYOPT }; -SFNBranch::SFNBranch(RealType tau, RealType feedback, DMCRefEnergy::Scheme refenergy_update_scheme) +SFNBranch::SFNBranch(RealType tau, RealType feedback, DMCRefEnergyScheme refenergy_update_scheme) : WarmUpToDoSteps(0), EtrialUpdateToDoSteps(0), myNode(NULL), diff --git a/src/QMCDrivers/SFNBranch.h b/src/QMCDrivers/SFNBranch.h index cd4cddf1db..712cfc9b27 100644 --- a/src/QMCDrivers/SFNBranch.h +++ b/src/QMCDrivers/SFNBranch.h @@ -149,7 +149,7 @@ class SFNBranch : public QMCTraits using VParamType = VParams; ///Constructor - SFNBranch(RealType tau, RealType feedback, DMCRefEnergy::Scheme); + SFNBranch(RealType tau, RealType feedback, DMCRefEnergyScheme); ///copy constructor SFNBranch(const SFNBranch& abranch) = delete; diff --git a/src/QMCDrivers/tests/test_SFNBranch.cpp b/src/QMCDrivers/tests/test_SFNBranch.cpp index e7d8c53d21..d2ccdc1d5d 100644 --- a/src/QMCDrivers/tests/test_SFNBranch.cpp +++ b/src/QMCDrivers/tests/test_SFNBranch.cpp @@ -49,7 +49,7 @@ class SetupSFNBranch walkers[0].get().R[0] = 1.0; walkers[1].get().R[0] = 0.5; - auto sfnb = std::make_unique(tau_, 1.0, DMCRefEnergy::Scheme::LIMITED_HISTORY); + auto sfnb = std::make_unique(tau_, 1.0, DMCRefEnergyScheme::LIMITED_HISTORY); createMyNode(*sfnb, valid_dmc_input_sections[valid_dmc_input_dmc_batch_index]); From 718a53020a4abc8e1edea23877187e4437bfd00c Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Sat, 4 Mar 2023 17:00:28 -0600 Subject: [PATCH 10/12] Fix warning. --- src/Estimators/tests/test_SizeLimitedDataQueue.cpp | 2 +- src/QMCDrivers/DMC/DMCRefEnergy.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Estimators/tests/test_SizeLimitedDataQueue.cpp b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp index c06f6d5507..88925cff67 100644 --- a/src/Estimators/tests/test_SizeLimitedDataQueue.cpp +++ b/src/Estimators/tests/test_SizeLimitedDataQueue.cpp @@ -39,7 +39,7 @@ TEST_CASE("SizeLimitedDataQueue", "[estimators]") CHECK(Approx(avg[0]) == 1.444444444); } { - weight_and_energy.push({0.5, 3.0}); + weight_and_energy.push({0.5, {3.0}}); CHECK(weight_and_energy.size() == 3); auto avg = weight_and_energy.weighted_avg(); CHECK(Approx(avg[0]) == 1.5); diff --git a/src/QMCDrivers/DMC/DMCRefEnergy.cpp b/src/QMCDrivers/DMC/DMCRefEnergy.cpp index a71bb207ea..0ae22692ac 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergy.cpp +++ b/src/QMCDrivers/DMC/DMCRefEnergy.cpp @@ -35,7 +35,7 @@ std::tuple DMCRefEnergy::getEnergyVariance() const void DMCRefEnergy::pushWeightEnergyVariance(FullPrecReal weight, FullPrecReal ene, FullPrecReal var) { if (scheme_ == DMCRefEnergyScheme::LIMITED_HISTORY) - energy_and_variance_.push({weight, ene, var}); + energy_and_variance_.push({weight, {ene, var}}); else { energy_hist_(ene); From 1ed62ef568245e1f3ec859e3e6d5d786030b01b0 Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Sun, 5 Mar 2023 22:10:05 -0600 Subject: [PATCH 11/12] Rename option value from legacy to unlimited_history. --- src/QMCDrivers/DMC/DMCBatched.cpp | 2 +- src/QMCDrivers/DMC/DMCDriverInput.cpp | 6 +++--- src/QMCDrivers/DMC/DMCRefEnergyScheme.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/QMCDrivers/DMC/DMCBatched.cpp b/src/QMCDrivers/DMC/DMCBatched.cpp index 5e265bb1c2..58b2e4c08c 100644 --- a/src/QMCDrivers/DMC/DMCBatched.cpp +++ b/src/QMCDrivers/DMC/DMCBatched.cpp @@ -396,7 +396,7 @@ void DMCBatched::process(xmlNodePtr node) app_log() << " Creating the branching engine and walker controler" << std::endl; const auto refE_update_scheme = dmcdriver_input_.get_refenergy_update_scheme(); app_log() << " Reference energy is updated using the " - << (refE_update_scheme == DMCRefEnergyScheme::LEGACY ? "legacy" : "history limited") << " scheme" + << (refE_update_scheme == DMCRefEnergyScheme::UNLIMITED_HISTORY ? "unlimited_history" : "limited_history") << " scheme" << std::endl; branch_engine_ = std::make_unique(qmcdriver_input_.get_tau(), dmcdriver_input_.get_feedback(), refE_update_scheme); diff --git a/src/QMCDrivers/DMC/DMCDriverInput.cpp b/src/QMCDrivers/DMC/DMCDriverInput.cpp index b4cab5512f..d954069722 100644 --- a/src/QMCDrivers/DMC/DMCDriverInput.cpp +++ b/src/QMCDrivers/DMC/DMCDriverInput.cpp @@ -25,7 +25,7 @@ void DMCDriverInput::readXML(xmlNodePtr node) parameter_set_.add(NonLocalMove, "nonlocalmoves", {"no", "yes", "v0", "v1", "v3"}); parameter_set_.add(max_age_, "MaxAge"); parameter_set_.add(feedback_, "feedback"); - parameter_set_.add(refE_update_scheme_str, "refenergy_update_scheme", {"legacy", "limited_history"}); + parameter_set_.add(refE_update_scheme_str, "refenergy_update_scheme", {"unlimited_history", "limited_history"}); // from DMC.cpp put(xmlNodePtr) parameter_set_.add(branch_interval_, "branchInterval"); @@ -68,8 +68,8 @@ void DMCDriverInput::readXML(xmlNodePtr node) if (reserve_ < 1.0) throw std::runtime_error("You can only reserve walkers above the target walker count"); - if (refE_update_scheme_str == "legacy") - refenergy_update_scheme_ = DMCRefEnergyScheme::LEGACY; + if (refE_update_scheme_str == "unlimited_history") + refenergy_update_scheme_ = DMCRefEnergyScheme::UNLIMITED_HISTORY; else refenergy_update_scheme_ = DMCRefEnergyScheme::LIMITED_HISTORY; } diff --git a/src/QMCDrivers/DMC/DMCRefEnergyScheme.h b/src/QMCDrivers/DMC/DMCRefEnergyScheme.h index efef598fa8..caa4d8f339 100644 --- a/src/QMCDrivers/DMC/DMCRefEnergyScheme.h +++ b/src/QMCDrivers/DMC/DMCRefEnergyScheme.h @@ -18,7 +18,7 @@ namespace qmcplusplus */ enum class DMCRefEnergyScheme { - LEGACY, + UNLIMITED_HISTORY, LIMITED_HISTORY }; } // namespace qmcplusplus From 8a4bd5882036570ece642d85e785967386ec7b65 Mon Sep 17 00:00:00 2001 From: Ye Luo Date: Wed, 8 Mar 2023 17:41:00 -0600 Subject: [PATCH 12/12] Fix doc. --- docs/methods.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/methods.rst b/docs/methods.rst index e76bb124c5..bb0913f8cf 100644 --- a/docs/methods.rst +++ b/docs/methods.rst @@ -1765,9 +1765,9 @@ Batched ``dmc`` driver (experimental) .. math:: - E_\text{trial} = E_\text{pop_avg}+(\ln \texttt{targetwalkers}-\ln N_\text{pop}) / \texttt{timestep} + E_\text{trial} = E_\text{pop\_avg}+(\ln \texttt{targetwalkers}-\ln N_\text{pop}) / \texttt{timestep} -where :math:`E_\text{pop_avg}` is the local energy average over the walker population at the current step +where :math:`E_\text{pop\_avg}` is the local energy average over the walker population at the current step and :math:`N_\text{pop}` is the current walker population size. After the warm-up phase, the trial energy is updated as @@ -1775,7 +1775,7 @@ After the warm-up phase, the trial energy is updated as E_\text{trial} = E_\text{ref}+\texttt{feedback}\cdot(\ln\texttt{targetWalkers}-\ln N_\text{pop}) -where :math:`E_\text{ref}` is the :math:`E_\text{pop_avg}` average over all the post warm-up steps up to the current step. The update frequency is controlled by ``energyUpdateInterval``. +where :math:`E_\text{ref}` is the :math:`E_\text{pop\_avg}` average over all the post warm-up steps up to the current step. The update frequency is controlled by ``energyUpdateInterval``. - ``energyUpdateInterval``: Post warm-up, the trial energy is updated every ``energyUpdateInterval`` steps. Default value is 1 (every step). @@ -1789,9 +1789,9 @@ where :math:`E_\text{ref}` is the :math:`E_\text{pop_avg}` average over all the equation in ``warmupsteps`` for more details. - ``refenergy_update_scheme``: choose a scheme for updating :math:`E_\text{ref}` used in calculating :math:`E_\text{trial}`. - 'legacy' uses unweighted average of :math:`E_\text{pop_avg}` of all the steps collected post warm-up. - 'limited_history' uses weighted average of :math:`E_\text{pop_avg}` of the latest at maximum - min(1, int(1.0 / (feedback * tau))) steps collected post warm-up. Default 'legacy'. + 'unlimited_history' uses unweighted average of :math:`E_\text{pop\_avg}` of all the steps collected post warm-up. + 'limited_history' uses weighted average of :math:`E_\text{pop\_avg}` of the latest at maximum + min(1, int(1.0 / (feedback * tau))) steps collected post warm-up. Default 'unlimited_history'. .. code-block:: :caption: The following is an example of a minimal DMC section using the batched ``dmc`` driver