kim-tools 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl

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/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.2"
1
+ __version__ = "0.2.4"
2
2
 
3
3
  from .aflow_util import *
4
4
  from .aflow_util import __all__ as aflow_all
@@ -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, aflow_executable: str = "aflow", aflow_work_dir: str = "", np: int = 4
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(["aflow", "--proto=A_cF4_225_a"])
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 any(
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 = 1e-5,
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
- rtol: float = 0.01,
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
- rtol:
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=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, sgnum, test_atoms_copy.cell
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
- rtol: float = 0.01,
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
- rtol:
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
- rtol,
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, sgnum: Union[int, str], cell: 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=1e-4):
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, get_short_name: bool = True, prim: bool = True, aflow_np: int = 4
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, output_file: Optional[str] = None, flat: bool = False
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, flat: bool = False
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(crystal_structure, flat=flat)
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(material)
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, atoms: Atoms, max_resid: float = 1e-5, cell_rtol: float = 0.01
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 = AFLOW().solve_for_params_of_known_prototype(
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
- AFLOW().get_prototype_designation_from_atoms(atoms)[
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 = True,
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, properties_to_deduplicate, allow_rotation
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(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 = True,
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, os.path.join(tmpdirname, str(i))
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(cart_rot, sgnum, cell):
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, False, aflow_np
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 = True,
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, allow_rotation
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.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>
@@ -1,12 +1,12 @@
1
- kim_tools/__init__.py,sha256=gGt0sG7foY9MROLXGAYUkxV8GdwEulr_PS5wMm06mcM,433
1
+ kim_tools/__init__.py,sha256=YtOUsgsVDwHP4lYryk1YLNspyTqXCTLof033m3a4xCw,433
2
2
  kim_tools/kimunits.py,sha256=jOxBv9gRVhxPE6ygAIUxOzCAfPI6tT6sBaF_FNl9m-M,5387
3
3
  kim_tools/aflow_util/__init__.py,sha256=lJnQ8fZCma80QVRQeKvY4MQ87oCWu-9KATV3dKJfpDc,80
4
- kim_tools/aflow_util/core.py,sha256=57K2G1jGgJhUA312RkWnhb3MOmlo9B5DdenNb_dIkzc,72206
4
+ kim_tools/aflow_util/core.py,sha256=6JAlTq7ciS1zWOTfwwA2Ms9sXHc5PoRKdCve-PwAsIs,75770
5
5
  kim_tools/aflow_util/data/README_PROTO.TXT,sha256=bTpcd8GHOkpcQn6YUZzqKhiTytwSDpkgu4boeoogT38,447851
6
6
  kim_tools/ase/__init__.py,sha256=1i6ko5tNr0VZC3T7hoEzq4fnSU0DdxNpxXcSaWMcJWc,76
7
7
  kim_tools/ase/core.py,sha256=d6eOu_HSxVr-ae0TSEbY4HKdePxhNu3yv8NN9VDl-BA,30256
8
8
  kim_tools/symmetry_util/__init__.py,sha256=uu-ZSUDUTe2P81rkAS3tXverx31s_uZ3wL4SD_dn5aI,86
9
- kim_tools/symmetry_util/core.py,sha256=VTYH1MRADraJVc6SBfFHZweWI_WZgCViSKM4MazF7KY,21634
9
+ kim_tools/symmetry_util/core.py,sha256=EED_LYfgwf6mmFwTJlzIwTvf8RUiM29bkzEIQrOqwUw,22271
10
10
  kim_tools/symmetry_util/data/possible_primitive_shifts.json,sha256=4OVNgn3NnykgGlYiAcecERmVWiIZFrmP2LZI3ml_Sh0,25010
11
11
  kim_tools/symmetry_util/data/primitive_GENPOS_ops.json,sha256=FDu4H4PosOpK9yKwOPy3SxbH7xLMOmZfKZ4ItKPMjoQ,224498
12
12
  kim_tools/symmetry_util/data/space_groups_for_each_bravais_lattice.json,sha256=wSNu6d5pH72lJ6Zj5MZ64qzwS_6Fn5WOs0ts7E9uPC4,2507
@@ -14,11 +14,11 @@ kim_tools/symmetry_util/data/wyck_pos_xform_under_normalizer.json,sha256=6g1YuYh
14
14
  kim_tools/symmetry_util/data/wyckoff_multiplicities.json,sha256=qG2RPBd_-ejDIfz-E4ZhkHyRpIboxRy7oiXkdDf5Eg8,32270
15
15
  kim_tools/symmetry_util/data/wyckoff_sets.json,sha256=f5ZpHKDHo6_JWki1b7KUGoYLlhU-44Qikw_-PtbLssw,9248
16
16
  kim_tools/test_driver/__init__.py,sha256=KOiceeZNqkfrgZ66CiRiUdniceDrCmmDXQkOw0wXaCQ,92
17
- kim_tools/test_driver/core.py,sha256=bA1tZPM3dES5PZSanN_xPC-SApSB1usO10EvoIq8EgY,78685
17
+ kim_tools/test_driver/core.py,sha256=Pyg6zR4ZeulL26B1QefJUDWiPHhkw4ig770U8pWzYJg,84841
18
18
  kim_tools/vc/__init__.py,sha256=zXjhxXCKVMLBMXXWYG3if7VOpBnsFrn_RjVpnohDm5c,74
19
19
  kim_tools/vc/core.py,sha256=BIjzEExnQAL2S90a_npptRm3ACqAo4fZBtvTDBMWMdw,13963
20
- kim_tools-0.2.2.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
21
- kim_tools-0.2.2.dist-info/METADATA,sha256=3OJoiiqV0-dLI_4hq--8wWF5BcedispUTMgZ1Z4ieR8,1460
22
- kim_tools-0.2.2.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
23
- kim_tools-0.2.2.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
24
- kim_tools-0.2.2.dist-info/RECORD,,
20
+ kim_tools-0.2.4.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
21
+ kim_tools-0.2.4.dist-info/METADATA,sha256=ybguaUJRvdCNr2TJGckx2BGySv5FvPIko1C5ld9kp84,1460
22
+ kim_tools-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ kim_tools-0.2.4.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
24
+ kim_tools-0.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5