kim-tools 0.2.3__py3-none-any.whl → 0.2.5__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.3"
1
+ __version__ = "0.2.5"
2
2
 
3
3
  from .aflow_util import *
4
4
  from .aflow_util import __all__ as aflow_all
@@ -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
@@ -63,6 +63,8 @@ __all__ = [
63
63
  "AFLOW",
64
64
  ]
65
65
 
66
+ AFLOW_EXECUTABLE = "aflow"
67
+
66
68
 
67
69
  class IncorrectSpaceGroupException(Exception):
68
70
  """
@@ -113,7 +115,7 @@ class EquivalentAtomSet:
113
115
 
114
116
 
115
117
  def write_tmp_poscar_from_atoms_and_run_function(
116
- atoms: Atoms, function: callable, *args, **kwargs
118
+ atoms: Atoms, function: Callable, *args, **kwargs
117
119
  ) -> Any:
118
120
  """
119
121
  Write the Atoms file to a NamedTemporaryFile and run 'function' on it.
@@ -141,7 +143,7 @@ def check_number_of_atoms(
141
143
  has the correct number of atoms according to prototype_label
142
144
 
143
145
  Raises:
144
- IncorrectNumAtomsException
146
+ IncorrectNumAtomsException
145
147
  """
146
148
  prototype_label_list = prototype_label.split("_")
147
149
  pearson = prototype_label_list[1]
@@ -267,8 +269,9 @@ def get_equivalent_atom_sets_from_prototype_and_atom_map(
267
269
  `atoms`, and `prototype_label` is the detected prototype label
268
270
 
269
271
  Args:
270
- sort_atoms: If `atom_map` was obtained by sorting `atoms` before writing it to
271
- POSCAR, set this to True
272
+ sort_atoms:
273
+ If `atom_map` was obtained by sorting `atoms` before writing it to
274
+ POSCAR, set this to True
272
275
  """
273
276
 
274
277
  if sort_atoms:
@@ -741,7 +744,10 @@ class AFLOW:
741
744
  """
742
745
 
743
746
  def __init__(
744
- self, aflow_executable: str = "aflow", aflow_work_dir: str = "", np: int = 4
747
+ self,
748
+ aflow_executable: str = AFLOW_EXECUTABLE,
749
+ aflow_work_dir: str = "",
750
+ np: int = 4,
745
751
  ):
746
752
  """
747
753
  Args:
@@ -752,7 +758,7 @@ class AFLOW:
752
758
  self.aflow_executable = aflow_executable
753
759
 
754
760
  try:
755
- subprocess.check_output(["aflow", "--proto=A_cF4_225_a"])
761
+ subprocess.check_output([aflow_executable, "--proto=A_cF4_225_a"])
756
762
  except Exception:
757
763
  raise self.AFLOWNotFoundException(
758
764
  "Failed to run an AFLOW test command. It is likely "
@@ -1209,9 +1215,10 @@ class AFLOW:
1209
1215
  sort_atoms2: Whether to sort atoms2 before comparing.
1210
1216
 
1211
1217
  Returns:
1212
- Tuple of arrays in the order:
1213
- basis transformation, rotation, origin shift, atom_map
1214
- atom_map[index_in_structure_1] = index_in_structure_2
1218
+ * basis transformation
1219
+ * rotation
1220
+ * origin shift
1221
+ * atom_map (atom_map[index_in_structure_1] = index_in_structure_2)
1215
1222
 
1216
1223
  Raises:
1217
1224
  AFLOW.FailedToMatchException: if AFLOW fails to match the crystals
@@ -1494,9 +1501,11 @@ class AFLOW:
1494
1501
  nl_len = nl.size
1495
1502
  cov_mult += 1
1496
1503
  # set the maximum error to 1% of NN distance to follow AFLOW convention
1497
- max_resid = nl.min() * 0.01
1504
+ # rescale by cube root of cell volume to get rough conversion from
1505
+ # cartesian to fractional
1506
+ max_resid = nl.min() * 0.01 * atoms.get_volume() ** (-1 / 3)
1498
1507
  logger.info(
1499
- "Automatically set max residual for solving position "
1508
+ "Automatically set max fractional residual for solving position "
1500
1509
  f"equations to {max_resid}"
1501
1510
  )
1502
1511
 
@@ -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 numpy.typing import ArrayLike
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
- NOTE: This requires ASE >= 3.25 to delete atoms that are close across PBCs
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
+ )
@@ -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,
@@ -464,7 +465,7 @@ class KIMTestDriver(ABC):
464
465
  to be useful to for most KIM tests
465
466
 
466
467
  Attributes:
467
- __kim_model_name (str, optional):
468
+ __kim_model_name (Optional[str]):
468
469
  KIM model name, absent if a non-KIM ASE calculator was provided
469
470
  __calc (:obj:`~ase.calculators.calculator.Calculator`):
470
471
  ASE calculator
@@ -563,7 +564,8 @@ class KIMTestDriver(ABC):
563
564
  ) -> None:
