kim-tools 0.3.5__py3-none-any.whl → 0.3.7__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.
@@ -0,0 +1,390 @@
1
+ import logging
2
+ import math
3
+ import os
4
+ import shutil
5
+ from typing import Dict, List, Tuple, Union
6
+
7
+ import numpy as np
8
+ import numpy.typing as npt
9
+
10
+ from .core import DATA_DIR, _check_space_group
11
+
12
+ logger = logging.getLogger(__name__)
13
+ logging.basicConfig(filename="kim-tools.log", level=logging.INFO, force=True)
14
+
15
+
16
+ def voigt_elast_class(sgnum: Union[int, str]) -> str:
17
+ """
18
+ Get the name of the class of the structure of the elasticity tensor, out of
19
+ the following possibilities:
20
+ "cubic", "hexagonal", "trigonal_3bar_m_2nd_pos", "trigonal_3bar_m_3rd_pos",
21
+ "trigonal_3bar", "tetragonal_class_4_slash_mmm", "tetragonal_class_4_slash_m",
22
+ "orthorhombic", "monoclinic", "triclinic". The names that don't
23
+ correspond to a crystal system are taken from
24
+ https://dictionary.iucr.org/Laue_class
25
+
26
+ Note that this is a novel classification as far as the authors are aware.
27
+ Most crystallography texts on the subject will show 9 classes. This function
28
+ returns 10 possibilities, because the structure of the components of
29
+ the elasticity tensor for Laue class -3m depends on whether the twofold
30
+ axis is aligned along the Cartesian x or y axis. Assuming one adopts a
31
+ standard orientation of the hexagonal unit cell w.r.t. the Cartesian coordinate
32
+ system, as we do, different space groups in this Laue class have different
33
+ forms.
34
+
35
+ See https://doi.org/10.1017/CBO9781139017657.008 pg 232 for a review
36
+ of the subject.
37
+ """
38
+ _check_space_group(sgnum)
39
+ sgnum = int(sgnum)
40
+
41
+ if sgnum < 3:
42
+ return "triclinic"
43
+ elif sgnum < 16:
44
+ return "monoclinic"
45
+ elif sgnum < 75:
46
+ return "orthorhombic"
47
+ elif sgnum < 89:
48
+ return "tetragonal_4_slash_m"
49
+ elif sgnum < 143:
50
+ return "tetragonal_4_slash_mmm"
51
+ elif sgnum < 149:
52
+ return "trigonal_3bar"
53
+ elif sgnum < 168:
54
+ # Determine if this is one of the groups with the 2-fold operation in the
55
+ # third position (e.g. 149:P312), which has different equations
56
+ if sgnum in (149, 151, 153, 157, 159, 162, 163):
57
+ return "trigonal_3bar_m_3rd_pos"
58
+ else:
59
+ return "trigonal_3bar_m_2nd_pos"
60
+ elif sgnum < 195:
61
+ return "hexagonal"
62
+ else:
63
+ return "cubic"
64
+
65
+
66
+ def voigt_elast_compon_eqn(sgnum: Union[int, str]) -> Dict:
67
+ """
68
+ Get the algebraic equations describing the symmetry restrictions
69
+ on the elasticity matrix in Voigt form given a space group number.
70
+ The unit cell
71
+ must be in the orientation defined in doi.org/10.1016/j.commatsci.2017.01.017
72
+ for these equations to be correct.
73
+
74
+ Returns:
75
+ Encoding of symmetry restrictions on elasticity matrices.
76
+ The keys are the Voigt indices of non-independent components.
77
+ The values are a pair of lists representing the linear combination
78
+ of the unique compoonents that is used to determine the non-unique component
79
+ specified in the key. The first list is the coefficients, the second
80
+ is the indices. If a non-independent component is zero, this is indicated
81
+ by a value of None. Any components not listed as a key are assumed to
82
+ be independent. Only the upper triangle (i<j) is listed. Indices are
83
+ one-based.
84
+ """
85
+ ELASTICITY_MATRIX_EQNS = {
86
+ "cubic": {
87
+ (1, 3): ([1], [(1, 2)]),
88
+ (1, 4): None,
89
+ (1, 5): None,
90
+ (1, 6): None,
91
+ (2, 2): ([1], [(1, 1)]),
92
+ (2, 3): ([1], [(1, 2)]),
93
+ (2, 4): None,
94
+ (2, 5): None,
95
+ (2, 6): None,
96
+ (3, 3): ([1], [(1, 1)]),
97
+ (3, 4): None,
98
+ (3, 5): None,
99
+ (3, 6): None,
100
+ (4, 5): None,
101
+ (4, 6): None,
102
+ (5, 5): ([1], [(4, 4)]),
103
+ (5, 6): None,
104
+ (6, 6): ([1], [(4, 4)]),
105
+ },
106
+ "hexagonal": {
107
+ (1, 4): None,
108
+ (1, 5): None,
109
+ (1, 6): None,
110
+ (2, 2): ([1], [(1, 1)]),
111
+ (2, 3): ([1], [(1, 3)]),
112
+ (2, 4): None,
113
+ (2, 5): None,
114
+ (2, 6): None,
115
+ (3, 4): None,
116
+ (3, 5): None,
117
+ (3, 6): None,
118
+ (4, 5): None,
119
+ (4, 6): None,
120
+ (5, 5): ([1], [(4, 4)]),
121
+ (5, 6): None,
122
+ (6, 6): ([0.5, -0.5], [(1, 1), (1, 2)]),
123
+ },
124
+ "trigonal_3bar_m_2nd_pos": {
125
+ (1, 5): None,
126
+ (1, 6): None,
127
+ (2, 2): ([1], [(1, 1)]),
128
+ (2, 3): ([1], [(1, 3)]),
129
+ (2, 4): ([-1], [(1, 4)]),
130
+ (2, 5): None,
131
+ (2, 6): None,
132
+ (3, 4): None,
133
+ (3, 5): None,
134
+ (3, 6): None,
135
+ (4, 5): None,
136
+ (4, 6): None,
137
+ (5, 5): ([1], [(4, 4)]),
138
+ (5, 6): ([1], [(1, 4)]),
139
+ (6, 6): ([0.5, -0.5], [(1, 1), (1, 2)]),
140
+ },
141
+ "trigonal_3bar_m_3rd_pos": {
142
+ (1, 4): None,
143
+ (1, 6): None,
144
+ (2, 2): ([1], [(1, 1)]),
145
+ (2, 3): ([1], [(1, 3)]),
146
+ (2, 4): None,
147
+ (2, 5): ([-1], [(1, 5)]),
148
+ (2, 6): None,
149
+ (3, 4): None,
150
+ (3, 5): None,
151
+ (3, 6): None,
152
+ (4, 5): None,
153
+ (4, 6): ([-1], [(1, 5)]),
154
+ (5, 5): ([1], [(4, 4)]),
155
+ (5, 6): None,
156
+ (6, 6): ([0.5, -0.5], [(1, 1), (1, 2)]),
157
+ },
158
+ "trigonal_3bar": {
159
+ (1, 6): None,
160
+ (2, 2): ([1], [(1, 1)]),
161
+ (2, 3): ([1], [(1, 3)]),
162
+ (2, 4): ([-1], [(1, 4)]),
163
+ (2, 5): ([-1], [(1, 5)]),
164
+ (2, 6): None,
165
+ (3, 4): None,
166
+ (3, 5): None,
167
+ (3, 6): None,
168
+ (4, 5): None,
169
+ (4, 6): ([-1], [(1, 5)]),
170
+ (5, 5): ([1], [(4, 4)]),
171
+ (5, 6): ([1], [(1, 4)]),
172
+ (6, 6): ([0.5, -0.5], [(1, 1), (1, 2)]),
173
+ },
174
+ "tetragonal_4_slash_mmm": {
175
+ (1, 4): None,
176
+ (1, 5): None,
177
+ (1, 6): None,
178
+ (2, 2): ([1], [(1, 1)]),
179
+ (2, 3): ([1], [(1, 3)]),
180
+ (2, 4): None,
181
+ (2, 5): None,
182
+ (2, 6): None,
183
+ (3, 4): None,
184
+ (3, 5): None,
185
+ (3, 6): None,
186
+ (4, 5): None,
187
+ (4, 6): None,
188
+ (5, 5): ([1], [(4, 4)]),
189
+ (5, 6): None,
190
+ },
191
+ "tetragonal_4_slash_m": {
192
+ (1, 4): None,
193
+ (1, 5): None,
194
+ (2, 2): ([1], [(1, 1)]),
195
+ (2, 3): ([1], [(1, 3)]),
196
+ (2, 4): None,
197
+ (2, 5): None,
198
+ (2, 6): ([-1], [(1, 6)]),
199
+ (3, 4): None,
200
+ (3, 5): None,
201
+ (3, 6): None,
202
+ (4, 5): None,
203
+ (4, 6): None,
204
+ (5, 5): ([1], [(4, 4)]),
205
+ (5, 6): None,
206
+ },
207
+ "orthorhombic": {
208
+ (1, 4): None,
209
+ (1, 5): None,
210
+ (1, 6): None,
211
+ (2, 4): None,
212
+ (2, 5): None,
213
+ (2, 6): None,
214
+ (3, 4): None,
215
+ (3, 5): None,
216
+ (3, 6): None,
217
+ (4, 5): None,
218
+ (4, 6): None,
219
+ (5, 6): None,
220
+ },
221
+ "monoclinic": {
222
+ (1, 4): None,
223
+ (1, 6): None,
224
+ (2, 4): None,
225
+ (2, 6): None,
226
+ (3, 4): None,
227
+ (3, 6): None,
228
+ (4, 5): None,
229
+ (5, 6): None,
230
+ },
231
+ "triclinic": {},
232
+ }
233
+
234
+ # error check typing in the above dicts
235
+ for eqn in ELASTICITY_MATRIX_EQNS.values():
236
+ # only unique keys
237
+ assert sorted(list(set(eqn.keys()))) == sorted(list(eqn.keys()))
238
+ # check that all components appearing in RHS of relations are independent, i.e.
239
+ # they don't appear as a key
240
+ for dependent_component in eqn:
241
+ if eqn[dependent_component] is not None:
242
+ for independent_component in eqn[dependent_component][1]:
243
+ assert not (independent_component in eqn)
244
+
245
+ return ELASTICITY_MATRIX_EQNS[voigt_elast_class(sgnum)]
246
+
247
+
248
+ def voigt_elast_struct_svg(sgnum: Union[int, str], dest_filename: str) -> None:
249
+ """
250
+ Write a copy of the image showing the structure of the Voigt elasticity matrix for
251
+ the specified space group
252
+ """
253
+ src_filename = os.path.join(DATA_DIR, "elast_" + voigt_elast_class(sgnum) + ".svg")
254
+ shutil.copyfile(src_filename, dest_filename)
255
+
256
+
257
+ def indep_elast_compon_names_and_values_from_voigt(
258
+ voigt: npt.ArrayLike, sgnum: Union[int, str]
259
+ ) -> Tuple[List[str], List[float]]:
260
+ """
261
+ From an elasticity matrix in Voigt order and a space group number,
262
+ extract the elastic constants that should be unique (cij where first i is as low as
263
+ possible, then j)
264
+ """
265
+ eqn = voigt_elast_compon_eqn(sgnum)
266
+
267
+ elastic_constants_names = []
268
+ elastic_constants_values = []
269
+
270
+ # first, figure out which constants are unique and extract them
271
+ for i in range(1, 7):
272
+ for j in range(i, 7):
273
+ if (i, j) not in eqn:
274
+ elastic_constants_names.append("c" + str(i) + str(j))
275
+ elastic_constants_values.append(voigt[i - 1, j - 1])
276
+
277
+ return elastic_constants_names, elastic_constants_values
278
+
279
+
280
+ def calc_bulk(elastic_constants):
281
+ """
282
+ Compute the bulk modulus given the elastic constants matrix in
283
+ Voigt ordering.
284
+
285
+ Parameters:
286
+ elastic_constants : float
287
+ A 6x6 numpy array containing the elastic constants in
288
+ Voigt ordering. The material can have arbitrary anisotropy.
289
+
290
+ Returns:
291
+ bulk : float
292
+ The bulk modulus, defined as the ratio between the hydrostatic
293
+ stress (negative of the pressure p) in hydrostatic loading and
294
+ the diltation e (trace of the strain tensor), i.e. B = -p/e
295
+ """
296
+ # Compute bulk modulus, based on exercise 6.14 in Tadmor, Miller, Elliott,
297
+ # Continuum Mechanics and Thermodynamics, Cambridge University Press, 2012.
298
+ rank_elastic_constants = np.linalg.matrix_rank(elastic_constants)
299
+ elastic_constants_aug = np.concatenate(
300
+ (elastic_constants, np.transpose([[1, 1, 1, 0, 0, 0]])), 1
301
+ )
302
+ rank_elastic_constants_aug = np.linalg.matrix_rank(elastic_constants_aug)
303
+ if rank_elastic_constants_aug > rank_elastic_constants:
304
+ assert rank_elastic_constants_aug == rank_elastic_constants + 1
305
+ logger.info(
306
+ "Information: Hydrostatic pressure not in the image of the elasticity "
307
+ "matrix, zero bulk modulus!"
308
+ )
309
+ return 0.0
310
+ else:
311
+ # if a solution exists for a stress state of [1,1,1,0,0,0],
312
+ # you can always use the pseudoinverse
313
+ compliance = np.linalg.pinv(elastic_constants)
314
+ bulk = 1 / np.sum(compliance[0:3, 0:3])
315
+ return bulk
316
+
317
+
318
+ def map_to_Kelvin(C: npt.ArrayLike) -> npt.ArrayLike:
319
+ """
320
+ Compute the Kelvin form of the input 6x6 Voigt matrix
321
+ """
322
+ Ch = C.copy()
323
+ Ch[0:3, 3:6] *= math.sqrt(2.0)
324
+ Ch[3:6, 0:3] *= math.sqrt(2.0)
325
+ Ch[3:6, 3:6] *= 2.0
326
+ return Ch
327
+
328
+
329
+ def function_of_matrix(A, f):
330
+ """Compute the function of a matrix"""
331
+ ev, R = np.linalg.eigh(A)
332
+ Dtilde = np.diag([f(e) for e in ev])
333
+ return np.matmul(np.matmul(R, Dtilde), np.transpose(R))
334
+
335
+
336
+ def find_nearest_isotropy(elastic_constants):
337
+ """
338
+ Compute the distance between the provided matrix of elastic constants
339
+ in Voigt notation, to the nearest matrix of elastic constants for an
340
+ isotropic material. Return this distance, and the isotropic bulk and
341
+ shear modulus.
342
+
343
+ Ref: Morin, L; Gilormini, P and Derrien, K,
344
+ "Generalized Euclidean Distances for Elasticity Tensors",
345
+ Journal of Elasticity, Vol 138, pp. 221-232 (2020).
346
+
347
+ Parameters:
348
+ elastic_constants : float
349
+ A 6x6 numpy array containing the elastic constants in
350
+ Voigt ordering. The material can have arbitrary anisotropy.
351
+
352
+ Returns:
353
+ d : float
354
+ Distance to the nearest elastic constants.
355
+ log Euclidean metric.
356
+ kappa : float
357
+ Isotropic bulk modulus
358
+ mu : float
359
+ Isotropic shear modulus
360
+ """
361
+ E0 = 1.0 # arbitrary scaling constant (result unaffected by it)
362
+
363
+ JJ = np.zeros(shape=(6, 6))
364
+ KK = np.zeros(shape=(6, 6))
365
+ v = {0: [0, 0], 1: [1, 1], 2: [2, 2], 3: [1, 2], 4: [0, 2], 5: [0, 1]}
366
+ for ii in range(6):
367
+ for jj in range(6):
368
+ # i j k l = v[ii][0] v[ii][1] v[jj][0] v[jj][1]
369
+ JJ[ii][jj] = (1.0 / 3.0) * (v[ii][0] == v[ii][1]) * (v[jj][0] == v[jj][1])
370
+ KK[ii][jj] = (1.0 / 2.0) * (
371
+ (v[ii][0] == v[jj][0]) * (v[ii][1] == v[jj][1])
372
+ + (v[ii][0] == v[jj][1]) * (v[ii][1] == v[jj][0])
373
+ ) - JJ[ii][jj]
374
+ Chat = map_to_Kelvin(elastic_constants)
375
+ JJhat = map_to_Kelvin(JJ)
376
+ KKhat = map_to_Kelvin(KK)
377
+
378
+ # Eqn (49) in Morin et al.
379
+ fCoverE0 = function_of_matrix(Chat / E0, math.log)
380
+ kappa = (E0 / 3.0) * math.exp(np.einsum("ij,ij", fCoverE0, JJhat))
381
+ mu = (E0 / 2.0) * math.exp(0.2 * np.einsum("ij,ij", fCoverE0, KKhat))
382
+
383
+ # Eqn (47) in Morin et al.
384
+ dmat = (
385
+ fCoverE0 - math.log(3.0 * kappa / E0) * JJhat - math.log(2.0 * mu / E0) * KKhat
386
+ )
387
+ d = math.sqrt(np.einsum("ij,ij", dmat, dmat))
388
+
389
+ # Return results
390
+ return d, kappa, mu
@@ -30,6 +30,7 @@
30
30
  Helper classes for KIM Test Drivers
