# -*- coding: utf-8 -*-
"""Utility class and functions for HubbardStructureData."""
# pylint: disable=no-name-in-module, invalid-name
from typing import List, Literal, Tuple
from pydantic import BaseModel, conint, constr, field_validator
__all__ = ('HubbardParameters', 'Hubbard')
[docs]class HubbardParameters(BaseModel):
"""Class for describing onsite and intersite Hubbard interaction parameters.
.. note: allowed manifold formats are:
* {N}{L} (2 characters)
* {N1}{L1}-{N2}{L2} (5 characters)
N = quantum number (1,2,3,...); L = orbital letter (s,p,d,f,g,h)
"""
[docs] atom_index: conint(strict=True, ge=0)
"""Atom index in the abstract structure."""
[docs] atom_manifold: constr(strip_whitespace=True, to_lower=True, min_length=2, max_length=5)
"""Atom manifold (syntax is `3d`, `3d-2p`)."""
[docs] neighbour_index: conint(strict=True, ge=0)
"""Neighbour index in the abstract structure."""
[docs] neighbour_manifold: constr(strip_whitespace=True, to_lower=True, min_length=2, max_length=5)
"""Atom manifold (syntax is `3d`, `3d-2p`)."""
[docs] translation: Tuple[conint(strict=True), conint(strict=True), conint(strict=True)]
"""Translation vector referring to the neighbour atom, (3,) shape list of ints."""
"""Value of the Hubbard parameter, expessed in eV."""
[docs] hubbard_type: Literal['Ueff', 'U', 'V', 'J', 'B', 'E2', 'E3']
"""Type of the Hubbard parameters used (`Ueff`, `U`, `V`, `J`, `B`, `E2`, `E3`)."""
@field_validator('atom_manifold', 'neighbour_manifold') # cls is mandatory to use
[docs] def check_manifolds(cls, value): # pylint: disable=no-self-argument, no-self-use
"""Check the validity of the manifold input.
Allowed formats are:
* {N}{L} (2 characters)
* {N1}{L1}-{N2}{L2} (5 characters)
N = quantum number (1,2,3,...); L = orbital letter (s,p,d,f,g,h)
"""
length = len(value)
if length not in [2, 5]:
raise ValueError(f'invalid length ``{length}``. Only 2 or 5.')
if length == 2:
if not value[0] in [str(_ + 1) for _ in range(6)]:
raise ValueError(f'invalid quantum number {value[0]}')
if not value[1] in ['s', 'p', 'd', 'f', 'h']:
raise ValueError(f'invalid manifold symbol {value[1]}')
if length == 5:
if not value[2] == '-':
raise ValueError(f'the separator {value[0]} is not allowed. Only `-`')
if not value[3] in [str(_ + 1) for _ in range(6)]:
raise ValueError(f'the quantum number {value[0]} is not correct')
if not value[4] in ['s', 'p', 'd', 'f', 'h']:
raise ValueError(f'the manifold number {value[1]} is not correct')
return value
[docs] def to_tuple(self) -> Tuple[int, str, int, str, float, Tuple[int, int, int], str]:
"""Return the parameters as a tuple.
The parameters have the following order:
* atom_index
* atom_manifold
* neighbour_index
* neighbour_manifold
* value
* translationr
* hubbard_type
"""
return (
self.atom_index, self.atom_manifold, self.neighbour_index, self.neighbour_manifold, self.value,
self.translation, self.hubbard_type
)
@staticmethod
[docs] def from_tuple(hubbard_parameters: Tuple[int, str, int, str, float, Tuple[int, int, int], str]):
"""Return a ``HubbardParameters`` instance from a list.
The parameters within the list must have the following order:
* atom_index
* atom_manifold
* neighbour_index
* neighbour_manifold
* value
* translation
* hubbard_type
"""
keys = [
'atom_index',
'atom_manifold',
'neighbour_index',
'neighbour_manifold',
'value',
'translation',
'hubbard_type',
]
return HubbardParameters(**dict(zip(keys, hubbard_parameters)))
[docs]class Hubbard(BaseModel):
"""Class for complete description of Hubbard interactions."""
[docs] parameters: List[HubbardParameters]
"""List of :class:`~aiida_quantumespresso.common.hubbard.HubbardParameters`."""
[docs] projectors: Literal['atomic',
'ortho-atomic',
'norm-atomic',
'wannier-functions',
'pseudo-potentials',
] = 'ortho-atomic'
"""Name of the projectors used. Allowed values are:
'atomic', 'ortho-atomic', 'norm-atomic', 'wannier-functions', 'pseudo-potentials'."""
"""Hubbard formulation used. Allowed values are: 'dudarev', `liechtenstein`."""
[docs] def to_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.parameters]
@staticmethod
[docs] def 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]
return Hubbard(parameters=parameters, projectors=projectors, formulation=formulation)