aimnet 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. aimnet-0.0.1/LICENSE +21 -0
  2. aimnet-0.0.1/PKG-INFO +78 -0
  3. aimnet-0.0.1/README.md +49 -0
  4. aimnet-0.0.1/aimnet/__init__.py +0 -0
  5. aimnet-0.0.1/aimnet/base.py +41 -0
  6. aimnet-0.0.1/aimnet/calculators/__init__.py +15 -0
  7. aimnet-0.0.1/aimnet/calculators/aimnet2ase.py +98 -0
  8. aimnet-0.0.1/aimnet/calculators/aimnet2pysis.py +76 -0
  9. aimnet-0.0.1/aimnet/calculators/calculator.py +320 -0
  10. aimnet-0.0.1/aimnet/calculators/model_registry.py +60 -0
  11. aimnet-0.0.1/aimnet/calculators/model_registry.yaml +33 -0
  12. aimnet-0.0.1/aimnet/calculators/nb_kernel_cpu.py +222 -0
  13. aimnet-0.0.1/aimnet/calculators/nb_kernel_cuda.py +217 -0
  14. aimnet-0.0.1/aimnet/calculators/nbmat.py +220 -0
  15. aimnet-0.0.1/aimnet/cli.py +22 -0
  16. aimnet-0.0.1/aimnet/config.py +170 -0
  17. aimnet-0.0.1/aimnet/constants.py +467 -0
  18. aimnet-0.0.1/aimnet/data/__init__.py +1 -0
  19. aimnet-0.0.1/aimnet/data/sgdataset.py +517 -0
  20. aimnet-0.0.1/aimnet/dftd3_data.pt +0 -0
  21. aimnet-0.0.1/aimnet/models/__init__.py +2 -0
  22. aimnet-0.0.1/aimnet/models/aimnet2.py +188 -0
  23. aimnet-0.0.1/aimnet/models/aimnet2.yaml +44 -0
  24. aimnet-0.0.1/aimnet/models/aimnet2_dftd3_wb97m.yaml +51 -0
  25. aimnet-0.0.1/aimnet/models/base.py +51 -0
  26. aimnet-0.0.1/aimnet/modules/__init__.py +3 -0
  27. aimnet-0.0.1/aimnet/modules/aev.py +201 -0
  28. aimnet-0.0.1/aimnet/modules/core.py +237 -0
  29. aimnet-0.0.1/aimnet/modules/lr.py +243 -0
  30. aimnet-0.0.1/aimnet/nbops.py +151 -0
  31. aimnet-0.0.1/aimnet/ops.py +208 -0
  32. aimnet-0.0.1/aimnet/train/__init__.py +0 -0
  33. aimnet-0.0.1/aimnet/train/calc_sae.py +43 -0
  34. aimnet-0.0.1/aimnet/train/default_train.yaml +166 -0
  35. aimnet-0.0.1/aimnet/train/loss.py +83 -0
  36. aimnet-0.0.1/aimnet/train/metrics.py +188 -0
  37. aimnet-0.0.1/aimnet/train/pt2jpt.py +81 -0
  38. aimnet-0.0.1/aimnet/train/train.py +155 -0
  39. aimnet-0.0.1/aimnet/train/utils.py +398 -0
  40. aimnet-0.0.1/pyproject.toml +143 -0
