Skip to content

Commit

Permalink
Added support for the ACE backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
lohedges committed Dec 8, 2023
1 parent 467ce9d commit 44e8a27
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ support the use of
[DeePMD-kit](https://docs.deepmodeling.com/projects/deepmd/en/master/index.html),
[ORCA](https://sites.google.com/site/orcainputlibrary/interfaces-and-qmm),
[SQM](https://ambermd.org/AmberTools.php),
[XTB](https://xtb-docs.readthedocs.io/en/latest), or
[XTB](https://xtb-docs.readthedocs.io/en/latest),
[ACE]( https://acesuit.github.io/) (implemented using [PyJulip](https://github.com/casv2/pyjulip)), or
[PySander](https://ambermd.org/AmberTools.php)
for the backend, providing reference MM or QM with EMLE embedding, and pure EMLE
implementations. To specify a backend, use the `--backend` argument when launching
Expand Down
8 changes: 8 additions & 0 deletions bin/emle-server
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ save_settings = os.getenv("EMLE_SAVE_SETTINGS")
orca_template = os.getenv("EMLE_ORCA_TEMPLATE")
deepmd_model = os.getenv("EMLE_DEEPMD_MODEL")
rascal_model = os.getenv("EMLE_RASCAL_MODEL")
ace_model = os.getenv("EMLE_ACE_MODEL")
parm7 = os.getenv("EMLE_PARM7")
try:
lambda_interpolate = [
Expand Down Expand Up @@ -122,6 +123,7 @@ env = {
"device": device,
"deepmd_model": deepmd_model,
"rascal_model": rascal_model,
"ace_model": ace_model,
"lambda_interpolate": lambda_interpolate,
"interpolate_steps": interpolate_steps,
"parm7": parm7,
Expand Down Expand Up @@ -217,6 +219,12 @@ parser.add_argument(
help="path to Rascal model file",
required=False,
)
parser.add_argument(
"--ace-model",
type=str,
help="path to ACE model file",
required=False,
)
parser.add_argument(
"--lambda-interpolate",
type=float,
Expand Down
80 changes: 80 additions & 0 deletions emle/emle.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ class EMLECalculator:
"sander",
"sqm",
"xtb",
"ace",
"external",
]

Expand All @@ -369,6 +370,7 @@ def __init__(
mm_charges=None,
deepmd_model=None,
rascal_model=None,
ace_model=None,
parm7=None,
qm_indices=None,
sqm_theory="DFTB3",
Expand Down Expand Up @@ -428,6 +430,10 @@ def __init__(
Path to the Rascal model file used to apply delta-learning corrections
to the in vacuo energies and gradients computed by the backed.
ace_model : str
Path to the ACE model file to use for in vacuo calculations. This
must be specified if "ace" is the selected backend.
lambda_interpolate : float, [float, float]
The value of lambda to use for end-state correction calculations. This
must be between 0 and 1, which is used to interpolate between a full MM
Expand Down Expand Up @@ -732,6 +738,26 @@ def __init__(
# Flag that delta-learning corrections will be applied.
self._is_delta = True

# Validate and load the ACE model.
if ace_model is not None:
if not isinstance(ace_model, str):
raise TypeError("'ace_model' must be of type 'str'")

# Convert to an absolute path.
abs_ace_model = os.path.abspath(ace_model)

# Make sure the model file exists.
if not os.path.isfile(abs_ace_model):
raise IOError(f"Unable to locate ACE model file: '{ace_model}'")

# Load the model.
try:
import pyjulip

self._ace_calc = pyjulip.ACE(abs_ace_model)
except:
raise RuntimeError("Unable to create ACE calculator!")

if restart is not None:
if not isinstance(restart, bool):
raise TypeError("'restart' must be of type 'bool'")
Expand Down Expand Up @@ -974,6 +1000,7 @@ def __init__(
"mm_charges": None if mm_charges is None else self._mm_charges.tolist(),
"deepmd_model": deepmd_model,
"rascal_model": rascal_model,
"ace_model": ace_model,
"parm7": parm7,
"qm_indices": None if qm_indices is None else self._qm_indices,
"sqm_theory": sqm_theory,
Expand Down Expand Up @@ -1121,6 +1148,15 @@ def run(self, path=None):
"Failed to calculate in vacuo energies using XTB backend!"
)

# ACE.
elif self._backend == "ace":
try:
E_vac, grad_vac = self._run_ace(atoms)
except:
raise RuntimeError(
"Failed to calculate in vacuo energies using ACE backend!"
)

# External backend.
else:
try:
Expand Down Expand Up @@ -2810,6 +2846,50 @@ def _run_xtb(atoms):

return energy, gradient

@staticmethod
def _run_ace(atoms):
"""
Internal function to compute in vacuo energies and gradients using
ACE (via PyJulip).
Parameters
----------
atoms : ase.atoms.Atoms
The atoms in the QM region.
Returns
-------
energy : float
The in vacuo ML energy in Eh.
gradients : numpy.array
The in vacuo gradient in Eh/Bohr.
"""

if not isinstance(atoms, ase.Atoms):
raise TypeError("'atoms' must be of type 'ase.atoms.Atoms'")

# ACE requires periodic box information so we translate the atoms so that
# the lowest (x, y, z) position is zero, then set the cell to the maximum
# position.
atoms.positions -= np.min(atoms.positions, axis=0)
atoms.cell = np.max(atoms.positions, axis=0)

# Bind the calculator to the atoms.
atoms.calc = self._ace_calc

# Get the energy and forces in atomic units.
energy = atoms.get_potential_energy()
forces = atoms.get_forces()

# Convert to Hartree and Eh/Bohr.
energy *= EV_TO_HARTREE
gradient = -forces * EV_TO_HARTREE * BOHR_TO_ANGSTROM

return energy, gradient

def _run_rascal(self, atoms):
"""
Internal function to compute delta-learning corrections using Rascal.
Expand Down
2 changes: 2 additions & 0 deletions environment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ dependencies:
- torchani
- xtb-python
- pip:
- julia
- git+https://github.com/lab-cosmo/librascal.git
- git+https://github.com/casv2/pyjulip.git

0 comments on commit 44e8a27

Please sign in to comment.