Abinit SCF 计算:收敛标准与代码流程详解

May 19, 2026
Published in 计算物理

Abstract

本文总结了Abinit当中SCF计算的收敛标准,以及代码运行的详细流程。

Keywords: Abinit, DFT, SCF, 收敛判据, tolvrs, 密度混合

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,子程序 scprqtchoice = 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 if

toldff 判据(连续 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 if

tolrff 判据(连续 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 if

tolvrs 判据(一次性满足,最常用)

! 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_core94_scfcv/m_scfcv_core.F90:263SCF 主驱动控制整个循环
setvtr67_common/m_setvtr.F90由密度构造试探势vtrial = vpsp + vxc + vhartr
vtorho79_seqpar_mpi/m_vtorho.F90从势求新密度(含本征态求解)cg, eigen, residm, res2, rhor
etotfor67_common/m_etotfor.F90计算总能量与原子受力etotal, deltae, diffor, maxfor, fcart
rhotov67_common/m_rhotov.F90从密度算新势vxc, vhartr, vtrial, res2
newrho68_rsprc/m_newrho.F90密度混合新的 rhor
newvtr68_rsprc/m_newvtr.F90势混合新的 vtrial
scprqt67_common/m_common.F90:183收敛判定与打印quit, conv_retcode

关键变量含义(收敛监控相关)

变量名含义计算位置
residm全部 k 点/能带的最大波函数残差m_vtorho.F90:2078residm = max(residm, maxval(resid))
res2密度或势残差的平方范数m_vtorho.F90:2221(密度混合)或 m_rhotov.F90(势混合)
deltae总能量差 E(n) − E(n−1)etotfor
diffor原子受力的最大变化量etotfor
maxfor当前最大力 `maxF_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 触发,可能来自:

  1. 满足某个 tol* 判据scprqt 设置)— 正常收敛
  2. istep == nstep — 达到最大步数(m_scfcv_core.F90:1753, 1966
  3. exit_check — 用户在工作目录创建 .exit 文件请求退出
  4. 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
  • 退出循环:scprqtquit=1,或 istep == nstep

关键文件汇总表

文件路径模块关键子程序
src/94_scfcv/m_scfcv.F90m_scfcvscfcv_init, scfcv_destroy, scfcv_run
src/94_scfcv/m_scfcv_core.F90m_scfcv_corescfcv_core(主驱动)
src/79_seqpar_mpi/m_vtorho.F90m_vtorhovtorho(波函数优化)
src/67_common/m_rhotov.F90m_rhotovrhotov(密度→势)
src/68_rsprc/m_newrho.F90m_newrhonewrho(密度混合)
src/68_rsprc/m_newvtr.F90m_newvtrnewvtr(势混合)
src/67_common/m_common.F90m_commonscprqt(收敛判定)
src/67_common/m_setvtr.F90m_setvtrsetvtr(构造试探势)
src/67_common/m_etotfor.F90m_etotforetotfor(总能+力)
src/94_scfcv/m_outscfcv.F90m_outscfcvoutscfcv(输出)
src/94_scfcv/m_afterscfloop.F90m_afterscfloopafterscfloop(后处理)

一句话总览

Abinit 的 SCF 收敛scprqt(位于 src/67_common/m_common.F90)根据用户设的 tolwfr/toldfe/tolvrs/toldff/tolrff 之一判定;主循环 scfcv_coresrc/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