Skip to content

Commit

Permalink
Merge pull request #34 from rul048/patch-9
Browse files Browse the repository at this point in the history
Add customized potential interface to matcalc/utils.py
  • Loading branch information
shyuep authored Oct 10, 2024
2 parents 254349b + f39708b commit 77253b7
Show file tree
Hide file tree
Showing 27 changed files with 493,614 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
cache-dependency-path: "**/requirements.txt"
- name: Install dependencies
run: |
pip install numpy
pip install git+https://github.com/materialsvirtuallab/maml.git
pip install --quiet -r requirements.txt -r requirements-ci.txt
pip install -e '.[models]'
- name: pytest
Expand Down
36 changes: 25 additions & 11 deletions citation.cff
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
# cff-version: 1.2.0
message: If you use MatCalc, please cite it as follows.
title: MatCalc
subtitle: A Python library for calculating materials properties
subtitle: A Python library for calculating materials properties from the potential energy surface (PES)
authors:
- given-names: Runze
family-names: Liu
affiliation: University of California, San Diego
email: [email protected]
orcid: https://orcid.org/0000-0002-1214-9908
github: https://github.com/rul048
- given-names: Elliott
family-names: Liu
affiliation: Massachusetts Institute of Technology
email: [email protected]
github: https://github.com/PROA200
- given-names: Janosh
family-names: Riebesell
email: [email protected]
affiliation: University of Cambridge, Lawrence Berkeley National Laboratory
orcid: https://orcid.org/0000-0001-5233-3462
github: https://github.com/janosh
- given-names: Elliott
family-names: Liu
email: [email protected]
github: https://github.com/PROA200
- given-names: Ji
family-names: Qi
email: [email protected]
affiliation: University of California, San Diego
github: https://github.com/JiQi535
- given-names: Tsz Wai
family-names: Ko
github: https://github.com/kenko911
orcid: https://orcid.org/0000-0002-0802-9559
- given-names: Shyue Ping
family-names: Ong
email: [email protected]
affiliation: University of California, San Diego
orcid: https://orcid.org/0000-0001-5726-2587
github: https://github.com/shyuep
- given-names: Tsz Wai
family-names: Ko
affiliation: University of California, San Diego
email: [email protected]
orcid: https://orcid.org/0000-0002-0802-9559
github: https://github.com/kenko911
license: BSD-3-Clause
license-url: https://github.com/materialsvirtuallab/matcalc/blob/-/LICENSE"
repository-code: https://github.com/materialsvirtuallab/matcalc
type: software
url: https://github.com/materialsvirtuallab/matcalc
version: 0.0.3 # replace with whatever version you use
date-released: "2023-07-24"
version: 0.0.4 # replace with whatever version you use
date-released: "2024-01-01"
248 changes: 246 additions & 2 deletions matcalc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
from typing import TYPE_CHECKING, Any

import ase.optimize
from ase.calculators.calculator import Calculator
from ase.optimize.optimize import Optimizer

if TYPE_CHECKING:
from ase.calculators.calculator import Calculator
from pathlib import Path

from ase import Atoms
from maml.apps.pes._lammps import LMPStaticCalculator
from pyace.basis import ACEBBasisSet, ACECTildeBasisSet, BBasisConfiguration


# Listing of supported universal calculators.
UNIVERSAL_CALCULATORS = (
Expand All @@ -23,12 +29,242 @@
)


class PESCalculator(Calculator):
"""
Potential calculator for ASE, supporting both **universal** and **customized** potentials, including:
Customized potentials: MatGL(M3GNet, CHGNet, TensorNet and SO3Net), MAML(MTP, GAP, NNP, SNAP and qSNAP) and ACE.
Universal potentials: M3GNet, CHGNet, MACE and SevenNet.
Though MatCalc can be used with any MLIP, this method does not yet cover all MLIPs.
Imports should be inside if statements to ensure that all models are optional dependencies.
"""

implemented_properties = ("energy", "forces", "stress")

