课程摘要
++本节衔接体积---能量分析,区分电子自洽、基组与k点采样收敛,学习以能量、应力及最终物性共同判断数值可靠性。通过可运行的教学记录回放,识别首次通过与进一步确认的区别,比较8条和9条预算下的不同状态,并练习处理自洽失败、指标缺失和条件不一致。理解小应变下的误差放大,建立有阈值、有预算、有停止条件的检查计划,为下一节弹性常数计算做好准备。++
一、课程导入:曲线很光滑,为什么结果仍可能不可靠?
上一节,我们从构造的能量---体积数据中找回了160 GPa的体积模量。
但只把中心能量增加1 meV,中心差分结果就变成了约139.492 GPa。
这说明一个重要问题:
材料参数可能来自能量或应力的导数,小的点间误差可能被明显放大。
因此,本节不再只问"计算有没有结束",而要进一步问:
当前数值精度,是否足够支撑我们想得到的力学结论?
完成本节后,你应能够:
- 区分SCF、基组和k点收敛;
- 在固定条件下比较能量与应力变化;
- 识别首次通过的候选设置;
- 制定有限的计算预算;
- 在证据不足时,明确报告尚未完成的检查。
本节不需要安装ABACUS。配套程序只回放构造的教学记录,不提交真实计算任务。
二、三种收敛,是三道不同的检查门
| 检查对象 | 改变什么 | 通过说明什么 | 不能说明什么 |
|---|---|---|---|
| SCF电子自洽 | 电子密度及相关变量 | 当前结构与设置下满足自洽要求 | 基组、k点和物性已经可靠 |
| 基组与数值网格 | 截断能、轨道或积分相关设置 | 目标结果对相应数值表示足够稳定 | 倒空间采样已经足够 |
| k点采样 | 倒空间采样密度与方案 | 目标结果对采样加密足够稳定 | 模型近似正确、所有应变状态均可靠 |
可以用拍照作一个不严格的类比:
SCF像把当前照片对好焦;基组与数值网格像检查分辨能力;k点则检查周期体系倒空间积分的采样是否充分。
但真正做计算时,必须分别检查,不能用一个"完成"标签代替全部判断。
插图一:收敛检查的层级与停止条件

