Skip to content

Commit 28be41b

Browse files
committed
added restart capabilities and changed the method run, to climb
1 parent 62c23f1 commit 28be41b

File tree

10 files changed

+110
-16
lines changed

10 files changed

+110
-16
lines changed

examples/XNO-H-XC_using_QE/saddleclimb/run_climb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@
4040
final=read('../final/opt.traj')
4141

4242
climber = SaddleClimb(init, final, calc)
43-
climber.run()
43+
climber.climb()
-64.4 KB
Binary file not shown.

examples/minimal_using_EMT/saddleclimb/climb.log renamed to examples/minimal_using_EMT/saddleclimb/no_restart/climb.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ Iteration Energy (eV) Fmax (eV/A)
1919
17 7.211764 0.026378
2020
18 7.211704 0.018304
2121
19 7.211657 0.009406
22+
Optimization complete!
1.34 MB
Binary file not shown.

examples/minimal_using_EMT/saddleclimb/run_climb.py renamed to examples/minimal_using_EMT/saddleclimb/no_restart/run_climb.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from ase.calculators.emt import EMT
55

66
calc = EMT()
7-
init=read('../init/opt.traj')
8-
final=read('../final/opt.traj')
7+
init=read('../../init/opt.traj')
8+
final=read('../../final/opt.traj')
99

1010
climber = SaddleClimb(init, final, calc)
11-
climber.run()
11+
climber.climb()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Iteration Energy (eV) Fmax (eV/A)
2+
0 7.162017 0.000888
3+
1 7.162922 0.030578
4+
2 7.16546 0.05738
5+
3 7.175275 0.157905
6+
4 7.205316 0.469773
7+
maxsteps reached, terminating!
8+
9+
Restarting:
10+
Iteration Energy (eV) Fmax (eV/A)
11+
5 7.23593 0.751324
12+
6 7.239443 0.729584
13+
7 7.232197 0.624944
14+
8 7.216657 0.178321
15+
9 7.21549 0.0771
16+
10 7.214951 0.08292
17+
11 7.213808 0.047538
18+
12 7.213432 0.037712
19+
13 7.213204 0.043334
20+
14 7.212673 0.049304
21+
15 7.211994 0.037834
22+
16 7.211815 0.027823
23+
17 7.211764 0.026378
24+
18 7.211704 0.018304
25+
19 7.211657 0.009406
26+
Optimization complete!
1.35 MB
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from ase import Atoms, Atom
2+
from ase.io import read
3+
from saddleclimb import SaddleClimb
4+
from ase.calculators.emt import EMT
5+
6+
calc = EMT()
7+
init=read('../../init/opt.traj')
8+
final=read('../../final/opt.traj')
9+
restarttraj = read('climb.traj')
10+
climber = SaddleClimb(init, final, calc)
11+
climber.restart_climb(restarttraj)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from ase import Atoms, Atom
2+
from ase.io import read
3+
from saddleclimb import SaddleClimb
4+
from ase.calculators.emt import EMT
5+
6+
calc = EMT()
7+
init=read('../../init/opt.traj')
8+
final=read('../../final/opt.traj')
9+
10+
climber = SaddleClimb(init, final, calc)
11+
climber.climb(maxsteps=4)

