Skip to content

Commit

Permalink
refactory
Browse files Browse the repository at this point in the history
  • Loading branch information
jinlhr542 committed Jul 17, 2024
1 parent 454aa5e commit 70628b4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 18 deletions.
29 changes: 23 additions & 6 deletions src/pymatgen/analysis/interfaces/coherent_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import numpy as np
from numpy.testing import assert_allclose
from scipy.linalg import polar

from pymatgen.analysis.elasticity.strain import Deformation
from pymatgen.analysis.interfaces.zsl import ZSLGenerator, fast_norm
from pymatgen.core.interface import Interface, label_termination
from pymatgen.core.surface import SlabGenerator
from scipy.linalg import polar

if TYPE_CHECKING:
from collections.abc import Iterator, Sequence
Expand All @@ -33,6 +34,8 @@ def __init__(
film_miller: Tuple3Ints,
substrate_miller: Tuple3Ints,
zslgen: ZSLGenerator | None = None,
termination_ftol=0.25,
label_index=False, # necessary to add index to termination
):
"""
Args:
Expand All @@ -41,14 +44,17 @@ def __init__(
film_miller: miller index of the film layer
substrate_miller: miller index for the substrate layer
zslgen: BiDirectionalZSL if you want custom lattice matching tolerances for coherency.
termination_ftol: tolerance to distinguish different terminating atomic planes.
label_index: whether to add an extra index at the beginning of the termination label.
"""
# Bulk structures
self.substrate_structure = substrate_structure
self.film_structure = film_structure
self.film_miller = film_miller
self.substrate_miller = substrate_miller
self.zslgen = zslgen or ZSLGenerator(bidirectional=True)

self.termination_ftol = termination_ftol
self.label_index = label_index
self._find_matches()
self._find_terminations()

Expand Down Expand Up @@ -130,14 +136,25 @@ def _find_terminations(self):
reorient_lattice=False, # This is necessary to not screw up the lattice
)

film_slabs = film_sg.get_slabs()
sub_slabs = sub_sg.get_slabs()
film_slabs = film_sg.get_slabs(ftol=self.termination_ftol)
sub_slabs = sub_sg.get_slabs(ftol=self.termination_ftol)

film_shifts = [slab.shift for slab in film_slabs]
film_terminations = [label_termination(slab) for slab in film_slabs]

if self.label_index:
film_terminations = [
label_termination(slab, self.termination_ftol, t_index) for t_index, slab in enumerate(film_slabs, start=1)
]
else:
film_terminations = [label_termination(slab, self.termination_ftol) for slab in film_slabs]

sub_shifts = [slab.shift for slab in sub_slabs]
sub_terminations = [label_termination(slab) for slab in sub_slabs]
if self.label_index:
sub_terminations = [
label_termination(slab, self.termination_ftol, t_index) for t_index, slab in enumerate(sub_slabs, start=1)
]
else:
sub_terminations = [label_termination(slab, self.termination_ftol) for slab in sub_slabs]

