Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
gmatteo committed Aug 8, 2021
2 parents 66d7cc3 + e5fd7f5 commit fa70861
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 28 deletions.
7 changes: 7 additions & 0 deletions CHANGES.rst
@@ -1,6 +1,13 @@
Change log
==========

v2022.0.11
----------
* New features to handle Grüneisen parameters (@JaGeo, @ab5424, @gpetretto, #2190)
* New option to return SymmetrizedStructure in CifParser (@mkhorton, 0d9a455)
* Fix for SubstrateAnalyzer (@shyamd, #2198)
* Fix for BandFillingCorrection (@kavanase, #2193)

v2022.0.10
----------
* Add spin-dependent eigenvalue band properties (@arosen93, #2187)
Expand Down
17 changes: 13 additions & 4 deletions pymatgen/analysis/interfaces/substrate_analyzer.py
Expand Up @@ -64,16 +64,24 @@ def from_zsl(
else:
elastic_energy = 0

match_dict = match.as_dict()

cls(
return cls(
film_miller=film_miller,
substrate_miller=substrate_miller,
strain=strain,
von_mises_strain=von_mises_strain,
elastic_energy=elastic_energy,
ground_state_energy=ground_state_energy,
**{k: match_dict[k] for k in match_dict.keys() if not k.startswith("@")},
**{
k: getattr(match, k)
for k in [
"film_sl_vectors",
"substrate_sl_vectors",
"film_vectors",
"substrate_vectors",
"film_transformation",
"substrate_transformation",
]
},
)

@property
Expand Down Expand Up @@ -183,6 +191,7 @@ def calculate(
substrate_miller,
] in surface_vector_sets:
for match in self(film_vectors, substrate_vectors, lowest):

sub_match = SubstrateMatch.from_zsl(
match=match,
film=film,
Expand Down
3 changes: 3 additions & 0 deletions pymatgen/analysis/interfaces/tests/test_substrate_analyzer.py
Expand Up @@ -35,6 +35,9 @@ def test_init(self):

matches = list(s.calculate(film, substrate, film_elac))
self.assertEqual(len(matches), 192)
for match in matches:
assert match is not None
assert isinstance(match.match_area, float)


if __name__ == "__main__":
Expand Down
4 changes: 4 additions & 0 deletions pymatgen/analysis/interfaces/tests/test_zsl.py
Expand Up @@ -60,6 +60,10 @@ def test_bidirectional(self):
matches = list(z(self.substrate.lattice.matrix[:2], self.film.lattice.matrix[:2]))
self.assertEqual(len(matches), 48)

for match in matches:
assert match is not None
assert isinstance(match.match_area, float)


if __name__ == "__main__":
unittest.main()
16 changes: 8 additions & 8 deletions pymatgen/analysis/interfaces/zsl.py
Expand Up @@ -6,7 +6,7 @@
This module implements the Zur and McGill lattice matching algorithm
"""

from typing import Iterator
from typing import Iterator, List

from dataclasses import dataclass
from itertools import product
Expand All @@ -24,17 +24,17 @@ class ZSLMatch(MSONable):
the appropriate transformation matrix
"""

film_sl_vectors: np.ndarray
substrate_sl_vectors: np.ndarray
film_vectors: np.ndarray
substrate_vectors: np.ndarray
film_transformation: np.ndarray
substrate_transformation: np.ndarray
film_sl_vectors: List
substrate_sl_vectors: List
film_vectors: List
substrate_vectors: List
film_transformation: List
substrate_transformation: List

@property
def match_area(self):
"""The area of the match between the substrate and film super lattice vectors"""
return vec_area(*self.film_sl_vectors.tolist())
return vec_area(*self.film_sl_vectors)

@property
def match_transformation(self):
Expand Down
2 changes: 1 addition & 1 deletion pymatgen/core/__init__.py
Expand Up @@ -30,7 +30,7 @@
__email__ = "pymatgen@googlegroups.com"
__maintainer__ = "Shyue Ping Ong"
__maintainer_email__ = "shyuep@gmail.com"
__version__ = "2022.0.10"
__version__ = "2022.0.11"


SETTINGS_FILE = os.path.join(os.path.expanduser("~"), ".pmgrc.yaml")
Expand Down
4 changes: 2 additions & 2 deletions pymatgen/entries/compatibility.py
Expand Up @@ -851,8 +851,8 @@ def __init__(
References:
Wang, A., Kingsbury, R., McDermott, M., Horton, M., Jain. A., Ong, S.P.,
Dwaraknath, S., Persson, K. A framework for quantifying uncertainty
in DFT energy corrections. ChemRxiv. Preprint.
https://doi.org/10.26434/chemrxiv.14593476.v1
in DFT energy corrections. Scientific Reports 11: 15496, 2021.
https://doi.org/10.1038/s41598-021-94550-5
Jain, A. et al. Formation enthalpies by mixing GGA and GGA + U calculations.
Phys. Rev. B - Condens. Matter Mater. Phys. 84, 1–10 (2011).
Expand Down
58 changes: 51 additions & 7 deletions pymatgen/io/cif.py
Expand Up @@ -28,9 +28,10 @@
from pymatgen.core.periodic_table import DummySpecies, Element, Species, get_el_sp
from pymatgen.core.structure import Structure
from pymatgen.electronic_structure.core import Magmom
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer, SpacegroupOperations
from pymatgen.symmetry.groups import SYMM_DATA, SpaceGroup
from pymatgen.symmetry.maggroups import MagneticSpaceGroup
from pymatgen.symmetry.structure import SymmetrizedStructure
from pymatgen.util.coord import find_in_coord_list_pbc, in_coord_list_pbc

__author__ = "Shyue Ping Ong, Will Richards, Matthew Horton"
Expand Down Expand Up @@ -911,7 +912,7 @@ def _parse_symbol(self, sym):

return parsed_sym

def _get_structure(self, data, primitive):
def _get_structure(self, data, primitive, symmetrized):
"""
Generate structure from part of the cif.
"""
Expand Down Expand Up @@ -951,6 +952,7 @@ def get_matching_coord(coord):
return False

for i in range(len(data["_atom_site_label"])):

try:
# If site type symbol exists, use it. Otherwise, we use the
# label.
Expand Down Expand Up @@ -1021,6 +1023,7 @@ def get_matching_coord(coord):
allcoords = []
allmagmoms = []
allhydrogens = []
equivalent_indices = []

# check to see if magCIF file is disordered
if self.feature_flags["magcif"]:
Expand All @@ -1034,9 +1037,11 @@ def get_matching_coord(coord):
raise NotImplementedError("Disordered magnetic structures not currently supported.")

if coord_to_species.items():
for comp, group in groupby(
sorted(list(coord_to_species.items()), key=lambda x: x[1]),
key=lambda x: x[1],
for idx, (comp, group) in enumerate(
groupby(
sorted(list(coord_to_species.items()), key=lambda x: x[1]),
key=lambda x: x[1],
)
):
tmp_coords = [site[0] for site in group]
tmp_magmom = [coord_to_magmoms[tmp_coord] for tmp_coord in tmp_coords]
Expand All @@ -1054,6 +1059,17 @@ def get_matching_coord(coord):
im_h = 0
species = comp

# The following might be a more natural representation of equivalent indicies,
# but is not in the format expect by SymmetrizedStructure:
# equivalent_indices.append(list(range(len(allcoords), len(coords)+len(allcoords))))
# The above gives a list like:
# [[0, 1, 2, 3], [4, 5, 6, 7, 8, 9, 10, 11]] where the
# integers are site indices, whereas the version used below will give a version like:
# [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]
# which is a list in the same order as the sites, but where if a site has the same integer
# it is equivalent.
equivalent_indices += len(coords) * [idx]

allhydrogens.extend(len(coords) * [im_h])
allcoords.extend(coords)
allspecies.extend(len(coords) * [species])
Expand All @@ -1079,6 +1095,19 @@ def get_matching_coord(coord):

struct = Structure(lattice, allspecies, allcoords, site_properties=site_properties)

if symmetrized:

# Wyckoff labels not currently parsed, note that not all CIFs will contain Wyckoff labels
# TODO: extract Wyckoff labels (or other CIF attributes) and include as site_properties
wyckoffs = ["Not Parsed"] * len(struct)

# Names of space groups are likewise not parsed (again, not all CIFs will contain this information)
# What is stored are the lists of symmetry operations used to generate the structure
# TODO: ensure space group labels are stored if present
sg = SpacegroupOperations("Not Parsed", -1, self.symmetry_operations)

return SymmetrizedStructure(struct, sg, equivalent_indices, wyckoffs)

struct = struct.get_sorted_structure()

if primitive and self.feature_flags["magcif"]:
Expand All @@ -1089,7 +1118,7 @@ def get_matching_coord(coord):

return struct

def get_structures(self, primitive=True):
def get_structures(self, primitive=True, symmetrized=False):
"""
Return list of structures in CIF file. primitive boolean sets whether a
conventional cell structure or primitive cell structure is returned.
Expand All @@ -1098,14 +1127,29 @@ def get_structures(self, primitive=True):
primitive (bool): Set to False to return conventional unit cells.
Defaults to True. With magnetic CIF files, will return primitive
magnetic cell which may be larger than nuclear primitive cell.
symmetrized (bool): If True, return a SymmetrizedStructure which will
include the equivalent indices and symmetry operations used to
create the Structure as provided by the CIF (if explicit symmetry
operations are included in the CIF) or generated from information
in the CIF (if only space group labels are provided). Note that
currently Wyckoff labels and space group labels or numbers are
not included in the generated SymmetrizedStructure, these will be
notated as "Not Parsed" or -1 respectively.
Returns:
List of Structures.
"""

if primitive and symmetrized:
raise ValueError(
"Using both 'primitive' and 'symmetrized' arguments is not currently supported "
"since unexpected behavior might result."
)

structures = []
for i, d in enumerate(self._cif.data.values()):
try:
s = self._get_structure(d, primitive)
s = self._get_structure(d, primitive, symmetrized)
if s:
structures.append(s)
except (KeyError, ValueError) as exc:
Expand Down
9 changes: 9 additions & 0 deletions pymatgen/io/tests/test_cif.py
Expand Up @@ -14,6 +14,7 @@
from pymatgen.core.structure import Structure
from pymatgen.analysis.structure_matcher import StructureMatcher
from pymatgen.electronic_structure.core import Magmom
from pymatgen.symmetry.structure import SymmetrizedStructure
from pymatgen.io.cif import CifBlock, CifParser, CifWriter
from pymatgen.io.vasp.inputs import Poscar
from pymatgen.util.testing import PymatgenTest
Expand Down Expand Up @@ -291,6 +292,14 @@ def test_CifParser(self):
self.assertEqual(len(parser.get_structures(primitive=False)[0]), 2)
self.assertFalse(parser.has_errors)

def test_get_symmetrized_structure(self):
parser = CifParser(self.TEST_FILES_DIR / "Li2O.cif")
sym_structure = parser.get_structures(primitive=False, symmetrized=True)[0]
structure = parser.get_structures(primitive=False, symmetrized=False)[0]
self.assertIsInstance(sym_structure, SymmetrizedStructure)
self.assertEqual(structure, sym_structure)
self.assertEqual(sym_structure.equivalent_indices, [[0, 1, 2, 3], [4, 5, 6, 7, 8, 9, 10, 11]])

def test_site_symbol_preference(self):
parser = CifParser(self.TEST_FILES_DIR / "site_type_symbol_test.cif")
self.assertEqual(parser.get_structures()[0].formula, "Ge0.4 Sb0.4 Te1")
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.txt
Expand Up @@ -4,9 +4,9 @@ sphinx_rtd_theme
pytest==6.2.4
pytest-cov==2.12.1
coverage==5.5
coveralls==3.1.0
coveralls==3.2.0
mypy==0.910
pydocstyle==6.1.1
flake8==3.9.2
pylint==2.9.3
black==21.6b0
pylint==2.9.6
black==21.7b0
2 changes: 1 addition & 1 deletion requirements-optional.txt
@@ -1,5 +1,5 @@
pybtex==0.24.0
tqdm==4.61.2
tqdm==4.62.0
ase==3.19.0
chemview==0.6
netCDF4==1.5.3
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Expand Up @@ -8,7 +8,7 @@ tabulate==0.8.9
matplotlib==3.3.4
palettable==3.3.0
spglib==1.16.1
pandas==1.2.5
pandas==1.3.0
networkx==2.5.1
plotly==4.14.3
beautifulsoup4==4.9.3
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -97,7 +97,7 @@ def finalize_options(self):
include=["pymatgen.*", "pymatgen.analysis.*", "pymatgen.io.*", "pymatgen.ext.*"],
exclude=["pymatgen.*.tests", "pymatgen.*.*.tests", "pymatgen.*.*.*.tests"],
),
version="2022.0.10",
version="2022.0.11",
cmdclass={"build_ext": build_ext},
python_requires=">=3.7",
install_requires=[
Expand Down

0 comments on commit fa70861

Please sign in to comment.