31
31
 
32
32
  """
33
+ import json
33
34
  import logging
34
35
  import os
35
36
  import shutil
@@ -65,7 +66,7 @@ from ..aflow_util import (
65
66
  get_space_group_number_from_prototype,
66
67
  prototype_labels_are_equivalent,
67
68
  )
68
- from ..aflow_util.core import AFLOW_EXECUTABLE
69
+ from ..aflow_util.core import AFLOW_EXECUTABLE, get_atom_indices_for_each_wyckoff_orb
69
70
  from ..ase import get_isolated_energy_per_atom
70
71
  from ..kimunits import convert_list, convert_units
71
72
  from ..symmetry_util import (
@@ -91,6 +92,7 @@ __all__ = [
91
92
  "detect_unique_crystal_structures",
92
93
  "get_deduplicated_property_instances",
93
94
  "minimize_wrapper",
95
+ "crystal_input_from_test_generator_line",
94
96
  ]
95
97
 
96
98
  # Force tolerance for the optional initial relaxation of the provided cell
@@ -139,7 +141,7 @@ def minimize_wrapper(
139
141
  logfile: Optional[Union[str, IO]] = "kim-tools.log",
140
142
  algorithm: Optimizer = LBFGSLineSearch,
141
143
  cell_filter: UnitCellFilter = FrechetCellFilter,
142
- fix_symmetry: bool = False,
144
+ fix_symmetry: Union[bool, FixSymmetry] = False,
143
145
  opt_kwargs: Dict = {},
144
146
  flt_kwargs: Dict = {},
145
147
  ) -> bool:
@@ -179,7 +181,8 @@ def minimize_wrapper(
179
181
  CellFilter:
180
182
  Filter to use if variable_cell is requested
181
183
  fix_symmetry:
182
- Whether to fix the crystallographic symmetry
184
+ Whether to fix the crystallographic symmetry. Can provide
185
+ a FixSymmetry class here instead of detecting it on the fly
183
186
  opt_kwargs:
184
187
  Dictionary of kwargs to pass to optimizer
185
188
  flt_kwargs:
@@ -188,8 +191,11 @@ def minimize_wrapper(
188
191
  Returns:
189
192
  Whether the minimization succeeded
190
193
  """
