Source code for wannierberri.formula
import numpy as np
import abc
"""some basic classes to construct formulae for evaluation"""
[docs]class Formula_ln(abc.ABC):
"""
A "Formula" is a ground concept of our calculation. Assume that we have divided
all our Wannierised states into two subspaces, called "inn" and "out".
We call a matrix "covariant" if it is covariant under gauge transformations
inside the "inn" or "out" subspaces but do not intermix them.
A `Formula_ln` object has methods that returns submatrices of the covariant matrix.
"""
@abc.abstractmethod
def __init__(self, data_K, internal_terms=True, external_terms=True, correction_wcc=False, dT_wcc=False):
self.internal_terms = internal_terms
self.external_terms = external_terms
self.correction_wcc = correction_wcc
if self.correction_wcc:
if not (self.external_terms and self.internal_terms):
raise ValueError(
f"correction_wcc makes sense only with all terms, but called with "
f"internal:{self.internal_terms}"
f"external:{self.external_terms}")
self.T_wcc = data_K.covariant('T_wcc')
if dT_wcc:
self.dT_wcc = data_K.covariant('T_wcc', gender=1)
@abc.abstractmethod
def ln(self, ik, inn, out):
"""Returns the submatrix :math:`X_{ln}` at point `ik`, where
:math:`l \in \mathrm{out}` and :math:`n \in \mathrm{inn}`
"""
@abc.abstractmethod
def nn(self, ik, inn, out):
"""Returns the submatrix :math:`X_{nn'}` at point `ik`, where
:math:`n, n' \in \mathrm{inn}`
"""
def nl(self, ik, inn, out):
"""Returns the submatrix :math:`X_{nl}` at point `ik`, where
:math:`l \in \mathrm{out}` and :math:`n \in \mathrm{inn}`
"""
return self.ln(ik, out, inn)
def ll(self, ik, inn, out):
"""Returns the submatrix :math:`X_{ll'}` at point `ik`, whee
:math:`l, l' \in \mathrm{out}`
"""
return self.nn(ik, out, inn)
@property
def additive(self):
""" if Trace_A+Trace_B = Trace_{A+B} holds.
needs override for quantities that do not obey this rule (e.g. Orbital magnetization)
"""
return True
def trace(self, ik, inn, out):
"Returns a trace over the `inn` states"
return np.einsum("nn...->...", self.nn(ik, inn, out)).real
[docs]class Matrix_ln(Formula_ln):
"anything that can be called just as elements of a matrix"
def __init__(self, matrix, TRodd=None, Iodd=None):
self.matrix = matrix
self.ndim = len(matrix.shape) - 3
if TRodd is not None:
self.TRodd = TRodd
if Iodd is not None:
self.Iodd = Iodd
def ln(self, ik, inn, out):
return self.matrix[ik][out][:, inn]
def nn(self, ik, inn, out):
return self.matrix[ik][inn][:, inn]
[docs]class Matrix_GenDer_ln(Formula_ln):
"generalized erivative of MAtrix_ln"
def __init__(self, matrix, matrix_comader, D, TRodd=None, Iodd=None):
self.A = matrix
self.dA = matrix_comader
self.D = D
self.ndim = matrix.ndim + 1
if TRodd is not None:
self.TRodd = TRodd
if Iodd is not None:
self.Iodd = Iodd
def nn(self, ik, inn, out):
summ = self.dA.nn(ik, inn, out)
summ -= np.einsum("mld,lnb...->mnb...d", self.D.nl(ik, inn, out), self.A.ln(ik, inn, out))
summ += np.einsum("mlb...,lnd->mnb...d", self.A.nl(ik, inn, out), self.D.ln(ik, inn, out))
return summ
def ln(self, ik, inn, out):
summ = self.dA.ln(ik, inn, out)
summ -= np.einsum("mld,lnb...->mnb...d", self.D.ln(ik, inn, out), self.A.nn(ik, inn, out))
summ += np.einsum("mlb...,lnd->mnb...d", self.A.ll(ik, inn, out), self.D.ln(ik, inn, out))
return summ
[docs]class FormulaProduct(Formula_ln):
"""a class to store a product of several formulae"""
def __init__(self, formula_list, name="unknown", hermitian=False):
if type(formula_list) not in (list, tuple):
formula_list = [formula_list]
self.TRodd = bool(sum(f.TRodd for f in formula_list) % 2)
self.Iodd = bool(sum(f.Iodd for f in formula_list) % 2)
self.name = name
self.formulae = formula_list
self.hermitian = hermitian
ndim_list = [f.ndim for f in formula_list]
self.ndim = sum(ndim_list)
self.einsumlines = []
letters = "abcdefghijklmnopqrstuvw"
dim = ndim_list[0]
for d in ndim_list[1:]:
self.einsumlines.append("LM" + letters[:dim] + ",MN" + letters[dim:dim + d] + "->LN" + letters[:dim + d])
dim += d
def nn(self, ik, inn, out):
matrices = [frml.nn(ik, inn, out) for frml in self.formulae]
res = matrices[0]
for mat, line in zip(matrices[1:], self.einsumlines):
res = np.einsum(line, res, mat)
if self.hermitian:
res = 0.5 * (res + res.swapaxes(0, 1).conj())
return np.array(res, dtype=complex)
def ln(self, ik, inn, out):
raise NotImplementedError()
from . import covariant
from . import covariant_basic