ase-uhal 0.1.0__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 (30) hide show
  1. ase_uhal-0.1.0/CODE_OF_CONDUCT.md +77 -0
  2. ase_uhal-0.1.0/LICENSE +22 -0
  3. ase_uhal-0.1.0/MANIFEST.in +6 -0
  4. ase_uhal-0.1.0/PKG-INFO +106 -0
  5. ase_uhal-0.1.0/README.md +56 -0
  6. ase_uhal-0.1.0/ase_uhal/__init__.py +6 -0
  7. ase_uhal-0.1.0/ase_uhal/_version.py +1 -0
  8. ase_uhal-0.1.0/ase_uhal/ace_installer.py +22 -0
  9. ase_uhal-0.1.0/ase_uhal/bias_calculators.py +153 -0
  10. ase_uhal-0.1.0/ase_uhal/committee_calculators/__init__.py +4 -0
  11. ase_uhal-0.1.0/ase_uhal/committee_calculators/ace_committee_calculator.py +172 -0
  12. ase_uhal-0.1.0/ase_uhal/committee_calculators/base_committee_calculator.py +378 -0
  13. ase_uhal-0.1.0/ase_uhal/committee_calculators/mace_committee_calculator.py +317 -0
  14. ase_uhal-0.1.0/ase_uhal/committee_calculators/torch_committee_calculator.py +114 -0
  15. ase_uhal-0.1.0/ase_uhal/data/__init__.py +0 -0
  16. ase_uhal-0.1.0/ase_uhal/data/_ace_utils.jl +68 -0
  17. ase_uhal-0.1.0/ase_uhal/distillation/__init__.py +2 -0
  18. ase_uhal-0.1.0/ase_uhal/distillation/build_linear_system.py +79 -0
  19. ase_uhal-0.1.0/ase_uhal/distillation/distillation.py +76 -0
  20. ase_uhal-0.1.0/ase_uhal/distillation/extract_weights.py +63 -0
  21. ase_uhal-0.1.0/ase_uhal/py.typed +1 -0
  22. ase_uhal-0.1.0/ase_uhal/structure_selector.py +123 -0
  23. ase_uhal-0.1.0/ase_uhal.egg-info/PKG-INFO +106 -0
  24. ase_uhal-0.1.0/ase_uhal.egg-info/SOURCES.txt +29 -0
  25. ase_uhal-0.1.0/ase_uhal.egg-info/dependency_links.txt +1 -0
  26. ase_uhal-0.1.0/ase_uhal.egg-info/not-zip-safe +1 -0
  27. ase_uhal-0.1.0/ase_uhal.egg-info/requires.txt +30 -0
  28. ase_uhal-0.1.0/ase_uhal.egg-info/top_level.txt +1 -0
  29. ase_uhal-0.1.0/pyproject.toml +127 -0
  30. ase_uhal-0.1.0/setup.cfg +20 -0
@@ -0,0 +1,77 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age,
8
+ body size, disability, ethnicity, gender identity and expression, level of
9
+ experience, nationality, personal appearance, race, religion, or sexual
10
+ identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment include:
15
+
16
+ * Using welcoming and inclusive language
17
+ * Being respectful of differing viewpoints and experiences
18
+ * Gracefully accepting constructive criticism
19
+ * Focusing on what is best for the community
20
+ * Showing empathy towards other community members
21
+
22
+ Examples of unacceptable behavior by participants include:
23
+
24
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
25
+ * Trolling, insulting/derogatory comments, and personal or political attacks
26
+ * Public or private harassment
27
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
28
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
29
+
30
+ ## Our Responsibilities
31
+
32
+ Project maintainers are responsible for clarifying the standards of acceptable
33
+ behavior and are expected to take appropriate and fair corrective action in
34
+ response to any instances of unacceptable behavior.
35
+
36
+ Project maintainers have the right and responsibility to remove, edit, or
37
+ reject comments, commits, code, wiki edits, issues, and other contributions
38
+ that are not aligned to this Code of Conduct, or to ban temporarily or
39
+ permanently any contributor for other behaviors that they deem inappropriate,
40
+ threatening, offensive, or harmful.
41
+
42
+ Moreover, project maintainers will strive to offer feedback and advice to
43
+ ensure quality and consistency of contributions to the code. Contributions
44
+ from outside the group of project maintainers are strongly welcomed but the
45
+ final decision as to whether commits are merged into the codebase rests with
46
+ the team of project maintainers.
47
+
48
+ ## Scope
49
+
50
+ This Code of Conduct applies both within project spaces and in public spaces
51
+ when an individual is representing the project or its community. Examples of
52
+ representing a project or community include using an official project e-mail
53
+ address, posting via an official social media account, or acting as an
54
+ appointed representative at an online or offline event. Representation of a
55
+ project may be further defined and clarified by project maintainers.
56
+
57
+ ## Enforcement
58
+
59
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
60
+ reported by contacting the project team at 'Thomas.Rocke@warwick.ac.uk'. The project team will
61
+ review and investigate all complaints, and will respond in a way that it deems
62
+ appropriate to the circumstances. The project team is obligated to maintain
63
+ confidentiality with regard to the reporter of an incident. Further details of
64
+ specific enforcement policies may be posted separately.
65
+
66
+ Project maintainers who do not follow or enforce the Code of Conduct in good
67
+ faith may face temporary or permanent repercussions as determined by other
68
+ members of the project's leadership.
69
+
70
+ ## Attribution
71
+
72
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
73
+ version 1.4, available at
74
+ [http://contributor-covenant.org/version/1/4][version]
75
+
76
+ [homepage]: http://contributor-covenant.org
77
+ [version]: http://contributor-covenant.org/version/1/4/
ase_uhal-0.1.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+
2
+ MIT License
3
+
4
+ Copyright (c) 2025 Thomas Rocke
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CODE_OF_CONDUCT.md
4
+
5
+ global-exclude *.py[cod] __pycache__ *.so
6
+ prune ase_uhal/tests
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: ase-uhal
3
+ Version: 0.1.0
4
+ Summary: Implementation of 'Universal HyperActive Learning' compatible with the Atomic Simulation Environment (ASE)
5
+ Author-email: Thomas Rocke <Thomas.Rocke@warwick.ac.uk>, James Kermode <J.R.Kermode@warwick.ac.uk>
6
+ License-Expression: MIT
7
+ Project-URL: Source, https://github.com/kermodegroup/ase_uhal
8
+ Project-URL: Documentation, https://kermodegroup.github.io/ase_uhal/
9
+ Project-URL: Bug Tracker, https://github.com/kermodegroup/ase_uhal/issues
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
18
+ Classifier: Topic :: Scientific/Engineering :: Physics
19
+ Classifier: Development Status :: 3 - Alpha
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: ase
24
+ Requires-Dist: numpy
25
+ Requires-Dist: scipy
26
+ Provides-Extra: mace
27
+ Requires-Dist: mace-torch; extra == "mace"
28
+ Requires-Dist: torch; extra == "mace"
29
+ Requires-Dist: e3nn; extra == "mace"
30
+ Provides-Extra: ace
31
+ Requires-Dist: juliacall; extra == "ace"
32
+ Requires-Dist: juliapkg; extra == "ace"
33
+ Provides-Extra: docs
34
+ Requires-Dist: Sphinx; extra == "docs"
35
+ Requires-Dist: pydata-sphinx-theme; extra == "docs"
36
+ Requires-Dist: sphinxcontrib-bibtex>2.6; extra == "docs"
37
+ Requires-Dist: nbsphinx; extra == "docs"
38
+ Requires-Dist: ipython; extra == "docs"
39
+ Requires-Dist: ipykernel; extra == "docs"
40
+ Requires-Dist: pypandoc; extra == "docs"
41
+ Requires-Dist: sphinx_design; extra == "docs"
42
+ Requires-Dist: sphinx-copybutton; extra == "docs"
43
+ Requires-Dist: nglview; extra == "docs"
44
+ Requires-Dist: ase_uhal[ace,mace]; extra == "docs"
45
+ Provides-Extra: test
46
+ Requires-Dist: pytest>=6.1.2; extra == "test"
47
+ Requires-Dist: pytest_allclose; extra == "test"
48
+ Requires-Dist: ase_uhal[ace,mace]; extra == "test"
49
+ Dynamic: license-file
50
+
51
+ ase_uhal
52
+ ==============================
53
+ [//]: # (Badges)
54
+ [![GitHub Actions Build Status](https://github.com/kermodegroup/ase_uhal/workflows/CI/badge.svg)](https://github.com/kermodegroup/ase_uhal/actions?query=workflow%3ACI)
55
+ [![codecov](https://codecov.io/gh/kermodegroup/ase_uhal/branch/main/graph/badge.svg)](https://codecov.io/gh/kermodegroup/ase_uhal/branch/main)
56
+
57
+
58
+ Implementation of "Universal HyperActive Learning" compatible with the Atomic Simulation Environment (ASE)
59
+
60
+ ### Documentation
61
+ Documentation is available at https://kermodegroup.github.io/ase_uhal/
62
+
63
+
64
+ ### Base Installation
65
+ Requires:
66
+ - Python >= 3.10
67
+ - Julia >= 1.11 (for ACE descriptor features)
68
+
69
+ **_NOTE:_** This package is intended to always be used in conjunction with additional dependencies, see the next section for more information.
70
+
71
+ Basic installation can be achieved via pip
72
+ ```bash
73
+ pip install ase-uhal
74
+
75
+ ```
76
+
77
+ You can also clone the Git repository:
78
+ ```bash
79
+ git clone https://github.com/kermodegroup/ase_uhal.git
80
+ cd ase_uhal
81
+ pip install .
82
+ ```
83
+
84
+ ### Extra Dependencies
85
+ `ase_uhal` supports interfaces to multiple MLIP architectures. To avoid a very large number of mandatory dependencies, specific requirements for each MLIP model are implemented as optional dependencies to this package. For example, to install the MACE compatibility,
86
+ ```bash
87
+ pip install ase-uhal[mace]
88
+ ```
89
+
90
+ #### ACE Installation
91
+ ACE installation is more complex, as it requires a connection between Python and Julia, both with the correct modules installed. This is handled by `pyjuliapkg`, and can be achieved via:
92
+ ```bash
93
+ pip install .[ace]
94
+ python -c "import ase_uhal; ase_uhal.install_ace_deps()"
95
+ ```
96
+ For more details on this, including customising the Julia installation, see the documentation.
97
+
98
+ ### Copyright
99
+
100
+ Copyright (c) 2025, Thomas Rocke
101
+
102
+
103
+ #### Acknowledgements
104
+
105
+ Project based on the
106
+ [Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version 1.11.
@@ -0,0 +1,56 @@
1
+ ase_uhal
2
+ ==============================
3
+ [//]: # (Badges)
4
+ [![GitHub Actions Build Status](https://github.com/kermodegroup/ase_uhal/workflows/CI/badge.svg)](https://github.com/kermodegroup/ase_uhal/actions?query=workflow%3ACI)
5
+ [![codecov](https://codecov.io/gh/kermodegroup/ase_uhal/branch/main/graph/badge.svg)](https://codecov.io/gh/kermodegroup/ase_uhal/branch/main)
6
+
7
+
8
+ Implementation of "Universal HyperActive Learning" compatible with the Atomic Simulation Environment (ASE)
9
+
10
+ ### Documentation
11
+ Documentation is available at https://kermodegroup.github.io/ase_uhal/
12
+
13
+
14
+ ### Base Installation
15
+ Requires:
16
+ - Python >= 3.10
17
+ - Julia >= 1.11 (for ACE descriptor features)
18
+
19
+ **_NOTE:_** This package is intended to always be used in conjunction with additional dependencies, see the next section for more information.
20
+
21
+ Basic installation can be achieved via pip
22
+ ```bash
23
+ pip install ase-uhal
24
+
25
+ ```
26
+
27
+ You can also clone the Git repository:
28
+ ```bash
29
+ git clone https://github.com/kermodegroup/ase_uhal.git
30
+ cd ase_uhal
31
+ pip install .
32
+ ```
33
+
34
+ ### Extra Dependencies
35
+ `ase_uhal` supports interfaces to multiple MLIP architectures. To avoid a very large number of mandatory dependencies, specific requirements for each MLIP model are implemented as optional dependencies to this package. For example, to install the MACE compatibility,
36
+ ```bash
37
+ pip install ase-uhal[mace]
38
+ ```
39
+
40
+ #### ACE Installation
41
+ ACE installation is more complex, as it requires a connection between Python and Julia, both with the correct modules installed. This is handled by `pyjuliapkg`, and can be achieved via:
42
+ ```bash
43
+ pip install .[ace]
44
+ python -c "import ase_uhal; ase_uhal.install_ace_deps()"
45
+ ```
46
+ For more details on this, including customising the Julia installation, see the documentation.
47
+
48
+ ### Copyright
49
+
50
+ Copyright (c) 2025, Thomas Rocke
51
+
52
+
53
+ #### Acknowledgements
54
+
55
+ Project based on the
56
+ [Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version 1.11.
@@ -0,0 +1,6 @@
1
+ """Implementation of "Universal HyperActive Learning" compatible with the Atomic Simulation Environment (ASE)"""
2
+
3
+ # Add imports here
4
+ from .structure_selector import StructureSelector
5
+ from .ace_installer import install_ace_deps
6
+ from ._version import __version__
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,22 @@
1
+
2
+ def install_ace_deps():
3
+ try:
4
+ import juliapkg
5
+ except ImportError as e:
6
+ err_text = ("ase_uhal is not installed with ACE compatibility.\n"
7
+ + " "*13 # Indentation
8
+ + "Run `pip install ase_uhal[ace]` to resolve"
9
+ )
10
+ raise ImportError(err_text) from e
11
+
12
+ juliapkg.resolve() # Initial resolve to make sure general registry exists
13
+ juliapkg.add("JSON")
14
+ juliapkg.add("Unitful")
15
+ juliapkg.add("AtomsBase")
16
+ juliapkg.add("AtomsCalculators")
17
+ # juliapkg does not yet seem to support >= specifiers
18
+ # Hack a >= using wildcard version bounds 0.10 - 0.* === [0.10.0, 1.0.0)
19
+ juliapkg.add("ACEpotentials", version="0.10 - 0")
20
+
21
+ # resolve() tries to download and install packages which were missing or at incorrect versions
22
+ juliapkg.resolve()
@@ -0,0 +1,153 @@
1
+ '''
2
+ ase-compatible HAL-style bias calculator, using the committee error as an energy bias.
3
+
4
+ '''
5
+ from ase.calculators.calculator import Calculator
6
+ import numpy as np
7
+ from .committee_calculators.base_committee_calculator import BaseCommitteeCalculator
8
+ from abc import ABCMeta, abstractmethod
9
+ from ase.stress import voigt_6_to_full_3x3_stress
10
+
11
+ class BaseBiasCalculator(Calculator, metaclass=ABCMeta):
12
+ '''
13
+ ASE-compatible Bias calculator with adaptive biasing
14
+
15
+ Derived from a combination of ACEHAL.bias_calc.BiasCalculator and ACEHAL.bias_calc.TauRelController from ACEHAL
16
+ https://github.com/ACEsuit/ACEHAL/blob/main/ACEHAL/bias_calc.py
17
+
18
+ '''
19
+ implemented_properties = ['energy', 'forces', 'stress']
20
+ default_parameters = {}
21
+ name = 'HALCalculator'
22
+
23
+ def __init__(self, mean_calc, committee_calc:BaseCommitteeCalculator, adaptive_tau=False, tau_rel=0.1, tau_hist=10, tau_delay=None, eps=0.2):
24
+ '''
25
+ '''
26
+
27
+ super().__init__()
28
+ self.mean_calc = mean_calc
29
+ self.committee_calc = committee_calc
30
+ self.adapt_tau = adaptive_tau
31
+ self.tau_rel = tau_rel
32
+ self.tau_hist = tau_hist
33
+ if tau_delay is not None:
34
+ self.tau_delay = tau_delay
35
+ else:
36
+ self.tau_delay = tau_hist
37
+
38
+ self._tau_delay = self.tau_delay
39
+
40
+ self.tau = 0 # Default to no mixing, until specified by user, or changed by adaptive mode
41
+ self.Fmean = None
42
+ self.Fbias = None
43
+ self.eps = eps
44
+
45
+ # Validation
46
+ assert self.tau_rel > 0
47
+ assert self.mixing > 0
48
+ assert self.tau_delay > 0
49
+
50
+ @property
51
+ def mixing(self):
52
+ return 1/self.tau_hist
53
+
54
+ @mixing.setter
55
+ def mixing(self, mixing):
56
+ self.tau_hist = 1/mixing
57
+
58
+ def calculate(self, atoms, properties, system_changes):
59
+ '''
60
+ Overload of the BaseCalculator.calculate() abstract method
61
+ Calculate props combining the results from the mean_calc with the results from the committee
62
+ '''
63
+ super().calculate(atoms, properties, system_changes)
64
+
65
+ if len(system_changes):
66
+ self.results = {}
67
+
68
+ assert self.tau is not None
69
+
70
+ self.committee_calc.calculate(atoms, ["bias_" + prop for prop in properties], system_changes)
71
+
72
+ self.mean_calc.calculate(atoms, properties, system_changes)
73
+
74
+ for prop in self.implemented_properties:
75
+ if prop in properties:
76
+ mean_prop = self.mean_calc.results[prop]
77
+ if prop == "stress" and mean_prop.shape != (3, 3):
78
+ mean_prop = voigt_6_to_full_3x3_stress(mean_prop)
79
+ # Use get_property as an interface to committee_calc, as torch-based comm calcs will use torch.Tensor in self.results
80
+ self.results[prop] = mean_prop - self.tau * self.committee_calc.get_property("bias_" + prop, atoms)
81
+
82
+ def update_tau(self, atoms=None):
83
+ '''
84
+ Exponential mixing of mean force magnitude and mean biasing force magnitude
85
+ (without the tau biasing constant)
86
+
87
+ Updates self.Fmean and self.Fbias based on self.mixing to mix between old values
88
+ and the new values provided as arguments
89
+ Modifies self.tau if self.tau_delay < 0, otherwise decreases self.tau_delay by 1
90
+ '''
91
+ Fmean = np.mean(np.linalg.norm(self.get_property("forces", atoms), axis=-1))
92
+ Fbias = np.mean(np.linalg.norm(self.committee_calc.get_property("bias_forces", atoms), axis=-1))
93
+
94
+ if self.Fmean is None or self.Fbias is None:
95
+ self.Fmean = Fmean
96
+ self.Fbias = Fbias
97
+ else:
98
+ self.Fmean = (1-self.mixing) * self.Fmean + self.mixing * Fmean
99
+ self.Fbias = (1-self.mixing) * self.Fbias + self.mixing * Fbias
100
+
101
+ if self._tau_delay > 0:
102
+ # Positive delay means tau should not yet be updated
103
+ # Updates to self.Fmean and self.Fbias needed to ensure
104
+ # smooth averaging when tau can be changed
105
+ self._tau_delay -= 1
106
+ else:
107
+ self.tau = self.tau_rel * (self.Fmean / self.Fbias)
108
+
109
+ def reset_tau(self):
110
+ '''
111
+ Sets the biasing strength to zero, and resets the internal tau mixing state
112
+ '''
113
+
114
+ self.tau = 0
115
+ self.Fmean = None
116
+ self.Fbias = None
117
+ self._tau_delay = self.tau_delay
118
+
119
+ @abstractmethod
120
+ def get_score(self, atoms=None):
121
+ pass
122
+
123
+ def select_structure(self, ats):
124
+ '''
125
+ Alias for self.committee_calc.select_structure
126
+ '''
127
+ self.committee_calc.select_structure(ats)
128
+
129
+ def resample_committee(self, committee_size=None):
130
+ '''
131
+ Alias for self.committee_calc.resample_committee
132
+ '''
133
+ self.committee_calc.resample_committee(committee_size)
134
+
135
+ def sync(self):
136
+ '''
137
+ Alias of self.committee_calc.sync()
138
+ '''
139
+ self.committee_calc.sync()
140
+
141
+ class HALBiasCalculator(BaseBiasCalculator):
142
+ '''
143
+ Bias calculator with HAL scoring metric
144
+ '''
145
+ def get_score(self, atoms=None):
146
+ Fmean = np.linalg.norm(self.get_property("forces", atoms), axis=-1)
147
+ Fbias = np.linalg.norm(self.committee_calc.get_property("bias_forces", atoms), axis=-1)
148
+
149
+ F = Fbias / (Fmean + self.eps)
150
+
151
+ s = np.exp(F) / (np.sum(np.exp(F)) + self.eps) # Apply softmax
152
+
153
+ return np.max(s)
@@ -0,0 +1,4 @@
1
+ from .ace_committee_calculator import ACE1Calculator, ACEHALCalculator
2
+ from .mace_committee_calculator import MACEHALCalculator
3
+ from .base_committee_calculator import BaseCommitteeCalculator
4
+ from .torch_committee_calculator import TorchCommitteeCalculator
@@ -0,0 +1,172 @@
1
+ from .base_committee_calculator import BaseCommitteeCalculator, HALBiasPotential, Calculator
2
+ import os
3
+ import numpy as np
4
+ from abc import ABCMeta, abstractmethod
5
+
6
+ file_root = os.path.dirname(os.path.abspath(__file__))
7
+
8
+ class BaseACECalculator(BaseCommitteeCalculator, metaclass=ABCMeta):
9
+ implemented_properties = ['energy', 'forces', 'stress', 'desc_energy', 'desc_forces', 'desc_stress',
10
+ 'comm_energy', 'comm_forces', 'comm_stress', 'bias_energy', 'bias_forces', 'bias_stress']
11
+ def __init__(self, ace_params, committee_size, prior_weight, **kwargs):
12
+ '''
13
+ Parameters
14
+ ----------
15
+ ace_params: string or dict
16
+ If ace_params is a string: Use ACEpotentials.load_model to load the model json file given by ace_params
17
+ If ace_params is a dict: interpret ace_params as the hyperparameters dict for ACEpotentials.ace1_model e.g.
18
+
19
+ .. code-block:: python
20
+
21
+ ace_params = {"elements" : ["Si"], # Expects list of str
22
+ "order" : 3, # Expects an int
23
+ "totaldegree" : 10, # Expects an int
24
+ "rcut" : 5.0 # Expects a float
25
+ }
26
+
27
+
28
+ committee_size: int
29
+ Number of members in the linear committee
30
+ prior_weight: float
31
+ Weight corresponding to the prior matrix in the linear system
32
+ **kwargs: Keyword Args
33
+ Extra keywork arguments fed to :class:`~ase_uhal.committee_calculators.BaseCommitteeCalculator`
34
+
35
+ '''
36
+
37
+ from juliacall import Main as jl
38
+
39
+
40
+ self.jl = jl
41
+ # ACEpotentials, plus some utilities
42
+ self.jl.seval('include("' + os.path.normpath(file_root + "/../data/_ace_utils.jl") + '")')
43
+
44
+ if type(ace_params) == str:
45
+ # assume filename
46
+ self.model = self.jl.load_ace(ace_params)
47
+ else:
48
+ # assume set of ace hyperparameters
49
+ if type(ace_params) == list:
50
+ elements, order, totaldegree, rcut = ace_params
51
+ else: # Dict
52
+ elements = ace_params["elements"]
53
+ order = ace_params["order"]
54
+ totaldegree = ace_params["totaldegree"]
55
+ rcut = ace_params["rcut"]
56
+ self.model = self.jl.model_from_params(elements, order, totaldegree, rcut)
57
+
58
+ descriptor_size = self.jl.length_basis(self.model)
59
+
60
+ super().__init__(committee_size, descriptor_size, prior_weight, **kwargs)
61
+
62
+ def _prep_atoms(self, atoms):
63
+ '''
64
+ Convert from ase atoms into the AtomsBase AbstractSystem, using ASEconvert
65
+ '''
66
+ numbers = atoms.get_atomic_numbers()
67
+ positions = atoms.positions
68
+ cell = atoms.cell[:, :]
69
+ pbc = atoms.pbc
70
+
71
+ return self.jl.convert_ats(numbers, positions, cell, pbc)
72
+
73
+ @abstractmethod
74
+ def _bias_energy(self, comm_energy):
75
+ pass
76
+
77
+ @abstractmethod
78
+ def _bias_forces(self, comm_forces, comm_energy):
79
+ pass
80
+
81
+ @abstractmethod
82
+ def _bias_stress(self, comm_stress, comm_energy):
83
+ pass
84
+
85
+ def calculate(self, atoms, properties, system_changes):
86
+ '''
87
+ Calculation for descriptor properties, committee properties, normal properties, and HAL properties
88
+
89
+ Descriptor properties use a "desc_" prefix, committee properties use "comm_", HAL properties use "hal_".
90
+
91
+ '''
92
+ super().calculate(atoms, properties, system_changes)
93
+
94
+ if "desc_energy" not in self.results.keys():
95
+ # System has changed, need to recalculate base descriptors
96
+ E, F, V = self.jl.eval_basis(self._prep_atoms(atoms), self.model)
97
+
98
+ self.results["desc_energy"] = np.array(E)
99
+ self.results["desc_forces"] = np.array(F)
100
+ self.results["desc_stress"] = -np.array(V) / atoms.get_volume()
101
+
102
+ for key in ["energy", "forces", "stress"]:
103
+ if "comm_" + key in properties or key in properties or "bias_" + key in properties or key == "energy":
104
+ # Always calculate energy properties, as committee energies
105
+ # needed for force and stress bias calc
106
+ comm_prop = np.tensordot(self.committee_weights, self.results["desc_" + key], axes=1)
107
+ self.results["comm_" + key] = comm_prop
108
+
109
+ self.results[key] = np.mean(comm_prop, axis=0)
110
+
111
+ if "bias_energy" in properties:
112
+ self.results["bias_energy"] = self._bias_energy(self.results["comm_energy"])
113
+
114
+ if "bias_forces" in properties:
115
+ self.results["bias_forces"] = self._bias_forces(self.results["comm_forces"], self.results["comm_energy"])
116
+
117
+ if "bias_stress" in properties:
118
+ self.results["bias_stress"] = self._bias_stress(self.results["comm_stress"], self.results["comm_energy"])
119
+
120
+
121
+ class ACE1Calculator(Calculator):
122
+ '''
123
+ Basic ACE1 ASE calculator interface, assumes json structure similar to the ACEpotentials tutorial example
124
+
125
+ NOTE: model_name = "ACE1" added to the hyperparameters dict
126
+
127
+ hyperparams = (elements = [:Ti, :Al],
128
+ order = 3,
129
+ totaldegree = 6,
130
+ rcut = 5.5,
131
+ Eref = [:Ti => -1586.0195, :Al => -105.5954],
132
+ model_name = "ACE1"
133
+ )
134
+
135
+ using JSON
136
+ open("TiAl_model.json", "w") do f
137
+ JSON.print(f, Dict("hyperparams" => hyperparams, "params" => model.ps))
138
+ end
139
+
140
+ '''
141
+ implemented_properties = ["energy", "forces", "stress"]
142
+ def __init__(self, pot_json):
143
+ super().__init__()
144
+
145
+ from juliacall import Main as jl
146
+ self.jl = jl
147
+ self.jl.seval('include("' + os.path.normpath(file_root + "/../data/_ace_utils.jl") + '")')
148
+
149
+ self.pot_json = pot_json
150
+
151
+
152
+ self.acemodel = jl.load_ace(pot_json, True)
153
+
154
+ def calculate(self, atoms, properties, system_changes):
155
+ super().calculate(atoms, properties, system_changes)
156
+ self.results = {}
157
+
158
+ jl_ats = self.jl.convert_ats(atoms.numbers, atoms.positions, atoms.cell[:, :], atoms.pbc)
159
+
160
+ E, F, V = self.jl.eval_observables(jl_ats, self.acemodel)
161
+
162
+ F = np.array(F).T; V = np.array(V)
163
+
164
+ S = -V/atoms.get_volume()
165
+
166
+ self.results["energy"] = E
167
+ self.results["forces"] = F
168
+ self.results["stress"] = S
169
+
170
+
171
+ class ACEHALCalculator(HALBiasPotential, BaseACECalculator):
172
+ name = "ACEHALCalculator"