Skip to content

Commit 557c7cd

Browse files
committed
recover the neb.py example
1 parent 481eeef commit 557c7cd

File tree

1 file changed

+111
-0
lines changed
  • python/ase-plugin/examples

1 file changed

+111
-0
lines changed

python/ase-plugin/examples/neb.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
'''
2+
PbTiO3 ferroelectric inversion energy barrier
3+
4+
Learn how to use the NEB module in ASE, please refer to the online manual at:
5+
https://ase-lib.org/examples_generated/tutorials/neb_idpp.html
6+
'''
7+
from pathlib import Path
8+
here = Path(__file__).parent
9+
10+
import numpy as np
11+
from ase.io import Trajectory
12+
from ase.atoms import Atoms
13+
from ase.optimize import FIRE
14+
from ase.mep import NEB
15+
import matplotlib.pyplot as plt
16+
from abacuslite import Abacus, AbacusProfile
17+
18+
pporb = here.parent.parent.parent / 'tests' / 'PP_ORB'
19+
20+
elem = ['Ti', 'Pb', 'O', 'O', 'O']
21+
taud = np.array([
22+
[0.5, 0.5, 0.5948316037314115],
23+
[0.0, 0.0, 0.1235879499999999],
24+
[0.0, 0.5, 0.5094847864489368],
25+
[0.5, 0.0, 0.5094847864489368],
26+
[0.5, 0.5, 0.0088672395150394],
27+
])
28+
cell = np.array([
29+
[3.8795519, 0.0000000, 0.00000000],
30+
[0.0000000, 3.8795519, 0.00000000],
31+
[0.0000000, 0.0000000, 4.28588762],
32+
])
33+
34+
# we have relaxed with the parameters above :)
35+
up = Atoms(elem, cell=cell, scaled_positions=taud)
36+
37+
# get the polarisation inversed by inversing the Ti atoms
38+
taud = np.array([
39+
[0.5, 0.5, 0.6508136593687969],
40+
[0.0, 0.0, 0.1235879499999999],
41+
[0.0, 0.5, 0.7348401327639794],
42+
[0.5, 0.0, 0.7348401327639794],
43+
[0.5, 0.5, 0.2364165087650052],
44+
])
45+
dw = Atoms(elem, cell=cell, scaled_positions=taud)
46+
47+
aprof = AbacusProfile(
48+
command='mpirun -np 8 abacus_2p',
49+
pseudo_dir=pporb,
50+
orbital_dir=pporb,
51+
omp_num_threads=1
52+
)
53+
pseudopotentials = {
54+
'Ti': 'Ti_ONCV_PBE-1.0.upf',
55+
'Pb': 'Pb_ONCV_PBE-1.0.upf',
56+
'O' : 'O_ONCV_PBE-1.0.upf',
57+
}
58+
basissets = {
59+
'Ti': 'Ti_gga_8au_100Ry_4s2p2d1f.orb',
60+
'Pb': 'Pb_gga_7au_100Ry_2s2p2d1f.orb',
61+
'O' : 'O_gga_7au_100Ry_2s2p1d.orb',
62+
}
63+
inp = {
64+
'profile': aprof,
65+
'pseudopotentials': pseudopotentials,
66+
'basissets': basissets,
67+
'inp': {
68+
'basis_type': 'lcao',
69+
'symmetry': 1,
70+
'kspacing': 0.25, # Oops!
71+
'init_chg': 'auto',
72+
'cal_force': 1,
73+
}
74+
}
75+
76+
n_replica = 7 # the ini and fin images included. 7 is acceptable for production
77+
replica = []
78+
for irep in range(n_replica):
79+
image = up.copy() if irep <= (n_replica // 2) else dw.copy()
80+
# attach the calculator to each image, so that we can run the optimization
81+
image.calc = Abacus(**inp, directory=here / f'neb-{irep}')
82+
replica.append(image)
83+
84+
neb = NEB(replica,
85+
k=0.05, # too high value is hard to converge
86+
climb=False, # use True in production run, though CI-NEB is harder to converge
87+
parallel=True)
88+
neb.interpolate('idpp')
89+
90+
qn = FIRE(neb, trajectory=here / 'neb.traj')
91+
qn.run(fmax=0.05)
92+
93+
energies = []
94+
# get the energy profile along the reaction path
95+
with Trajectory(here / 'neb.traj') as traj:
96+
replica = traj[-7:] # the last NEB frames
97+
for i, rep in enumerate(replica):
98+
rep: Atoms # type hint
99+
# the energies of the initial and the final state
100+
# are not calculated, here we calculate them
101+
rep.calc = Abacus(**inp, directory=here / f'neb-{i}')
102+
energies.append(rep.get_potential_energy())
103+
104+
energies = np.array(energies)
105+
# plot the energy profile
106+
plt.plot(energies - energies[0], 'o-')
107+
plt.xlabel('NEB image index')
108+
plt.ylabel('Total energies (eV)')
109+
plt.title('Energy profile along the reaction path')
110+
plt.savefig(here / 'energy_profile.png', dpi=300)
111+
plt.close()

0 commit comments

Comments
 (0)