图中是教学检查逻辑。SCF需要在每一次作业中检查,而不是整个流程只检查一次。
2.1 达到迭代上限,不等于达到自洽要求
例如,程序执行了规定的最大电子迭代次数后结束,不代表已经满足收敛判据。
本节继续锁定ABACUS v3.8.5文档解释参数:
scf_nmax控制电子迭代次数上限;scf_thr涉及密度相关的收敛要求。
不能把后者直接理解成跨版本、跨基组通用的"总能量误差是多少eV"。官方参数说明
出现SCF振荡时,也不应只无限增加迭代次数。应先检查结构、电子态、占据和数值设置,再根据诊断考虑混合方法及相关参数。金属的展宽设置同样需要与研究目标保持一致,不能只为了让程序结束而随意改变。官方SCF收敛说明
2.2 基组收敛不等于"把一个参数调大"
在PW路径中,ecutwfc与平面波截断有关,单位是Ry。
LCAO路径还涉及有限的局域轨道基组及其他数值设置。仅提高ecutwfc,不能自动消除局域轨道基组的全部误差。ABACUS参数说明
本节练习固定为PW教学情境,不将结论直接推广到所有LCAO任务。
2.3 k点不是原子,也不是有限元单元
\(4\times4\times4\)描述的是一种倒空间采样网格:
- 不表示64个原子;
- 不表示64个有限元单元;
- 也不保证实际使用64个不可约k点。
比较时应保持网格类型、偏移和相关约定一致。不同晶胞不能机械照搬同样的三个整数。官方KPT说明
三、先冻结比较条件,才能解释数值变化
假设你同时进行了以下修改:
提高截断能
加密k点
更换赝势
改变晶格常数
调整展宽
随后能量发生变化。
这时,能否说变化来自截断能?
不能,因为多个条件同时变化,已经失去单变量解释的基础。
本节采用以下顺序:
固定结构与物理模型
↓
固定k点等条件,扫描截断能
↓
识别候选,进一步加密检查
↓
暂时固定较严格的截断能,扫描k点
↓
回查最终组合设置与目标物性
比较时,还应保持或明确记录:
- 组成、原子数与结构;
- 赝势、泛函、磁态和占据约定;
- 软件版本与基组路径;
- 能量定义与归一化;
- SCF要求;
- 应力的单位、分量和符号。
如果使用每原子能量:
\ e_i=\\frac{E_i}{N}, \\
相邻变化为:
\ \\Delta e_i=\|e_i-e_{i-1}\|. \\
这里的 \(N\) 是这一固定结构比较中保持一致的原子数。
除以原子数,并不能让不同组成或不同物理约定自动变得可比。
另外,顺序筛查只是起点。在粗k点下看起来足够的截断能,在最终更密的k点下仍可能需要回查。
四、判据应该跟着目标物性走
4.1 本节使用两个教学指标
第一个指标是相邻每原子能量差:
\ \\Delta e_i\^{\\mathrm{meV/atom}} = 1000\|e_i-e_{i-1}\|. \\
第二个指标是一个应力分量的变化:
\ \\Delta s_i = \|\\sigma_{xx,i}-\\sigma_{xx,i-1}\|. \\
课堂要求两项同时满足:
\ \\Delta e_i\\leq2\\ \\mathrm{meV/atom}, \\\ \\Delta s_i\\leq0.05\\ \\mathrm{GPa}. \\
这些数值只是为了练习决策逻辑,不是ABACUS或任何材料的推荐精度。
代码只检查一个应力分量。真实弹性计算需要检查相关分量,必要时采用全张量指标,并直接检查最终弹性常数。
4.2 相邻变化小,不等于精确误差小
本节计算的是两个设置之间的变化,不是相对精确解的误差。
两个点可能共同受到系统偏差影响;k点加密的结果也未必单调变化。
因此:
\ \\text{相邻变化很小} \\neq \\text{已经知道严格误差上界}. \\
本节采用"连续两次相邻加密均通过"作为教学确认规则。它比首次通过更谨慎,但不是通用标准,更不是物理正确性的证明。
五、实战一:从截断能序列识别候选设置
沿用原课程目录中的五个教学点,再增加70 Ry作为进一步检查。
所有数据均为人为构造,不对应真实元素或ABACUS输出。
固定 \(4\times4\times4\) 网格:
| 截断能/Ry | 能量/(eV/atom) | \(\sigma_{xx}\)/GPa |
|---|---|---|
| 20 | -10.0000 | 2.000 |
| 30 | -10.1000 | 0.600 |
| 40 | -10.1200 | 0.160 |
| 50 | -10.1230 | 0.100 |
| 60 | -10.1234 | 0.090 |
| 70 | -10.1235 | 0.088 |
5.1 50 Ry为什么没有通过?
相对40 Ry:
\ \\Delta e = 1000\|-10.1230+10.1200\| = 3\\ \\mathrm{meV/atom}, \\\ \\Delta s = \|0.100-0.160\| = 0.060\\ \\mathrm{GPa}. \\
两项都超出了教学阈值。
5.2 60 Ry为什么只是候选?
相对50 Ry:
\ \\Delta e=0.4\\ \\mathrm{meV/atom}, \\\ \\Delta s=0.010\\ \\mathrm{GPa}. \\
两项首次同时通过,所以60 Ry是候选设置。
但按照本节规则,还需要进一步加密检查。
5.3 70 Ry提供了什么证据?
相对60 Ry:
\ \\Delta e=0.1\\ \\mathrm{meV/atom}, \\\ \\Delta s=0.002\\ \\mathrm{GPa}. \\
再次通过,满足本节的两次连续规则。
为了后续直接复用已有记录,本节暂时固定70 Ry检查k点。这不是证明70 Ry成本最优,也不是向所有材料推荐70 Ry。
插图二:能量与应力的相邻变化