aimnet-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024, Roman Zubatyuk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
aimnet-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.1
2
+ Name: aimnet
3
+ Version: 0.0.1
4
+ Summary: AIMNet Machine Learned Interatomic Potential
5
+ Home-page: https://github.com/isayevlab/aimnetcentral
6
+ Author: Roman Zubatyuk
7
+ Author-email: zubatyuk@gmail.com
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Dist: click (>=8.1.7,<9.0.0)
15
+ Requires-Dist: h5py (>=3.12.1,<4.0.0)
16
+ Requires-Dist: ignite (>=1.1.0,<2.0.0)
17
+ Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
18
+ Requires-Dist: numba (>=0.60.0,<0.61.0)
19
+ Requires-Dist: numpy (<2.0)
20
+ Requires-Dist: omegaconf (>=2.3.0,<3.0.0)
21
+ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
22
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
23
+ Requires-Dist: torch (>=2.5.0,<3.0.0)
24
+ Requires-Dist: wandb (>=0.18.5,<0.19.0)
25
+ Project-URL: Documentation, https://isayevlab.github.io/aimnetcentral/
26
+ Project-URL: Repository, https://github.com/isayevlab/aimnetcentral
27
+ Description-Content-Type: text/markdown
28
+
29
+ # aimnetcentral
30
+
31
+ [![Release](https://img.shields.io/github/v/release/isayevlab/aimnetcentral)](https://img.shields.io/github/v/release/isayevlab/aimnetcentral)
32
+ [![Build status](https://img.shields.io/github/actions/workflow/status/isayevlab/aimnetcentral/main.yml?branch=main)](https://github.com/isayevlab/aimnetcentral/actions/workflows/main.yml?query=branch%3Amain)
33
+ [![codecov](https://codecov.io/gh/isayevlab/aimnetcentral/branch/main/graph/badge.svg)](https://codecov.io/gh/isayevlab/aimnetcentral)
34
+ [![Commit activity](https://img.shields.io/github/commit-activity/m/isayevlab/aimnetcentral)](https://img.shields.io/github/commit-activity/m/isayevlab/aimnetcentral)
35
+ [![License](https://img.shields.io/github/license/isayevlab/aimnetcentral)](https://img.shields.io/github/license/isayevlab/aimnetcentral)
36
+
37
+ AIMNet Machine Learned Interatomic Potential
38
+
39
+ - **Github repository**: <https://github.com/isayevlab/aimnetcentral/>
40
+ - **Documentation** <https://isayevlab.github.io/aimnetcentral/>
41
+
42
+ ## Getting started with your project
43
+
44
+ First, create a repository on GitHub with the same name as this project, and then run the following commands:
45
+
46
+ ```bash
47
+ git init -b main
48
+ git add .
49
+ git commit -m "init commit"
50
+ git remote add origin git@github.com:isayevlab/aimnetcentral.git
51
+ git push -u origin main
52
+ ```
53
+
54
+ Finally, install the environment and the pre-commit hooks with
55
+
56
+ ```bash
57
+ make install
58
+ ```
59
+
60
+ You are now ready to start development on your project!
61
+ The CI/CD pipeline will be triggered when you open a pull request, merge to main, or when you create a new release.
62
+
63
+ To finalize the set-up for publishing to PyPI or Artifactory, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/publishing/#set-up-for-pypi).
64
+ For activating the automatic documentation with MkDocs, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/mkdocs/#enabling-the-documentation-on-github).
65
+ To enable the code coverage reports, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/codecov/).
66
+
67
+ ## Releasing a new version
68
+
69
+ - Create an API Token on [PyPI](https://pypi.org/).
70
+ - Add the API Token to your projects secrets with the name `PYPI_TOKEN` by visiting [this page](https://github.com/isayevlab/aimnetcentral/settings/secrets/actions/new).
71
+ - Create a [new release](https://github.com/isayevlab/aimnetcentral/releases/new) on Github.
72
+ - Create a new tag in the form `*.*.*`.
73
+ - For more details, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/cicd/#how-to-trigger-a-release).
74
+
75
+ ---
76
+
77
+ Repository initiated with [fpgmaas/cookiecutter-poetry](https://github.com/fpgmaas/cookiecutter-poetry).
78
+
aimnet-0.0.1/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # aimnetcentral
2
+
3
+ [![Release](https://img.shields.io/github/v/release/isayevlab/aimnetcentral)](https://img.shields.io/github/v/release/isayevlab/aimnetcentral)
4
+ [![Build status](https://img.shields.io/github/actions/workflow/status/isayevlab/aimnetcentral/main.yml?branch=main)](https://github.com/isayevlab/aimnetcentral/actions/workflows/main.yml?query=branch%3Amain)
5
+ [![codecov](https://codecov.io/gh/isayevlab/aimnetcentral/branch/main/graph/badge.svg)](https://codecov.io/gh/isayevlab/aimnetcentral)
6
+ [![Commit activity](https://img.shields.io/github/commit-activity/m/isayevlab/aimnetcentral)](https://img.shields.io/github/commit-activity/m/isayevlab/aimnetcentral)
7
+ [![License](https://img.shields.io/github/license/isayevlab/aimnetcentral)](https://img.shields.io/github/license/isayevlab/aimnetcentral)
8
+
9
+ AIMNet Machine Learned Interatomic Potential
10
+
11
+ - **Github repository**: <https://github.com/isayevlab/aimnetcentral/>
12
+ - **Documentation** <https://isayevlab.github.io/aimnetcentral/>
13
+
14
+ ## Getting started with your project
15
+
16
+ First, create a repository on GitHub with the same name as this project, and then run the following commands:
17
+
18
+ ```bash
19
+ git init -b main
20
+ git add .
21
+ git commit -m "init commit"
22
+ git remote add origin git@github.com:isayevlab/aimnetcentral.git
23
+ git push -u origin main
24
+ ```
25
+
26
+ Finally, install the environment and the pre-commit hooks with
27
+
28
+ ```bash
29
+ make install
30
+ ```
31
+
32
+ You are now ready to start development on your project!
33
+ The CI/CD pipeline will be triggered when you open a pull request, merge to main, or when you create a new release.
34
+
35
+ To finalize the set-up for publishing to PyPI or Artifactory, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/publishing/#set-up-for-pypi).
36
+ For activating the automatic documentation with MkDocs, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/mkdocs/#enabling-the-documentation-on-github).
37
+ To enable the code coverage reports, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/codecov/).
38
+
39
+ ## Releasing a new version
40
+
41
+ - Create an API Token on [PyPI](https://pypi.org/).
42
+ - Add the API Token to your projects secrets with the name `PYPI_TOKEN` by visiting [this page](https://github.com/isayevlab/aimnetcentral/settings/secrets/actions/new).
43
+ - Create a [new release](https://github.com/isayevlab/aimnetcentral/releases/new) on Github.
44
+ - Create a new tag in the form `*.*.*`.
45
+ - For more details, see [here](https://fpgmaas.github.io/cookiecutter-poetry/features/cicd/#how-to-trigger-a-release).
46
+
47
+ ---
48
+
49
+ Repository initiated with [fpgmaas/cookiecutter-poetry](https://github.com/fpgmaas/cookiecutter-poetry).
File without changes
@@ -0,0 +1,41 @@
1
+ from typing import ClassVar, Dict, Final
2
+
3
+ import torch
4
+ from torch import Tensor, nn
5
+
6
+ from aimnet import nbops
7
+
8
+
9
+ class AIMNet2Base(nn.Module): # pylint: disable=abstract-method
10
+ """Base class for AIMNet2 models. Implements pre-processing data:
11
+ converting to right dtype and device, setting nb mode, calculating masks.
12
+ """
13
+
14
+ _required_keys: Final = ["coord", "numbers", "charge"]
15
+ _required_keys_dtype: Final = [torch.float32, torch.int64, torch.float32]
16
+ _optional_keys: Final = ["mult", "nbmat", "nbmat_lr", "mol_idx", "shifts", "cell"]
17
+ _optional_keys_dtype: Final = [torch.float32, torch.int64, torch.int64, torch.int64, torch.float32, torch.float32]
18
+ __constants__: ClassVar = ["_required_keys", "_required_keys_dtype", "_optional_keys", "_optional_keys_dtype"]
19
+
20
+ def __init__(self):
21
+ super().__init__()
22
+
23
+ def _prepare_dtype(self, data: Dict[str, Tensor]) -> Dict[str, Tensor]:
24
+ for k, d in zip(self._required_keys, self._required_keys_dtype):
25
+ assert k in data, f"Key {k} is required"
26
+ data[k] = data[k].to(d)
27
+ for k, d in zip(self._optional_keys, self._optional_keys_dtype):
28
+ if k in data:
29
+ data[k] = data[k].to(d)
30
+ return data
31
+
32
+ def prepare_input(self, data: Dict[str, Tensor]) -> Dict[str, Tensor]:
33
+ """Some sommon operations"""
34
+ data = self._prepare_dtype(data)
35
+ data = nbops.set_nb_mode(data)
36
+ data = nbops.calc_masks(data)
37
+
38
+ assert data["charge"].ndim == 1, "Charge should be 1D tensor."
39
+ if "mult" in data:
40
+ assert data["mult"].ndim == 1, "Mult should be 1D tensor."
41
+ return data
@@ -0,0 +1,15 @@
1
+ import importlib.util
2
+
3
+ from .calculator import AIMNet2Calculator
4
+
5
+ __all__ = ["AIMNet2Calculator"]
6
+
7
+ if importlib.util.find_spec("ase") is not None:
8
+ from .aimnet2ase import AIMNet2ASE
9
+
10
+ __all__.append(AIMNet2ASE) # type: ignore
11
+
12
+ if importlib.util.find_spec("pysisyphus") is not None:
13
+ from .aimnet2pysis import AIMNet2Pysis
14
+
15
+ __all__.append(AIMNet2Pysis) # type: ignore
@@ -0,0 +1,98 @@
1
+ import numpy as np
2
+ import torch
3
+
4
+ try:
5
+ from ase.calculators.calculator import Calculator, all_changes # type: ignore
6
+ except ImportError:
7
+ raise ImportError("ASE is not installed. Please install ASE to use this module.") from None
8
+
9
+ from .calculator import AIMNet2Calculator
10
+
11
+
12
+ class AIMNet2ASE(Calculator):
13
+ from typing import ClassVar
14
+
15
+ implemented_properties: ClassVar[list[str]] = ["energy", "forces", "free_energy", "charges", "stress"]
16
+
17
+ def __init__(self, base_calc: AIMNet2Calculator | str = "aimnet2", charge=0, mult=1):
18
+ super().__init__()
19
+ if isinstance(base_calc, str):
20
+ base_calc = AIMNet2Calculator(base_calc)
21
+ self.base_calc = base_calc
22
+ self.charge = charge
23
+ self.mult = mult
24
+ self.reset()
25
+ # list of implemented species
26
+ if hasattr(base_calc, "implemented_species"):
27
+ self.implemented_species = base_calc.implemented_species.cpu().numpy() # type: ignore
28
+ else:
29
+ self.implemented_species = None
30
+
31
+ def reset(self):
32
+ super().reset()
33
+ self._t_numbers = None
34
+ self._t_charge = None
35
+ self._t_mult = None
36
+ self.charge = 0.0
37
+ self.mult = 1.0
38
+
39
+ def set_atoms(self, atoms):
40
+ if self.implemented_species is not None and not np.in1d(atoms.numbers, self.implemented_species).all():
41
+ raise ValueError("Some species are not implemented in the AIMNet2Calculator")
42
+ self.reset()
43
+ self.atoms = atoms
44
+
45
+ def set_charge(self, charge):
46
+ self.charge = charge
47
+ self._t_charge = None
48
+ self.update_tensors()
49
+
50
+ def set_mult(self, mult):
51
+ self.mult = mult
52
+ self._t_mult = None
53
+ self.update_tensors()
54
+
55
+ def update_tensors(self):
56
+ if self._t_numbers is None:
57
+ self._t_numbers = torch.tensor(self.atoms.numbers, dtype=torch.int64, device=self.base_calc.device)
58
+ if self._t_charge is None:
59
+ self._t_charge = torch.tensor(self.charge, dtype=torch.float32, device=self.base_calc.device)
60
+ if self._t_mult is None:
61
+ self._t_mult = torch.tensor(self.mult, dtype=torch.float32, device=self.base_calc.device)
62
+
63
+ def calculate(self, atoms=None, properties=None, system_changes=all_changes):
64
+ if properties is None:
65
+ properties = ["energy"]
66
+ super().calculate(atoms, properties, system_changes)
67
+ self.update_tensors()
68
+
69
+ cell = self.atoms.cell.array if self.atoms.cell is not None and self.atoms.pbc.any() else None
70
+
71
+ _in = {
72
+ "coord": torch.tensor(self.atoms.positions, dtype=torch.float32, device=self.base_calc.device),
73
+ "numbers": self._t_numbers,
74
+ "charge": self._t_charge,
75
+ "mult": self._t_mult,
76
+ }
77
+
78
+ _unsqueezed = False
79
+ if cell is not None:
80
+ _in["cell"] = cell
81
+ else:
82
+ for k, v in _in.items():
83
+ _in[k] = v.unsqueeze(0)
84
+ _unsqueezed = True
85
+
86
+ results = self.base_calc(_in, forces="forces" in properties, stress="stress" in properties)
87
+
88
+ for k, v in results.items():
89
+ if _unsqueezed:
90
+ v = v.squeeze(0)
91
+ results[k] = v.detach().cpu().numpy() # type: ignore
92
+
93
+ self.results["energy"] = results["energy"]
94
+ self.results["charges"] = results["charges"]
95
+ if "forces" in properties:
96
+ self.results["forces"] = results["forces"]
97
+ if "stress" in properties:
98
+ self.results["stress"] = results["stress"]
@@ -0,0 +1,76 @@
1
+ from typing import ClassVar
2
+
3
+ import torch
4
+
5
+ from .calculator import AIMNet2Calculator
6
+
7
+ try:
8
+ import pysisyphus.run # type: ignore
9
+ from pysisyphus.calculators.Calculator import Calculator # type: ignore
10
+ from pysisyphus.constants import ANG2BOHR, AU2EV, BOHR2ANG # type: ignore
11
+ from pysisyphus.elem_data import ATOMIC_NUMBERS # type: ignore
12
+ except ImportError:
13
+ raise ImportError("Pysisyphus is not installed. Please install Pysisyphus to use this module.") from None
14
+
15
+ EV2AU = 1 / AU2EV
16
+
17
+
18
+ class AIMNet2Pysis(Calculator):
19
+ implemented_properties: ClassVar = ["energy", "forces", "free_energy", "charges", "stress"]
20
+
21
+ def __init__(self, model: AIMNet2Calculator | str = "aimnet2", charge=0, mult=1, **kwargs):
22
+ super().__init__(charge=charge, mult=mult, **kwargs)
23
+ if isinstance(model, str):
24
+ model = AIMNet2Calculator(model)
25
+ self.model = model
26
+
27
+ def _prepere_input(self, atoms, coord):
28
+ device = self.model.device
29
+ numbers = torch.as_tensor([ATOMIC_NUMBERS[a.lower()] for a in atoms], device=device)
30
+ coord = torch.as_tensor(coord, dtype=torch.float, device=device).view(-1, 3) * BOHR2ANG
31
+ charge = torch.as_tensor([self.charge], dtype=torch.float, device=device)
32
+ mult = torch.as_tensor([self.mult], dtype=torch.float, device=device)
33
+ return {"coord": coord, "numbers": numbers, "charge": charge, "mult": mult}
34
+
35
+ @staticmethod
36
+ def _results_get_energy(results):
37
+ return results["energy"].item() * EV2AU
38
+
39
+ @staticmethod
40
+ def _results_get_forces(results):
41
+ return (results["forces"].detach() * (EV2AU / ANG2BOHR)).flatten().to(torch.double).cpu().numpy()
42
+
43
+ @staticmethod
44
+ def _results_get_hessian(results):
45
+ return (
46
+ (results["hessian"].flatten(0, 1).flatten(-2, -1) * (EV2AU / ANG2BOHR / ANG2BOHR))
47
+ .to(torch.double)
48
+ .cpu()
49
+ .numpy()
50
+ )
51
+
52
+ def get_energy(self, atoms, coords):
53
+ _in = self._prepere_input(atoms, coords)
54
+ res = self.model(_in)
55
+ energy = self._results_get_energy(res)
56
+ return {"energy": energy}
57
+
58
+ def get_forces(self, atoms, coords):
59
+ _in = self._prepere_input(atoms, coords)
60
+ res = self.model(_in, forces=True)
61
+ energy = self._results_get_energy(res)
62
+ forces = self._results_get_forces(res)
63
+ return {"energy": energy, "forces": forces}
64
+
65
+ def get_hessian(self, atoms, coords):
66
+ _in = self._prepere_input(atoms, coords)
67
+ res = self.model(_in, forces=True, hessian=True)
68
+ energy = self._results_get_energy(res)
69
+ forces = self._results_get_forces(res)
70
+ hessian = self._results_get_hessian(res)
71
+ return {"energy": energy, "forces": forces, "hessian": hessian}
72
+
73
+
74
+ def run_pysis():
75
+ pysisyphus.run.CALC_DICT["aimnet"] = AIMNet2Pysis
76
+ pysisyphus.run.run()