import numpy as np
from ..utility import alpha_A, beta_A
from .formula import Formula_ln
from .covariant import DerDcov, Eavln
from ..symmetry.point_symmetry import transform_ident, transform_odd
""" The following Formulue are fundamental. They can be used to construct all
quantities relatred to Berry curvature and orbital magnetic moment. They are written
in the most explicit form, although probably not the most efecient.
Foe practical reasons more eficient formulae may be constructed (e.g. by excluding
some terms that cancel out). However, the following may be used as benchmark.
"""
########################
# Berry curvature #
########################
[docs]
class tildeFab(Formula_ln):
def __init__(self, data_K, **parameters):
super().__init__(data_K, **parameters)
self.D = data_K.Dcov
# print (f"tildeFab evaluating: internal({self.internal_terms}) and external({self.external_terms})")
if self.external_terms:
self.A = data_K.covariant('AA')
self.V = data_K.covariant('Ham', gender=1)
self.F = data_K.covariant('FF')
self.ndim = 2
# self.Iodd=False
# self.TRodd=True
[docs]
def nn(self, ik, inn, out):
summ = np.zeros((len(inn), len(inn), 3, 3), dtype=complex)
Dnl = self.D.nl(ik, inn, out)
Dln = self.D.ln(ik, inn, out)
if self.internal_terms:
summ += -np.einsum("mla,lnb->mnab", Dnl, Dln)
if self.external_terms:
summ += self.F.nn(ik, inn, out)
summ += 2j * np.einsum("mla,lnb->mnab", Dnl, self.A.ln(ik, inn, out))
# summ += 1j * np.einsum("mla,lnb->mnab", self.A.nl (ik,inn,out),Dln )
summ += -1 * np.einsum("mla,lnb->mnab", self.A.nn(ik, inn, out), self.A.nn(ik, inn, out))
summ = 0.5 * (summ + summ.transpose((1, 0, 3, 2)).conj())
return summ
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
########################
# derivative of #
# Berry curvature #
########################
[docs]
class tildeFab_d(Formula_ln):
def __init__(self, data_K, **parameters):
super().__init__(data_K, **parameters)
self.dD = DerDcov(data_K)
self.D = data_K.Dcov
# print (f"derOmega evaluating: internal({self.internal_terms}) and external({self.external_terms})")
if self.external_terms:
self.A = data_K.covariant('AA')
self.dA = data_K.covariant('AA', gender=1)
self.dF = data_K.covariant('FF', gender=1)
self.ndim = 3
# self.Iodd=True
# self.TRodd=False
[docs]
def nn(self, ik, inn, out):
summ = np.zeros((len(inn), len(inn), 3, 3, 3), dtype=complex)
Dnl = self.D.nl(ik, inn, out)
dDln = self.dD.ln(ik, inn, out)
if self.internal_terms:
summ += -2 * np.einsum("mla,lnbd->mnabd", Dnl, dDln)
if self.external_terms:
summ += self.dF.nn(ik, inn, out)
summ += 2j * np.einsum("mla,lnbd->mnabd", Dnl, self.dA.ln(ik, inn, out))
summ += 2j * np.einsum("mla,lnbd->mnabd", self.A.nl(ik, inn, out), dDln)
summ += -2 * np.einsum("mla,lnbd->mnabd", self.A.nn(ik, inn, out), self.dA.nn(ik, inn, out))
# Terms (a<->b, m<-n> )* are accounted above by factor 2
summ = 0.5 * (summ + summ.transpose((1, 0, 3, 2, 4)).conj())
return summ
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
###############################################################
# tildeHab = <\tilde\partial_a u | H |\tilde\partial_b u> #
###############################################################
[docs]
class tildeHab(Formula_ln):
def __init__(self, data_K, **parameters):
super().__init__(data_K, **parameters)
if self.external_terms:
self.A = data_K.covariant('AA')
self.B = data_K.covariant('BB')
self.H = data_K.covariant('CCab')
self.D = data_K.Dcov
self.E = data_K.E_K
self.ndim = 2
self.transformTR = transform_odd
self.transformInv = transform_ident
@property
def additive(self):
return False
[docs]
def nn(self, ik, inn, out):
summ = np.zeros((len(inn), len(inn), 3, 3), dtype=complex)
if self.internal_terms:
summ += -np.einsum(
"mla,lnb->mnab",
self.D.nl(ik, inn, out) * self.E[ik][out][None, :, None], self.D.ln(ik, inn, out))
if self.external_terms:
summ += self.H.nn(ik, inn, out)
summ += 2j * np.einsum("mla,lnb->mnab", self.D.nl(ik, inn, out), self.B.ln(ik, inn, out))
summ += -np.einsum(
"mla,lnb->mnab",
self.A.nn(ik, inn, out) * self.E[ik][inn][None, :, None], self.A.nn(ik, inn, out))
summ = 0.5 * (summ + summ.transpose((1, 0, 3, 2)).conj())
return summ
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
[docs]
class tildeHGab(Formula_ln):
def __init__(self, data_K, sign=+1, **parameters):
self.F = tildeFab(data_K, **parameters)
self.H = tildeHab(data_K, **parameters)
self.E = Eavln(data_K)
self.sign = sign
self.ndim = 2
@property
def additive(self):
return False
[docs]
def nn(self, ik, inn, out):
return self.H.nn(ik, inn, out) + self.sign * self.E.nn(ik, inn, out)[:, :, None, None] * self.F.nn(ik, inn, out)
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
##################################################################################
# tildeHab:d = \tilde\partial_d <\tilde\partial_a u | H |\tilde\partial_b u> #
##################################################################################
[docs]
class tildeHab_d(Formula_ln):
def __init__(self, data_K, **parameters):
super().__init__(data_K, **parameters)
self.dD = DerDcov(data_K)
self.D = data_K.Dcov
self.V = data_K.covariant('Ham', gender=1)
self.E = data_K.E_K
if self.external_terms:
self.A = data_K.covariant('AA')
self.dA = data_K.covariant('AA', gender=1)
self.B = data_K.covariant('BB')
self.dB = data_K.covariant('BB', gender=1)
self.dH = data_K.covariant('CCab', gender=1)
self.ndim = 2
self.transformTR = transform_ident
self.transformInv = transform_odd
[docs]
def nn(self, ik, inn, out):
summ = np.zeros((len(inn), len(inn), 3, 3, 3), dtype=complex)
if self.internal_terms:
summ += -1 * np.einsum(
"mpa,pld,lnb->mnabd", self.D.nl(ik, inn, out), self.V.ll(ik, inn, out), self.D.ln(ik, inn, out))
summ += -2 * np.einsum(
"mla,lnbd->mnabd",
self.D.nl(ik, inn, out) * self.E[ik][out][None, :, None], self.dD.ln(ik, inn, out))
if self.external_terms:
summ += self.dH.nn(ik, inn, out)
summ += -np.einsum(
"mpa,pld,lnb->mnabd", self.A.nn(ik, inn, out), self.V.nn(ik, inn, out), self.A.nn(ik, inn, out))
summ += -2 * np.einsum(
"mla,lnbd->mnabd",
self.A.nn(ik, inn, out) * self.E[ik][inn][None, :, None], self.dA.nn(ik, inn, out))
summ += 2j * np.einsum("mla,lnbd->mnabd", self.D.nl(ik, inn, out), self.dB.ln(ik, inn, out))
summ += 2j * np.einsum("lma,lnbd->mnabd", (self.B.ln(ik, inn, out)).conj(), self.dD.ln(ik, inn, out))
summ = 0.5 * (summ + summ.transpose((1, 0, 3, 2, 4)).conj())
return summ
@property
def additive(self):
return False
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
[docs]
class tildeHGab_d(Formula_ln):
def __init__(self, data_K, sign=+1, **parameters):
self.F = tildeFab(data_K, **parameters)
self.dF = tildeFab_d(data_K, **parameters)
self.dH = tildeHab_d(data_K, **parameters)
self.E = Eavln(data_K)
self.V = data_K.covariant('Ham', gender=1)
self.sign = sign
self.ndim = 3
@property
def additive(self):
return False
[docs]
def nn(self, ik, inn, out):
res = self.dH.nn(ik, inn, out)
if self.sign != 0:
res += self.sign * self.E.nn(ik, inn, out)[:, :, None, None, None] * self.dF.nn(ik, inn, out)
res += 0.5 * self.sign * np.einsum("mpab,pnd->mnabd", self.F.nn(ik, inn, out), self.V.nn(ik, inn, out))
res += 0.5 * self.sign * np.einsum("mpd,pnab->mnabd", self.V.nn(ik, inn, out), self.F.nn(ik, inn, out))
return res
[docs]
def ln(self, ik, inn, out):
raise NotImplementedError()
###################################################
# Now define their anitsymmetric combinations #
###################################################
[docs]
class AntiSymmetric(Formula_ln):
def __init__(self, full, data_K, **parameters):
self.full = full(data_K, **parameters)
self.ndim = self.full.ndim - 1
[docs]
def nn(self, ik, inn, out):
fab = self.full.nn(ik, inn, out)
return 1j * (fab[:, :, alpha_A, beta_A] - fab[:, :, beta_A, alpha_A])
[docs]
def ln(self, ik, inn, out):
fab = self.full.ln(ik, inn, out)
return 1j * (fab[:, :, alpha_A, beta_A] - fab[:, :, beta_A, alpha_A])
[docs]
class Symmetric(Formula_ln):
def __init__(self, full, data_K, axes=[0, 1], **parameters):
self.full = full(data_K, **parameters)
self.ndim = self.full.ndim
self.axes = axes
[docs]
def nn(self, ik, inn, out):
fab = self.full.nn(ik, inn, out)
return fab + fab.swapaxes(self.axes[0] + 2, self.axes[1] + 2)
[docs]
def ln(self, ik, inn, out):
fab = self.full.nn(ik, inn, out)
return fab + fab.swapaxes(self.axes[0] + 2, self.axes[1] + 2)
[docs]
class tildeFc(AntiSymmetric):
def __init__(self, data_K, **parameters):
super().__init__(tildeFab, data_K, **parameters)
self.transformTR = transform_odd
self.transformInv = transform_ident
[docs]
class tildeHGc(AntiSymmetric):
def __init__(self, data_K, **parameters):
super().__init__(tildeHGab, data_K, **parameters)
self.transformTR = transform_odd
self.transformInv = transform_ident
@property
def additive(self):
return False
[docs]
class tildeFc_d(AntiSymmetric):
def __init__(self, data_K, **parameters):
super().__init__(tildeFab_d, data_K, **parameters)
self.transformTR = transform_ident
self.transformInv = transform_odd
[docs]
class tildeHGc_d(AntiSymmetric):
def __init__(self, data_K, **parameters):
super().__init__(tildeHGab_d, data_K, **parameters)
self.transformTR = transform_ident
self.transformInv = transform_odd
@property
def additive(self):
return False
# derivative of band orbital moment
[docs]
class Der_morb(tildeHGc_d):
def __init__(self, data_K, **parameters):
super().__init__(data_K, sign=-1, **parameters)