图由配套程序实际回放结果绘制。纵轴为对数坐标,展示相邻设置的变化,不是相对精确解的误差。
六、实战二:截断能检查完成,k点检查还没有
固定70 Ry,使用以下教学记录:
| k点网格 | 能量/(eV/atom) | \(\sigma_{xx}\)/GPa |
|---|---|---|
| \(4\times4\times4\) | -10.1235 | 0.088 |
| \(6\times6\times6\) | -10.1265 | 0.120 |
| \(8\times8\times8\) | -10.1275 | 0.130 |
| \(10\times10\times10\) | -10.1277 | 0.133 |
第一行直接复用前一阶段70 Ry的记录,不额外计算一次。
结果为:
- 从 \(4^3\) 到 \(6^3\):能量变化3 meV/atom,没有通过;
- 从 \(6^3\) 到 \(8^3\):能量变化1 meV/atom,应力变化0.010 GPa,首次通过;
- 从 \(8^3\) 到 \(10^3\):能量变化0.2 meV/atom,应力变化0.003 GPa,再次通过。
现在加入一个约束:
最多允许8条作业记录。
前面的截断能检查已经使用6条记录,只剩两条用于 \(6^3\) 和 \(8^3\)。
这时,k点只有一次通过,缺少后续确认。
正确状态应该是:
NOT_CONVERGED_WITHIN_BUDGET
它表示:
"在这份计划和预算内,尚未完成规定的确认。"
不表示材料不存在收敛设置,也不等于已经证明结果错误。
七、配套程序:实际运行与预期输出
7.1 代码放在哪里?
"""Replay synthetic convergence records under a job-count budget; no ABACUS calls."""
import argparse
import copy
import json
import math
from pathlib import Path
def teaching_records():
# shortcut: scalar sigma_xx only; a real elastic workflow must check relevant tensor components.
values = [(20, 4, -10.0, 2.0), (30, 4, -10.1, 0.6),
(40, 4, -10.12, 0.16), (50, 4, -10.123, 0.10),
(60, 4, -10.1234, 0.09), (70, 4, -10.1235, 0.088),
(70, 6, -10.1265, 0.12), (70, 8, -10.1275, 0.13),
(70, 10, -10.1277, 0.133)]
return [dict(stage="cutoff" if i < 6 else "kpoints", ecut_Ry=c, kmesh=k,
energy_eV_atom=e, sigma_xx_GPa=s, scf_ok=True,
context="FIXED_PW_TEACHING_CONTEXT")
for i, (c, k, e, s) in enumerate(values)]
def finite(x):
return type(x) in (int, float) and math.isfinite(x)
def within(value, limit):
return value <= limit or math.isclose(value, limit, rel_tol=1e-10, abs_tol=1e-10)
def replay(budget=8, records=None, energy_tol=2.0, stress_tol=0.05):
if type(budget) is not int or budget < 0:
raise ValueError("budget must be a non-negative integer")
if any(not finite(t) or t <= 0 for t in (energy_tol, stress_tol)):
raise ValueError("Tolerances must be positive finite numbers")
records = teaching_records() if records is None else records
result = dict(source="SYNTHETIC_CONVERGENCE", ABACUS_run=False,
physical_verified=False, final_property_verified=False,
budget=budget, used=0, energy_tol_meV_atom=energy_tol,
stress_tol_GPa=stress_tol, cutoff_confirmed=False,
kpoints_confirmed=False, audit=[])
streak = dict(cutoff=0, kpoints=0)
previous = None
def finish(status, reason):
result.update(status=status, reason=reason)
return result
for record in records:
if result["used"] >= budget:
return finish("NOT_CONVERGED_WITHIN_BUDGET", "No budget for the next confirmation record")
if record.get("stage") == "kpoints" and not result["cutoff_confirmed"]:
return finish("INSUFFICIENT_CONFIRMATION_DATA", "Confirm cutoff before k-point refinement")
result["used"] += 1
stage = record.get("stage")
row = dict(job=result["used"], stage=stage, ecut_Ry=record.get("ecut_Ry"),
kmesh=record.get("kmesh"), state="PENDING")
result["audit"].append(row)
if type(record.get("scf_ok")) is not bool:
row["state"] = "INVALID_SCF_FLAG"
return finish("STOP_INVALID_SCF_FLAG", "SCF status must be an explicit boolean")
if not record["scf_ok"]:
row["state"] = "SCF_FAILED"
return finish("STOP_SCF_FAILED", "Do not use unconverged energy in refinement comparisons")
metrics = (record.get("energy_eV_atom"), record.get("sigma_xx_GPa"))
if any(x is None for x in metrics):
row["state"] = "MISSING_METRIC"
return finish("STOP_MISSING_METRIC", "Missing data is not zero")
if not all(finite(x) for x in metrics):
row["state"] = "INVALID_METRIC"
return finish("STOP_INVALID_METRIC", "Metrics must be finite numbers")
valid = (stage in streak and record.get("context") == "FIXED_PW_TEACHING_CONTEXT"
and finite(record.get("ecut_Ry")) and record["ecut_Ry"] > 0
and type(record.get("kmesh")) is int and record["kmesh"] > 0)
if previous is None:
valid = valid and stage == "cutoff"
elif stage == "cutoff":
valid = (valid and previous["stage"] == "cutoff"
and record["kmesh"] == previous["kmesh"]
and record["ecut_Ry"] > previous["ecut_Ry"])
else:
valid = (valid and record["ecut_Ry"] == previous["ecut_Ry"]
and record["kmesh"] > previous["kmesh"])
if not valid:
row["state"] = "PROTOCOL_MISMATCH"
return finish("STOP_PROTOCOL_MISMATCH", "Only the active refinement variable may change")
row.update(energy_eV_atom=metrics[0], sigma_xx_GPa=metrics[1])
if previous is None:
row["state"] = "BASELINE"
else:
de = abs(metrics[0] - previous["energy_eV_atom"]) * 1000
ds = abs(metrics[1] - previous["sigma_xx_GPa"])
passed = within(de, energy_tol) and within(ds, stress_tol)
streak[stage] = streak[stage] + 1 if passed else 0
row.update(dE_meV_atom=de, dSigma_GPa=ds, passed=passed,
streak=streak[stage], state="PASS" if passed else "FAIL")
result["cutoff_confirmed" if stage == "cutoff" else "kpoints_confirmed"] = streak[stage] >= 2
previous = record
if result["cutoff_confirmed"] and result["kpoints_confirmed"]:
return finish("TEACHING_RULES_PASS", "Both sequential refinement checks passed twice; not a physics certificate")
status = "NOT_CONVERGED_WITHIN_BUDGET" if result["used"] >= budget else "INSUFFICIENT_CONFIRMATION_DATA"
return finish(status, "Further refinement evidence is still needed")
def self_test():
assert replay(8)["status"] == "NOT_CONVERGED_WITHIN_BUDGET"
assert replay(8)["cutoff_confirmed"] and not replay(8)["kpoints_confirmed"]
assert replay(9)["status"] == "TEACHING_RULES_PASS"
assert replay(5)["used"] == 5 and not replay(5)["cutoff_confirmed"]
assert replay(0)["used"] == 0
cases = [("scf_ok", False, "STOP_SCF_FAILED"),
("sigma_xx_GPa", None, "STOP_MISSING_METRIC"),
("energy_eV_atom", float("nan"), "STOP_INVALID_METRIC"),
("scf_ok", "true", "STOP_INVALID_SCF_FLAG"),
("kmesh", 6, "STOP_PROTOCOL_MISMATCH")]
for key, value, status in cases:
records = teaching_records()
records[1][key] = value
before = copy.deepcopy(records)
outcome = replay(9, records)
assert outcome["status"] == status and outcome["used"] == 2
assert repr(records) == repr(before)
assert within(2.0, 2.0) and not within(2.001, 2.0)
assert all(not replay(b)["physical_verified"] for b in (0, 5, 8, 9))
for options in (dict(budget=True), dict(budget=-1), dict(energy_tol=0),
dict(stress_tol=float("inf"))):
try:
replay(**options)
except ValueError:
pass
else:
raise AssertionError("Invalid argument accepted")
print("SELF_TEST=PASS (budgets, confirmation, 5 failure cases, input guards)")
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--budget", type=int, default=8)
parser.add_argument("--out", type=Path, default=Path("lesson61_run"))
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
return
if args.out.exists():
parser.error("Output path exists; choose a new --out directory")
try:
result = replay(args.budget)
except ValueError as exc:
parser.error(str(exc))
for row in result["audit"]:
prefix = f"#{row['job']} {row['stage']} ecut={row['ecut_Ry']} Ry k={row['kmesh']}^3"
if "passed" in row:
print(f"{prefix}: dE={row['dE_meV_atom']:.3f} meV/atom; "
f"dSigma={row['dSigma_GPa']:.3f} GPa; {row['state']} streak={row['streak']}/2")
else:
print(f"{prefix}: {row['state']}")
print(f"cutoff_confirmed={result['cutoff_confirmed']}; kpoints_confirmed={result['kpoints_confirmed']}")
print(f"STATUS={result['status']}; used={result['used']}/{result['budget']}")
print("MODE=SYNTHETIC_CONVERGENCE; ABACUS_run=False; final_property_verified=False")
args.out.mkdir(parents=True, exist_ok=False)
(args.out / "report.json").write_text(json.dumps(result, indent=2, allow_nan=False), encoding="utf-8")
print(f"SAVED={args.out / 'report.json'}")
if __name__ == "__main__":
main()
将lesson61_convergence.py保存到自己的课程文件夹,在该文件夹打开终端即可。
它是独立脚本,不需要插入之前的代码。核心只使用Python标准库,完整代码也已收录在下载讲义附录中。
程序回放内置教学记录,不会:
- 运行ABACUS;
- 自动解析真实SCF日志;
- 提交HPC作业;
- 测量实际计算时间或费用。
其中的SCF状态也是预设的教学布尔值,不是真实求解器证据。
7.2 先运行自测
python lesson61_convergence.py --self-test
实际输出:
SELF_TEST=PASS (budgets, confirmation, 5 failure cases, input guards)
测试包括预算控制、确认逻辑、自洽失败、指标缺失、非有限数和比较条件变化等。
7.3 使用8条记录预算
python lesson61_convergence.py --budget 8 --out lesson61_run_8
实际输出:
#1 cutoff ecut=20 Ry k=4^3: BASELINE
#2 cutoff ecut=30 Ry k=4^3: dE=100.000 meV/atom; dSigma=1.400 GPa; FAIL streak=0/2
#3 cutoff ecut=40 Ry k=4^3: dE=20.000 meV/atom; dSigma=0.440 GPa; FAIL streak=0/2
#4 cutoff ecut=50 Ry k=4^3: dE=3.000 meV/atom; dSigma=0.060 GPa; FAIL streak=0/2
#5 cutoff ecut=60 Ry k=4^3: dE=0.400 meV/atom; dSigma=0.010 GPa; PASS streak=1/2
#6 cutoff ecut=70 Ry k=4^3: dE=0.100 meV/atom; dSigma=0.002 GPa; PASS streak=2/2
#7 kpoints ecut=70 Ry k=6^3: dE=3.000 meV/atom; dSigma=0.032 GPa; FAIL streak=0/2
#8 kpoints ecut=70 Ry k=8^3: dE=1.000 meV/atom; dSigma=0.010 GPa; PASS streak=1/2
cutoff_confirmed=True; kpoints_confirmed=False
STATUS=NOT_CONVERGED_WITHIN_BUDGET; used=8/8
MODE=SYNTHETIC_CONVERGENCE; ABACUS_run=False; final_property_verified=False
SAVED=lesson61_run_8\report.json
解释几个字段:
BASELINE:第一条记录,没有前一个设置可以比较;streak:当前连续通过次数,失败会归零;cutoff_confirmed=True:满足本节截断能确认规则;kpoints_confirmed=False:k点确认尚未完成;final_property_verified=False:没有验证最终物性。
k=4^3只是输出中的网格简写,不是一个波矢的数值。
另外,脚本正常退出只表示回放和保存完成,不能据此宣布数值检查通过。后续自动化应读取JSON中的状态字段。
7.4 独立比较9条预算情形
python lesson61_convergence.py --budget 9 --out lesson61_run_9
前8条相同,新增和改变的结果为:
#9 kpoints ecut=70 Ry k=10^3: dE=0.200 meV/atom; dSigma=0.003 GPa; PASS streak=2/2
cutoff_confirmed=True; kpoints_confirmed=True
STATUS=TEACHING_RULES_PASS; used=9/9
MODE=SYNTHETIC_CONVERGENCE; ABACUS_run=False; final_property_verified=False
SAVED=lesson61_run_9\report.json
TEACHING_RULES_PASS仅表示构造记录通过了本节规则。
它不是实际材料的数值收敛证明,也不是最终弹性常数通过。
插图三:8条与9条预算的对照

