Skip to content

Commit 4b1fc7d

Browse files
19helloFei Yang
andauthored
Reset BFGS history after cell changes (deepmodeling#7507)
* Reset BFGS history after cell changes * Add reset-after-cell-change coverage Fixes deepmodeling#4140. This PR resets ionic BFGS state after an actual cell update in cell-relax so the optimizer does not reuse coordinates, gradients, Hessian history, trust radius, or traditional BFGS initialization from the previous cell. The test coverage now lives in the existing ions_move_methods_test.cpp target and checks both new BFGS and traditional BFGS reset paths. --------- Co-authored-by: Fei Yang <2501213217@stu.pku.edu.cn>
1 parent f7b3111 commit 4b1fc7d

9 files changed

Lines changed: 170 additions & 6 deletions

source/source_relax/ions_move_bfgs.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ void Ions_Move_BFGS::allocate()
3737
return;
3838
}
3939

40+
void Ions_Move_BFGS::reset()
41+
{
42+
if (init_done)
43+
{
44+
std::fill(pos.begin(), pos.end(), 0.0);
45+
std::fill(pos_p.begin(), pos_p.end(), 0.0);
46+
std::fill(grad.begin(), grad.end(), 0.0);
47+
std::fill(grad_p.begin(), grad_p.end(), 0.0);
48+
std::fill(move.begin(), move.end(), 0.0);
49+
std::fill(move_p.begin(), move_p.end(), 0.0);
50+
51+
this->reset_hessian();
52+
}
53+
this->save_flag = false;
54+
this->tr_min_hit = false;
55+
this->first_step = true;
56+
57+
Ions_Move_Basic::trust_radius = 0.0;
58+
Ions_Move_Basic::trust_radius_old = 0.0;
59+
}
60+
4061
bool Ions_Move_BFGS::start(UnitCell& ucell, const ModuleBase::matrix& force, const double& energy_in, const int istep, int& update_iter, std::ofstream& ofs, std::vector<double>& etot_info)
4162
{
4263
ModuleBase::TITLE("Ions_Move_BFGS", "start");

source/source_relax/ions_move_bfgs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Ions_Move_BFGS : public BFGS_Basic
1414
~Ions_Move_BFGS();
1515

1616
void allocate(void);
17+
void reset(void);
1718
bool start(UnitCell& ucell, const ModuleBase::matrix& force, const double& energy_in, const int istep, int& update_iter, std::ofstream& ofs, std::vector<double>& etot_info);
1819

1920
private:

source/source_relax/ions_move_bfgs2.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ void Ions_Move_BFGS2::allocate(const int _size)
3333
is_initialized = true;
3434
}
3535

36+
void Ions_Move_BFGS2::reset()
37+
{
38+
is_initialized = false;
39+
}
40+
3641

3742
bool Ions_Move_BFGS2::relax_step(const ModuleBase::matrix& _force,UnitCell& ucell, std::ofstream& ofs_running)
3843
{

source/source_relax/ions_move_bfgs2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Ions_Move_BFGS2
1515
{
1616
public:
1717
void allocate(const int _size);//initialize parameters
18+
void reset();
1819
bool relax_step(const ModuleBase::matrix& _force,UnitCell& ucell, std::ofstream& ofs_running);//a full iteration step
1920

2021

source/source_relax/ions_move_methods.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "ions_move_methods.h"
22

3+
#include <algorithm>
4+
35
#include "ions_move_basic.h"
46
#include "source_base/global_function.h"
57
#include "source_base/global_variable.h"
@@ -93,3 +95,34 @@ void Ions_Move_Methods::cal_movement(const int &istep,
9395
}
9496
return;
9597
}
98+
99+
void Ions_Move_Methods::reset_after_cell_change(const std::vector<std::string>& relax_method, std::ofstream& ofs)
100+
{
101+
ModuleBase::TITLE("Ions_Move_Methods", "reset_after_cell_change");
102+
103+
if (relax_method.empty())
104+
{
105+
return;
106+
}
107+
108+
const std::string method = relax_method[0];
109+
const std::string method_arg = relax_method.size() > 1 ? relax_method[1] : "";
110+
const auto reset_common_state = [this]() {
111+
this->converged_ = false;
112+
this->update_iter_ = 0;
113+
std::fill(this->etot_info_.begin(), this->etot_info_.end(), 0.0);
114+
};
115+
116+
if (method == "bfgs" && method_arg != "1")
117+
{
118+
reset_common_state();
119+
this->bfgs.reset();
120+
ofs << " Reset ionic BFGS history after cell change." << std::endl;
121+
}
122+
else if (method == "bfgs" && method_arg == "1")
123+
{
124+
reset_common_state();
125+
this->bfgs_trad.reset();
126+
ofs << " Reset traditional ionic BFGS history after cell change." << std::endl;
127+
}
128+
}

source/source_relax/ions_move_methods.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Ions_Move_Methods
2525
UnitCell &ucell,
2626
std::ofstream& ofs,
2727
std::vector<std::string>& relax_method);
28+
void reset_after_cell_change(const std::vector<std::string>& relax_method, std::ofstream& ofs);
2829