191
- if fix_symmetry:
192
- symmetry = FixSymmetry(atoms)
194
+ if fix_symmetry is not False:
195
+ if fix_symmetry is True:
196
+ symmetry = FixSymmetry(atoms)
197
+ else:
198
+ symmetry = fix_symmetry
193
199
  atoms.set_constraint(symmetry)
194
200
  if variable_cell:
195
201
  supercell_wrapped = cell_filter(atoms, **flt_kwargs)
@@ -225,11 +231,18 @@ def minimize_wrapper(
225
231
  del atoms.constraints
226
232
 
227
233
  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
234
+ try:
235
+ logger.info("Final forces:")
236
+ logger.info(atoms.get_forces())
237
+ logger.info("Final stress:")
238
+ logger.info(atoms.get_stress())
239
+ except Exception as e:
240
+ logger.info(
241
+ "The following exception was caught "
242
+ "trying to evaluate final forces and stress:"
243
+ )
244
+ logger.info(repr(e))
245
+ return False
233
246
  else:
234
247
  return True
235
248
 
@@ -498,11 +511,15 @@ class KIMTestDriver(ABC):
498
511
  requires a KIM model (e.g. a LAMMPS TD) with a non-KIM Calculator
499
512
  """
500
513
 
501
- def __init__(self, model: Union[str, Calculator]) -> None:
514
+ def __init__(
515
+ self, model: Union[str, Calculator], suppr_sm_lmp_log: bool = False
516
+ ) -> None:
502
517
  """
503
518
  Args:
504
519
  model:
505
520
  ASE calculator or KIM model name to use
521
+ suppr_sm_lmp_log:
522
+ Suppress writing a lammps.log
506
523
  """
507
524
  if isinstance(model, Calculator):
508
525
  self.__calc = model
@@ -512,6 +529,9 @@ class KIMTestDriver(ABC):
512
529
 
513
530
  self.__kim_model_name = model
514
531
  self.__calc = KIM(self.__kim_model_name)
532
+ if suppr_sm_lmp_log:
533
+ if hasattr(self.__calc.parameters, "log_file"):
534
+ self.__calc.parameters.log_file = None
515
535
 
516
536
  self.__output_property_instances = "[]"
517
537
 
@@ -549,6 +569,8 @@ class KIMTestDriver(ABC):
549
569
  # count how many instances we had before we started
550
570
  previous_properties_end = len(kim_edn.loads(self.__output_property_instances))
551
571
 
572
+ os.makedirs("output", exist_ok=True)
573
+
552
574
  # _setup is likely overridden by an derived class
553
575
  self._setup(material, **kwargs)
554
576
 
@@ -1182,17 +1204,22 @@ class SingleCrystalTestDriver(KIMTestDriver):
1182
1204
  """
1183
1205
 
1184
1206
  def __init__(
1185
- self, model: Union[str, Calculator], aflow_executable: str = AFLOW_EXECUTABLE
1207
+ self,
1208
+ model: Union[str, Calculator],
1209
+ suppr_sm_lmp_log: bool = False,
1210
+ aflow_executable: str = AFLOW_EXECUTABLE,
1186
1211
  ) -> None:
1187
1212
  """
1188
1213
  Args:
1189
1214
  model:
1190
1215
  ASE calculator or KIM model name to use
1216
+ suppr_sm_lmp_log:
1217
+ Suppress writing a lammps.log
1191
1218
  aflow_executable:
1192
1219
  Path to AFLOW executable
1193
1220
  """
1194
1221
  self.aflow_executable = aflow_executable
1195
- super().__init__(model)
1222
+ super().__init__(model, suppr_sm_lmp_log=suppr_sm_lmp_log)
1196
1223
 
1197
1224
  def _setup(
1198
1225
  self,
@@ -1307,7 +1334,7 @@ class SingleCrystalTestDriver(KIMTestDriver):
1307
1334
  )
1308
1335
  print(f"\nNOTE: {msg}\n")
1309
1336
  logger.info(msg)
1310
- if cell_cauchy_stress_eV_angstrom3 != [0, 0, 0, 0, 0, 0]:
1337
+ if cell_cauchy_stress_eV_angstrom3 == [0, 0, 0, 0, 0, 0]:
1311
1338
  stress_max = np.max(atoms_tmp.get_stress())
1312
1339
  if stress_max > FMAX_INITIAL:
1313
1340
  msg = (
@@ -1856,6 +1883,22 @@ class SingleCrystalTestDriver(KIMTestDriver):
1856
1883
  atoms_tmp.calc = self._calc
1857
1884
  return atoms_tmp
1858
1885
 
1886
+ def get_nominal_prototype_label(self) -> str:
1887
+ return self._get_nominal_crystal_structure_npt()["prototype-label"][
1888
+ "source-value"
1889
+ ]
1890
+
1891
+ def get_atom_indices_for_each_wyckoff_orb(self) -> List[Dict]:
1892
+ """
1893
+ Get a list of dictionaries containing the atom indices of each Wyckoff
1894
+ orbit.
1895
+
1896
+ Returns:
1897
+ The information is in this format --
1898
+ ``[{"letter":"a", "indices":[0,1]}, ... ]``
1899
+ """
1900
+ return get_atom_indices_for_each_wyckoff_orb(self.get_nominal_prototype_label())
1901
+
1859
1902
 
1860
1903
  def query_crystal_structures(
1861
1904
  stoichiometric_species: List[str],
@@ -1955,7 +1998,7 @@ def query_crystal_structures(
1955
1998
  logger.info(len_msg)
1956
1999
  logger.debug(f"Query result (length={len(query_result)}):\n{query_result}")
1957
2000
 
1958
- print(f"!!! {len_msg} !!!")
2001
+ print(f"\n!!! {len_msg} !!!\n")
1959
2002
 
1960
2003
  return query_result
1961
2004
 
@@ -2210,6 +2253,40 @@ def get_deduplicated_property_instances(
2210
2253
  return property_instances_deduplicated
2211
2254
 
2212
2255
 
2213
- # If called directly, do nothing
2214
- if __name__ == "__main__":
2215
- pass
2256
+ def crystal_input_from_test_generator_line(
2257
+ test_generator_line: str, kim_model_name: str
2258
+ ) -> List[Dict]:
2259
+ """
2260
+ Produce a list of dictionaries of kwargs for a Crystal Genome Test Driver invocation
2261
+ from a line in its ``test_generator.json``
2262
+ """
2263
+ test_generator_dict = json.loads(test_generator_line)
2264
+ stoichiometric_species = test_generator_dict["stoichiometric_species"]
2265
+ prototype_label = test_generator_dict["prototype_label"]
2266
+ cell_cauchy_stress_eV_angstrom3 = test_generator_dict.get(
2267
+ "cell_cauchy_stress_eV_angstrom3"
2268
+ )
2269
+ temperature_K = test_generator_dict.get("temperature_K")
2270
+ crystal_genome_test_args = test_generator_dict.get("crystal_genome_test_args")
2271
+ equilibria = query_crystal_structures(
2272
+ stoichiometric_species=stoichiometric_species,
2273
+ prototype_label=prototype_label,
2274
+ kim_model_name=kim_model_name,
2275
+ )
2276
+ inputs = []
2277
+ for equilibrium in equilibria:
2278
+ inputs.append(
2279
+ {
2280
+ "material": equilibrium,
2281
+ }
2282
+ )
2283
+ if cell_cauchy_stress_eV_angstrom3 is not None:
2284
+ inputs[-1][
2285
+ "cell_cauchy_stress_eV_angstrom3"
2286
+ ] = cell_cauchy_stress_eV_angstrom3
2287
+ if temperature_K is not None:
2288
+ inputs[-1]["temperature_K"] = temperature_K
2289
+ if crystal_genome_test_args is not None:
2290
+ inputs[-1].update(crystal_genome_test_args)
2291
+
2292
+ return inputs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kim-tools
3
- Version: 0.3.5
3
+ Version: 0.3.7
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=AZO0kIOJrYHA6ai-MX9cxxAzz4wsN21eGn9cAX7LRoc,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=9qlQQwhcFKJ8HwcHdEPgoEKRK_viQAFlZUqCV9nlcE0,80301
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,18 @@ 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=eMGgVt9MPcaLi_8jVMJ5UyQHvYbiiAFQ4HdJotnp8dk,43277
2008
+ kim_tools/symmetry_util/elasticity.py,sha256=VxJ8wUcsSOPyJ8id6OpKmVlRAbIUIWxtzYJtkvVJIVs,13328
2009
+ kim_tools/symmetry_util/data/elast_cubic.svg,sha256=UpN4XcoLoOwv8a7KE0WyINkSH5AU2DPVZ08eGQf-Cds,8953
2010
+ kim_tools/symmetry_util/data/elast_hexagonal.svg,sha256=wOkw5IO3fZy039tLHhvtwrkatVYs5XzigUormLKtRlw,8705
2011
+ kim_tools/symmetry_util/data/elast_monoclinic.svg,sha256=71zWo1ClStyVbM8KHLU-bEU1m7itJScFnsqIY7tHTuw,10555
2012
+ kim_tools/symmetry_util/data/elast_orthorhombic.svg,sha256=J-1rLi0JpBpHo0sD6gQcdO7CPZaYbuA6DUY6hMRqEcE,8197
2013
+ kim_tools/symmetry_util/data/elast_tetragonal_4_slash_m.svg,sha256=sBdXu0e0uqnglAyBJNoA-B7bllfp7_c9MiT7aCPNh0I,10321
2014
+ kim_tools/symmetry_util/data/elast_tetragonal_4_slash_mmm.svg,sha256=1oXCrWYqVhQetgcCNoGp-ypDgCyyugZ2023Evk417vI,8902
2015
+ kim_tools/symmetry_util/data/elast_triclinic.svg,sha256=9LGE6FLvYJ-4-M3c1BciasVkEu4eXo9jjeggJ8FJSIo,15269
2016
+ kim_tools/symmetry_util/data/elast_trigonal_3bar.svg,sha256=3gVsl_bRryw6hJRG7H_UTRDCWprcDhKfMXr7uQ5LDV4,12771
2017
+ kim_tools/symmetry_util/data/elast_trigonal_3bar_m_2nd_pos.svg,sha256=2kzOIKZPbQbGMwDzmlBs5pMg9EfrNZ7EV4ihnTiExz0,10738
2018
+ kim_tools/symmetry_util/data/elast_trigonal_3bar_m_3rd_pos.svg,sha256=pN8ov9-AQ2jYGoMZj5BrhLlYW2G-O6d5woz93H4K5Hc,10738
2008
2019
  kim_tools/symmetry_util/data/possible_primitive_shifts.json,sha256=4OVNgn3NnykgGlYiAcecERmVWiIZFrmP2LZI3ml_Sh0,25010
2009
2020
  kim_tools/symmetry_util/data/primitive_GENPOS_ops.json,sha256=FDu4H4PosOpK9yKwOPy3SxbH7xLMOmZfKZ4ItKPMjoQ,224498
2010
2021
  kim_tools/symmetry_util/data/space_groups_for_each_bravais_lattice.json,sha256=wSNu6d5pH72lJ6Zj5MZ64qzwS_6Fn5WOs0ts7E9uPC4,2507
@@ -2012,11 +2023,11 @@ kim_tools/symmetry_util/data/wyck_pos_xform_under_normalizer.json,sha256=6g1YuYh
2012
2023
  kim_tools/symmetry_util/data/wyckoff_multiplicities.json,sha256=qG2RPBd_-ejDIfz-E4ZhkHyRpIboxRy7oiXkdDf5Eg8,32270
2013
2024
  kim_tools/symmetry_util/data/wyckoff_sets.json,sha256=f5ZpHKDHo6_JWki1b7KUGoYLlhU-44Qikw_-PtbLssw,9248
2014
2025
  kim_tools/test_driver/__init__.py,sha256=KOiceeZNqkfrgZ66CiRiUdniceDrCmmDXQkOw0wXaCQ,92
2015
- kim_tools/test_driver/core.py,sha256=8FbOhQRu38zX48CBgFgMrB2tLLSXUsbrXl9dYx5CVHw,90320
2026
+ kim_tools/test_driver/core.py,sha256=sSdDBr99Y4NvKV_BKvz-T8Sp1p_pzk2teZoHv0IjpSo,93309
2016
2027
  kim_tools/vc/__init__.py,sha256=zXjhxXCKVMLBMXXWYG3if7VOpBnsFrn_RjVpnohDm5c,74
2017
2028
  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,,
2029
+ kim_tools-0.3.7.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
2030
+ kim_tools-0.3.7.dist-info/METADATA,sha256=xewZHVokzllXvhRCAbMMQ7JO5RNe8R2sB0VXEV7QyBM,2032
2031
+ kim_tools-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
2032
+ kim_tools-0.3.7.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
2033
+ kim_tools-0.3.7.dist-info/RECORD,,