格子表示记录计数,不表示每个任务的运行时间相同。
真实增加计算预算需要获得授权,不能由自动化系统自行扩额。重复练习时也应更换输出目录,程序不会覆盖已有结果。
八、误差预算:为什么应力只差一点,弹性常数可能差很多?
下一节将从应变---应力关系提取弹性常数。先看一个误差放大的例子。
采用正负应变计算斜率:
\ C\\approx \\frac{\\sigma(+\\varepsilon)-\\sigma(-\\varepsilon)} {2\\varepsilon}. \\
如果两端应力的绝对误差都不超过 \(\eta\),最坏情况下:
\ \|\\delta C\| \\leq \\frac{\\eta+\\eta}{2\\varepsilon} = \\frac{\\eta}{\\varepsilon}. \\
取:
\ \\eta=0.01\\ \\mathrm{GPa}, \\qquad \\varepsilon=0.001, \\
则:
\ \|\\delta C\|\\leq10\\ \\mathrm{GPa}. \\
如果希望在同一简化误差模型下将它控制到1 GPa,需要:
\ \\eta\\leq0.001\\ \\mathrm{GPa}. \\
这里有两个重要限制:
第一,\(\eta\)被假设为实际应力误差的上界;相邻设置差不是自动成立的误差上界。
第二,本节0.05 GPa教学阈值没有按上述1 GPa弹性目标设计,不能直接拿它承诺实际精度。
所以,真正的验收应直接检查:
- 最终弹性常数在更严格设置下是否稳定;
- 代表性正负应变状态是否足够收敛;
- 不同体积或剪切状态是否需要额外检查。
只在平衡结构一个点上检查能量,不足以覆盖全部材料计算。
数值收敛也不能消除交换关联近似、赝势适用性或选错磁态等模型问题。
九、给自动化系统一张有限、清楚的计划
一份真实计划至少应包含:
| 项目 | 需要说明的内容 |
|---|---|
| 目标物性 | 总能量差、体积模量、\(C_{44}\)或其他量 |
| 固定条件 | 结构、赝势、泛函、磁态、单位与能量定义 |
| 加密顺序 | 初筛、进一步确认、k点检查、组合回查 |
| 验收要求 | 指标、阈值及最终物性检查 |
| 资源边界 | 最大尝试数、单作业时间、资源数量和总预算 |
| 停止与交接 | 失败、缺失或超预算时保留哪些记录 |
举一个资源算术示例:
若最多8个顺序作业,每个最多15分钟,固定使用8个CPU核,则运行时间合计上限为2小时,对应16核时。
这不包含排队时间,也不是真实成本预测。集群计费还要核对实际规则。
本节程序只实施记录数预算,不实施真实超时、资源配额或费用限制。
遇到异常,应该怎样报告?
| 情况 | 本节状态 | 原则 |
|---|---|---|
| SCF未通过 | STOP_SCF_FAILED |
不使用未自洽能量进行有效比较 |
| 缺少应力 | STOP_MISSING_METRIC |
缺失不等于零 |
| 出现NaN或无穷大 | STOP_INVALID_METRIC |
检查数据来源 |
| 比较条件不一致 | STOP_PROTOCOL_MISMATCH |
不把多变量变化归因于一个参数 |
| 预算达到且缺少确认 | NOT_CONVERGED_WITHIN_BUDGET |
停止并说明未完成项 |
失败尝试也消耗资源,不能从统计中删除。
同样,不能为了得到"通过"而放宽阈值、重置计数或隐藏失败记录。
十、本节练习与参考答案
练习一:原始20---60 Ry五点数据中,将能量阈值收紧到0.2 meV/atom,有通过者吗?
没有。
60 Ry的相邻能量变化仍为0.4 meV/atom,不能在缺少进一步证据时直接宣布通过。
练习二:9条回放通过后,可以发布最终 \(C_{44}\) 吗?
不能。
尚未运行真实电子结构计算,也没有检查最终组合设置、剪切应变状态和 \(C_{44}\) 本身。
练习三:8条预算一定不够吗?
不是,取决于预先制定的计划。
如果已有合理依据,可以预先省去20 Ry点,从30 Ry开始,用5条截断能记录和3条新增k点记录完成本节规则。
但是,已经实际消耗的20 Ry尝试不能事后从成本中抹掉。
练习四:失败点能否直接跳过,继续比较?
不能默认这样做。
应先诊断原因,确认比较条件。失败作业不能当成有效物性点,也不能从资源统计中消失。
练习五:本节应该交付什么?
建议交付:
- 一份固定条件记录;
- 一张收敛检查图;
- 一份预算与停止计划;
- 一份明确写出未完成项的状态报告。
这些内容,比给出一个所谓"万能截断能"更能说明精度依据。
十一、小结与下一节安排
本节的核心可以归纳为五句话:
- SCF完成、基组收敛与k点收敛不是同一件事。
- 先确定目标物性,再制定相应的数值要求。
- 首次通过得到候选,加密检查提供进一步证据。
- 相邻差不是严格误差界,顺序筛查也需要组合回查。
- 预算不足时可以诚实停下,不能把未完成包装成可靠。
