kim-tools 0.2.4__tar.gz → 0.2.5__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.
- {kim_tools-0.2.4/kim_tools.egg-info → kim_tools-0.2.5}/PKG-INFO +9 -2
- kim_tools-0.2.5/README.md +8 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/__init__.py +1 -1
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/aflow_util/core.py +10 -8
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/core.py +196 -13
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/test_driver/core.py +78 -37
- {kim_tools-0.2.4 → kim_tools-0.2.5/kim_tools.egg-info}/PKG-INFO +9 -2
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools.egg-info/requires.txt +3 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/pyproject.toml +7 -2
- {kim_tools-0.2.4 → kim_tools-0.2.5}/tests/test_aflow_util.py +7 -1
- {kim_tools-0.2.4 → kim_tools-0.2.5}/tests/test_symmetry_util.py +23 -0
- kim_tools-0.2.4/README.md +0 -4
- {kim_tools-0.2.4 → kim_tools-0.2.5}/LICENSE.CDDL +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/MANIFEST.in +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/aflow_util/__init__.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/aflow_util/data/README_PROTO.TXT +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/ase/__init__.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/ase/core.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/kimunits.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/__init__.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/possible_primitive_shifts.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/primitive_GENPOS_ops.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/space_groups_for_each_bravais_lattice.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/wyck_pos_xform_under_normalizer.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/wyckoff_multiplicities.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/wyckoff_sets.json +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/test_driver/__init__.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/vc/__init__.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/vc/core.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools.egg-info/SOURCES.txt +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools.egg-info/dependency_links.txt +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools.egg-info/top_level.txt +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/setup.cfg +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/setup.py +0 -0
- {kim_tools-0.2.4 → kim_tools-0.2.5}/tests/test_test_driver.py +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kim-tools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.5
|
4
4
|
Summary: Base classes and helper routines for writing KIM Tests
|
5
|
-
Author-email: ilia Nikiforov <nikif002@umn.edu>, Ellad Tadmor <tadmor@umn.edu>, Claire Waters <bwaters@umn.edu>, "Daniel S. Karls" <karl0100umn@gmail.com>, Matt Bierbaum <matt.bierbaum@gmail.com>, Eric Fuemmeler <efuemmel@umn.edu>
|
5
|
+
Author-email: ilia Nikiforov <nikif002@umn.edu>, Ellad Tadmor <tadmor@umn.edu>, Claire Waters <bwaters@umn.edu>, "Daniel S. Karls" <karl0100umn@gmail.com>, Matt Bierbaum <matt.bierbaum@gmail.com>, Eric Fuemmeler <efuemmel@umn.edu>, Philipp Hoellmer <ph2484@nyu.edu>, Guanming Zhang <gz2241@nyu.edu>
|
6
6
|
Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
|
7
7
|
Project-URL: Homepage, https://kim-tools.readthedocs.io
|
8
8
|
Project-URL: Issues, https://github.com/openkim/kim-tools/issues
|
@@ -24,9 +24,16 @@ Requires-Dist: sympy>=1.13.2
|
|
24
24
|
Requires-Dist: numpy>=1.13.1
|
25
25
|
Requires-Dist: scipy>=1.3.0
|
26
26
|
Requires-Dist: jinja2>=2.7.2
|
27
|
+
Requires-Dist: matplotlib
|
28
|
+
Requires-Dist: scipy
|
29
|
+
Requires-Dist: scikit-learn
|
27
30
|
Dynamic: license-file
|
28
31
|
|
29
32
|
# kim-tools
|
30
33
|
|
34
|
+

