Strained graphene superlattice#
We showcase the interface between meanfi and Kwant with a strained graphene supercell. In this tutorial, we qualitatively reproduce the results from [1].
We first create the atomistic model in Kwant. The complete source code of this example can be found in strained_graphene_kwant.py. To reduce the computational cost, we perform the calculations with a \(16 \times 16\) supercell whereas in 1 the calculations were performed with a \(25 \times 25\) supercell. Thus, the agreement throughout the tutorial is only qualitative.
We verify the band structure of the Kwant model along a high-symmetry k-path.
h0_builder, lat, k_path = create_system(n=16)
We now use the Kwant model to create the interacting Hamiltonian. Following [1], we consider only onsite interactions.
def func_hop(site1, site2):
return 0 * np.ones((2, 2))
def func_onsite(site, U):
return U * np.ones((2, 2))
int_builder = utils.build_interacting_syst(
h0_builder,
lat,
func_onsite,
func_hop,
max_neighbor=0,
)
After we have created the interacting system we can use MeanFi again for getting the solution. We turn both the non-interacting and interacting systems into tight binding dictionaries using the kwant utils. Then we combine them into a mean-field model.
from meanfi.kwant_helper import utils as utils
h0, data = utils.builder_to_tb(h0_builder, params={"xi": 7}, return_data=True)
params_int = dict(U=0.8)
ndof = [*h0.values()][0].shape[0]
filling = ndof // 2
h_int = utils.builder_to_tb(int_builder, params_int)
mf_model = meanfi.Model(h0, h_int, filling=filling)
Now getting the solution by providing a guess and the mean-field model to the solver. To accelerate the convergence, we use an antiferromagnetic guess.
def func_hop(site1, site2):
return 0 * np.ones((2, 2))
def func_onsite(site):
if site.family == lat.sublattices[0]:
return sz
else:
return -sz
guess_builder = utils.build_interacting_syst(
h0_builder,
lat,
func_onsite,
func_hop,
max_neighbor=0,
)
guess = utils.builder_to_tb(guess_builder)
Due to the large supercell, lwe use a coarse k-point grid. Furthermore, to speed up the calculation we provide additional optimizer_kwargs.
mf_sol = meanfi.solver(
mf_model,
guess,
nk=2,
optimizer_kwargs={
"M": 10,
"f_tol": 1e-4,
"maxiter": 100,
"line_search": "armijo",
},
)
We now verify that the mean-field solution results in a gapped phase.
mf_ham = meanfi.add_tb(h0, mf_sol)
hk_mf = meanfi.tb_to_kfunc(mf_ham)
plot_bands(hk_mf, k_path)
Now we turn the mean-field corrections into a kwant.Builder such that we can visualize observables using Kwant’s functionalities. We provide the mean-field solution mf_sol as well as the sites and periods of the bulk system to the tb_to_builder function.
mf_sol_builder = utils.tb_to_builder(mf_sol, data["sites"], data["periods"])
We now plot the magnetization of the system. First, we define the magnetization direction. We do extracting the exchange field at it site and finding the direction where all the spins are pointing to.
exchange_field = np.array([value[1] for value in list(mf_sol_builder.site_value_pairs())])
magnetization_direction = np.zeros(3)
for i, sigma in enumerate(sigmas):
for site_field in exchange_field:
magnetization_direction[i] += np.abs(np.trace(sigma @ site_field))
magnetization_direction /= np.linalg.norm(magnetization_direction)
reference_magnetization = np.transpose(sigmas, (1, 2, 0)) @ magnetization_direction
Now we plot the magnetization of the solution on the sites of the system. We do this by creating functions which calculate the magnetization and its magnitude with respect to the reference magnetization direction.
def magnetisation(site):
matrix = mf_sol_builder.H[site][1]
return np.trace(reference_magnetization @ matrix).real
def abs_magnetisation(site):
matrix = mf_sol_builder.H[site][1]
projected_magnetization = []
for sigma in sigmas[1:]:
projected_magnetization.append(np.trace(sigma @ matrix))
return np.sqrt(np.sum(np.array(projected_magnetization) ** 2).real)
def systemPlotter(syst, onsite, ax, cmap):
"""
Plots the system with the onsite potential given by the function onsite.
"""
sites = [*syst.sites()]
density = [onsite(site) for site in sites]
def size(site):
return 0.3 * np.abs(onsite(site)) / np.max(np.abs(density))
kwant.plot(
syst, site_color=onsite, ax=ax, cmap=cmap, site_size=size, show=False, unit=1
)
return np.min(density), np.max(density)
/home/docs/checkouts/readthedocs.org/user_builds/meanfi/conda/latest/lib/python3.11/site-packages/kwant/_plotter.py:77: RuntimeWarning: plotly is not available, if other engines are unavailable, only iterator-providing functions will work
warnings.warn("plotly is not available, if other engines are unavailable,"