self._terminations = {
(film_label, sub_label): (film_shift, sub_shift)
Expand Down
5 changes: 3 additions & 2 deletions src/pymatgen/analysis/interfaces/substrate_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

if TYPE_CHECKING:
from numpy.typing import ArrayLike
from typing_extensions import Self

from pymatgen.core import Structure
from pymatgen.util.typing import Tuple3Ints
from typing_extensions import Self


@dataclass
Expand Down Expand Up @@ -94,7 +95,7 @@ class SubstrateAnalyzer(ZSLGenerator):
"""

def __init__(self, film_max_miller=1, substrate_max_miller=1, **kwargs):
"""Initialize the substrate analyzer.
"""Initialize the substrate analyzer
Args:
zslgen (ZSLGenerator): Defaults to a ZSLGenerator with standard
Expand Down
31 changes: 21 additions & 10 deletions src/pymatgen/core/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,26 @@
import numpy as np
from monty.fractions import lcm
from numpy.testing import assert_allclose
from scipy.cluster.hierarchy import fcluster, linkage
from scipy.spatial.distance import squareform

from pymatgen.analysis.adsorption import AdsorbateSiteFinder
from pymatgen.core.lattice import Lattice
from pymatgen.core.sites import PeriodicSite, Site
from pymatgen.core.structure import Structure
from pymatgen.core.surface import Slab
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.util.typing import Tuple3Ints
from scipy.cluster.hierarchy import fcluster, linkage
from scipy.spatial.distance import squareform

if TYPE_CHECKING:
from collections.abc import Sequence
from typing import Any, Callable

from numpy.typing import ArrayLike, NDArray
from typing_extensions import Self

from pymatgen.core import Element
from pymatgen.util.typing import CompositionLike, Matrix3D, MillerIndex, Tuple3Floats, Vector3D
from typing_extensions import Self

Tuple4Ints = tuple[int, int, int, int]
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -696,7 +698,7 @@ def gb_from_parameters(
list(top_grain.frac_coords) + list(bottom_grain.frac_coords),
)
t_and_b_dis = t_and_b.lattice.get_all_distances(
t_and_b.frac_coords[:n_sites], t_and_b.frac_coords[n_sites : n_sites * 2]
t_and_b.frac_coords[0:n_sites], t_and_b.frac_coords[n_sites : n_sites * 2]
)
index_incident = np.nonzero(t_and_b_dis < np.min(t_and_b_dis) + tol_coi)

Expand Down Expand Up @@ -1442,7 +1444,7 @@ def enum_sigma_hex(
v = 2 * v1 + u1
w = w1
else:
u, v, w = r_axis # type: ignore[misc]
u, v, w = r_axis

# Make sure mu, mv are coprime integers
if c2_a2_ratio is None:
Expand Down Expand Up @@ -1555,7 +1557,7 @@ def enum_sigma_rho(
# Make sure math.(r_axis) == 1
if reduce(math.gcd, r_axis) != 1:
r_axis = cast(Tuple3Ints, tuple([round(x / reduce(math.gcd, r_axis)) for x in r_axis]))
u, v, w = r_axis # type: ignore[misc]
u, v, w = r_axis

# Make sure mu, mv are coprime integers
if ratio_alpha is None:
Expand Down Expand Up @@ -2837,8 +2839,13 @@ def from_slabs(
return iface


def label_termination(slab: Structure) -> str:
"""Label the slab surface termination."""
def label_termination(slab: Structure, ftol: float = 0.25, t_index: int | None = None) -> str:
"""Label the slab surface termination.
Args:
slab (Slab): film or substrate slab to label termination for
ftol (float): tolerance for terminating position hierachical clustering
t_index (None|int): if not None, adding an extra index to the termination label output
"""
frac_coords = slab.frac_coords
n = len(frac_coords)

Expand All @@ -2861,7 +2868,7 @@ def label_termination(slab: Structure) -> str:

condensed_m = squareform(dist_matrix)
z = linkage(condensed_m)
clusters = fcluster(z, 0.25, criterion="distance")
clusters = fcluster(z, ftol, criterion="distance")

clustered_sites: dict[int, list[Site]] = {c: [] for c in clusters}
for idx, cluster in enumerate(clusters):
Expand All @@ -2874,7 +2881,11 @@ def label_termination(slab: Structure) -> str:

sp_symbol = SpacegroupAnalyzer(top_plane, symprec=0.1).get_space_group_symbol()
form = top_plane.reduced_formula
return f"{form}_{sp_symbol}_{len(top_plane)}"

if t_index is None:
return f"{form}_{sp_symbol}_{len(top_plane)}"

return f"{t_index}_{form}_{sp_symbol}_{len(top_plane)}"


def count_layers(struct: Structure, el: Element | None = None) -> int:
Expand Down

0 comments on commit 70628b4

Please sign in to comment.