Skip to content

Commit

Permalink
Add group_order_from_schoenflies, ready to auto-convert from relaxe…
Browse files Browse the repository at this point in the history
…d structure -> point symmetry -> orientational degeneracy
  • Loading branch information
kavanase committed Nov 22, 2023
1 parent fffff6b commit 779a528
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 78 deletions.
85 changes: 8 additions & 77 deletions doped/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
get_primitive_structure,
get_wyckoff,
get_wyckoff_label_and_equiv_coord_list,
schoenflies_from_hermann,
)

_dummy_species = DummySpecies("X") # Dummy species used to keep track of defect coords in the supercell
Expand Down Expand Up @@ -258,7 +259,7 @@ def get_defect_name_from_defect(defect, element_list=None, symm_ops=None, sympre
symm_dataset, _unique_sites = _get_symm_dataset_of_struc_with_all_equiv_sites(
defect.site.frac_coords, defect.structure, symm_ops=symm_ops, symprec=symprec
)
spglib_point_group_symbol = herm2sch(symm_dataset["site_symmetry_symbols"][-1])
spglib_point_group_symbol = schoenflies_from_hermann(symm_dataset["site_symmetry_symbols"][-1])
if spglib_point_group_symbol is not None:
point_group_symbol = spglib_point_group_symbol
else: # symm_ops approach failed, just use diagonal defect supercell approach:
Expand All @@ -268,7 +269,7 @@ def get_defect_name_from_defect(defect, element_list=None, symm_ops=None, sympre
) # create defect supercell, which is a diagonal expansion of the unit cell so that the defect
# periodic image retains the unit cell symmetry, in order not to affect the point group symmetry
sga = _get_sga(defect_diagonal_supercell, symprec=symprec)
point_group_symbol = herm2sch(sga.get_point_group_symbol())
point_group_symbol = schoenflies_from_hermann(sga.get_point_group_symbol())

return f"{defect.name}_{point_group_symbol}_{closest_site_info(defect, element_list=element_list)}"

Expand All @@ -292,15 +293,15 @@ def _check_unrelaxed_defect_symmetry_determination(
symm_ops=symm_ops,
symprec=symprec,
)
unrelaxed_spglib_point_group_symbol = herm2sch(symm_dataset["pointgroup"])
unrelaxed_spglib_point_group_symbol = schoenflies_from_hermann(symm_dataset["pointgroup"])

symm_dataset, _unique_sites = _get_symm_dataset_of_struc_with_all_equiv_sites(
defect_entry.defect_supercell_site.frac_coords,
defect_entry.bulk_supercell,
symm_ops=symm_ops,
symprec=symprec,
)
bulk_spglib_point_group_symbol = herm2sch(symm_dataset["pointgroup"])
bulk_spglib_point_group_symbol = schoenflies_from_hermann(symm_dataset["pointgroup"])

if bulk_spglib_point_group_symbol != unrelaxed_spglib_point_group_symbol:
if verbose:
Expand Down Expand Up @@ -442,14 +443,14 @@ def get_defect_name_from_entry(
# site_symmetry_symbols[-1] works better for unrelaxed defects (as sometimes with the equivalent
# sites population it can change the overall point group symbol (but site symmetry symbol is
# still correct))
spglib_point_group_symbol = herm2sch(symm_dataset["site_symmetry_symbols"][-1])
spglib_point_group_symbol = schoenflies_from_hermann(symm_dataset["site_symmetry_symbols"][-1])

else:
# For relaxed defects the "defect supercell site" is not necessarily the true centre of mass of
# the defect (e.g. for split-interstitials, split-vacancies, swapped vacancies etc),
# so use 'pointgroup' output (in this case the reduced symmetry avoids the symmetry-upgrade
# possibility with the equivalent sites, as when unrelaxed=True)
spglib_point_group_symbol = herm2sch(symm_dataset["pointgroup"])
spglib_point_group_symbol = schoenflies_from_hermann(symm_dataset["pointgroup"])

if spglib_point_group_symbol is not None:
point_group_symbol = spglib_point_group_symbol
Expand All @@ -467,7 +468,7 @@ def get_defect_name_from_entry(
) # create defect supercell, which is a diagonal expansion of the unit cell so that the defect
# periodic image retains the unit cell symmetry, in order not to affect the point group symmetry
sga = _get_sga(defect_diagonal_supercell, symprec=symprec)
point_group_symbol = herm2sch(sga.get_point_group_symbol())
point_group_symbol = schoenflies_from_hermann(sga.get_point_group_symbol())

return (
f"{defect_entry.defect.name}_{point_group_symbol}"
Expand Down Expand Up @@ -697,32 +698,6 @@ def handle_repeated_name(defect_naming_dict, full_defect_name):
return defect_naming_dict


def herm2sch(herm_symbol):
"""
Convert from Hermann-Mauguin to Schoenflies.
"""
herm_symbol = herm_symbol.replace(".", "")
schoenflies = _HERM2SCH.get(herm_symbol, None)
if schoenflies is None:
# try rearranging, symbols in spglib can be rearranged vs _HERM2SCH dict
# get _HERM2SCH key that has the same characters as herm_symbol
# (i.e. same characters, but possibly in a different order)
from collections import Counter

def find_matching_key(input_str, input_dict):
input_str_counter = Counter(input_str)
for key in input_dict:
if Counter(key) == input_str_counter:
return key
return None

herm_key = find_matching_key(herm_symbol, _HERM2SCH)
if herm_key is not None:
schoenflies = _HERM2SCH[herm_key]

return schoenflies


def get_oxi_probabilities(element_symbol: str) -> dict:
"""
Get a dictionary of oxidation states and their probabilities for an
Expand Down Expand Up @@ -2339,47 +2314,3 @@ def _get_interstitial_candidate_sites(args):
"""
interstitial_generator, structure = args
return [*interstitial_generator._get_candidate_sites(structure)]


# Schoenflies, Hermann-Mauguin, spgid dict: (Taken from the excellent Abipy with GNU GPL License)
_PTG_IDS = [
("C1", "1", 1),
("Ci", "-1", 2),
("C2", "2", 3),
("Cs", "m", 6),
("C2h", "2/m", 10),
("D2", "222", 16),
("C2v", "mm2", 25),
("D2h", "mmm", 47),
("C4", "4", 75),
("S4", "-4", 81),
("C4h", "4/m", 83),
("D4", "422", 89),
("C4v", "4mm", 99),
("D2d", "-42m", 111),
("D4h", "4/mmm", 123),
("C3", "3", 143),
("C3i", "-3", 147),
("D3", "32", 149),
("C3v", "3m", 156),
("D3d", "-3m", 162),
("C6", "6", 168),
("C3h", "-6", 174),
("C6h", "6/m", 175),
("D6", "622", 177),
("C6v", "6mm", 183),
("D3h", "-6m2", 189),
("D6h", "6/mmm", 191),
("T", "23", 195),
("Th", "m-3", 200),
("O", "432", 207),
("Td", "-43m", 215),
("Oh", "m-3m", 221),
]

_SCH2HERM = {t[0]: t[1] for t in _PTG_IDS}
_HERM2SCH = {t[1]: t[0] for t in _PTG_IDS}
_SPGID2SCH = {t[2]: t[0] for t in _PTG_IDS}
_SCH2SPGID = {t[0]: t[2] for t in _PTG_IDS}

sch_symbols = list(_SCH2HERM.keys())
2 changes: 1 addition & 1 deletion doped/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pymatgen.core.periodic_table import Element
from pymatgen.util.string import latexify

from doped.generation import sch_symbols # point group symbols
from doped.utils.symmetry import sch_symbols # point group symbols


# TODO: Make a specific tutorial in docs for editing return Matplotlib figures, or with rcParams,
Expand Down
115 changes: 115 additions & 0 deletions doped/utils/symmetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,3 +837,118 @@ def _skip_to_spacegroup(f, spacegroup, setting=None):
if line.startswith(name):
break
return line


# Schoenflies, Hermann-Mauguin, spgid dict: (Taken from the excellent Abipy with GNU GPL License)
_PTG_IDS = [
("C1", "1", 1),
("Ci", "-1", 2),
("C2", "2", 3),
("Cs", "m", 6),
("C2h", "2/m", 10),
("D2", "222", 16),
("C2v", "mm2", 25),
("D2h", "mmm", 47),
("C4", "4", 75),
("S4", "-4", 81),
("C4h", "4/m", 83),
("D4", "422", 89),
("C4v", "4mm", 99),
("D2d", "-42m", 111),
("D4h", "4/mmm", 123),
("C3", "3", 143),
("C3i", "-3", 147),
("D3", "32", 149),
("C3v", "3m", 156),
("D3d", "-3m", 162),
("C6", "6", 168),
("C3h", "-6", 174),
("C6h", "6/m", 175),
("D6", "622", 177),
("C6v", "6mm", 183),
("D3h", "-6m2", 189),
("D6h", "6/mmm", 191),
("T", "23", 195),
("Th", "m-3", 200),
("O", "432", 207),
("Td", "-43m", 215),
("Oh", "m-3m", 221),
]

_SCH_to_HERM = {t[0]: t[1] for t in _PTG_IDS}
_HERM_to_SCH = {t[1]: t[0] for t in _PTG_IDS}
_SPGID_to_SCH = {t[2]: t[0] for t in _PTG_IDS}
_SCH_to_SPGID = {t[0]: t[2] for t in _PTG_IDS}

sch_symbols = list(_SCH_to_HERM.keys())


def schoenflies_from_hermann(herm_symbol):
"""
Convert from Hermann-Mauguin to Schoenflies.
"""
herm_symbol = herm_symbol.replace(".", "")
schoenflies = _HERM_to_SCH.get(herm_symbol)
if schoenflies is None:
# try rearranging, symbols in spglib can be rearranged vs _HERM_to_SCH dict
# get _HERM_to_SCH key that has the same characters as herm_symbol
# (i.e. same characters, but possibly in a different order)
from collections import Counter

def find_matching_key(input_str, input_dict):
input_str_counter = Counter(input_str)
for key in input_dict:
if Counter(key) == input_str_counter:
return key
return None

herm_key = find_matching_key(herm_symbol, _HERM_to_SCH)
if herm_key is not None:
schoenflies = _HERM_to_SCH[herm_key]

return schoenflies


_point_group_order = {
"C1": 1,
"Ci": 2, # aka. S2, -1 in Hermann-Mauguin
"C2": 2,
"Cs": 2, # aka. C1h (m in Hermann-Mauguin)
"C3": 3,
"C4": 4,
"S4": 4, # C4 with improper rotation
"C2h": 4, # 2/m in Hermann-Mauguin
"D2": 4, # 222 in Hermann-Mauguin
"C2v": 4, # mm2 in Hermann-Mauguin
"C3i": 6, # aka. S6, -3 in Hermann-Mauguin
"C6": 6,
"C3h": 6,
"D3": 6, # 32 in Hermann-Mauguin
"C3v": 6, # 3m in Hermann-Mauguin
"D2h": 8, # mmm in Hermann-Mauguin
"C4h": 8, # 4/m in Hermann-Mauguin
"D4": 8, # 422 in Hermann-Mauguin
"C4v": 8, # 4mm in Hermann-Mauguin
"D2d": 8, # 42m in Hermann-Mauguin
"C6h": 12, # 6/m in Hermann-Mauguin
"T": 12, # 23 in Hermann-Mauguin
"D3d": 12, # 3m1 in Hermann-Mauguin
"D6": 12, # 622 in Hermann-Mauguin
"C6v": 12, # 6mm in Hermann-Mauguin
"D3h": 12, # 6m2 in Hermann-Mauguin
"D4h": 16, # 4/mmm in Hermann-Mauguin
"D6h": 24, # 6/mmm in Hermann-Mauguin
"Th": 24, # m3 in Hermann-Mauguin
"O": 24, # 432 in Hermann-Mauguin
"Td": 24, # 43m in Hermann-Mauguin
"Oh": 48, # m3m in Hermann-Mauguin
}


def group_order_from_schoenflies(sch_symbol):
"""
Return the order of the point group from the Schoenflies symbol.
Useful for symmetry and orientational degeneracy analysis.
"""
return _point_group_order[sch_symbol]

0 comments on commit 779a528

Please sign in to comment.