saddleclimb/saddleclimb.py

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(
3434
self.delta = delta0
3535
self.logfile = logfile
3636
self.trajfile = trajfile
37+
self._restart = False
3738
if not self.indices:
3839
self._get_moving_atoms()
3940
self.hessian = 100 * np.eye(3*len(self.indices))
@@ -118,7 +119,18 @@ def _initialize_atoms(self: None) -> tuple[Atoms, np.ndarray, np.ndarray]:
118119
B_init = self.hessian.copy()
119120
return atoms, idx, B_init
120121

121-
def _initialize_run(self: None, atoms: Atoms, idx: list) -> np.ndarray:
122+
def _initialize_atoms_restart(self: None) -> tuple[Atoms,
123+
np.ndarray,
124+
np.ndarray]:
125+
atoms = self._restart_trajectory.copy()
126+
constraints = self._restart_trajectory.constraints.copy()
127+
atoms.set_constraint(constraints)
128+
atoms.calc = copy.deepcopy(self.calculator)
129+
idx = self.indices.copy()
130+
B_init = self._restart_trajectory.info['saddleclimb_hessian'].copy()
131+
return atoms, idx, B_init
132+
133+
def _initialize_run(self: None, atoms: Atoms, idx: list):
122134
traj = Trajectory(self.trajfile, 'w')
123135
g_init = -self._get_F(atoms)[idx, :].reshape(-1)
124136
E_init = atoms.calc.results['energy']
@@ -128,15 +140,22 @@ def _initialize_run(self: None, atoms: Atoms, idx: list) -> np.ndarray:
128140
self._log(log_string)
129141
return traj, g_init, E_init
130142

143+
def _initialize_run_restart(self: None, idx: list):
144+
traj = Trajectory(self.trajfile, 'a')
145+
g_tot = -self._restart_trajectory.calc.results['forces']
146+
g = g_tot[idx, :].reshape(-1).copy()
147+
E = self._restart_trajectory.calc.results['energy'] + 0
148+
Fmax = np.max(np.abs(g))
149+
return traj, g, E, Fmax
150+
131151
def _get_initial_step(
132152
self: None, idx: list
133153
) -> tuple[np.ndarray, np.ndarray]:
134-
135154
self._pos_f_1D = self.atoms_final.positions[idx, :].reshape(-1)
136155
self._pos_i_1D = self.atoms_initial.positions[idx, :].reshape(-1)
137156
dx_1D = self.delta * self.normalize(self._pos_f_1D - self._pos_i_1D)
138-
dx_init = dx_1D.reshape(-1, 3)
139-
return dx_init
157+
dx = dx_1D.reshape(-1, 3)
158+
return dx, dx_1D
140159

141160
def _get_log_string(self, n, E, Fmax):
142161
n_str = str(n).ljust(20)
@@ -154,9 +173,12 @@ def _initialize_logging(self: None):
154173
n_str = 'Iteration'.ljust(20)
155174
E_str = 'Energy (eV)'.ljust(20)
156175
F_str = 'Fmax (eV/A)'.ljust(20)
157-
log_string = n_str + E_str + F_str
176+
if self._restart:
177+
log_string = '\nRestarting:\n' + n_str + E_str + F_str
178+
else:
179+
log_string = n_str + E_str + F_str
158180
climb = Path(self.logfile)
159-
if climb.exists():
181+
if climb.exists() and not self._restart:
160182
os.remove(self.logfile)
161183
self._log(log_string)
162184

@@ -168,13 +190,23 @@ def _get_F(self, atoms):
168190
raise Exception('forces not able to be computed')
169191
return f
170192

171-
def run(self: None) -> None:
172-
atoms, idx, B = self._initialize_atoms()
193+
def climb(self: None, maxsteps=None) -> None:
173194
self._initialize_logging()
174-
traj, g, E = self._initialize_run(atoms, idx)
175-
dx = self._get_initial_step(idx)
176-
dx_1D = dx.reshape(-1)
177-
Fmax, dxi, n = 1, 0, 0
195+
if self._restart:
196+
atoms, idx, B = self._initialize_atoms_restart()
197+
traj, g, E, Fmax = self._initialize_run_restart(idx)
198+
self._pos_f_1D = self.atoms_final.positions[idx, :].reshape(-1)
199+
self._pos_i_1D = self.atoms_initial.positions[idx, :].reshape(-1)
200+
dx_1D = self._get_step(B, g, atoms.positions[idx, :].reshape(-1))
201+
dx = dx_1D.reshape(-1, 3)
202+
pos_1D = atoms.positions[idx, :].reshape(-1)
203+
dxi = LA.norm(self._pos_i_1D - pos_1D)
204+
n = self._restart_trajectory.info['saddleclimb_iterations']
205+
else:
206+
atoms, idx, B = self._initialize_atoms()
207+
traj, g, E = self._initialize_run(atoms, idx)
208+
dx, dx_1D = self._get_initial_step(idx)
209+
Fmax, dxi, n = 1, 0, 0
178210
while Fmax > self.fmax or dxi < 0.5:
179211
atoms.positions[idx, :] += dx
180212
pos_1D = atoms.positions[idx, :].reshape(-1)
@@ -190,7 +222,20 @@ def run(self: None) -> None:
190222
n += 1
191223
log_string = self._get_log_string(n, E, Fmax)
192224
self._log(log_string)
225+
atoms.info['saddleclimb_hessian'] = B.copy()
226+
atoms.info['saddleclimb_iterations'] = n + 0
193227
traj.write(atoms)
228+
if maxsteps and n >= maxsteps:
229+
self._log('maxsteps reached, terminating!')
230+
break
231+
if Fmax < self.fmax and dxi > 0.5:
232+
self._log('Optimization complete!')
233+
234+
def restart_climb(self, restart_trajectory: Atoms):
235+
assert 'saddleclimb_hessian' in restart_trajectory.info
236+
self._restart = True
237+
self._restart_trajectory = copy.deepcopy(restart_trajectory)
238+
self.climb()
194239

195240
def normalize(self: None, v: np.ndarray) -> np.ndarray:
196241
norm = LA.norm(v)

0 commit comments

Comments
 (0)