2930
bool get_converged() const
3031
{
@@ -56,6 +57,6 @@ class Ions_Move_Methods
5657
Ions_Move_LBFGS lbfgs;
5758
bool converged_ = false;
5859
int update_iter_ = 0;
59-
std::vector<double> etot_info_{2, 0.0}; // [etot, etot_p]
60+
std::vector<double> etot_info_{0.0, 0.0}; // [etot, etot_p]
6061
};
6162
#endif

source/source_relax/relax_nsync.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ bool IonCellOptimizer::relax_step(const int& istep,
128128
// Reset force_step counter after cell change for fresh atomic relaxation
129129
force_step = 1;
130130
stress_step++;
131+
IMM.reset_after_cell_change(PARAM.inp.relax_method, ofs_running);
131132
ucell.cell_parameter_updated = true;
132133

133134
// Update cell-related parameters after volume change
@@ -145,4 +146,3 @@ bool IonCellOptimizer::relax_step(const int& istep,
145146

146147
return true;
147148
}
148-

source/source_relax/test/CMakeLists.txt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,27 @@ AddTest(
8686
${cell_source_files}
8787
)
8888

89+
AddTest(
90+
TARGET MODULE_RELAX_ions_move_methods_test
91+
LIBS parameter ${math_libs} base device
92+
SOURCES ions_move_methods_test.cpp
93+
../ions_move_methods.cpp
94+
../ions_move_bfgs.cpp
95+
../ions_move_bfgs2.cpp
96+
../ions_move_cg.cpp
97+
../ions_move_sd.cpp
98+
../ions_move_lbfgs.cpp
99+
../ions_move_basic.cpp
100+
../bfgs_basic.cpp
101+
../cg_base.cpp
102+
../matrix_methods.cpp
103+
../relax_data.cpp
104+
../../source_io/module_output/orb_io.cpp
105+
../../source_cell/bcast_cell.cpp
106+
../../source_cell/print_cell.cpp
107+
../../source_io/module_output/output.cpp
108+
)
109+
89110
AddTest(
90111
TARGET MODULE_RELAX_ions_move_cg_test
91112
LIBS parameter ${math_libs} base device
@@ -102,4 +123,4 @@ AddTest(
102123
TARGET MODULE_RELAX_ions_move_sd_test
103124
LIBS parameter ${math_libs} base device
104125
SOURCES ions_move_sd_test.cpp ../ions_move_sd.cpp ../ions_move_basic.cpp ../relax_data.cpp ${cell_source_files}
105-
)
126+
)

source/source_relax/test/ions_move_methods_test.cpp

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
#include "for_test.h"
22
#include "gmock/gmock.h"
33
#include "gtest/gtest.h"
4+
#include <algorithm>
5+
#include <cstdio>
6+
#include <fstream>
7+
#include <iterator>
8+
#include <string>
9+
#include <vector>
410
#define private public
11+
#define protected public
512
#include "source_relax/ions_move_methods.h"
13+
#undef protected
614
#undef private
715
/************************************************
816
* unit tests of class Ions_Move_Methods
@@ -62,6 +70,10 @@ namespace unitcell
6270
}
6371
}
6472

73+
void update_pos_tau(const Lattice&, const double*, const int, const int, Atom*)
74+
{
75+
}
76+
6577
// Helper function to reset mock state
6678
void reset_remake_cell_mock()
6779
{
@@ -130,7 +142,9 @@ TEST_F(IonsMoveMethodsTest, CalMovement)
130142
{
131143
const int istep = 0;
132144
const int force_step = 1;
133-
const ModuleBase::matrix f(3, 3);
145+
ModuleBase::matrix f(natom, 3);
146+
f(0, 0) = 0.1;
147+
f(1, 1) = -0.1;
134148
const double etot = 0.0;
135149
UnitCell ucell;
136150
std::ofstream ofs;
@@ -205,7 +219,74 @@ TEST_F(IonsMoveMethodsTest, GetTrustRadius)
205219
// Test the get_update_iter() function
206220
TEST_F(IonsMoveMethodsTest, GetUpdateIter)
207221
{
208-
Ions_Move_Basic::update_iter = 4;
222+
imm.update_iter_ = 4;
209223

210224
EXPECT_EQ(imm.get_update_iter(), 4);
211-
}
225+
}
226+
227+
TEST_F(IonsMoveMethodsTest, ResetAfterCellChange)
228+
{
229+
const std::string log_file = "reset_after_cell_change.log";
230+
std::ofstream ofs(log_file);
231+
232+
imm.allocate(natom, "bfgs", "2");
233+
imm.converged_ = true;
234+
imm.update_iter_ = 4;
235+
imm.etot_info_ = {-1.0, -2.0};
236+
imm.bfgs.first_step = false;
237+
imm.bfgs.save_flag = true;
238+
imm.bfgs.tr_min_hit = true;
239+
std::fill(imm.bfgs.pos.begin(), imm.bfgs.pos.end(), 1.0);
240+
std::fill(imm.bfgs.pos_p.begin(), imm.bfgs.pos_p.end(), 2.0);
241+
std::fill(imm.bfgs.grad.begin(), imm.bfgs.grad.end(), 3.0);
242+
std::fill(imm.bfgs.grad_p.begin(), imm.bfgs.grad_p.end(), 4.0);
243+
std::fill(imm.bfgs.move.begin(), imm.bfgs.move.end(), 5.0);
244+
std::fill(imm.bfgs.move_p.begin(), imm.bfgs.move_p.end(), 6.0);
245+
Ions_Move_Basic::trust_radius = 0.3;
246+
Ions_Move_Basic::trust_radius_old = 0.2;
247+
248+
imm.reset_after_cell_change({"bfgs", "2"}, ofs);
249+
250+
EXPECT_FALSE(imm.converged_);
251+
EXPECT_EQ(imm.update_iter_, 0);
252+
EXPECT_THAT(imm.etot_info_, testing::Each(0.0));
253+
EXPECT_TRUE(imm.bfgs.first_step);
254+
EXPECT_FALSE(imm.bfgs.save_flag);
255+
EXPECT_FALSE(imm.bfgs.tr_min_hit);
256+
EXPECT_THAT(imm.bfgs.pos, testing::Each(0.0));
257+
EXPECT_THAT(imm.bfgs.pos_p, testing::Each(0.0));
258+
EXPECT_THAT(imm.bfgs.grad, testing::Each(0.0));
259+
EXPECT_THAT(imm.bfgs.grad_p, testing::Each(0.0));
260+
EXPECT_THAT(imm.bfgs.move, testing::Each(0.0));
261+
EXPECT_THAT(imm.bfgs.move_p, testing::Each(0.0));
262+
for (int i = 0; i < Ions_Move_Basic::dim; ++i)
263+
{
264+
for (int j = 0; j < Ions_Move_Basic::dim; ++j)
265+
{
266+
EXPECT_DOUBLE_EQ(imm.bfgs.inv_hess(i, j), i == j ? 1.0 : 0.0);
267+
}
268+
}
269+
EXPECT_DOUBLE_EQ(Ions_Move_Basic::trust_radius, 0.0);
270+
EXPECT_DOUBLE_EQ(Ions_Move_Basic::trust_radius_old, 0.0);
271+
272+
imm.allocate(natom, "bfgs", "1");
273+
imm.converged_ = true;
274+
imm.update_iter_ = 3;
275+
imm.etot_info_ = {-3.0, -4.0};
276+
ASSERT_TRUE(imm.bfgs_trad.is_initialized);
277+
278+
imm.reset_after_cell_change({"bfgs", "1"}, ofs);
279+
ofs.close();
280+
281+
EXPECT_FALSE(imm.converged_);
282+
EXPECT_EQ(imm.update_iter_, 0);
283+
EXPECT_THAT(imm.etot_info_, testing::Each(0.0));
284+
EXPECT_FALSE(imm.bfgs_trad.is_initialized);
285+
286+
std::ifstream ifs(log_file);
287+
const std::string output((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
288+
EXPECT_THAT(output, testing::HasSubstr("Reset ionic BFGS history after cell change."));
289+
EXPECT_THAT(output, testing::HasSubstr("Reset traditional ionic BFGS history after cell change."));
290+
ifs.close();
291+
std::remove(log_file.c_str());
292+
}

0 commit comments

Comments
 (0)