From b379cc5199ad096e83c2c6e498cf6242574d068e Mon Sep 17 00:00:00 2001 From: Jiacheng Xu <13862180016@163.com> Date: Tue, 20 Oct 2026 17:34:41 +0800 Subject: [PATCH] fix(input): reject mem_saver resets in SCF and relaxation --- .../module_parameter/read_inp_sys.cpp | 30 +++++--- .../test_serial/read_input_item_test.cpp | 74 +++++++++++++++++-- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index b2b725ac66..04c4741837 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -776,18 +776,30 @@ For `basis_type=lcao_in_pw`, `init_wfc` is automatically set to `nao`. item.type = "Integer"; item.description = R"(Save memory when performing nscf calculations. * 0: no memory saving techniques are used. -* 1: a memory saving technique will be used for many k point calculations.)"; +* 1: a memory saving technique will be used for many k point calculations. + +Legal values are 0 and 1. For calculation=scf or relax, mem_saver must be 0; setting it to 1 is an input error rather than being reset to 0.)"; item.default_value = "0"; item.set_availability("calculation==nscf and basis_type==pw"); read_sync_int(input.mem_saver); - item.reset_value = [](const Input_Item& item, Parameter& para) { - if (para.input.mem_saver == 1) - { - if (para.input.calculation == "scf" || para.input.calculation == "relax") - { - para.input.mem_saver = 0; - ModuleBase::GlobalFunc::AUTO_SET("mem_saver", "0"); - } + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.mem_saver != 0 && para.input.mem_saver != 1) + { + const std::string message + = "Invalid INPUT mem_saver=" + longstring(item.str_values) + + ". Legal values are 0 or 1.\n" + "See https://abacus.deepmodeling.com/en/latest/advanced/input_files/input-main.html#mem-saver"; + ModuleBase::WARNING_QUIT("ReadInput", message); + } + if (para.input.mem_saver == 1 + && (para.input.calculation == "scf" || para.input.calculation == "relax")) + { + const std::string message + = "Invalid INPUT mem_saver=" + longstring(item.str_values) + + " with calculation=" + para.input.calculation + + ". Use mem_saver=0 for this calculation; memory saving with mem_saver=1 is intended for nscf.\n" + "See https://abacus.deepmodeling.com/en/latest/advanced/input_files/input-main.html#mem-saver"; + ModuleBase::WARNING_QUIT("ReadInput", message); } }; this->add_item(item); diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 096b5c4515..4487cdeb10 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -134,6 +134,71 @@ TEST_F(InputTest, PccSelectionAndUnsupportedCombinations) EXPECT_EXIT(it->second.check_value(it->second, param), testing::ExitedWithCode(1), ""); } +TEST_F(InputTest, RejectInvalidMemSaver) +{ + const std::string filename = testing::TempDir() + "abacus_invalid_mem_saver_INPUT"; + for (const std::string calculation : {"scf", "relax", "nscf"}) + { + for (const int value : {-1, 1, 2}) + { + if (calculation == "nscf" && value == 1) + { + continue; + } + SCOPED_TRACE(calculation); + SCOPED_TRACE(value); + { + std::ofstream input(filename.c_str()); + input << "INPUT_PARAMETERS\ncalculation " << calculation << "\nmem_saver " << value << "\n"; + } + ModuleIO::ReadInput reader(0); + reader.check_ntype_flag = false; + Parameter param; + testing::internal::CaptureStdout(); + EXPECT_EXIT(reader.read_parameters(param, filename), testing::ExitedWithCode(1), ""); + const std::string diagnostic = testing::internal::GetCapturedStdout(); + const std::string invalid_value = "Invalid INPUT mem_saver=" + std::to_string(value); + EXPECT_THAT(diagnostic, testing::HasSubstr(invalid_value)); + EXPECT_THAT(diagnostic, testing::HasSubstr("input-main.html#mem-saver")); + if (value == 1) + { + const std::string invalid_mode = "calculation=" + calculation; + EXPECT_THAT(diagnostic, testing::HasSubstr(invalid_mode)); + EXPECT_THAT(diagnostic, testing::HasSubstr("mem_saver=0")); + } + else + { + EXPECT_THAT(diagnostic, testing::HasSubstr("0 or 1")); + } + EXPECT_EQ(std::remove(filename.c_str()), 0); + } + } +} + +TEST_F(InputTest, AcceptSupportedMemSaverInputs) +{ + const std::string filename = testing::TempDir() + "abacus_valid_mem_saver_INPUT"; + for (const std::string parameters : {"", + "mem_saver 0\n", + "calculation relax\nmem_saver 0\n", + "calculation nscf\nmem_saver 1\n", + "basis_type lcao\ncalculation nscf\nmem_saver 1\n"}) + { + SCOPED_TRACE(parameters); + { + std::ofstream input(filename.c_str()); + input << "INPUT_PARAMETERS\n" << parameters; + } + ModuleIO::ReadInput reader(0); + reader.check_ntype_flag = false; + Parameter param; + reader.read_parameters(param, filename); + const int expected_value = param.inp.calculation == "nscf" ? 1 : 0; + EXPECT_EQ(param.inp.mem_saver, expected_value); + EXPECT_EQ(std::remove(filename.c_str()), 0); + } +} + TEST_F(InputTest, Item_test) { ModuleIO::ReadInput readinput(0); @@ -322,14 +387,13 @@ TEST_F(InputTest, Item_test) { // mem_saver auto it = find_label("mem_saver", readinput.input_lists); TestParameters::input(param).mem_saver = 1; + it->second.str_values = {"1"}; TestParameters::input(param).calculation = "scf"; - it->second.reset_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).mem_saver, 0); + EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); - TestParameters::input(param).mem_saver = 1; TestParameters::input(param).calculation = "relax"; - it->second.reset_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).mem_saver, 0); + EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); + EXPECT_EQ(TestParameters::input(param).mem_saver, 1); } { // gint_precision auto it = find_label("gint_precision", readinput.input_lists);