Source code for aiida_hubbard.calculations.functions.structure_relabel_kinds
# -*- coding: utf-8 -*-
"""Calculation function to relabel the kinds of a Hubbard structure."""
from __future__ import annotations
from copy import deepcopy
from aiida.engine import calcfunction
from aiida.orm import Dict
from aiida_quantumespresso.data.hubbard_structure import HubbardStructureData
@calcfunction
[docs]def structure_relabel_kinds(
hubbard_structure: HubbardStructureData,
hubbard: Dict,
magnetization: dict | None = None,
) -> Dict:
"""Create a clone of the given structure but with new kinds, based on the new hubbard sites.
:param hubbard_structure: ``HubbardStructureData`` instance.
:param hubbard: the ``hubbard`` output Dict node of a ``HpCalculation``.
:param magnetization: Dict instance containing the `starting_magnetization` QuantumESPRESSO inputs.
:return: dict with keys:
* ``hubbard_structure``: relabelled ``HubbardStructureData``
* ``starting_magnetization``: updated magnetization as :class:`~aiida.orm.Dict` (if provided in inputs)
"""
relabeled = hubbard_structure.clone()
relabeled.clear_kinds()
relabeled.clear_sites()
type_to_kind = {}
sites = hubbard_structure.sites
if magnetization:
old_magnetization = magnetization.get_dict()
new_magnetization = deepcopy(old_magnetization)
# Removing old Hubbard spin-polarized atom label.
for site in hubbard['sites']:
new_magnetization.pop(site['kind'], None)
kind_set = hubbard_structure.get_site_kindnames()
symbol_set = [hubbard_structure.get_kind(kind_name).symbol for kind_name in kind_set]
symbol_counter = {key: 0 for key in hubbard_structure.get_symbols_set()}
# First do the Hubbard sites, popping the kind name suffix each time a new type is encountered. We do the suffix
# generation ourselves, because the indexing done by hp.x contains gaps in the sequence.
for index, site in enumerate(hubbard['sites']):
symbol = symbol_set[index]
try:
# We define a `spin_type`, since ``hp.x`` does not distinguish new types according to spin
spin_type = str(int(site['new_type']) * int(site['spin']))
kind_name = type_to_kind[spin_type]
except KeyError:
kind_name = get_relabelled_symbol(symbol, symbol_counter[symbol])
type_to_kind[spin_type] = kind_name
symbol_counter[symbol] += 1
if magnetization:
# filling 'starting magnetization' with input value but new label;
# if does not present a starting value, pass.
if site['kind'] in old_magnetization:
new_magnetization[kind_name] = old_magnetization[site['kind']]
site = sites[index]
try:
relabeled.append_atom(position=site.position, symbols=symbol, name=kind_name)
except ValueError as exc:
raise ValueError('cannot distinguish kinds with the given Hubbard input configuration') from exc
# Now add the non-Hubbard sites
for site in sites[len(relabeled.sites):]:
symbols = hubbard_structure.get_kind(site.kind_name).symbols
names = hubbard_structure.get_kind(site.kind_name).name
relabeled.append_atom(position=site.position, symbols=symbols, name=names)
outputs = {'hubbard_structure': relabeled}
if magnetization:
outputs.update({'starting_magnetization': Dict(new_magnetization)})
return outputs
[docs]def get_relabelled_symbol(symbol: str, counter: int) -> str:
"""Return a relabelled symbol.
.. warning:: this function produces up to 36 different chemical symbols.
:param symbol: a chemical symbol, NOT a kind name
:param counter: a integer to assing the new label. Up to 9 an interger
is appended, while an *ascii uppercase letter* is used. Lower cases
are discarded to avoid possible misleading names
:return: a 3 digit length symbol (QuantumESPRESSO allows only up to 3)
"""
from string import ascii_uppercase, digits
suffix = (digits + ascii_uppercase)[counter]
return f'{symbol}{suffix}'