Skip to content

Commit

Permalink
add discretized site occupancy transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
computron committed Oct 31, 2017
1 parent af98568 commit 0979f00
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
64 changes: 64 additions & 0 deletions pymatgen/transformations/advanced_transformations.py
Expand Up @@ -242,6 +242,70 @@ def is_one_to_many(self):
return True


class DiscretizeOccupanciesTransformation(AbstractTransformation):
"""
Discretizes the site occupancies in a disordered structure; useful for
grouping similar structures or as a pre-processing step for order-disorder
transformations.
Args:
max_denominator:
An integer maximum denominator for discretization. A higher
denominator allows for finer resolution in the site occupancies.
tol:
A float that sets the maximum difference between the original and
discretized occupancies before throwing an error. The maximum
allowed difference is calculated as 1/max_denominator * 0.5 * tol.
A tol of 1.0 indicates to try to accept all discretizations.
"""

def __init__(self, max_denominator=5, tol=0.25):
self.max_denominator = max_denominator
self.tol = tol

def apply_transformation(self, structure):
"""
Discretizes the site occupancies in the structure.
Args:
structure: disordered Structure to discretize occupancies
Returns:
A new disordered Structure with occupancies discretized
"""
if structure.is_ordered:
return structure

species = [dict(sp) for sp in structure.species_and_occu]

for sp in species:
for k, v in sp.items():
old_occ = sp[k]
new_occ = float(
Fraction(old_occ).limit_denominator(self.max_denominator))
if round(abs(old_occ - new_occ), 6) > (
1 / self.max_denominator / 2) * self.tol:
raise RuntimeError(
"Cannot discretize structure within tolerance!")
sp[k] = new_occ

return Structure(structure.lattice, species, structure.frac_coords)

def __str__(self):
return "DiscretizeOccupanciesTransformation"

def __repr__(self):
return self.__str__()

@property
def inverse(self):
return None

@property
def is_one_to_many(self):
return False


class EnumerateStructureTransformation(AbstractTransformation):
"""
Order a disordered structure using enumlib. For complete orderings, this
Expand Down
20 changes: 18 additions & 2 deletions pymatgen/transformations/tests/test_advanced_transformations.py
Expand Up @@ -9,7 +9,7 @@

import numpy as np

from pymatgen import Lattice, Structure, Specie
from pymatgen import Lattice, Structure, Specie, Element
from pymatgen.transformations.standard_transformations import \
OxidationStateDecorationTransformation, SubstitutionTransformation, \
OrderDisorderedStructureTransformation, AutoOxiStateDecorationTransformation
Expand All @@ -18,7 +18,7 @@
MultipleSubstitutionTransformation, ChargeBalanceTransformation, \
SubstitutionPredictorTransformation, MagOrderingTransformation, \
DopingTransformation, _find_codopant, SlabTransformation, \
MagOrderParameterConstraint
MagOrderParameterConstraint, DiscretizeOccupanciesTransformation
from monty.os.path import which
from pymatgen.io.vasp.inputs import Poscar
from pymatgen.io.cif import CifParser
Expand Down Expand Up @@ -152,6 +152,22 @@ def test_apply_transformation(self):
self.assertAlmostEqual(s.charge, 0, 5)


class DiscretizeOccupanciesTransformationTest(unittest.TestCase):

def test_apply_transformation(self):
l = Lattice.cubic(4)
s_orig = Structure(l, [{"Li": 0.19, "Na": 0.19, "K": 0.62}, {"O": 1}],
[[0, 0, 0], [0.5, 0.5, 0.5]])
dot = DiscretizeOccupanciesTransformation(max_denominator=5, tol=0.25)
s = dot.apply_transformation(s_orig)
self.assertEqual(dict(s[0].species_and_occu), {Element("Li"): 0.2,
Element("Na"): 0.2,
Element("K"): 0.6})

dot = DiscretizeOccupanciesTransformation(max_denominator=5, tol=0.1)
self.assertRaises(RuntimeError, dot.apply_transformation, s_orig)


@unittest.skipIf(not enumlib_present, "enum_lib not present.")
class EnumerateStructureTransformationTest(unittest.TestCase):

Expand Down

0 comments on commit 0979f00

Please sign in to comment.