Abinit SCF 计算:收敛标准 + 代码流程详解
基于 Abinit 10.4.7 源码分析
SCF 收敛标准:五大判据
Abinit 的 SCF 循环允许用户选择 5 种收敛判据之一(在输入文件中设置,不能多选)。判据由 dtset 结构体读入,统一存放在数组 tollist(1:8) 中。
判据数组位置:src/67_common/m_common.F90 第 450-452 行(scprqt 子程序)
| 输入变量 | 物理含义 | 监控变量 | 默认/典型场景 |
|---|---|---|---|
tolwfr | 波函数残差平方的容差 | residm(最大本征态残差) | 非自洽计算必须用;GW 等高精度 |
toldfe | 总能量差的容差 | deltae = E(istep) − E(istep−1) | 单点能计算常用 |
tolvrs | 势/密度残差平方范数容差 | res2 = ‖V_new − V_old‖² | 自洽计算最常用 |
toldff | 力变化量的容差 | diffor(最大原子力变化) | 结构优化时 |
tolrff | 力的相对变化容差 | diffor / maxfor | 结构优化(相对判据) |
注:tollist(8) = vdw_df_threshold 是 vdW-DF 修正的阈值,不算主判据。
收敛判据的核心代码逻辑
文件:src/67_common/m_common.F90,子程序 scprqt,choice = 2 分支(第 553-771 行)。
tolwfr 判据(一次性满足即收敛)
! m_common.F90:565
if (ttolwfr==1 .and. (ttolvrs+ttoldfe+ttoldff+ttolrff==0) .and. .not.noquit) then
if (residm < tolwfr) then
write(message,...) ' At SCF step',istep,' max residual=',residm,' < tolwfr=',tolwfr,' =>converged.'
quit=1
end if
end iftoldff 判据(连续 2 次满足才收敛)
! m_common.F90:583
if (ttoldff==1) then
if (istep==1) then
toldff_ok=0
else if (diffor < toldff) then
toldff_ok=toldff_ok+1 ! 计数器累加
else
toldff_ok=0 ! 不满足就清零
end if
if (toldff_ok>=2 .and. .not.noquit) quit=1
end iftolrff 判据(连续 2 次 diffor < tolrff*maxfor)
! m_common.F90:620
else if (diffor < tolrff*maxfor .or. (maxfor < tol16 .and. diffor < tol16)) then
tolrff_ok=tolrff_ok+1
if (maxfor < tol16 .and. res2 > tol9) tolrff_ok=0 ! 防止伪收敛toldfe 判据(连续 2 次 |ΔE| < toldfe)
! m_common.F90:654
if (ttoldfe==1) then
if (istep==1) then
toldfe_ok=0
else if (abs(deltae)<toldfe) then
toldfe_ok=toldfe_ok+1
else
toldfe_ok=0
end if
! 杂化泛函下规则不同(只需第一次满足)
if (toldfe_ok>=2 .and. .not.noquit) quit=1
end iftolvrs 判据(一次性满足,最常用)
! m_common.F90:731
if (ttolvrs==1 .and. .not.noquit) then
if (res2 < tolvrs) then
write(message,...) ' At SCF step',istep,' vres2=',res2,' < tolvrs=',tolvrs,' =>converged.'
quit=1
end if
end if
核心退出旗标:quit=1 → 主循环 exit,进入收敛后处理。
SCF 主循环代码流程(步骤 + 代码实现)
总体调用层级
abinit (主程序)
└── driver (95_drive)
└── gstateimg → gstate
└── scfcv_run (src/94_scfcv/m_scfcv.F90)
└── scfcv_core (src/94_scfcv/m_scfcv_core.F90) ← 主 SCF 循环在此主循环结构
文件:src/94_scfcv/m_scfcv_core.F90
! 第 445 行:读取最大迭代数
nstep = dtset%nstep
! 第 1034 行:进入 SCF 主循环
do istep = 1, max(1, nstep)
! 步骤 1:初始化(仅 istep=1 或原子移动时)
call getcut(...) ! 倒空间截断
call getph(...) ! 结构因子相位
! 步骤 2:构造试探势 V_trial
call setvtr(...) ! 第 1408 行:V_trial = V_psp + V_xc + V_Hartree
! 步骤 3:核心 —— 由势求新密度
call vtorho(...) ! 第 1632 行
! 输出: cg, eigen, residm, res2, rhor, rhog
! 步骤 4 (密度混合 iscf>=10):计算总能与力
call etotfor(...) ! 第 1716 行 → deltae, diffor, maxfor
! 步骤 5 (密度混合):检查收敛
call scprqt(choice=2, ...) ! 第 1738 行 → 设 quit
if (istep == nstep) quit=1
if (quit==1) exit ! 第 1760 行:满足判据则退出
! 步骤 6 (密度混合):密度混合
call newrho(...) ! 第 1798 行:Anderson/Pulay/CG 等混合方案
! 步骤 7:由新密度求新势
call rhotov(...) ! 第 1884 行 → vxc, vhartr, vtrial, res2
! 步骤 8 (势混合 iscf<10):算总能 + 检查收敛 + 势混合
call etotfor(...)
call scprqt(...) ! 第 1951 行
if (quit==1) exit
call newvtr(...) ! 第 2000 行
end do ! 第 2077 行:循环结束
关键子程序详解
| 子程序 | 文件位置 | 作用 | 关键输出 |
|---|---|---|---|
scfcv_core | 94_scfcv/m_scfcv_core.F90:263 | SCF 主驱动 | 控制整个循环 |
setvtr | 67_common/m_setvtr.F90 | 由密度构造试探势 | vtrial = vpsp + vxc + vhartr |
vtorho | 79_seqpar_mpi/m_vtorho.F90 | 从势求新密度(含本征态求解) | cg, eigen, residm, res2, rhor |
etotfor | 67_common/m_etotfor.F90 | 计算总能量与原子受力 | etotal, deltae, diffor, maxfor, fcart |
rhotov | 67_common/m_rhotov.F90 | 从密度算新势 | vxc, vhartr, vtrial, res2 |
newrho | 68_rsprc/m_newrho.F90 | 密度混合 | 新的 rhor |
newvtr | 68_rsprc/m_newvtr.F90 | 势混合 | 新的 vtrial |
scprqt | 67_common/m_common.F90:183 | 收敛判定与打印 | quit, conv_retcode |
关键变量含义(收敛监控相关)
| 变量名 | 含义 | 计算位置 |
|---|---|---|
residm | 全部 k 点/能带的最大波函数残差 | m_vtorho.F90:2078:residm = max(residm, maxval(resid)) |
res2 | 密度或势残差的平方范数 | m_vtorho.F90:2221(密度混合)或 m_rhotov.F90(势混合) |
deltae | 总能量差 E(n) − E(n−1) | etotfor |
diffor | 原子受力的最大变化量 | etotfor |
maxfor | 当前最大力 `max | F_i |
quit | 退出标志(0=继续,1=退出) | scprqt |
conv_retcode | 最终收敛码(0=收敛,1=未收敛) | scprqt(choice=3) |
nstep | 最大 SCF 迭代步数 | 输入参数 dtset%nstep |
istep | 当前迭代步索引 | 主循环计数器 |
iscf 选项决定的两种工作模式
势混合模式(iscf < 10):先求势残差再混合
vtorho → rhotov → scprqt → newvtr
密度混合模式(iscf >= 10,常用):先混合密度再求势
vtorho → etotfor → scprqt → newrho → rhotov
特殊值:
iscf < 0:非自洽(NSCF),所有迭代在vtorho内部完成,主循环只跑 1 圈iscf == 22:ODA(Optimal Damping Algorithm)混合
强制退出条件(总结)
主循环退出由 quit==1 触发,可能来自:
- 满足某个
tol*判据(scprqt设置)— 正常收敛 istep == nstep— 达到最大步数(m_scfcv_core.F90:1753, 1966)exit_check— 用户在工作目录创建.exit文件请求退出- MPI 全局通信 — 任一进程要求退出(
xmpi_sum(quit_sum,...))
典型输出消息(在 m_common.F90 第 565-763 行)
At SCF step 6 vres2 = 4.56E-09 < tolvrs= 1.00E-08 =>converged.
At SCF step 8, etot is converged :
for the second time, diff in etot= 2.34E-09 < toldfe= 1.00E-08
scprqt: WARNING -
nstep= 100 was not enough SCF cycles to converge;
maximum residual= 3.45E-07 exceeds tolwfr= 1.00E-08
SCF 循环流程图(Mermaid)
flowchart TD
Start([START: scfcv_core<br/>读 nstep, 初始化 tolwfr/tolvrs/toldfe...]) --> LoopHead{istep = 1 .. nstep}
LoopHead --> Init["初始化(istep==1 或原子移动)<br/>对称化原子坐标 / 倒空间数据 / PAW 初始化"]
Init --> SetVtr["<b>setvtr</b><br/>构造试探势<br/>vtrial = Vpsp + Vxc + VHartree"]
SetVtr --> Vtorho[/"<b>vtorho</b>(核心波函数步)<br/>优化波函数 / 求本征值 / 求占据数 / 求 rhor<br/>→ 输出 cg, eigen, residm, res2, rhor"/]
Vtorho --> IscfBranch{iscf 模式?}
%% 密度混合分支
IscfBranch -- "iscf >= 10<br/>(密度混合)" --> EtotforA["<b>etotfor</b><br/>算总能 → deltae / 算力 → diffor, maxfor"]
EtotforA --> ScprqtA["<b>scprqt</b> (choice=2)<br/>检查 tolwfr/toldfe/tolvrs/toldff/tolrff"]
ScprqtA --> QuitA{quit == 1 ?}
QuitA -- "是 (收敛)" --> AfterLoop
QuitA -- "否" --> NewRho["<b>newrho</b><br/>密度混合 (Anderson/Pulay/CG...)"]
NewRho --> RhotovA["<b>rhotov</b><br/>由新密度算新势 → vxc, vhartr, vtrial, res2"]
RhotovA --> StepCheck
%% 势混合分支
IscfBranch -- "iscf < 10<br/>(势混合)" --> RhotovB["<b>rhotov</b><br/>由新密度算新势 → vxc, vhartr, vresidnew, res2"]
RhotovB --> EtotforB["<b>etotfor</b><br/>算总能 / 算力"]
EtotforB --> ScprqtB["<b>scprqt</b> (choice=2)<br/>检查收敛判据"]
ScprqtB --> QuitB{quit == 1 ?}
QuitB -- "是 (收敛)" --> AfterLoop
QuitB -- "否" --> NewVtr["<b>newvtr</b><br/>势混合"]
NewVtr --> StepCheck
%% 步数检查
StepCheck{istep == nstep ?}
StepCheck -- "是" --> AfterLoop
StepCheck -- "否" --> LoopHead
AfterLoop["循环后处理<br/><b>scprqt</b> (choice=3) 打印收敛状态<br/>设 conv_retcode (0=收敛 / 1=未收敛)"]
AfterLoop --> EndNode([END])
classDef coreStep fill:#fde68a,stroke:#b45309,stroke-width:2px,color:#000;
classDef decision fill:#bfdbfe,stroke:#1d4ed8,color:#000;
classDef terminal fill:#d1fae5,stroke:#047857,color:#000;
class Vtorho,SetVtr,NewRho,NewVtr,RhotovA,RhotovB,EtotforA,EtotforB,ScprqtA,ScprqtB coreStep;
class IscfBranch,QuitA,QuitB,StepCheck,LoopHead decision;
class Start,EndNode,AfterLoop terminal;
图例说明
- 黄色块:SCF 循环内的核心计算子程序
- 蓝色块:分支/判断节点
- 绿色块:起止/收敛后处理
关键路径速记
- 密度混合 (
iscf >= 10):vtorho → etotfor → scprqt → newrho → rhotov - 势混合 (
iscf < 10):vtorho → rhotov → etotfor → scprqt → newvtr - 退出循环:
scprqt设quit=1,或istep == nstep
关键文件汇总表
| 文件路径 | 模块 | 关键子程序 |
|---|---|---|
src/94_scfcv/m_scfcv.F90 | m_scfcv | scfcv_init, scfcv_destroy, scfcv_run |
src/94_scfcv/m_scfcv_core.F90 | m_scfcv_core | scfcv_core(主驱动) |
src/79_seqpar_mpi/m_vtorho.F90 | m_vtorho | vtorho(波函数优化) |
src/67_common/m_rhotov.F90 | m_rhotov | rhotov(密度→势) |
src/68_rsprc/m_newrho.F90 | m_newrho | newrho(密度混合) |
src/68_rsprc/m_newvtr.F90 | m_newvtr | newvtr(势混合) |
src/67_common/m_common.F90 | m_common | scprqt(收敛判定) |
src/67_common/m_setvtr.F90 | m_setvtr | setvtr(构造试探势) |
src/67_common/m_etotfor.F90 | m_etotfor | etotfor(总能+力) |
src/94_scfcv/m_outscfcv.F90 | m_outscfcv | outscfcv(输出) |
src/94_scfcv/m_afterscfloop.F90 | m_afterscfloop | afterscfloop(后处理) |
一句话总览
Abinit 的 SCF 收敛由
scprqt(位于src/67_common/m_common.F90)根据用户设的tolwfr/toldfe/tolvrs/toldff/tolrff之一判定;主循环scfcv_core(src/94_scfcv/m_scfcv_core.F90)按setvtr → vtorho → etotfor → scprqt → newrho/newvtr → rhotov的步骤反复迭代,直到quit=1或达到nstep。**
References
Gonze, Xavier, et al. "The Abinit Project: Impact, Environment and Recent Developments." Computer Physics Communications, vol. 248, 2020, p. 107042. link
Pulay, Peter. "Convergence Acceleration of Iterative Sequences. The Case of SCF Iteration." Chemical Physics Letters, vol. 73, no. 2, 1980, pp. 393–398. link
The Abinit Code. Version 10.4.7, 2024. link