Skip to content

Raise error when disordered structure is passed to Transitions #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/gemdat/trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@


def _lengths(vectors: np.ndarray, lattice: Lattice) -> np.ndarray:
"""Calculate vector lengths using the metric tensor (Dunitz 1078, p227).
"""Calculate vector lengths using the metric tensor (Dunitz 1978, p227).

Parameters
----------
Expand Down
29 changes: 12 additions & 17 deletions src/gemdat/transitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ class Transitions:
Assingn NOSITE if the atom is in transition
"""

DISORDER_ERROR_MSG = (
'Input `sites` are disordered! '
'The analysis does not work with disordered structures. '
'Remove disorder and partial occupancies or try '
'`gemdat.utils.remove_disorder_from_structure(). '
'See https://github.com/GEMDAT-repos/GEMDAT/issues/339 for more information.'
)

def __init__(
self,
*,
Expand All @@ -49,7 +57,6 @@ def __init__(
events: pd.DataFrame,
states: np.ndarray,
inner_states: np.ndarray,
set_partial_occupancies_to_1: bool = False,
):
"""Store event data for jumps and transitions between sites.

Expand All @@ -68,24 +75,9 @@ def __init__(
Input states
inner_states : np.ndarray
Input states for inner sites
set_partial_occupancies_to_1 : bool
Change partial occupancies in the disordered sites and set them to 1.
"""
if not (sites.is_ordered):
warn(
'Input `sites` are disordered! '
'Although the code may work, it was written under the assumption '
'that an ordered structure would be passed. '
'Use `set_partial_occupancies_to_1=True` to set all occupancies to 1.'
'See https://github.com/GEMDAT-repos/GEMDAT/issues/339 for more information.',
stacklevel=2,
)

if set_partial_occupancies_to_1:
for idx, site in enumerate(sites):
if site.is_ordered:
continue
sites.replace(idx=idx, species=site.species.elements[0], label=site.label)
raise ValueError(self.DISORDER_ERROR_MSG)

self.sites = sites
self.trajectory = trajectory
Expand Down Expand Up @@ -125,6 +117,9 @@ def from_trajectory(
-------
transitions: Transitions
"""
if not (sites.is_ordered):
raise ValueError(cls.DISORDER_ERROR_MSG)

diff_trajectory = trajectory.filter(floating_specie)

if site_radius is None:
Expand Down
24 changes: 24 additions & 0 deletions src/gemdat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,27 @@ def fft_autocorrelation(coords: np.ndarray) -> np.ndarray:
autocorrelation = autocorrelation / autocorrelation[:, 0, np.newaxis]

return autocorrelation


def remove_disorder_from_structure(structure: Structure) -> Structure:
"""Attempts to remove disorder and partial occupancies from input
structure.

Parameters
----------
structure : Structure
Input structure

Returns
-------
new_structure : Structure
Output structure with disorder removed
"""
new_structure = structure.copy()

for idx, site in enumerate(new_structure):
if site.is_ordered:
continue
new_structure.replace(idx=idx, species=site.species.elements[0], label=site.label)

return new_structure
25 changes: 24 additions & 1 deletion tests/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
import numpy as np
import pytest
from numpy.testing import assert_allclose, assert_equal
from pymatgen.core import Structure

from gemdat.utils import bfill, cartesian_to_spherical, ffill, integer_remap, meanfreq
from gemdat.utils import (
bfill,
cartesian_to_spherical,
ffill,
integer_remap,
meanfreq,
remove_disorder_from_structure,
)


@pytest.fixture
Expand Down Expand Up @@ -132,3 +140,18 @@ def test_cartesian_to_spherical():
]
)
assert_allclose(ret, expected, rtol=1e-5)


def test_remove_disorder_from_structure():
structure = Structure(
lattice=np.eye(3) * 10,
coords=[(0, 0, 0), (0.5, 0.5, 0.5)],
species=[{'Si': 0.5, 'Ge': 0.5}, {'Ge': 0.5}],
labels=['A', 'B'],
)
assert not structure.is_ordered

new_structure = remove_disorder_from_structure(structure)
assert new_structure.is_ordered
assert len(new_structure) == 2
assert new_structure.labels == structure.labels