dpdata
dpdata是一个用于处理计算科学软件数据格式的Python包,包括DeePMD-kit、VASP、LAMMPS、GROMACS和Gaussian。 dpdata仅适用于Python 3.7及以上版本。
安装
可以通过以下命令下载dpdata的源代码:
git clone https://github.com/deepmodeling/dpdata.git dpdata
然后使用pip
从源代码安装模块:
cd dpdata
pip install .
也可以直接通过pip安装dpdata
,无需下载源代码:
pip install dpdata
快速入门
本节提供一些dpdata使用示例。首先需要在Python 3.x兼容的代码中导入模块。
import dpdata
dpdata
的典型工作流程为:
- 从VASP、LAMMPS或DeePMD-kit数据文件加载数据。
- 操作数据
- 将数据以所需格式导出
加载数据
d_poscar = dpdata.System("POSCAR", fmt="vasp/poscar")
或者让dpdata根据文件名扩展名推断文件格式(vasp/poscar
)
d_poscar = dpdata.System("my.POSCAR")
从POSCAR
加载原子数量、原子类型和坐标,并存储到名为d_poscar
的数据System
中。
数据System
(deepmd-kit使用的概念)包含具有相同数量和类型原子的帧。在一个System
中,原子的顺序在所有帧中应保持一致。
需要注意的是,POSCAR
仅包含一帧。
如果需要多帧数据,例如存储在OUTCAR
中的数据,可以使用:
d_outcar = dpdata.LabeledSystem("OUTCAR")
OUTCAR
中提供的标签,即能量、力和应力(如果有)由LabeledSystem
加载。需要注意的是,原子的力始终被假定存在。LabeledSystem
是System
的派生类。
System
或LabeledSystem
可以从以下文件格式构建,表中的格式关键字
作为fmt
参数传递:
软件 | 格式 | 多帧 | 已标记 | 类别 | 格式键 |
---|---|---|---|---|---|
vasp | poscar | 否 | 否 | System | 'vasp/poscar' |
vasp | outcar | 是 | 是 | LabeledSystem | 'vasp/outcar' |
vasp | xml | 是 | 是 | LabeledSystem | 'vasp/xml' |
lammps | lmp | 否 | 否 | System | 'lammps/lmp' |
lammps | dump | 是 | 否 | System | 'lammps/dump' |
deepmd | raw | 是 | 否 | System | 'deepmd/raw' |
deepmd | npy | 是 | 否 | System | 'deepmd/npy' |
deepmd | raw | 是 | 是 | LabeledSystem | 'deepmd/raw' |
deepmd | npy | 是 | 是 | LabeledSystem | 'deepmd/npy' |
deepmd | npy | 是 | 是 | MultiSystems | 'deepmd/npy/mixed' |
deepmd | npy | 是 | 否 | MultiSystems | 'deepmd/npy/mixed' |
gaussian | log | 否 | 是 | LabeledSystem | 'gaussian/log' |
gaussian | log | 是 | 是 | LabeledSystem | 'gaussian/md' |
siesta | output | 否 | 是 | LabeledSystem | 'siesta/output' |
siesta | aimd_output | 是 | 是 | LabeledSystem | 'siesta/aimd_output' |
cp2k(未来将弃用) | output | 否 | 是 | LabeledSystem | 'cp2k/output' |
cp2k(未来将弃用) | aimd_output | 是 | 是 | LabeledSystem | 'cp2k/aimd_output' |
cp2k(插件) | stdout | 否 | 是 | LabeledSystem | 'cp2kdata/e_f' |
cp2k(插件) | stdout | 是 | 是 | LabeledSystem | 'cp2kdata/md' |
QE | log | 否 | 是 | LabeledSystem | 'qe/pw/scf' |
QE | log | 是 | 否 | System | 'qe/cp/traj' |
QE | log | 是 | 是 | LabeledSystem | 'qe/cp/traj' |
Fhi-aims | output | 是 | 是 | LabeledSystem | 'fhi_aims/md' |
Fhi-aims | output | 否 | 是 | LabeledSystem | 'fhi_aims/scf' |
quip/gap | xyz | 是 | 是 | MultiSystems | 'quip/gap/xyz' |
PWmat | atom.config | 否 | 否 | System | 'pwmat/atom.config' |
PWmat | movement | 是 | 是 | LabeledSystem | 'pwmat/movement' |
PWmat | OUT.MLMD | 是 | 是 | LabeledSystem | 'pwmat/out.mlmd' |
Amber | multi | 是 | 是 | LabeledSystem | 'amber/md' |
Amber/sqm | sqm.out | 否 | 否 | System | 'sqm/out' |
Gromacs | gro | 是 | 否 | System | 'gromacs/gro' |
ABACUS | STRU | 否 | 否 | System | 'abacus/stru' |
ABACUS | STRU | 否 | 是 | LabeledSystem | 'abacus/scf' |
ABACUS | cif | 是 | 是 | LabeledSystem | 'abacus/md' |
ABACUS | STRU | 是 | 是 | LabeledSystem | 'abacus/relax' |
ase | structure | 是 | 是 | MultiSystems | 'ase/structure' |
DFTB+ | dftbplus | 否 | 是 | LabeledSystem | 'dftbplus' |
n2p2 | n2p2 | 是 | 是 | LabeledSystem | 'n2p2' |
dpdata.MultiSystems
类可以从包含多个不同系统文件的目录中读取数据,或从包含不同系统的单个 xyz 文件中读取数据。
使用 dpdata.MultiSystems.from_dir
从目录中读取,dpdata.MultiSystems
将递归遍历目录并找到所有具有特定文件名的文件。支持 dpdata.LabeledSystem
支持的所有文件格式。
使用 dpdata.MultiSystems.from_file
从单个文件中读取。单文件支持适用于 quip/gap/xyz
和 ase/structure
格式。
例如,对于 quip/gap xyz
文件,单个 .xyz 文件可能包含具有不同原子数量和原子类型的多个不同配置。
以下与 Class dpdata.MultiSystems
相关的命令可能有用。
# 加载数据
xyz_multi_systems = dpdata.MultiSystems.from_file(
file_name="tests/xyz/xyz_unittest.xyz", fmt="quip/gap/xyz"
)
vasp_multi_systems = dpdata.MultiSystems.from_dir(
dir_name="./mgal_outcar", file_name="OUTCAR", fmt="vasp/outcar"
)
# 使用通配符
vasp_multi_systems = dpdata.MultiSystems.from_dir(
dir_name="./mgal_outcar", file_name="*OUTCAR", fmt="vasp/outcar"
)
# 打印多系统信息
print(xyz_multi_systems)
print(xyz_multi_systems.systems) # 返回字典
# 打印系统信息
print(xyz_multi_systems.systems["B1C9"].data)
# 将系统数据导出到 ./my_work_dir/B1C9_raw 文件夹
xyz_multi_systems.systems["B1C9"].to_deepmd_raw("./my_work_dir/B1C9_raw")
# 导出所有系统
xyz_multi_systems.to_deepmd_raw("./my_deepmd_data/")
您也可以使用以下代码来解析多系统:
from dpdata import LabeledSystem, MultiSystems
from glob import glob
处理多个系统
```python
fs = glob("./*/OUTCAR") # 记得在这里修改!!!
ms = MultiSystems()
for f in fs:
try:
ls = LabeledSystem(f)
except:
print(f)
if len(ls) > 0:
ms.append(ls)
ms.to_deepmd_raw("deepmd")
ms.to_deepmd_npy("deepmd")
访问数据
存储在System
和LabeledSystem
中的这些属性可以通过操作符[]
加上属性的键来访问,例如
coords = d_outcar["coords"]
可用的属性如下(nframe: 系统中的帧数,natoms: 系统中的总原子数)
键 | 类型 | 维度 | 是否标签 | 描述 |
---|---|---|---|---|
'atom_names' | 字符串列表 | ntypes | 否 | 每种原子类型的名称 |
'atom_numbs' | 整数列表 | ntypes | 否 | 每种原子类型的原子数量 |
'atom_types' | np.ndarray | natoms | 否 | 为每个原子分配类型的数组 |
'cells' | np.ndarray | nframes x 3 x 3 | 否 | 每帧的晶胞张量 |
'coords' | np.ndarray | nframes x natoms x 3 | 否 | 原子坐标 |
'energies' | np.ndarray | nframes | 是 | 帧能量 |
'forces' | np.ndarray | nframes x natoms x 3 | 是 | 原子受力 |
'virials' | np.ndarray | nframes x 3 x 3 | 是 | 每帧的维里张量 |
导出数据
存储在System
或LabeledSystem
中的数据可以以'lammps/lmp'或'vasp/poscar'格式导出,例如:
d_outcar.to("lammps/lmp", "conf.lmp", frame_idx=0)
d_outcar
的第一帧将被导出到'conf.lmp'
d_outcar.to("vasp/poscar", "POSCAR", frame_idx=-1)
d_outcar
的最后一帧将被导出到'POSCAR'。
存储在LabeledSystem
中的数据可以导出为deepmd-kit原始格式,例如
d_outcar.to("deepmd/raw", "dpmd_raw")
或者一个更简单的命令:
dpdata.LabeledSystem("OUTCAR").to("deepmd/raw", "dpmd_raw")
可以通过以下方式实现帧选择
dpdata.LabeledSystem("OUTCAR").sub_system([0, -1]).to("deepmd/raw", "dpmd_raw")
这样只有第一帧和最后一帧会被导出到dpmd_raw
。
复制
dpdata将创建当前原子配置的超胞。
dpdata.System("./POSCAR").replicate(
(
1,
2,
3,
)
)
元组(1,2,3)表示在x方向不复制原子配置,在y方向复制2次,在z方向复制3次。
扰动
通过以下示例,原始系统(dpdata.System('./POSCAR')
)的每一帧都被扰动以生成三个新帧。对于每一帧,晶胞被扰动5%,原子位置被扰动0.6埃。atom_pert_style
表示对原子位置的扰动遵循正态分布。atom_pert_style
的其他可用选项有uniform
(在球内均匀分布)和const
(在球面上均匀分布)。
perturbed_system = dpdata.System("./POSCAR").perturb(
pert_num=3,
cell_pert_fraction=0.05,
atom_pert_distance=0.6,
atom_pert_style="normal",
)
print(perturbed_system.data)
替换
通过以下示例,系统中随机8个Hf原子将被Zr原子替换,原子位置保持不变。
s = dpdata.System("tests/poscars/POSCAR.P42nmc", fmt="vasp/poscar")
s.replace("Hf", "Zr", 8)
s.to_vasp_poscar("POSCAR.P42nmc.replace")
BondOrderSystem
dpdata中引入了一个新的类BondOrderSystem
,它继承自System
类。这个新类包含化学键和形式电荷的信息(存储在BondOrderSystem.data['bonds']
和BondOrderSystem.data['formal_charges']
中)。目前BondOrderSystem只能从.mol/.sdf格式读取,因为它依赖于rdkit(这意味着如果你想使用这个功能,必须安装rdkit)。其他格式,如pdb,必须转换为.mol/.sdf格式(可能需要使用open babel等软件)。
import dpdata
system_1 = dpdata.BondOrderSystem(
"tests/bond_order/CH3OH.mol", fmt="mol"
) # 从.mol文件读取
system_2 = dpdata.BondOrderSystem(
"tests/bond_order/methane.sdf", fmt="sdf"
) # 从.sdf文件读取
在sdf文件中,所有分子必须具有相同的拓扑结构(即相同分子构型的构象异构体)。
BondOrderSystem
还支持直接从rdkit.Chem.rdchem.Mol
对象初始化。
from rdkit import Chem
from rdkit.Chem import AllChem
import dpdata
mol = Chem.MolFromSmiles("CC")
mol = Chem.AddHs(mol)
AllChem.EmbedMultipleConfs(mol, 10)
system = dpdata.BondOrderSystem(rdkit_mol=mol)
键序分配
BondOrderSystem
实现了一个更加健壮的rdkit Mol净化程序,定义在dpdata.rdkit.santizie.Sanitizer
中。该类定义了三个级别的净化过程:低、中、高(默认为中级)。
- 低级:使用
rdkit.Chem.SanitizeMol()
函数来净化分子。 - 中级:在使用rdkit之前,程序会先为每个原子分配形式电荷,以避免不适当的价态异常。然而,这种模式要求给定分子中的键序信息正确无误。
- 高级:程序将尝试修复芳香杂环、磷酸盐、硫酸盐、羧基、硝基、亚硝基、胍基中不适当的键序。如果这个程序无法净化给定的分子,程序将尝试调用
obabel
来预处理分子并重复净化程序。也就是说,如果你想使用这个级别的净化,请确保环境中已安装obabel
。 根据我们的测试,我们的净化程序可以成功读取PDBBind精炼集中的4852个小分子。需要指出的是,在分子文件(mol/sdf)中,显式氢原子的数量必须正确。因此,我们建议使用obabel xxx -O xxx -h
来预处理文件。我们没有在dpdata中实现这个加氢程序的原因是我们无法保证其正确性。
import dpdata
for sdf_file in glob.glob("bond_order/refined-set-ligands/obabel/*sdf"):
syst = dpdata.BondOrderSystem(sdf_file, sanitize_level="high", verbose=False)
形式电荷分配
BondOrderSystem实现了一种基于8电子规则(见下文)为每个原子分配形式电荷的方法。请注意,它仅支持生物系统中的常见元素:B、C、N、O、P、S、As
import dpdata
syst = dpdata.BondOrderSystem("tests/bond_order/CH3NH3+.mol", fmt="mol")
print(syst.get_formal_charges()) # 返回每个原子的形式电荷
print(syst.get_charge()) # 返回系统的总电荷
如果检测到碳的价态为3,形式电荷将被分配为-1。因为在大多数情况下(炔基阴离子、异腈、环戊二烯基阴离子),三价碳上的形式电荷为-1,这也与8电子规则一致。
混合类型格式
deepmd/npy/mixed
格式是DeePMD-kit的混合类型numpy格式,可以通过dpdata.MultiSystems
类加载或导出。
在这种格式下,具有相同原子数量但不同分子式的系统可以被放在一起组成一个更大的系统,尤其是当系统中的帧数稀疏时。
这也有助于将类型信息混合在一起,用于带有类型嵌入网络的模型训练。
以下是使用deepmd/npy/mixed
格式的示例:
- 将MultiSystems导出到混合类型的numpy目录:
import dpdata
dpdata.MultiSystems(*systems).to_deepmd_npy_mixed("mixed_dir")
- 将混合类型数据加载到MultiSystems中:
import dpdata
dpdata.MultiSystems().load_systems_from_file("mixed_dir", fmt="deepmd/npy/mixed")
插件
可以参照一个简单的示例通过创建和安装插件来添加自己的格式。关键是要在pyproject.toml
中将Format类添加到entry_points['dpdata.plugins']
中:
[project.entry-points.'dpdata.plugins']
random = "dpdata_random:RandomFormat"