kim-tools 0.3.14__py3-none-any.whl → 0.4.0__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 +1 -1
- kim_tools/aflow_util/core.py +4 -12
- kim_tools/symmetry_util/core.py +64 -114
- {kim_tools-0.3.14.dist-info → kim_tools-0.4.0.dist-info}/METADATA +1 -1
- {kim_tools-0.3.14.dist-info → kim_tools-0.4.0.dist-info}/RECORD +8 -8
- {kim_tools-0.3.14.dist-info → kim_tools-0.4.0.dist-info}/WHEEL +0 -0
- {kim_tools-0.3.14.dist-info → kim_tools-0.4.0.dist-info}/licenses/LICENSE.CDDL +0 -0
- {kim_tools-0.3.14.dist-info → kim_tools-0.4.0.dist-info}/top_level.txt +0 -0
kim_tools/__init__.py
CHANGED
kim_tools/aflow_util/core.py
CHANGED
@@ -17,7 +17,6 @@ import numpy as np
|
|
17
17
|
import numpy.typing as npt
|
18
18
|
from ase import Atoms
|
19
19
|
from ase.cell import Cell
|
20
|
-
from ase.neighborlist import natural_cutoffs, neighbor_list
|
21
20
|
from semver import Version
|
22
21
|
from sympy import Symbol, linear_eq_to_matrix, matrix2numpy, parse_expr
|
23
22
|
|
@@ -30,6 +29,7 @@ from ..symmetry_util import (
|
|
30
29
|
cartesian_rotation_is_in_point_group,
|
31
30
|
get_possible_primitive_shifts,
|
32
31
|
get_primitive_wyckoff_multiplicity,
|
32
|
+
get_smallest_nn_dist,
|
33
33
|
get_wyck_pos_xform_under_normalizer,
|
34
34
|
space_group_numbers_are_enantiomorphic,
|
35
35
|
)
|
@@ -1605,20 +1605,12 @@ class AFLOW:
|
|
1605
1605
|
"""
|
1606
1606
|
# If max_resid not provided, determine it from neighborlist
|
1607
1607
|
if max_resid is None:
|
1608
|
-
nl_len = 0
|
1609
|
-
cov_mult = 1
|
1610
|
-
while nl_len == 0:
|
1611
|
-
logger.info(
|
1612
|
-
"Attempting to find NN distance by searching "
|
1613
|
-
f"within covalent radii times {cov_mult}"
|
1614
|
-
)
|
1615
|
-
nl = neighbor_list("d", atoms, natural_cutoffs(atoms, mult=cov_mult))
|
1616
|
-
nl_len = nl.size
|
1617
|
-
cov_mult += 1
|
1618
1608
|
# set the maximum error to 1% of NN distance to follow AFLOW convention
|
1619
1609
|
# rescale by cube root of cell volume to get rough conversion from
|
1620
1610
|
# cartesian to fractional
|
1621
|
-
max_resid =
|
1611
|
+
max_resid = (
|
1612
|
+
get_smallest_nn_dist(atoms) * 0.01 * atoms.get_volume() ** (-1 / 3)
|
1613
|
+
)
|
1622
1614
|
logger.info(
|
1623
1615
|
"Automatically set max fractional residual for solving position "
|
1624
1616
|
f"equations to {max_resid}"
|
kim_tools/symmetry_util/core.py
CHANGED
@@ -9,7 +9,6 @@ from itertools import product
|
|
9
9
|
from math import ceil
|
10
10
|
from typing import Dict, List, Optional, Tuple, Union
|
11
11
|
|
12
|
-
import matplotlib.pyplot as plt
|
13
12
|
import numpy as np
|
14
13
|
import numpy.typing as npt
|
15
14
|
import sympy as sp
|
@@ -17,11 +16,9 @@ from ase import Atoms
|
|
17
16
|
from ase.cell import Cell
|
18
17
|
from ase.constraints import FixSymmetry
|
19
18
|
from ase.geometry import get_distances, get_duplicate_atoms
|
20
|
-
from
|
19
|
+
from ase.neighborlist import natural_cutoffs, neighbor_list
|
21
20
|
from pymatgen.core.operations import SymmOp
|
22
21
|
from pymatgen.core.tensors import Tensor
|
23
|
-
from scipy.stats import kstest
|
24
|
-
from sklearn.decomposition import PCA
|
25
22
|
from sympy import Matrix, cos, matrix2numpy, sin, sqrt, symbols
|
26
23
|
from sympy.tensor.array.expressions import ArrayContraction, ArrayTensorProduct
|
27
24
|
|
@@ -50,6 +47,7 @@ __all__ = [
|
|
50
47
|
"change_of_basis_atoms",
|
51
48
|
"get_possible_primitive_shifts",
|
52
49
|
"get_primitive_genpos_ops",
|
50
|
+
"get_smallest_nn_dist",
|
53
51
|
]
|
54
52
|
|
55
53
|
C_CENTERED_ORTHORHOMBIC_GROUPS = (20, 21, 35, 36, 37, 63, 64, 65, 66, 67, 68)
|
@@ -516,7 +514,9 @@ def get_change_of_basis_matrix_to_conventional_cell_from_formal_bravais_lattice(
|
|
516
514
|
return np.round(change_of_basis_matrix)
|
517
515
|
|
518
516
|
|
519
|
-
def change_of_basis_atoms(
|
517
|
+
def change_of_basis_atoms(
|
518
|
+
atoms: Atoms, change_of_basis: npt.ArrayLike, cutoff: Optional[float] = None
|
519
|
+
) -> Atoms:
|
520
520
|
"""
|
521
521
|
Perform an arbitrary basis change on an ``Atoms`` object, duplicating or cropping
|
522
522
|
atoms as needed. A basic check is made that the determinant of ``change_of_basis``
|
@@ -524,7 +524,7 @@ def change_of_basis_atoms(atoms: Atoms, change_of_basis: npt.ArrayLike) -> Atoms
|
|
524
524
|
that ``change_of_basis`` is appropriate for the particuar crystal described by
|
525
525
|
``atoms``, which is up to the user.
|
526
526
|
|
527
|
-
TODO: Incorporate :func:`
|
527
|
+
TODO: Incorporate :func:`cutoff_test_reduced_distances` into this function
|
528
528
|
|
529
529
|
Args:
|
530
530
|
atoms:
|
@@ -543,6 +543,9 @@ def change_of_basis_atoms(atoms: Atoms, change_of_basis: npt.ArrayLike) -> Atoms
|
|
543
543
|
|
544
544
|
Relationship between fractional coordinates in each basis:
|
545
545
|
**x** = **P** **x**'
|
546
|
+
cutoff:
|
547
|
+
The cutoff to use for deleting duplicate atoms. If not specified,
|
548
|
+
the AFLOW tolerance of 0.01*(smallest NN distance) is used.
|
546
549
|
|
547
550
|
Returns:
|
548
551
|
The transformed ``Atoms`` object, containing the original number of
|
@@ -577,7 +580,9 @@ def change_of_basis_atoms(atoms: Atoms, change_of_basis: npt.ArrayLike) -> Atoms
|
|
577
580
|
new_atoms = atoms.repeat(repeat)
|
578
581
|
new_atoms.set_cell(new_cell)
|
579
582
|
new_atoms.wrap()
|
580
|
-
|
583
|
+
if cutoff is None:
|
584
|
+
cutoff = get_smallest_nn_dist(atoms) * 0.01
|
585
|
+
get_duplicate_atoms(new_atoms, cutoff=cutoff, delete=True)
|
581
586
|
|
582
587
|
volume_change = np.linalg.det(change_of_basis)
|
583
588
|
if not np.isclose(len(atoms) * volume_change, len(new_atoms)):
|
@@ -634,14 +639,16 @@ def transform_atoms(atoms: Atoms, op: Dict) -> Atoms:
|
|
634
639
|
return atoms_transformed
|
635
640
|
|
636
641
|
|
637
|
-
def reduce_and_avg(
|
638
|
-
atoms: Atoms, repeat: Tuple[int, int, int]
|
639
|
-
) -> Tuple[Atoms, npt.ArrayLike]:
|
642
|
+
def reduce_and_avg(atoms: Atoms, repeat: Tuple[int, int, int]) -> Atoms:
|
640
643
|
"""
|
641
644
|
TODO: Upgrade :func:`change_of_basis_atoms` to provide the distances
|
642
645
|
array, obviating this function
|
643
646
|
|
644
|
-
Function to reduce all atoms to the original unit cell position
|
647
|
+
Function to reduce all atoms to the original unit cell position,
|
648
|
+
assuming the supercell is built from contiguous repeats of the unit cell
|
649
|
+
(i.e. atoms 0 to N-1 in the supercell are the original unit cell, atoms N to
|
650
|
+
2*[N-1] are the original unit cell shifted by an integer multiple of
|
651
|
+
the lattice vectors, and so on)
|
645
652
|
|
646
653
|
Args:
|
647
654
|
atoms:
|
@@ -651,10 +658,13 @@ def reduce_and_avg(
|
|
651
658
|
provided supercell
|
652
659
|
|
653
660
|
Returns:
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
661
|
+
The reduced unit cell
|
662
|
+
|
663
|
+
Raises:
|
664
|
+
PeriodExtensionException:
|
665
|
+
If two atoms that should be identical by translational symmetry
|
666
|
+
are further than 0.01*(smallest NN distance) apart when
|
667
|
+
reduced to the unit cell
|
658
668
|
"""
|
659
669
|
new_atoms = atoms.copy()
|
660
670
|
|
@@ -685,126 +695,49 @@ def reduce_and_avg(
|
|
685
695
|
# Start from end of the atoms
|
686
696
|
# because we will remove all atoms except the reference ones.
|
687
697
|
for i in reversed(range(number_atoms)):
|
698
|
+
reference_atom_index = i % original_number_atoms
|
688
699
|
if i >= original_number_atoms:
|
689
700
|
# Get the distance to the reference atom in the original unit cell with the
|
690
701
|
# minimum image convention.
|
691
702
|
distance = new_atoms.get_distance(
|
692
|
-
|
703
|
+
reference_atom_index, i, mic=True, vector=True
|
693
704
|
)
|
694
705
|
# Get the position that has the closest distance to
|
695
706
|
# the reference atom in the original unit cell.
|
696
|
-
position_i = positions[
|
707
|
+
position_i = positions[reference_atom_index] + distance
|
697
708
|
# Remove atom from atoms object.
|
698
709
|
new_atoms.pop()
|
699
710
|
else:
|
700
711
|
# Atom was part of the original unit cell.
|
701
712
|
position_i = positions[i]
|
702
713
|
# Average
|
703
|
-
avg_positions_in_prim_cell[
|
714
|
+
avg_positions_in_prim_cell[reference_atom_index] += position_i / M
|
704
715
|
positions_in_prim_cell[i] = position_i
|
705
716
|
|
706
717
|
new_atoms.set_positions(avg_positions_in_prim_cell)
|
707
718
|
|
708
|
-
#
|
709
|
-
|
710
|
-
for
|
711
|
-
|
712
|
-
|
713
|
-
|
719
|
+
# Check that all atoms are within tolerance of their translational images
|
720
|
+
cutoff = get_smallest_nn_dist(new_atoms) * 0.01
|
721
|
+
logger.info(f"Cutoff for period extension test is {cutoff}")
|
722
|
+
for i in range(original_number_atoms):
|
723
|
+
positions_of_all_images_of_atom_i = [
|
724
|
+
positions_in_prim_cell[j * original_number_atoms + i] for j in range(M)
|
725
|
+
]
|
726
|
+
_, r = get_distances(
|
727
|
+
positions_of_all_images_of_atom_i,
|
714
728
|
cell=new_atoms.get_cell(),
|
715
729
|
pbc=True,
|
716
730
|
)
|
717
|
-
#
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
reduced_distances: npt.ArrayLike,
|
726
|
-
significance_level: float = 0.05,
|
727
|
-
plot_filename: Optional[str] = None,
|
728
|
-
number_bins: Optional[int] = None,
|
729
|
-
) -> None:
|
730
|
-
"""
|
731
|
-
TODO: Incorporate this into :func:`change_of_basis_atoms`
|
732
|
-
|
733
|
-
Function to test whether the reduced atom positions are normally distributed
|
734
|
-
around their average.
|
735
|
-
|
736
|
-
Args:
|
737
|
-
reduced_distances:
|
738
|
-
Distance array provided by :func:`reduce_and_avg`
|
739
|
-
significance_level:
|
740
|
-
Significance level for Kolmogorov-Smirnov
|
741
|
-
plot_filename:
|
742
|
-
number_bins:
|
743
|
-
Number of bins for plot
|
744
|
-
|
745
|
-
Raises:
|
746
|
-
PeriodExtensionException:
|
747
|
-
If a non-normal distribution is detected
|
748
|
-
"""
|
749
|
-
assert len(reduced_distances.shape) == 3
|
750
|
-
assert reduced_distances.shape[2] == 3
|
751
|
-
|
752
|
-
if plot_filename is not None:
|
753
|
-
if number_bins is None:
|
754
|
-
raise ValueError(
|
755
|
-
"number_bins must be specified if plot_filename is specified"
|
731
|
+
# Checking full MxM matrix, could probably speed up by
|
732
|
+
# checking upper triangle only. Could also save memory
|
733
|
+
# by looping over individual distances instead of
|
734
|
+
# checking the max of a giant matrix
|
735
|
+
assert r.shape == (M, M)
|
736
|
+
if r.max() > cutoff:
|
737
|
+
raise PeriodExtensionException(
|
738
|
+
f"At least one image of atom {i} is outside of tolerance"
|
756
739
|
)
|
757
|
-
|
758
|
-
raise ValueError(f"{plot_filename} is not a PDF file")
|
759
|
-
with PdfPages(plot_filename) as pdf:
|
760
|
-
for i in range(reduced_distances.shape[0]):
|
761
|
-
fig, axs = plt.subplots(1, 3, figsize=(10.0, 4.0))
|
762
|
-
for j in range(reduced_distances.shape[2]):
|
763
|
-
axs[j].hist(reduced_distances[i, :, j], bins=number_bins)
|
764
|
-
axs[j].set_xlabel(f"$x_{j}$")
|
765
|
-
axs[0].set_ylabel("Counts")
|
766
|
-
fig.suptitle(f"Atom {i}")
|
767
|
-
pdf.savefig()
|
768
|
-
else:
|
769
|
-
if number_bins is not None:
|
770
|
-
raise ValueError(
|
771
|
-
"number_bins must not be specified if plot_filename is not specified"
|
772
|
-
)
|
773
|
-
|
774
|
-
p_values = np.empty((reduced_distances.shape[0], reduced_distances.shape[2]))
|
775
|
-
for i in range(reduced_distances.shape[0]):
|
776
|
-
atom_distances = reduced_distances[i]
|
777
|
-
|
778
|
-
# Perform PCA on the xyz distribution.
|
779
|
-
pca = PCA(n_components=atom_distances.shape[1])
|
780
|
-
pca_components = pca.fit_transform(atom_distances)
|
781
|
-
assert (
|
782
|
-
pca_components.shape == atom_distances.shape == reduced_distances.shape[1:]
|
783
|
-
)
|
784
|
-
|
785
|
-
# Test each component with a KS test.
|
786
|
-
for j in range(pca_components.shape[1]):
|
787
|
-
component = pca_components[:, j]
|
788
|
-
component_mean = np.mean(component)
|
789
|
-
assert abs(component_mean) < 1.0e-7
|
790
|
-
component_std = np.std(component)
|
791
|
-
# Normalize component
|
792
|
-
normalized_component = (component - component_mean) / component_std
|
793
|
-
assert abs(np.mean(normalized_component)) < 1.0e-7
|
794
|
-
assert abs(np.std(normalized_component) - 1.0) < 1.0e-7
|
795
|
-
res = kstest(normalized_component, "norm")
|
796
|
-
p_values[i, j] = res.pvalue
|
797
|
-
|
798
|
-
if np.any(p_values <= significance_level):
|
799
|
-
raise PeriodExtensionException(
|
800
|
-
"Detected non-normal distribution of reduced atom positions around their "
|
801
|
-
f"average (smallest p value {np.min(p_values)})."
|
802
|
-
)
|
803
|
-
else:
|
804
|
-
print(
|
805
|
-
"Detected normal distribution or reduced atom positions around their "
|
806
|
-
f"average (smallest p value {np.min(p_values)})."
|
807
|
-
)
|
740
|
+
return new_atoms
|
808
741
|
|
809
742
|
|
810
743
|
def voigt_to_full_symb(voigt_input: sp.Array) -> sp.MutableDenseNDimArray:
|
@@ -1073,6 +1006,23 @@ def fit_voigt_tensor_to_cell_and_space_group(
|
|
1073
1006
|
return t_symmetrized.voigt
|
1074
1007
|
|
1075
1008
|
|
1009
|
+
def get_smallest_nn_dist(atoms: Atoms) -> float:
|
1010
|
+
"""
|
1011
|
+
Get the smallest NN distance in an Atoms object
|
1012
|
+
"""
|
1013
|
+
nl_len = 0
|
1014
|
+
cov_mult = 1
|
1015
|
+
while nl_len == 0:
|
1016
|
+
logger.info(
|
1017
|
+
"Attempting to find NN distance by searching "
|
1018
|
+
f"within covalent radii times {cov_mult}"
|
1019
|
+
)
|
1020
|
+
nl = neighbor_list("d", atoms, natural_cutoffs(atoms, mult=cov_mult))
|
1021
|
+
nl_len = nl.size
|
1022
|
+
cov_mult += 1
|
1023
|
+
return nl.min()
|
1024
|
+
|
1025
|
+
|
1076
1026
|
class FixProvidedSymmetry(FixSymmetry):
|
1077
1027
|
"""
|
1078
1028
|
A modification of :obj:`~ase.constraints.FixSymmetry` that takes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kim-tools
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
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>, Navaneeth Mohan <mohan227@umn.edu>
|
6
6
|
Maintainer-email: ilia Nikiforov <nikif002@umn.edu>
|
@@ -1,7 +1,7 @@
|
|
1
|
-
kim_tools/__init__.py,sha256=
|
1
|
+
kim_tools/__init__.py,sha256=5zBMy-IWgNOROy8kqq0jxJ4bPsz-87y2FNW9LY9VjqA,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=
|
4
|
+
kim_tools/aflow_util/core.py,sha256=OmU4-m2jl81jfs0ni4bSECpC8GYt7-hEEH7cfKmrdoM,80886
|
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=umJY0LV3_zrEZLOXAFoz6AFigxA69sAOBzAGoBTDzxA,34335
|
2006
2006
|
kim_tools/symmetry_util/__init__.py,sha256=uu-ZSUDUTe2P81rkAS3tXverx31s_uZ3wL4SD_dn5aI,86
|
2007
|
-
kim_tools/symmetry_util/core.py,sha256=
|
2007
|
+
kim_tools/symmetry_util/core.py,sha256=DR2vOYvuFTRYLbvFHeM5Xvwey-jCbRR5zFe4RkMOVsA,41408
|
2008
2008
|
kim_tools/symmetry_util/elasticity.py,sha256=VxJ8wUcsSOPyJ8id6OpKmVlRAbIUIWxtzYJtkvVJIVs,13328
|
2009
2009
|
kim_tools/symmetry_util/data/elast_cubic.svg,sha256=UpN4XcoLoOwv8a7KE0WyINkSH5AU2DPVZ08eGQf-Cds,8953
|
2010
2010
|
kim_tools/symmetry_util/data/elast_hexagonal.svg,sha256=wOkw5IO3fZy039tLHhvtwrkatVYs5XzigUormLKtRlw,8705
|
@@ -2026,8 +2026,8 @@ kim_tools/test_driver/__init__.py,sha256=KOiceeZNqkfrgZ66CiRiUdniceDrCmmDXQkOw0w
|
|
2026
2026
|
kim_tools/test_driver/core.py,sha256=3UUru2HfDZMD4zeA6lxVnUPr5KjQQhFAbRS1XA-WngY,101610
|
2027
2027
|
kim_tools/vc/__init__.py,sha256=zXjhxXCKVMLBMXXWYG3if7VOpBnsFrn_RjVpnohDm5c,74
|
2028
2028
|
kim_tools/vc/core.py,sha256=BIjzEExnQAL2S90a_npptRm3ACqAo4fZBtvTDBMWMdw,13963
|
2029
|
-
kim_tools-0.
|
2030
|
-
kim_tools-0.
|
2031
|
-
kim_tools-0.
|
2032
|
-
kim_tools-0.
|
2033
|
-
kim_tools-0.
|
2029
|
+
kim_tools-0.4.0.dist-info/licenses/LICENSE.CDDL,sha256=I2luEED_SHjuZ01B4rYG-AF_135amL24JpHvZ1Jhqe8,16373
|
2030
|
+
kim_tools-0.4.0.dist-info/METADATA,sha256=AS9mzIzat5Kgj3ly4h6R6chJrqQZ68J6wmNHU0I0e0A,2068
|
2031
|
+
kim_tools-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
2032
|
+
kim_tools-0.4.0.dist-info/top_level.txt,sha256=w_YCpJ5ERigj9te74ln7k64tqj1VumOzM_s9dsalIWY,10
|
2033
|
+
kim_tools-0.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|