Skip to content

Refactor the relax module#7456

Open
mohanchen wants to merge 49 commits into
deepmodeling:developfrom
mohanchen:20260608-relax
Open

Refactor the relax module#7456
mohanchen wants to merge 49 commits into
deepmodeling:developfrom
mohanchen:20260608-relax

Conversation

@mohanchen

Copy link
Copy Markdown
Collaborator

Refactor the relax module

@mohanchen mohanchen requested a review from 19hello June 8, 2026 13:55
@mohanchen mohanchen added the Refactor Refactor ABACUS codes label Jun 8, 2026
abacus_fixer added 18 commits June 9, 2026 13:48
主要修改:
1. 移除了 relax_driver.h 中未使用的 Ions_Move_BFGS2 bfgs_trad 成员变量及其头文件包含
2. 将 relax_driver.cpp 中 while 循环内的逻辑拆分为多个独立函数:
   - init_relax(): 初始化弛豫方法
   - iter_info(): 打印迭代信息
   - esolve(): 电子结构计算
   - relax_step(): 执行单次弛豫步骤
   - stru_out(): 输出结构文件
   - json_out(): 输出 JSON 结果
   - stop_cond(): 检查停止条件
   - final_out(): 最终输出

3. 添加了成员变量用于缓存计算结果:force_, stress_, force_step, stress_step
4. 优化了 final_out() 函数,将重复的条件判断合并为早期返回
5. 所有成员变量和成员函数调用都添加了 this-> 前缀,提高代码可读性
abacus_fixer added 2 commits June 11, 2026 16:04
@@ -87,87 +43,73 @@ void Ions_Move_CG::start(UnitCell &ucell, const ModuleBase::matrix &force, const
static double steplength = 0.0;
static double fmax = 0.0;
static int nbrent = 0;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CG line-search state is still stored as function-local static variables (sd, trial, ncggrad, fa/fb/fc, xa/xb/xc, etc.).

This keeps the state shared across all instances of Ions_Move_CG. It is not a new behavior introduced by this PR, but since this PR is refactoring the relax module and moving other data into class-owned vectors, it would be better to move these variables into class members as well.

That would make the CG optimizer state explicit, easier to reset in allocate() / initialization, and safer if multiple optimizer objects are ever created in the same process.

Comment on lines 36 to 48
static bool sd = false;

// a cubic interpolation is used to make the third point,
// when sa = trial = false, we use Brent to get the
// minimum point in this direction.
static bool trial = false;

// ncggrad is a parameter to control the cg method,
// every ten cg direction, we change the direction back to
// the steepest descent method
static bool trial = false;
static int ncggrad = 0;

static double fa = 0.0;
static double fb = 0.0;
static double fc = 0.0;

static double xa = 0.0;
static double xb = 0.0;
static double xc = 0.0;

static double xpt = 0.0;
static double steplength = 0.0;
static double fmax = 0.0;

static int nbrent = 0;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shares the same problem as the static local variables in Ions_Move_CG.

Comment thread source/source_relax/relax_driver.cpp Outdated
Comment on lines +92 to +100
if (PARAM.inp.cal_force)
{
p_esolver->cal_force(ucell, this->force_);
}

// calculate and gather all parts of total ionic forces
if (inp.cal_force)
{
p_esolver->cal_force(ucell, force);
}
else
{
// do nothing
}
if (PARAM.inp.cal_stress)
{
p_esolver->cal_stress(ucell, this->stress_);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relax_Driver::relax_driver() receives const Input_para& inp, but some helper functions still read from the global PARAM.inp, for example esolve() checks PARAM.inp.cal_force and PARAM.inp.cal_stress.

Could we pass inp into esolve() and use inp.cal_force / inp.cal_stress there?

Using both an explicit input parameter and the global PARAM.inp in the same driver makes the data source less clear. Keeping the helper functions driven by the passed inp would make the refactor cleaner and reduce hidden global dependencies.

Comment on lines 56 to 66
void Ions_Move_Methods::cal_movement(const int &istep,
const int &force_step,
const ModuleBase::matrix &f,
const double &etot,
UnitCell &ucell)
UnitCell &ucell,
std::ofstream& ofs)
{
ModuleBase::TITLE("Ions_Move_Methods", "init");
// Ions_Move_Basic::istep = istep;
Ions_Move_Basic::istep = force_step;
if (Ions_Move_Basic::relax_method[0] == "bfgs"&&Ions_Move_Basic::relax_method[1] != "1")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ions_Move_Methods::allocate() now receives relax_method_0 and relax_method_1, but cal_movement() still dispatches based on the global Ions_Move_Basic::relax_method.

This makes the interface look instance-based during allocation, while the runtime behavior is still controlled by global state. It could also become inconsistent if Ions_Move_Basic::relax_method is changed after allocation, for example in the cg_bfgs path.

Could Ions_Move_Methods store the selected method as member variables during allocate() and use those members in cal_movement()?

Comment thread source/source_relax/relax_driver.cpp Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactor Refactor ABACUS codes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants