matcalc 0.2.0__tar.gz → 0.2.2__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.
- {matcalc-0.2.0/src/matcalc.egg-info → matcalc-0.2.2}/PKG-INFO +18 -13
- {matcalc-0.2.0 → matcalc-0.2.2}/README.md +13 -12
- {matcalc-0.2.0 → matcalc-0.2.2}/pyproject.toml +20 -3
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/__init__.py +4 -1
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/base.py +63 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/benchmark.py +124 -36
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/cli.py +1 -1
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/config.py +1 -1
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/elasticity.py +10 -4
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/eos.py +3 -1
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/utils.py +3 -60
- {matcalc-0.2.0 → matcalc-0.2.2/src/matcalc.egg-info}/PKG-INFO +18 -13
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc.egg-info/requires.txt +6 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_benchmark.py +9 -21
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_chain.py +4 -2
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_cli.py +10 -1
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_elasticity.py +1 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_neb.py +1 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_phonon.py +1 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_qha.py +1 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_relaxation.py +15 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_stability.py +1 -0
- matcalc-0.2.2/tests/test_utils.py +168 -0
- matcalc-0.2.0/tests/test_utils.py +0 -157
- {matcalc-0.2.0 → matcalc-0.2.2}/LICENSE +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/setup.cfg +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/elemental_refs/MatPES-PBE-Element-Refs.json.gz +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/elemental_refs/MatPES-r2SCAN-Element-Refs.json.gz +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/neb.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/phonon.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/py.typed +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/qha.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/relaxation.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/stability.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc/units.py +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc.egg-info/SOURCES.txt +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc.egg-info/dependency_links.txt +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc.egg-info/entry_points.txt +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/src/matcalc.egg-info/top_level.txt +0 -0
- {matcalc-0.2.0 → matcalc-0.2.2}/tests/test_eos.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matcalc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Calculators for materials properties from the potential energy surface.
|
|
5
5
|
Author-email: Runze Liu <rul048@ucsd.edu>, Eliott Liu <elliottliu17@gmail.com>, Janosh Riebesell <janosh@lbl.gov>, Ji Qi <j1qi@ucsd.edu>, Shyue Ping Ong <ongsp@ucsd.edu>, Tsz Wai Ko <t1ko@ucsd.edu>
|
|
6
6
|
Keywords: AI,deep learning,force field,graph,interatomic potential,machine learning,materials,property prediction,science
|
|
@@ -41,11 +41,15 @@ Provides-Extra: grace
|
|
|
41
41
|
Requires-Dist: tensorpotential>=0.5.1; extra == "grace"
|
|
42
42
|
Provides-Extra: matgl
|
|
43
43
|
Requires-Dist: matgl>=1.2.3; extra == "matgl"
|
|
44
|
+
Provides-Extra: orb
|
|
45
|
+
Requires-Dist: orb-models>=0.4.2; extra == "orb"
|
|
46
|
+
Provides-Extra: ace
|
|
47
|
+
Requires-Dist: pyace>=0.1.1; extra == "ace"
|
|
44
48
|
Dynamic: license-file
|
|
45
49
|
|
|
46
50
|
<h1 align="center">
|
|
47
|
-
<img src="https://
|
|
48
|
-
|
|
51
|
+
<img src="https://raw.githubusercontent.com/materialsvirtuallab/matcalc/refs/heads/main/docs/assets/matcalc.png"
|
|
52
|
+
width="200" alt="MatCalc" style="vertical-align: middle;" /><br>
|
|
49
53
|
</h1>
|
|
50
54
|
|
|
51
55
|
[](https://github.com/materialsvirtuallab/matcalc/workflows/Testing/badge.svg)
|
|
@@ -87,12 +91,12 @@ MatCalc provides convenient methods to quickly compute properties, using a minim
|
|
|
87
91
|
an example of a computation of the elastic constants of Si using the `TensorNet-MatPES-PBE-v2025.1-PES` universal MLIP.
|
|
88
92
|
|
|
89
93
|
```python
|
|
90
|
-
from matcalc import PESCalculator, ElasticityCalc
|
|
94
|
+
from matcalc import PESCalculator, ElasticityCalc, load_up
|
|
91
95
|
from pymatgen.ext.matproj import MPRester
|
|
92
96
|
|
|
93
97
|
mpr = MPRester()
|
|
94
98
|
si = mpr.get_structure_by_material_id("mp-149")
|
|
95
|
-
c = ElasticityCalc(
|
|
99
|
+
c = ElasticityCalc(load_up("TensorNet-MatPES-PBE-v2025.1-PES"), relax_structure=True)
|
|
96
100
|
props = c.calc(si)
|
|
97
101
|
print(f"K_VRH = {props['bulk_modulus_vrh'] * 160.2176621} GPa")
|
|
98
102
|
```
|
|
@@ -103,9 +107,9 @@ While we generally recommend users to specify exactly the model they would like
|
|
|
103
107
|
(case-insensitive) aliases to our recommended models for PBE and r2SCAN predictions. These can be loaded using:
|
|
104
108
|
|
|
105
109
|
```python
|
|
106
|
-
from matcalc import
|
|
107
|
-
pbe_calculator =
|
|
108
|
-
r2scan_calculator =
|
|
110
|
+
from matcalc import load_up
|
|
111
|
+
pbe_calculator = load_up("pbe")
|
|
112
|
+
r2scan_calculator = load_up("r2scan")
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
At the time of writing, these are the TensorNet-MatPES models. However, these recommendations may updated as improved
|
|
@@ -138,9 +142,9 @@ computed by all steps. Note that the `relax_structure` should be set to False in
|
|
|
138
142
|
do not redo the relatively expensive relaxation.
|
|
139
143
|
|
|
140
144
|
```python
|
|
141
|
-
from matcalc import
|
|
145
|
+
from matcalc import load_up, ElasticityCalc, RelaxCalc, EnergeticsCalc, ChainedCalc
|
|
142
146
|
import numpy as np
|
|
143
|
-
calculator =
|
|
147
|
+
calculator = load_up("pbe")
|
|
144
148
|
relax_calc = RelaxCalc(
|
|
145
149
|
calculator,
|
|
146
150
|
optimizer="FIRE",
|
|
@@ -160,7 +164,8 @@ elast_calc = ElasticityCalc(
|
|
|
160
164
|
relax_structure=False, # Since we are chaining, we do not need to relax structure in later steps.
|
|
161
165
|
relax_deformed_structures=True,
|
|
162
166
|
)
|
|
163
|
-
|
|
167
|
+
prop_calc = ChainedCalc([relax_calc, energetics_calc, elast_calc])
|
|
168
|
+
results = prop_calc.calc(structure)
|
|
164
169
|
```
|
|
165
170
|
|
|
166
171
|
Chaining can also be used with the `calc_many` method, with parallelization.
|
|
@@ -181,8 +186,8 @@ the `MatCalc-Benchmark`.
|
|
|
181
186
|
For example, the following code can be used to run the ElasticityBenchmark on `TensorNet-MatPES-PBE-v2025.1-PES` UMLIP.
|
|
182
187
|
|
|
183
188
|
```python
|
|
184
|
-
from matcalc import
|
|
185
|
-
calculator =
|
|
189
|
+
from matcalc import load_up
|
|
190
|
+
calculator = load_up("TensorNet-MatPES-PBE-v2025.1-PES")
|
|
186
191
|
from matcalc.benchmark import ElasticityBenchmark
|
|
187
192
|
benchmark = ElasticityBenchmark(fmax=0.05, relax_structure=True)
|
|
188
193
|
results = benchmark.run(calculator, "TensorNet-MatPES")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1 align="center">
|
|
2
|
-
<img src="https://
|
|
3
|
-
|
|
2
|
+
<img src="https://raw.githubusercontent.com/materialsvirtuallab/matcalc/refs/heads/main/docs/assets/matcalc.png"
|
|
3
|
+
width="200" alt="MatCalc" style="vertical-align: middle;" /><br>
|
|
4
4
|
</h1>
|
|
5
5
|
|
|
6
6
|
[](https://github.com/materialsvirtuallab/matcalc/workflows/Testing/badge.svg)
|
|
@@ -42,12 +42,12 @@ MatCalc provides convenient methods to quickly compute properties, using a minim
|
|
|
42
42
|
an example of a computation of the elastic constants of Si using the `TensorNet-MatPES-PBE-v2025.1-PES` universal MLIP.
|
|
43
43
|
|
|
44
44
|
```python
|
|
45
|
-
from matcalc import PESCalculator, ElasticityCalc
|
|
45
|
+
from matcalc import PESCalculator, ElasticityCalc, load_up
|
|
46
46
|
from pymatgen.ext.matproj import MPRester
|
|
47
47
|
|
|
48
48
|
mpr = MPRester()
|
|
49
49
|
si = mpr.get_structure_by_material_id("mp-149")
|
|
50
|
-
c = ElasticityCalc(
|
|
50
|
+
c = ElasticityCalc(load_up("TensorNet-MatPES-PBE-v2025.1-PES"), relax_structure=True)
|
|
51
51
|
props = c.calc(si)
|
|
52
52
|
print(f"K_VRH = {props['bulk_modulus_vrh'] * 160.2176621} GPa")
|
|
53
53
|
```
|
|
@@ -58,9 +58,9 @@ While we generally recommend users to specify exactly the model they would like
|
|
|
58
58
|
(case-insensitive) aliases to our recommended models for PBE and r2SCAN predictions. These can be loaded using:
|
|
59
59
|
|
|
60
60
|
```python
|
|
61
|
-
from matcalc import
|
|
62
|
-
pbe_calculator =
|
|
63
|
-
r2scan_calculator =
|
|
61
|
+
from matcalc import load_up
|
|
62
|
+
pbe_calculator = load_up("pbe")
|
|
63
|
+
r2scan_calculator = load_up("r2scan")
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
At the time of writing, these are the TensorNet-MatPES models. However, these recommendations may updated as improved
|
|
@@ -93,9 +93,9 @@ computed by all steps. Note that the `relax_structure` should be set to False in
|
|
|
93
93
|
do not redo the relatively expensive relaxation.
|
|
94
94
|
|
|
95
95
|
```python
|
|
96
|
-
from matcalc import
|
|
96
|
+
from matcalc import load_up, ElasticityCalc, RelaxCalc, EnergeticsCalc, ChainedCalc
|
|
97
97
|
import numpy as np
|
|
98
|
-
calculator =
|
|
98
|
+
calculator = load_up("pbe")
|
|
99
99
|
relax_calc = RelaxCalc(
|
|
100
100
|
calculator,
|
|
101
101
|
optimizer="FIRE",
|
|
@@ -115,7 +115,8 @@ elast_calc = ElasticityCalc(
|
|
|
115
115
|
relax_structure=False, # Since we are chaining, we do not need to relax structure in later steps.
|
|
116
116
|
relax_deformed_structures=True,
|
|
117
117
|
)
|
|
118
|
-
|
|
118
|
+
prop_calc = ChainedCalc([relax_calc, energetics_calc, elast_calc])
|
|
119
|
+
results = prop_calc.calc(structure)
|
|
119
120
|
```
|
|
120
121
|
|
|
121
122
|
Chaining can also be used with the `calc_many` method, with parallelization.
|
|
@@ -136,8 +137,8 @@ the `MatCalc-Benchmark`.
|
|
|
136
137
|
For example, the following code can be used to run the ElasticityBenchmark on `TensorNet-MatPES-PBE-v2025.1-PES` UMLIP.
|
|
137
138
|
|
|
138
139
|
```python
|
|
139
|
-
from matcalc import
|
|
140
|
-
calculator =
|
|
140
|
+
from matcalc import load_up
|
|
141
|
+
calculator = load_up("TensorNet-MatPES-PBE-v2025.1-PES")
|
|
141
142
|
from matcalc.benchmark import ElasticityBenchmark
|
|
142
143
|
benchmark = ElasticityBenchmark(fmax=0.05, relax_structure=True)
|
|
143
144
|
results = benchmark.run(calculator, "TensorNet-MatPES")
|
|
@@ -42,9 +42,9 @@ dependencies = [
|
|
|
42
42
|
"pymatgen",
|
|
43
43
|
"numpy<2.0.0",
|
|
44
44
|
"fsspec",
|
|
45
|
-
"scikit-learn>=1.6.1"
|
|
45
|
+
"scikit-learn>=1.6.1"
|
|
46
46
|
]
|
|
47
|
-
version = "0.2.
|
|
47
|
+
version = "0.2.2"
|
|
48
48
|
|
|
49
49
|
[project.optional-dependencies]
|
|
50
50
|
phonon = ["seekpath"]
|
|
@@ -67,6 +67,12 @@ grace = [
|
|
|
67
67
|
matgl = [
|
|
68
68
|
"matgl>=1.2.3",
|
|
69
69
|
]
|
|
70
|
+
orb = [
|
|
71
|
+
"orb-models>=0.4.2",
|
|
72
|
+
]
|
|
73
|
+
ace = [
|
|
74
|
+
"pyace>=0.1.1",
|
|
75
|
+
]
|
|
70
76
|
|
|
71
77
|
[project.scripts]
|
|
72
78
|
matcalc = "matcalc.cli:main"
|
|
@@ -84,8 +90,10 @@ build-backend = "setuptools.build_meta"
|
|
|
84
90
|
|
|
85
91
|
[dependency-groups]
|
|
86
92
|
dev = [
|
|
93
|
+
"codecov-cli>=10.3.0",
|
|
87
94
|
"coverage>=7.7.1",
|
|
88
95
|
"coveralls>=4.0.1",
|
|
96
|
+
"ipython>=8.34.0",
|
|
89
97
|
"jupyter>=1.1.1",
|
|
90
98
|
"maml>=2025.2.25",
|
|
91
99
|
"matgl>=1.2.3",
|
|
@@ -102,13 +110,21 @@ lint = [
|
|
|
102
110
|
"ruff>=0.11.2",
|
|
103
111
|
]
|
|
104
112
|
maintain = [
|
|
113
|
+
"docutils>=0.21.2",
|
|
105
114
|
"invoke>=2.2.0",
|
|
106
115
|
"sphinx>=8.1.3",
|
|
107
116
|
"sphinx-markdown-builder>=0.6.8",
|
|
108
117
|
]
|
|
118
|
+
test-models = [
|
|
119
|
+
"mace-torch>=0.3.12",
|
|
120
|
+
"orb-models>=0.4.2",
|
|
121
|
+
"pynanoflann>=0.10.0",
|
|
122
|
+
"sevenn>=0.10.4",
|
|
123
|
+
"tensorpotential>=0.5.1",
|
|
124
|
+
]
|
|
109
125
|
|
|
110
126
|
[tool.ruff]
|
|
111
|
-
target-version = "
|
|
127
|
+
target-version = "py310"
|
|
112
128
|
line-length = 120
|
|
113
129
|
extend-include = ["*.ipynb"]
|
|
114
130
|
|
|
@@ -168,6 +184,7 @@ exclude_lines = [
|
|
|
168
184
|
"except PackageNotFoundError:",
|
|
169
185
|
"if 0:",
|
|
170
186
|
"if TYPE_CHECKING:",
|
|
187
|
+
"if typing.TYPE_CHECKING:",
|
|
171
188
|
"if __name__ == .__main__.:",
|
|
172
189
|
"if self.debug:",
|
|
173
190
|
"if settings.DEBUG",
|
|
@@ -9,7 +9,7 @@ try:
|
|
|
9
9
|
except PackageNotFoundError:
|
|
10
10
|
pass # package not installed
|
|
11
11
|
|
|
12
|
-
from .base import PropCalc
|
|
12
|
+
from .base import ChainedCalc, PropCalc
|
|
13
13
|
from .config import clear_cache
|
|
14
14
|
from .elasticity import ElasticityCalc
|
|
15
15
|
from .eos import EOSCalc
|
|
@@ -19,3 +19,6 @@ from .qha import QHACalc
|
|
|
19
19
|
from .relaxation import RelaxCalc
|
|
20
20
|
from .stability import EnergeticsCalc
|
|
21
21
|
from .utils import UNIVERSAL_CALCULATORS, PESCalculator
|
|
22
|
+
|
|
23
|
+
# Provide an alias for loading calculators quickly.
|
|
24
|
+
load_up = PESCalculator.load_universal
|
|
@@ -78,3 +78,66 @@ class PropCalc(abc.ABC):
|
|
|
78
78
|
else:
|
|
79
79
|
_func = self.calc # type: ignore[assignment]
|
|
80
80
|
return parallel(delayed(_func)(s) for s in structures)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ChainedCalc(PropCalc):
|
|
84
|
+
"""A chained calculator that runs a series of PropCalcs on a structure or set of structures.
|
|
85
|
+
|
|
86
|
+
Often, you may want to obtain multiple properties at once, e.g., perform a relaxation with a formation energy
|
|
87
|
+
computation and a elasticity calculation. This can be done using this class by supplying a list of calculators.
|
|
88
|
+
Note that it is likely
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, prop_calcs: Sequence[PropCalc]) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Initialize a chained calculator.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
prop_calcs: Sequence of prop calcs.
|
|
97
|
+
"""
|
|
98
|
+
self.prop_calcs = tuple(prop_calcs)
|
|
99
|
+
|
|
100
|
+
def calc(self, structure: Structure | dict[str, Any]) -> dict[str, Any]:
|
|
101
|
+
"""
|
|
102
|
+
Runs the series of PropCalcs on a structure.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
structure: Pymatgen structure or a dict containing a pymatgen Structure under a "final_structure" or
|
|
106
|
+
"structure" key. Allowing dicts provide the means to chain calculators, e.g., do a relaxation followed
|
|
107
|
+
by an elasticity calculation.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
dict[str, Any]: In the form {"prop_name": value}.
|
|
111
|
+
"""
|
|
112
|
+
results = structure # type:ignore[assignment]
|
|
113
|
+
for prop_calc in self.prop_calcs:
|
|
114
|
+
results = prop_calc.calc(results) # type:ignore[assignment]
|
|
115
|
+
return results # type:ignore[return-value]
|
|
116
|
+
|
|
117
|
+
def calc_many(
|
|
118
|
+
self,
|
|
119
|
+
structures: Sequence[Structure | dict[str, Any]],
|
|
120
|
+
n_jobs: None | int = None,
|
|
121
|
+
allow_errors: bool = False, # noqa: FBT001,FBT002
|
|
122
|
+
**kwargs: Any,
|
|
123
|
+
) -> Generator[dict | None]:
|
|
124
|
+
"""Runs the sequence of PropCalc on many structures.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
structures: List or generator of Structures.
|
|
128
|
+
n_jobs: The maximum number of concurrently running jobs. If -1 all CPUs are used. For n_jobs below -1,
|
|
129
|
+
(n_cpus + 1 + n_jobs) are used. None is a marker for `unset` that will be interpreted as n_jobs=1
|
|
130
|
+
unless the call is performed under a parallel_config() context manager that sets another value for
|
|
131
|
+
n_jobs.
|
|
132
|
+
allow_errors: Whether to skip failed calculations. For these calculations, None will be returned. For
|
|
133
|
+
large scale calculations, you may want this to be True to avoid the entire calculation failing.
|
|
134
|
+
Defaults to False.
|
|
135
|
+
**kwargs: Passthrough to calc_many method of all PropCalcs.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Generator of dicts.
|
|
139
|
+
"""
|
|
140
|
+
results = structures # type:ignore[assignment]
|
|
141
|
+
for prop_calc in self.prop_calcs:
|
|
142
|
+
results = prop_calc.calc_many(results, n_jobs=n_jobs, allow_errors=allow_errors, **kwargs) # type:ignore[assignment]
|
|
143
|
+
return results # type:ignore[return-value]
|
|
@@ -7,20 +7,24 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
9
|
import random
|
|
10
|
-
import typing
|
|
11
10
|
from pathlib import Path
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
12
|
from urllib.parse import urlparse
|
|
13
13
|
|
|
14
14
|
import fsspec
|
|
15
15
|
import numpy as np
|
|
16
16
|
import pandas as pd
|
|
17
17
|
import requests
|
|
18
|
+
from matminer.featurizers.site import CrystalNNFingerprint
|
|
19
|
+
from matminer.featurizers.structure import SiteStatsFingerprint
|
|
18
20
|
from monty.json import MontyDecoder
|
|
19
21
|
from monty.serialization import dumpfn, loadfn
|
|
20
22
|
from pymatgen.io.ase import AseAtomsAdaptor
|
|
21
23
|
from scipy.optimize import curve_fit
|
|
22
24
|
|
|
23
|
-
if
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from collections.abc import Sequence
|
|
27
|
+
|
|
24
28
|
from ase.calculators.calculator import Calculator
|
|
25
29
|
|
|
26
30
|
from .base import PropCalc
|
|
@@ -28,7 +32,7 @@ if typing.TYPE_CHECKING:
|
|
|
28
32
|
from .config import BENCHMARK_DATA_DIR, BENCHMARK_DATA_DOWNLOAD_URL, BENCHMARK_DATA_URL
|
|
29
33
|
from .elasticity import ElasticityCalc
|
|
30
34
|
from .phonon import PhononCalc
|
|
31
|
-
from .
|
|
35
|
+
from .stability import EnergeticsCalc
|
|
32
36
|
from .units import eVA3ToGPa
|
|
33
37
|
|
|
34
38
|
logger = logging.getLogger(__name__)
|
|
@@ -119,7 +123,7 @@ class CheckpointFile:
|
|
|
119
123
|
return results, *[a[len(results) :] for a in args]
|
|
120
124
|
return [], *args
|
|
121
125
|
|
|
122
|
-
def save(self, results: list[dict[str,
|
|
126
|
+
def save(self, results: list[dict[str, Any]]) -> None:
|
|
123
127
|
"""
|
|
124
128
|
Saves a list of results at the specified checkpoint location.
|
|
125
129
|
|
|
@@ -161,7 +165,7 @@ class Benchmark(metaclass=abc.ABCMeta):
|
|
|
161
165
|
def __init__(
|
|
162
166
|
self,
|
|
163
167
|
benchmark_name: str | Path,
|
|
164
|
-
properties:
|
|
168
|
+
properties: Sequence[str],
|
|
165
169
|
index_name: str,
|
|
166
170
|
other_fields: tuple = (),
|
|
167
171
|
property_rename_map: dict[str, str] | None = None,
|
|
@@ -237,7 +241,7 @@ class Benchmark(metaclass=abc.ABCMeta):
|
|
|
237
241
|
self.ground_truth = rows
|
|
238
242
|
|
|
239
243
|
@abc.abstractmethod
|
|
240
|
-
def get_prop_calc(self, calculator: Calculator, **kwargs:
|
|
244
|
+
def get_prop_calc(self, calculator: Calculator, **kwargs: Any) -> PropCalc:
|
|
241
245
|
"""
|
|
242
246
|
Abstract method to retrieve a property calculation object using the provided calculator and additional
|
|
243
247
|
parameters.
|
|
@@ -336,8 +340,7 @@ class Benchmark(metaclass=abc.ABCMeta):
|
|
|
336
340
|
# We make sure of the generator from prop_calc.calc_many to do this in a memory efficient manner.
|
|
337
341
|
# allow_errors typically should be true since some of the calculations may fail.
|
|
338
342
|
for row, d in zip(
|
|
339
|
-
ground_truth,
|
|
340
|
-
prop_calc.calc_many(structures, n_jobs=n_jobs, allow_errors=True, **kwargs),
|
|
343
|
+
ground_truth, prop_calc.calc_many(structures, n_jobs=n_jobs, allow_errors=True, **kwargs), strict=True
|
|
341
344
|
):
|
|
342
345
|
r = dict(row)
|
|
343
346
|
r.update(self.process_result(d, model_name))
|
|
@@ -366,15 +369,16 @@ class Benchmark(metaclass=abc.ABCMeta):
|
|
|
366
369
|
return results_df
|
|
367
370
|
|
|
368
371
|
|
|
369
|
-
class
|
|
372
|
+
class EquilibriumBenchmark(Benchmark):
|
|
370
373
|
"""
|
|
371
|
-
Represents a benchmark for evaluating and analyzing
|
|
374
|
+
Represents a benchmark for evaluating and analyzing equilibrium properties of materials.
|
|
372
375
|
This benchmark utilizes a dataset and provides functionality for property calculation
|
|
373
376
|
and result processing. The class is designed to work with a predefined framework for
|
|
374
|
-
benchmarking
|
|
375
|
-
structures along with additional metadata. This class
|
|
376
|
-
metadata files, index names, and additional benchmark
|
|
377
|
-
calculators and utility classes for property computations
|
|
377
|
+
benchmarking equilibrium properties. The benchmark dataset contains data such as relaxed
|
|
378
|
+
structures, un-/corrected formation energy along with additional metadata. This class
|
|
379
|
+
supports configurability through metadata files, index names, and additional benchmark
|
|
380
|
+
properties. It relies on external calculators and utility classes for property computations
|
|
381
|
+
and result handling.
|
|
378
382
|
"""
|
|
379
383
|
|
|
380
384
|
def __init__(
|
|
@@ -385,9 +389,9 @@ class RelaxationBenchmark(Benchmark):
|
|
|
385
389
|
**kwargs, # noqa:ANN003
|
|
386
390
|
) -> None:
|
|
387
391
|
"""
|
|
388
|
-
Initializes the
|
|
392
|
+
Initializes the EquilibriumBenchmark instance with specified benchmark metadata and
|
|
389
393
|
configuration parameters. It sets up the benchmark with the necessary properties
|
|
390
|
-
required for
|
|
394
|
+
required for equilibrium benchmark analysis.
|
|
391
395
|
|
|
392
396
|
:param index_name: The name of the index used to uniquely identify records in the dataset.
|
|
393
397
|
:type index_name: str
|
|
@@ -399,36 +403,38 @@ class RelaxationBenchmark(Benchmark):
|
|
|
399
403
|
:type kwargs: dict
|
|
400
404
|
"""
|
|
401
405
|
self.folder_name = folder_name
|
|
402
|
-
|
|
403
|
-
kwargs.setdefault("
|
|
404
|
-
# Other fields such as the material formula may be included.
|
|
406
|
+
kwargs.setdefault("properties", ("structure", "formation_energy_per_atom"))
|
|
407
|
+
kwargs.setdefault("property_rename_map", {"formation_energy_per_atom": "Eform"})
|
|
405
408
|
kwargs.setdefault("other_fields", ("formula",))
|
|
406
409
|
super().__init__(benchmark_name, index_name=index_name, **kwargs)
|
|
407
410
|
|
|
408
|
-
def get_prop_calc(self, calculator: Calculator, **kwargs:
|
|
411
|
+
def get_prop_calc(self, calculator: Calculator, **kwargs: Any) -> PropCalc:
|
|
409
412
|
"""
|
|
410
|
-
Returns a property calculation object for performing relaxation
|
|
411
|
-
This method initializes the
|
|
412
|
-
object and any additional configuration parameters.
|
|
413
|
+
Returns a property calculation object for performing relaxation and formation energy
|
|
414
|
+
calculations. This method initializes the stability calculator using the provided
|
|
415
|
+
Calculator object and any additional configuration parameters.
|
|
413
416
|
|
|
414
|
-
:param calculator: A Calculator object responsible for performing the relaxation
|
|
417
|
+
:param calculator: A Calculator object responsible for performing the relaxation and
|
|
418
|
+
formation energy calculation.
|
|
415
419
|
:type calculator: Calculator
|
|
416
420
|
:param kwargs: Additional keyword arguments used for configuration.
|
|
417
421
|
:type kwargs: dict
|
|
418
|
-
:return: An initialized PropCalc object configured for relaxation
|
|
422
|
+
:return: An initialized PropCalc object configured for relaxation and formation energy
|
|
423
|
+
calculations.
|
|
419
424
|
:rtype: PropCalc
|
|
420
425
|
"""
|
|
421
|
-
return
|
|
426
|
+
return EnergeticsCalc(calculator, relax_calc_kwargs={"perturb_distance": 0.1}, **kwargs)
|
|
422
427
|
|
|
423
428
|
def process_result(self, result: dict | None, model_name: str) -> dict:
|
|
424
429
|
"""
|
|
425
|
-
Processes the result dictionary containing final
|
|
426
|
-
according to the provided model name. If the result is None, default values
|
|
427
|
-
NaN are returned for final structures.
|
|
430
|
+
Processes the result dictionary containing final structures and formation energy per atom,
|
|
431
|
+
formats the keys according to the provided model name. If the result is None, default values
|
|
432
|
+
of NaN are returned for final structures or formation energy per atom.
|
|
428
433
|
|
|
429
434
|
:param result:
|
|
430
|
-
A dictionary containing the final
|
|
431
|
-
'final_structure'. It can also be None to indicate missing
|
|
435
|
+
A dictionary containing the final structures and formation energy per atom under the keys
|
|
436
|
+
'final_structure' and 'formation energy per atom'. It can also be None to indicate missing
|
|
437
|
+
elemental_refs.
|
|
432
438
|
:type result: dict or None
|
|
433
439
|
|
|
434
440
|
:param model_name:
|
|
@@ -437,15 +443,97 @@ class RelaxationBenchmark(Benchmark):
|
|
|
437
443
|
:type model_name: str
|
|
438
444
|
|
|
439
445
|
:return:
|
|
440
|
-
A dictionary containing the specific final
|
|
441
|
-
The values will be NaN if the input result is None.
|
|
446
|
+
A dictionary containing the specific final structure and formation energy per atomprefixed
|
|
447
|
+
by the model name. The values will be NaN if the input result is None.
|
|
442
448
|
|
|
443
449
|
:rtype: dict
|
|
444
450
|
"""
|
|
445
451
|
return {
|
|
446
452
|
f"structure_{model_name}": (result["final_structure"] if result is not None else float("nan")),
|
|
453
|
+
f"formation_energy_per_atom_{model_name}": (
|
|
454
|
+
result["formation_energy_per_atom"] if result is not None else float("nan")
|
|
455
|
+
),
|
|
447
456
|
}
|
|
448
457
|
|
|
458
|
+
def run(
|
|
459
|
+
self,
|
|
460
|
+
calculator: Calculator,
|
|
461
|
+
model_name: str,
|
|
462
|
+
*,
|
|
463
|
+
n_jobs: None | int = -1,
|
|
464
|
+
checkpoint_file: str | Path | None = None,
|
|
465
|
+
checkpoint_freq: int = 1000,
|
|
466
|
+
delete_checkpoint_on_finish: bool = True,
|
|
467
|
+
include_full_results: bool = False,
|
|
468
|
+
**kwargs, # noqa:ANN003
|
|
469
|
+
) -> pd.DataFrame:
|
|
470
|
+
"""
|
|
471
|
+
Processes a collection of structures using a calculator, saves intermittent checkpoints,
|
|
472
|
+
and returns the results in a DataFrame. In addition to the base processing performed
|
|
473
|
+
by the parent class, this method computes the Euclidean distance between the relaxed
|
|
474
|
+
structure (obtained from the property calculation) and the reference DFT structure,
|
|
475
|
+
using SiteStatsFingerprint. The computed distance is added as a new column in the
|
|
476
|
+
results DataFrame with the key "distance_{model_name}".
|
|
477
|
+
|
|
478
|
+
This function supports parallel computation and allows for error tolerance during processing.
|
|
479
|
+
It retrieves a property calculator and utilizes it to calculate desired results for the given
|
|
480
|
+
set of structures. Checkpoints are saved periodically based on the specified frequency,
|
|
481
|
+
ensuring that progress is not lost in case of interruptions.
|
|
482
|
+
|
|
483
|
+
:param calculator: ASE-compatible calculator instance used to provide PES information for PropCalc.
|
|
484
|
+
:type calculator: Calculator
|
|
485
|
+
:param model_name: Name of the model used for properties' calculation.
|
|
486
|
+
This name is updated in the results DataFrame.
|
|
487
|
+
:type model_name: str
|
|
488
|
+
:param n_jobs: Number of parallel jobs to be used in the computation. Use -1
|
|
489
|
+
to allocate all cores available on the system. Defaults to -1.
|
|
490
|
+
:type n_jobs: int | None
|
|
491
|
+
:param checkpoint_file: File path where checkpoint elemental_refs is saved periodically.
|
|
492
|
+
If None, no checkpoints are saved.
|
|
493
|
+
:type checkpoint_file: str | Path | None
|
|
494
|
+
:param checkpoint_freq: Frequency after which checkpoint elemental_refs is saved.
|
|
495
|
+
Corresponds to the number of structures processed.
|
|
496
|
+
:type checkpoint_freq: int
|
|
497
|
+
:param delete_checkpoint_on_finish: Whether to delete checkpoint files when the benchmark finishes. Defaults to
|
|
498
|
+
True.
|
|
499
|
+
:type delete_checkpoint_on_finish: bool
|
|
500
|
+
:param include_full_results: Whether to save full results from PropCalc.calc for analysis afterwards. For
|
|
501
|
+
instance, the ElasticityProp does not just compute the bulk and shear moduli, but also the full elastic
|
|
502
|
+
tensors, which can be used for other kinds of analysis. Defaults to False.
|
|
503
|
+
:type include_full_results: bool
|
|
504
|
+
:param kwargs: Additional keyword arguments passed to the property calculator,
|
|
505
|
+
for instance, to customize its behavior or computation options.
|
|
506
|
+
:type kwargs: dict
|
|
507
|
+
:return: A pandas DataFrame containing the processed results for the given
|
|
508
|
+
input structures. The DataFrame includes updated results and relevant
|
|
509
|
+
metrics.
|
|
510
|
+
:rtype: pd.DataFrame
|
|
511
|
+
"""
|
|
512
|
+
results_df = super().run(
|
|
513
|
+
calculator,
|
|
514
|
+
model_name,
|
|
515
|
+
n_jobs=n_jobs,
|
|
516
|
+
checkpoint_file=checkpoint_file,
|
|
517
|
+
checkpoint_freq=checkpoint_freq,
|
|
518
|
+
delete_checkpoint_on_finish=delete_checkpoint_on_finish,
|
|
519
|
+
include_full_results=include_full_results,
|
|
520
|
+
**kwargs,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
ssf = SiteStatsFingerprint(
|
|
524
|
+
CrystalNNFingerprint.from_preset("ops", distance_cutoffs=None, x_diff_weight=0),
|
|
525
|
+
stats=("mean", "std_dev", "minimum", "maximum"),
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
results_df[f"d_{model_name}"] = [
|
|
529
|
+
np.linalg.norm(np.array(ssf.featurize(model)) - np.array(ssf.featurize(dft)))
|
|
530
|
+
if model is not None and dft is not None
|
|
531
|
+
else np.nan
|
|
532
|
+
for model, dft in zip(results_df[f"structure_{model_name}"], results_df["structure_DFT"], strict=True)
|
|
533
|
+
]
|
|
534
|
+
|
|
535
|
+
return results_df
|
|
536
|
+
|
|
449
537
|
|
|
450
538
|
class ElasticityBenchmark(Benchmark):
|
|
451
539
|
"""
|
|
@@ -490,7 +578,7 @@ class ElasticityBenchmark(Benchmark):
|
|
|
490
578
|
**kwargs,
|
|
491
579
|
)
|
|
492
580
|
|
|
493
|
-
def get_prop_calc(self, calculator: Calculator, **kwargs:
|
|
581
|
+
def get_prop_calc(self, calculator: Calculator, **kwargs: Any) -> PropCalc:
|
|
494
582
|
"""
|
|
495
583
|
Calculates and returns a property calculation object based on the provided
|
|
496
584
|
calculator and optional parameters. This is useful for initializing and
|
|
@@ -581,7 +669,7 @@ class PhononBenchmark(Benchmark):
|
|
|
581
669
|
**kwargs,
|
|
582
670
|
)
|
|
583
671
|
|
|
584
|
-
def get_prop_calc(self, calculator: Calculator, **kwargs:
|
|
672
|
+
def get_prop_calc(self, calculator: Calculator, **kwargs: Any) -> PropCalc:
|
|
585
673
|
"""
|
|
586
674
|
Retrieves a phonon calculation instance based on the given calculator and
|
|
587
675
|
additional keyword arguments.
|
|
@@ -598,7 +686,7 @@ class PhononBenchmark(Benchmark):
|
|
|
598
686
|
optional parameters.
|
|
599
687
|
:rtype: PropCalc
|
|
600
688
|
"""
|
|
601
|
-
return PhononCalc(calculator, **kwargs)
|
|
689
|
+
return PhononCalc(calculator, write_phonon=False, **kwargs)
|
|
602
690
|
|
|
603
691
|
def process_result(self, result: dict | None, model_name: str) -> dict:
|
|
604
692
|
"""
|
|
@@ -23,7 +23,7 @@ def calculate_property(args: Any) -> None:
|
|
|
23
23
|
:param args:
|
|
24
24
|
:return:
|
|
25
25
|
"""
|
|
26
|
-
calculator = mtc.
|
|
26
|
+
calculator = mtc.load_up(args.model)
|
|
27
27
|
mod = mtc.__dict__[args.property](calculator)
|
|
28
28
|
results = []
|
|
29
29
|
for f in args.structure:
|
|
@@ -11,7 +11,7 @@ BENCHMARK_DATA_DIR = pathlib.Path.home() / ".cache" / "matcalc"
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def clear_cache(*, confirm: bool = True) -> None:
|
|
14
|
-
"""Deletes all files in the
|
|
14
|
+
"""Deletes all files in the mattcalc cache. This is used to clean out downloaded benchmarks.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
17
|
confirm: Whether to ask for confirmation. Default is True.
|
|
@@ -30,6 +30,7 @@ class ElasticityCalc(PropCalc):
|
|
|
30
30
|
norm_strains: Sequence[float] | float = (-0.01, -0.005, 0.005, 0.01),
|
|
31
31
|
shear_strains: Sequence[float] | float = (-0.06, -0.03, 0.03, 0.06),
|
|
32
32
|
fmax: float = 0.1,
|
|
33
|
+
symmetry: bool = False,
|
|
33
34
|
relax_structure: bool = True,
|
|
34
35
|
relax_deformed_structures: bool = False,
|
|
35
36
|
use_equilibrium: bool = True,
|
|
@@ -43,10 +44,11 @@ class ElasticityCalc(PropCalc):
|
|
|
43
44
|
shear_strains: single or multiple strain values to apply to each shear mode.
|
|
44
45
|
Defaults to (-0.06, -0.03, 0.03, 0.06).
|
|
45
46
|
fmax: maximum force in the relaxed structure (if relax_structure). Defaults to 0.1.
|
|
47
|
+
symmetry: whether or not to use symmetry reduction. Defaults to False.
|
|
46
48
|
relax_structure: whether to relax the provided structure with the given calculator.
|
|
47
49
|
Defaults to True.
|
|
48
50
|
relax_deformed_structures: whether to relax the atomic positions of the deformed/strained structures
|
|
49
|
-
with the given calculator. Defaults to
|
|
51
|
+
with the given calculator. Defaults to False.
|
|
50
52
|
use_equilibrium: whether to use the equilibrium stress and strain. Ignored and set
|
|
51
53
|
to True if either norm_strains or shear_strains has length 1 or is a float.
|
|
52
54
|
Defaults to True.
|
|
@@ -65,6 +67,7 @@ class ElasticityCalc(PropCalc):
|
|
|
65
67
|
self.relax_structure = relax_structure
|
|
66
68
|
self.relax_deformed_structures = relax_deformed_structures
|
|
67
69
|
self.fmax = fmax
|
|
70
|
+
self.symmetry = symmetry
|
|
68
71
|
if len(self.norm_strains) > 1 and len(self.shear_strains) > 1:
|
|
69
72
|
self.use_equilibrium = use_equilibrium
|
|
70
73
|
else:
|
|
@@ -93,14 +96,17 @@ class ElasticityCalc(PropCalc):
|
|
|
93
96
|
|
|
94
97
|
if self.relax_structure or self.relax_deformed_structures:
|
|
95
98
|
relax_calc = RelaxCalc(self.calculator, fmax=self.fmax, **(self.relax_calc_kwargs or {}))
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
if self.relax_structure:
|
|
100
|
+
result |= relax_calc.calc(structure_in)
|
|
101
|
+
structure_in = result["final_structure"]
|
|
102
|
+
if self.relax_deformed_structures:
|
|
103
|
+
relax_calc.relax_cell = False
|
|
99
104
|
|
|
100
105
|
deformed_structure_set = DeformedStructureSet(
|
|
101
106
|
structure_in,
|
|
102
107
|
self.norm_strains,
|
|
103
108
|
self.shear_strains,
|
|
109
|
+
self.symmetry,
|
|
104
110
|
)
|
|
105
111
|
stresses = []
|
|
106
112
|
for deformed_structure in deformed_structure_set:
|