diff --git a/docs/advanced/opt.md b/docs/advanced/opt.md index eddd1a0d181..72d4f8fb204 100644 --- a/docs/advanced/opt.md +++ b/docs/advanced/opt.md @@ -4,11 +4,11 @@ By setting `calculation` to be `relax` or `cell-relax`, ABACUS supports structur ABACUS provides two CG implementations for variable-cell relaxation, selected by the [relax_method](./input_files/input-main.md#relax_method) parameter: -- **CG variant 2** (`relax_method = cg 2` or `relax_method = cg`, default since v3.8): Uses simultaneous conjugate gradient (CG) optimization for both ionic positions and cell parameters. Both degrees of freedom are optimized together in each step. +- **Simultaneous CG** (`relax_method = cg`, default since v3.8): Uses simultaneous conjugate gradient (CG) optimization for both ionic positions and cell parameters. Both degrees of freedom are optimized together in each step. -- **CG variant 1** (`relax_method = cg 1`): Follows a nested procedure where fixed-cell structural relaxation is performed first, followed by an update of the cell parameters, and the process is repeated until convergence is achieved. +- **Nested CG** (`relax_method = cg_trad`): Follows a nested procedure where fixed-cell structural relaxation is performed first, followed by an update of the cell parameters, and the process is repeated until convergence is achieved. -An example of the variable cell relaxation can be found in our [repository](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/17_relax/01_pw_cell_relax_BFGS_Al), which is provided with the reference output file log.ref. When using CG variant 1, each ionic step is labelled in the following manner: +An example of the variable cell relaxation can be found in our [repository](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/17_relax/01_pw_cell_relax_BFGS_Al), which is provided with the reference output file log.ref. When using Nested CG, each ionic step is labelled in the following manner: ``` ------------------------------------------- RELAX CELL : 3 @@ -21,11 +21,11 @@ indicating that this is the first ionic step of the 3rd cell configuration, and ## Optimization Algorithms -ABACUS offers multiple optimization algorithms for structural relaxation, which can be selected using the [relax_method](./input_files/input-main.md#relax_method) keyword. The optional second value selects an implementation variant for CG or BFGS. For both methods, variant 1 is the traditional implementation and variant 2 is the recommended default. +ABACUS offers multiple optimization algorithms for structural relaxation, which can be selected using the [relax_method](./input_files/input-main.md#relax_method) keyword. Specify one scalar value. ### Available Algorithms -- **CG (Conjugate Gradient)**: Variant 1 optimizes ionic positions and cell parameters in separate stages; variant 2 optimizes them simultaneously with line search. +- **CG (Conjugate Gradient)**: `cg_trad` optimizes ionic positions and cell parameters in separate stages; `cg` optimizes them simultaneously with line search. - **BFGS**: Quasi-Newton method for ionic relaxation. - **LBFGS**: Limited-memory BFGS for ionic relaxation. - **SD (Steepest Descent)**: Simple gradient descent for ionic relaxation. @@ -37,11 +37,11 @@ We also provide a [list of keywords](./input_files/input-main.md#geometry-relaxa The [BFGS method](https://en.wikipedia.org/wiki/Broyden%E2%80%93Fletcher%E2%80%93Goldfarb%E2%80%93Shanno_algorithm) is a quasi-Newton method for solving nonlinear optimization problems. It belongs to the class of quasi-Newton methods where the Hessian matrix is approximated during the optimization process. If the initial point is not far from the extrema, BFGS tends to work better than gradient-based methods. -ABACUS provides two BFGS implementations, controlled by the second element of [relax_method](./input_files/input-main.md#relax_method): +ABACUS provides two BFGS implementations, selected by [relax_method](./input_files/input-main.md#relax_method): -- **Default BFGS** (`relax_method = bfgs 2` or `relax_method = bfgs`): Updates the inverse of the approximate Hessian matrix B directly. This is the recommended implementation. +- **Default BFGS** (`relax_method = bfgs`): Updates the inverse of the approximate Hessian matrix B directly. This is the recommended implementation. -- **Traditional BFGS** (`relax_method = bfgs 1`): Updates the approximate Hessian matrix B itself, then obtains the inverse by solving matrix eigenvalues and taking their reciprocals. Both methods are mathematically equivalent, but in some cases the traditional variant may perform better. +- **Traditional BFGS** (`relax_method = bfgs_trad`): Updates the approximate Hessian matrix B itself, then obtains the inverse by solving matrix eigenvalues and taking their reciprocals. Both methods are mathematically equivalent, but in some cases the traditional variant may perform better. ### LBFGS method @@ -61,11 +61,9 @@ The [CG (conjugate gradient) method](https://en.wikipedia.org/wiki/Conjugate_gra ABACUS provides two implementations of the CG method: -- **CG variant 2** (`relax_method = cg 2` or `relax_method = cg`, default): Performs simultaneous optimization of both ionic positions and cell parameters using a line search algorithm. This implementation is more efficient for `cell-relax` calculations as it optimizes all degrees of freedom together. The step size can be controlled by [relax_scale_force](./input_files/input-main.md#relax_scale_force). +- **Simultaneous CG** (`relax_method = cg`, default): Performs simultaneous optimization of both ionic positions and cell parameters using a line search algorithm. This implementation is more efficient for `cell-relax` calculations as it optimizes all degrees of freedom together. The step size can be controlled by [relax_scale_force](./input_files/input-main.md#relax_scale_force). -- **CG variant 1** (`relax_method = cg 1`): Uses a nested procedure where ionic positions are optimized first using CG, followed by cell parameter optimization (also using CG) in `cell-relax` calculations. This is the traditional approach where the two optimization steps are separated. - -The former `relax_new` parameter has been removed. Replace `relax_new = True` with `relax_method = cg 2`, and replace `relax_new = False` with `relax_method = cg 1` when using CG. The `bfgs`, `lbfgs`, `sd`, and `cg_bfgs` methods do not require a separate switch. +- **Nested CG** (`relax_method = cg_trad`): Uses a nested procedure where ionic positions are optimized first using CG, followed by cell parameter optimization (also using CG) in `cell-relax` calculations. This is the traditional approach where the two optimization steps are separated. ## Constrained Optimization @@ -105,13 +103,13 @@ Sometimes we want to do variable-cell relaxation with some of the cell degrees o **Available constraints by implementation:** -- **CG variant 2** (`relax_method = cg 2` or `relax_method = cg`): +- **Simultaneous CG** (`relax_method = cg`): - `fixed_axes = "shape"`: Only allows volume changes (hydrostatic pressure), cell shape is fixed - `fixed_axes = "volume"`: Allows shape changes but keeps volume constant - `fixed_axes = "a"`, `"b"`, `"c"`, `"ab"`, `"ac"`, `"bc"`, or `"abc"`: Fix specific lattice vectors or combinations - `fixed_ibrav = True`: Maintain the Bravais lattice type during relaxation -- **`relax_method = cg 1`, `bfgs`, `lbfgs`, `sd`, or `cg_bfgs`**: +- **`relax_method = cg_trad`, `bfgs`, `bfgs_trad`, `lbfgs`, `sd`, or `cg_bfgs`**: - `fixed_axes = "a"`, `"b"`, `"c"`, `"ab"`, `"ac"`, `"bc"`, or `"abc"`: Fix specific lattice vectors or combinations - `fixed_axes = "shape"`, `"volume"` and `fixed_ibrav = True` are not available diff --git a/docs/developers_guide/input_availability.md b/docs/developers_guide/input_availability.md index ee80bf534dd..40a97e45d43 100644 --- a/docs/developers_guide/input_availability.md +++ b/docs/developers_guide/input_availability.md @@ -57,7 +57,7 @@ so forms such as `basis_type == pw` and `bare-value` is a non-empty value containing no whitespace or any of `()[],=<>!`. A value containing at least one of those characters must use the non-empty double-quoted form, and a value that does not require quotes must not -use them. Thus `basis_type==pw` and `relax_method=="cg 2"` are canonical, while +use them. Thus `basis_type==pw` and `relax_method==cg` are canonical, while `basis_type=="pw"` is not. `==` compares one complete value. Two or more alternatives use `in [...]`, while `parameter contains value` tests whether a vector contains one element, such as `td_ttype contains 0`. `/` is an ordinary diff --git a/examples/17_relax/03_relax_with_output_pw/INPUT b/examples/17_relax/03_relax_with_output_pw/INPUT index 305dea867fd..0eb0bf31c0e 100644 --- a/examples/17_relax/03_relax_with_output_pw/INPUT +++ b/examples/17_relax/03_relax_with_output_pw/INPUT @@ -19,7 +19,7 @@ ks_solver cg mixing_type broyden mixing_beta 0.7 -relax_method cg 1 +relax_method cg_trad pseudo_dir ../../../tests/PP_ORB orbital_dir ../../../tests/PP_ORB diff --git a/examples/17_relax/04_relax_with_output_lcao/INPUT b/examples/17_relax/04_relax_with_output_lcao/INPUT index 05125b6fa1e..f58cf4201de 100644 --- a/examples/17_relax/04_relax_with_output_lcao/INPUT +++ b/examples/17_relax/04_relax_with_output_lcao/INPUT @@ -19,7 +19,7 @@ ks_solver scalapack_gvx mixing_type broyden mixing_beta 0.7 -relax_method cg 1 +relax_method cg_trad pseudo_dir ../../../tests/PP_ORB orbital_dir ../../../tests/PP_ORB diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index d86993b63d9..df182ea3e58 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -161,11 +161,11 @@ struct Input_para // int bessel_nao_lmax; ///< lmax used in descriptor // ============== #Parameters (4.Relaxation) =========================== - std::vector relax_method = {"cg", "2"}; ///< relaxation algorithm and optional variant + std::string relax_method = "cg"; ///< geometry optimization method bool uses_simultaneous_relaxation() const { - return relax_method.size() == 2 && relax_method[0] == "cg" && relax_method[1] == "2"; + return relax_method == "cg"; } bool relax = false; ///< allow relaxation along the specific direction double relax_scale_force = 0.5; diff --git a/source/source_io/module_parameter/read_inp_relax.cpp b/source/source_io/module_parameter/read_inp_relax.cpp index d3946a2ca4b..0d1d22d50c8 100644 --- a/source/source_io/module_parameter/read_inp_relax.cpp +++ b/source/source_io/module_parameter/read_inp_relax.cpp @@ -6,42 +6,6 @@ namespace ModuleIO { -namespace -{ -std::vector parse_relax_method(const std::vector& values) -{ - if (values.empty() || values.size() > 2) - { - ModuleBase::WARNING_QUIT("ReadInput", "relax_method accepts one or two values"); - } - - const std::string& method = values[0]; - const std::vector valid_methods = {"cg", "sd", "cg_bfgs", "lbfgs", "bfgs"}; - if (std::find(valid_methods.begin(), valid_methods.end(), method) == valid_methods.end()) - { - ModuleBase::WARNING_QUIT("ReadInput", nofound_str(valid_methods, "relax_method")); - } - - if (method == "cg" || method == "bfgs") - { - const std::string variant = values.size() == 1 ? "2" : values[1]; - if (variant != "1" && variant != "2") - { - const std::string algorithm = method == "cg" ? "CG" : "BFGS"; - ModuleBase::WARNING_QUIT("ReadInput", "the " + algorithm + " variant must be 1 or 2"); - } - return {method, variant}; - } - - if (values.size() == 2) - { - ModuleBase::WARNING_QUIT("ReadInput", "relax_method " + method + " does not accept a second value"); - } - return {method, ""}; -} -} // namespace - - void ReadInput::item_relax() { // NOTE: The order of add_item() calls below determines the parameter order @@ -49,44 +13,43 @@ void ReadInput::item_relax() // Please preserve this ordering when adding new parameters. { Input_Item item("relax_method"); - item.annotation = "cg; bfgs; sd; cg_bfgs; lbfgs"; + item.annotation = "cg; cg_trad; bfgs; bfgs_trad; sd; cg_bfgs; lbfgs"; item.category = "Geometry relaxation"; - item.type = "Vector of string"; - item.description = R"(The method used for geometry optimization. + item.type = "String"; + item.description = R"(The method used for geometry optimization. Select exactly one option: -First element (algorithm selection): -* cg: Conjugate gradient (CG) algorithm. -* bfgs: Broyden–Fletcher–Goldfarb–Shanno (BFGS) quasi-Newton algorithm. +* cg: Simultaneously optimize ionic positions and cell parameters with conjugate gradient and line search (recommended default). +* cg_trad: First optimize ionic positions at fixed cell, then update the cell, and repeat. +* bfgs: Default BFGS that directly updates the inverse Hessian (recommended). +* bfgs_trad: Traditional BFGS that updates the Hessian matrix B and then inverts it. * lbfgs: Limited-memory BFGS algorithm, suitable for large systems. * cg_bfgs: Mixed method starting with CG and switching to BFGS when force convergence reaches relax_cg_thr. -* sd: Steepest descent algorithm. Not recommended for production use. - -Optional second element: -* cg 1: First optimize ionic positions at fixed cell, then update the cell, and repeat. -* cg 2 or omitted: Simultaneously optimize ionic positions and cell parameters with line search (recommended). -* bfgs 1: Traditional BFGS that updates the Hessian matrix B and then inverts it. -* bfgs 2 or omitted: Default BFGS that directly updates the inverse Hessian (recommended). - -The second element is not accepted by other methods. - -[NOTE] In the 3.10-LTS version, the type of this parameter is std::string. It can be set to "cg", "bfgs", "cg_bfgs", "bfgs_trad", "lbfgs", "sd", "fire".)"; - item.default_value = "cg 2"; +* sd: Steepest descent algorithm. Not recommended for production use.)"; + item.default_value = "cg"; item.unit = ""; item.read_value = [](const Input_Item& item, Parameter& para) { - para.input.relax_method = parse_relax_method(item.str_values); + const std::vector methods + = {"cg", "cg_trad", "bfgs", "bfgs_trad", "sd", "cg_bfgs", "lbfgs"}; + if (item.str_values.size() != 1 || std::find(methods.begin(), methods.end(), strvalue) == methods.end()) + { + const std::string message = "relax_method requires exactly one scalar option. " + + nofound_str(methods, "relax_method"); + ModuleBase::WARNING_QUIT("ReadInput", message); + } + para.input.relax_method = strvalue; }; - sync_stringvec(input.relax_method, para.input.relax_method.size(), ""); + sync_string(input.relax_method); this->add_item(item); } { Input_Item item("relax_scale_force"); - item.annotation = "controls the size of the first CG 2 step"; + item.annotation = "controls the size of the first simultaneous CG step"; item.category = "Geometry relaxation"; item.type = "Real"; item.description = "The paramether controls the size of the first conjugate gradient step. A smaller value means the first step along a new CG direction is smaller. This might be helpful for large systems, where it is safer to take a smaller initial step to prevent the collapse of the whole configuration."; item.default_value = "0.5"; item.unit = ""; - item.set_availability("relax_method==\"cg 2\""); + item.set_availability("relax_method==cg"); read_sync_double(input.relax_scale_force); this->add_item(item); } @@ -193,7 +156,7 @@ The second element is not accepted by other methods. item.description = "Controls the Wolfe condition for the Broyden–Fletcher–Goldfarb–Shanno (BFGS) algorithm used in geometry relaxation. This parameter sets the sufficient decrease condition (c1 in Wolfe conditions). For more information, see Phys. Chem. Chem. Phys., 2000, 2, 2177."; item.default_value = "0.01"; item.unit = ""; - item.set_availability("relax_method in [bfgs, cg_bfgs]"); + item.set_availability("relax_method in [bfgs, bfgs_trad, cg_bfgs]"); read_sync_double(input.relax_bfgs_w1); this->add_item(item); } @@ -205,7 +168,7 @@ The second element is not accepted by other methods. item.description = "Controls the Wolfe condition for the Broyden–Fletcher–Goldfarb–Shanno (BFGS) algorithm used in geometry relaxation. This parameter sets the curvature condition (c2 in Wolfe conditions). For more information, see Phys. Chem. Chem. Phys., 2000, 2, 2177."; item.default_value = "0.5"; item.unit = ""; - item.set_availability("relax_method in [bfgs, cg_bfgs]"); + item.set_availability("relax_method in [bfgs, bfgs_trad, cg_bfgs]"); read_sync_double(input.relax_bfgs_w2); this->add_item(item); } @@ -217,7 +180,7 @@ The second element is not accepted by other methods. item.description = "Maximum allowed total displacement of all atoms during geometry optimization. The sum of atomic displacements can increase during optimization steps but cannot exceed this value."; item.default_value = "0.8"; item.unit = "Bohr"; - item.set_availability("relax_method in [bfgs, cg_bfgs]"); + item.set_availability("relax_method in [bfgs, bfgs_trad, cg_bfgs]"); read_sync_double(input.relax_bfgs_rmax); this->add_item(item); } @@ -226,10 +189,10 @@ The second element is not accepted by other methods. item.annotation = "minimal trust radius, unit: Bohr"; item.category = "Geometry relaxation"; item.type = "Real"; - item.description = "Minimum allowed total displacement of all atoms. When the total atomic displacement falls below this value and force convergence is not achieved, the calculation will terminate. Note: This parameter is not used in the default BFGS algorithm (relax_method = bfgs 2 or bfgs)."; + item.description = "Minimum allowed total displacement of all atoms. When the total atomic displacement falls below this value and force convergence is not achieved, the calculation will terminate. Note: This parameter is not used in the default BFGS algorithm (relax_method = bfgs)."; item.default_value = "1e-5"; item.unit = "Bohr"; - item.set_availability("relax_method==\"bfgs 1\""); + item.set_availability("relax_method==bfgs_trad"); read_sync_double(input.relax_bfgs_rmin); this->add_item(item); } @@ -241,7 +204,7 @@ The second element is not accepted by other methods. item.description = "Initial total displacement of all atoms in the first BFGS step. This sets the scale for the initial movement."; item.default_value = "0.5"; item.unit = "Bohr"; - item.set_availability("relax_method in [bfgs, cg_bfgs]"); + item.set_availability("relax_method in [bfgs, bfgs_trad, cg_bfgs]"); read_sync_double(input.relax_bfgs_init); this->add_item(item); } @@ -296,7 +259,7 @@ The second element is not accepted by other methods. item.type = "String"; item.description = R"(Specifies which cell degrees of freedom are fixed during variable-cell relaxation. The available options depend on relax_method: -With relax_method = cg 2 (default), all options are available: +With relax_method = cg (default), all options are available: * None: Default; all cell parameters can relax freely * volume: Relaxation with fixed volume (allows shape changes) * shape: Fix shape but allow volume changes (hydrostatic pressure only) @@ -308,7 +271,7 @@ With relax_method = cg 2 (default), all options are available: * bc: Fix both b and c axes during relaxation * abc: Fix all three lattice vectors during relaxation -With relax_method set to cg 1, bfgs, lbfgs, sd, or cg_bfgs, None and a, b, c, ab, ac, bc, abc are available. The shape and volume options require cg 2. +With relax_method set to cg_trad, bfgs, bfgs_trad, lbfgs, sd, or cg_bfgs, None and a, b, c, ab, ac, bc, abc are available. The shape and volume options require cg. [NOTE] For VASP users, see the ISIF correspondence table in the geometry optimization documentation.)"; item.default_value = "None"; @@ -319,7 +282,7 @@ With relax_method set to cg 1, bfgs, lbfgs, sd, or cg_bfgs, None and a, b, c, ab if ((para.input.fixed_axes == "shape" || para.input.fixed_axes == "volume") && !para.input.uses_simultaneous_relaxation()) { - ModuleBase::WARNING_QUIT("ReadInput", "fixed shape and fixed volume require relax_method = cg 2"); + ModuleBase::WARNING_QUIT("ReadInput", "fixed shape and fixed volume require relax_method = cg"); } }; this->add_item(item); @@ -335,12 +298,12 @@ With relax_method set to cg 1, bfgs, lbfgs, sd, or cg_bfgs, None and a, b, c, ab [NOTE] Note: it is possible to use fixed_ibrav with fixed_axes, but please make sure you know what you are doing. For example, if we are doing relaxation of a simple cubic lattice (latname = "sc"), and we use fixed_ibrav along with fixed_axes = "volume", then the cell is never allowed to move and as a result, the relaxation never converges. When both are used, fixed_ibrav is applied first, then fixed_axes = "volume" rescaling is applied.)"; item.default_value = "False"; item.unit = ""; - item.set_availability("relax_method==\"cg 2\" and latname!=none"); + item.set_availability("relax_method==cg and latname!=none"); read_sync_bool(input.fixed_ibrav); item.check_value = [](const Input_Item& item, const Parameter& para) { if (para.input.fixed_ibrav && !para.input.uses_simultaneous_relaxation()) { - ModuleBase::WARNING_QUIT("ReadInput", "fixed_ibrav requires relax_method = cg 2"); + ModuleBase::WARNING_QUIT("ReadInput", "fixed_ibrav requires relax_method = cg"); } if (para.input.latname == "none" && para.input.fixed_ibrav) { diff --git a/source/source_io/module_parameter/test/availability_test.cpp b/source/source_io/module_parameter/test/availability_test.cpp index ea44f9a250f..8d9c1fe1d02 100644 --- a/source/source_io/module_parameter/test/availability_test.cpp +++ b/source/source_io/module_parameter/test/availability_test.cpp @@ -49,11 +49,11 @@ TEST(AvailabilityParser, VectorContainmentSemantics) TEST(AvailabilityParser, QuotedMultiTokenValueRoundTrip) { - const AvailabilityExpr e = parse_availability("relax_method==\"cg 2\""); + const AvailabilityExpr e = parse_availability("example_option==\"two words\""); EXPECT_TRUE(e.is_leaf()); EXPECT_EQ(e.condition.op, "=="); - EXPECT_EQ(e.condition.values, (std::vector{"cg 2"})); - EXPECT_EQ(e.to_string(), "relax_method==\"cg 2\""); + EXPECT_EQ(e.condition.values, (std::vector{"two words"})); + EXPECT_EQ(e.to_string(), "example_option==\"two words\""); } TEST(AvailabilityParser, AndGroup) @@ -95,10 +95,10 @@ TEST(AvailabilityParser, InvalidExpressionsAreRejected) " and basis_type==pw", "basis_type==lcao and esolver_type==tddft or ", "basis_type==pw==lcao", - "relax_method in [cg 2]", - "relax_method in [cg 2, bfgs]", - "relax_method in [\"cg 2\"]", - "relax_method==\"cg 2", + "example_option in [two words]", + "example_option in [two words, other]", + "example_option in [\"two words\"]", + "example_option==\"two words", "2 in td_ttype", "basis_type==pw)", "(basis_type==pw", @@ -145,7 +145,7 @@ TEST(AvailabilityValidator, AcceptsKnownTypedReferences) {"basis_type", AvailabilityValueKind::String}, {"mixing_restart", AvailabilityValueKind::Real}, {"td_ttype", AvailabilityValueKind::IntegerVector}, - {"relax_method", AvailabilityValueKind::StringVector}, + {"relax_method", AvailabilityValueKind::String}, }; EXPECT_NO_THROW(validate_availability_expr( "example", @@ -157,7 +157,11 @@ TEST(AvailabilityValidator, AcceptsKnownTypedReferences) "example", parse_availability("td_ttype contains two"), types), std::invalid_argument); EXPECT_NO_THROW(validate_availability_expr( - "example", parse_availability("relax_method==\"cg 2\""), types)); + "example", parse_availability("relax_method==cg"), types)); + const AvailabilityExpr scalar_selection = parse_availability("relax_method in [cg, cg_trad]"); + EXPECT_NO_THROW(validate_availability_expr("example", scalar_selection, types)); + const AvailabilityExpr vector_selection = parse_availability("relax_method contains cg"); + EXPECT_THROW(validate_availability_expr("example", vector_selection, types), std::invalid_argument); } TEST(AvailabilityValidator, InfersDocumentedTypes) diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/test/read_input_ptest.cpp index 30398cd7796..086bea4607d 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/test/read_input_ptest.cpp @@ -119,7 +119,7 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.fixed_axes, "None"); EXPECT_FALSE(param.inp.fixed_ibrav); EXPECT_FALSE(param.inp.fixed_atoms); - EXPECT_EQ(param.inp.relax_method[0], "cg"); + EXPECT_EQ(param.inp.relax_method, "cg"); EXPECT_DOUBLE_EQ(param.inp.relax_cg_thr, 0.5); EXPECT_EQ(param.inp.out_level, "ie"); EXPECT_TRUE(param.globalv.out_md_control); @@ -574,6 +574,9 @@ TEST_F(InputParaTest, TypedTDFieldLists) Parameter param; readinput.read_parameters(param, "./support/INPUT.td_field_mixed"); + EXPECT_EQ(param.inp.relax_method, "cg_trad"); + EXPECT_FALSE(param.inp.uses_simultaneous_relaxation()); + EXPECT_THAT(param.inp.td_ttype, testing::ElementsAre(4, 0, 1, 2, 3, 0, 4, 1, 2, 3)); EXPECT_THAT(param.inp.td_vext_dire, testing::ElementsAre(1, 2, 3, 1, 2, 3, 1, 2, 3, 1)); EXPECT_THAT(param.inp.td_gauss_freq, testing::ElementsAre(0.7, -1.1)); diff --git a/source/source_io/test/support/INPUT b/source/source_io/test/support/INPUT index 8e8d3902c9c..1e44965f10a 100644 --- a/source/source_io/test/support/INPUT +++ b/source/source_io/test/support/INPUT @@ -116,7 +116,7 @@ fixed_axes None #which axes are fixed fixed_ibrav 0 #whether to preseve lattice type during relaxation fixed_atoms 0 #whether to preseve direct coordinates of atoms during relaxation relax_method cg #bfgs; sd; cg; cg_bfgs; -relax_scale_force 0.5 #controls the size of the first CG 2 step +relax_scale_force 0.5 #controls the size of the first simultaneous CG step out_level ie #ie(for electrons); i(for ions); out_dmk 0 #>0 output density matrix DM(k) deepks_out_labels 0 #>0 compute descriptor for deepks diff --git a/source/source_io/test/support/INPUT.td_field_mixed b/source/source_io/test/support/INPUT.td_field_mixed index b60e6a7dc9e..6f908a7b19c 100644 --- a/source/source_io/test/support/INPUT.td_field_mixed +++ b/source/source_io/test/support/INPUT.td_field_mixed @@ -35,3 +35,5 @@ td_supsine_phase 0.2 -0.5 td_supsine_sigma 0.75 1.20 td_supsine_tstart default 2 td_supsine_tend 5 default + +relax_method cg_trad # exercise non-default scalar broadcast 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 6107585e733..aa7b1c50c33 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -56,45 +56,34 @@ TEST_F(InputTest, RelaxMethod) Parameter param; auto it = find_label("relax_method", readinput.input_lists); - it->second.str_values = {"cg"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"cg", "2"})); - EXPECT_TRUE(TestParameters::input(param).uses_simultaneous_relaxation()); - - it->second.str_values = {"cg", "1"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"cg", "1"})); - EXPECT_FALSE(TestParameters::input(param).uses_simultaneous_relaxation()); - - it->second.str_values = {"cg", "2"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"cg", "2"})); - EXPECT_TRUE(TestParameters::input(param).uses_simultaneous_relaxation()); - - it->second.str_values = {"bfgs"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"bfgs", "2"})); - EXPECT_FALSE(TestParameters::input(param).uses_simultaneous_relaxation()); - - it->second.str_values = {"bfgs", "1"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"bfgs", "1"})); - - it->second.str_values = {"bfgs", "2"}; - it->second.read_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).relax_method, (std::vector{"bfgs", "2"})); + EXPECT_EQ(TestParameters::input(param).relax_method, "cg"); + EXPECT_EQ(it->second.type, "String"); + EXPECT_EQ(it->second.default_value, "cg"); + for (const std::string method : {"cg", "cg_trad", "bfgs", "bfgs_trad", "sd", "cg_bfgs", "lbfgs"}) + { + it->second.str_values = {method}; + it->second.read_value(it->second, param); + EXPECT_EQ(TestParameters::input(param).relax_method, method); + EXPECT_EQ(param.inp.uses_simultaneous_relaxation(), method == "cg"); + it->second.final_value.str(""); + it->second.get_final_value(it->second, param); + EXPECT_EQ(it->second.final_value.str(), method); + } for (const std::vector& invalid : { - std::vector{"cg", "3"}, - std::vector{"bfgs", "3"}, - std::vector{"sd", "1"}, + std::vector{}, std::vector{"none"}, + std::vector{"cg", "1"}, + std::vector{"cg", "2"}, + std::vector{"bfgs", "1"}, + std::vector{"bfgs", "2"}, + std::vector{"sd", "1"}, + std::vector{"cg_trad", "1"}, std::vector{"cg", "2", "extra"}}) { it->second.str_values = invalid; EXPECT_EXIT(it->second.read_value(it->second, param), ::testing::ExitedWithCode(1), ""); } - EXPECT_EQ(find_label("relax_new", readinput.input_lists), readinput.input_lists.end()); } @@ -989,14 +978,14 @@ TEST_F(InputTest, Item_test) { // fixed_axes auto it = find_label("fixed_axes", readinput.input_lists); TestParameters::input(param).fixed_axes = "shape"; - TestParameters::input(param).relax_method = {"cg", "1"}; + TestParameters::input(param).relax_method = "cg_trad"; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("NOTICE")); TestParameters::input(param).fixed_axes = "volume"; - TestParameters::input(param).relax_method = {"cg", "1"}; + TestParameters::input(param).relax_method = "cg_trad"; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); @@ -1005,7 +994,7 @@ TEST_F(InputTest, Item_test) { // fixed_ibrav auto it = find_label("fixed_ibrav", readinput.input_lists); TestParameters::input(param).fixed_ibrav = true; - TestParameters::input(param).relax_method = {"cg", "1"}; + TestParameters::input(param).relax_method = "cg_trad"; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); diff --git a/source/source_io/test_serial/read_input_test.cpp b/source/source_io/test_serial/read_input_test.cpp index 236b8e8f87d..e11f0111da8 100644 --- a/source/source_io/test_serial/read_input_test.cpp +++ b/source/source_io/test_serial/read_input_test.cpp @@ -212,26 +212,33 @@ TEST_F(InputTest, RejectAutoDevice) EXPECT_TRUE(std::remove("./auto_device_INPUT") == 0); } -TEST_F(InputTest, ValidateRelaxMethodVariants) +TEST_F(InputTest, ValidateRelaxMethodScalar) { - Parameter cg_param; - EXPECT_NO_THROW(read_parameters("relax_cg_INPUT", "relax_method cg\n", cg_param)); - EXPECT_EQ(cg_param.inp.relax_method, (std::vector{"cg", "2"})); - EXPECT_TRUE(cg_param.inp.uses_simultaneous_relaxation()); - - Parameter bfgs_default_param; - EXPECT_NO_THROW(read_parameters("relax_bfgs_default_INPUT", "relax_method bfgs\n", bfgs_default_param)); - EXPECT_EQ(bfgs_default_param.inp.relax_method, (std::vector{"bfgs", "2"})); - EXPECT_FALSE(bfgs_default_param.inp.uses_simultaneous_relaxation()); - - Parameter bfgs_one_param; - EXPECT_NO_THROW(read_parameters("relax_bfgs_one_INPUT", "relax_method bfgs 1\n", bfgs_one_param)); - EXPECT_EQ(bfgs_one_param.inp.relax_method, (std::vector{"bfgs", "1"})); - - expect_invalid_input("relax_bad_variant_INPUT", "relax_method cg 3\n", "the CG variant must be 1 or 2"); - expect_invalid_input("relax_irrelevant_variant_INPUT", - "relax_method sd 1\n", - "relax_method sd does not accept a second value"); + for (const std::string method : {"cg", "cg_trad", "bfgs", "bfgs_trad", "sd", "cg_bfgs", "lbfgs"}) + { + Parameter param; + EXPECT_NO_THROW(read_parameters("relax_scalar_INPUT", "relax_method " + method + " # comment\n", param)); + EXPECT_EQ(param.inp.relax_method, method); + EXPECT_EQ(param.inp.uses_simultaneous_relaxation(), method == "cg"); + + const std::string output = testing::TempDir() + "relax_scalar_roundtrip_INPUT"; + ModuleIO::ReadInput writer(0); + writer.write_parameters(param, output); + ModuleIO::ReadInput reader(0); + reader.check_ntype_flag = false; + Parameter restored; + EXPECT_NO_THROW(reader.read_parameters(restored, output)); + EXPECT_EQ(restored.inp.relax_method, method); + EXPECT_EQ(std::remove(output.c_str()), 0); + } + const std::string invalid_method_message + = "relax_method requires exactly one scalar option. " + "The parameter relax_method must be 'cg', 'cg_trad', 'bfgs', 'bfgs_trad', 'sd', 'cg_bfgs' or 'lbfgs'!"; + for (const std::string invalid : {"", "none", "cg 1", "cg 2", "bfgs 1", "bfgs 2", "sd 1", "cg_trad 1", "cg 2 extra"}) + { + expect_invalid_input("relax_invalid_INPUT", "relax_method " + invalid + "\n", + invalid_method_message); + } expect_invalid_input("relax_new_removed_INPUT", "relax_new 1\n", "THE PARAMETER NAME 'relax_new' IS INCORRECT"); } diff --git a/source/source_relax/ions_move_cg.cpp b/source/source_relax/ions_move_cg.cpp index 77ef3121fda..043944dfd98 100644 --- a/source/source_relax/ions_move_cg.cpp +++ b/source/source_relax/ions_move_cg.cpp @@ -37,7 +37,7 @@ void Ions_Move_CG::allocate(const int dim) this->fmax = 0.0; } -bool Ions_Move_CG::start(UnitCell &ucell, const ModuleBase::matrix &force, const double &etot_in, const int istep, int& update_iter, std::ofstream& ofs, std::vector& etot_info, std::vector& relax_method, const Relax_Criteria& criteria) +bool Ions_Move_CG::start(UnitCell &ucell, const ModuleBase::matrix &force, const double &etot_in, const int istep, int& update_iter, std::ofstream& ofs, std::vector& etot_info, std::string& relax_method, const Relax_Criteria& criteria) { ModuleBase::TITLE("Ions_Move_CG", "start"); assert(Ions_Move_Basic::dim > 0); @@ -106,13 +106,12 @@ bool Ions_Move_CG::start(UnitCell &ucell, const ModuleBase::matrix &force, const this->fmax = this->fa; this->sd = false; - if (relax_method[0] == "cg_bfgs") + if (relax_method == "cg_bfgs") { if (Ions_Move_Basic::largest_grad * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A < RELAX_CG_THR) { - relax_method[0] = "bfgs"; - relax_method[1] = "1"; + relax_method = "bfgs_trad"; } Ions_Move_Basic::best_xxx = this->steplength; } diff --git a/source/source_relax/ions_move_cg.h b/source/source_relax/ions_move_cg.h index 4ac306fe0d4..efcce60d81a 100644 --- a/source/source_relax/ions_move_cg.h +++ b/source/source_relax/ions_move_cg.h @@ -16,7 +16,7 @@ class Ions_Move_CG : public CG_Base ~Ions_Move_CG() = default; void allocate(const int dim); - bool start(UnitCell &ucell, const ModuleBase::matrix &force, const double &etot, const int istep, int& update_iter, std::ofstream& ofs, std::vector& etot_info, std::vector& relax_method, const Relax_Criteria& criteria); + bool start(UnitCell &ucell, const ModuleBase::matrix &force, const double &etot, const int istep, int& update_iter, std::ofstream& ofs, std::vector& etot_info, std::string& relax_method, const Relax_Criteria& criteria); static double RELAX_CG_THR; diff --git a/source/source_relax/ions_move_methods.cpp b/source/source_relax/ions_move_methods.cpp index 6b2fede7077..0cc9de4c1b1 100644 --- a/source/source_relax/ions_move_methods.cpp +++ b/source/source_relax/ions_move_methods.cpp @@ -15,7 +15,7 @@ Ions_Move_Methods::~Ions_Move_Methods() { } -void Ions_Move_Methods::allocate(const int &natom, const std::string& relax_method_0, const std::string& relax_method_1) +void Ions_Move_Methods::allocate(const int &natom, const std::string& relax_method) { if (natom <= 0) { @@ -23,28 +23,28 @@ void Ions_Move_Methods::allocate(const int &natom, const std::string& relax_meth } Ions_Move_Basic::dim = natom * 3; - if (relax_method_0 == "bfgs" && relax_method_1 != "1") + if (relax_method == "bfgs") { this->bfgs.allocate(); } - else if (relax_method_0 == "sd") + else if (relax_method == "sd") { this->sd.allocate(); } - else if (relax_method_0 == "cg") + else if (relax_method == "cg_trad") { this->cg.allocate(Ions_Move_Basic::dim); } - else if (relax_method_0 == "cg_bfgs") + else if (relax_method == "cg_bfgs") { this->cg.allocate(Ions_Move_Basic::dim); this->bfgs.allocate(); } - else if(relax_method_0 == "bfgs" && relax_method_1 == "1") + else if(relax_method == "bfgs_trad") { this->bfgs_trad.allocate(natom); } - else if(relax_method_0 == "lbfgs") + else if(relax_method == "lbfgs") { this->lbfgs.allocate(natom, PARAM.inp.relax_bfgs_rmax, PARAM.inp.out_level); } @@ -62,31 +62,31 @@ void Ions_Move_Methods::cal_movement(const int &istep, const double &etot, UnitCell &ucell, std::ofstream& ofs, - std::vector& relax_method, + std::string& relax_method, const Relax_Criteria& criteria) { ModuleBase::TITLE("Ions_Move_Methods", "init"); - if (relax_method[0] == "bfgs" && relax_method[1] != "1") + if (relax_method == "bfgs") { converged_ = bfgs.start(ucell, f, etot, force_step, update_iter_, ofs, etot_info_, criteria); } - else if (relax_method[0] == "sd") + else if (relax_method == "sd") { converged_ = sd.start(ucell, f, etot, force_step, update_iter_, ofs, etot_info_, criteria); } - else if (relax_method[0] == "cg") + else if (relax_method == "cg_trad") { converged_ = cg.start(ucell, f, etot, force_step, update_iter_, ofs, etot_info_, relax_method, criteria); } - else if (relax_method[0] == "cg_bfgs") + else if (relax_method == "cg_bfgs") { converged_ = cg.start(ucell, f, etot, force_step, update_iter_, ofs, etot_info_, relax_method, criteria); } - else if (relax_method[0] == "bfgs" && relax_method[1] == "1") + else if (relax_method == "bfgs_trad") { converged_ = bfgs_trad.relax_step(f, ucell, ofs); } - else if (relax_method[0] == "lbfgs") + else if (relax_method == "lbfgs") { converged_ = lbfgs.relax_step(f, ucell, etot, ofs, criteria); } @@ -98,7 +98,7 @@ void Ions_Move_Methods::cal_movement(const int &istep, return; } -void Ions_Move_Methods::reset_after_cell_change(const std::vector& relax_method, std::ofstream& ofs) +void Ions_Move_Methods::reset_after_cell_change(const std::string& relax_method, std::ofstream& ofs) { ModuleBase::TITLE("Ions_Move_Methods", "reset_after_cell_change"); @@ -107,21 +107,19 @@ void Ions_Move_Methods::reset_after_cell_change(const std::vector& return; } - const std::string method = relax_method[0]; - const std::string method_arg = relax_method.size() > 1 ? relax_method[1] : ""; const auto reset_common_state = [this]() { this->converged_ = false; this->update_iter_ = 0; std::fill(this->etot_info_.begin(), this->etot_info_.end(), 0.0); }; - if (method == "bfgs" && method_arg != "1") + if (relax_method == "bfgs") { reset_common_state(); this->bfgs.reset(); ofs << " Reset ionic BFGS history after cell change." << std::endl; } - else if (method == "bfgs" && method_arg == "1") + else if (relax_method == "bfgs_trad") { reset_common_state(); this->bfgs_trad.reset(); diff --git a/source/source_relax/ions_move_methods.h b/source/source_relax/ions_move_methods.h index cc4b22fc253..00d0106585d 100644 --- a/source/source_relax/ions_move_methods.h +++ b/source/source_relax/ions_move_methods.h @@ -18,16 +18,16 @@ class Ions_Move_Methods Ions_Move_Methods(); ~Ions_Move_Methods(); - void allocate(const int &natom, const std::string& relax_method_0, const std::string& relax_method_1); + void allocate(const int &natom, const std::string& relax_method); void cal_movement(const int &istep, const int &force_step, const ModuleBase::matrix &f, const double &etot, UnitCell &ucell, std::ofstream& ofs, - std::vector& relax_method, + std::string& relax_method, const Relax_Criteria& criteria); - void reset_after_cell_change(const std::vector& relax_method, std::ofstream& ofs); + void reset_after_cell_change(const std::string& relax_method, std::ofstream& ofs); bool get_converged() const { diff --git a/source/source_relax/relax_driver.cpp b/source/source_relax/relax_driver.cpp index 7497fc8e1c9..1b672d3f736 100644 --- a/source/source_relax/relax_driver.cpp +++ b/source/source_relax/relax_driver.cpp @@ -316,7 +316,7 @@ void Relax_Driver::print_not_converged_summary(const Input_para& inp, std::ofstr ? rl.get_max_stress_history() : rl_old.get_max_stress_history(); const int ionic_steps = static_cast(force_hist.size()); - const std::string method = inp.relax_method.empty() ? "unknown" : inp.relax_method[0]; + const std::string method = inp.relax_method.empty() ? "unknown" : inp.relax_method; ofs_running << " Relaxation method: " << method << std::endl; ofs_running << " Relaxation stopped after " << ionic_steps << " ionic step(s) (relax_nmax = " << inp.relax_nmax << " reached)." << std::endl; diff --git a/source/source_relax/relax_nsync.cpp b/source/source_relax/relax_nsync.cpp index 548090880d8..b577df2e070 100644 --- a/source/source_relax/relax_nsync.cpp +++ b/source/source_relax/relax_nsync.cpp @@ -9,7 +9,7 @@ void IonCellOptimizer::print_converged_summary(const int istep, const bool with_stress, std::ofstream& ofs_running) const { - ofs_running << " Relaxation method: " << inp_->relax_method[0] << std::endl; + ofs_running << " Relaxation method: " << inp_->relax_method << std::endl; ofs_running << " Relaxation converged in " << istep << " step(s)." << std::endl; if (!max_force_history_.empty()) { @@ -40,11 +40,11 @@ void IonCellOptimizer::init_relax(const int& natom, const Input_para& inp) if (inp_->calculation == "relax") { - IMM.allocate(natom, inp_->relax_method[0], inp_->relax_method[1]); + IMM.allocate(natom, inp_->relax_method); } if (inp_->calculation == "cell-relax") { - IMM.allocate(natom, inp_->relax_method[0], inp_->relax_method[1]); + IMM.allocate(natom, inp_->relax_method); LCM.allocate(); } } @@ -100,7 +100,7 @@ bool IonCellOptimizer::relax_step(const int& istep, // This step never ran cal_movement, so no force was recorded for it; // the actual number of ionic steps taken is the history length. const int ionic_steps = static_cast(max_force_history_.size()); - ofs_running << " Relaxation method: " << inp_->relax_method[0] << std::endl; + ofs_running << " Relaxation method: " << inp_->relax_method << std::endl; ofs_running << " Relaxation stopped after " << ionic_steps << " ionic step(s) (relax_nmax = " << inp_->relax_nmax << " reached)." << std::endl; if (!max_force_history_.empty()) @@ -140,7 +140,7 @@ bool IonCellOptimizer::relax_step(const int& istep, assert(inp_->cal_force == 1); // Calculate and apply atomic movement - std::vector relax_method = inp_->relax_method; + std::string relax_method = inp_->relax_method; Relax_Criteria criteria; criteria.force_thr = inp_->force_thr; diff --git a/source/source_relax/relax_sync.cpp b/source/source_relax/relax_sync.cpp index b2e79c5a931..1b8081ea847 100644 --- a/source/source_relax/relax_sync.cpp +++ b/source/source_relax/relax_sync.cpp @@ -297,7 +297,7 @@ void Relax::print_gradient_summary(bool force_converged, std::ofstream& ofs_runn // setup_gradient runs before istep is incremented at the end of // relax_step, so the step that just converged is istep + 1. const int converged_step = istep + 1; - const std::string method = inp_->relax_method.empty() ? "unknown" : inp_->relax_method[0]; + const std::string method = inp_->relax_method.empty() ? "unknown" : inp_->relax_method; ofs_running << " Relaxation method: " << method << std::endl; ofs_running << " Relaxation converged in " << converged_step << " step(s)." << std::endl; ofs_running << " Largest force per step (eV/Angstrom):" << format_relax_history(max_force_history_); diff --git a/source/source_relax/unittests/test_ions_move_cg.cpp b/source/source_relax/unittests/test_ions_move_cg.cpp index 8603be86b55..5509bc776ed 100644 --- a/source/source_relax/unittests/test_ions_move_cg.cpp +++ b/source/source_relax/unittests/test_ions_move_cg.cpp @@ -123,7 +123,7 @@ TEST_F(IonsMoveCGTest, TestStartConverged) ModuleBase::matrix force(2, 3); double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg", "1"}; + std::string relax_method = "cg_trad"; // call function std::ofstream ofs("TestStartConverged.log"); @@ -155,7 +155,7 @@ TEST_F(IonsMoveCGTest, TestStartSd) { // setup data const int istep = 1; - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; Ions_Move_CG::RELAX_CG_THR = 100.0; UnitCell ucell; setupucell(ucell); @@ -179,7 +179,7 @@ TEST_F(IonsMoveCGTest, TestStartSd) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.01); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, -1.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::relax_bfgs_init, 1.0); @@ -197,7 +197,7 @@ TEST_F(IonsMoveCGTest, TestStartTrialGoto) force(0, 0) = 0.1; double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; // call function set_move0(0, 1.0); @@ -208,7 +208,7 @@ TEST_F(IonsMoveCGTest, TestStartTrialGoto) int istep_2 = 2; set_move0(0, 10.0); force(0, 0) = 0.001; - relax_method = {"cg_bfgs", "1"}; + relax_method = "cg_bfgs"; std::ofstream ofs("TestStartTrialGoto.log"); im_cg.start(ucell, force, etot, istep_2, update_iter, ofs, etot_info, relax_method, criteria); ofs.close(); @@ -223,7 +223,7 @@ TEST_F(IonsMoveCGTest, TestStartTrialGoto) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.001); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, 10.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::relax_bfgs_init, 10.0); @@ -240,7 +240,7 @@ TEST_F(IonsMoveCGTest, TestStartTrial) force(0, 0) = 0.01; double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; // call function set_move0(0, 1.0); @@ -264,7 +264,7 @@ TEST_F(IonsMoveCGTest, TestStartTrial) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.01); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, 10.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::relax_bfgs_init, 70.0); @@ -282,7 +282,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase1) force(0, 0) = 0.1; double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; // call function set_move0(0, 1.0); @@ -297,7 +297,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase1) std::remove("TestStartNoTrialGotoCase1_temp2.log"); set_move0(0, 1.0); force(0, 0) = 0.001; - relax_method = {"cg_bfgs", "1"}; + relax_method = "cg_bfgs"; std::ofstream ofs("TestStartNoTrialGotoCase1.log"); im_cg.start(ucell, force, etot, istep_2, update_iter, ofs, etot_info, relax_method, criteria); ofs.close(); @@ -312,7 +312,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase1) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.001); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, 490.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::relax_bfgs_init, 490.0); @@ -330,7 +330,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase2) force(0, 0) = 0.01; double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; Ions_Move_Basic::best_xxx = 1.0; Ions_Move_Basic::relax_bfgs_init = 1.0; @@ -346,7 +346,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase2) im_cg.start(ucell, force, etot, istep_2, update_iter, ofs2, etot_info, relax_method, criteria); ofs2.close(); std::remove("TestStartNoTrialGotoCase2_temp2.log"); - relax_method = {"cg_bfgs", "1"}; + relax_method = "cg_bfgs"; std::ofstream ofs("TestStartNoTrialGotoCase2.log"); im_cg.start(ucell, force, etot, istep_2, update_iter, ofs, etot_info, relax_method, criteria); ofs.close(); @@ -361,7 +361,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrialGotoCase2) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.01); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, 70.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::relax_bfgs_init, 70.0); @@ -379,7 +379,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrial) force(0, 0) = 0.01; double etot = 0.0; std::vector etot_info(2, 0.0); - std::vector relax_method = {"cg_bfgs", "1"}; + std::string relax_method = "cg_bfgs"; Ions_Move_Basic::best_xxx = 1.0; Ions_Move_Basic::relax_bfgs_init = 1.0; @@ -410,7 +410,7 @@ TEST_F(IonsMoveCGTest, TestStartNoTrial) EXPECT_THAT(output, testing::HasSubstr(expected_output)); EXPECT_EQ(update_iter, 5); - EXPECT_EQ(relax_method[0], "bfgs"); + EXPECT_EQ(relax_method, "bfgs_trad"); EXPECT_DOUBLE_EQ(Ions_Move_Basic::largest_grad, 0.001); EXPECT_DOUBLE_EQ(Ions_Move_Basic::best_xxx, 1.0); EXPECT_NEAR(Ions_Move_Basic::relax_bfgs_init, 1.2345679012345678, 1e-12); diff --git a/source/source_relax/unittests/test_ions_move_methods.cpp b/source/source_relax/unittests/test_ions_move_methods.cpp index 2504e018706..794d49c2073 100644 --- a/source/source_relax/unittests/test_ions_move_methods.cpp +++ b/source/source_relax/unittests/test_ions_move_methods.cpp @@ -110,16 +110,16 @@ class IonsMoveMethodsTest : public ::testing::Test // Test the allocate() function TEST_F(IonsMoveMethodsTest, Allocate) { - imm.allocate(natom, "bfgs", "1"); + imm.allocate(natom, "bfgs_trad"); EXPECT_EQ(Ions_Move_Basic::dim, 6); - imm.allocate(natom, "sd", "1"); + imm.allocate(natom, "sd"); EXPECT_EQ(Ions_Move_Basic::dim, 6); - imm.allocate(natom, "cg", "1"); + imm.allocate(natom, "cg_trad"); EXPECT_EQ(Ions_Move_Basic::dim, 6); - imm.allocate(natom, "cg_bfgs", "1"); + imm.allocate(natom, "cg_bfgs"); EXPECT_EQ(Ions_Move_Basic::dim, 6); } @@ -127,7 +127,7 @@ TEST_F(IonsMoveMethodsTest, Allocate) TEST_F(IonsMoveMethodsTest, AllocateWarningQuit) { GlobalV::ofs_warning.open("log"); - imm.allocate(natom, "none", "1"); + imm.allocate(natom, "none"); GlobalV::ofs_warning.close(); std::ifstream ifs("log"); @@ -149,22 +149,22 @@ TEST_F(IonsMoveMethodsTest, CalMovement) UnitCell ucell; std::ofstream ofs; - std::vector relax_method; + std::string relax_method; - relax_method = {"bfgs", "1"}; - imm.allocate(natom, "bfgs", "1"); + relax_method = "bfgs_trad"; + imm.allocate(natom, "bfgs_trad"); imm.cal_movement(istep, force_step, f, etot, ucell, ofs, relax_method, criteria); - relax_method = {"sd", "1"}; - imm.allocate(natom, "sd", "1"); + relax_method = "sd"; + imm.allocate(natom, "sd"); imm.cal_movement(istep, force_step, f, etot, ucell, ofs, relax_method, criteria); - relax_method = {"cg", "1"}; - imm.allocate(natom, "cg", "1"); + relax_method = "cg_trad"; + imm.allocate(natom, "cg_trad"); imm.cal_movement(istep, force_step, f, etot, ucell, ofs, relax_method, criteria); - relax_method = {"cg_bfgs", "1"}; - imm.allocate(natom, "cg_bfgs", "1"); + relax_method = "cg_bfgs"; + imm.allocate(natom, "cg_bfgs"); imm.cal_movement(istep, force_step, f, etot, ucell, ofs, relax_method, criteria); } @@ -177,8 +177,8 @@ TEST_F(IonsMoveMethodsTest, CalMovementWarningQuit) const double etot = 0.0; UnitCell ucell; std::ofstream ofs; - std::vector relax_method = {"none", "1"}; - imm.allocate(natom, "none", "1"); + std::string relax_method = "none"; + imm.allocate(natom, "none"); GlobalV::ofs_warning.open("log"); imm.cal_movement(istep, force_step, f, etot, ucell, ofs, relax_method, criteria); @@ -229,7 +229,7 @@ TEST_F(IonsMoveMethodsTest, ResetAfterCellChange) const std::string log_file = "reset_after_cell_change.log"; std::ofstream ofs(log_file); - imm.allocate(natom, "bfgs", "2"); + imm.allocate(natom, "bfgs"); imm.set_converged(true); imm.set_update_iter(4); imm.get_etot_info() = {-1.0, -2.0}; @@ -246,7 +246,7 @@ TEST_F(IonsMoveMethodsTest, ResetAfterCellChange) Ions_Move_Basic::trust_radius = 0.3; Ions_Move_Basic::trust_radius_old = 0.2; - imm.reset_after_cell_change({"bfgs", "2"}, ofs); + imm.reset_after_cell_change("bfgs", ofs); EXPECT_FALSE(imm.get_converged()); EXPECT_EQ(imm.get_update_iter(), 0); @@ -270,13 +270,13 @@ TEST_F(IonsMoveMethodsTest, ResetAfterCellChange) EXPECT_DOUBLE_EQ(Ions_Move_Basic::trust_radius, 0.0); EXPECT_DOUBLE_EQ(Ions_Move_Basic::trust_radius_old, 0.0); - imm.allocate(natom, "bfgs", "1"); + imm.allocate(natom, "bfgs_trad"); imm.set_converged(true); imm.set_update_iter(3); imm.get_etot_info() = {-3.0, -4.0}; ASSERT_TRUE(imm.get_bfgs_trad().get_is_initialized()); - imm.reset_after_cell_change({"bfgs", "1"}, ofs); + imm.reset_after_cell_change("bfgs_trad", ofs); ofs.close(); EXPECT_FALSE(imm.get_converged()); diff --git a/source/source_relax/unittests/test_relax_nsync.cpp b/source/source_relax/unittests/test_relax_nsync.cpp index 0efd1289544..7939822354e 100644 --- a/source/source_relax/unittests/test_relax_nsync.cpp +++ b/source/source_relax/unittests/test_relax_nsync.cpp @@ -18,7 +18,7 @@ /** * The running-log convergence reporting is centralized in * IonCellOptimizer::relax_step. These tests lock the unified format shared by - * every relax method (sd/cg/bfgs/bfgs_trad/lbfgs) and by cell-relax: + * every relax method (sd/cg_trad/bfgs/bfgs_trad/lbfgs) and by cell-relax: * Largest force is ... eV/Angstrom while threshold is ... eV/Angstrom * Largest stress is ... kbar while threshold is ... kbar * Relaxation is converged! @@ -152,7 +152,7 @@ class IonCellOptimizerTest : public ::testing::Test TestParameters::set_relax("m", 0.2, 1.0e-5, 0.5, "None"); inp.calculation = "relax"; - inp.relax_method = {"lbfgs", "1"}; + inp.relax_method = "lbfgs"; inp.relax_nmax = 50; inp.force_thr = 0.1; // Ry/Bohr inp.force_thr_ev = 0.1 * 13.6058 / 0.529177; // eV/Angstrom diff --git a/source/source_relax/unittests/test_relax_sync.cpp b/source/source_relax/unittests/test_relax_sync.cpp index 0405bcf59bc..e57b6e1fc67 100644 --- a/source/source_relax/unittests/test_relax_sync.cpp +++ b/source/source_relax/unittests/test_relax_sync.cpp @@ -402,7 +402,7 @@ TEST(RelaxSyncSummary, ConvergedPrintsSummary) const int nat = 1; Input_para inp; inp.calculation = "relax"; - inp.relax_method = {"cg", "2"}; + inp.relax_method = "cg"; inp.force_thr = 0.001; // force_thr_eva ~ 0.0257 eV/Angstrom inp.force_thr_ev = inp.force_thr * 13.6058 / 0.529177; @@ -465,7 +465,7 @@ TEST(RelaxSyncSummary, TwoStepConvergence) const int nat = 1; Input_para inp; inp.calculation = "relax"; - inp.relax_method = {"cg", "2"}; + inp.relax_method = "cg"; inp.force_thr = 0.001; // force_thr_eva ~ 0.0257 eV/Angstrom inp.force_thr_ev = inp.force_thr * 13.6058 / 0.529177; @@ -534,7 +534,7 @@ TEST(RelaxSyncSummary, CellRelaxConvergedPrintsStressHistory) const int nat = 1; Input_para inp; inp.calculation = "cell-relax"; - inp.relax_method = {"cg", "2"}; + inp.relax_method = "cg"; inp.force_thr = 0.001; inp.force_thr_ev = inp.force_thr * 13.6058 / 0.529177; inp.stress_thr = 0.5; // kbar @@ -711,7 +711,7 @@ TEST(RelaxSyncMaxStep, GeometryMovedAndNotConverged) const int nat = 1; Input_para inp; inp.calculation = "relax"; - inp.relax_method = {"cg", "2"}; + inp.relax_method = "cg"; inp.force_thr = 0.0; // never converged -> always take the move inp.force_thr_ev = 0.0; inp.fixed_axes = "None"; diff --git a/tests/01_PW/058_PW_RE_MB/INPUT b/tests/01_PW/058_PW_RE_MB/INPUT index 63dc8ffd9f5..dbfe3094f7e 100644 --- a/tests/01_PW/058_PW_RE_MB/INPUT +++ b/tests/01_PW/058_PW_RE_MB/INPUT @@ -9,7 +9,7 @@ calculation relax relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs # Self-Consistent Field basis_type pw diff --git a/tests/01_PW/059_PW_RE_MB_traj/INPUT b/tests/01_PW/059_PW_RE_MB_traj/INPUT index 64b211c2931..85c87c524d0 100644 --- a/tests/01_PW/059_PW_RE_MB_traj/INPUT +++ b/tests/01_PW/059_PW_RE_MB_traj/INPUT @@ -17,7 +17,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 1 +relax_method bfgs_trad #Parameters (4.Basis) basis_type pw diff --git a/tests/01_PW/060_PW_RE_MG/INPUT b/tests/01_PW/060_PW_RE_MG/INPUT index 2d1a1681ec7..84f286bbcc5 100644 --- a/tests/01_PW/060_PW_RE_MG/INPUT +++ b/tests/01_PW/060_PW_RE_MG/INPUT @@ -17,7 +17,7 @@ cal_force 1 #Parameters (3.Relaxation) relax_nmax 2 force_thr_ev 0.01 -relax_method cg 1 +relax_method cg_trad #Parameters (4.Basis) basis_type pw diff --git a/tests/01_PW/relax_cell/INPUT b/tests/01_PW/relax_cell/INPUT index c2475148d0b..da5b411976c 100644 --- a/tests/01_PW/relax_cell/INPUT +++ b/tests/01_PW/relax_cell/INPUT @@ -13,7 +13,7 @@ ecutwfc 20 scf_nmax 20 kpar 2 -relax_method cg 1 +relax_method cg_trad relax_nmax 2 cal_stress 1 diff --git a/tests/01_PW/relax_cell_fix_abc/INPUT b/tests/01_PW/relax_cell_fix_abc/INPUT index 99baec6201b..c86868895d3 100644 --- a/tests/01_PW/relax_cell_fix_abc/INPUT +++ b/tests/01_PW/relax_cell_fix_abc/INPUT @@ -14,7 +14,7 @@ scf_nmax 20 basis_type pw relax_nmax 2 -relax_method cg 1 +relax_method cg_trad cal_stress 1 stress_thr 1e-6 diff --git a/tests/01_PW/relax_cell_fix_ac/INPUT b/tests/01_PW/relax_cell_fix_ac/INPUT index 9feeeab06a2..c17948c2964 100644 --- a/tests/01_PW/relax_cell_fix_ac/INPUT +++ b/tests/01_PW/relax_cell_fix_ac/INPUT @@ -15,7 +15,7 @@ scf_nmax 20 basis_type pw relax_nmax 2 -relax_method cg 1 +relax_method cg_trad cal_stress 1 stress_thr 1e-6 diff --git a/tests/01_PW/relax_cell_move/INPUT b/tests/01_PW/relax_cell_move/INPUT index 18996cab80f..18ed4977f27 100644 --- a/tests/01_PW/relax_cell_move/INPUT +++ b/tests/01_PW/relax_cell_move/INPUT @@ -12,7 +12,7 @@ scf_nmax 20 basis_type pw relax_nmax 2 -relax_method cg 1 +relax_method cg_trad cal_stress 1 stress_thr 1e-6 diff --git a/tests/02_NAO_Gamma/010_NO_GO_RE_OW/INPUT b/tests/02_NAO_Gamma/010_NO_GO_RE_OW/INPUT index 35a2fcddcb0..1ed906ec516 100644 --- a/tests/02_NAO_Gamma/010_NO_GO_RE_OW/INPUT +++ b/tests/02_NAO_Gamma/010_NO_GO_RE_OW/INPUT @@ -17,7 +17,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs #Parameters (4.Basis) basis_type lcao diff --git a/tests/02_NAO_Gamma/011_NO_GO_RE_OW2/INPUT b/tests/02_NAO_Gamma/011_NO_GO_RE_OW2/INPUT index 4a03fe40a40..e9c7f396c97 100644 --- a/tests/02_NAO_Gamma/011_NO_GO_RE_OW2/INPUT +++ b/tests/02_NAO_Gamma/011_NO_GO_RE_OW2/INPUT @@ -18,7 +18,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs #Parameters (4.Basis) basis_type lcao diff --git a/tests/02_NAO_Gamma/relax_old_cg/INPUT b/tests/02_NAO_Gamma/relax_old_cg/INPUT index 6be9ec96459..47c7cb99777 100644 --- a/tests/02_NAO_Gamma/relax_old_cg/INPUT +++ b/tests/02_NAO_Gamma/relax_old_cg/INPUT @@ -17,7 +17,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method cg 1 +relax_method cg_trad cal_stress 1 #Parameters (4.Basis) diff --git a/tests/02_NAO_Gamma/relax_out_hk/INPUT b/tests/02_NAO_Gamma/relax_out_hk/INPUT index 2010cbaf9a2..66f813f3cda 100644 --- a/tests/02_NAO_Gamma/relax_out_hk/INPUT +++ b/tests/02_NAO_Gamma/relax_out_hk/INPUT @@ -17,7 +17,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs #Parameters (4.Basis) basis_type lcao diff --git a/tests/02_NAO_Gamma/relax_out_hk_spin2/INPUT b/tests/02_NAO_Gamma/relax_out_hk_spin2/INPUT index a9497b2548b..1609a28e700 100644 --- a/tests/02_NAO_Gamma/relax_out_hk_spin2/INPUT +++ b/tests/02_NAO_Gamma/relax_out_hk_spin2/INPUT @@ -18,7 +18,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs #Parameters (4.Basis) basis_type lcao diff --git a/tests/03_NAO_multik/relax_bfgs2/INPUT b/tests/03_NAO_multik/relax_bfgs2/INPUT index 484206fdea0..a3676d3e07d 100644 --- a/tests/03_NAO_multik/relax_bfgs2/INPUT +++ b/tests/03_NAO_multik/relax_bfgs2/INPUT @@ -17,7 +17,7 @@ scf_nmax 100 relax_nmax 2 cal_force 1 force_thr_ev 0.01 -relax_method bfgs 2 +relax_method bfgs #Parameters (4.Basis) basis_type lcao diff --git a/tests/03_NAO_multik/relax_cell/INPUT b/tests/03_NAO_multik/relax_cell/INPUT index 1951ff56f7f..f178ab38ecb 100644 --- a/tests/03_NAO_multik/relax_cell/INPUT +++ b/tests/03_NAO_multik/relax_cell/INPUT @@ -22,4 +22,4 @@ ks_solver scalapack_gvx mixing_type broyden mixing_beta 0.7 -relax_method cg 1 +relax_method cg_trad diff --git a/tests/03_NAO_multik/relax_old_cg/INPUT b/tests/03_NAO_multik/relax_old_cg/INPUT index e61814f7cee..77ebb96abed 100644 --- a/tests/03_NAO_multik/relax_old_cg/INPUT +++ b/tests/03_NAO_multik/relax_old_cg/INPUT @@ -22,4 +22,4 @@ ks_solver scalapack_gvx mixing_type broyden mixing_beta 0.7 -relax_method cg 1 +relax_method cg_trad diff --git a/tests/09_DeePKS/07_NO_GO_deepks_relax/INPUT b/tests/09_DeePKS/07_NO_GO_deepks_relax/INPUT index 4dc7e157c99..6f01b08f315 100644 --- a/tests/09_DeePKS/07_NO_GO_deepks_relax/INPUT +++ b/tests/09_DeePKS/07_NO_GO_deepks_relax/INPUT @@ -2,7 +2,7 @@ INPUT_PARAMETERS #Parameters (1.General) suffix autotest calculation relax -relax_method bfgs 2 +relax_method bfgs relax_nmax 10 dft_functional pbe diff --git a/tests/09_DeePKS/08_NO_KP_deepks_relax/INPUT b/tests/09_DeePKS/08_NO_KP_deepks_relax/INPUT index 63269558033..d92385116f7 100644 --- a/tests/09_DeePKS/08_NO_KP_deepks_relax/INPUT +++ b/tests/09_DeePKS/08_NO_KP_deepks_relax/INPUT @@ -2,7 +2,7 @@ INPUT_PARAMETERS #Parameters (1.General) suffix autotest calculation relax -relax_method bfgs 2 +relax_method bfgs relax_nmax 10 dft_functional pbe