DMFT self consistent framework

This is a small framework for doing self consistent DMFT calculations for the Hubbard model on the square lattice using the triqs_cthyb impurity solver. The framework is based on the TPRF helper class ParameterCollection that makes it easier to keep the results of a calculation in a single object that can be stored and passed as argument.

A script performing a self consisten calculation using the framework takes the form

from common import *

p = ParameterCollection(
    t = 1.,
    B = 0.,
    U = 10.,
    mu = 0.,
    n_k = 16,
    n_iter = 10,
    G_l_tol = 1e-5,
    )

p.solve = ParameterCollection(
    length_cycle = 10,
    n_warmup_cycles = 10000,
    n_cycles = int(8e6),
    move_double = False,
    measure_G_l = True,
    )

p.init = ParameterCollection(
    beta = 1.,
    n_l = 10,
    n_iw = 400,
    n_tau = 4000,
    gf_struct = [('up',[0]), ('do',[0])])

p0 = setup_dmft_calculation(p)
ps = solve_self_consistent_dmft(p0)

if mpi.is_master_node():
    with HDFArchive('data_sc.h5', 'w') as a:
        a['ps'] = ParameterCollections(ps)

where the framework is used to setup the calcuation by calling the function setup_dmft_calculation and the self consistent solution i obtained by calling solve_self_consistent_dmft. For details on these function please se next section.

The result is the self consistent DMFT solution of the system, plotted below.

../../_images/figure_sc.svg

The visulaization script is available here: plot_sc.py.

Implementation details

The above script uses the common.py python module, available for download here: common.py. This section goes through the details of the routines in the module.

The common.py module includes ther modules from TRIQS, triqs_cthyb, and TPRF, etc..

import copy
import glob
import numpy as np

import triqs.utility.mpi as mpi
from h5 import HDFArchive
from triqs.gf import Gf, MeshImFreq, Fourier, LegendreToMatsubara, BlockGf, inverse, Idx

import triqs_cthyb

from triqs_tprf.lattice import lattice_dyson_g_w
from triqs_tprf.ParameterCollection import ParameterCollection
from triqs_tprf.ParameterCollection import ParameterCollections
from triqs_tprf.utilities import BlockGf_data

Setup DMFT Calculation

The function setup_dmft_calculation takes a ParameterCollection as input and constructs

  • the local interaction \(H_{\textrm{int}} = Un_\uparrow n_\downarrow - \frac{U}{2} (n_\uparrow + n_\downarrow)\) in p.solve.h_int,

  • the lattice dispersion \(\epsilon_{\mathbf{k}}\) in p.e_k, and

  • the initial (zero) guess for the self-energy \(\Sigma\) in p.sigma_w.

def setup_dmft_calculation(p):

    p = copy.deepcopy(p)
    p.iter = 0

    # -- Local Hubbard interaction
    from triqs.operators import n
    p.solve.h_int = p.U*n('up', 0)*n('do', 0) - 0.5*p.U*(n('up', 0) + n('do', 0))

    # -- 2D square lattice w. nearest neighbour hopping t
    from triqs_tprf.tight_binding import TBLattice
    T = -p.t * np.eye(2)
    H = TBLattice(
        units = [(1, 0, 0), (0, 1, 0)],
        orbital_positions = [(0,0,0)]*2,
        orbital_names = ['up', 'do'],
        hopping = {(0, +1) : T, (0, -1) : T, (+1, 0) : T, (-1, 0) : T})
    
    kmesh = H.get_kmesh(n_k = (p.n_k, p.n_k, 1))
    p.e_k = H.fourier(kmesh)

    # -- Initial zero guess for the self-energy    
    p.sigma_w = Gf(mesh=MeshImFreq(p.init.beta(), 'Fermion', p.init.n_iw), target_shape=[2, 2])
    p.sigma_w.zero()

Solve Self-Consistent DMFT

The function solve_self_consistent_dmft repeatedly runs the DMFT self consistency step and looks for convergence in the local Legendre Green’s function \(G_l\).


def solve_self_consistent_dmft(p):

    ps = []
    for dmft_iter in range(p.n_iter):
        mpi.report('--> DMFT Iteration: {:d}'.format(p.iter))
        p = dmft_self_consistent_step(p)
        ps.append(p)
        mpi.report('--> DMFT Convergence: dG_l = {:f}'.format(p.dG_l))
        if p.dG_l < p.G_l_tol: break

    if dmft_iter >= p.n_iter - 1: mpi.report('--> Warning: DMFT Not converged!')
    else: mpi.report('--> DMFT Converged: dG_l = {:f}'.format(p.dG_l))

DMFT Self-Consistent Step

The function dmft_self_consistent_step performs a complete DMFT step starting from the given self-energy \(\Sigma\) it takes the steps,

  • compute the lattice local Green’s function \(g(i\omega_n)\) in p.g_w

  • compute the local Weiss field \(g_0(i\omega_n) = [ g^{-1} + \Sigma ]^{-1}\) in p.g0_w

  • setup the triqs_cthyb solver

  • set the Weiss field of the solver in cthyb.G0_iw from the lattice p.g0_w.

  • run the triqs_cthyb solver and sample the Legendre Green’s function \(G_l\) in p.G_l

  • compute a new self energy \(\Sigma\) from the sampled Greens function p.G_l and Weiss field p.G0_w

  • set the lattice self energy p.sigma_w from the impurity self energy p.Sigma_w


def dmft_self_consistent_step(p):

    p = copy.deepcopy(p)
    p.iter += 1

    p.g_w = lattice_dyson_g_w(p.mu, p.e_k, p.sigma_w - np.diag([p.B, -p.B]))
    p.g0_w = p.g_w.copy()
    p.g0_w << inverse(inverse(p.g_w) + p.sigma_w)

    cthyb = triqs_cthyb.Solver(**p.init.dict())

    # -- set impurity from lattice
    cthyb.G0_iw['up'][0, 0] << p.g0_w[0, 0]
    cthyb.G0_iw['do'][0, 0] << p.g0_w[1, 1]

    cthyb.solve(**p.solve.dict())

    p.dG_l = np.max(np.abs(BlockGf_data(cthyb.G_l-p.G_l))) if hasattr(p,'G_l') else float('nan')
    p.G_l = cthyb.G_l

    p.G_tau, p.G_tau_raw = cthyb.G_tau.copy(), cthyb.G_tau.copy()
    p.G0_w, p.G_w, p.Sigma_w = cthyb.G0_iw.copy(), cthyb.G0_iw.copy(), cthyb.G0_iw.copy()

    p.G_tau << LegendreToMatsubara(p.G_l)
    p.G_w << Fourier(p.G_tau)
    p.Sigma_w << inverse(p.G0_w) - inverse(p.G_w)

    # -- set lattice from impurity
    p.sigma_w[0, 0] << p.Sigma_w['up'][0, 0]
    p.sigma_w[1, 1] << p.Sigma_w['do'][0, 0]

    # -- local observables
    p.rho = p.g_w.density()
    M_old = p.M if hasattr(p, 'M') else float('nan')
    p.M = 0.5*(p.rho[0, 0] - p.rho[1, 1])
    p.dM = np.abs(p.M - M_old)