Source code for aiida_phonopy.calculations.functions.link_structures
# -*- coding: utf-8 -*-
"""Functions for linking PhonopyAtoms and StructureData."""
from __future__ import annotations
from aiida.orm import StructureData
from phonopy.structure.cells import PhonopyAtoms
__all__ = ('phonopy_atoms_to_structure', 'phonopy_atoms_from_structure', 'if_to_map')
[docs]def phonopy_atoms_to_structure(
cell: PhonopyAtoms,
mapping: dict | None = None,
pbc: tuple[bool, bool, bool] = (True, True, True),
) -> StructureData:
"""Return a StructureData from a PhonopyAtoms instance.
:param cell: a PhonopyAtoms instance
:param mapping: a number to kinds and symbols map, defaults to None
:param pbc: periodic boundary conditions in the three lattice directions
"""
if mapping:
numbers_to_kinds, numbers_to_symbols = mapping
symbols = []
positions = []
names = []
for number in cell.numbers:
try:
names.append(numbers_to_kinds[number])
symbols.append(numbers_to_symbols[number])
except KeyError:
names.append(numbers_to_kinds[str(number)])
symbols.append(numbers_to_symbols[str(number)])
else:
names = cell.symbols
symbols = cell.symbols
positions = cell.positions
masses = cell.masses
structure = StructureData(cell=cell.cell, pbc=pbc)
for position, symbol, name, mass in zip(positions, symbols, names, masses):
structure.append_atom(position=position, symbols=symbol, name=name, mass=mass)
return structure
[docs]def phonopy_atoms_from_structure(structure: StructureData) -> PhonopyAtoms:
"""Return a tuple containg the PhonopyAtoms and the mapping from a StructureData.
:param structure: StructureData instance
:return: tuple with element:
* a :class:`~phonopy.structure.cells.PhonopyAtoms` istance
* mapping dictionary, with key:pair of the type int:str, string
referring to the custom atomic name
"""
to_map = if_to_map(structure)
if not to_map: # when kind_names=symbols are used in the structure
cell = PhonopyAtoms(
symbols=[site.kind_name for site in structure.sites],
positions=[site.position for site in structure.sites],
cell=structure.cell,
)
return (cell, None)
# when using custom kind_names (!=symbols) in the structure
sites = structure.sites
symbols = [] # chemical symbols
positions = []
masses = []
names = [] # actual kind names
numbers = []
kind_names = structure.get_kind_names()
# The numbers start from 1, i.e. from the hydrogen element.
kinds_to_numbers = {kind_names[i]: i + 1 for i in range(len(kind_names))}
for site in sites:
kind = structure.get_kind(site.kind_name)
symbols.append(kind.symbol)
masses.append(kind.mass)
names.append(kind.name)
positions.append(site.position)
numbers.append(kinds_to_numbers[kind.name])
numbers_to_symbols = {numbers[i]: symbols[i] for i in range(len(sites))}
# I build a PhonopyAtoms instance using the numbers instead of the symbols.
# This will change the symbols which will be automatically stored in the instance.
# We keep track of this 'issue' by returning `mapping` used
# afterwards to remap the kind_names to the atoms.
cell = PhonopyAtoms(
numbers=numbers,
positions=positions,
masses=masses,
cell=structure.cell,
)
# Also here we start from 1.
numbers_to_kinds = {i + 1: kind_names[i] for i in range(len(kind_names))}
return (cell, [numbers_to_kinds, numbers_to_symbols])
[docs]def if_to_map(structure: StructureData) -> bool:
"""Return a bool according whether kind names and symbols are the same.
:param structure: StructureData instance
:return: True if kind names different from symbols are used, False otherwise
"""
check_kinds = [True for kind in structure.kinds if kind.name != kind.symbol]
return bool(check_kinds)