kim-tools 0.3.5__py3-none-any.whl → 0.3.6__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.3.5"
1
+ __version__ = "0.3.6"
2
2
 
3
3
  from .aflow_util import *
4
4
  from .aflow_util import __all__ as aflow_all
@@ -392,6 +392,30 @@ def get_wyckoff_lists_from_prototype(prototype_label: str) -> List[str]:
392
392
  return expanded_wyckoff_letters
393
393
 
394
394
 
395
+ def get_atom_indices_for_each_wyckoff_orb(prototype_label: str) -> List[Dict]:
396
+ """
397
+ Get a list of dictionaries containing the atom indices of each Wyckoff
398
+ orbit.
399
+
400
+ Returns:
401
+ The information is in this format:
402
+
403
+ [{"letter":"a", "indices":[0,1]}, ... ]
404
+ """
405
+ return_list = []
406
+ wyck_lists = get_wyckoff_lists_from_prototype(prototype_label)
407
+ sgnum = get_space_group_number_from_prototype(prototype_label)
408
+ range_start = 0
409
+ for letter in "".join(wyck_lists):
410
+ multiplicity = get_primitive_wyckoff_multiplicity(sgnum, letter)
411
+ range_end = range_start + multiplicity
412
+ return_list.append(
413
+ {"letter": letter, "indices": list(range(range_start, range_end))}
414
+ )
415
+ range_start = range_end
416
+ return return_list
417
+
418
+
395
419
  def prototype_labels_are_equivalent(
396
420
  prototype_label_1: str,
397
421
  prototype_label_2: str,
@@ -841,9 +865,8 @@ class AFLOW:
841
865
  "that the AFLOW executable was not found."
842
866
  )
843
867
  # I am fine with allowing prereleases
