Source code for aiida_atomistic.data.structure.hubbard_mixin

# -*- coding: utf-8 -*-
"""Utility class and functions for HubbardStructureData.
Borrowed and adapted from aiida-quantumespresso
"""
# pylint: disable=no-name-in-module, invalid-name
from typing import List, Literal, Tuple
from pymatgen.core import Lattice, PeriodicSite

import numpy as np

from aiida_quantumespresso.common.hubbard import Hubbard, HubbardParameters

[docs] class HubbardGetterMixin:
[docs] def get_hubbard_list(self) -> List[Tuple[int, str, int, str, float, Tuple[int, int, int], str]]: """Return the Hubbard `parameters` as a list of lists. The parameters have the following order within each list: * atom_index * atom_manifold * neighbour_index * neighbour_manifold * value * translation * hubbard_type """ return [params.to_tuple() for params in self.properties.hubbard.parameters]
[docs] class HubbardSetterMixin: #@staticmethod
[docs] def set_hubbard_from_list( parameters: List[Tuple[int, str, int, str, float, Tuple[int, int, int], str]], projectors: str = 'ortho-atomic', formulation: str = 'dudarev', ): """Return a :meth:`~aiida_quantumespresso.common.hubbard.Hubbard` instance from a list of tuples. Each list must contain the hubbard parameters in the following order: * atom_index * atom_manifold * neighbour_index * neighbour_manifold * value * translation * hubbard_type """ parameters = [HubbardParameters.from_tuple(value) for value in parameters] self.properties.hubbard = Hubbard(parameters=parameters, projectors=projectors, formulation=formulation) return
[docs] def append_hubbard_parameter( self, atom_index: int, atom_manifold: str, neighbour_index: int, neighbour_manifold: str, value: float, translation: Tuple[int, int, int] = None, hubbard_type: str = 'Ueff', ): """Append a :class:`~aiida_quantumespresso.common.hubbard.HubbardParameters`. :param atom_index: atom index in unitcell :param atom_manifold: atomic manifold (e.g. 3d, 3d-2p) :param neighbour_index: neighbouring atom index in unitcell :param neighbour_manifold: neighbour manifold (e.g. 3d, 3d-2p) :param value: value of the Hubbard parameter, in eV :param translation: (3,) list of ints, describing the translation vector associated with the neighbour atom, defaults to None :param hubbard_type: hubbard type (U, V, J, ...), defaults to 'Ueff' (see :class:`~aiida_quantumespresso.common.hubbard.Hubbard` for full allowed values) """ sites = [ PeriodicSite( species=site.species, coords=site.coords, lattice=Lattice(self.properties.cell, pbc=self.properties.pbc), coords_are_cartesian=True ) for site in self.get_pymatgen_structure().sites ] if any((atom_index > len(sites) - 1, neighbour_index > len(sites) - 1)): raise ValueError( 'atom_index and neighbour_index must be within the range of the number of sites in the structure' ) if translation is None: _, translation = sites[atom_index].distance_and_image(sites[neighbour_index]) translation = np.array(translation, dtype=np.int64).tolist() hp_tuple = (atom_index, atom_manifold, neighbour_index, neighbour_manifold, value, translation, hubbard_type) parameters = HubbardParameters.from_tuple(hp_tuple) hubbard = self.properties.hubbard if parameters not in hubbard.parameters: hubbard.parameters.append(parameters) self.properties.hubbard = hubbard
[docs] def pop_hubbard_parameters(self, index: int = -1): """Pop Hubbard parameters in the list. :param index: index of the Hubbard parameters to pop """ hubbard = self.properties.hubbard hubbard.parameters.pop(index) if index != -1 else hubbard.parameters.pop() self.properties.hubbard = hubbard
[docs] def clear_hubbard_parameters(self): """Clear all the Hubbard parameters.""" hubbard = self.properties.hubbard hubbard.parameters = [] self.properties.hubbard = hubbard
[docs] def initialize_intersites_hubbard( self, atom_name: str, atom_manifold: str, neighbour_name: str, neighbour_manifold: str, value: float = 1e-8, hubbard_type: str = 'V', use_kinds: bool = True, ): """Initialize and append intersite Hubbard values between an atom and its neighbour(s). .. note:: this only initialize the value between the first neighbour. In case `use_kinds` is False, all the possible combination of couples having kind name equal to symbol are initialized. :param atom_name: atom name in unitcell :param atom_manifold: atomic manifold (e.g. 3d, 3d-2p) :param neighbour_index: neighbouring atom name in unitcell :param neighbour_manifold: neighbour manifold (e.g. 3d, 3d-2p) :param value: value of the Hubbard parameter, in eV :param hubbard_type: hubbard type (U, V, J, ...), defaults to 'V' (see :class:`~aiida_quantumespresso.common.hubbard.Hubbard` for full allowed values) :param use_kinds: whether to use kinds for initializing the parameters; when False, it initializes all the ``Kinds`` matching the ``atom_name`` """ sites = self.get_pymatgen_structure().sites function = self._get_one_kind_index if use_kinds else self._get_symbol_indices atom_indices = function(atom_name) neigh_indices = function(neighbour_name) if atom_indices is None or neigh_indices is None: raise ValueError('species or kind names not in structure') for atom_index in atom_indices: for neighbour_index in neigh_indices: _, translation = sites[atom_index].distance_and_image(sites[neighbour_index]) translation = np.array(translation, dtype=np.int64).tolist() args = ( atom_index, atom_manifold, neighbour_index, neighbour_manifold, value, translation, hubbard_type ) self.append_hubbard_parameter(*args)
[docs] def initialize_onsites_hubbard( self, atom_name: str, atom_manifold: str, value: float = 1e-8, hubbard_type: str = 'Ueff', use_kinds: bool = True, ): """Initialize and append onsite Hubbard values of atoms with specific name. :param atom_name: atom name in unitcell :param atom_manifold: atomic manifold (e.g. 3d, 3d-2p) :param value: value of the Hubbard parameter, in eV :param hubbard_type: hubbard type (U, J, ...), defaults to 'Ueff' (see :class:`~aiida_quantumespresso.common.hubbard.Hubbard` for full allowed values) :param use_kinds: whether to use kinds for initializing the parameters; when False, it initializes all the ``Kinds`` matching the ``atom_name`` """ function = self._get_one_kind_index if use_kinds else self._get_symbol_indices atom_indices = function(atom_name) if atom_indices is None: raise ValueError('species or kind names not in structure') for atom_index in atom_indices: args = (atom_index, atom_manifold, atom_index, atom_manifold, value, [0, 0, 0], hubbard_type) self.append_hubbard_parameter(*args)
[docs] def _get_one_kind_index(self, kinds: str) -> List[int]: """Return the first site index matching with `kinds`.""" for i, site in enumerate(self.properties.sites): if site.kind_name == kinds: return [i]
[docs] def _get_symbol_indices(self, symbol: str) -> List[int]: """Return one site index for each kind name matching symbol.""" matching_kinds = [kind for kind, symbols in zip(self.properties.kind_names,self.properties.symbols) if symbol == symbols] return [self.properties.kind_names.index(kind) for kind in matching_kinds]