Skip to content

Commit

Permalink
Re-worked some of the CI tests and added the initial and final images…
Browse files Browse the repository at this point in the history
… to the interpolation (as required)
  • Loading branch information
GabrielBram committed Mar 25, 2024
1 parent 33e5987 commit 15a6303
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 33 deletions.
50 changes: 23 additions & 27 deletions carmm/run/workflows/react.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def get_mulliken_charges(self, atoms: Atoms, restart: bool = True):
def search_ts(self, initial: Atoms, final: Atoms,
fmax: float, unc: float, interpolation=None,
n=0.25, steps=40, restart=True, prev_calcs=None,
input_check=0.01, mace_preopt=0, preopt_maxstep=200):
input_check=0.01, mace_preopt=0, preopt_maxsteps=200):
"""
This function allows calculation of the transition state using the CatLearn software package in an
ASE/sockets/FHI-aims setup. The resulting converged band will be located in the MLNEB.traj file.
Expand Down Expand Up @@ -371,7 +371,7 @@ def search_ts(self, initial: Atoms, final: Atoms,
1: Full Preopt - MACE preoptimises TS before FHI-aims - FHI-aims inherits all structures from MACE.
2: TS only - MACE preoptimises after FHI-aims check - MACE receives initial and reactant
structures from FHI-aims and does not optimise
preopt_maxstep: int
preopt_maxsteps: int
Controls the maximum number of steps used in the preoptimiser before giving up and passing the
calculation onto MLNEB with FHI-aims.
Expand Down Expand Up @@ -422,11 +422,12 @@ def search_ts(self, initial: Atoms, final: Atoms,
"""Run preoptimisation flavour 1"""
if self.mace_preopt_flavour == 1:

preopt_ts = self._mace_preoptimise_ts(initial, final, fmax, n, self.interpolation, input_check)
preopt_ts = self._mace_preoptimise_ts(initial, final, fmax, n, self.interpolation,
input_check, max_steps=preopt_maxsteps)

initial = preopt_ts[0]
final = preopt_ts[-1]
self.interpolation = preopt_ts[1:-1]
self.mace_interpolation = preopt_ts

if input_check:
filename_copy = self.filename
Expand All @@ -444,9 +445,10 @@ def search_ts(self, initial: Atoms, final: Atoms,
"""Run preotimisation flavour 2"""
if self.mace_preopt_flavour == 2:

preopt_ts = self._mace_preoptimise_ts(initial, final, fmax, n, self.interpolation, input_check)
preopt_ts = self._mace_preoptimise_ts(initial, final, fmax, n, self.interpolation,
input_check, max_steps=preopt_maxsteps)

self.interpolation = preopt_ts[1:-1]
self.mace_interpolation = preopt_ts

if not minimum_energy_path:
minimum_energy_path = [None, None]
Expand Down Expand Up @@ -478,17 +480,16 @@ def search_ts(self, initial: Atoms, final: Atoms,
"""GAB: ML-NEB misbehaves if a calculator is not provided for interpolated images"""
""" following function ensures correct calculators are attached with closed """
""" sockets. """
initial = self.attach_calculator(initial, params, out_fn=out,
dimensions=self.dimensions, directory=subdirectory_name, calc_e=True)
final = self.attach_calculator(final, params, out_fn=out,
dimensions=self.dimensions, directory=subdirectory_name, calc_e=True)

if isinstance(self.interpolation, list):
for idx, image in enumerate(self.interpolation):
if (self.interpolation[idx].calc) is None:
self.attach_calculator(self.interpolation[idx], params,
out_fn=out, dimensions=self.dimensions, directory=subdirectory_name,
calc_e=True)
self.interpolation = [ image.copy() for image in self.mace_interpolation[1:-1] ]
self.interpolation = [initial] + self.interpolation + [final]

for idx, image in enumerate(self.interpolation):
self.attach_calculator(self.interpolation[idx], params,
out_fn=out, dimensions=self.dimensions, directory=subdirectory_name,
calc_e=True)

initial = self.interpolation[0]
final = self.interpolation[-1]

while not os.path.exists(traj_name):
if iterations > 0:
Expand Down Expand Up @@ -517,10 +518,9 @@ def search_ts(self, initial: Atoms, final: Atoms,

iterations += 1
os.chdir(parent_dir)
elif self.mace_preopt_flavour > 0:
self.ts = sorted(self.interpolation, key=lambda k: k.get_potential_energy(), reverse=True)[0]
return self.ts
else:

os.chdir(parent_dir)
return None

"""Find maximum energy, i.e. transition state to return it"""
Expand Down Expand Up @@ -654,7 +654,7 @@ def _mace_preoptimise(self, atoms: Atoms, fmax, relax_unit_cell, optimiser, opt_

return preopt_atoms

def _mace_preoptimise_ts(self, initial, final, fmax, n, interpolation, input_check):
def _mace_preoptimise_ts(self, initial, final, fmax, n, interpolation, input_check, max_steps=200):
"""
Internal function for preoptimisation of NEB with a pre-set MACE calculator
Expand All @@ -680,15 +680,11 @@ def _mace_preoptimise_ts(self, initial, final, fmax, n, interpolation, input_che

preopt_ts = self._MaceReactor.search_ts_neb(initial, final, fmax, n, k=0.05, method="improvedtangent",
interpolation=interpolation, input_check=input_check,
max_steps=200, restart=True)
max_steps=max_steps, restart=True)

