atomate 使用¶
约 1526 个字 365 行代码 预计阅读时间 10 分钟
介绍¶
-
官网:atomate (Materials Science Workflows) — atomate 1.0.3 documentation
-
高通量计算(主要 VASP)工具;主要在队列系统(如 Slurm、PBS 等)上运行;自动生成、保存任务运行过程中的所有记录(输入文件、输出文件、数据提取、错误信息等)
-
数据存储于数据库(MongoDB)中,易于获取、查询、分析
-
提供了许多性质计算(静态、弛豫、弹性常数、能带、EOS、体模量、NEB)的标准 workflow,只需提供晶体结构(POSCAR),即可进行高通量计算;标准的 workflow 可以进行自定义修改
-
可自定义设计新的性质计算 workflow
-
少量计算还是手动计算速度更快
firetask 细节会在提交后生成的 *submit*
文本文件中查看
custodian 默认的纠错次数上限为 5
atomate workflow 的自定义设计代码主要由 FireWorks 包控制
输入参数形成的输入文件代码主要由 pymatgen 包控制
输出文件中的数据提取、绘图及其他高级分析主要由 pymatgen 包控制
Workflow,Firework(Firework 的列表可称做 fireworks),Firetask(一个 Firework 由若干个基本的 Firetask 组成)
使用¶
lpad¶
- 管理 launchpad
# lpad 参数
-i # ID
-s # 状态;有 READY/WAITING/COMPLETED/FIZZLED/RUNNING
# DEFUSED 该 firework 不运行
-m # max
-t # 以表格形式列出 workflow 中 firework 的状态
-d # all 会显示 firework 之间的层级关系
# count 统计数目
# ids 统计 id
# more 输出中的 _exception 字段会显示 custodian 的相关 warning 或报错
# 查看 fireworks 报告
lpad report
# 重新计算 fireworks
lpad rerun_fws -i 3
lpad rerun_fws -s FIZZLED
# 查看 fireworks
lpad get_fws
lpad get_fws -i 3
lpad get_fws -s FIZZLED
lpad get_fws -s FIZZLED -m 5
lpad get_fws -s FIZZLED -d more
# 查看 workflow (所属 fireworks 及其计算目录)
lpad get_wflows
lpad get_wflows -i 1
lpad get_wflows -s FIZZLED -d more
# -t 参数需安装 prettytable 包
lpad get_wflows -s FIZZLED -t -m 5
# 查看 fireworks 的计算目录
lpad get_launchdir fw_id
# 其他子命令
pause_fws # 暂停单个 Firework
resume_fws # 恢复系列 Fireworks
defuse_wflows # cancel (de-fuse) 整个 Workflow
reignite_wflows # reignite (un-cancel) 整个 Workflow
archive_wflows # 存档(soft-remove) 整个 Workflow
delete_wflows # 永远删除
# 以下两个命令不推荐使用
# 重设lpad,所有 lpad 中的 fireworks 都会被删除
lpad reset
# 初始化,一般不用?
lpad init
qlaunch¶
-
将 workflow 提交到超算队列
- 过程:先创建
block_<date>/launcher_<date>
workflow 目录(qlaunch rapidfire
命令;qlaunch singleshot
无此步骤),之后生成FW_submit.script
Slurm 提交脚本,再在此目录下创建<launcher_date>
firework 计算目录
- 过程:先创建
-
qlaunch rapidfire
若出现以下提示时,不会再提交作业
qlaunch (-r) rapidfire # 一次提交多个作业
qlaunch rapidfire --nlaunches 5 # 指定提交作业数
qlaunch singleshot # 一次提交一个作业
rlaunch¶
- 直接在计算平台本地上运行计算
- 高通量正确计算完成时,custodian.json 文件无纠错
使用 tips¶
-
用 Python 脚本生成 workflows 的 fireworks 后,需要用 qlaunch 相关命令将 fireworks 提交到队列系统中,对于只有一个 firework 的 workflows(如弛豫和静态计算),若共生成了N 个 fireworks,
qlaunch rapidfire --nlaunches N
即可(体系较小时,N 可缩减成 N/2 等) -
对于有多个 fireworks(如 M 个)的 workflows(如弹性常数计算),可以先提前了解这些多个 fireworks 之间的逻辑关系,若共有N 个 workflows,可先
qlaunch rapidfire --nlaunches N
,N 个中有部分 fireworks(如 X 个)计算完成后,可适当再qlaunch rapidfire --nlaunches X*(M-1)
,进行该 workflow 其余部分 fireworks 的计算,一定程度上可以控制计算成本(虽然可能需要时不时查看 fireworks 的计算完成情况) -
不建议直接
qlaunch rapidfire
(只要作业未结束,生成其他的 workflow,会自动到队列中等待,计算目录容易混淆) -
atomate 无法在只将 workflow 产生后就能看到输入文件,需让其实际运行才能看到;做法:核数设为 1;运行后待输入文件产生,将 Jobid 删除,检查输入文件参数
案例¶
静态计算¶
- Python 代码示例
from atomate.common.powerups import add_namefile, add_tags
from atomate.vasp.workflows.presets.core import wf_static
from fireworks.core.launchpad import LaunchPad
from pymatgen.core.structure import Structure
structure = Structure.from_file("POSCAR")
wf = wf_static(structure)
wf = add_namefile(wf)
wf = add_tags(wf, {"task_name": "atomate static workflow test"})
lpad = LaunchPad.auto_load()
lpad.add_wf(wf)
print("The static test workflow is added.")
弛豫计算¶
- Python 代码示例
from atomate.common.powerups import add_namefile, add_tags
from atomate.vasp.workflows.presets.core import wf_structure_optimization
from fireworks.core.launchpad import LaunchPad
from pymatgen.core.structure import Structure
structure = Structure.from_file("POSCAR")
wf = wf_structure_optimization(structure)
wf = add_namefile(wf)
wf = add_tags(wf, {"task_name": "atomate relaxation workflow test"})
lpad = LaunchPad.auto_load()
lpad.add_wf(wf)
print("The relaxation test workflow is added.")
弹性常数计算¶
- Python 代码示例
from atomate.common.powerups import add_namefile, add_tags
from atomate.vasp.workflows.presets.core import wf_elastic_constant
from fireworks.core.launchpad import LaunchPad
from pymatgen.core.structure import Structure
structure = Structure.from_file("POSCAR")
wf = wf_elastic_constant(structure=structure)
wf = add_namefile(wf)
wf = add_tags(wf, {"task_name": "atomate elastic constant workflow test"})
lpad = LaunchPad.auto_load()
lpad.add_wf(wf)
print("The elastic constant test workflow is added.")
-
atomate 中计算弹性常数使用的是应力 - 应变法;先结构优化,再施加变形并 ISIF=2 弛豫 (用到的是 StaticSetOne.yaml 文件中的参数),最后拟合弹性常数并计算弹性性质
-
弹性常数计算 workflow 的
fw.name
Ni-elastic structure optimization--78
Ni-elastic deformation 0--77
...
Ni-elastic deformation 5--72
Analyze Elastic Data--71
-
运行弹性常数计算 workflow 时,若部分变形的 firework 计算结束,部分 fizzled,它会先根据已计算的变形 firework 的数据进行弹性常数拟合,因此需检查该 workflow 中的所有 firework 是否都计算完成并检验结果是否合理
-
atomate 计算弹性常数得到的弹性张量中 POSCAR-format (raw) 与 IEEE-format (ieee_format) 之间的区别:
- Elastic Constants - Materials Project Documentation
- 有时相同,有时不同(存在旋转关系),可使用
pymatgen.core.tensors.Tensor
类的get_ieee_rotation()
方法进行转换 - 建议采用 POSCAR-format
# 弹性常数计算 workflow 程序实现涉及的文件路径
# wf_elastic_constant()
atomate/vasp/workflows/presets/core.py
# get_wf_elastic_constant()
atomate/vasp/workflows/base/elastic.py
# ElasticTensorToDb 类;含弹性常数拟合细节
# 自定义弹性数据保存到 db 中的 collection 的名称:修改 "elasticity" 即可,即 db.db["elasticity"]
atomate/vasp/firetasks/parse_outputs.py
- 弹性常数计算 workflow 默认参数设置
# 计算 2 阶弹性常数参数设置(默认)
# 第一步弛豫,其余参数由 MPRelaxSet 控制
{"ENCUT": 700, "EDIFF": 1e-6, "LAECHG": False, "LREAL": False}
# 变形部分,ISIF = 2 弛豫,其余参数由 MPStaticSet 控制,如 ENCUT=500
{"ISIF": 2, "IBRION": 2, "NSW": 99, "ISTART": 1}
kpts_settings = {"grid_density": 7000}
stencils = None
# 计算 3 阶弹性常数
Kpoints.automatic_density(structure, 40000, force_gamma=True)
stencils = np.linspace(-0.075, 0.075, 7)
# wf_elastic_constant_minimal() 设置
stencil = np.arange(0.01, 0.01 * order, step=0.01)
# wf_elastic() 会调用 get_wf_elastic_constant()
# get_wf_elastic_constant() 源代码
# Convert to conventional if specified
if conventional:
structure = SpacegroupAnalyzer(structure).get_conventional_standard_structure()
uis_elastic = {"IBRION": 2, "NSW": 99, "ISIF": 2, "ISTART": 1}
vis = vasp_input_set or MPStaticSet(structure, user_incar_settings=uis_elastic)
strains = []
if strain_states is None:
strain_states = get_default_strain_states(order)
if stencils is None:
# 应变范围为 -10% ~ 10%,间隔 5%
stencils = [np.linspace(-0.01, 0.01, 5 + (order - 2) * 2)] * len(strain_states)
if np.array(stencils).ndim == 1:
stencils = [stencils] * len(strain_states)
for state, stencil in zip(strain_states, stencils):
strains.extend([Strain.from_voigt(s * np.array(state)) for s in stencil])
计算数据获取¶
使用 MongoDB Compass 连接数据库¶
-
连接数据库:New connection - Advanced Connection Options
- General: Connection String Scheme 选择 mongodb;填写 Host
- Authentication: Authentication Method 选择 Username/Password;填写 Username、Password 和 Database,Authentication Mechanism 选择 Default
-
修改连接的 connection 名称:"New Connection" 有编辑选项
MongoDB Compass 使用¶
-
新版 MongoDB Compass 可以修改一个页面下的 Document 条数(25-100)
-
MongoDB 中存储的每条数据称为 document,具体数据值通过字段查询(即 dict 中的 key 和 value)
-
在 MongoDB Compass 软件中通过字段筛选 document,字段间通过
.
连接,示例
使用 atomate 连接 MongoDB 数据库并筛选、获取数据¶
连接数据库¶
import os
from atomate.vasp.database import VaspCalcDb
from monty.serialization import dumpfn, loadfn
# 方式 1 直接变量赋值
db_json_path = ...
# 方式 2 将 db.json 放入 ~/.{bash,zsh}rc 文件中
db_json_path = os.getenv("DB_JSON_PATH")
atomate_db = VaspCalcDb.from_db_file(db_json_path)
# 弹性数据分析 colletion
elasticity_collection = atomate_db.db["elasticity"]
# 吉布斯计算任务 collection
gibbs_collection = atomate_db.db["gibbs_tasks"]
筛选、获取数据¶
-
可用 Projection Operators:Query and Projection Operators - MongoDB Manual v7.0
# find() 可以使用 Projection Operators(以 $ 开头)
query = {"task_label": "volume relaxation"}
query = {"task_id": {"$gt": 18, "$lt": 44}}
query = {"tags.solute": {"$in": solute_list}}
query = {"completed_at": {"$regex": "2022-08-05 *"}}
# 0: 不提取数据;1: 提取数据
projection = {
"_id": 0,
"dir_name": 1,
"task_id": 1,
"completed_at": 1,
"state": 1,
"task_label": 1,
"run_stats": 1,
"input": 1,
"output": 1,
"tags": 1,
}
# 统计满足筛选条件的 documents 数目
# 方式 1
count = atomate_db.collection.count_documents(query)
# 方式 2
count = atomate_db.collection.aggregate([{"$match": query}, {"$count": "total"}])
# 方式 3 不行?
count = db.collection.find(query).count()
# 获取满足 query projection 条件的所有 documents
documents = atomate_db.collection.find(query, projection)
# 获取一条 document
document = atomate_db.collection.find_one(query, projection)
# 对 document 进行排序;sort() 参数为 query 中的 key
documents = atomate_db.collection.find(query, projection).sort(...)
# 从 elasticity_collection 筛选数据
documnets_elasticity = elasticity_collection.find(query)
# 将获取的 documents dump 至 json 文件
dumpfn(list(documents), "documents.json")
# 导入 json 数据文件
documents_list = loadfn(input_data_fn)
for document in documents_list:
# 从 dict 获取的 value 直接就是 Structure object
structure: Structure = document["input"]["structure"]
# 不支持该写法 document["output.energy"]
energy = document["output"]["energy"]
- document 常用数据
# 输入构型
input_structure = document["input"]["structure"]
# 输出构型
output_structure = document["output"]["structure"]
# 能量
energy = document["output"]["energy"]
energy_pa = document["output"]["energy_per_atom"]
# 计算耗时
document["run_stats"]["overall"]["Elapsed time (sec)"]
document["run_stats"]["overall"]["Total CPU time used (sec)"]
# 每个 firework 计算目录路径;需通过简单的正则表达式处理
dir_name = document["dir_name"]
calc_path = (re.search("/dssg.*", dir_name)).group()
# add_tags() 中添加的一些 tag
document["tags"]["XXX"]
# 以下数据可对 Structure 进行操作获取
# 原子数
natoms = document["nsites"]
# 元素数
nelements = document["nelements"]
# 构型体积
volume = document["output"]["structure"]["lattice"]["volume"]
# 平均原子体积
volume_pa = volume / natoms
常见 workflow 的 document keys¶
- 弛豫 wf
dict_keys(
[
"_id",
"dir_name",
"analysis",
"calcs_reversed",
"chemsys",
"completed_at",
"composition_reduced",
"composition_unit_cell",
"custodian",
"elements",
"formula_anonymous",
"formula_pretty",
"formula_reduced_abc",
"input",
"last_updated",
"nelements",
"nsites",
"orig_inputs",
"output",
"run_stats",
"schema",
"state",
"tags",
"task_id",
"task_label",
"transformations",
]
)
calcs_reversed
key 下的 keys (需添加[0]
;含大部分同级下的 keys)
dict_keys(
[
"vasp_version",
"has_vasp_completed",
"nsites",
"elements",
"nelements",
"run_type",
"input",
"output",
"formula_pretty",
"composition_reduced",
"composition_unit_cell",
"formula_anonymous",
"formula_reduced_abc",
"dir_name",
"completed_at",
"task",
"output_file_paths",
"bader",
]
)
- 弹性常数计算 wf 会生成弹性性质分析
elasticity
collection
dict_keys(
[
"_id",
"analysis",
"initial_structure",
"optimized_structure",
"tags",
"fitting_data",
"elastic_tensor",
"derived_properties",
"formula_pretty",
"fitting_method",
"order",
]
)
- 吉布斯自由能计算 wf 会生成
gibbs_tasks
collection
dict_keys(
[
"_id",
"metadata",
"structure",
"formula_pretty",
"energies",
"volumes",
"pressure",
"poisson",
"mass",
"natoms",
"bulk_modulus",
"gibbs_free_energy",
"temperatures",
"optimum_volumes",
"debye_temperature",
"gruneisen_parameter",
"thermal_conductivity",
"anharmonic_contribution",
"success",
]
)
相关问题¶
-
注:随着 atomate 及其依赖 package 版本的更新,以下问题可能会被解决
-
KSPACING 参数和 KPOINTS 文件:atomate 中的
wf_structure_optimization()
和wf_static()
函数中的源代码中的MPStaticSet()
或MPRelaxSet()
没有设置user_kpoints_settings
参数,因此在使用add_modify_incar
时添加 KSPCAING 和 KGAMMA 参数时,可不生成 KPOINTS 文件。而wf_elastic_constant()
函数有设置,因此都会生成 KPOINTS 文件,KSPACING 设置无效果;可注释掉user_kpoints_settings
参数,使 KSPACING 重新起效果(在pymatgen/io/vasp/sets.py
VASPInputSets
中有相关代码及注释,第 264 行) -
Master 服务器上
db.json
文件中的 Host 写法:Host 只能写数字的形式,超算上可以写字符串的形式(在 MongoDB Compass 填写的 Host 也需对应的形式)
- MongoDB 数据库连接失败(数据库服务未启动;XXX 指 Host)
# 报错情况 1
getaddrinfo ENOTFOUND XXX
# 报错情况 2
Connection failed: XXXX: [Errno 111] Connection refused, Timeout: 30s, Topology Description:
atomate/vasp/workflows/base/elastic.py
中的第 145 行代码内容出错
wf_elastic.append_wf(
# 应为 Workflow.from_firework
Workflow.from_Firework(fw_analysis), wf_elastic.leaf_fw_ids
)
- INCAR 参数设置
MAGMOM=None
出现报错
/XXX/atomate/vasp/firetasks/run_calc.py:150: FutureWarning: ScanMetalHandler is deprecated; use KspacingMetalHandler in custodian.vasp.handlers instead.
ScanMetalHandler was deprecated on 2023-11-03 and will be removed in a future release. Use KspacingMetalHandler instead.
ScanMetalHandler(),
Error reading item
/XXX/custodian/vasp/handlers.py:714: UserWarning: Looks like you made a typo in the INCAR. Please double- check it.
warnings.warn("Looks like you made a typo in the INCAR. Please double-check it.", UserWarning)
ERROR:custodian.custodian:VaspErrorHandler
- INCAR 参数设置
LCHARG=False
出现报错(atomate/vasp/drones.py
中的相关函数会使用 CHGCAR 文件获取相关信息,建议输出该文件)
2025-08-09 11:52:31,137 ERROR atomate.vasp.drones Traceback (most recent call last):
File "/XXX/atomate/vasp/drones.py", line 270, in generate_doc
d["calcs_reversed"] = [
^
- 部分 workflow 有 VASP 计算过程,但无法将计算数据保存到 MongoDB 中(个人理解)
- 参考:Check returncode to raise CustodianError() leading some trouble · Issue #41 · materialsproject/custodian · GitHub
- 源代码修改:将
custodian/custodian.py
中Custodian
类的__init__
方法terminate_on_nonzero_returncode
参数值改成False