844
- aflow_ver_no_prerelease = Version.parse(ver_str)
845
- aflow_ver_no_prerelease.replace(prerelease=None)
846
- if aflow_ver_no_prerelease < Version.parse(REQUIRED_AFLOW):
868
+ aflow_ver = Version.parse(ver_str)
869
+ if aflow_ver.replace(prerelease=None) < Version.parse(REQUIRED_AFLOW):
847
870
  raise self.AFLOWNotFoundException(
848
871
  f"Your AFLOW version {ver_str} is less "
849
872
  f"than the required {REQUIRED_AFLOW}"
@@ -14,6 +14,7 @@ import numpy as np
14
14
  import numpy.typing as npt
15
15
  from ase import Atoms
16
16
  from ase.cell import Cell
17
+ from ase.constraints import FixSymmetry
17
18
  from ase.geometry import get_distances, get_duplicate_atoms
18
19
  from matplotlib.backends.backend_pdf import PdfPages
19
20
  from pymatgen.core.operations import SymmOp
@@ -617,6 +618,20 @@ def get_primitive_genpos_ops(sgnum: Union[int, str]) -> List[Dict]:
617
618
  return np.asarray(json.load(f)[str(sgnum)])
618
619
 
619
620
 
621
+ def transform_atoms(atoms: Atoms, op: Dict) -> Atoms:
622
+ """
623
+ Transform atoms by an operation defined by a dictionary containing a matrix 'W' and
624
+ translation 'w' defined as fractional operations in the unit cell. 'W' should be
625
+ oriented to operate on column vectors
626
+ """
627
+ frac_pos_columns = atoms.get_scaled_positions().T
628
+ frac_pos_cols_xform = op["W"] @ frac_pos_columns + np.reshape(op["w"], (3, 1))
629
+ atoms_transformed = atoms.copy()
630
+ atoms_transformed.set_scaled_positions(frac_pos_cols_xform.T)
631
+ atoms_transformed.wrap()
632
+ return atoms_transformed
633
+
634
+
620
635
  def reduce_and_avg(
621
636
  atoms: Atoms, repeat: Tuple[int, int, int]
622
637
  ) -> Tuple[Atoms, npt.ArrayLike]:
@@ -832,3 +847,78 @@ def fit_voigt_tensor_to_cell_and_space_group(
832
847
  t_symmetrized = sum(t_rotated_list) / len(t_rotated_list)
833
848
 
834
849
  return t_symmetrized.voigt
850
+
851
+
852
+ class FixProvidedSymmetry(FixSymmetry):
853
+ """
854
+ A modification of :obj:`~ase.constraints.FixSymmetry` that takes
855
+ a prescribed symmetry instead of analyzing the atoms object on the fly
856
+ """
857
+
858
+ def __init__(
859
+ self,
860
+ atoms: Atoms,
861
+ symmetry: Union[str, int, List[Dict]],
862
+ adjust_positions=True,
863
+ adjust_cell=True,
864
+ ):
865
+ """
866
+ Args:
867
+ symmetry:
868
+ Either the space group number, or a list of operations
869
+ as dictionaries with keys "W": (fractional rotation matrix),
870
+ "w": (fractional translation). The space group number input
871
+ will not work correctly unless this contraint is applied to
872
+ a primitive unit cell as defined in
873
+ http://doi.org/10.1016/j.commatsci.2017.01.017
874
+ """
875
+ self.atoms = atoms.copy()
876
+ self.symmetry = symmetry
877
+
878
+ if isinstance(symmetry, str) or isinstance(symmetry, int):
879
+ primitive_genpos_ops = get_primitive_genpos_ops(symmetry)
880
+ else:
881
+ try:
882
+ for op in symmetry:
883
+ assert np.asarray(op["W"]).shape == (3, 3)
884
+ assert np.asarray(op["w"]).shape == (3,)
885
+ primitive_genpos_ops = symmetry
886
+ except Exception:
887
+ raise RuntimeError("Incorrect input provided to FixProvidedSymmetry")
888
+
889
+ self.rotations = []
890
+ self.translations = []
891
+ for op in primitive_genpos_ops:
892
+ self.rotations.append(np.asarray(op["W"]))
893
+ self.translations.append(np.asarray(op["w"]))
894
+ self.prep_symm_map()
895
+
896
+ self.do_adjust_positions = adjust_positions
897
+ self.do_adjust_cell = adjust_cell
898
+
899
+ def prep_symm_map(self) -> None:
900
+ """
901
+ Prepare self.symm_map using provided symmetries
902
+ """
903
+ self.symm_map = []
904
+ scaled_pos = self.atoms.get_scaled_positions()
905
+ for rot, trans in zip(self.rotations, self.translations):
906
+ this_op_map = [-1] * len(self.atoms)
907
+ for i_at in range(len(self.atoms)):
908
+ new_p = rot @ scaled_pos[i_at, :] + trans
909
+ dp = scaled_pos - new_p
910
+ dp -= np.round(dp)
911
+ i_at_map = np.argmin(np.linalg.norm(dp, axis=1))
912
+ this_op_map[i_at] = i_at_map
913
+ self.symm_map.append(this_op_map)
914
+
915
+ def todict(self):
916
+ return {
917
+ "name": "FixProvidedSymmetry",
918
+ "kwargs": {
919
+ "atoms": self.atoms,
920
+ "symmetry": self.symmetry,
921
+ "adjust_positions": self.do_adjust_positions,
922
+ "adjust_cell": self.do_adjust_cell,
923
+ },
924
+ }
@@ -65,7 +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
+ from ..aflow_util.core import AFLOW_EXECUTABLE, get_atom_indices_for_each_wyckoff_orb
69
69
  from ..ase import get_isolated_energy_per_atom
70
70
  from ..kimunits import convert_list, convert_units
71
71
  from ..symmetry_util import (
@@ -139,7 +139,7 @@ def minimize_wrapper(
139
139
  logfile: Optional[Union[str, IO]] = "kim-tools.log",
140
140
  algorithm: Optimizer = LBFGSLineSearch,
141
141
  cell_filter: UnitCellFilter = FrechetCellFilter,
142
- fix_symmetry: bool = False,
142
+ fix_symmetry: Union[bool, FixSymmetry] = False,
143
143
  opt_kwargs: Dict = {},
144
144
  flt_kwargs: Dict = {},
145
145
  ) -> bool:
@@ -179,7 +179,8 @@ def minimize_wrapper(
179
179
  CellFilter:
180
180
  Filter to use if variable_cell is requested
181
181
  fix_symmetry:
182
- Whether to fix the crystallographic symmetry
182
+ Whether to fix the crystallographic symmetry. Can provide
183
+ a FixSymmetry class here instead of detecting it on the fly
183
184
  opt_kwargs:
184
185
  Dictionary of kwargs to pass to optimizer
185
186
  flt_kwargs:
@@ -188,8 +189,11 @@ def minimize_wrapper(
188
189
  Returns:
189
190
  Whether the minimization succeeded
190
191
  """
191
- if fix_symmetry:
192
- symmetry = FixSymmetry(atoms)
192
+ if fix_symmetry is not False:
193
+ if fix_symmetry is True:
194
+ symmetry = FixSymmetry(atoms)
195
+ else:
196
+ symmetry = fix_symmetry
193
197
  atoms.set_constraint(symmetry)
194
198
  if variable_cell:
195
199
  supercell_wrapped = cell_filter(atoms, **flt_kwargs)
@@ -225,11 +229,18 @@ def minimize_wrapper(
225
229
  del atoms.constraints
226
230
 
227
231
  if minimization_stalled or iteration_limits_reached:
228
- logger.info("Final forces:")
229
- logger.info(atoms.get_forces())
230
- logger.info("Final stress:")
231
- logger.info(atoms.get_stress())
232
- return False
232
+ try:
233
+ logger.info("Final forces:")
234
+ logger.info(atoms.get_forces())
235
+ logger.info("Final stress:")
236
+ logger.info(atoms.get_stress())
237
+ except Exception as e:
238
+ logger.info(
239
+ "The following exception was caught "
240
+ "trying to evaluate final forces and stress:"
241
+ )
242
+ logger.info(repr(e))
243
+ return False
233
244
  else:
234
245
  return True
235
246
 
@@ -1307,7 +1318,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
1307
1318
  )
1308
1319
  print(f"\nNOTE: {msg}\n")
1309
1320
  logger.info(msg)
1310
- if cell_cauchy_stress_eV_angstrom3 != [0, 0, 0, 0, 0, 0]:
1321
+ if cell_cauchy_stress_eV_angstrom3 == [0, 0, 0, 0, 0, 0]:
1311
1322
  stress_max = np.max(atoms_tmp.get_stress())
1312
1323
  if stress_max > FMAX_INITIAL:
1313
1324
  msg = (
@@ -1856,6 +1867,23 @@ class SingleCrystalTestDriver(KIMTestDriver):
1856
1867
  atoms_tmp.calc = self._calc
1857
1868
  return atoms_tmp
1858
1869
 
1870
+ def get_nominal_prototype_label(self) -> str:
1871
+ return self._get_nominal_crystal_structure_npt()["prototype-label"][
1872
+ "source-value"
1873
+ ]
1874
+
1875
+ def get_atom_indices_for_each_wyckoff_orb(self) -> List[Dict]:
1876
+ """
1877
+ Get a list of dictionaries containing the atom indices of each Wyckoff
1878
+ orbit.
1879
+
1880
+ Returns:
1881
+ The information is in this format:
1882
+
1883
+ [{"letter":"a", "indices":[0,1]}, ... ]
1884
+ """
1885
+ return get_atom_indices_for_each_wyckoff_orb(self.get_nominal_prototype_label())
1886
+
1859
1887
 
1860
1888
  def query_crystal_structures(
1861
1889
  stoichiometric_species: List[str],
@@ -1955,7 +1983,7 @@ def query_crystal_structures(
1955
1983
  logger.info(len_msg)
1956
1984
  logger.debug(f"Query result (length={len(query_result)}):\n{query_result}")
1957
1985
 
1958
- print(f"!!! {len_msg} !!!")
1986
+ print(f"\n!!! {len_msg} !!!\n")
1959
1987
 
1960
1988
  return query_result
1961
1989
 
@@ -2208,8 +2236,3 @@ def get_deduplicated_property_instances(
2208
2236
  property_instances_deduplicated.sort(key=lambda a: a["instance-id"])
2209
2237
 
2210
2238
  return property_instances_deduplicated
2211
-
2212
-
2213
- # If called directly, do nothing
2214
- if __name__ == "__main__":
2215
- pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kim-tools
3
- Version: 0.3.5
3
+ Version: 0.3.6
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>, Philipp Hoellmer <ph2484@nyu.edu>, Guanming Zhang <gz2241@nyu.edu>, Tom Egg <tje3676@nyu.edu>
6
6
  Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
@@ -1,7 +1,7 @@
1
- kim_tools/__init__.py,sha256=y8h76B1TbTZ5GZBpVnnyhzD06UpiOrAN5xffFW2TfLI,433
1
+ kim_tools/__init__.py,sha256=kYbIfF9bmWajsk_oLkaGok3kpnHeo1rlLBUAranse8o,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=zi69wMcgkcYBTKbc-OvKlMIzUtgphO57yBA8LB7_5wc,77484
4
+ kim_tools/aflow_util/core.py,sha256=YH1KCMQjXiKMqhT1TAuoafpsGqPlybsykRRMaa8wWqc,78219
5
5
  kim_tools/aflow_util/aflow_prototype_encyclopedia/data/A108B24C11D24_cP334_222_h4i_i_bf_i-001/info.json,sha256=IsFiO9X2Ko7yoq2QkDurUVP7k1BE4WFgblu7oxl6iZs,2013
6
6
  kim_tools/aflow_util/aflow_prototype_encyclopedia/data/A10B11_tI84_139_dehim_eh2n-001/info.json,sha256=f1EdtouuSL2y9NNw40Rvz2J9ZZcsqQBcyEmlHj6XoW8,1186
7
7
  kim_tools/aflow_util/aflow_prototype_encyclopedia/data/A10B2C_hP39_171_5c_c_a-001/info.json,sha256=vD1xjZKWShL0E6XNsSlmIhilGcGNefl56oQDLQlHO1M,1596
@@ -2004,7 +2004,7 @@ kim_tools/aflow_util/aflow_prototype_encyclopedia/data/A_tP50_134_a2m2n-001/info
2004
2004
  kim_tools/ase/__init__.py,sha256=1i6ko5tNr0VZC3T7hoEzq4fnSU0DdxNpxXcSaWMcJWc,76
2005
2005
  kim_tools/ase/core.py,sha256=odRuHQGZl-pcRtkdYvG31_3kW6nt3qwHdKvAOJ-ifwM,31207
2006
2006
  kim_tools/symmetry_util/__init__.py,sha256=uu-ZSUDUTe2P81rkAS3tXverx31s_uZ3wL4SD_dn5aI,86
2007
- kim_tools/symmetry_util/core.py,sha256=HfDy1CwNWUZIkb4cs3ebUDgWjtt4jRSkBKgGEnlkjuI,30888
2007
+ kim_tools/symmetry_util/core.py,sha256=aDaeYmtwfkNlNDcYQ3mAkez7e9_Lk84xQxwQ24cir38,34231
2008
2008
  kim_tools/symmetry_util/data/possible_primitive_shifts.json,sha256=4OVNgn3NnykgGlYiAcecERmVWiIZFrmP2LZI3ml_Sh0,25010
2009
2009
  kim_tools/symmetry_util/data/primitive_GENPOS_ops.json,sha256=FDu4H4PosOpK9yKwOPy3SxbH7xLMOmZfKZ4ItKPMjoQ,224498
2010
2010
  kim_tools/symmetry_util/data/space_groups_for_each_bravais_lattice.json,sha256=wSNu6d5pH72lJ6Zj5MZ64qzwS_6Fn5WOs0ts7E9uPC4,2507
@@ -2012,11 +2012,11 @@ kim_tools/symmetry_util/data/wyck_pos_xform_under_normalizer.json,sha256=6g1YuYh
2012
2012
  kim_tools/symmetry_util/data/wyckoff_multiplicities.json,sha256=qG2RPBd_-ejDIfz-E4ZhkHyRpIboxRy7oiXkdDf5Eg8,32270
2013
2013
  kim_tools/symmetry_util/data/wyckoff_sets.json,sha256=f5ZpHKDHo6_JWki1b7KUGoYLlhU-44Qikw_-PtbLssw,9248
2014
2014
  kim_tools/test_driver/__init__.py,sha256=KOiceeZNqkfrgZ66CiRiUdniceDrCmmDXQkOw0wXaCQ,92
2015
- kim_tools/test_driver/core.py,sha256=8FbOhQRu38zX48CBgFgMrB2tLLSXUsbrXl9dYx5CVHw,90320
2015
+ kim_tools/test_driver/core.py,sha256=DseMkfdb-b116rRQQR0N7HKhsMsZGq8ZxtKoCBlw8X8,91307
2016
2016
  kim_tools/vc/__init__.py,sha256=zXjhxXCKVMLBMXXWYG3if7VOpBnsFrn_RjVpnohDm5c,74
2017
2017
  kim_tools/vc/core.py,sha256=BIjzEExnQAL2S90a_npptRm3ACqAo4fZBtvTDBMWMdw,13963
2018
- kim_tools-0.3.5.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
2019
- kim_tools-0.3.5.dist-info/METADATA,sha256=YHR8cikv3dJ0DLWxltEXkNyDbHFJMMT5hullZnEvYvs,2032
2020
- kim_tools-0.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
2021
- kim_tools-0.3.5.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
2022
- kim_tools-0.3.5.dist-info/RECORD,,
2018
+ kim_tools-0.3.6.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
2019
+ kim_tools-0.3.6.dist-info/METADATA,sha256=Q_aemQPU34z7rSPK04WnMP6WzUnS845Frlr3YWofcjw,2032
2020
+ kim_tools-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
2021
+ kim_tools-0.3.6.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
2022
+ kim_tools-0.3.6.dist-info/RECORD,,