564
565
  """
565
566
  Add a key to the most recent property instance added with
566
- :func:`~kim_tools.KIMTestDriver._add_property_instance`. If the value is an
567
+ :func:`~kim_tools.test_driver.core.KIMTestDriver._add_property_instance`.
568
+ If the value is an
567
569
  array, this function will assume you want to write to the beginning of the array
568
570
  in every dimension. This function is intended to write entire keys in one go,
569
571
  and should not be used for modifying existing keys.
@@ -721,15 +723,16 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
721
723
  prototype_label: str,
722
724
  stoichiometric_species: List[str],
723
725
  a: float,
726
+ a_unit: str,
724
727
  parameter_values: Optional[List[float]] = None,
725
728
  library_prototype_label: Optional[Union[List[str], str]] = None,
726
729
  short_name: Optional[Union[List[str], str]] = None,
727
730
  cell_cauchy_stress: Optional[List[float]] = None,
731
+ cell_cauchy_stress_unit: Optional[str] = None,
728
732
  temperature: Optional[float] = None,
733
+ temperature_unit: Optional[str] = "K",
729
734
  crystal_genome_source_structure_id: Optional[List[List[str]]] = None,
730
- a_unit: str = "angstrom",
731
- cell_cauchy_stress_unit: str = "eV/angstrom^3",
732
- temperature_unit: str = "K",
735
+ aflow_executable: str = AFLOW_EXECUTABLE,
733
736
  ) -> str:
734
737
  """
735
738
  Write common Crystal Genome keys to the last element of ``property_instances``. See
@@ -741,6 +744,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
741
744
  property_instances:
742
745
  An EDN-serialized list of dictionaries representing KIM Property Instances.
743
746
  The key will be added to the last dictionary in the list
747
+ aflow_executable:
748
+ Path to the AFLOW executable
744
749
 
745
750
  Returns:
746
751
  Updated EDN-serialized list of property instances
@@ -756,7 +761,7 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
756
761
  )
757
762
 
758
763
  # get parameter names
759
- aflow = AFLOW()
764
+ aflow = AFLOW(aflow_executable=aflow_executable)
760
765
  aflow_parameter_names = aflow.get_param_names_from_prototype(prototype_label)
761
766
  if parameter_values is None:
762
767
  if len(aflow_parameter_names) > 1:
@@ -795,6 +800,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
795
800
  "Please specify the Cauchy stress as a 6-dimensional vector in Voigt "
796
801
  "order [xx, yy, zz, yz, xz, xy]"
797
802
  )
