|
本帖最后由 jiyy 于 2023-1-28 17:48 编辑
ASE 是一个用来构建模型、进行可视化以及后处理分析的Python工具包。 ABACUS 提供了相应的接口(https://gitlab.com/1041176461/ase-abacus),使 ASE 可以对 ABACUS 的输入输出进行分析,并调用 ABACUS 为Calculator进行计算。
本贴主要用于记录我用过的一些方法 (欢迎补充!!!)
1. 文件处理
之前 HongriTianqi 已经介绍了如何把cif文件转换为STRU文件 (详见:怎样把cif文件转换为STRU文件?)。我们也可以采用相同的方式读取ABACUS的running_*log文件,只需要修改format参数为"abacus-out"即可,例如:
- from ase.io import read
- atoms = read("running_scf.log", format='abacus-out')
复制代码 这个方法对于分析MD结果有比较大的帮助(详见:https://gitlab.com/1041176461/ase-abacus/-/issues/3),接口还支持读取MD续算后的running_md.log
2. 能带计算
(1)调用ABACUS calculator做SCF计算,输出电荷密度:
- from ase.calculators.abacus import Abacus, AbacusProfile
- from ase.build import bulk
- Si = bulk('Si')
- pp = {'Si':'Si_ONCV_PBE-1.0.upf'}
- pseudo_dir = r'/home/jiyy/potential/SG15/SG15_upf'
- basis_dir = r'/home/jiyy/GD_orb/dpsi-T-S'
- basis = {'Si':'dpsi_Si.dat'}
- kpts = {'size': [6, 6, 6], 'gamma': True}
- parameters = {
- 'xc': 'pbe',
- 'ecutwfc': 100,
- 'smearing_method': 'gaussian',
- 'smearing_sigma': 0.01,
- 'basis_type': 'lcao',
- 'ks_solver': 'genelpa',
- 'mixing_type': 'pulay',
- 'scf_thr': 1e-8,
- 'out_chg': 1,
- 'calculation': 'scf',
- }
- profile = AbacusProfile(argv=['mpirun', '-n', '8', 'abacus'])
- calc = Abacus(profile=profile, pp=pp, pseudo_dir=pseudo_dir, basis=basis, basis_dir=basis_dir, kpts=kpts, **parameters)
- Si.calc = calc
- Si.get_potential_energy()
复制代码 (2)获取SCF计算得到的Fermi能级,并生成高对称路径
- fermi_level = calc.get_fermi_level() # 读取Fermi能级
- kpath = Si.cell.bandpath(npoints=100) # 生成高对称路径,总共100个k点
复制代码 (3)调用ABACUS calculator做NSCF
- parameters.update({'calculation': 'nscf', 'init_chg': 'file', 'out_chg': 0, 'out_band': 1}) # 更新参数做能带计算
复制代码 (4)画能带
- bs = BandStructure(path=kpath, energies=energies, reference=fermi_level) # 传入高对称路径,本征值,费米能
- bsp = bs.subtract_reference() # 减去费米能
- bsp.plot(emin=-6, emax=6, filename='band.png') # 画图
复制代码
3. 构建分子模型
ABACUS做分子计算需要人为构建真空层,接口提供了两种方法来构建真空层
(1)atoms.center(vacuum=None, axis=(0, 1, 2), about=None)
这个方法可以将atoms放置于Cell的中心位置,用户可以指定任意x, y, z方向上的真空层大小
- from ase.build import molecule
复制代码 由该方法得到的STRU如下:
- ATOMIC_SPECIES
- H 1.008 H_ONCV_PBE-1.0.upf
- NUMERICAL_ORBITAL
- dpsi_H.dat
- LATTICE_CONSTANT
- 1.8897261258369282
- LATTICE_VECTORS
- 30.000000000 0.0000000000 0.0000000000
- 0.0000000000 30.000000000 0.0000000000
- 0.0000000000 0.0000000000 30.737166000
- ATOMIC_POSITIONS
- Direct
- H
- 0.0000000000
- 2
- 0.5000000000 0.5000000000 0.5119910000 1 1 1
- 0.5000000000 0.5000000000 0.4880090000 1 1 1
复制代码 (2)atoms.set_cell(cell, scale_atoms=False, apply_constraint=True)
这个方法相当于直接在STRU文件中修改LATTICE_VECTORS。
得到的分子可能会处于Cell的边界,此时HR/SR矩阵会分配到不同的cells,而不是集中在(0, 0, 0) cell,但并不影响基于HR/SR矩阵得到的计算结果。
由该方法得到的STRU如下:
- ATOMIC_SPECIES
- H 1.008 H_ONCV_PBE-1.0.upf
- NUMERICAL_ORBITAL
- dpsi_H.dat
- LATTICE_CONSTANT
- 1.8897261258369282
- LATTICE_VECTORS
- 30.000000000 0.0000000000 0.0000000000
- 0.0000000000 30.000000000 0.0000000000
- 0.0000000000 0.0000000000 30.000000000
- ATOMIC_POSITIONS
- Direct
- H
- 0.0000000000
- 2
- 0.5000000000 0.5000000000 0.5245720000 1 1 1
- 0.5000000000 0.5000000000 0.5000000000 1 1 1
复制代码
4. 基组的Delta测试
假设有C的SZ,DZP,TZDP,QZTP基组,用接口可以计算彼此之间的Delta值
- import json
- from pathlib import Path
- from ase.collections import dcdft
- from ase.calculators.abacus import Abacus, AbacusProfile
- from ase.io import Trajectory, read
- from ase.eos import EquationOfState as EOS
- from ase.units import kJ
- from ase.utils.deltacodesdft import delta
- # 计算七个能量点,并保存至traj文件
- def cal_EOS(symbol, parameters, labels):
- for label, orb in labels.items():
- traj = Trajectory(f'{symbol}-{label}.traj', 'w')
- if label == 'PW':
- parameters.update({
- 'basis_type': 'pw',
- 'ks_solver': 'cg',
- })
- else:
- basis_dir = f"/home/jiyy/Orb/Gen/C/Orbital_C_{label}"
- basis = {symbol: orb}
- parameters.update({
- 'basis_type': 'lcao',
- 'ks_solver': 'genelpa',
- 'basis': basis,
- 'basis_dir': basis_dir
- })
- for s in range(94, 108, 2):
- atoms = dcdft[symbol]
- atoms.set_cell(atoms.cell * (s / 100)**(1 / 3), scale_atoms=True)
- atoms.calc = Abacus(profile=profile, directory=f'{symbol}-{label}',
- scaled=False, **parameters)
- atoms.get_potential_energy()
- traj.write(atoms)
- #读取traj文件,用Birch-Murnaghan公式拟合体积模量
- def fit(symbol, label):
- V = []
- E = []
- for atoms in read(f'{symbol}-{label}.traj@:'):
- V.append(atoms.get_volume() / len(atoms))
- E.append(atoms.get_potential_energy() / len(atoms))
- eos = EOS(V, E, 'birchmurnaghan')
- eos.fit(warn=False)
- e0, B, Bp, v0 = eos.eos_parameters
- return e0, v0, B, Bp
- # 将基组结果和Wien2K数据保存到json文件
- def save_json(symbol):
- data = {f'{symbol}': {}}
- labels = []
- for path in Path().glob('*.traj'):
- filename = path.stem
- symbol, label = filename.split('-')
- labels.append(label)
- e0, v0, B, Bp = fit(symbol, label)
- sub_data = {f'{label}': {
- 'volume': v0,
- 'B': B * 1e24 / kJ,
- 'Bp': Bp
- }}
- data[symbol].update(sub_data)
- data[symbol]['wien2k'] = {
- 'volume': dcdft.data[symbol]['wien2k_volume'],
- 'B': dcdft.data[symbol]['wien2k_B'],
- 'Bp': dcdft.data[symbol]['wien2k_Bp'],
- }
- with open(f'{symbol}.json', 'w') as fp:
- json.dump(data, fp)
- def get_tuple(data, label):
- return (data[label]['volume'], data[label]['B'], data[label]['Bp'])
- if __name__ == "__main__":
- import sys
- xc = sys.argv[1]
- mpi = sys.argv[2]
- omp = sys.argv[3]
- profile = AbacusProfile(
- argv=['mpirun', '-env', f'OMP_NUM_THREADS={omp}', '-n', f'{mpi}', '/home/jiyy/software/ABACUS/abacus-develop-2.3.5/bin/abacus'])
- symbol = 'C'
- pp = {"C": "C_ONCV_PBE-1.0.upf"}
- pseudo_dir = "/home/jiyy/PP/SG15"
- kpts = [8, 8, 8]
- parameters = {
- 'xc': f'{xc}',
- 'ecutwfc': 100,
- 'smearing_method': 'gaussian',
- 'smearing_sigma': 0.01,
- 'mixing_type': 'pulay',
- 'scf_thr': 1e-8,
- 'out_chg': 1,
- 'kpts': kpts,
- 'pp': pp,
- 'pseudo_dir': pseudo_dir,
- }
- labels = {'PW': '',
- 'Z': 'C_gga_8au_100Ry_1s1p.orb',
- 'DZP': 'C_gga_8au_100Ry_2s2p1d.orb',
- 'TZDP': 'C_gga_8au_100Ry_3s3p2d.orb',
- 'QZTP': 'C_gga_8au_100Ry_4s4p3d.orb',
- }
- cal_EOS(symbol, parameters, labels)
- save_json(symbol)
- # 计算彼此delta值
- with open(f'{symbol}.json', 'r') as fp:
- data = json.load(fp)[symbol]
- pw = get_tuple(data, 'PW')
- wien2k = get_tuple(data, 'wien2k')
- z = get_tuple(data, 'Z')
- dzp = get_tuple(data, 'DZP')
- tzdp = get_tuple(data, 'TZDP')
- qztp = get_tuple(data, 'QZTP')
- delta_data = {
- 'pw-wien2k': delta(*pw, *wien2k),
- 'z-pw': delta(*z, *pw),
- 'dzp-pw': delta(*dzp, *pw),
- 'tzdp': delta(*tzdp, *pw),
- 'qztp': delta(*qztp, *pw)
- }
- with open(f'delta-{symbol}.json', 'w') as fp:
- json.dump(delta_data, fp)
复制代码 delta-C.json:
- {"pw-wien2k": 0.3519292445820627, "z-pw": 6.826961630421406, "dzp-pw": 0.0590395574697385, "tzdp": 0.026290147268529143, "qztp": 0.04396233617693006}
复制代码
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|