def __init__(
self,
potential: LMPStaticCalculator,
stress_weight: float = 1 / 160.21766208,
**kwargs: Any,
) -> None:
"""
Initialize PESCalculator with a potential from maml.
Args:
potential (LMPStaticCalculator): maml.apps.pes._lammps.LMPStaticCalculator
stress_weight (float): The conversion factor from GPa to eV/A^3, if it is set to 1.0, the unit is in GPa.
Default to 1 / 160.21766208.
**kwargs: Additional keyword arguments passed to super().__init__().
"""
super().__init__(**kwargs)
self.potential = potential
self.stress_weight = stress_weight

def calculate(
self,
atoms: Atoms | None = None,
properties: list | None = None,
system_changes: list | None = None,
) -> None:
"""
Perform calculation for an input Atoms.
Args:
atoms (ase.Atoms): ase Atoms object
properties (list): The list of properties to calculate
system_changes (list): monitor which properties of atoms were
changed for new calculation. If not, the previous calculation
results will be loaded.
"""
from ase.calculators.calculator import all_changes, all_properties
from maml.apps.pes import EnergyForceStress
from pymatgen.io.ase import AseAtomsAdaptor

properties = properties or all_properties
system_changes = system_changes or all_changes
super().calculate(atoms=atoms, properties=properties, system_changes=system_changes)

structure = AseAtomsAdaptor.get_structure(atoms)
efs_calculator = EnergyForceStress(ff_settings=self.potential)
energy, forces, stresses = efs_calculator.calculate([structure])[0]

self.results = {
"energy": energy,
"forces": forces,
"stress": stresses * self.stress_weight,
}

@staticmethod
def load_matgl(path: str | Path, **kwargs: Any) -> Calculator:
"""
Load the MatGL model for use in ASE as a calculator.
Args:
path (str | Path): The path to the folder storing model.
**kwargs (Any): Additional keyword arguments for the M3GNetCalculator.
Returns:
Calculator: ASE calculator compatible with the MatGL model.
"""
import matgl
from matgl.ext.ase import M3GNetCalculator

model = matgl.load_model(path=path)
kwargs.setdefault("stress_weight", 1 / 160.21766208)
return M3GNetCalculator(potential=model, **kwargs)

@staticmethod
def load_mtp(filename: str | Path, elements: list, **kwargs: Any) -> Calculator:
"""
Load the MTP model for use in ASE as a calculator.
Args:
filename (str | Path): The file storing parameters of potentials, filename should ends with ".mtp".
elements (list): The list of elements.
**kwargs (Any): Additional keyword arguments for the PESCalculator.
Returns:
Calculator: ASE calculator compatible with the MTP model.
"""
from maml.apps.pes import MTPotential

model = MTPotential.from_config(filename=filename, elements=elements)
return PESCalculator(potential=model, **kwargs)

@staticmethod
def load_gap(filename: str | Path, **kwargs: Any) -> Calculator:
"""
Load the GAP model for use in ASE as a calculator.
Args:
filename (str | Path): The file storing parameters of potentials, filename should ends with ".xml".
**kwargs (Any): Additional keyword arguments for the PESCalculator.
Returns:
Calculator: ASE calculator compatible with the GAP model.
"""
from maml.apps.pes import GAPotential

model = GAPotential.from_config(filename=filename)
return PESCalculator(potential=model, **kwargs)

@staticmethod
def load_nnp(
input_filename: str | Path, scaling_filename: str | Path, weights_filenames: list, **kwargs: Any
) -> Calculator:
"""
Load the NNP model for use in ASE as a calculator.
Args:
input_filename (str | Path): The file storing the input configuration of
Neural Network Potential.
scaling_filename (str | Path): The file storing scaling info of
Neural Network Potential.
weights_filenames (list | Path): List of files storing weights of each specie in
Neural Network Potential.
**kwargs (Any): Additional keyword arguments for the PESCalculator.
Returns:
Calculator: ASE calculator compatible with the NNP model.
"""
from maml.apps.pes import NNPotential

model = NNPotential.from_config(
input_filename=input_filename,
scaling_filename=scaling_filename,
weights_filenames=weights_filenames,
)
return PESCalculator(potential=model, **kwargs)