803
+ if cell_cauchy_stress_unit is None:
804
+ raise KIMTestDriver("Please provide a `cell_cauchy_stress_unit`")
798
805
  property_instances = _add_key_to_current_property_instance(
799
806
  property_instances,
800
807
  "cell-cauchy-stress",
@@ -803,6 +810,8 @@ def _add_common_crystal_genome_keys_to_current_property_instance(
803
810
  )
804
811
 
805
812
  if temperature is not None:
813
+ if temperature_unit is None:
814
+ raise KIMTestDriver("Please provide a `temperature_unit`")
806
815
  property_instances = _add_key_to_current_property_instance(
807
816
  property_instances, "temperature", temperature, temperature_unit
808
817
  )
@@ -822,17 +831,18 @@ def _add_property_instance_and_common_crystal_genome_keys(
822
831
  prototype_label: str,
823
832
  stoichiometric_species: List[str],
824
833
  a: float,
834
+ a_unit: str,
825
835
  parameter_values: Optional[List[float]] = None,
826
836
  library_prototype_label: Optional[Union[List[str], str]] = None,
827
837
  short_name: Optional[Union[List[str], str]] = None,
828
838
  cell_cauchy_stress: Optional[List[float]] = None,
839
+ cell_cauchy_stress_unit: Optional[str] = None,
829
840
  temperature: Optional[float] = None,
841
+ temperature_unit: Optional[str] = "K",
830
842
  crystal_genome_source_structure_id: Optional[List[List[str]]] = None,
831
- a_unit: str = "angstrom",
832
- cell_cauchy_stress_unit: str = "eV/angstrom^3",
833
- temperature_unit: str = "K",
834
843
  disclaimer: Optional[str] = None,
835
844
  property_instances: Optional[str] = None,
845
+ aflow_executable: str = AFLOW_EXECUTABLE,
836
846
  ) -> str:
837
847
  """
838
848
  Initialize a new property instance to ``property_instances`` (an empty
@@ -853,6 +863,8 @@ def _add_property_instance_and_common_crystal_genome_keys(
853
863
  "This relaxation did not reach the desired tolerance."
854
864
  property_instances:
855
865
  A pre-existing EDN-serialized list of KIM Property instances to add to
866
+ aflow_executable:
867
+ Path to the AFLOW executable
856
868
 
857
869
  Returns:
858
870
  Updated EDN-serialized list of property instances
@@ -861,24 +873,29 @@ def _add_property_instance_and_common_crystal_genome_keys(
861
873
  property_name, disclaimer, property_instances
862
874
  )
863
875
  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,
876
+ property_instances=property_instances,
877
+ prototype_label=prototype_label,
878
+ stoichiometric_species=stoichiometric_species,
879
+ a=a,
880
+ a_unit=a_unit,
881
+ parameter_values=parameter_values,
882
+ library_prototype_label=library_prototype_label,
883
+ short_name=short_name,
884
+ temperature=temperature,
885
+ temperature_unit=temperature_unit,
886
+ crystal_genome_source_structure_id=crystal_genome_source_structure_id,
887
+ cell_cauchy_stress_unit=cell_cauchy_stress_unit,
888
+ cell_cauchy_stress=cell_cauchy_stress,
889
+ aflow_executable=aflow_executable,
877
890
  )
878
891
 
879
892
 
880
893
  def get_crystal_structure_from_atoms(
881
- atoms: Atoms, get_short_name: bool = True, prim: bool = True, aflow_np: int = 4
894
+ atoms: Atoms,
895
+ get_short_name: bool = True,
896
+ prim: bool = True,
897
+ aflow_np: int = 4,
898
+ aflow_executable: str = AFLOW_EXECUTABLE,
882
899
  ) -> Dict:
883
900
  """
884
901
  By performing a symmetry analysis on an :class:`~ase.Atoms` object, generate a
@@ -896,6 +913,8 @@ def get_crystal_structure_from_atoms(
896
913
  whether to compare against AFLOW prototype library to obtain short-name
897
914
  prim: whether to primitivize the atoms object first
898
915
  aflow_np: Number of processors to use with AFLOW executable
916
+ aflow_executable:
917
+ Path to the AFLOW executable
899
918
 
900
919
  Returns:
901
920
  A dictionary that has the following Property Keys (possibly optionally) defined.
@@ -912,7 +931,7 @@ def get_crystal_structure_from_atoms(
912
931
  - "short-name"
913
932
 
914
933
  """
915
- aflow = AFLOW(np=aflow_np)
934
+ aflow = AFLOW(aflow_executable=aflow_executable, np=aflow_np)
916
935
 
917
936
  proto_des = aflow.get_prototype_designation_from_atoms(atoms, prim=prim)
918
937
  library_prototype_label, short_name = (
@@ -933,16 +952,21 @@ def get_crystal_structure_from_atoms(
933
952
  prototype_label=proto_des["aflow_prototype_label"],
934
953
  stoichiometric_species=sorted(list(set(atoms.get_chemical_symbols()))),
935
954
  a=a,
955
+ a_unit="angstrom",
936
956
  parameter_values=parameter_values,
937
957
  library_prototype_label=library_prototype_label,
938
958
  short_name=short_name,
959
+ aflow_executable=aflow_executable,
939
960
  )
940
961
 
941
962
  return kim_edn.loads(property_instances)[0]
942
963
 
943
964
 
944
965
  def get_poscar_from_crystal_structure(
945
- crystal_structure: Dict, output_file: Optional[str] = None, flat: bool = False
966
+ crystal_structure: Dict,
967
+ output_file: Optional[str] = None,
968
+ flat: bool = False,
969
+ aflow_executable: str = AFLOW_EXECUTABLE,
946
970
  ) -> Optional[str]:
947
971
  """
948
972
  Write a POSCAR coordinate file (or output it as a multiline string) from the AFLOW
@@ -968,13 +992,15 @@ def get_poscar_from_crystal_structure(
968
992
  Name of the output file. If not provided, the output is returned as a string
969
993
  flat:
970
994
  whether the input dictionary is flattened
995
+ aflow_executable:
996
+ path to AFLOW executable
971
997
  Returns:
972
998
  If ``output_file`` is not provided, a string in POSCAR format containg the
973
999
  primitive unit cell of the crystal as defined in
974
1000
  http://doi.org/10.1016/j.commatsci.2017.01.017. Lengths are always in angstrom.
975
1001
  Raises:
976
- AFLOW.ChangedSymmetryException: if the symmetry of the atoms object is different
977
- from ``prototype_label``
1002
+ AFLOW.ChangedSymmetryException:
1003
+ if the symmetry of the atoms object is different from ``prototype_label``
978
1004
  """
979
1005
  if flat:
980
1006
  prototype_label = crystal_structure["prototype-label.source-value"]
@@ -993,7 +1019,7 @@ def get_poscar_from_crystal_structure(
993
1019
  "source-value"
994
1020
  ]
995
1021
 
996
- aflow = AFLOW()
1022
+ aflow = AFLOW(aflow_executable=aflow_executable)
997
1023
  aflow_parameter_names = aflow.get_param_names_from_prototype(prototype_label)
998
1024
 
999
1025
  # Atoms objects are always in angstrom
@@ -1035,7 +1061,9 @@ def get_poscar_from_crystal_structure(
1035
1061
 
1036
1062
 
1037
1063
  def get_atoms_from_crystal_structure(
1038
- crystal_structure: Dict, flat: bool = False
1064
+ crystal_structure: Dict,
1065
+ flat: bool = False,
1066
+ aflow_executable: str = AFLOW_EXECUTABLE,
1039
1067
  ) -> Atoms:
1040
1068
  """
1041
1069
  Generate an :class:`~ase.Atoms` object from the AFLOW Prototype Designation obtained
@@ -1059,6 +1087,8 @@ def get_atoms_from_crystal_structure(
1059
1087
  Dictionary containing the required keys in KIM Property Instance format
1060
1088
  flat:
1061
1089
  whether the dictionary is flattened
1090
+ aflow_executable:
1091
+ path to AFLOW executable
1062
1092
 
1063
1093
  Returns:
1064
1094
  Primitive unit cell of the crystal as defined in the
@@ -1070,7 +1100,9 @@ def get_atoms_from_crystal_structure(
1070
1100
  if the symmetry of the atoms object is different from ``prototype_label``
1071
1101
  """
1072
1102
  try:
1073
- poscar_string = get_poscar_from_crystal_structure(crystal_structure, flat=flat)
1103
+ poscar_string = get_poscar_from_crystal_structure(
1104
+ crystal_structure, flat=flat, aflow_executable=aflow_executable
1105
+ )
1074
1106
  except AFLOW.ChangedSymmetryException as e:
1075
1107
  # re-raise, just indicating that this function knows about this exception
1076
1108
  raise e
@@ -1094,8 +1126,23 @@ class SingleCrystalTestDriver(KIMTestDriver):
1094
1126
  <https://openkim.org/properties/show/crystal-structure-npt>`_
1095
1127
  property representing the nominal crystal structure and conditions of the
1096
1128
  current call to the Test Driver.
1129
+ aflow_executable [str]:
1130
+ Path to the AFLOW executable
1097
1131
  """
1098
1132
 
1133
+ def __init__(
1134
+ self, model: Union[str, Calculator], aflow_executable: str = AFLOW_EXECUTABLE
1135
+ ) -> None:
1136
+ """
1137
+ Args:
1138
+ model:
1139
+ ASE calculator or KIM model name to use
1140
+ aflow_executable:
1141
+ Path to AFLOW executable
1142
+ """
1143
+ self.aflow_executable = aflow_executable
1144
+ super().__init__(model)
1145
+
1099
1146
  def _setup(
1100
1147
  self,
1101
1148
  material: Union[Atoms, Dict],
@@ -1156,11 +1203,14 @@ class SingleCrystalTestDriver(KIMTestDriver):
1156
1203
  simply provides recordkeeping of it. It is up to derived classes to
1157
1204
  implement actually setting the temperature of the system.
1158
1205
  """
1206
+
1159
1207
  if cell_cauchy_stress_eV_angstrom3 is None:
1160
1208
  cell_cauchy_stress_eV_angstrom3 = [0, 0, 0, 0, 0, 0]
1161
1209
 
1162
1210
  if isinstance(material, Atoms):
1163
- crystal_structure = get_crystal_structure_from_atoms(material)
1211
+ crystal_structure = get_crystal_structure_from_atoms(
1212
+ atoms=material, aflow_executable=self.aflow_executable
1213
+ )
1164
1214
  msg = (
1165
1215
  "Rebuilding atoms object in a standard setting defined by "
1166
1216
  "doi.org/10.1016/j.commatsci.2017.01.017. See log file or computed "
@@ -1243,7 +1293,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
1243
1293
  In practical terms, this means that this function is designed to take as input a
1244
1294
  relaxed or time-averaged from MD (and folded back into the original primitive
1245
1295
  cell) copy of the :class:`~ase.Atoms` object originally obtained from
1246
- :func:`~kim_tools.SingleCrystalTestDriver._get_atoms()`.
1296
+ :func:`~kim_tools.test_driver.core.SingleCrystalTestDriver._get_atoms()`.
1247
1297
 
1248
1298
  If finding the parameter fails, this function will raise an exception. This
1249
1299
  probably indicates a phase transition to a different symmetry, which is a normal
@@ -1279,9 +1329,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
1279
1329
  If a more definitive error indicating a phase transformation is
1280
1330
  encountered
1281
1331
  """
1282
-
1332
+ aflow = AFLOW(aflow_executable=self.aflow_executable)
1283
1333
  try:
1284
- aflow_parameter_values = AFLOW().solve_for_params_of_known_prototype(
1334
+ aflow_parameter_values = aflow.solve_for_params_of_known_prototype(
1285
1335
  atoms=atoms,
1286
1336
  prototype_label=self.__nominal_crystal_structure_npt["prototype-label"][
1287
1337
  "source-value"
@@ -1324,10 +1374,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
1324
1374
  Whether or not the symmetry is unchanged
1325
1375
 
1326
1376
  """
1377
+ aflow = AFLOW(aflow_executable=self.aflow_executable)
1327
1378
  return prototype_labels_are_equivalent(
1328
- AFLOW().get_prototype_designation_from_atoms(atoms)[
1329
- "aflow_prototype_label"
1330
- ],
1379
+ aflow.get_prototype_designation_from_atoms(atoms)["aflow_prototype_label"],
1331
1380
  self.__nominal_crystal_structure_npt["prototype-label"]["source-value"],
1332
1381
  )
1333
1382
 
@@ -1343,7 +1392,8 @@ class SingleCrystalTestDriver(KIMTestDriver):
1343
1392
 
1344
1393
  Args:
1345
1394
  change_of_basis:
1346
- Passed to :meth:`kim_tools.SingleCrystalTestDriver._get_atoms`
1395
+ Passed to
1396
+ :meth:`kim_tools.test_driver.core.SingleCrystalTestDriver._get_atoms`
1347
1397
  filename:
1348
1398
  File to save to. Will be automatically moved and renamed,
1349
1399
  e.g. 'instance.poscar' -> 'output/instance-1.poscar'
@@ -1362,8 +1412,10 @@ class SingleCrystalTestDriver(KIMTestDriver):
1362
1412
  def _add_property_instance_and_common_crystal_genome_keys(
1363
1413
  self,
1364
1414
  property_name: str,
1365
- write_stress: bool = False,
1366
- 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",
1367
1419
  disclaimer: Optional[str] = None,
1368
1420
  ) -> None:
1369
1421
  """
@@ -1378,9 +1430,20 @@ class SingleCrystalTestDriver(KIMTestDriver):
1378
1430
  "tag:staff@noreply.openkim.org,2023-02-21:property/binding-energy-crystal"
1379
1431
  or "binding-energy-crystal"
1380
1432
  write_stress:
1381
- Write the "cell-cauchy-stress" key
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`.
1382
1438
  write_temp:
1383
- Write the "temperature" key
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.
1384
1447
  disclaimer:
1385
1448
  An optional disclaimer commenting on the applicability of this result,
1386
1449
  e.g. "This relaxation did not reach the desired tolerance."
@@ -1407,20 +1470,37 @@ class SingleCrystalTestDriver(KIMTestDriver):
1407
1470
 
1408
1471
  short_name = _get_optional_source_value(crystal_structure, "short-name")
1409
1472
 
1410
- # stress and temperature are always there (default 0), but we don't always write
1411
- if write_stress:
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
+ )
1412
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
+ ]
1413
1487
  else:
1414
- cell_cauchy_stress = None
1415
-
1416
- cell_cauchy_stress_unit = crystal_structure["cell-cauchy-stress"]["source-unit"]
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
1417
1494
 
1418
- if write_temp:
1495
+ if write_temp is False:
1496
+ temperature = None
1497
+ temperature_unit = None
1498
+ elif write_temp is True:
1419
1499
  temperature = crystal_structure["temperature"]["source-value"]
1500
+ temperature_unit = crystal_structure["temperature"]["source-unit"]
1420
1501
  else:
1421
- temperature = None
1422
-
1423
- temperature_unit = crystal_structure["temperature"]["source-unit"]
1502
+ temperature = write_temp
1503
+ temperature_unit = temp_unit
1424
1504
 
1425
1505
  crystal_genome_source_structure_id = _get_optional_source_value(
1426
1506
  crystal_structure, "crystal-genome-source-structure-id"
@@ -1432,17 +1512,18 @@ class SingleCrystalTestDriver(KIMTestDriver):
1432
1512
  prototype_label=prototype_label,
1433
1513
  stoichiometric_species=stoichiometric_species,
1434
1514
  a=a,
1515
+ a_unit=a_unit,
1435
1516
  parameter_values=parameter_values,
1436
1517
  library_prototype_label=library_prototype_label,
1437
1518
  short_name=short_name,
1438
1519
  cell_cauchy_stress=cell_cauchy_stress,
1439
- temperature=temperature,
1440
- crystal_genome_source_structure_id=crystal_genome_source_structure_id,
1441
- a_unit=a_unit,
1442
1520
  cell_cauchy_stress_unit=cell_cauchy_stress_unit,
1521
+ temperature=temperature,
1443
1522
  temperature_unit=temperature_unit,
1523
+ crystal_genome_source_structure_id=crystal_genome_source_structure_id,
1444
1524
  disclaimer=disclaimer,
1445
1525
  property_instances=super()._get_serialized_property_instances(),
1526
+ aflow_executable=self.aflow_executable,
1446
1527
  )
1447
1528
  )
1448
1529
 
@@ -1460,8 +1541,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
1460
1541
  Get the nominal temperature
1461
1542
 
1462
1543
  Args:
1463
- unit: The requested unit for the output. Must be understood by the GNU
1464
- ``units`` utility
1544
+ unit:
1545
+ The requested unit for the output. Must be understood by the GNU
1546
+ ``units`` utility
1465
1547
  """
1466
1548
  source_value = self.__nominal_crystal_structure_npt["temperature"][
1467
1549
  "source-value"
@@ -1478,8 +1560,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
1478
1560
  Get the nominal stress
1479
1561
 
1480
1562
  Args:
1481
- unit: The requested unit for the output. Must be understood by the GNU
1482
- ``units`` utility
1563
+ unit:
1564
+ The requested unit for the output. Must be understood by the GNU
1565
+ ``units`` utility
1483
1566
  """
1484
1567
  source_value = self.__nominal_crystal_structure_npt["cell-cauchy-stress"][
1485
1568
  "source-value"
@@ -1578,6 +1661,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
1578
1661
  aflow_np=aflow_np,
1579
1662
  rot_rtol=rot_rtol,
1580
1663
  rot_atol=rot_atol,
1664
+ aflow_executable=self.aflow_executable,
1581
1665
  )
1582
1666
  logger.info(
1583
1667
  f"Deduplicated {len(self.property_instances)} Property Instances "
@@ -1639,7 +1723,8 @@ class SingleCrystalTestDriver(KIMTestDriver):
1639
1723
  corresponding to the "old basis" and the returned ``Atoms`` object being
1640
1724
  in the "new basis".
1641
1725
 
1642
- See the docstring for :func:`kim_tools.change_of_basis_atoms` for
1726
+ See the docstring for
1727
+ :func:`kim_tools.symmetry_util.core.change_of_basis_atoms` for
1643
1728
  more information on how to define the change of basis.
1644
1729
 
1645
1730
  Returns:
@@ -1647,7 +1732,9 @@ class SingleCrystalTestDriver(KIMTestDriver):
1647
1732
  Lengths are always in angstrom
1648
1733
  """
1649
1734
  crystal_structure = self.__nominal_crystal_structure_npt
1650
- atoms_prim = get_atoms_from_crystal_structure(crystal_structure)
1735
+ atoms_prim = get_atoms_from_crystal_structure(
1736
+ crystal_structure, aflow_executable=self.aflow_executable
1737
+ )
1651
1738
  if isinstance(change_of_basis, str):
1652
1739
  if change_of_basis.lower() == "primitive":
1653
1740
  change_of_basis_matrix = None
@@ -1702,7 +1789,8 @@ def query_crystal_structures(
1702
1789
  The list of possible shortnames is taken by postprocessing README_PROTO.TXT
1703
1790
  from the AFLOW software and packaged with kim-tools for reproducibility. To
1704
1791
  see the exact list of possible short names, call
1705
- :func:`kim_tools.read_shortnames` and inspect the values of the returned
1792
+ :func:`kim_tools.aflow_util.core.read_shortnames` and inspect the values of
1793
+ the returned
1706
1794
  dictionary. Note that a given short name corresponds to an exact set of
1707
1795
  parameters (with some tolerance), except the overall scale of the crystal.
1708
1796
  For example, "Hexagonal Close Packed" will return only structures with a
@@ -1785,6 +1873,7 @@ def detect_unique_crystal_structures(
1785
1873
  aflow_np: int = 4,
1786
1874
  rot_rtol: float = 0.01,
1787
1875
  rot_atol: float = 0.01,
1876
+ aflow_executable=AFLOW_EXECUTABLE,
1788
1877
  ) -> Dict:
1789
1878
  """
1790
1879
  Detect which of the provided crystal structures is unique
@@ -1813,6 +1902,8 @@ def detect_unique_crystal_structures(
1813
1902
  rotations. Default value chosen to be commensurate with AFLOW
1814
1903
  default distance tolerance of 0.01*(NN distance). Used only if
1815
1904
  `allow_rotation` is False
1905
+ aflow_executable:
1906
+ Path to AFLOW executable
1816
1907
  Returns:
1817
1908
  Dictionary with keys corresponding to indices of unique structures and values
1818
1909
  being lists of indices of their duplicates
@@ -1820,7 +1911,7 @@ def detect_unique_crystal_structures(
1820
1911
  if len(crystal_structures) == 0:
1821
1912
  return []
1822
1913
 
1823
- aflow = AFLOW(np=aflow_np)
1914
+ aflow = AFLOW(aflow_executable=aflow_executable, np=aflow_np)
1824
1915
 
1825
1916
  with TemporaryDirectory() as tmpdirname:
1826
1917
  # I don't know if crystal_structurs is a list or a dict with integer keys
@@ -1832,7 +1923,9 @@ def detect_unique_crystal_structures(
1832
1923
  structure = crystal_structures[i]
1833
1924
  try:
1834
1925
  get_poscar_from_crystal_structure(
1835
- structure, os.path.join(tmpdirname, str(i))
1926
+ structure,
1927
+ os.path.join(tmpdirname, str(i)),
1928
+ aflow_executable=aflow_executable,
1836
1929
  )
1837
1930
  except AFLOW.ChangedSymmetryException:
1838
1931
  logger.info(
@@ -1888,6 +1981,7 @@ def detect_unique_crystal_structures(
1888
1981
  aflow_np=aflow_np,
1889
1982
  rot_rtol=rot_rtol,
1890
1983
  rot_atol=rot_atol,
1984
+ aflow_executable=aflow_executable,
1891
1985
  )
1892
1986
  )
1893
1987
 
@@ -1901,6 +1995,7 @@ def get_deduplicated_property_instances(
1901
1995
  aflow_np: int = 4,
1902
1996
  rot_rtol: float = 0.01,
1903
1997
  rot_atol: float = 0.01,
1998
+ aflow_executable: str = AFLOW_EXECUTABLE,
1904
1999
  ) -> List[Dict]:
1905
2000
  """
1906
2001
  Given a list of dictionaries constituting KIM Property instances,
@@ -1935,6 +2030,8 @@ def get_deduplicated_property_instances(
1935
2030
  rotations. Default value chosen to be commensurate with AFLOW
1936
2031
  default distance tolerance of 0.01*(NN distance). Used only if
1937
2032
  `allow_rotation` is False
2033
+ aflow_executable:
2034
+ Path to aflow executable
1938
2035
 
1939
2036
  Returns:
1940
2037
  The deduplicated property instances
@@ -1969,6 +2066,7 @@ def get_deduplicated_property_instances(
1969
2066
  aflow_np=aflow_np,
1970
2067
  rot_rtol=rot_rtol,
1971
2068
  rot_atol=rot_atol,
2069
+ aflow_executable=aflow_executable,
1972
2070
  )
1973
2071
 
1974
2072
  # Put together the list of unique instances for the current
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kim-tools
3
- Version: 0.2.3
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
+ ![testing](https://github.com/openkim/kim-tools/actions/workflows/testing.yml/badge.svg)
35
+ [![docs](https://app.readthedocs.org/projects/kim-tools/badge/?version=latest)](https://kim-tools.readthedocs.io/en/latest/)
36
+ [![PyPI](https://img.shields.io/pypi/v/kim-tools.svg)](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.
@@ -1,12 +1,12 @@
1
- kim_tools/__init__.py,sha256=KCoi0Z7lrEF8Q2naGttDB6JIrnlSoBPfubmh0QePzPY,433
1
+ kim_tools/__init__.py,sha256=R9ao3IDvoNpX2rM78JclHnE-LLpCDqYzT5n-dqIlY5g,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=1oHweHfm1m_7hVD1ziyrWpe9IbkbxFXAj7FKtav8FiI,75538
4
+ kim_tools/aflow_util/core.py,sha256=t12Gi7dNRhkYhFgBpWrFrJJPGVIdstAAcVaNoOtI7u0,75789
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=EED_LYfgwf6mmFwTJlzIwTvf8RUiM29bkzEIQrOqwUw,22271
9
+ kim_tools/symmetry_util/core.py,sha256=lxg02QlDmfUtBxw0CZRpuX84cRhk9dLZv33-xpPHF3g,29042
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=N0xnJzF_yF5tav3nqeUyX1NSrJUDigYV6n7Ym4wtzLA,82518
17
+ kim_tools/test_driver/core.py,sha256=Zo8rnuGChRBg-YhcSC69BYhVKlhNOTQpAROy5E6Ll48,86900
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.3.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
21
- kim_tools-0.2.3.dist-info/METADATA,sha256=Z_rs3Y3nRmX-11yJo8MuGK-GHUXvdhPWdpUPwLQmmFc,1460
22
- kim_tools-0.2.3.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
23
- kim_tools-0.2.3.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
24
- kim_tools-0.2.3.dist-info/RECORD,,
20
+ kim_tools-0.2.5.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
21
+ kim_tools-0.2.5.dist-info/METADATA,sha256=l2u-Jdzex0bEIvtwyVCWTIH5qTCbrQoCZqy5j-AFqsg,1910
22
+ kim_tools-0.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ kim_tools-0.2.5.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
24
+ kim_tools-0.2.5.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