kim-tools 0.2.2__tar.gz → 0.2.4__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.2/kim_tools.egg-info → kim_tools-0.2.4}/PKG-INFO +1 -1
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/__init__.py +1 -1
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/aflow_util/core.py +91 -21
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/core.py +17 -3
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/test_driver/core.py +177 -39
- {kim_tools-0.2.2 → kim_tools-0.2.4/kim_tools.egg-info}/PKG-INFO +1 -1
- {kim_tools-0.2.2 → kim_tools-0.2.4}/tests/test_symmetry_util.py +3 -1
- {kim_tools-0.2.2 → kim_tools-0.2.4}/LICENSE.CDDL +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/MANIFEST.in +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/README.md +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/aflow_util/__init__.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/aflow_util/data/README_PROTO.TXT +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/ase/__init__.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/ase/core.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/kimunits.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/__init__.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/possible_primitive_shifts.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/primitive_GENPOS_ops.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/space_groups_for_each_bravais_lattice.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/wyck_pos_xform_under_normalizer.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/wyckoff_multiplicities.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/symmetry_util/data/wyckoff_sets.json +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/test_driver/__init__.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/vc/__init__.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools/vc/core.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools.egg-info/SOURCES.txt +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools.egg-info/dependency_links.txt +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools.egg-info/requires.txt +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/kim_tools.egg-info/top_level.txt +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/pyproject.toml +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/setup.cfg +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/setup.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/tests/test_aflow_util.py +0 -0
- {kim_tools-0.2.2 → kim_tools-0.2.4}/tests/test_test_driver.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kim-tools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: Base classes and helper routines for writing KIM Tests
|
5
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>
|
6
6
|
Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
|
@@ -18,6 +18,7 @@ import ase
|
|
18
18
|
import numpy as np
|
19
19
|
from ase import Atoms
|
20
20
|
from ase.cell import Cell
|
21
|
+
from ase.neighborlist import natural_cutoffs, neighbor_list
|
21
22
|
from numpy.typing import ArrayLike
|
22
23
|
from sympy import Symbol, linear_eq_to_matrix, matrix2numpy, parse_expr
|
23
24
|
|
@@ -62,6 +63,8 @@ __all__ = [
|
|
62
63
|
"AFLOW",
|
63
64
|
]
|
64
65
|
|
66
|
+
AFLOW_EXECUTABLE = "aflow"
|
67
|
+
|
65
68
|
|
66
69
|
class IncorrectSpaceGroupException(Exception):
|
67
70
|
"""
|
@@ -740,7 +743,10 @@ class AFLOW:
|
|
740
743
|
"""
|
741
744
|
|
742
745
|
def __init__(
|
743
|
-
self,
|
746
|
+
self,
|
747
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
748
|
+
aflow_work_dir: str = "",
|
749
|
+
np: int = 4,
|
744
750
|
):
|
745
751
|
"""
|
746
752
|
Args:
|
@@ -751,7 +757,7 @@ class AFLOW:
|
|
751
757
|
self.aflow_executable = aflow_executable
|
752
758
|
|
753
759
|
try:
|
754
|
-
subprocess.check_output([
|
760
|
+
subprocess.check_output([aflow_executable, "--proto=A_cF4_225_a"])
|
755
761
|
except Exception:
|
756
762
|
raise self.AFLOWNotFoundException(
|
757
763
|
"Failed to run an AFLOW test command. It is likely "
|
@@ -1116,9 +1122,7 @@ class AFLOW:
|
|
1116
1122
|
misfit_min_overall = struct["misfit"]
|
1117
1123
|
library_proto_overall = struct["name"]
|
1118
1124
|
found_overall = True
|
1119
|
-
if struct["misfit"] < misfit_min_inlist and
|
1120
|
-
proto in struct["name"] for proto in shortnames
|
1121
|
-
):
|
1125
|
+
if struct["misfit"] < misfit_min_inlist and struct["name"] in shortnames:
|
1122
1126
|
misfit_min_inlist = struct["misfit"]
|
1123
1127
|
library_proto_inlist = struct["name"]
|
1124
1128
|
found_inlist = True
|
@@ -1429,8 +1433,10 @@ class AFLOW:
|
|
1429
1433
|
self,
|
1430
1434
|
atoms: Atoms,
|
1431
1435
|
prototype_label: str,
|
1432
|
-
max_resid: float =
|
1436
|
+
max_resid: Optional[float] = None,
|
1433
1437
|
cell_rtol: float = 0.01,
|
1438
|
+
rot_rtol: float = 0.01,
|
1439
|
+
rot_atol: float = 0.01,
|
1434
1440
|
) -> List[float]:
|
1435
1441
|
"""
|
1436
1442
|
Given an Atoms object that is a primitive cell of its Bravais lattice as
|
@@ -1455,8 +1461,19 @@ class AFLOW:
|
|
1455
1461
|
max_resid:
|
1456
1462
|
Maximum residual allowed when attempting to match the fractional
|
1457
1463
|
positions of the atoms to the crystallographic equations
|
1464
|
+
If not provided, this is automatically set to 0.01*(minimum NN distance)
|
1458
1465
|
cell_rtol:
|
1459
1466
|
Relative tolerance on cell lengths and angles
|
1467
|
+
Justification for default value: AFLOW uses 0.01*(minimum NN distance)
|
1468
|
+
as default tolerance.
|
1469
|
+
rot_rtol:
|
1470
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1471
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1472
|
+
default distance tolerance of 0.01*(NN distance)
|
1473
|
+
rot_atol:
|
1474
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1475
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1476
|
+
default distance tolerance of 0.01*(NN distance)
|
1460
1477
|
|
1461
1478
|
Returns:
|
1462
1479
|
List of free parameters that will regenerate `atoms` (up to permutations,
|
@@ -1469,6 +1486,27 @@ class AFLOW:
|
|
1469
1486
|
if AFLOW fails to match the re-generated crystal to the input crystal
|
1470
1487
|
|
1471
1488
|
"""
|
1489
|
+
# If max_resid not provided, determine it from neighborlist
|
1490
|
+
if max_resid is None:
|
1491
|
+
nl_len = 0
|
1492
|
+
cov_mult = 1
|
1493
|
+
while nl_len == 0:
|
1494
|
+
logger.info(
|
1495
|
+
"Attempting to find NN distance by searching "
|
1496
|
+
f"within covalent radii times {cov_mult}"
|
1497
|
+
)
|
1498
|
+
nl = neighbor_list("d", atoms, natural_cutoffs(atoms, mult=cov_mult))
|
1499
|
+
nl_len = nl.size
|
1500
|
+
cov_mult += 1
|
1501
|
+
# set the maximum error to 1% of NN distance to follow AFLOW convention
|
1502
|
+
# rescale by cube root of cell volume to get rough conversion from
|
1503
|
+
# cartesian to fractional
|
1504
|
+
max_resid = nl.min() * 0.01 * atoms.get_volume() ** (-1 / 3)
|
1505
|
+
logger.info(
|
1506
|
+
"Automatically set max fractional residual for solving position "
|
1507
|
+
f"equations to {max_resid}"
|
1508
|
+
)
|
1509
|
+
|
1472
1510
|
# solve for cell parameters
|
1473
1511
|
cell_params = solve_for_aflow_cell_params_from_primitive_ase_cell_params(
|
1474
1512
|
atoms.cell.cellpar(), prototype_label
|
@@ -1655,11 +1693,13 @@ class AFLOW:
|
|
1655
1693
|
# The internal shift may have taken us to an internal parameter
|
1656
1694
|
# solution that represents a rotation, so we need to check
|
1657
1695
|
if self.confirm_unrotated_prototype_designation(
|
1658
|
-
atoms,
|
1659
|
-
species,
|
1660
|
-
prototype_label,
|
1661
|
-
candidate_prototype_param_values,
|
1662
|
-
cell_rtol,
|
1696
|
+
reference_atoms=atoms,
|
1697
|
+
species=species,
|
1698
|
+
prototype_label=prototype_label,
|
1699
|
+
parameter_values=candidate_prototype_param_values,
|
1700
|
+
cell_rtol=cell_rtol,
|
1701
|
+
rot_rtol=rot_rtol,
|
1702
|
+
rot_atol=rot_atol,
|
1663
1703
|
):
|
1664
1704
|
logger.info(
|
1665
1705
|
f"Found set of parameters for prototype {prototype_label} "
|
@@ -1689,7 +1729,9 @@ class AFLOW:
|
|
1689
1729
|
test_atoms: Atoms,
|
1690
1730
|
ref_atoms: Atoms,
|
1691
1731
|
sgnum: Union[int, str],
|
1692
|
-
|
1732
|
+
cell_rtol: float = 0.01,
|
1733
|
+
rot_rtol: float = 0.01,
|
1734
|
+
rot_atol: float = 0.01,
|
1693
1735
|
) -> bool:
|
1694
1736
|
"""
|
1695
1737
|
Check whether `test_atoms` and `reference_atoms` are unrotated as follows:
|
@@ -1711,11 +1753,21 @@ class AFLOW:
|
|
1711
1753
|
Primitive cell of a crystal
|
1712
1754
|
sgnum:
|
1713
1755
|
Space group number
|
1714
|
-
|
1756
|
+
cell_rtol:
|
1715
1757
|
Parameter to pass to :func:`numpy.allclose` for comparing cell params.
|
1758
|
+
Justification for default value: AFLOW uses 0.01*(minimum NN distance)
|
1759
|
+
as default tolerance.
|
1760
|
+
rot_rtol:
|
1761
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1762
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1763
|
+
default distance tolerance of 0.01*(NN distance)
|
1764
|
+
rot_atol:
|
1765
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1766
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1767
|
+
default distance tolerance of 0.01*(NN distance)
|
1716
1768
|
"""
|
1717
1769
|
if not np.allclose(
|
1718
|
-
ref_atoms.cell.cellpar(), test_atoms.cell.cellpar(), rtol=
|
1770
|
+
ref_atoms.cell.cellpar(), test_atoms.cell.cellpar(), rtol=cell_rtol
|
1719
1771
|
):
|
1720
1772
|
logger.info(
|
1721
1773
|
"Cell lengths and angles do not match.\n"
|
@@ -1748,7 +1800,11 @@ class AFLOW:
|
|
1748
1800
|
return False
|
1749
1801
|
|
1750
1802
|
return cartesian_rotation_is_in_point_group(
|
1751
|
-
cart_rot,
|
1803
|
+
cart_rot=cart_rot,
|
1804
|
+
sgnum=sgnum,
|
1805
|
+
cell=test_atoms_copy.cell,
|
1806
|
+
rtol=rot_rtol,
|
1807
|
+
atol=rot_atol,
|
1752
1808
|
)
|
1753
1809
|
|
1754
1810
|
def confirm_unrotated_prototype_designation(
|
@@ -1757,7 +1813,9 @@ class AFLOW:
|
|
1757
1813
|
species: List[str],
|
1758
1814
|
prototype_label: str,
|
1759
1815
|
parameter_values: List[float],
|
1760
|
-
|
1816
|
+
cell_rtol: float = 0.01,
|
1817
|
+
rot_rtol: float = 0.01,
|
1818
|
+
rot_atol: float = 0.01,
|
1761
1819
|
) -> bool:
|
1762
1820
|
"""
|
1763
1821
|
Check whether the provided prototype designation recreates ``reference_atoms``
|
@@ -1779,8 +1837,18 @@ class AFLOW:
|
|
1779
1837
|
without specified atomic species
|
1780
1838
|
parameter_values:
|
1781
1839
|
The free parameters of the AFLOW prototype designation
|
1782
|
-
|
1840
|
+
cell_rtol:
|
1783
1841
|
Parameter to pass to :func:`numpy.allclose` for comparing cell params
|
1842
|
+
Justification for default value: AFLOW uses 0.01*(minimum NN distance)
|
1843
|
+
as default tolerance.
|
1844
|
+
rot_rtol:
|
1845
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1846
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1847
|
+
default distance tolerance of 0.01*(NN distance)
|
1848
|
+
rot_atol:
|
1849
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1850
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1851
|
+
default distance tolerance of 0.01*(NN distance)
|
1784
1852
|
|
1785
1853
|
Returns:
|
1786
1854
|
Whether or not the crystals match
|
@@ -1792,8 +1860,10 @@ class AFLOW:
|
|
1792
1860
|
)
|
1793
1861
|
|
1794
1862
|
return self.confirm_atoms_unrotated_when_cells_aligned(
|
1795
|
-
test_atoms,
|
1796
|
-
reference_atoms,
|
1797
|
-
get_space_group_number_from_prototype(prototype_label),
|
1798
|
-
|
1863
|
+
test_atoms=test_atoms,
|
1864
|
+
ref_atoms=reference_atoms,
|
1865
|
+
sgnum=get_space_group_number_from_prototype(prototype_label),
|
1866
|
+
cell_rtol=cell_rtol,
|
1867
|
+
rot_rtol=rot_rtol,
|
1868
|
+
rot_atol=rot_atol,
|
1799
1869
|
)
|
@@ -168,7 +168,11 @@ def fractional_to_cartesian_itc_rotation_from_ase_cell(
|
|
168
168
|
|
169
169
|
|
170
170
|
def cartesian_rotation_is_in_point_group(
|
171
|
-
cart_rot: ArrayLike,
|
171
|
+
cart_rot: ArrayLike,
|
172
|
+
sgnum: Union[int, str],
|
173
|
+
cell: ArrayLike,
|
174
|
+
rtol: float = 1e-2,
|
175
|
+
atol: float = 1e-2,
|
172
176
|
) -> bool:
|
173
177
|
"""
|
174
178
|
Check that a Cartesian rotation is in the point group of a crystal given by its
|
@@ -184,6 +188,14 @@ def cartesian_rotation_is_in_point_group(
|
|
184
188
|
http://doi.org/10.1016/j.commatsci.2017.01.017, with each row being a
|
185
189
|
cartesian vector representing a lattice vector. This is
|
186
190
|
consistent with most simulation packages, but transposed from the ITC
|
191
|
+
rtol:
|
192
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
193
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
194
|
+
default distance tolerance of 0.01*(NN distance)
|
195
|
+
atol:
|
196
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
197
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
198
|
+
default distance tolerance of 0.01*(NN distance)
|
187
199
|
"""
|
188
200
|
# we don't care about properly transposing (i.e. worrying whether it's operating on
|
189
201
|
# row or column vectors) the input cart_rot because that one is orthogonal, and
|
@@ -192,9 +204,11 @@ def cartesian_rotation_is_in_point_group(
|
|
192
204
|
|
193
205
|
space_group_ops = get_primitive_genpos_ops(sgnum)
|
194
206
|
|
207
|
+
logger.info(f"Attempting to match fractional rotation:\n{frac_rot}")
|
208
|
+
|
195
209
|
for op in space_group_ops:
|
196
|
-
if np.allclose(frac_rot, op["W"], atol=
|
197
|
-
logger.info("Found matching rotation")
|
210
|
+
if np.allclose(frac_rot, op["W"], rtol=rtol, atol=atol):
|
211
|
+
logger.info(f"Found matching rotation with point group op:\n{op['W']}")
|
198
212
|
return True
|
199
213
|
|
200
214
|
logger.info("No matching rotation found")
|
@@ -65,6 +65,7 @@ from ..aflow_util import (
|
|
65
65
|
get_space_group_number_from_prototype,
|
66
66
|
prototype_labels_are_equivalent,
|
67
67
|
)
|
68
|
+
from ..aflow_util.core import AFLOW_EXECUTABLE
|
68
69
|
from ..kimunits import convert_list, convert_units
|
69
70
|
from ..symmetry_util import (
|
70
71
|
cartesian_rotation_is_in_point_group,
|
@@ -730,6 +731,7 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
730
731
|
a_unit: str = "angstrom",
|
731
732
|
cell_cauchy_stress_unit: str = "eV/angstrom^3",
|
732
733
|
temperature_unit: str = "K",
|
734
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
733
735
|
) -> str:
|
734
736
|
"""
|
735
737
|
Write common Crystal Genome keys to the last element of ``property_instances``. See
|
@@ -741,6 +743,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
741
743
|
property_instances:
|
742
744
|
An EDN-serialized list of dictionaries representing KIM Property Instances.
|
743
745
|
The key will be added to the last dictionary in the list
|
746
|
+
aflow_executable:
|
747
|
+
Path to the AFLOW executable
|
744
748
|
|
745
749
|
Returns:
|
746
750
|
Updated EDN-serialized list of property instances
|
@@ -756,7 +760,7 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
|
|
756
760
|
)
|
757
761
|
|
758
762
|
# get parameter names
|
759
|
-
aflow = AFLOW()
|
763
|
+
aflow = AFLOW(aflow_executable=aflow_executable)
|
760
764
|
aflow_parameter_names = aflow.get_param_names_from_prototype(prototype_label)
|
761
765
|
if parameter_values is None:
|
762
766
|
if len(aflow_parameter_names) > 1:
|
@@ -833,6 +837,7 @@ def _add_property_instance_and_common_crystal_genome_keys(
|
|
833
837
|
temperature_unit: str = "K",
|
834
838
|
disclaimer: Optional[str] = None,
|
835
839
|
property_instances: Optional[str] = None,
|
840
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
836
841
|
) -> str:
|
837
842
|
"""
|
838
843
|
Initialize a new property instance to ``property_instances`` (an empty
|
@@ -853,6 +858,8 @@ def _add_property_instance_and_common_crystal_genome_keys(
|
|
853
858
|
"This relaxation did not reach the desired tolerance."
|
854
859
|
property_instances:
|
855
860
|
A pre-existing EDN-serialized list of KIM Property instances to add to
|
861
|
+
aflow_executable:
|
862
|
+
Path to the AFLOW executable
|
856
863
|
|
857
864
|
Returns:
|
858
865
|
Updated EDN-serialized list of property instances
|
@@ -861,24 +868,29 @@ def _add_property_instance_and_common_crystal_genome_keys(
|
|
861
868
|
property_name, disclaimer, property_instances
|
862
869
|
)
|
863
870
|
return _add_common_crystal_genome_keys_to_current_property_instance(
|
864
|
-
property_instances,
|
865
|
-
prototype_label,
|
866
|
-
stoichiometric_species,
|
867
|
-
a,
|
868
|
-
parameter_values,
|
869
|
-
library_prototype_label,
|
870
|
-
short_name,
|
871
|
-
cell_cauchy_stress,
|
872
|
-
temperature,
|
873
|
-
crystal_genome_source_structure_id,
|
874
|
-
a_unit,
|
875
|
-
cell_cauchy_stress_unit,
|
876
|
-
temperature_unit,
|
871
|
+
property_instances=property_instances,
|
872
|
+
prototype_label=prototype_label,
|
873
|
+
stoichiometric_species=stoichiometric_species,
|
874
|
+
a=a,
|
875
|
+
parameter_values=parameter_values,
|
876
|
+
library_prototype_label=library_prototype_label,
|
877
|
+
short_name=short_name,
|
878
|
+
cell_cauchy_stress=cell_cauchy_stress,
|
879
|
+
temperature=temperature,
|
880
|
+
crystal_genome_source_structure_id=crystal_genome_source_structure_id,
|
881
|
+
a_unit=a_unit,
|
882
|
+
cell_cauchy_stress_unit=cell_cauchy_stress_unit,
|
883
|
+
temperature_unit=temperature_unit,
|
884
|
+
aflow_executable=aflow_executable,
|
877
885
|
)
|
878
886
|
|
879
887
|
|
880
888
|
def get_crystal_structure_from_atoms(
|
881
|
-
atoms: Atoms,
|
889
|
+
atoms: Atoms,
|
890
|
+
get_short_name: bool = True,
|
891
|
+
prim: bool = True,
|
892
|
+
aflow_np: int = 4,
|
893
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
882
894
|
) -> Dict:
|
883
895
|
"""
|
884
896
|
By performing a symmetry analysis on an :class:`~ase.Atoms` object, generate a
|
@@ -896,6 +908,8 @@ def get_crystal_structure_from_atoms(
|
|
896
908
|
whether to compare against AFLOW prototype library to obtain short-name
|
897
909
|
prim: whether to primitivize the atoms object first
|
898
910
|
aflow_np: Number of processors to use with AFLOW executable
|
911
|
+
aflow_executable:
|
912
|
+
Path to the AFLOW executable
|
899
913
|
|
900
914
|
Returns:
|
901
915
|
A dictionary that has the following Property Keys (possibly optionally) defined.
|
@@ -912,7 +926,7 @@ def get_crystal_structure_from_atoms(
|
|
912
926
|
- "short-name"
|
913
927
|
|
914
928
|
"""
|
915
|
-
aflow = AFLOW(np=aflow_np)
|
929
|
+
aflow = AFLOW(aflow_executable=aflow_executable, np=aflow_np)
|
916
930
|
|
917
931
|
proto_des = aflow.get_prototype_designation_from_atoms(atoms, prim=prim)
|
918
932
|
library_prototype_label, short_name = (
|
@@ -936,13 +950,17 @@ def get_crystal_structure_from_atoms(
|
|
936
950
|
parameter_values=parameter_values,
|
937
951
|
library_prototype_label=library_prototype_label,
|
938
952
|
short_name=short_name,
|
953
|
+
aflow_executable=aflow_executable,
|
939
954
|
)
|
940
955
|
|
941
956
|
return kim_edn.loads(property_instances)[0]
|
942
957
|
|
943
958
|
|
944
959
|
def get_poscar_from_crystal_structure(
|
945
|
-
crystal_structure: Dict,
|
960
|
+
crystal_structure: Dict,
|
961
|
+
output_file: Optional[str] = None,
|
962
|
+
flat: bool = False,
|
963
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
946
964
|
) -> Optional[str]:
|
947
965
|
"""
|
948
966
|
Write a POSCAR coordinate file (or output it as a multiline string) from the AFLOW
|
@@ -968,6 +986,8 @@ def get_poscar_from_crystal_structure(
|
|
968
986
|
Name of the output file. If not provided, the output is returned as a string
|
969
987
|
flat:
|
970
988
|
whether the input dictionary is flattened
|
989
|
+
aflow_executable:
|
990
|
+
path to AFLOW executable
|
971
991
|
Returns:
|
972
992
|
If ``output_file`` is not provided, a string in POSCAR format containg the
|
973
993
|
primitive unit cell of the crystal as defined in
|
@@ -993,7 +1013,7 @@ def get_poscar_from_crystal_structure(
|
|
993
1013
|
"source-value"
|
994
1014
|
]
|
995
1015
|
|
996
|
-
aflow = AFLOW()
|
1016
|
+
aflow = AFLOW(aflow_executable=aflow_executable)
|
997
1017
|
aflow_parameter_names = aflow.get_param_names_from_prototype(prototype_label)
|
998
1018
|
|
999
1019
|
# Atoms objects are always in angstrom
|
@@ -1035,7 +1055,9 @@ def get_poscar_from_crystal_structure(
|
|
1035
1055
|
|
1036
1056
|
|
1037
1057
|
def get_atoms_from_crystal_structure(
|
1038
|
-
crystal_structure: Dict,
|
1058
|
+
crystal_structure: Dict,
|
1059
|
+
flat: bool = False,
|
1060
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
1039
1061
|
) -> Atoms:
|
1040
1062
|
"""
|
1041
1063
|
Generate an :class:`~ase.Atoms` object from the AFLOW Prototype Designation obtained
|
@@ -1059,6 +1081,8 @@ def get_atoms_from_crystal_structure(
|
|
1059
1081
|
Dictionary containing the required keys in KIM Property Instance format
|
1060
1082
|
flat:
|
1061
1083
|
whether the dictionary is flattened
|
1084
|
+
aflow_executable:
|
1085
|
+
path to AFLOW executable
|
1062
1086
|
|
1063
1087
|
Returns:
|
1064
1088
|
Primitive unit cell of the crystal as defined in the
|
@@ -1070,7 +1094,9 @@ def get_atoms_from_crystal_structure(
|
|
1070
1094
|
if the symmetry of the atoms object is different from ``prototype_label``
|
1071
1095
|
"""
|
1072
1096
|
try:
|
1073
|
-
poscar_string = get_poscar_from_crystal_structure(
|
1097
|
+
poscar_string = get_poscar_from_crystal_structure(
|
1098
|
+
crystal_structure, flat=flat, aflow_executable=aflow_executable
|
1099
|
+
)
|
1074
1100
|
except AFLOW.ChangedSymmetryException as e:
|
1075
1101
|
# re-raise, just indicating that this function knows about this exception
|
1076
1102
|
raise e
|
@@ -1094,8 +1120,23 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1094
1120
|
<https://openkim.org/properties/show/crystal-structure-npt>`_
|
1095
1121
|
property representing the nominal crystal structure and conditions of the
|
1096
1122
|
current call to the Test Driver.
|
1123
|
+
aflow_executable [str]:
|
1124
|
+
Path to the AFLOW executable
|
1097
1125
|
"""
|
1098
1126
|
|
1127
|
+
def __init__(
|
1128
|
+
self, model: Union[str, Calculator], aflow_executable: str = AFLOW_EXECUTABLE
|
1129
|
+
) -> None:
|
1130
|
+
"""
|
1131
|
+
Args:
|
1132
|
+
model:
|
1133
|
+
ASE calculator or KIM model name to use
|
1134
|
+
aflow_executable:
|
1135
|
+
Path to AFLOW executable
|
1136
|
+
"""
|
1137
|
+
self.aflow_executable = aflow_executable
|
1138
|
+
super().__init__(model)
|
1139
|
+
|
1099
1140
|
def _setup(
|
1100
1141
|
self,
|
1101
1142
|
material: Union[Atoms, Dict],
|
@@ -1156,11 +1197,14 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1156
1197
|
simply provides recordkeeping of it. It is up to derived classes to
|
1157
1198
|
implement actually setting the temperature of the system.
|
1158
1199
|
"""
|
1200
|
+
|
1159
1201
|
if cell_cauchy_stress_eV_angstrom3 is None:
|
1160
1202
|
cell_cauchy_stress_eV_angstrom3 = [0, 0, 0, 0, 0, 0]
|
1161
1203
|
|
1162
1204
|
if isinstance(material, Atoms):
|
1163
|
-
crystal_structure = get_crystal_structure_from_atoms(
|
1205
|
+
crystal_structure = get_crystal_structure_from_atoms(
|
1206
|
+
atoms=material, aflow_executable=self.aflow_executable
|
1207
|
+
)
|
1164
1208
|
msg = (
|
1165
1209
|
"Rebuilding atoms object in a standard setting defined by "
|
1166
1210
|
"doi.org/10.1016/j.commatsci.2017.01.017. See log file or computed "
|
@@ -1219,7 +1263,12 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1219
1263
|
logger.info(msg)
|
1220
1264
|
|
1221
1265
|
def _update_nominal_parameter_values(
|
1222
|
-
self,
|
1266
|
+
self,
|
1267
|
+
atoms: Atoms,
|
1268
|
+
max_resid: Optional[float] = None,
|
1269
|
+
cell_rtol: float = 0.01,
|
1270
|
+
rot_rtol: float = 0.01,
|
1271
|
+
rot_atol: float = 0.01,
|
1223
1272
|
) -> None:
|
1224
1273
|
"""
|
1225
1274
|
Update the nominal parameter values of the nominal crystal structure from the
|
@@ -1250,9 +1299,20 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1250
1299
|
atoms: Structure to analyze to get the new parameter values
|
1251
1300
|
max_resid:
|
1252
1301
|
Maximum residual allowed when attempting to match the fractional
|
1253
|
-
positions of the atoms to the crystallographic equations
|
1302
|
+
positions of the atoms to the crystallographic equations.
|
1303
|
+
If not provided, this is automatically set to 0.01*(minimum NN distance)
|
1254
1304
|
cell_rtol:
|
1255
|
-
Relative tolerance on cell lengths and angles
|
1305
|
+
Relative tolerance on cell lengths and angles.
|
1306
|
+
Justification for default value: AFLOW uses 0.01*(minimum NN distance)
|
1307
|
+
as default tolerance.
|
1308
|
+
rot_rtol:
|
1309
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1310
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1311
|
+
default distance tolerance of 0.01*(NN distance)
|
1312
|
+
rot_atol:
|
1313
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1314
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1315
|
+
default distance tolerance of 0.01*(NN distance)
|
1256
1316
|
|
1257
1317
|
Raises:
|
1258
1318
|
AFLOW.FailedToMatchException:
|
@@ -1263,15 +1323,17 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1263
1323
|
If a more definitive error indicating a phase transformation is
|
1264
1324
|
encountered
|
1265
1325
|
"""
|
1266
|
-
|
1326
|
+
aflow = AFLOW(aflow_executable=self.aflow_executable)
|
1267
1327
|
try:
|
1268
|
-
aflow_parameter_values =
|
1328
|
+
aflow_parameter_values = aflow.solve_for_params_of_known_prototype(
|
1269
1329
|
atoms=atoms,
|
1270
1330
|
prototype_label=self.__nominal_crystal_structure_npt["prototype-label"][
|
1271
1331
|
"source-value"
|
1272
1332
|
],
|
1273
1333
|
max_resid=max_resid,
|
1274
1334
|
cell_rtol=cell_rtol,
|
1335
|
+
rot_rtol=rot_rtol,
|
1336
|
+
rot_atol=rot_atol,
|
1275
1337
|
)
|
1276
1338
|
except (AFLOW.FailedToMatchException, AFLOW.ChangedSymmetryException) as e:
|
1277
1339
|
raise type(e)(
|
@@ -1306,10 +1368,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1306
1368
|
Whether or not the symmetry is unchanged
|
1307
1369
|
|
1308
1370
|
"""
|
1371
|
+
aflow = AFLOW(aflow_executable=self.aflow_executable)
|
1309
1372
|
return prototype_labels_are_equivalent(
|
1310
|
-
|
1311
|
-
"aflow_prototype_label"
|
1312
|
-
],
|
1373
|
+
aflow.get_prototype_designation_from_atoms(atoms)["aflow_prototype_label"],
|
1313
1374
|
self.__nominal_crystal_structure_npt["prototype-label"]["source-value"],
|
1314
1375
|
)
|
1315
1376
|
|
@@ -1425,6 +1486,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1425
1486
|
temperature_unit=temperature_unit,
|
1426
1487
|
disclaimer=disclaimer,
|
1427
1488
|
property_instances=super()._get_serialized_property_instances(),
|
1489
|
+
aflow_executable=self.aflow_executable,
|
1428
1490
|
)
|
1429
1491
|
)
|
1430
1492
|
|
@@ -1516,7 +1578,10 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1516
1578
|
def deduplicate_property_instances(
|
1517
1579
|
self,
|
1518
1580
|
properties_to_deduplicate: Optional[List[str]] = None,
|
1519
|
-
allow_rotation: bool =
|
1581
|
+
allow_rotation: bool = False,
|
1582
|
+
aflow_np: int = 4,
|
1583
|
+
rot_rtol: float = 0.01,
|
1584
|
+
rot_atol: float = 0.01,
|
1520
1585
|
) -> None:
|
1521
1586
|
"""
|
1522
1587
|
In the internally stored property instances,
|
@@ -1537,9 +1602,27 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1537
1602
|
allow_rotation:
|
1538
1603
|
Whether or not structures that are rotated by a rotation that is not in
|
1539
1604
|
the crystal's point group are considered identical
|
1605
|
+
aflow_np:
|
1606
|
+
Number of processors to use to run the AFLOW executable
|
1607
|
+
rot_rtol:
|
1608
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1609
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1610
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1611
|
+
`allow_rotation` is False
|
1612
|
+
rot_atol:
|
1613
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1614
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1615
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1616
|
+
`allow_rotation` is False
|
1540
1617
|
"""
|
1541
1618
|
deduplicated_property_instances = get_deduplicated_property_instances(
|
1542
|
-
self.property_instances,
|
1619
|
+
property_instances=self.property_instances,
|
1620
|
+
properties_to_deduplicate=properties_to_deduplicate,
|
1621
|
+
allow_rotation=allow_rotation,
|
1622
|
+
aflow_np=aflow_np,
|
1623
|
+
rot_rtol=rot_rtol,
|
1624
|
+
rot_atol=rot_atol,
|
1625
|
+
aflow_executable=self.aflow_executable,
|
1543
1626
|
)
|
1544
1627
|
logger.info(
|
1545
1628
|
f"Deduplicated {len(self.property_instances)} Property Instances "
|
@@ -1609,7 +1692,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
|
|
1609
1692
|
Lengths are always in angstrom
|
1610
1693
|
"""
|
1611
1694
|
crystal_structure = self.__nominal_crystal_structure_npt
|
1612
|
-
atoms_prim = get_atoms_from_crystal_structure(
|
1695
|
+
atoms_prim = get_atoms_from_crystal_structure(
|
1696
|
+
crystal_structure, aflow_executable=self.aflow_executable
|
1697
|
+
)
|
1613
1698
|
if isinstance(change_of_basis, str):
|
1614
1699
|
if change_of_basis.lower() == "primitive":
|
1615
1700
|
change_of_basis_matrix = None
|
@@ -1743,8 +1828,11 @@ def query_crystal_structures(
|
|
1743
1828
|
|
1744
1829
|
def detect_unique_crystal_structures(
|
1745
1830
|
crystal_structures: Union[List[Dict], Dict],
|
1746
|
-
allow_rotation: bool =
|
1831
|
+
allow_rotation: bool = False,
|
1747
1832
|
aflow_np: int = 4,
|
1833
|
+
rot_rtol: float = 0.01,
|
1834
|
+
rot_atol: float = 0.01,
|
1835
|
+
aflow_executable=AFLOW_EXECUTABLE,
|
1748
1836
|
) -> Dict:
|
1749
1837
|
"""
|
1750
1838
|
Detect which of the provided crystal structures is unique
|
@@ -1761,6 +1849,20 @@ def detect_unique_crystal_structures(
|
|
1761
1849
|
allow_rotation:
|
1762
1850
|
Whether or not structures that are rotated by a rotation that is not in the
|
1763
1851
|
crystal's point group are considered identical
|
1852
|
+
aflow_np:
|
1853
|
+
Number of processors to use to run the AFLOW executable
|
1854
|
+
rot_rtol:
|
1855
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1856
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1857
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1858
|
+
`allow_rotation` is False
|
1859
|
+
rot_atol:
|
1860
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1861
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1862
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1863
|
+
`allow_rotation` is False
|
1864
|
+
aflow_executable:
|
1865
|
+
Path to AFLOW executable
|
1764
1866
|
Returns:
|
1765
1867
|
Dictionary with keys corresponding to indices of unique structures and values
|
1766
1868
|
being lists of indices of their duplicates
|
@@ -1768,7 +1870,7 @@ def detect_unique_crystal_structures(
|
|
1768
1870
|
if len(crystal_structures) == 0:
|
1769
1871
|
return []
|
1770
1872
|
|
1771
|
-
aflow = AFLOW(np=aflow_np)
|
1873
|
+
aflow = AFLOW(aflow_executable=aflow_executable, np=aflow_np)
|
1772
1874
|
|
1773
1875
|
with TemporaryDirectory() as tmpdirname:
|
1774
1876
|
# I don't know if crystal_structurs is a list or a dict with integer keys
|
@@ -1780,7 +1882,9 @@ def detect_unique_crystal_structures(
|
|
1780
1882
|
structure = crystal_structures[i]
|
1781
1883
|
try:
|
1782
1884
|
get_poscar_from_crystal_structure(
|
1783
|
-
structure,
|
1885
|
+
structure,
|
1886
|
+
os.path.join(tmpdirname, str(i)),
|
1887
|
+
aflow_executable=aflow_executable,
|
1784
1888
|
)
|
1785
1889
|
except AFLOW.ChangedSymmetryException:
|
1786
1890
|
logger.info(
|
@@ -1813,7 +1917,13 @@ def detect_unique_crystal_structures(
|
|
1813
1917
|
"structures_duplicate"
|
1814
1918
|
]:
|
1815
1919
|
cart_rot = potential_rotated_duplicate["rotation"]
|
1816
|
-
if not cartesian_rotation_is_in_point_group(
|
1920
|
+
if not cartesian_rotation_is_in_point_group(
|
1921
|
+
cart_rot=cart_rot,
|
1922
|
+
sgnum=sgnum,
|
1923
|
+
cell=cell,
|
1924
|
+
rtol=rot_rtol,
|
1925
|
+
atol=rot_atol,
|
1926
|
+
):
|
1817
1927
|
i_rot_dup = int(
|
1818
1928
|
potential_rotated_duplicate["name"].split("/")[-1]
|
1819
1929
|
)
|
@@ -1825,7 +1935,12 @@ def detect_unique_crystal_structures(
|
|
1825
1935
|
|
1826
1936
|
unique_materials.update(
|
1827
1937
|
detect_unique_crystal_structures(
|
1828
|
-
rotated_structures,
|
1938
|
+
crystal_structures=rotated_structures,
|
1939
|
+
allow_rotation=False,
|
1940
|
+
aflow_np=aflow_np,
|
1941
|
+
rot_rtol=rot_rtol,
|
1942
|
+
rot_atol=rot_atol,
|
1943
|
+
aflow_executable=aflow_executable,
|
1829
1944
|
)
|
1830
1945
|
)
|
1831
1946
|
|
@@ -1835,7 +1950,11 @@ def detect_unique_crystal_structures(
|
|
1835
1950
|
def get_deduplicated_property_instances(
|
1836
1951
|
property_instances: List[Dict],
|
1837
1952
|
properties_to_deduplicate: Optional[List[str]] = None,
|
1838
|
-
allow_rotation: bool =
|
1953
|
+
allow_rotation: bool = False,
|
1954
|
+
aflow_np: int = 4,
|
1955
|
+
rot_rtol: float = 0.01,
|
1956
|
+
rot_atol: float = 0.01,
|
1957
|
+
aflow_executable: str = AFLOW_EXECUTABLE,
|
1839
1958
|
) -> List[Dict]:
|
1840
1959
|
"""
|
1841
1960
|
Given a list of dictionaries constituting KIM Property instances,
|
@@ -1858,6 +1977,20 @@ def get_deduplicated_property_instances(
|
|
1858
1977
|
allow_rotation:
|
1859
1978
|
Whether or not structures that are rotated by a rotation that is not in the
|
1860
1979
|
crystal's point group are considered identical
|
1980
|
+
aflow_np:
|
1981
|
+
Number of processors to use to run the AFLOW executable
|
1982
|
+
rot_rtol:
|
1983
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1984
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1985
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1986
|
+
`allow_rotation` is False
|
1987
|
+
rot_atol:
|
1988
|
+
Parameter to pass to :func:`numpy.allclose` for compariong fractional
|
1989
|
+
rotations. Default value chosen to be commensurate with AFLOW
|
1990
|
+
default distance tolerance of 0.01*(NN distance). Used only if
|
1991
|
+
`allow_rotation` is False
|
1992
|
+
aflow_executable:
|
1993
|
+
Path to aflow executable
|
1861
1994
|
|
1862
1995
|
Returns:
|
1863
1996
|
The deduplicated property instances
|
@@ -1887,7 +2020,12 @@ def get_deduplicated_property_instances(
|
|
1887
2020
|
|
1888
2021
|
# Get unique-duplicate dictionary
|
1889
2022
|
unique_crystal_structures = detect_unique_crystal_structures(
|
1890
|
-
property_instances_curr_name,
|
2023
|
+
crystal_structures=property_instances_curr_name,
|
2024
|
+
allow_rotation=allow_rotation,
|
2025
|
+
aflow_np=aflow_np,
|
2026
|
+
rot_rtol=rot_rtol,
|
2027
|
+
rot_atol=rot_atol,
|
2028
|
+
aflow_executable=aflow_executable,
|
1891
2029
|
)
|
1892
2030
|
|
1893
2031
|
# Put together the list of unique instances for the current
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kim-tools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: Base classes and helper routines for writing KIM Tests
|
5
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>
|
6
6
|
Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
|
@@ -19,7 +19,9 @@ def test_change_of_basis_atoms(
|
|
19
19
|
):
|
20
20
|
calc = KIM("LJ_ElliottAkerson_2015_Universal__MO_959249795837_003")
|
21
21
|
atoms_conventional.calc = calc
|
22
|
-
crystal_structure = get_crystal_structure_from_atoms(
|
22
|
+
crystal_structure = get_crystal_structure_from_atoms(
|
23
|
+
atoms_conventional, get_short_name=False
|
24
|
+
)
|
23
25
|
prototype_label = crystal_structure["prototype-label"]["source-value"]
|
24
26
|
sgnum = get_space_group_number_from_prototype(prototype_label)
|
25
27
|
formal_bravais_lattice = get_formal_bravais_lattice_from_space_group(sgnum)
|
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
|
{kim_tools-0.2.2 → kim_tools-0.2.4}/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.2 → kim_tools-0.2.4}/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
|
File without changes
|
File without changes
|
File without changes
|