@staticmethod
def load_snap(param_file: str | Path, coeff_file: str | Path, **kwargs: Any) -> Calculator:
"""
Load the SNAP or qSNAP model for use in ASE as a calculator.
Args:
param_file (str | Path): The file storing the configuration of potentials.
coeff_file (str | Path): The file storing the coefficients of potentials.
**kwargs (Any): Additional keyword arguments for the PESCalculator.
Returns:
Calculator: ASE calculator compatible with the SNAP or qSNAP model.
"""
from maml.apps.pes import SNAPotential

model = SNAPotential.from_config(param_file=param_file, coeff_file=coeff_file)
return PESCalculator(potential=model, **kwargs)

@staticmethod
def load_ace(
basis_set: str | Path | ACEBBasisSet | ACECTildeBasisSet | BBasisConfiguration, **kwargs: Any
) -> Calculator:
"""
Load the ACE model for use in ASE as a calculator.
Args:
basis_set: The specification of ACE potential, could be in following forms:
".ace" potential filename
".yaml" potential filename
ACEBBasisSet object
ACECTildeBasisSet object
BBasisConfiguration object
**kwargs (Any): Additional keyword arguments for the PyACECalculator.
Returns:
Calculator: ASE calculator compatible with the ACE model.
"""
from pyace import PyACECalculator

return PyACECalculator(basis_set=basis_set, **kwargs)

@staticmethod
def load_universal(name: str | Calculator, **kwargs: Any) -> Calculator:
"""
Load the universal model for use in ASE as a calculator.
Args:
name (str | Calculator): The name of universal calculator.
**kwargs (Any): Additional keyword arguments for universal calculator.
Returns:
Calculator: ASE calculator compatible with the universal model.
"""
if not isinstance(name, str): # e.g. already an ase Calculator instance
return name

if name.lower().startswith("m3gnet"):
import matgl
from matgl.ext.ase import M3GNetCalculator

# M3GNet is shorthand for latest M3GNet based on DIRECT sampling.
name = {"m3gnet": "M3GNet-MP-2021.2.8-DIRECT-PES"}.get(name.lower(), name)
model = matgl.load_model(name)
kwargs.setdefault("stress_weight", 1 / 160.21766208)
return M3GNetCalculator(potential=model, **kwargs)

if name.lower() == "chgnet":
from chgnet.model.dynamics import CHGNetCalculator

return CHGNetCalculator(**kwargs)

if name.lower() == "mace":
from mace.calculators import mace_mp

return mace_mp(**kwargs)

if name.lower() == "sevennet":
from sevenn.sevennet_calculator import SevenNetCalculator

return SevenNetCalculator(**kwargs)

raise ValueError(f"Unrecognized {name=}, must be one of {UNIVERSAL_CALCULATORS}")


@functools.lru_cache
def get_universal_calculator(name: str | Calculator, **kwargs: Any) -> Calculator:
"""Helper method to get some well-known **universal** calculators.
Imports should be inside if statements to ensure that all models are optional dependencies.
All calculators must be universal, i.e. encompass a wide swath of the periodic table.
Though matcalc can be used with any MLIP, even custom ones, this function is not meant as
Though MatCalc can be used with any MLIP, even custom ones, this function is not meant as
a list of all MLIPs.
Args:
Expand All @@ -41,6 +277,14 @@ def get_universal_calculator(name: str | Calculator, **kwargs: Any) -> Calculato
Returns:
Calculator
"""
import warnings

warnings.warn(
"get_universal_calculator() will be deprecated in the future. Use PESCalculator.load_YOUR_MODEL() instead.",
DeprecationWarning,
stacklevel=2,
)

if not isinstance(name, str): # e.g. already an ase Calculator instance
return name

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ dependencies = ["ase>=3.23.0", "joblib", "phonopy", "pymatgen", "numpy<2.0.0"]
version = "0.0.4"

[project.optional-dependencies]
models = ["chgnet>=0.3.8", "mace-torch>=0.3.6", "matgl>=1.0.0", "sevenn>=0.9.3", "dgl<=2.1.0", "torch<=2.2.1"]
models = ["chgnet>=0.3.8", "mace-torch>=0.3.6", "matgl>=1.0.0", "sevenn>=0.9.3", "maml>=2024.6.13", "dgl<=2.1.0", "torch<=2.2.1"]

[tool.setuptools]
packages = ["matcalc"]
Expand Down
Loading

0 comments on commit 77253b7

Please sign in to comment.