Source code for meanfi.kwant_helper.utils
from itertools import product
from collections import defaultdict
from typing import Callable, Optional
import inspect
import numpy as np
import kwant
from kwant.builder import Site
import kwant.lattice
import kwant.builder
from meanfi.tb.tb import _tb_type
[docs]
def builder_to_tb(
builder: kwant.builder.Builder, params: dict = {}, return_data: bool = False
) -> _tb_type:
"""Construct a tight-binding dictionary from a `kwant.builder.Builder` system.
Parameters
----------
builder :
system to convert to tight-binding dictionary.
params :
Dictionary of parameters to evaluate the builder on.
return_data :
Returns dictionary with sites and number of orbitals per site.
Returns
-------
:
Tight-binding dictionary that corresponds to the builder.
:
Data with sites and number of orbitals. Only if `return_data=True`.
"""
prim_vecs = builder.symmetry.periods
dims = len(prim_vecs)
idx_by_site = {site: idx for idx, site in enumerate(builder.sites())}
norbs_list = [site.family.norbs for site in builder.sites()]
if any(norbs is None for norbs in norbs_list):
raise ValueError("Number of orbitals must be specified for all sites.")
offsets = np.cumsum([0] + norbs_list)
tb_norbs = sum(norbs_list)
tb_shape = (tb_norbs, tb_norbs)
onsite_idx = tuple([0] * dims)
h_0 = defaultdict(lambda: np.zeros(tb_shape, dtype=complex))
onsite = h_0[onsite_idx]
for site, val in builder.site_value_pairs():
if callable(val):
param_keys = inspect.getfullargspec(val).args[1:]
try:
val = val(site, *[params[key] for key in param_keys])
except KeyError as key:
raise KeyError(f"Parameter {key} not found in params.")
site_idx = idx_by_site[site]
onsite[
offsets[site_idx] : offsets[site_idx + 1],
offsets[site_idx] : offsets[site_idx + 1],
] = val
for (site1, site2), val in builder.hopping_value_pairs():
if callable(val):
param_keys = inspect.getfullargspec(val).args[2:]
try:
val = val(site1, site2, *[params[key] for key in param_keys])
except KeyError as key:
raise KeyError(f"Parameter {key} not found in params.")
site2_dom = builder.symmetry.which(site2)
site2_fd = builder.symmetry.to_fd(site2)
site1_idx, site2_idx = [idx_by_site[site1], idx_by_site[site2_fd]]
to_slice, from_slice = [
slice(offsets[idx], offsets[idx + 1]) for idx in [site1_idx, site2_idx]
]
h_0[site2_dom][to_slice, from_slice] = val
h_0[-site2_dom][from_slice, to_slice] = val.T.conj()
if return_data:
data = {}
data["periods"] = prim_vecs
data["sites"] = list(idx_by_site.keys())
return h_0, data
else:
return h_0
[docs]
def tb_to_builder(
h_0: _tb_type, sites_list: list[Site, ...], periods: np.ndarray
) -> kwant.builder.Builder:
"""
Construct a `kwant.builder.Builder` from a tight-binding dictionary.
Parameters
----------
h_0 :
Tight-binding dictionary.
sites_list :
List of sites in the builder's unit cell.
periods :
2d array with periods of the translational symmetry.
Returns
-------
:
`kwant.builder.Builder` that corresponds to the tight-binding dictionary.
"""
if periods == ():
builder = kwant.Builder()
else:
builder = kwant.Builder(kwant.TranslationalSymmetry(*periods))
onsite_idx = tuple([0] * len(list(h_0)[0]))
norbs_list = [site.family.norbs for site in sites_list]
norbs_list = [1 if norbs is None else norbs for norbs in norbs_list]
def site_to_tbIdxs(site):
site_idx = sites_list.index(site)
return (np.sum(norbs_list[:site_idx]) + range(norbs_list[site_idx])).astype(int)
# assemble the sites first
for site in sites_list:
tb_idxs = site_to_tbIdxs(site)
value = h_0[onsite_idx][
tb_idxs[0] : tb_idxs[-1] + 1, tb_idxs[0] : tb_idxs[-1] + 1
]
builder[site] = value
# connect hoppings within the unit-cell
for site1, site2 in product(sites_list, sites_list):
if site1 == site2:
continue
tb_idxs1 = site_to_tbIdxs(site1)
tb_idxs2 = site_to_tbIdxs(site2)
value = h_0[onsite_idx][
tb_idxs1[0] : tb_idxs1[-1] + 1, tb_idxs2[0] : tb_idxs2[-1] + 1
]
if np.all(value == 0):
continue
builder[(site1, site2)] = value
# connect hoppings between unit-cells
for key in h_0:
if key == onsite_idx:
continue
for site1, site2_fd in product(sites_list, sites_list):
site2 = builder.symmetry.act(key, site2_fd)
tb_idxs1 = site_to_tbIdxs(site1)
tb_idxs2 = site_to_tbIdxs(site2_fd)
value = h_0[key][
tb_idxs1[0] : tb_idxs1[-1] + 1, tb_idxs2[0] : tb_idxs2[-1] + 1
]
if np.all(value == 0):
continue
builder[(site1, site2)] = value
return builder
[docs]
def build_interacting_syst(
builder: kwant.builder.Builder,
lattice: kwant.lattice.Polyatomic,
func_onsite: Callable,
func_hop: Optional[Callable] = None,
max_neighbor: int = 1,
) -> kwant.builder.Builder:
"""
Construct an auxiliary `kwant` system that encodes the interactions.
Parameters
----------
builder :
Non-interacting `kwant.builder.Builder` system.
lattice :
Lattice of the system.
func_onsite :
Onsite interactions function.
func_hop :
Hopping/inter unit cell interactions function.
max_neighbor :
The maximal number of neighbouring unit cells (along a lattice vector)
connected by interaction. Interaction goes to zero after this distance.
Returns
-------
:
Auxiliary `kwant.builder.Builder` that encodes the interactions of the system.
"""
int_builder = kwant.builder.Builder(
kwant.lattice.TranslationalSymmetry(*builder.symmetry.periods)
)
int_builder[builder.sites()] = func_onsite
if func_hop is not None:
for neighbors in range(max_neighbor):
int_builder[lattice.neighbors(neighbors + 1)] = func_hop
return int_builder