self._MaceReactor.filename = filname

new_interpolation = self._MaceReactor.interpolation.copy()
for idx, image in enumerate(new_interpolation):
new_interpolation[idx].calc = None

return new_interpolation
return self._MaceReactor.interpolation.copy()

def attach_calculator(self, atoms, params,
out_fn="aims.out",
Expand Down
18 changes: 12 additions & 6 deletions examples/run_workflows_ReactAims_MACEpreopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_run_workflows_ReactAims_MACE_preopt():

'''Call relevant calculations'''
'''The below has been previously calculated and data is retrieved from saved trajectories'''
model_optimised, _ = reactor.aims_optimise(atoms, fmax=0.01, restart=True, optimiser=FIRE, mace_preopt=2)
model_optimised, _ = reactor.aims_optimise(atoms, fmax=0.01, restart=True, optimiser=FIRE, mace_preopt=True)
'''I do not like this test - it tests EMT more than it does the workflow'''
assert is_converged(reactor.model_optimised, 0.01), \
"Model is not optimised after preoptimisation"
Expand All @@ -49,11 +49,17 @@ def test_run_workflows_ReactAims_MACE_preopt():
atoms1 = atoms.copy()
atoms1[1].x += 8
atoms2 = atoms.copy()
transition_state = reactor.search_ts(atoms1, atoms2, 0.05, 0.03, n=6, input_check=0.01, mace_preopt=2)

activation_energy = transition_state.get_potential_energy()-model_optimised.get_potential_energy()

assert 5.34946 == round(activation_energy, 5)
'''Tests each flavour of ML-NEB'''
transition_state = reactor.search_ts(atoms1, atoms2, 0.05, 0.03, n=6, input_check=0.01, mace_preopt=2, restart=False)
print(len(reactor.mace_interpolation))
assert is_converged(reactor.mace_interpolation[3], 0.03), \
"MACE pre-optimised NEB flavour 2 is not converged"
transition_state = reactor.search_ts(atoms1, atoms2, 0.05, 0.03, n=6, input_check=0.01, mace_preopt=1, restart=False)
assert is_converged(reactor.mace_interpolation[3], 0.03), \
"MACE pre-optimised NEB flavour 1 is not converged"
transition_state = reactor.search_ts(atoms1, atoms2, 0.05, 0.03, n=6, input_check=0.01, mace_preopt=0, restart=False)
assert isinstance(reactor.interpolation, str), \
"ML-NEB is somehow running even though not requested"

'''Return to parent directory'''
os.chdir(parent_dir)
Expand Down

0 comments on commit 15a6303

Please sign in to comment.