From 220116a14232559651f66c3611012c7bdfb4d473 Mon Sep 17 00:00:00 2001 From: Xiaoyang Zhang Date: Mon, 21 Sep 2026 14:08:59 +0800 Subject: [PATCH] tests: take three charge/DM tests off #define private public Redo of the work in #7988 and #7990, both of which were closed while the charge density module was being restructured. That restructuring landed in #7972 and already did most of the decoupling those PRs proposed: allocate(), renormalize_rho() and sum_rho() now take their inputs explicitly, the mixing parameters are aggregated in a MixingConfig, and chg_mix.cpp / chg_drho.cpp / charge.cpp are free of global parameter reads. What was left was the test-side access. Production changes are additive only - no existing signature moves and no line is deleted from any production header: Charge::get_allocate_rho() - report whether allocate() has run Charge_Mixing::get_rho_mdata() - mirror the existing get_dmr_mdata() Charge_Mixing::get_tau_mdata() Charge_Mixing::set_mixing_config() - pair for the existing getter, for callers that must update the snapshot without rebuilding the mixing history XC_Functional::set_func_type() - pair for get_func_type() XC_Functional::set_ked_flag() - pair for get_ked_flag() Test changes: test_dm_r_init - two sites move to the already public get_DMR_save() test_charge - the global parameter scratchpad becomes fixture state (32 refs -> 0); PW_Basis setup goes through the public initgrids/initparameters/setuptransform sequence instead of the protected distribute_r()/distribute_g() test_chg_mix - the scratchpad becomes a fixture-owned MixingConfig (163 refs -> 0); the three blocks that hand-wired Charge::_space_* now take their buffers from the fixture, which owns them as vectors and points the public rho/rhog/kin_r views at them with the same stride No expected value or tolerance was changed. Co-Authored-By: Claude Opus 5 (1M context) --- source/source_estate/module_charge/charge.h | 5 + source/source_estate/module_charge/chg_mix.h | 25 + .../module_charge/unittests/test_charge.cpp | 121 ++-- .../module_charge/unittests/test_chg_mix.cpp | 660 +++++++++--------- .../module_dm/test/test_dm_r_init.cpp | 6 +- .../source_hamilt/module_xc/xc_functional.h | 14 + 6 files changed, 428 insertions(+), 403 deletions(-) diff --git a/source/source_estate/module_charge/charge.h b/source/source_estate/module_charge/charge.h index 098113972cb..fb2aa242ebd 100644 --- a/source/source_estate/module_charge/charge.h +++ b/source/source_estate/module_charge/charge.h @@ -135,6 +135,11 @@ class Charge void save_rho_before_sum_band(); + /// @brief whether allocate() has already claimed the density buffers + /// @return true once allocate() has run; allocate() is idempotent and + /// returns early when this is already true + bool get_allocate_rho() const { return allocate_rho; } + // mohan add 2021-02-20 int nrxx=0; // number of r vectors in this processor int nxyz = 0; // total number of r vectors diff --git a/source/source_estate/module_charge/chg_mix.h b/source/source_estate/module_charge/chg_mix.h index 4cf6ca2e738..2bdc6a4ad56 100644 --- a/source/source_estate/module_charge/chg_mix.h +++ b/source/source_estate/module_charge/chg_mix.h @@ -93,11 +93,36 @@ class Charge_Mixing */ Base_Mixing::Mixing_Data& get_dmr_mdata() {return dmr_mdata;} + /** + * @brief mutable access to the charge-density mixing history + * + * Same ownership story as get_dmr_mdata(): the buffer belongs to + * Charge_Mixing but is driven through Base_Mixing::Mixing, so callers + * that reset or inspect the history need a handle on it. + */ + Base_Mixing::Mixing_Data& get_rho_mdata() {return rho_mdata;} + + /** + * @brief mutable access to the kinetic-energy-density mixing history + */ + Base_Mixing::Mixing_Data& get_tau_mdata() {return tau_mdata;} + /** * @brief read-only access to the aggregated mixing config set by set_mixing() */ const MixingConfig& get_mixing_config() const {return cfg_;} + /** + * @brief replace the aggregated mixing config without re-running set_mixing() + * + * set_mixing() both stores the config and rebuilds the mixing objects. This + * setter is for callers that need to update the snapshot alone - typically + * because a derived runtime global (nspin, domag, ...) changed after the + * mixing objects were already built - and must not disturb the mixing + * history. Pair it with get_mixing_config() to amend individual fields. + */ + void set_mixing_config(const MixingConfig& cfg) {cfg_ = cfg;} + // for mixing restart /// which step to restart mixing during SCF int mixing_restart_step = 0; diff --git a/source/source_estate/module_charge/unittests/test_charge.cpp b/source/source_estate/module_charge/unittests/test_charge.cpp index f491ccf5f70..ad65a910293 100644 --- a/source/source_estate/module_charge/unittests/test_charge.cpp +++ b/source/source_estate/module_charge/unittests/test_charge.cpp @@ -1,13 +1,10 @@ #include "gtest/gtest.h" #include "gmock/gmock.h" -#define private public -#define protected public #include "source_cell/unitcell.h" #include "source_estate/module_charge/charge.h" #include "source_estate/module_charge/chg_tools.h" #include "source_hamilt/module_xc/xc_functional.h" -#include "source_io/module_parameter/parameter.h" #include "prepare_unitcell.h" // mock functions for UnitCell @@ -21,18 +18,15 @@ Magnetism::~Magnetism() } // mock functions for Charge +// xc_functional.cpp is not linked into this target, so the private statics +// need a definition here. Defining them out of line does not require access +// to the class, only changing them does - that goes through the setters. int XC_Functional::func_type = 1; bool XC_Functional::ked_flag = false; namespace elecstate { double tmp_ucell_omega = 500.0; double tmp_gridecut = 80.0; -void Set_GlobalV_Default() -{ - PARAM.input.nspin = 1; - PARAM.input.test_charge = 0; - PARAM.input.nelec = 8; -} } // namespace elecstate /************************************************ @@ -45,7 +39,7 @@ void Set_GlobalV_Default() * - this is a trivial test * - Allocate: Charge::set_rhopw(), Charge::allocate(), Charge::destroy() * - allocate rho, rhog, rho_save, rhog_save, kin_r, kin_r_save - * - using rhopw and PARAM.input.nspin + * - using rhopw and the nspin passed in * - SumRho: Charge::sum_rho() * - calculate \sum_{is}^nspin \sum_{ir}^nrxx rho[is][ir] * - RenormalizeRho: Charge::renormalize_rho() @@ -64,16 +58,23 @@ class ChargeTest : public ::testing::Test Charge* charge; ModulePW::PW_Basis* rhopw; std::string output; + /// Charge::allocate() and Charge::renormalize_rho() take these explicitly, + /// so the fixture owns them instead of writing the global parameter + /// singleton. The values mirror the Input_para defaults the test relied on. + int nspin = 1; + int test_charge = 0; + double nelec = 8; + bool out_elf_on = false; void SetUp() override { - elecstate::Set_GlobalV_Default(); ucell = utp.SetUcellInfo(); charge = new Charge; rhopw = new ModulePW::PW_Basis; rhopw->initgrids(ucell->lat0, ucell->latvec, elecstate::tmp_gridecut); - rhopw->distribute_r(); rhopw->initparameters(false, elecstate::tmp_gridecut); - rhopw->distribute_g(); + // setuptransform() runs distribute_r() then distribute_g(), both of + // which are protected; this is the public route to the same state. + rhopw->setuptransform(); } void TearDown() override { @@ -84,7 +85,7 @@ class ChargeTest : public ::testing::Test TEST_F(ChargeTest, Constructor) { - EXPECT_FALSE(charge->allocate_rho); + EXPECT_FALSE(charge->get_allocate_rho()); } TEST_F(ChargeTest, Allocate) @@ -101,79 +102,75 @@ TEST_F(ChargeTest, Allocate) EXPECT_EQ(rhopw->npw, 3143); EXPECT_EQ(rhopw->npwtot, 3143); // call Charge::allocate() - PARAM.input.test_charge = 2; - XC_Functional::func_type = 3; - XC_Functional::ked_flag = true; + test_charge = 2; + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(true); charge->set_rhopw(rhopw); - EXPECT_FALSE(charge->allocate_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (PARAM.input.out_elf[0] > 0); - charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge); - EXPECT_TRUE(charge->allocate_rho); + EXPECT_FALSE(charge->get_allocate_rho()); + const bool kin_den = XC_Functional::get_ked_flag() || out_elf_on; + charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), test_charge); + EXPECT_TRUE(charge->get_allocate_rho()); // test if Charge::allocate() be called twice - EXPECT_NO_THROW(charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge)); - EXPECT_TRUE(charge->allocate_rho); + EXPECT_NO_THROW(charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), + test_charge)); + EXPECT_TRUE(charge->get_allocate_rho()); } TEST_F(ChargeTest, SumRho) { charge->set_rhopw(rhopw); - EXPECT_FALSE(charge->allocate_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (PARAM.input.out_elf[0] > 0); - charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge); - EXPECT_TRUE(charge->allocate_rho); - int nspin = (PARAM.input.nspin == 2) ? 2 : 1; - for (int is = 0; is < nspin; is++) + EXPECT_FALSE(charge->get_allocate_rho()); + const bool kin_den = XC_Functional::get_ked_flag() || out_elf_on; + charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), test_charge); + EXPECT_TRUE(charge->get_allocate_rho()); + int nspin_rho = (nspin == 2) ? 2 : 1; + for (int is = 0; is < nspin_rho; is++) { for (int ir = 0; ir < rhopw->nrxx; ir++) { charge->rho[is][ir] = 0.1; } } - EXPECT_NEAR(charge->sum_rho(ucell->omega), 0.1 * nspin * rhopw->nrxx * ucell->omega / rhopw->nxyz, 1E-10); + EXPECT_NEAR(charge->sum_rho(ucell->omega), 0.1 * nspin_rho * rhopw->nrxx * ucell->omega / rhopw->nxyz, 1E-10); } TEST_F(ChargeTest, RenormalizeRho) { charge->set_rhopw(rhopw); - EXPECT_FALSE(charge->allocate_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (PARAM.input.out_elf[0] > 0); - charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge); - EXPECT_TRUE(charge->allocate_rho); - int nspin = (PARAM.input.nspin == 2) ? 2 : 1; - for (int is = 0; is < nspin; is++) + EXPECT_FALSE(charge->get_allocate_rho()); + const bool kin_den = XC_Functional::get_ked_flag() || out_elf_on; + charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), test_charge); + EXPECT_TRUE(charge->get_allocate_rho()); + int nspin_rho = (nspin == 2) ? 2 : 1; + for (int is = 0; is < nspin_rho; is++) { for (int ir = 0; ir < rhopw->nrxx; ir++) { charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(PARAM.input.nelec, 8); - charge->renormalize_rho(PARAM.input.nelec, ucell->omega); + EXPECT_EQ(nelec, 8); + charge->renormalize_rho(nelec, ucell->omega); EXPECT_NEAR(charge->sum_rho(ucell->omega), 8.0, 1e-10); } TEST_F(ChargeTest, CheckNe) { charge->set_rhopw(rhopw); - EXPECT_FALSE(charge->allocate_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (PARAM.input.out_elf[0] > 0); - charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge); - EXPECT_TRUE(charge->allocate_rho); - int nspin = (PARAM.input.nspin == 2) ? 2 : 1; - for (int is = 0; is < nspin; is++) + EXPECT_FALSE(charge->get_allocate_rho()); + const bool kin_den = XC_Functional::get_ked_flag() || out_elf_on; + charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), test_charge); + EXPECT_TRUE(charge->get_allocate_rho()); + int nspin_rho = (nspin == 2) ? 2 : 1; + for (int is = 0; is < nspin_rho; is++) { for (int ir = 0; ir < rhopw->nrxx; ir++) { charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(PARAM.input.nelec, 8); - charge->renormalize_rho(PARAM.input.nelec, ucell->omega); + EXPECT_EQ(nelec, 8); + charge->renormalize_rho(nelec, ucell->omega); EXPECT_NEAR(charge->sum_rho(ucell->omega), 8.0, 1e-10); EXPECT_NEAR(module_charge::cal_rho2ne(charge->rho[0], rhopw->nrxx, ucell->omega, rhopw->nxyz), 8.0, 1e-10); @@ -182,25 +179,23 @@ TEST_F(ChargeTest, CheckNe) TEST_F(ChargeTest, SaveRhoBeforeSumBand) { charge->set_rhopw(rhopw); - EXPECT_FALSE(charge->allocate_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (PARAM.input.out_elf[0] > 0); - charge->allocate(PARAM.input.nspin, kin_den, XC_Functional::get_ked_flag(), - PARAM.input.test_charge); - EXPECT_TRUE(charge->allocate_rho); - int nspin = (PARAM.input.nspin == 2) ? 2 : 1; - for (int is = 0; is < nspin; is++) + EXPECT_FALSE(charge->get_allocate_rho()); + const bool kin_den = XC_Functional::get_ked_flag() || out_elf_on; + charge->allocate(nspin, kin_den, XC_Functional::get_ked_flag(), test_charge); + EXPECT_TRUE(charge->get_allocate_rho()); + int nspin_rho = (nspin == 2) ? 2 : 1; + for (int is = 0; is < nspin_rho; is++) { for (int ir = 0; ir < rhopw->nrxx; ir++) { charge->rho[is][ir] = 0.1; } } - EXPECT_EQ(PARAM.input.nelec, 8); - XC_Functional::func_type = 3; - XC_Functional::ked_flag = true; - charge->renormalize_rho(PARAM.input.nelec, ucell->omega); + EXPECT_EQ(nelec, 8); + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(true); + charge->renormalize_rho(nelec, ucell->omega); charge->save_rho_before_sum_band(); EXPECT_NEAR(module_charge::cal_rho2ne(charge->rho_save[0], rhopw->nrxx, ucell->omega, rhopw->nxyz), 8.0, 1e-10); } - diff --git a/source/source_estate/module_charge/unittests/test_chg_mix.cpp b/source/source_estate/module_charge/unittests/test_chg_mix.cpp index 0de1e8463e2..3146275c7ad 100644 --- a/source/source_estate/module_charge/unittests/test_chg_mix.cpp +++ b/source/source_estate/module_charge/unittests/test_chg_mix.cpp @@ -1,9 +1,5 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -// TODO(governance): remove this access hack once chg_drho.cpp and Charge no -// longer read global PARAM/RAW state (Step 4 of the module_charge refactor). -// The test still has to drive Charge::_space_* and XC_Functional privates. -#define private public #include "../chg_mix.h" #include "../chg_drho.h" #include "../chg_drho_detail.h" @@ -12,7 +8,6 @@ #include "source_base/module_mixing/broyden_mixing.h" #include "source_basis/module_pw/pw_basis.h" #include "source_hamilt/module_xc/xc_functional.h" -#include "source_io/module_parameter/parameter.h" #ifdef _OPENMP #include @@ -92,16 +87,25 @@ class ChargeMixingTest : public ::testing::Test pw_dbasis.setuptransform(&pw_basis); pw_dbasis.collect_local_pw(); // default mixing parameters - PARAM.input.mixing_mode = "broyden"; - PARAM.input.mixing_beta = 0.8; - PARAM.input.mixing_ndim = 8; - PARAM.input.mixing_gg0 = 1.0; - PARAM.input.mixing_tau = false; - PARAM.input.mixing_beta_mag = 1.6; - PARAM.input.mixing_gg0_mag = 0.0; - PARAM.input.mixing_gg0_min = 0.1; - PARAM.input.mixing_angle = -10.0; - PARAM.input.mixing_dmr = false; + cfg.mixing_mode = "broyden"; + cfg.mixing_beta = 0.8; + cfg.mixing_ndim = 8; + cfg.mixing_gg0 = 1.0; + cfg.mixing_tau = false; + cfg.mixing_beta_mag = 1.6; + cfg.mixing_gg0_mag = 0.0; + cfg.mixing_gg0_min = 0.1; + cfg.mixing_angle = -10.0; + cfg.mixing_dmr = false; + // the remaining fields are runtime globals the tests steer per case; + // seed them with the Input_para / System_para defaults + cfg.nspin = 1; + cfg.scf_thr_type = -1; + cfg.double_grid = false; + cfg.gamma_only_pw = false; + cfg.domag = false; + cfg.domag_z = false; + cfg.scf_nmax = 100; ucell.omega = 1.0; ucell.tpiba = 1.0; } @@ -109,49 +113,84 @@ class ChargeMixingTest : public ::testing::Test ModulePW::PW_Basis_Sup pw_dbasis; Charge charge; - // Build a MixingConfig from the PARAM.input values set in the ctor, so - // set_mixing is driven by explicit config instead of a 12-arg call. - // Aggregate-initialize so that adding a field to MixingConfig without - // updating this list is a compile error (-Wmissing-field-initializers - // promoted to error via pragma). Fields are in declaration order. + /// The mixing configuration under test. The production mixing code takes + /// this snapshot explicitly rather than reading any global, so the fixture + /// owns it outright instead of staging values in the parameter singleton; + /// each case amends the fields it cares about and hands it to set_mixing(). + MixingConfig cfg; + + /// Backing storage for the Charge views under test. charge.cpp is not one + /// of this target's sources, so Charge::allocate() is unavailable here and + /// the fixture supplies the buffers itself, pointing the public + /// rho/rhog/kin_r views at them with the same is*nrxx (resp. is*npw) + /// stride allocate() would lay out. Owning them as vectors also means the + /// fixture cleans up after itself. + std::vector buf_rho, buf_rho_save, buf_kin_r, buf_kin_r_save; + std::vector> buf_rhog, buf_rhog_save; + std::vector ptr_rho, ptr_rho_save, ptr_kin_r, ptr_kin_r_save; + std::vector*> ptr_rhog, ptr_rhog_save; + + void wire_charge(const int nspin, const int nrxx, const int npw, const bool kin_den) + { + buf_rho.assign(nspin * nrxx, 0.0); + buf_rho_save.assign(nspin * nrxx, 0.0); + buf_rhog.assign(nspin * npw, std::complex(0.0, 0.0)); + buf_rhog_save.assign(nspin * npw, std::complex(0.0, 0.0)); + ptr_rho.resize(nspin); + ptr_rho_save.resize(nspin); + ptr_rhog.resize(nspin); + ptr_rhog_save.resize(nspin); + for (int is = 0; is < nspin; is++) + { + ptr_rho[is] = buf_rho.data() + is * nrxx; + ptr_rho_save[is] = buf_rho_save.data() + is * nrxx; + ptr_rhog[is] = buf_rhog.data() + is * npw; + ptr_rhog_save[is] = buf_rhog_save.data() + is * npw; + } + charge.rho = ptr_rho.data(); + charge.rho_save = ptr_rho_save.data(); + charge.rhog = ptr_rhog.data(); + charge.rhog_save = ptr_rhog_save.data(); + if (kin_den) + { + buf_kin_r.assign(nspin * nrxx, 0.0); + buf_kin_r_save.assign(nspin * nrxx, 0.0); + ptr_kin_r.resize(nspin); + ptr_kin_r_save.resize(nspin); + for (int is = 0; is < nspin; is++) + { + ptr_kin_r[is] = buf_kin_r.data() + is * nrxx; + ptr_kin_r_save[is] = buf_kin_r_save.data() + is * nrxx; + } + charge.kin_r = ptr_kin_r.data(); + charge.kin_r_save = ptr_kin_r_save.data(); + } + } + + // mixing_tau is only honoured when the functional actually carries a + // kinetic energy density, which set_mixing's callers fold in. Cases flip + // XC_Functional::set_ked_flag() around, so apply it at hand-off time. MixingConfig make_cfg() { -#pragma GCC diagnostic push -#pragma GCC diagnostic error "-Wmissing-field-initializers" - MixingConfig cfg{ - PARAM.input.mixing_mode, // mixing_mode - PARAM.input.mixing_beta, // mixing_beta - PARAM.input.mixing_ndim, // mixing_ndim - PARAM.input.mixing_gg0, // mixing_gg0 - PARAM.input.mixing_tau && XC_Functional::get_ked_flag(), // mixing_tau - PARAM.input.mixing_beta_mag, // mixing_beta_mag - PARAM.input.mixing_gg0_mag, // mixing_gg0_mag - PARAM.input.mixing_gg0_min, // mixing_gg0_min - PARAM.input.mixing_angle, // mixing_angle - PARAM.input.mixing_dmr, // mixing_dmr - PARAM.input.nspin, // nspin - PARAM.input.scf_thr_type, // scf_thr_type - PARAM.globalv.double_grid, // double_grid - PARAM.globalv.gamma_only_pw, // gamma_only_pw - PARAM.globalv.domag, // domag - PARAM.globalv.domag_z, // domag_z - PARAM.input.scf_nmax // scf_nmax - }; -#pragma GCC diagnostic pop - return cfg; + MixingConfig out = cfg; + out.mixing_tau = cfg.mixing_tau && XC_Functional::get_ked_flag(); + return out; } // Re-sync the runtime globals (nspin/scf_thr_type/gamma_only_pw/domag/domag_z) - // into an already-configured Charge_Mixing. Tests mutate PARAM.sys/PARAM.input - // after set_mixing to steer the residual/inner-product branches; the object - // now reads them from cfg_, so the test must push the new values in. + // into an already-configured Charge_Mixing. Cases mutate them after + // set_mixing to steer the residual/inner-product branches, and the object + // reads them from its own snapshot, so the test must push the new values in + // without disturbing the mixing history that init_mixing() built. void sync_cfg(Charge_Mixing& cm) { - cm.cfg_.nspin = PARAM.input.nspin; - cm.cfg_.scf_thr_type = PARAM.input.scf_thr_type; - cm.cfg_.gamma_only_pw = PARAM.sys.gamma_only_pw; - cm.cfg_.domag = PARAM.sys.domag; - cm.cfg_.domag_z = PARAM.sys.domag_z; + MixingConfig cur = cm.get_mixing_config(); + cur.nspin = cfg.nspin; + cur.scf_thr_type = cfg.scf_thr_type; + cur.gamma_only_pw = cfg.gamma_only_pw; + cur.domag = cfg.domag; + cur.domag_z = cfg.domag_z; + cm.set_mixing_config(cur); } }; @@ -160,12 +199,12 @@ TEST_F(ChargeMixingTest, SetMixingTest) #ifdef _OPENMP omp_set_num_threads(1); #endif - PARAM.input.nspin = 1; + cfg.nspin = 1; Charge_Mixing CMtest; CMtest.set_rhopw(&pw_basis, &pw_basis); - PARAM.input.mixing_beta = 1.0; - PARAM.input.mixing_ndim = 1; - PARAM.input.mixing_gg0 = 1.0; + cfg.mixing_beta = 1.0; + cfg.mixing_ndim = 1; + cfg.mixing_gg0 = 1.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); EXPECT_EQ(CMtest.get_mixing_mode(), "broyden"); @@ -179,33 +218,33 @@ TEST_F(ChargeMixingTest, SetMixingTest) EXPECT_EQ(CMtest.get_mixing_config().mixing_angle, -10.0); EXPECT_EQ(CMtest.get_mixing_config().mixing_dmr, false); - PARAM.input.mixing_tau = true; - XC_Functional::ked_flag = true; - PARAM.input.mixing_mode = "plain"; + cfg.mixing_tau = true; + XC_Functional::set_ked_flag(true); + cfg.mixing_mode = "plain"; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); EXPECT_EQ(CMtest.get_mixing_mode(), "plain"); EXPECT_EQ(CMtest.get_mixing_config().mixing_tau, true); - XC_Functional::ked_flag = false; + XC_Functional::set_ked_flag(false); - PARAM.input.mixing_beta = 1.1; + cfg.mixing_beta = 1.1; std::string output; testing::internal::CaptureStdout(); EXPECT_EXIT(CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba);, ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("You'd better set mixing_beta to [0.0, 1.0]!")); - PARAM.input.mixing_beta = 0.7; - PARAM.input.mixing_beta_mag = -0.1; - PARAM.input.nspin = 2; + cfg.mixing_beta = 0.7; + cfg.mixing_beta_mag = -0.1; + cfg.nspin = 2; testing::internal::CaptureStdout(); EXPECT_EXIT(CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba);, ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("You'd better set mixing_beta_mag >= 0.0!")); - PARAM.input.nspin = 1; - PARAM.input.mixing_beta = 0.7; - PARAM.input.mixing_beta_mag = 1.6; - PARAM.input.mixing_mode = "nothing"; + cfg.nspin = 1; + cfg.mixing_beta = 0.7; + cfg.mixing_beta_mag = 1.6; + cfg.mixing_mode = "nothing"; testing::internal::CaptureStdout(); EXPECT_EXIT(CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba);, ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); @@ -217,42 +256,42 @@ TEST_F(ChargeMixingTest, InitMixingTest) #ifdef _OPENMP omp_set_num_threads(1); #endif - PARAM.input.nspin = 1; - XC_Functional::func_type = 1; - XC_Functional::ked_flag = false; + cfg.nspin = 1; + XC_Functional::set_func_type(1); + XC_Functional::set_ked_flag(false); Charge_Mixing CMtest; CMtest.set_rhopw(&pw_basis, &pw_basis); CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - PARAM.input.scf_thr_type= 1; + cfg.scf_thr_type= 1; sync_cfg(CMtest); CMtest.init_mixing(); - EXPECT_EQ(CMtest.rho_mdata.length, pw_basis.npw); + EXPECT_EQ(CMtest.get_rho_mdata().length, pw_basis.npw); - PARAM.input.scf_thr_type= 2; + cfg.scf_thr_type= 2; sync_cfg(CMtest); CMtest.init_mixing(); - EXPECT_EQ(CMtest.rho_mdata.length, pw_basis.nrxx); + EXPECT_EQ(CMtest.get_rho_mdata().length, pw_basis.nrxx); - PARAM.input.nspin = 4; + cfg.nspin = 4; sync_cfg(CMtest); CMtest.init_mixing(); - EXPECT_EQ(CMtest.rho_mdata.length, 4 * pw_basis.nrxx); + EXPECT_EQ(CMtest.get_rho_mdata().length, 4 * pw_basis.nrxx); - PARAM.input.nspin = 1; - PARAM.input.mixing_tau = true; - XC_Functional::func_type = 3; - XC_Functional::ked_flag = true; + cfg.nspin = 1; + cfg.mixing_tau = true; + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(true); CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest.init_mixing(); - EXPECT_EQ(CMtest.tau_mdata.length, pw_basis.nrxx); + EXPECT_EQ(CMtest.get_tau_mdata().length, pw_basis.nrxx); - PARAM.input.nspin = 4; - PARAM.input.mixing_angle = 1.0; + cfg.nspin = 4; + cfg.mixing_angle = 1.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest.init_mixing(); - EXPECT_EQ(CMtest.rho_mdata.length, 2 * pw_basis.nrxx); + EXPECT_EQ(CMtest.get_rho_mdata().length, 2 * pw_basis.nrxx); } TEST_F(ChargeMixingTest, InnerDotRealTest) @@ -261,24 +300,24 @@ TEST_F(ChargeMixingTest, InnerDotRealTest) // non mixing angle case CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest.set_rhopw(&pw_basis, &pw_basis); - PARAM.input.nspin = 4; + cfg.nspin = 4; sync_cfg(CMtest); // a simple sum for inner product - std::vector drho1(pw_basis.nrxx * PARAM.input.nspin); - std::vector drho2(pw_basis.nrxx * PARAM.input.nspin); - for (int i = 0; i < pw_basis.nrxx * PARAM.input.nspin; ++i) + std::vector drho1(pw_basis.nrxx * cfg.nspin); + std::vector drho2(pw_basis.nrxx * cfg.nspin); + for (int i = 0; i < pw_basis.nrxx * cfg.nspin; ++i) { drho1[i] = 1.0; drho2[i] = double(i); } - double inner = module_charge::inner_product_real(drho1.data(), drho2.data(), pw_basis, CMtest.cfg_); - EXPECT_NEAR(inner, 0.5 * pw_basis.nrxx * PARAM.input.nspin * (pw_basis.nrxx * PARAM.input.nspin - 1), 1e-8); + double inner = module_charge::inner_product_real(drho1.data(), drho2.data(), pw_basis, CMtest.get_mixing_config()); + EXPECT_NEAR(inner, 0.5 * pw_basis.nrxx * cfg.nspin * (pw_basis.nrxx * cfg.nspin - 1), 1e-8); // mixing angle case - PARAM.input.mixing_angle = 1.0; + cfg.mixing_angle = 1.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - PARAM.input.nspin = 4; + cfg.nspin = 4; // a simple sum for inner product drho1.resize(pw_basis.nrxx * 2); @@ -288,7 +327,7 @@ TEST_F(ChargeMixingTest, InnerDotRealTest) drho1[i] = 1.0; drho2[i] = double(i); } - inner = module_charge::inner_product_real(drho1.data(), drho2.data(), pw_basis, CMtest.cfg_); + inner = module_charge::inner_product_real(drho1.data(), drho2.data(), pw_basis, CMtest.get_mixing_config()); EXPECT_NEAR(inner, 0.5 * pw_basis.nrxx * 2 * (pw_basis.nrxx * 2 - 1), 1e-8); } @@ -299,7 +338,7 @@ TEST_F(ChargeMixingTest, InnerDotRecipHartreeTest) CMtest.set_rhopw(&pw_basis, &pw_basis); const int npw = pw_basis.npw; const int nrxx = pw_basis.nrxx; - PARAM.input.nspin = 1; + cfg.nspin = 1; std::vector drhor1(pw_basis.nrxx); std::vector drhor2(pw_basis.nrxx); for (int i = 0; i < pw_basis.nrxx; ++i) @@ -311,14 +350,14 @@ TEST_F(ChargeMixingTest, InnerDotRecipHartreeTest) // nspin from cfg_, which is default-constructed (and thus invalid) until // set_mixing runs. CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - double inner = module_charge::inner_product_real(drhor1.data(), drhor2.data(), pw_basis, CMtest.cfg_); + double inner = module_charge::inner_product_real(drhor1.data(), drhor2.data(), pw_basis, CMtest.get_mixing_config()); EXPECT_NEAR(inner, 0.5 * pw_basis.nrxx * (pw_basis.nrxx - 1), 1e-8); // RECIPROCAL NSPIN=1 ucell.tpiba2 = 1.0; ucell.omega = 2.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - PARAM.input.nspin = 1; + cfg.nspin = 1; sync_cfg(CMtest); std::vector> drhog1(pw_basis.npw); std::vector> drhog2(pw_basis.npw); @@ -330,17 +369,17 @@ TEST_F(ChargeMixingTest, InnerDotRecipHartreeTest) pw_basis.real2recip(drhor1.data(), drhog1.data()); pw_basis.real2recip(drhor2.data(), drhog2.data()); - inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, -0.3 * ModuleBase::e2 * ModuleBase::FOUR_PI, 1e-8); // RECIPROCAL NSPIN=2 - PARAM.input.nspin = 2; + cfg.nspin = 2; sync_cfg(CMtest); - drhog1.resize(pw_basis.npw * PARAM.input.nspin); - drhog2.resize(pw_basis.npw * PARAM.input.nspin); - std::vector> drhog1_mag(pw_basis.npw * PARAM.input.nspin); - std::vector> drhog2_mag(pw_basis.npw * PARAM.input.nspin); - for (int i = 0; i < pw_basis.npw * PARAM.input.nspin; ++i) + drhog1.resize(pw_basis.npw * cfg.nspin); + drhog2.resize(pw_basis.npw * cfg.nspin); + std::vector> drhog1_mag(pw_basis.npw * cfg.nspin); + std::vector> drhog2_mag(pw_basis.npw * cfg.nspin); + for (int i = 0; i < pw_basis.npw * cfg.nspin; ++i) { drhog1[i] = std::complex(1.0, double(i)); drhog2[i] = std::complex(1.0, 1.0); @@ -353,41 +392,41 @@ TEST_F(ChargeMixingTest, InnerDotRecipHartreeTest) drhog2_mag[i] = drhog2[i] + drhog2[i+pw_basis.npw]; drhog2_mag[i+pw_basis.npw] = drhog2[i] - drhog2[i+pw_basis.npw]; } - PARAM.sys.gamma_only_pw= false; + cfg.gamma_only_pw= false; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1_mag.data(), drhog2_mag.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1_mag.data(), drhog2_mag.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 236763.82650318215, 1e-8); - PARAM.sys.gamma_only_pw= true; + cfg.gamma_only_pw= true; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1_mag.data(), drhog2_mag.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1_mag.data(), drhog2_mag.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 236763.82650318215 * 2, 1e-8); // RECIPROCAL NSPIN=4 without mixing_angle - PARAM.input.nspin = 4; + cfg.nspin = 4; sync_cfg(CMtest); - drhog1.resize(pw_basis.npw * PARAM.input.nspin); - drhog2.resize(pw_basis.npw * PARAM.input.nspin); - for (int i = 0; i < pw_basis.npw * PARAM.input.nspin; ++i) + drhog1.resize(pw_basis.npw * cfg.nspin); + drhog2.resize(pw_basis.npw * cfg.nspin); + for (int i = 0; i < pw_basis.npw * cfg.nspin; ++i) { drhog1[i] = std::complex(1.0, double(i)); drhog2[i] = std::complex(1.0, 1.0); } - PARAM.sys.domag = false; - PARAM.sys.domag_z = false; + cfg.domag = false; + cfg.domag_z = false; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 28260.091995611871, 1e-8); - PARAM.sys.gamma_only_pw= true; - PARAM.sys.domag = true; - PARAM.sys.domag_z = true; + cfg.gamma_only_pw= true; + cfg.domag = true; + cfg.domag_z = true; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 110668.61166927818, 1e-8); // RECIPROCAL NSPIN=4 with mixing_angle - PARAM.input.nspin = 4; - PARAM.input.mixing_angle = 1.0; + cfg.nspin = 4; + cfg.mixing_angle = 1.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); drhog1.resize(pw_basis.npw * 2); drhog2.resize(pw_basis.npw * 2); @@ -396,13 +435,13 @@ TEST_F(ChargeMixingTest, InnerDotRecipHartreeTest) drhog1[i] = std::complex(1.0, double(i)); drhog2[i] = std::complex(1.0, 1.0); } - PARAM.sys.gamma_only_pw= false; + cfg.gamma_only_pw= false; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 36548.881431837777, 1e-8); - PARAM.sys.gamma_only_pw= true; + cfg.gamma_only_pw= true; sync_cfg(CMtest); - inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::inner_product_recip_hartree(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 44776.555369916401, 1e-8); } @@ -411,7 +450,7 @@ TEST_F(ChargeMixingTest, InnerDotRecipRhoTest) // REAL Charge_Mixing CMtest; CMtest.set_rhopw(&pw_basis, &pw_basis); - PARAM.input.nspin = 1; + cfg.nspin = 1; std::vector drhor1(pw_basis.nrxx); std::vector drhor2(pw_basis.nrxx); for (int i = 0; i < pw_basis.nrxx; ++i) @@ -421,14 +460,14 @@ TEST_F(ChargeMixingTest, InnerDotRecipRhoTest) } // Populate cfg_ before the first inner_product call (see the hartree test). CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - double inner = module_charge::inner_product_real(drhor1.data(), drhor2.data(), pw_basis, CMtest.cfg_); + double inner = module_charge::inner_product_real(drhor1.data(), drhor2.data(), pw_basis, CMtest.get_mixing_config()); EXPECT_NEAR(inner, 0.5 * pw_basis.nrxx * (pw_basis.nrxx - 1), 1e-8); // RECIPROCAL ucell.tpiba2 = 1.0; ucell.omega = 2.0; CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); - PARAM.input.nspin = 1; + cfg.nspin = 1; sync_cfg(CMtest); std::vector> drhog1(pw_basis.npw); std::vector> drhog2(pw_basis.npw); @@ -440,47 +479,47 @@ TEST_F(ChargeMixingTest, InnerDotRecipRhoTest) pw_basis.real2recip(drhor1.data(), drhog1.data()); pw_basis.real2recip(drhor2.data(), drhog2.data()); - inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, -0.3 * ModuleBase::e2 * ModuleBase::FOUR_PI, 1e-8); - PARAM.input.nspin = 2; + cfg.nspin = 2; sync_cfg(CMtest); - drhog1.resize(pw_basis.npw * PARAM.input.nspin); - drhog2.resize(pw_basis.npw * PARAM.input.nspin); - for (int i = 0; i < pw_basis.npw * PARAM.input.nspin; ++i) + drhog1.resize(pw_basis.npw * cfg.nspin); + drhog2.resize(pw_basis.npw * cfg.nspin); + for (int i = 0; i < pw_basis.npw * cfg.nspin; ++i) { drhog1[i] = std::complex(1.0, double(i)); drhog2[i] = std::complex(1.0, 1.0); } - PARAM.sys.gamma_only_pw= false; + cfg.gamma_only_pw= false; sync_cfg(CMtest); - inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 236763.82650318215, 1e-8); - PARAM.sys.gamma_only_pw= true; + cfg.gamma_only_pw= true; sync_cfg(CMtest); - inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 236763.82650318215 * 2, 1e-8); - PARAM.input.nspin = 4; + cfg.nspin = 4; sync_cfg(CMtest); - drhog1.resize(pw_basis.npw * PARAM.input.nspin); - drhog2.resize(pw_basis.npw * PARAM.input.nspin); - for (int i = 0; i < pw_basis.npw * PARAM.input.nspin; ++i) + drhog1.resize(pw_basis.npw * cfg.nspin); + drhog2.resize(pw_basis.npw * cfg.nspin); + for (int i = 0; i < pw_basis.npw * cfg.nspin; ++i) { drhog1[i] = std::complex(1.0, double(i)); drhog2[i] = std::complex(1.0, 1.0); } - PARAM.sys.domag = false; - PARAM.sys.domag_z = false; + cfg.domag = false; + cfg.domag_z = false; sync_cfg(CMtest); - inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 28260.091995611871, 1e-8); - PARAM.sys.gamma_only_pw= true; - PARAM.sys.domag = true; - PARAM.sys.domag_z = true; + cfg.gamma_only_pw= true; + cfg.domag = true; + cfg.domag_z = true; sync_cfg(CMtest); - inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.cfg_, ucell.omega, ucell.tpiba); + inner = module_charge::detail::inner_product_recip_rho(drhog1.data(), drhog2.data(), pw_basis, CMtest.get_mixing_config(), ucell.omega, ucell.tpiba); EXPECT_NEAR(inner, 110668.61166927818, 1e-8); } @@ -488,29 +527,31 @@ TEST_F(ChargeMixingTest, KerkerScreenRecipTest) { ucell.tpiba = 1.0; // nspin = 1 - PARAM.input.nspin = 1; - MixingConfig cfg = make_cfg(); - std::complex* drhog = new std::complex[PARAM.input.nspin*pw_basis.npw]; - std::complex* drhog_old = new std::complex[PARAM.input.nspin*pw_basis.npw]; - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + cfg.nspin = 1; + // kcfg is the snapshot handed to the kernels; cfg (the fixture member) is + // the source make_cfg() reads, so nspin has to be set on cfg, not on kcfg. + MixingConfig kcfg = make_cfg(); + std::complex* drhog = new std::complex[cfg.nspin*pw_basis.npw]; + std::complex* drhog_old = new std::complex[cfg.nspin*pw_basis.npw]; + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { drhog_old[i] = drhog[i] = std::complex(1.0, 1.0); } // no kerker - cfg.mixing_gg0 = 0.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + kcfg.mixing_gg0 = 0.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { EXPECT_EQ(drhog[i], drhog_old[i]); } // kerker - cfg.mixing_gg0 = 1.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); + kcfg.mixing_gg0 = 1.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); double gg0 = std::pow(ModuleBase::BOHR_TO_A, 2); for (int i = 0; i < pw_basis.npw; ++i) { double gg = this->pw_basis.gg[i]; - double ref = std::max(gg / (gg + gg0), 0.1 / cfg.mixing_beta); + double ref = std::max(gg / (gg + gg0), 0.1 / kcfg.mixing_beta); EXPECT_NEAR(drhog[i].real(), ref, 1e-10); EXPECT_NEAR(drhog[i].imag(), ref, 1e-10); } @@ -518,31 +559,31 @@ TEST_F(ChargeMixingTest, KerkerScreenRecipTest) delete[] drhog_old; // nspin = 2 - PARAM.input.nspin = 2; - cfg = make_cfg(); - cfg.mixing_beta = 0.4; - cfg.mixing_beta_mag = 1.6; - drhog = new std::complex[PARAM.input.nspin*pw_basis.npw]; - drhog_old = new std::complex[PARAM.input.nspin*pw_basis.npw]; - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + cfg.nspin = 2; + kcfg = make_cfg(); + kcfg.mixing_beta = 0.4; + kcfg.mixing_beta_mag = 1.6; + drhog = new std::complex[cfg.nspin*pw_basis.npw]; + drhog_old = new std::complex[cfg.nspin*pw_basis.npw]; + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { drhog_old[i] = drhog[i] = std::complex(1.0, 1.0); } // mixing_gg0 = 0.0 - cfg.mixing_gg0 = 0.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + kcfg.mixing_gg0 = 0.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { EXPECT_EQ(drhog[i], drhog_old[i]); } // mixing_gg0 = 1.0, mixing_gg0_mag = 0.0 - cfg.mixing_gg0 = 1.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); + kcfg.mixing_gg0 = 1.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); gg0 = std::pow(ModuleBase::BOHR_TO_A, 2); for (int i = 0; i < pw_basis.npw; ++i) { double gg = this->pw_basis.gg[i]; - double ref = std::max(gg / (gg + gg0), 0.1 / cfg.mixing_beta); + double ref = std::max(gg / (gg + gg0), 0.1 / kcfg.mixing_beta); // rho EXPECT_NEAR(drhog[i].real(), ref, 1e-10); EXPECT_NEAR(drhog[i].imag(), ref, 1e-10); @@ -554,29 +595,29 @@ TEST_F(ChargeMixingTest, KerkerScreenRecipTest) delete[] drhog_old; // nspin = 4 - PARAM.input.nspin = 4; - cfg = make_cfg(); - drhog = new std::complex[PARAM.input.nspin*pw_basis.npw]; - drhog_old = new std::complex[PARAM.input.nspin*pw_basis.npw]; - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + cfg.nspin = 4; + kcfg = make_cfg(); + drhog = new std::complex[cfg.nspin*pw_basis.npw]; + drhog_old = new std::complex[cfg.nspin*pw_basis.npw]; + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { drhog_old[i] = drhog[i] = std::complex(1.0, 1.0); } // mixing_gg0 = 0.0 - cfg.mixing_gg0 = 0.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + kcfg.mixing_gg0 = 0.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { EXPECT_EQ(drhog[i], drhog_old[i]); } // mixing_gg0 = 1.0, mixing_gg0_mag = 0.0 - cfg.mixing_gg0 = 1.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); + kcfg.mixing_gg0 = 1.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); gg0 = std::pow(ModuleBase::BOHR_TO_A, 2); for (int i = 0; i < pw_basis.npw; ++i) { double gg = this->pw_basis.gg[i]; - double ref = std::max(gg / (gg + gg0), 0.1 / cfg.mixing_beta); + double ref = std::max(gg / (gg + gg0), 0.1 / kcfg.mixing_beta); // rho EXPECT_NEAR(drhog[i].real(), ref, 1e-10); EXPECT_NEAR(drhog[i].imag(), ref, 1e-10); @@ -587,15 +628,15 @@ TEST_F(ChargeMixingTest, KerkerScreenRecipTest) EXPECT_NEAR(drhog[i + pw_basis.npw].imag(), 1.0, 1e-10); } // mixing_gg0 = 1.0, mixing_gg0_mag = 2.0 - cfg.mixing_gg0 = 1.0; - cfg.mixing_gg0_mag = 2.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); + kcfg.mixing_gg0 = 1.0; + kcfg.mixing_gg0_mag = 2.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); double gg1 = std::pow(1.0 * ModuleBase::BOHR_TO_A, 2); double gg2 = std::pow(2.0 * ModuleBase::BOHR_TO_A, 2); for (int i = 0; i < pw_basis.npw; ++i) { double gg = this->pw_basis.gg[i]; - double ref = std::max(gg / (gg + gg1), 0.1 / cfg.mixing_beta); + double ref = std::max(gg / (gg + gg1), 0.1 / kcfg.mixing_beta); // rho EXPECT_NEAR(drhog[i].real(), ref * ref, 1e-10); EXPECT_NEAR(drhog[i].imag(), ref * ref, 1e-10); @@ -603,9 +644,9 @@ TEST_F(ChargeMixingTest, KerkerScreenRecipTest) for (int i = 0; i < pw_basis.npw; ++i) { double gg = this->pw_basis.gg[i]; - double ref = std::max(gg / (gg + gg2), 0.1 / cfg.mixing_beta_mag); + double ref = std::max(gg / (gg + gg2), 0.1 / kcfg.mixing_beta_mag); // rho - for (int j = 1; j < PARAM.input.nspin; ++j) + for (int j = 1; j < cfg.nspin; ++j) { EXPECT_NEAR(drhog[i + pw_basis.npw * j].real(), ref, 1e-10); EXPECT_NEAR(drhog[i + pw_basis.npw * j].imag(), ref, 1e-10); @@ -619,18 +660,20 @@ TEST_F(ChargeMixingTest, KerkerScreenRealTest) { ucell.tpiba = 1.0; // nspin = 1 - PARAM.input.nspin = 1; - MixingConfig cfg = make_cfg(); - double* drhor = new double[PARAM.input.nspin*pw_basis.nrxx]; - double* drhor_ref = new double[PARAM.input.nspin*pw_basis.nrxx]; - for (int i = 0; i < PARAM.input.nspin*pw_basis.nrxx; ++i) + cfg.nspin = 1; + // kcfg is the snapshot handed to the kernels; nspin is set on the fixture + // member cfg, which is what make_cfg() reads. + MixingConfig kcfg = make_cfg(); + double* drhor = new double[cfg.nspin*pw_basis.nrxx]; + double* drhor_ref = new double[cfg.nspin*pw_basis.nrxx]; + for (int i = 0; i < cfg.nspin*pw_basis.nrxx; ++i) { drhor_ref[i] = drhor[i] = 1.0; } // no kerker - cfg.mixing_gg0 = 0.0; - module_charge::kerker_screen_real(cfg, &pw_basis, ucell.tpiba, drhor); - for (int i = 0; i < PARAM.input.nspin*pw_basis.nrxx; ++i) + kcfg.mixing_gg0 = 0.0; + module_charge::kerker_screen_real(kcfg, &pw_basis, ucell.tpiba, drhor); + for (int i = 0; i < cfg.nspin*pw_basis.nrxx; ++i) { EXPECT_EQ(drhor[i], drhor_ref[i]); } @@ -638,33 +681,33 @@ TEST_F(ChargeMixingTest, KerkerScreenRealTest) delete[] drhor_ref; // nspin = 2 - PARAM.input.nspin = 2; - cfg = make_cfg(); - cfg.mixing_gg0 = 0.0; - std::complex* drhog = new std::complex[PARAM.input.nspin*pw_basis.npw]; - std::complex* drhog_old = new std::complex[PARAM.input.nspin*pw_basis.npw]; - drhor = new double[PARAM.input.nspin*pw_basis.nrxx]; - drhor_ref = new double[PARAM.input.nspin*pw_basis.nrxx]; - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + cfg.nspin = 2; + kcfg = make_cfg(); + kcfg.mixing_gg0 = 0.0; + std::complex* drhog = new std::complex[cfg.nspin*pw_basis.npw]; + std::complex* drhog_old = new std::complex[cfg.nspin*pw_basis.npw]; + drhor = new double[cfg.nspin*pw_basis.nrxx]; + drhor_ref = new double[cfg.nspin*pw_basis.nrxx]; + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { drhog_old[i] = drhog[i] = std::complex(1.0, 1.0); } - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); // no kerker - for (int i = 0; i < PARAM.input.nspin*pw_basis.npw; ++i) + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); // no kerker + for (int i = 0; i < cfg.nspin*pw_basis.npw; ++i) { EXPECT_EQ(drhog[i], drhog_old[i]); } // RECIPROCAL - cfg.mixing_gg0 = 1.0; - cfg.mixing_gg0_mag = 0.0; - module_charge::kerker_screen_recip(cfg, &pw_basis, ucell.tpiba, drhog); + kcfg.mixing_gg0 = 1.0; + kcfg.mixing_gg0_mag = 0.0; + module_charge::kerker_screen_recip(kcfg, &pw_basis, ucell.tpiba, drhog); const double gg0 = std::pow(ModuleBase::BOHR_TO_A, 2); for (int i = 0; i < pw_basis.npw; ++i) { std::complex ration = drhog[i] / drhog[i+pw_basis.npw]; double gg = this->pw_basis.gg[i]; - double ration_ref = std::max(gg / (gg + gg0), 0.1 / cfg.mixing_beta); + double ration_ref = std::max(gg / (gg + gg0), 0.1 / kcfg.mixing_beta); EXPECT_NEAR(ration.real(), ration_ref, 1e-10); EXPECT_NEAR(ration.imag(), 0, 1e-10); } @@ -673,13 +716,13 @@ TEST_F(ChargeMixingTest, KerkerScreenRealTest) pw_basis.recip2real(drhog, drhor_ref); pw_basis.recip2real(drhog_old, drhor); - cfg.mixing_gg0 = 0.0; - cfg.mixing_gg0_mag = 0.0; + kcfg.mixing_gg0 = 0.0; + kcfg.mixing_gg0_mag = 0.0; // nothing happens - module_charge::kerker_screen_real(cfg, &pw_basis, ucell.tpiba, drhor); + module_charge::kerker_screen_real(kcfg, &pw_basis, ucell.tpiba, drhor); - cfg.mixing_gg0 = 1.0; - module_charge::kerker_screen_real(cfg, &pw_basis, ucell.tpiba, drhor); + kcfg.mixing_gg0 = 1.0; + module_charge::kerker_screen_real(kcfg, &pw_basis, ucell.tpiba, drhor); for (int i = 0; i < pw_basis.nrxx; ++i) { EXPECT_NEAR(drhor[i], drhor_ref[i], 1e-8); @@ -694,40 +737,20 @@ TEST_F(ChargeMixingTest, KerkerScreenRealTest) TEST_F(ChargeMixingTest, MixRhoTest) { - PARAM.sys.double_grid = false; + cfg.double_grid = false; charge.set_rhopw(&pw_basis); - const int nspin = PARAM.input.nspin = 1; - PARAM.sys.domag_z = false; - XC_Functional::func_type = 3; - XC_Functional::ked_flag = true; - PARAM.input.mixing_beta = 0.7; - PARAM.input.mixing_ndim = 1; - PARAM.input.mixing_gg0 = 0.0; - PARAM.input.mixing_tau = true; - PARAM.input.mixing_mode = "plain"; + const int nspin = cfg.nspin = 1; + cfg.domag_z = false; + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(true); + cfg.mixing_beta = 0.7; + cfg.mixing_ndim = 1; + cfg.mixing_gg0 = 0.0; + cfg.mixing_tau = true; + cfg.mixing_mode = "plain"; const int nrxx = pw_basis.nrxx; const int npw = pw_basis.npw; - charge._space_rho.resize(nspin * nrxx); - charge._space_rho_save.resize(nspin * nrxx); - charge._space_rhog.resize(nspin * npw); - charge._space_rhog_save.resize(nspin * npw); - charge._space_kin_r.resize(nspin * nrxx); - charge._space_kin_r_save.resize(nspin * nrxx); - charge.rho = new double*[nspin]; - charge.rhog = new std::complex*[nspin]; - charge.rho_save = new double*[nspin]; - charge.rhog_save = new std::complex*[nspin]; - charge.kin_r = new double*[nspin]; - charge.kin_r_save = new double*[nspin]; - for (int is = 0; is < nspin; is++) - { - charge.rho[is] = charge._space_rho.data() + is * nrxx; - charge.rhog[is] = charge._space_rhog.data() + is * npw; - charge.rho_save[is] = charge._space_rho_save.data() + is * nrxx; - charge.rhog_save[is] = charge._space_rhog_save.data() + is * npw; - charge.kin_r[is] = charge._space_kin_r.data() + is * nrxx; - charge.kin_r_save[is] = charge._space_kin_r_save.data() + is * nrxx; - } + wire_charge(nspin, nrxx, npw, XC_Functional::get_ked_flag()); std::vector real_ref(nspin * nrxx); std::vector real_save_ref(nspin * nrxx); std::vector> recip_ref(nspin * npw); @@ -746,18 +769,18 @@ TEST_F(ChargeMixingTest, MixRhoTest) // RECIPROCAL Charge_Mixing CMtest_recip; CMtest_recip.set_rhopw(&pw_basis, &pw_basis); - PARAM.input.scf_thr_type= 1; + cfg.scf_thr_type= 1; CMtest_recip.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest_recip.init_mixing(); for(int i = 0 ; i < nspin * npw; ++i) { - charge._space_rhog[i] = recip_ref[i]; - charge._space_rhog_save[i] = recip_save_ref[i]; + charge.rhog[i / npw][i % npw] = recip_ref[i]; + charge.rhog_save[i / npw][i % npw] = recip_save_ref[i]; } for(int i = 0 ; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CMtest_recip.mix_rho(&charge); for(int is = 0 ; is < nspin; ++is) @@ -775,14 +798,14 @@ TEST_F(ChargeMixingTest, MixRhoTest) // REAL Charge_Mixing CMtest_real; - PARAM.input.scf_thr_type= 2; + cfg.scf_thr_type= 2; CMtest_real.set_rhopw(&pw_basis, &pw_basis); CMtest_real.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest_real.init_mixing(); for(int i = 0 ; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CMtest_recip.mix_rho(&charge); for(int is = 0 ; is < nspin; ++is) @@ -795,12 +818,8 @@ TEST_F(ChargeMixingTest, MixRhoTest) } //------------------------------------------------------------------------- - delete[] charge.rho; - delete[] charge.rhog; - delete[] charge.rho_save; - delete[] charge.rhog_save; - delete[] charge.kin_r; - delete[] charge.kin_r_save; + // the fixture owns the buffers behind charge.rho/rhog/kin_r, so there is + // nothing to delete here } // Regression test: close_kerker_gg0() must short-circuit the Kerker screening @@ -812,29 +831,22 @@ TEST_F(ChargeMixingTest, MixRhoTest) // = 0 baseline. TEST_F(ChargeMixingTest, CloseKerkerGg0DisablesScreenReal) { - PARAM.sys.double_grid = false; + cfg.double_grid = false; charge.set_rhopw(&pw_basis); - const int nspin = PARAM.input.nspin = 1; - PARAM.sys.domag_z = false; - XC_Functional::func_type = 3; - XC_Functional::ked_flag = false; - PARAM.input.mixing_beta = 0.7; - PARAM.input.mixing_ndim = 1; - PARAM.input.mixing_gg0 = 1.0; // Kerker active by default - PARAM.input.mixing_tau = false; - PARAM.input.mixing_mode = "plain"; - PARAM.input.scf_thr_type = 2; // real-space path + const int nspin = cfg.nspin = 1; + cfg.domag_z = false; + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(false); + cfg.mixing_beta = 0.7; + cfg.mixing_ndim = 1; + cfg.mixing_gg0 = 1.0; // Kerker active by default + cfg.mixing_tau = false; + cfg.mixing_mode = "plain"; + cfg.scf_thr_type = 2; // real-space path const int nrxx = pw_basis.nrxx; - charge._space_rho.resize(nspin * nrxx); - charge._space_rho_save.resize(nspin * nrxx); - charge.rho = new double*[nspin]; - charge.rho_save = new double*[nspin]; - for (int is = 0; is < nspin; is++) - { - charge.rho[is] = charge._space_rho.data() + is * nrxx; - charge.rho_save[is] = charge._space_rho_save.data() + is * nrxx; - } + // Only rho/rho_save are exercised on this real-space path. + wire_charge(nspin, nrxx, pw_basis.npw, XC_Functional::get_ked_flag()); // Non-trivial real-space residual: linear ramp so Kerker (which damps // long wavelengths) actually changes the output vs the no-Kerker path. std::vector real_ref(nspin * nrxx); @@ -853,11 +865,11 @@ TEST_F(ChargeMixingTest, CloseKerkerGg0DisablesScreenReal) CM_disabled.close_kerker_gg0(); for (int i = 0; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CM_disabled.mix_rho(&charge); - std::vector rho_A(charge._space_rho); + std::vector rho_A(charge.rho[0], charge.rho[0] + nspin * nrxx); // --- Run B: cfg.mixing_gg0 = 0 baseline, no close_kerker_gg0 --- Charge_Mixing CM_baseline; @@ -868,11 +880,11 @@ TEST_F(ChargeMixingTest, CloseKerkerGg0DisablesScreenReal) CM_baseline.init_mixing(); for (int i = 0; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CM_baseline.mix_rho(&charge); - std::vector rho_B(charge._space_rho); + std::vector rho_B(charge.rho[0], charge.rho[0] + nspin * nrxx); // close_kerker_gg0 path must match the Kerker-off baseline. for (int i = 0; i < nspin * nrxx; ++i) @@ -890,11 +902,11 @@ TEST_F(ChargeMixingTest, CloseKerkerGg0DisablesScreenReal) CM_active.init_mixing(); for (int i = 0; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CM_active.mix_rho(&charge); - std::vector rho_C(charge._space_rho); + std::vector rho_C(charge.rho[0], charge.rho[0] + nspin * nrxx); bool any_diff = false; for (int i = 0; i < nspin * nrxx; ++i) @@ -909,46 +921,26 @@ TEST_F(ChargeMixingTest, CloseKerkerGg0DisablesScreenReal) << "Kerker-active output equals Kerker-disabled output, so the " "close_kerker_gg0 test cannot prove the flag does anything"; - delete[] charge.rho; - delete[] charge.rho_save; + // the fixture owns the buffers behind charge.rho/rho_save } TEST_F(ChargeMixingTest, MixDoubleGridRhoTest) { - PARAM.sys.double_grid = true; + cfg.double_grid = true; charge.set_rhopw(&pw_dbasis); - const int nspin = PARAM.input.nspin = 1; - PARAM.sys.domag_z = false; - XC_Functional::func_type = 3; - XC_Functional::ked_flag = true; - PARAM.input.mixing_beta = 0.7; - PARAM.input.mixing_ndim = 1; - PARAM.input.mixing_gg0 = 0.0; - PARAM.input.mixing_tau = true; - PARAM.input.mixing_mode = "plain"; + const int nspin = cfg.nspin = 1; + cfg.domag_z = false; + XC_Functional::set_func_type(3); + XC_Functional::set_ked_flag(true); + cfg.mixing_beta = 0.7; + cfg.mixing_ndim = 1; + cfg.mixing_gg0 = 0.0; + cfg.mixing_tau = true; + cfg.mixing_mode = "plain"; const int nrxx = pw_dbasis.nrxx; const int npw = pw_dbasis.npw; - charge._space_rho.resize(nspin * nrxx); - charge._space_rho_save.resize(nspin * nrxx); - charge._space_rhog.resize(nspin * npw); - charge._space_rhog_save.resize(nspin * npw); - charge._space_kin_r.resize(nspin * nrxx); - charge._space_kin_r_save.resize(nspin * nrxx); - charge.rho = new double*[nspin]; - charge.rhog = new std::complex*[nspin]; - charge.rho_save = new double*[nspin]; - charge.rhog_save = new std::complex*[nspin]; - charge.kin_r = new double*[nspin]; - charge.kin_r_save = new double*[nspin]; - for (int is = 0; is < nspin; is++) - { - charge.rho[is] = charge._space_rho.data() + is * nrxx; - charge.rhog[is] = charge._space_rhog.data() + is * npw; - charge.rho_save[is] = charge._space_rho_save.data() + is * nrxx; - charge.rhog_save[is] = charge._space_rhog_save.data() + is * npw; - charge.kin_r[is] = charge._space_kin_r.data() + is * nrxx; - charge.kin_r_save[is] = charge._space_kin_r_save.data() + is * nrxx; - } + // charge is pointed at pw_dbasis here, so size the buffers from the dense grid. + wire_charge(nspin, nrxx, npw, XC_Functional::get_ked_flag()); std::vector real_ref(nspin * nrxx); std::vector real_save_ref(nspin * nrxx); std::vector> recip_ref(nspin * npw); @@ -968,19 +960,19 @@ TEST_F(ChargeMixingTest, MixDoubleGridRhoTest) Charge_Mixing CMtest_recip; CMtest_recip.set_rhopw(&pw_basis, &pw_dbasis); - PARAM.input.scf_thr_type= 1; + cfg.scf_thr_type= 1; CMtest_recip.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); CMtest_recip.init_mixing(); for (int i = 0; i < nspin * npw; ++i) { - charge._space_rhog[i] = recip_ref[i]; - charge._space_rhog_save[i] = recip_save_ref[i]; + charge.rhog[i / npw][i % npw] = recip_ref[i]; + charge.rhog_save[i / npw][i % npw] = recip_save_ref[i]; } for (int i = 0; i < nspin * nrxx; ++i) { - charge._space_rho[i] = real_ref[i]; - charge._space_rho_save[i] = real_save_ref[i]; + charge.rho[i / nrxx][i % nrxx] = real_ref[i]; + charge.rho_save[i / nrxx][i % nrxx] = real_save_ref[i]; } CMtest_recip.mix_rho(&charge); for (int is = 0; is < nspin; ++is) @@ -997,18 +989,14 @@ TEST_F(ChargeMixingTest, MixDoubleGridRhoTest) } //------------------------------------------------------------------------- - delete[] charge.rho; - delete[] charge.rhog; - delete[] charge.rho_save; - delete[] charge.rhog_save; - delete[] charge.kin_r; - delete[] charge.kin_r_save; + // the fixture owns the buffers behind charge.rho/rhog/kin_r, so there is + // nothing to delete here } TEST_F(ChargeMixingTest, MixDivCombTest) { // NSPIN = 1 - PARAM.input.nspin = 1; + cfg.nspin = 1; Charge_Mixing CMtest; CMtest.set_rhopw(&pw_basis, &pw_dbasis); std::vector> data(pw_dbasis.npw, 1.0); @@ -1042,7 +1030,7 @@ TEST_F(ChargeMixingTest, MixDivCombTest) // No explicit cleanup call needed: vectors manage their own storage. // NSPIN = 2 - PARAM.input.nspin = 2; + cfg.nspin = 2; data.resize(npw_dense * 2, 1.0); dataout.assign(npw_dense * 2, std::complex(0, 0)); std::vector> datas2(npw_smooth * 2); @@ -1063,7 +1051,7 @@ TEST_F(ChargeMixingTest, SCFOscillationTest) int scf_nmax = 20; // if_scf_oscillate sizes _drho_history from cfg_.scf_nmax, so cfg_ must // be populated before the loop; a default-constructed cfg_ leaves it 0. - PARAM.input.scf_nmax = scf_nmax; + cfg.scf_nmax = scf_nmax; CMtest.set_rhopw(&pw_basis, &pw_basis); CMtest.set_mixing(make_cfg(), ucell.omega, ucell.tpiba); int scf_os_ndim = 3; diff --git a/source/source_estate/module_dm/test/test_dm_r_init.cpp b/source/source_estate/module_dm/test/test_dm_r_init.cpp index f1768ff807a..d4c982e0664 100644 --- a/source/source_estate/module_dm/test/test_dm_r_init.cpp +++ b/source/source_estate/module_dm/test/test_dm_r_init.cpp @@ -3,11 +3,9 @@ #include #include "gmock/gmock.h" #include "gtest/gtest.h" -#define private public #include "source_estate/module_dm/density_matrix.h" #include "source_hamilt/module_hcontainer/hcontainer.h" #include "source_cell/klist.h" -#undef private /************************************************ * unit test of DensityMatrix constructor ***********************************************/ @@ -285,14 +283,14 @@ TEST_F(DMTest, saveDMR) DM_test.init_DMR(*DM.get_DMR_pointer(1)); DM_test.save_DMR(); EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM.get_DMR_pointer(1)->get_nnr()); - EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM_test._DMR_save[0].size()); + EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM_test.get_DMR_save()[0].size()); // add a new AtomPair, act as a relaxation hamilt::AtomPair tmp_ap(9, 9, 1, 0, 0, paraV); DM_test.get_DMR_pointer(1)->insert_pair(tmp_ap); DM_test.get_DMR_pointer(1)->allocate(); // update DMR_save DM_test.save_DMR(); - EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM_test._DMR_save[0].size()); + EXPECT_EQ(DM_test.get_DMR_pointer(1)->get_nnr(), DM_test.get_DMR_save()[0].size()); // delete delete kv; } diff --git a/source/source_hamilt/module_xc/xc_functional.h b/source/source_hamilt/module_xc/xc_functional.h index 4dce5e3e99f..8d6dcf5dbb8 100644 --- a/source/source_hamilt/module_xc/xc_functional.h +++ b/source/source_hamilt/module_xc/xc_functional.h @@ -93,6 +93,14 @@ class XC_Functional return func_type; }; + /// @brief Set the functional class directly. set_xc_type() derives this from + /// a functional name and is what production code uses; this is for + /// callers that need to select a branch without configuring libxc. + static void set_func_type(const int func_type_in) + { + func_type = func_type_in; + }; + static void set_xc_type(const std::string xc_func_in); // For hybrid functional @@ -122,6 +130,12 @@ class XC_Functional return ked_flag; }; + /// @brief Set whether the functional needs the kinetic energy density. + static void set_ked_flag(const bool ked_flag_in) + { + ked_flag = ked_flag_in; + }; + static bool get_need_laplacian() { return need_laplacian;