|
35
|
+
[](https://kim-tools.readthedocs.io/en/latest/)
|
36
|
+
[](https://pypi.org/project/kim-tools/)
|
37
|
+
|
31
38
|
KIMTestDriver and SingleCrystalTestDriver classes for creating OpenKIM Test Drivers, and helper routines for writing
|
32
39
|
KIM Tests and Verification Checks. Documentation at https://kim-tools.readthedocs.io.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# kim-tools
|
2
|
+
|
3
|
+

|
4
|
+
[](https://kim-tools.readthedocs.io/en/latest/)
|
5
|
+
[](https://pypi.org/project/kim-tools/)
|
6
|
+
|
7
|
+
KIMTestDriver and SingleCrystalTestDriver classes for creating OpenKIM Test Drivers, and helper routines for writing
|
8
|
+
KIM Tests and Verification Checks. Documentation at https://kim-tools.readthedocs.io.
|
@@ -12,7 +12,7 @@ from math import acos, cos, degrees, radians, sin, sqrt
|
|
12
12
|
from os import PathLike
|
13
13
|
from random import random
|
14
14
|
from tempfile import NamedTemporaryFile
|
15
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
15
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
16
16
|
|
17
17
|
import ase
|
18
18
|
import numpy as np
|
@@ -115,7 +115,7 @@ class EquivalentAtomSet:
|
|
115
115
|
|
116
116
|
|
117
117
|
def write_tmp_poscar_from_atoms_and_run_function(
|
118
|
-
atoms: Atoms, function:
|
118
|
+
atoms: Atoms, function: Callable, *args, **kwargs
|
119
119
|
) -> Any:
|
120
120
|
"""
|
121
121
|
Write the Atoms file to a NamedTemporaryFile and run 'function' on it.
|
@@ -143,7 +143,7 @@ def check_number_of_atoms(
|
|
143
143
|
has the correct number of atoms according to prototype_label
|
144
144
|
|
145
145
|
Raises:
|
146
|
-
|
146
|
+
IncorrectNumAtomsException
|
147
147
|
"""
|
148
148
|
prototype_label_list = prototype_label.split("_")
|
149
149
|
pearson = prototype_label_list[1]
|
@@ -269,8 +269,9 @@ def get_equivalent_atom_sets_from_prototype_and_atom_map(
|
|
269
269
|
`atoms`, and `prototype_label` is the detected prototype label
|
270
270
|
|
271
271
|
Args:
|
272
|
-
sort_atoms:
|
273
|
-
|
272
|
+
sort_atoms:
|
273
|
+
If `atom_map` was obtained by sorting `atoms` before writing it to
|
274
|
+
POSCAR, set this to True
|
274
275
|
"""
|
275
276
|
|
276
277
|
if sort_atoms:
|
@@ -1214,9 +1215,10 @@ class AFLOW:
|
|
1214
1215
|
sort_atoms2: Whether to sort atoms2 before comparing.
|
1215
1216
|
|
1216
1217
|
Returns:
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1218
|
+
* basis transformation
|
1219
|
+
* rotation
|
1220
|
+
* origin shift
|
1221
|
+
* atom_map (atom_map[index_in_structure_1] = index_in_structure_2)
|
1220
1222
|
|
1221
1223
|
Raises:
|
1222
1224
|
AFLOW.FailedToMatchException: if AFLOW fails to match the crystals
|
@@ -7,13 +7,17 @@ import logging
|
|
7
7
|
import os
|
8
8
|
from itertools import product
|
9
9
|
from math import ceil
|
10
|
-
from typing import Dict, List, Union
|
10
|
+
from typing import Dict, List, Optional, Tuple, Union
|
11
11
|
|
12
|
+
import matplotlib.pyplot as plt
|
12
13
|
import numpy as np
|
14
|
+
import numpy.typing as npt
|
13
15
|
from ase import Atoms
|
14
16
|
from ase.cell import Cell
|
15
|
-
from ase.geometry import get_duplicate_atoms
|
16
|
-
from
|
17
|
+
from ase.geometry import get_distances, get_duplicate_atoms
|
18
|
+
from matplotlib.backends.backend_pdf import PdfPages
|
19
|
+
from scipy.stats import kstest
|
20
|
+
from sklearn.decomposition import PCA
|
17
21
|
from sympy import Matrix, cos, matrix2numpy, sin, sqrt, symbols
|
18
22
|
|
19
23
|
logger = logging.getLogger(__name__)
|
@@ -85,6 +89,12 @@ class IncorrectNumAtomsException(Exception):
|
|
85
89
|
"""
|
86
90
|
|
87
91
|
|
92
|
+
class PeriodExtensionException(Exception):
|
93
|
+
"""
|
94
|
+
Raised when a period-extending phase transition is detected.
|
95
|
+
"""
|
96
|
+
|
97
|
+
|
88
98
|
def _check_space_group(sgnum: Union[int, str]):
|
89
99
|
try:
|
90
100
|
assert 1 <= int(sgnum) <= 230
|
@@ -96,8 +106,8 @@ def _check_space_group(sgnum: Union[int, str]):
|
|
96
106
|
|
97
107
|
|
98
108
|
def cartesian_to_fractional_itc_rotation_from_ase_cell(
|
99
|
-
cart_rot: ArrayLike, cell: ArrayLike
|
100
|
-
) -> ArrayLike:
|
109
|
+
cart_rot: npt.ArrayLike, cell: npt.ArrayLike
|
110
|
+
) -> npt.ArrayLike:
|
101
111
|
"""
|
102
112
|
Convert Cartesian to fractional rotation. Read the arguments and returns carefully,
|
103
113
|
as there is some unfortunate mixing of row and columns because of the different
|
@@ -132,8 +142,8 @@ def cartesian_to_fractional_itc_rotation_from_ase_cell(
|
|
132
142
|
|
133
143
|
|
134
144
|
def fractional_to_cartesian_itc_rotation_from_ase_cell(
|
135
|
-
frac_rot: ArrayLike, cell: ArrayLike
|
136
|
-
) -> ArrayLike:
|
145
|
+
frac_rot: npt.ArrayLike, cell: npt.ArrayLike
|
146
|
+
) -> npt.ArrayLike:
|
137
147
|
"""
|
138
148
|
Convert fractional to Cartesian rotation. Read the arguments and returns carefully,
|
139
149
|
as there is some unfortunate mixing of row and columns because of the different
|
@@ -168,9 +178,9 @@ def fractional_to_cartesian_itc_rotation_from_ase_cell(
|
|
168
178
|
|
169
179
|
|
170
180
|
def cartesian_rotation_is_in_point_group(
|
171
|
-
cart_rot: ArrayLike,
|
181
|
+
cart_rot: npt.ArrayLike,
|
172
182
|
sgnum: Union[int, str],
|
173
|
-
cell: ArrayLike,
|
183
|
+
cell: npt.ArrayLike,
|
174
184
|
rtol: float = 1e-2,
|
175
185
|
atol: float = 1e-2,
|
176
186
|
) -> bool:
|
@@ -215,7 +225,7 @@ def cartesian_rotation_is_in_point_group(
|
|
215
225
|
return False
|
216
226
|
|
217
227
|
|
218
|
-
def get_cell_from_poscar(poscar: os.PathLike) -> ArrayLike:
|
228
|
+
def get_cell_from_poscar(poscar: os.PathLike) -> npt.ArrayLike:
|
219
229
|
"""
|
220
230
|
Extract the unit cell from a POSCAR file, including the specified scaling
|
221
231
|
"""
|
@@ -437,7 +447,7 @@ def get_symbolic_cell_from_formal_bravais_lattice(
|
|
437
447
|
|
438
448
|
def get_change_of_basis_matrix_to_conventional_cell_from_formal_bravais_lattice(
|
439
449
|
formal_bravais_lattice: str,
|
440
|
-
) -> ArrayLike:
|
450
|
+
) -> npt.ArrayLike:
|
441
451
|
"""
|
442
452
|
Get a change of basis matrix **P** as defined in ITA 1.5.1.2, with "old basis"
|
443
453
|
being the primitive cell of the provided Bravais lattice, and the "new basis" being
|
@@ -498,7 +508,7 @@ def get_change_of_basis_matrix_to_conventional_cell_from_formal_bravais_lattice(
|
|
498
508
|
return np.round(change_of_basis_matrix)
|
499
509
|
|
500
510
|
|
501
|
-
def change_of_basis_atoms(atoms: Atoms, change_of_basis: ArrayLike) -> Atoms:
|
511
|
+
def change_of_basis_atoms(atoms: Atoms, change_of_basis: npt.ArrayLike) -> Atoms:
|
502
512
|
"""
|
503
513
|
Perform an arbitrary basis change on an ``Atoms`` object, duplicating or cropping
|
504
514
|
atoms as needed. A basic check is made that the determinant of ``change_of_basis``
|
@@ -506,7 +516,7 @@ def change_of_basis_atoms(atoms: Atoms, change_of_basis: ArrayLike) -> Atoms:
|
|
506
516
|
that ``change_of_basis`` is appropriate for the particuar crystal described by
|
507
517
|
``atoms``, which is up to the user.
|
508
518
|
|
509
|
-
|
519
|
+
TODO: Incorporate :func:`kstest_reduced_distances` into this function
|
510
520
|
|
511
521
|
Args:
|
512
522
|
atoms:
|
@@ -600,3 +610,176 @@ def get_primitive_genpos_ops(sgnum: Union[int, str]) -> List[Dict]:
|
|
600
610
|
_check_space_group(sgnum)
|
601
611
|
with open(os.path.join(DATA_DIR, "primitive_GENPOS_ops.json")) as f:
|
602
612
|
return np.asarray(json.load(f)[str(sgnum)])
|
613
|
+
|
614
|
+
|
615
|
+
def reduce_and_avg(
|
616
|
+
atoms: Atoms, repeat: Tuple[int, int, int]
|
617
|
+
) -> Tuple[Atoms, npt.NDArray]:
|
618
|
+
"""
|
619
|
+
TODO: Upgrade :func:`change_of_basis_atoms` to provide the distances
|
620
|
+
array, obviating this function
|
621
|
+
|
622
|
+
Function to reduce all atoms to the original unit cell position.
|
623
|
+
|
624
|
+
Args:
|
625
|
+
atoms:
|
626
|
+
The supercell to reduce
|
627
|
+
repeat:
|
628
|
+
The number of repeats of each unit cell vector in the
|
629
|
+
provided supercell
|
630
|
+
|
631
|
+
Returns:
|
632
|
+
* The reduced unit cell
|
633
|
+
* An array of displacement vectors. First dimension: index of reference atom
|
634
|
+
in reduced cell. Second dimension: index of atom in provided supercell.
|
635
|
+
Third dimension: x, y, z
|
636
|
+
"""
|
637
|
+
new_atoms = atoms.copy()
|
638
|
+
|
639
|
+
cell = new_atoms.get_cell()
|
640
|
+
|
641
|
+
# Divide each unit vector by its number of repeats.
|
642
|
+
# See
|
643
|
+
# https://stackoverflow.com/questions/19602187/numpy-divide-each-row-by-a-vector-element.
|
644
|
+
cell = cell / np.array(repeat)[:, None]
|
645
|
+
|
646
|
+
# Decrease size of cell in the atoms object.
|
647
|
+
new_atoms.set_cell(cell)
|
648
|
+
new_atoms.set_pbc((True, True, True))
|
649
|
+
|
650
|
+
# Set averaging factor
|
651
|
+
M = np.prod(repeat)
|
652
|
+
|
653
|
+
# Wrap back the repeated atoms on top of
|
654
|
+
# the reference atoms in the original unit cell.
|
655
|
+
positions = new_atoms.get_positions(wrap=True)
|
656
|
+
|
657
|
+
number_atoms = len(new_atoms)
|
658
|
+
original_number_atoms = number_atoms // M
|
659
|
+
assert number_atoms == original_number_atoms * M
|
660
|
+
avg_positions_in_prim_cell = np.zeros((original_number_atoms, 3))
|
661
|
+
positions_in_prim_cell = np.zeros((number_atoms, 3))
|
662
|
+
|
663
|
+
# Start from end of the atoms
|
664
|
+
# because we will remove all atoms except the reference ones.
|
665
|
+
for i in reversed(range(number_atoms)):
|
666
|
+
if i >= original_number_atoms:
|
667
|
+
# Get the distance to the reference atom in the original unit cell with the
|
668
|
+
# minimum image convention.
|
669
|
+
distance = new_atoms.get_distance(
|
670
|
+
i % original_number_atoms, i, mic=True, vector=True
|
671
|
+
)
|
672
|
+
# Get the position that has the closest distance to
|
673
|
+
# the reference atom in the original unit cell.
|
674
|
+
position_i = positions[i % original_number_atoms] + distance
|
675
|
+
# Remove atom from atoms object.
|
676
|
+
new_atoms.pop()
|
677
|
+
else:
|
678
|
+
# Atom was part of the original unit cell.
|
679
|
+
position_i = positions[i]
|
680
|
+
# Average
|
681
|
+
avg_positions_in_prim_cell[i % original_number_atoms] += position_i / M
|
682
|
+
positions_in_prim_cell[i] = position_i
|
683
|
+
|
684
|
+
new_atoms.set_positions(avg_positions_in_prim_cell)
|
685
|
+
|
686
|
+
# Calculate the distances.
|
687
|
+
distances = np.empty((original_number_atoms, M, 3))
|
688
|
+
for i in range(number_atoms):
|
689
|
+
dr, _ = get_distances(
|
690
|
+
positions_in_prim_cell[i],
|
691
|
+
avg_positions_in_prim_cell[i % original_number_atoms],
|
692
|
+
cell=new_atoms.get_cell(),
|
693
|
+
pbc=True,
|
694
|
+
)
|
695
|
+
# dr is a distance matrix, here we only have one distance
|
696
|
+
assert dr.shape == (1, 1, 3)
|
697
|
+
distances[i % original_number_atoms, i // original_number_atoms] = dr[0][0]
|
698
|
+
|
699
|
+
return new_atoms, distances
|
700
|
+
|
701
|
+
|
702
|
+
def kstest_reduced_distances(
|
703
|
+
reduced_distances: npt.NDArray,
|
704
|
+
significance_level: float = 0.05,
|
705
|
+
plot_filename: Optional[str] = None,
|
706
|
+
number_bins: Optional[int] = None,
|
707
|
+
) -> None:
|
708
|
+
"""
|
709
|
+
TODO: Incorporate this into :func:`change_of_basis_atoms`
|
710
|
+
|
711
|
+
Function to test whether the reduced atom positions are normally distributed
|
712
|
+
around their average.
|
713
|
+
|
714
|
+
Args:
|
715
|
+
reduced_distances:
|
716
|
+
Distance array provided by :func:`reduce_and_avg`
|
717
|
+
significance_level:
|
718
|
+
Significance level for Kolmogorov-Smirnov
|
719
|
+
plot_filename:
|
720
|
+
number_bins:
|
721
|
+
Number of bins for plot
|
722
|
+
|
723
|
+
Raises:
|
724
|
+
PeriodExtensionException:
|
725
|
+
If a non-normal distribution is detected
|
726
|
+
"""
|
727
|
+
assert len(reduced_distances.shape) == 3
|
728
|
+
assert reduced_distances.shape[2] == 3
|
729
|
+
|
730
|
+
if plot_filename is not None:
|
731
|
+
if number_bins is None:
|
732
|
+
raise ValueError(
|
733
|
+
"number_bins must be specified if plot_filename is specified"
|
734
|
+
)
|
735
|
+
if not plot_filename.endswith(".pdf"):
|
736
|
+
raise ValueError(f"{plot_filename} is not a PDF file")
|
737
|
+
with PdfPages(plot_filename) as pdf:
|
738
|
+
for i in range(reduced_distances.shape[0]):
|
739
|
+
fig, axs = plt.subplots(1, 3, figsize=(10.0, 4.0))
|
740
|
+
for j in range(reduced_distances.shape[2]):
|
741
|
+
axs[j].hist(reduced_distances[i, :, j], bins=number_bins)
|
742
|
+
axs[j].set_xlabel(f"$x_{j}$")
|
743
|
+
axs[0].set_ylabel("Counts")
|
744
|
+
fig.suptitle(f"Atom {i}")
|
745
|
+
pdf.savefig()
|
746
|
+
else:
|
747
|
+
if number_bins is not None:
|
748
|
+
raise ValueError(
|
749
|
+
"number_bins must not be specified if plot_filename is not specified"
|
750
|
+
)
|
751
|
+
|
752
|
+
p_values = np.empty((reduced_distances.shape[0], reduced_distances.shape[2]))
|
753
|
+
for i in range(reduced_distances.shape[0]):
|
754
|
+
atom_distances = reduced_distances[i]
|
755
|
+
|
756
|
+
# Perform PCA on the xyz distribution.
|
757
|
+
pca = PCA(n_components=atom_distances.shape[1])
|
758
|
+
pca_components = pca.fit_transform(atom_distances)
|
759
|
+
assert (
|
760
|
+
pca_components.shape == atom_distances.shape == reduced_distances.shape[1:]
|
761
|
+
)
|
762
|
+
|
763
|
+
# Test each component with a KS test.
|
764
|
+
for j in range(pca_components.shape[1]):
|
765
|
+
component = pca_components[:, j]
|
766
|
+
component_mean = np.mean(component)
|
767
|
+
assert abs(component_mean) < 1.0e-7
|
768
|
+
component_std = np.std(component)
|
769
|
+
# Normalize component
|
770
|
+
normalized_component = (component - component_mean) / component_std
|
771
|
+
assert abs(np.mean(normalized_component)) < 1.0e-7
|
772
|
+
assert abs(np.std(normalized_component) - 1.0) < 1.0e-7
|
773
|
+
res = kstest(normalized_component, "norm")
|
774
|
+
p_values[i, j] = res.pvalue
|
775
|
+
|
776
|
+
if np.any(p_values <= significance_level):
|
777
|
+
raise PeriodExtensionException(
|
778
|
+
"Detected non-normal distribution of reduced atom positions around their "
|
779
|
+
f"average (smallest p value {np.min(p_values)})."
|
780
|
+
)
|
781
|
+
else:
|
782
|
+
print(
|
783
|
+
"Detected normal distribution or reduced atom positions around their "
|
784
|
+
f"average (smallest p value {np.min(p_values)})."
|
785
|
+
)
|
@@ -465,7 +465,7 @@ class KIMTestDriver(ABC):
|
|
465
465
|
to be useful to for most KIM tests
|
466
466
|
|
467
467
|
Attributes:
|
468
|
-
__kim_model_name (str
|
468
|
+
__kim_model_name (Optional[str]):
|
469
469
|
KIM model name, absent if a non-KIM ASE calculator was provided
|
470
470
|
__calc (:obj:`~ase.calculators.calculator.Calculator`):
|
471
471
|
ASE calculator
|
@@ -564,7 +564,8 @@ class KIMTestDriver(ABC):
|
|
564
564
|
) -> None:
|
565
565
|
"""
|
566
566
|
Add a key to the most recent property instance added with
|
567
|
-
:func:`~kim_tools.KIMTestDriver._add_property_instance`.
|
567
|
+
:func:`~kim_tools.test_driver.core.KIMTestDriver._add_property_instance`.
|
568
|
+
If the value is an
|
568
569
|
array, this function will assume you want to write to the beginning of the array
|
569
570
|
in every dimension. This function is intended to write entire keys in one go,
|
570
571
|
and should not be used for modifying existing keys.
|
@@ -722,15 +723,15 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
722
723
|
prototype_label: str,
|
723
724
|
stoichiometric_species: List[str],
|
724
725
|
a: float,
|
726
|
+
a_unit: str,
|
725
727
|
parameter_values: Optional[List[float]] = None,
|
726
728
|
library_prototype_label: Optional[Union[List[str], str]] = None,
|
727
729
|
short_name: Optional[Union[List[str], str]] = None,
|
728
730
|
cell_cauchy_stress: Optional[List[float]] = None,
|
731
|
+
cell_cauchy_stress_unit: Optional[str] = None,
|
729
732
|
temperature: Optional[float] = None,
|
733
|
+
temperature_unit: Optional[str] = "K",
|
730
734
|
crystal_genome_source_structure_id: Optional[List[List[str]]] = None,
|
731
|
-
a_unit: str = "angstrom",
|
732
|
-
cell_cauchy_stress_unit: str = "eV/angstrom^3",
|
733
|
-
temperature_unit: str = "K",
|
734
735
|
aflow_executable: str = AFLOW_EXECUTABLE,
|
735
736
|
) -> str:
|
736
737
|
"""
|
@@ -799,6 +800,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
799
800
|
"Please specify the Cauchy stress as a 6-dimensional vector in Voigt "
|
800
801
|
"order [xx, yy, zz, yz, xz, xy]"
|
801
802
|
)
|
803
|
+
if cell_cauchy_stress_unit is None:
|
804
|
+
raise KIMTestDriver("Please provide a `cell_cauchy_stress_unit`")
|
802
805
|
property_instances = _add_key_to_current_property_instance(
|
803
806
|
property_instances,
|
804
807
|
"cell-cauchy-stress",
|
@@ -807,6 +810,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
807
810
|
)
|
808
811
|
|
809
812
|
if temperature is not None:
|
813
|
+
if temperature_unit is None:
|
814
|
+
raise KIMTestDriver("Please provide a `temperature_unit`")
|
810
815
|
property_instances = _add_key_to_current_property_instance(
|
811
816
|
property_instances, "temperature", temperature, temperature_unit
|
812
817
|
)
|
@@ -826,15 +831,15 @@ def _add_property_instance_and_common_crystal_genome_keys(
|
|
826
831
|
prototype_label: str,
|
827
832
|
stoichiometric_species: List[str],
|
828
833
|
a: float,
|
834
|
+
a_unit: str,
|
829
835
|
parameter_values: Optional[List[float]] = None,
|
830
836
|
library_prototype_label: Optional[Union[List[str], str]] = None,
|
831
837
|
short_name: Optional[Union[List[str], str]] = None,
|
832
838
|
cell_cauchy_stress: Optional[List[float]] = None,
|
839
|
+
cell_cauchy_stress_unit: Optional[str] = None,
|
833
840
|
temperature: Optional[float] = None,
|
841
|
+
temperature_unit: Optional[str] = "K",
|
834
842
|
crystal_genome_source_structure_id: Optional[List[List[str]]] = None,
|
835
|
-
a_unit: str = "angstrom",
|
836
|
-
cell_cauchy_stress_unit: str = "eV/angstrom^3",
|
837
|
-
temperature_unit: str = "K",
|
838
843
|
disclaimer: Optional[str] = None,
|
839
844
|
property_instances: Optional[str] = None,
|
840
845
|
aflow_executable: str = AFLOW_EXECUTABLE,
|
@@ -872,15 +877,15 @@ def _add_property_instance_and_common_crystal_genome_keys(
|
|
872
877
|
prototype_label=prototype_label,
|
873
878
|
stoichiometric_species=stoichiometric_species,
|
874
879
|
a=a,
|
880
|
+
a_unit=a_unit,
|
875
881
|
parameter_values=parameter_values,
|
876
882
|
library_prototype_label=library_prototype_label,
|
877
883
|
short_name=short_name,
|
878
|
-
cell_cauchy_stress=cell_cauchy_stress,
|
879
884
|
temperature=temperature,
|
885
|
+
temperature_unit=temperature_unit,
|
880
886
|
crystal_genome_source_structure_id=crystal_genome_source_structure_id,
|
881
|
-
a_unit=a_unit,
|
882
887
|
cell_cauchy_stress_unit=cell_cauchy_stress_unit,
|
883
|
-
|
888
|
+
cell_cauchy_stress=cell_cauchy_stress,
|
884
889
|
aflow_executable=aflow_executable,
|
885
890
|
)
|
886
891
|
|
@@ -947,6 +952,7 @@ def get_crystal_structure_from_atoms(
|
|
947
952
|
prototype_label=proto_des["aflow_prototype_label"],
|
948
953
|
stoichiometric_species=sorted(list(set(atoms.get_chemical_symbols()))),
|
949
954
|
a=a,
|
955
|
+
a_unit="angstrom",
|
950
956
|
parameter_values=parameter_values,
|
951
957
|
library_prototype_label=library_prototype_label,
|
952
958
|
short_name=short_name,
|
@@ -993,8 +999,8 @@ def get_poscar_from_crystal_structure(
|
|
993
999
|
primitive unit cell of the crystal as defined in
|
994
1000
|
http://doi.org/10.1016/j.commatsci.2017.01.017. Lengths are always in angstrom.
|
995
1001
|
Raises:
|
996
|
-
AFLOW.ChangedSymmetryException:
|
997
|
-
|
1002
|
+
AFLOW.ChangedSymmetryException:
|
1003
|
+
if the symmetry of the atoms object is different from ``prototype_label``
|
998
1004
|
"""
|
999
1005
|
if flat:
|
1000
1006
|
prototype_label = crystal_structure["prototype-label.source-value"]
|
@@ -1287,7 +1293,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1287
1293
|
In practical terms, this means that this function is designed to take as input a
|
1288
1294
|
relaxed or time-averaged from MD (and folded back into the original primitive
|
1289
1295
|
cell) copy of the :class:`~ase.Atoms` object originally obtained from
|
1290
|
-
:func:`~kim_tools.SingleCrystalTestDriver._get_atoms()`.
|
1296
|
+
:func:`~kim_tools.test_driver.core.SingleCrystalTestDriver._get_atoms()`.
|
1291
1297
|
|
1292
1298
|
If finding the parameter fails, this function will raise an exception. This
|
1293
1299
|
probably indicates a phase transition to a different symmetry, which is a normal
|
@@ -1386,7 +1392,8 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1386
1392
|
|
1387
1393
|
Args:
|
1388
1394
|
change_of_basis:
|
1389
|
-
Passed to
|
1395
|
+
Passed to
|
1396
|
+
:meth:`kim_tools.test_driver.core.SingleCrystalTestDriver._get_atoms`
|
1390
1397
|
filename:
|
1391
1398
|
File to save to. Will be automatically moved and renamed,
|
1392
1399
|
e.g. 'instance.poscar' -> 'output/instance-1.poscar'
|
@@ -1405,8 +1412,10 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1405
1412
|
def _add_property_instance_and_common_crystal_genome_keys(
|
1406
1413
|
self,
|
1407
1414
|
property_name: str,
|
1408
|
-
write_stress: bool = False,
|
1409
|
-
write_temp: bool = False,
|
1415
|
+
write_stress: Union[bool, List[float]] = False,
|
1416
|
+
write_temp: Union[bool, float] = False,
|
1417
|
+
stress_unit: Optional[str] = None,
|
1418
|
+
temp_unit: str = "K",
|
1410
1419
|
disclaimer: Optional[str] = None,
|
1411
1420
|
) -> None:
|
1412
1421
|
"""
|
@@ -1421,9 +1430,20 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1421
1430
|
"tag:staff@noreply.openkim.org,2023-02-21:property/binding-energy-crystal"
|
1422
1431
|
or "binding-energy-crystal"
|
1423
1432
|
write_stress:
|
1424
|
-
|
1433
|
+
What (if any) to write to the "cell-cauchy-stress" key.
|
1434
|
+
If True, write the nominal stress the Test Driver was initialized with.
|
1435
|
+
If a list of floats is given, write that value (it must be a length 6
|
1436
|
+
list representing a stress tensor in Voigt order xx,yy,zz,yz,xz,xy).
|
1437
|
+
If a list is specified, you must also specify `stress_unit`.
|
1425
1438
|
write_temp:
|
1426
|
-
|
1439
|
+
What (if any) to write to the "temperature" key.
|
1440
|
+
If True, write the nominal temperature the Test Driver was initialized
|
1441
|
+
with. If float is given, write that value.
|
1442
|
+
stress_unit:
|
1443
|
+
Unit of stress. Required if a stress tensor is specified in
|
1444
|
+
`write_stress`.
|
1445
|
+
temp_unit:
|
1446
|
+
Unit of temperature. Defaults to K.
|
1427
1447
|
disclaimer:
|
1428
1448
|
An optional disclaimer commenting on the applicability of this result,
|
1429
1449
|
e.g. "This relaxation did not reach the desired tolerance."
|
@@ -1450,20 +1470,37 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1450
1470
|
|
1451
1471
|
short_name = _get_optional_source_value(crystal_structure, "short-name")
|
1452
1472
|
|
1453
|
-
|
1454
|
-
|
1473
|
+
if write_stress is False:
|
1474
|
+
cell_cauchy_stress = None
|
1475
|
+
cell_cauchy_stress_unit = None
|
1476
|
+
elif write_stress is True:
|
1477
|
+
if stress_unit is not None:
|
1478
|
+
raise KIMTestDriverError(
|
1479
|
+
"Setting write_stress=True indicates that you wish to use the "
|
1480
|
+
"nominal stress and stress unit stored in this object. Do not "
|
1481
|
+
"specify a stress_unit in this case"
|
1482
|
+
)
|
1455
1483
|
cell_cauchy_stress = crystal_structure["cell-cauchy-stress"]["source-value"]
|
1484
|
+
cell_cauchy_stress_unit = crystal_structure["cell-cauchy-stress"][
|
1485
|
+
"source-unit"
|
1486
|
+
]
|
1456
1487
|
else:
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1488
|
+
if len(write_stress) != 6:
|
1489
|
+
raise KIMTestDriverError(
|
1490
|
+
"`write_stress` must be a boolean or an array of length 6"
|
1491
|
+
)
|
1492
|
+
cell_cauchy_stress = write_stress
|
1493
|
+
cell_cauchy_stress_unit = stress_unit
|
1460
1494
|
|
1461
|
-
if write_temp:
|
1495
|
+
if write_temp is False:
|
1496
|
+
temperature = None
|
1497
|
+
temperature_unit = None
|
1498
|
+
elif write_temp is True:
|
1462
1499
|
temperature = crystal_structure["temperature"]["source-value"]
|
1500
|
+
temperature_unit = crystal_structure["temperature"]["source-unit"]
|
1463
1501
|
else:
|
1464
|
-
temperature =
|
1465
|
-
|
1466
|
-
temperature_unit = crystal_structure["temperature"]["source-unit"]
|
1502
|
+
temperature = write_temp
|
1503
|
+
temperature_unit = temp_unit
|
1467
1504
|
|
1468
1505
|
crystal_genome_source_structure_id = _get_optional_source_value(
|
1469
1506
|
crystal_structure, "crystal-genome-source-structure-id"
|
@@ -1475,15 +1512,15 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1475
1512
|
prototype_label=prototype_label,
|
1476
1513
|
stoichiometric_species=stoichiometric_species,
|
1477
1514
|
a=a,
|
1515
|
+
a_unit=a_unit,
|
1478
1516
|
parameter_values=parameter_values,
|
1479
1517
|
library_prototype_label=library_prototype_label,
|
1480
1518
|
short_name=short_name,
|
1481
1519
|
cell_cauchy_stress=cell_cauchy_stress,
|
1482
|
-
temperature=temperature,
|
1483
|
-
crystal_genome_source_structure_id=crystal_genome_source_structure_id,
|
1484
|
-
a_unit=a_unit,
|
1485
1520
|
cell_cauchy_stress_unit=cell_cauchy_stress_unit,
|
1521
|
+
temperature=temperature,
|
1486
1522
|
temperature_unit=temperature_unit,
|
1523
|
+
crystal_genome_source_structure_id=crystal_genome_source_structure_id,
|
1487
1524
|
disclaimer=disclaimer,
|
1488
1525
|
property_instances=super()._get_serialized_property_instances(),
|
1489
1526
|
aflow_executable=self.aflow_executable,
|
@@ -1504,8 +1541,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1504
1541
|
Get the nominal temperature
|
1505
1542
|
|
1506
1543
|
Args:
|
1507
|
-
unit:
|
1508
|
-
|
1544
|
+
unit:
|
1545
|
+
The requested unit for the output. Must be understood by the GNU
|
1546
|
+
``units`` utility
|
1509
1547
|
"""
|
1510
1548
|
source_value = self.__nominal_crystal_structure_npt["temperature"][
|
1511
1549
|
"source-value"
|
@@ -1522,8 +1560,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1522
1560
|
Get the nominal stress
|
1523
1561
|
|
1524
1562
|
Args:
|
1525
|
-
unit:
|
1526
|
-
|
1563
|
+
unit:
|
1564
|
+
The requested unit for the output. Must be understood by the GNU
|
1565
|
+
``units`` utility
|
1527
1566
|
"""
|
1528
1567
|
source_value = self.__nominal_crystal_structure_npt["cell-cauchy-stress"][
|
1529
1568
|
"source-value"
|
@@ -1684,7 +1723,8 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1684
1723
|
corresponding to the "old basis" and the returned ``Atoms`` object being
|
1685
1724
|
in the "new basis".
|
1686
1725
|
|
1687
|
-
See the docstring for
|
1726
|
+
See the docstring for
|
1727
|
+
:func:`kim_tools.symmetry_util.core.change_of_basis_atoms` for
|
1688
1728
|
more information on how to define the change of basis.
|
1689
1729
|
|
1690
1730
|
Returns:
|
@@ -1749,7 +1789,8 @@ def query_crystal_structures(
|
|
1749
1789
|
The list of possible shortnames is taken by postprocessing README_PROTO.TXT
|
1750
1790
|
from the AFLOW software and packaged with kim-tools for reproducibility. To
|
1751
1791
|
see the exact list of possible short names, call
|
1752
|
-
:func:`kim_tools.read_shortnames` and inspect the values of
|
1792
|
+
:func:`kim_tools.aflow_util.core.read_shortnames` and inspect the values of
|
1793
|
+
the returned
|
1753
1794
|
dictionary. Note that a given short name corresponds to an exact set of
|
1754
1795
|
parameters (with some tolerance), except the overall scale of the crystal.
|
1755
1796
|
For example, "Hexagonal Close Packed" will return only structures with a
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kim-tools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.5
|
4
4
|
Summary: Base classes and helper routines for writing KIM Tests
|
5
|
-
Author-email: ilia Nikiforov <nikif002@umn.edu>, Ellad Tadmor <tadmor@umn.edu>, Claire Waters <bwaters@umn.edu>, "Daniel S. Karls" <karl0100umn@gmail.com>, Matt Bierbaum <matt.bierbaum@gmail.com>, Eric Fuemmeler <efuemmel@umn.edu>
|
5
|
+
Author-email: ilia Nikiforov <nikif002@umn.edu>, Ellad Tadmor <tadmor@umn.edu>, Claire Waters <bwaters@umn.edu>, "Daniel S. Karls" <karl0100umn@gmail.com>, Matt Bierbaum <matt.bierbaum@gmail.com>, Eric Fuemmeler <efuemmel@umn.edu>, Philipp Hoellmer <ph2484@nyu.edu>, Guanming Zhang <gz2241@nyu.edu>
|
6
6
|
Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
|
7
7
|
Project-URL: Homepage, https://kim-tools.readthedocs.io
|
8
8
|
Project-URL: Issues, https://github.com/openkim/kim-tools/issues
|
@@ -24,9 +24,16 @@ Requires-Dist: sympy>=1.13.2
|
|
24
24
|
Requires-Dist: numpy>=1.13.1
|
25
25
|
Requires-Dist: scipy>=1.3.0
|
26
26
|
Requires-Dist: jinja2>=2.7.2
|
27
|
+
Requires-Dist: matplotlib
|
28
|
+
Requires-Dist: scipy
|
29
|
+
Requires-Dist: scikit-learn
|
27
30
|
Dynamic: license-file
|
28
31
|
|
29
32
|
# kim-tools
|
30
33
|
|
34
|
+

|
35
|
+
[](https://kim-tools.readthedocs.io/en/latest/)
|
36
|
+
[](https://pypi.org/project/kim-tools/)
|
37
|
+
|
31
38
|
KIMTestDriver and SingleCrystalTestDriver classes for creating OpenKIM Test Drivers, and helper routines for writing
|
32
39
|
KIM Tests and Verification Checks. Documentation at https://kim-tools.readthedocs.io.
|
@@ -14,7 +14,10 @@ dependencies = [
|
|
14
14
|
"sympy >= 1.13.2",
|
15
15
|
"numpy >= 1.13.1",
|
16
16
|
"scipy >= 1.3.0",
|
17
|
-
"jinja2 >= 2.7.2"
|
17
|
+
"jinja2 >= 2.7.2",
|
18
|
+
"matplotlib",
|
19
|
+
"scipy",
|
20
|
+
"scikit-learn"
|
18
21
|
]
|
19
22
|
authors = [
|
20
23
|
{ name = "ilia Nikiforov", email = "nikif002@umn.edu" },
|
@@ -22,7 +25,9 @@ authors = [
|
|
22
25
|
{ name = "Claire Waters", email = "bwaters@umn.edu" },
|
23
26
|
{ name = "Daniel S. Karls", email = "karl0100umn@gmail.com" },
|
24
27
|
{ name = "Matt Bierbaum", email = "matt.bierbaum@gmail.com" },
|
25
|
-
{ name = "Eric Fuemmeler", email = "efuemmel@umn.edu"}
|
28
|
+
{ name = "Eric Fuemmeler", email = "efuemmel@umn.edu" },
|
29
|
+
{ name = "Philipp Hoellmer", email = "ph2484@nyu.edu" },
|
30
|
+
{ name = "Guanming Zhang", email = "gz2241@nyu.edu" }
|
26
31
|
]
|
27
32
|
maintainers = [
|
28
33
|
{ name = "ilia Nikiforov", email = "nikif002@umn.edu" },
|
@@ -32,6 +32,7 @@ logging.basicConfig(filename="kim-tools.log", level=logging.INFO, force=True)
|
|
32
32
|
|
33
33
|
TEST_CASES = [572, 365, 1729, 1194, 1473, 166, 1205, 1357, 915, 212, 641, 22]
|
34
34
|
MATERIALS_FILE = "test_structures.json"
|
35
|
+
QUERY_DUMP = "output/query_result.json"
|
35
36
|
|
36
37
|
|
37
38
|
def shuffle_atoms(atoms: Atoms) -> Atoms:
|
@@ -205,6 +206,9 @@ def get_test_crystal_structures(
|
|
205
206
|
indices_to_test = [0]
|
206
207
|
test_crystal_structures += [query_result[i] for i in indices_to_test]
|
207
208
|
|
209
|
+
with open(QUERY_DUMP, "w") as f:
|
210
|
+
json.dump(test_crystal_structures, f)
|
211
|
+
|
208
212
|
return test_crystal_structures
|
209
213
|
|
210
214
|
|
@@ -441,4 +445,6 @@ def test_solve_for_params_of_known_prototype(input_crystal_structures):
|
|
441
445
|
|
442
446
|
|
443
447
|
if __name__ == "__main__":
|
444
|
-
|
448
|
+
test_solve_for_params_of_known_prototype(
|
449
|
+
get_test_crystal_structures(test_cases=None)
|
450
|
+
)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import numpy as np
|
4
4
|
from ase.build import bulk
|
5
5
|
from ase.calculators.kim.kim import KIM
|
6
|
+
from ase.io import read
|
6
7
|
|
7
8
|
from kim_tools import (
|
8
9
|
CENTERING_DIVISORS,
|
@@ -12,6 +13,11 @@ from kim_tools import (
|
|
12
13
|
get_formal_bravais_lattice_from_space_group,
|
13
14
|
get_space_group_number_from_prototype,
|
14
15
|
)
|
16
|
+
from kim_tools.symmetry_util.core import (
|
17
|
+
PeriodExtensionException,
|
18
|
+
kstest_reduced_distances,
|
19
|
+
reduce_and_avg,
|
20
|
+
)
|
15
21
|
|
16
22
|
|
17
23
|
def test_change_of_basis_atoms(
|
@@ -51,5 +57,22 @@ def test_change_of_basis_atoms(
|
|
51
57
|
assert np.isclose(conventional_energy, conventional_rebuilt_energy)
|
52
58
|
|
53
59
|
|
60
|
+
def test_test_reduced_distances():
|
61
|
+
data_file_has_period_extension = {
|
62
|
+
"structures/FeP_period_extended_phase_transition.data": True,
|
63
|
+
"structures/FeP_stable.data": False,
|
64
|
+
}
|
65
|
+
repeat = [11, 11, 11]
|
66
|
+
for data_file in data_file_has_period_extension:
|
67
|
+
has_period_extension = data_file_has_period_extension[data_file]
|
68
|
+
atoms = read(data_file, format="lammps-data")
|
69
|
+
_, reduced_distances = reduce_and_avg(atoms, repeat)
|
70
|
+
try:
|
71
|
+
kstest_reduced_distances(reduced_distances)
|
72
|
+
assert not has_period_extension
|
73
|
+
except PeriodExtensionException:
|
74
|
+
assert has_period_extension
|
75
|
+
|
76
|
+
|
54
77
|
if __name__ == "__main__":
|
55
78
|
test_change_of_basis_atoms()
|
kim_tools-0.2.4/README.md
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/possible_primitive_shifts.json
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{kim_tools-0.2.4 → kim_tools-0.2.5}/kim_tools/symmetry_util/data/wyckoff_multiplicities.json
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|