示例#1
0
def matsubara_frequencies(n_points, beta) -> xr.DataArray:
    iws = xr.DataArray(gt.matsubara_frequencies(n_points, beta=beta),
                       dims=[Dim.iws], coords=[n_points])
    iws.name = 'iω_n'
    iws.attrs['description'] = 'fermionic Matsubara frequencies'
    iws.attrs['temperature'] = 1/beta
    return iws
示例#2
0
def curr_acorr_n1_iv(prm: Hubbard_Parameters, self_iw, occ, N_iv: int):
    """Calculate bosonic Matsubara current-current correlation function.

    Parameters
    ----------
    prm : Hubbard_Parameters
        The model.
    self_iw : (N_sp, N_l=1, N_iw) complex np.ndarray
        The local self-energy, for non-negative Matsubaras `iws.imag > 0`.
    occ : (N_sp, N_l=1) float np.ndarray
        Occupation number, needed to perform Matsubara sum corrections.
    N_iv : int
        Number of bosonic Matsubaras to calculate. Must be non-negative,
        only non-negative Matsubaras will be calculated.

    Returns
    -------
    curr_acorr_n1_iv : (N_sp, 1, N_iv) complex np.ndarray
        The current-current correlation function.

    """
    assert prm.N_l == 1
    assert occ.shape == self_iw.shape[:
                                      -1], "Shape mismatch of occupation and self-energy."
    N_iw = self_iw.shape[-1]
    # we need sum over positive and negative Matsubaras
    self_iw = np.concatenate((self_iw[..., ::-1].conj(), self_iw), axis=-1)
    iws = gt.matsubara_frequencies(range(-N_iw, N_iw), beta=prm.beta)
    assert model.rev_dict_hilbert_transfrom[prm.hilbert_transform] == 'bethe', \
        "Only Bethe lattice derivative implemented."
    gf_iw = prm.gf_dmft_s(iws, self_iw)
    xi_iw = (iws + prm.onsite_energy() - self_iw)
    # we assume as symmetric density of states, thus that ϵ^{(0)} = 0
    xi0 = prm.onsite_energy(hartree=occ[::-1])
    xi0_iw_inv = 1. / (iws + xi0)
    gf_d1_iw = gt.bethe_gf_d1_omega(xi_iw, half_bandwidth=prm.D)

    def p_iv(n_b):
        # there is no `-0` so we have to treat that separately
        lmsk = Ellipsis, slice(None, -n_b if n_b != 0 else None)
        rmsk = Ellipsis, slice(n_b, None)
        d_xi_iw = xi_iw[lmsk] - xi_iw[rmsk]
        small_limit = abs(d_xi_iw) < 1e-8
        # only very few elements should be `small_limit` so we don't care about overhead
        res = gf_iw[lmsk] - gf_iw[rmsk]
        res[~small_limit] /= d_xi_iw[~small_limit]
        # symmetric, just in case
        res[small_limit] = .5 * (gf_d1_iw[lmsk][small_limit] +
                                 gf_d1_iw[rmsk][small_limit])
        # Matsubara sum corrections
        delta_sum = prm.T * np.sum(res + xi0_iw_inv[lmsk] * xi0_iw_inv[rmsk],
                                   axis=-1)
        if n_b == 0:  # only relevant near half filling to have corrections
            return delta_sum - gt.fermi_fct_d1(xi0, beta=prm.beta)
        return delta_sum  # for N_l == 1 there are only corrections to iν_0

    return np.moveaxis(np.array([p_iv(n_b) for n_b in range(N_iv)]), 0, -1)
示例#3
0
def test_2x2_matrix():
    """Compare with analytic inversion of (2, 2) matrix.

    Done for the 1D chain of sites.
    """
    prm = model.Hubbard_Parameters(2, lattice='chain')

    def gf_2x2(omega, t_mat, onsite_energys):
        assert np.all(np.diag(t_mat) == 0.), \
            "No diagonal elements for t_mat allowed"
        assert t_mat.shape == (2, 2)
        assert onsite_energys.shape == (2, )
        diag = omega + onsite_energys
        norm = 1. / (np.prod(diag) - t_mat[0, 1] * t_mat[1, 0])
        gf = np.zeros_like(t_mat, dtype=np.complex)
        gf[0, 0] = diag[1]
        gf[1, 1] = diag[0]
        gf[0, 1] = -t_mat[0, 1]
        gf[1, 0] = -t_mat[1, 0]
        return norm * gf

    prm.T = 0.0137
    prm.t_mat = np.zeros((2, 2))
    prm.t_mat[0, 1] = prm.t_mat[1, 0] = 1.3
    prm.mu = np.array([0, 1.73])
    prm.h = np.array([0, -0.3])
    prm.D = None
    prm.assert_valid()

    omegas = gt.matsubara_frequencies(np.arange(100), prm.beta)
    gf_prm = prm.gf0(omegas, diagonal=False)
    e_onsite = prm.onsite_energy()
    gf_2x2_up = np.array([
        gf_2x2(iw, prm.t_mat,
               e_onsite.sel({
                   Dim.sp: 'up'
               }).values) for iw in omegas
    ])
    gf_2x2_up = gf_2x2_up.transpose(1, 2,
                                    0)  # adjuste axis order (2, 2, omegas)
    assert np.allclose(gf_2x2_up, gf_prm.sel({Dim.sp: 'up'}))
    gf_2x2_dn = np.array([
        gf_2x2(iw, prm.t_mat,
               e_onsite.sel({
                   Dim.sp: 'dn'
               }).values) for iw in omegas
    ])
    gf_2x2_dn = gf_2x2_dn.transpose(1, 2,
                                    0)  # adjuste axis order (2, 2, omegas)
    assert np.allclose(gf_2x2_dn, gf_prm.sel({Dim.sp: 'dn'}))
示例#4
0
def fit_iw_tail(gf_iw, beta, order) -> FourierFct:
    """Fit the tail of `gf_iw` with function behaving as (iw)^{-`order`}.

    Parameters
    ----------
    gf_iw : (..., N_iw) complex np.ndarray
        The function at **fermionic** Matsubara frequencies.
    beta : float
        The inverse temperature `beta` = 1/T.
    order : int
        Leading order of the high-frequency behavior of the tail.

    Returns
    -------
    fit_iw_tail.iw : (..., N_iw) complex np.ndarray
        The tail fit for the same frequencies as `gf_iw`.
    fit_iw_tail.tau : (..., 2*N_iw + 1) float np.ndarray
        The Fourier transform of the tail for τ ∈ [0, β].

    Raises
    ------
    RuntimeError
        If the Fourier transform of the tail contains `np.nan`. This should be
        fixed and never occur. It indicates a overflow in `get_gf_from_moments()`.

    """
    N_iw = gf_iw.shape[-1]
    odd = order % 2
    # CC = 2.*order  # shift to make the function small for low frequencies
    CC = 0.
    iws = gt.matsubara_frequencies(np.arange(N_iw), beta=beta)
    tau = np.linspace(0, beta, num=2*N_iw + 1, endpoint=True)

    def to_float(number):
        # scipy only handles np.float64
        return (number.imag if odd else number.real).astype(np.float64)

    norm_tail_iw = .5 * ((iws + CC)**-order + (iws - CC)**-order)  # tail with amplitude 1
    sigma = to_float(iws**(-order-2))  # next order correction that is odd/even

    moment, err = _fitting(iws.imag, fit_iw=to_float(norm_tail_iw),
                           gf_iw=to_float(gf_iw), sigma=sigma)
    LOGGER.info('Amplitude of fit (order %s): %s ± %s', order, moment, err)
    moment = moment[..., np.newaxis]
    gf_tau_fct = get_order_n_pole(order)
    tail_tau = moment*.5*(gf_tau_fct(tau, CC, beta) + gf_tau_fct(tau, -CC, beta))
    if _has_nan(tail_tau):
        raise RuntimeError("Calculation of tail-fit failed. Most likely a overflow occurred.")
    return FourierFct(iw=moment*norm_tail_iw, tau=tail_tau)
示例#5
0
def get_gf_from_moments(moments, beta, N_iw) -> FourierFct:
    """Green's function from `moments` on Matsubara axis and imaginary time.

    Parameters
    ----------
    moment : (n, ...) float array_like or float
        High frequency moment of `gf_iw`.
    beta : float
        The inverse temperature.
    N_iw : int
        Number of Matsubara frequencies

    Returns
    -------
    moments.iw : (..., N_iw) complex np.ndarray
        Matsubara Green's function calculated from the moments for positive
        frequencies.
    moments.tau : (..., 2*N_iw + 1) float np.ndarray
        Imaginary time Green's function calculated from the moments for τ in [0, β].

    """
    moments = np.asarray(moments)
    iws = gt.matsubara_frequencies(np.arange(N_iw), beta=beta)
    if moments.shape[-1] == 1:  # last dimension can be used for iws/tau
        return FourierFct(iw=moments/iws, tau=-.5*moments)
    if moments.shape[-1] == 2:
        m1, m2 = moments[..., 0], moments[..., 1]
        if np.any(m1 == 0.):
            if np.all(m2 == 0.) and np.all(m1 == 0.):
                return FourierFct(iw=0, tau=0)
            # TODO: TEST THIS!
            tau = np.linspace(0, beta, num=2*N_iw + 1, endpoint=True)
            mom_iw = np.zeros((*m1.shape, N_iw), dtype=iws.dtype)
            mom_tau = np.zeros((*m1.shape, tau.size), dtype=tau.dtype)
            # cases where mom[0] == 0:
            mom_is0 = m1 == 0
            mom_iw[mom_is0] = m2[mom_is0, np.newaxis]/iws**2
            mom_tau[mom_is0] = m2[mom_is0, np.newaxis]*(.5*tau + .25*beta)
            # cases where mom[0] != 0:
            pole = (m2[~mom_is0]/m1[~mom_is0])[..., np.newaxis]
            mom_iw[~mom_is0] = m1[~mom_is0, np.newaxis]/(iws - pole)
            mom_tau[~mom_is0] = m1[~mom_is0, np.newaxis] * ft_pole2tau(tau, pole=pole, beta=beta)
            return FourierFct(iw=mom_iw, tau=mom_tau)
        tau = np.linspace(0, beta, num=2*N_iw + 1, endpoint=True)
        pole = (m2/m1)[..., np.newaxis]
        mom_iw = m1[..., np.newaxis]/(iws - pole)
        mom_tau = m1[..., np.newaxis] * ft_pole2tau(tau, pole=pole, beta=beta)
        return FourierFct(iw=mom_iw, tau=mom_tau)
    raise NotImplementedError()
示例#6
0
def test_compare_greensfunction():
    """Non-interacting and DMFT should give the same for self-energy=0."""
    N = 13
    prm = model.Hubbard_Parameters(N, lattice='bethe')
    prm.T = 0.137
    prm.D = 1.  # half-bandwidth
    prm.mu[N // 2] = 0.45
    prm.h[N // 2] = 0.9
    t = 0.2
    prm.t_mat = model.hopping_matrix(N, nearest_neighbor=t)

    iw = gt.matsubara_frequencies(np.arange(100), beta=prm.beta)
    gf0 = prm.gf0(iw)
    gf_dmft = prm.gf_dmft_s(iw, np.zeros_like(gf0))
    assert np.allclose(gf0, gf_dmft)
示例#7
0
def curr_acorr0_n1_iv0(prm: Hubbard_Parameters, *, occ=None, n_iw=2**16):
    """Calculate non-interacting bosonic Matsubara current-current correlation function.

    For the non-interacting case, only the zeroth Matsubara frequency
    :math:`iν_0 = 0` is finite, all other frequencies vanish. Thus only the
    zeroth frequency is calculated.

    Parameters
    ----------
    prm : Hubbard_Parameters
        The model.
    occ : (N_sp, N_l=1) float np.ndarray
        Used to include Hartree contribution if `prm.U ≠ 0`
    n_iw : int
        How many fermionic Matsubaras will be used for the summation.

    Returns
    -------
    curr_acorr_n1_iv : (N_sp, 1) complex np.ndarray
        The current-current correlation function.

    Notes
    -----
    For the non-interacting case it is in fact not a good idea, to use Matsubara
    summation. It would probably be more efficient to perform the Matsubara sum
    analytic and numerically integrate over the DOS.
    Furthermore, using Pade instead of Matsubara frequencies would be way more
    efficient.

    """
    # TODO: dynamically calculate the number of Matsubaras to use from temperature
    iws = gt.matsubara_frequencies(range(n_iw), beta=prm.beta)
    if occ is not None:
        occ = occ[::-1]
    xi = prm.onsite_energy(iws, hartree=occ)
    assert model.rev_dict_hilbert_transfrom[prm.hilbert_transform] == 'bethe'
    gf_d1 = gt.bethe_gf_d1_omega(np.add.outer(xi, iws), half_bandwidth=prm.D)
    delta_sum = 2 * prm.T * np.sum(gf_d1 + 1. / (iws + xi)**2, axis=-1).real
    return delta_sum - gt.fermi_fct_d1(xi, beta=prm.beta)
示例#8
0
def test_Hartree_curr_acorr_n1():
    """Compare the results of `curr_acorr_n1_iv` with the Hartree case."""
    prm = model.Hubbard_Parameters(N_l=1, lattice='bethe')
    prm.D = 1.37
    prm.mu[:] = .136
    prm.U[:] = 2.37
    prm.T = 0.01
    prm.assert_valid()

    iws = gt.matsubara_frequencies(range(1024), beta=prm.beta)
    hartree = layer_dmft.hartree_solution(prm, iws)
    self_hartree = hartree.self_iw
    occ = hartree.occ
    K_iv = conduct.curr_acorr_n1_iv(prm,
                                    self_iw=self_hartree,
                                    occ=occ,
                                    N_iv=10)
    assert np.allclose(K_iv.imag, 0), "Correlation is real quantity."
    # accuracy depends on temperature!
    # Finite values are due to truncation of Matsubara sums
    assert np.allclose(
        K_iv[...,
             1:], 0, atol=1e-4), "For U=0, only zeroth frequency contributes."
    assert np.allclose(K_iv[..., 0], conduct.curr_acorr0_n1_iv0(prm, occ=occ))
示例#9
0
def plot_spectral(it: Union[int, str] = -1):
    #
    # load data
    #
    lay_obj = dataio.LayerData()
    lay_data, iteration = lay_obj.iter(it, return_iternum=True)
    logging.debug("Load iteration %s of layer data", iteration)

    # FIXME: imp_data gets collected upon calling `iter` and discarding the object!
    imp_obj = dataio.ImpurityData()
    imp_data = imp_obj.iter(iteration)

    assert lay_data["temperature"] == prm.T

    layers = list(imp_data.keys())

    gf_lay_iw: np.ndarray = lay_data['gf_iw']
    gf_lay_iw = gf_lay_iw[:, layers]
    gf_imp_iw = np.array([imp_lay['gf_iw'] for imp_lay in imp_data.values()
                          ]).transpose(1, 0, 2)
    # gf_imp_iw = np.array([imp_data[lay]['gf_iw'] for lay in sorted(imp_data.keys())]).transpose(1, 0, 2)
    # print(*sorted(imp_data.keys()))

    N_iw = gf_lay_iw.shape[-1]
    iws = gt.matsubara_frequencies(np.arange(N_iw), beta=prm.beta)

    #
    # options
    #
    SPLIT_PLOTS = False
    PARAMAGNETIC = False if np.count_nonzero(
        prm.h) or not layer_dmft.FORCE_PARAMAGNET else True
    SHIFT: complex = 0.2 * iws[0]
    # SHIFT *= 4  # FIXME
    THRESHOLD: float = SHIFT.imag / 2
    THRESHOLD = np.infty  # FIXME

    if PARAMAGNETIC:  # average over spins
        gf_lay_iw = gf_lay_iw.mean(axis=0,
                                   keepdims=True)  # should already be averaged
        gf_imp_iw = gf_imp_iw.mean(axis=0, keepdims=True)

    omega = np.linspace(-4 * prm.D, 4 * prm.D, num=1000, dtype=complex)
    omega += SHIFT  # shift into imaginary plane
    N_w = omega.size

    # prepare Pade
    kind_gf = pade.KindGf(N_iw // 10, 8 * N_iw // 10)
    no_neg_imag = pade.FilterNegImag(THRESHOLD)
    pade_gf = partial(pade.avg_no_neg_imag,
                      z_in=iws,
                      z_out=omega,
                      kind=kind_gf,
                      threshold=THRESHOLD)

    # perform Pade
    gf_lay_w = pade_gf(fct_z=gf_lay_iw)
    gf_imp_w = pade_gf(fct_z=gf_imp_iw)

    #
    # IMPURITY GREEN'S FUNCTION FROM SELF-ENERGY
    #
    # FIXME: save hybridization function with data
    lay_data_prev = lay_obj.iter(iteration - 1)
    siams = prm.get_impurity_models(z=iws,
                                    self_z=lay_data_prev['self_iw'],
                                    gf_z=lay_data_prev['gf_iw'],
                                    occ=lay_data_prev['occ'])

    #
    # create figure
    #
    rows, cols = gf_lay_iw.shape[:-1]
    if SPLIT_PLOTS:
        axes = np.array([
            plt.subplots(nrows=rows, sharex=True, squeeze=False)[1][:, 0]
            for __ in range(cols)
        ]).T
        print(axes.shape)
    else:
        __, axes = plt.subplots(nrows=rows,
                                ncols=cols,
                                sharex=True,
                                sharey="row",
                                squeeze=False)
    for axis in axes.flatten():
        axis.grid(True)
        axis.axhline(0, color="black", linewidth=1)
        axis.axvline(0, color="black", linewidth=1)

    data_max = max(abs(dat.x.imag).max() for dat in (gf_lay_w, gf_imp_w))
    ax: plt.Axes = axes[-1, 0]
    ax.set_ylim(bottom=-1.05 * data_max, top=0.05 * data_max)
    ax = axes[0, 0]
    ax.set_ylim(bottom=0.05 * data_max, top=-1.05 * data_max)

    # gf_lay_w.x[0] *= -1  # check ifspins are correct

    #
    # plot data
    #
    for ax, gf_lay_ll, gf_lay_ll_err in zip(axes.reshape((-1)),
                                            gf_lay_w.x.reshape((-1, N_w)),
                                            gf_lay_w.err.reshape((-1, N_w))):
        plot.err_plot(x=omega.real,
                      y=gf_lay_ll.imag,
                      yerr=gf_lay_ll_err.imag,
                      axis=ax,
                      fmt='--',
                      label='Gf_lay')

    for ax, gf_imp_ll, gf_imp_ll_err in zip(axes.reshape((-1)),
                                            gf_imp_w.x.reshape((-1, N_w)),
                                            gf_imp_w.err.reshape((-1, N_w))):
        plot.err_plot(x=omega.real,
                      y=gf_imp_ll.imag,
                      yerr=gf_imp_ll_err.imag,
                      axis=ax,
                      fmt='--',
                      label='Gf_imp')
    for lay, siam_ll in enumerate(siams):
        siam_ll: model.SIAM
        if lay not in layers:
            continue
        self_iw = lay_data['self_iw'][:, lay]
        coeff = pade.coefficients(iws, fct_z=siam_ll.hybrid_fct + self_iw)
        kind_self = pade.KindSelf(N_iw // 10, 8 * N_iw // 10)
        valid = no_neg_imag(
            omega,
            kind_self.islice(pade.calc_iterator(omega, z_in=iws, coeff=coeff)))

        def _mod(z, pade_z):
            return 1 / (z - pade_z + siam_ll.e_onsite[..., np.newaxis])

        gf_hyb = pade.Mod_Averager(z_in=iws,
                                   coeff=coeff,
                                   mod_fct=_mod,
                                   valid_pades=valid,
                                   kind=kind_self)(omega)
        for ax, sp in zip(axes[:, layers.index(lay)], model.Spins):
            plot.err_plot(x=omega.real,
                          y=gf_hyb.x[sp].imag,
                          yerr=gf_hyb.err[sp].imag,
                          axis=ax,
                          fmt='--',
                          label=r'Gf_hyb[$\Sigma$]')

    spin_strs = ('↑', '↓')
    for sp, ax in zip(spin_strs, axes[:, 0]):
        ax.set_ylabel(rf"$\Im G_{{{sp}l}}(i\omega_n)$")

    for lay, ax in zip(imp_data.keys(), axes[0]):
        ax.set_title(f"l = {lay}")

    for ax in axes[-1]:
        ax.set_xlabel("ω")

    axes[-1, -1].legend()

    plt.tight_layout()
    plt.show()
示例#10
0
def charge_self_consistency_int(prm: Hubbard_Parameters, self_iw, occ0, tol):
    """Charge self-consistency using root-finding algorithm.

    Parameters
    ----------
    parameters : model.Hubbard_Parameters
        `model.Hubbard_Parameters` object with the parameters set,
        determining Hamiltonian.
    tol : float
        Target tol of the self-consistency. Iteration stops if it is
        achieved.
    occ : ndarray, optional
        Starting value for the occupation.

    Returns
    -------
    sol : OptimizedResult
        The solution of the optimization routine, see `optimize.root`.
        `x` contains the actual values, and `success` states if convergence was
        achieved.
    occ : SpinResolvedArray
        The final occupation of the converged result.
    V : ndarray
        The final potential of the converged result.

    """
    # TODO: optimize n_points from error guess
    # TODO: check against given `n` if sum gives right result
    # TODO: give back self-energy?
    # optimization: allow mask
    assert self_iw.shape[-2] == occ0.shape[-1] == prm.N_l
    iws = gt.matsubara_frequencies(np.arange(self_iw.shape[-1]), beta=prm.beta)

    # subtract Hartree part
    self_iw_bare = self_iw - hfm.self_m0(prm.U, occ0[::-1])[..., np.newaxis]

    output = {}

    # TODO: check tol of density for target tol
    optimizer = partial(update_occupation,
                        i_omega=iws,
                        params=prm,
                        out_dict=output,
                        self_iw_bare=self_iw_bare)
    solve = partial(_root, fun=optimizer, x0=occ0, tol=tol)
    LOGGER.progress("Search self-consistent occupation number")
    try:
        sol = solve()
    except KeyboardInterrupt as key_err:
        print('Optimization canceled -- trying to continue')
        try:
            hartree_occ = output['occ'][::-1]
        except KeyError:
            print('Failed! No occupation so far.')
            raise key_err
        sol = optimize.OptimizeResult()
        sol.x = output['occ']
        sol.success = False
        sol.message = 'Optimization interrupted by user, not terminated.'
    else:
        hartree_occ = output['occ'][::-1]
    # finalize
    gf_iw = prm.gf_dmft_s(iws,
                          self_z=self_iw_bare +
                          hfm.self_m0(prm.U, hartree_occ)[..., np.newaxis])
    occ = prm.occ0(gf_iw, hartree=hartree_occ, return_err=True)
    LOGGER.info("Success of finding self-consistent occupation: %s",
                sol.success)
    LOGGER.info("%s", sol.message)
    return ChargeSelfconsistency(sol=sol, occ=occ, V=prm.V)
示例#11
0
def charge_self_consistency(parameters,
                            tol,
                            V0=None,
                            occ0=None,
                            kind='auto',
                            n_points=2**11):
    """Charge self-consistency using root-finding algorithm.

    Parameters
    ----------
    parameters : model.Hubbard_Parameters
        `model.Hubbard_Parameters` object with the parameters set,
        determining Hamiltonian.
    tol : float
        Target tol of the self-consistency. Iteration stops if it is
        achieved.
    V0 : ndarray, optional
        Starting value for the electrical potential.
    occ : ndarray, optional
        Starting value for the occupation.
    kind : {'auto', 'occ', 'occ_lsq' 'V'}, optional
        Weather self-consistency is determined according to the charge 'occ' or
        the electrical potential 'V'. In the magnetic case 'V' seems to
        convergence better, there are half as many degrees of freedom. 'occ' on
        the other hand can readily incorporate the Hartree term of the self-energy.
        Per default ('auto') 'occ' is used in the interacting and 'V' in the
        non-interacting case.
        Additionally a constrained (:math:`0 ≤ n_{lσ} ≤ 1`) least-square
        algorithm can be used. If the root-finding algorithms do not converge,
        this `kind` might help.
    n_points : int, optional
        Number of Matsubara frequencies taken into account to calculate the
        charge.

    Returns
    -------
    sol : OptimizedResult
        The solution of the optimization routine, see `optimize.root`.
        `x` contains the actual values, and `success` states if convergence was
        achieved.
    occ : SpinResolvedArray
        The final occupation of the converged result.
    V : ndarray
        The final potential of the converged result.

    """
    # TODO: optimize n_points from error guess
    # TODO: check against given `n` if sum gives right result
    assert kind in set(
        ('auto', 'occ', 'occ_lsq', 'V')), f"Unknown kind: {kind}"
    assert V0 is None or occ0 is None
    params = parameters
    iw_array = xr.Variable(data=gt.matsubara_frequencies(np.arange(n_points),
                                                         beta=params.beta),
                           dims=Dim.iws)

    if kind == 'auto':
        if np.any(params.U != 0):  # interacting case
            kind = 'occ'  # use 'occ', it can incorporate Hartree term
        else:  # non-interacting case
            kind = 'V'  # use 'V', has half as many parameters to optimize

    if V0 is not None:
        params.V[:] = V0
    output = {}

    # TODO: check tol of density for target tol
    if kind.startswith('occ'):
        if occ0 is None:
            gf_iw = params.gf0(iw_array)
            occ0 = params.occ0(gf_iw, return_err=False)
        optimizer = partial(update_occupation,
                            i_omega=iw_array,
                            params=params,
                            out_dict=output)
        root_finder = _occ_least_square if kind == 'occ_lsq' else _root
        solve = partial(root_finder, fun=optimizer, x0=occ0, tol=tol)
    elif kind == 'V':
        optimizer = partial(update_potential,
                            i_omega=iw_array,
                            params=params,
                            out_dict=output)
        solve = partial(_root, fun=optimizer, x0=params.V[:], tol=tol)
    LOGGER.progress("Search self-consistent occupation number")
    try:
        sol = solve()
    except KeyboardInterrupt as key_err:
        print('Optimization canceled -- trying to continue')
        try:
            hartree_occ = output['occ'][::-1]
        except KeyError:
            print('Failed! No occupation so far.')
            raise key_err
        sol = optimize.OptimizeResult()
        sol.x = output['occ' if kind in ('occ', 'occ_lsq') else 'V']
        sol.success = False
        sol.message = 'Optimization interrupted by user, not terminated.'
    else:
        hartree_occ = output['occ'].roll({Dim.sp: 1}, roll_coords=False)
    # finalize
    gf_iw = params.gf0(iw_array, hartree=hartree_occ)
    occ = params.occ0(gf_iw, hartree=hartree_occ, return_err=True)
    LOGGER.info("Success of finding self-consistent occupation: %s",
                sol.success)
    LOGGER.info("%s", sol.message)
    return ChargeSelfconsistency(sol=sol, occ=occ, V=params.V)
示例#12
0
def read_iw(dir_='.'):
    """Return the Matsubara frequencies."""
    prm = load_param(dir_)
    out_dir = output_dir(dir_)
    iw_output = np.loadtxt(out_dir / GF_FILE, unpack=True)
    return gt.matsubara_frequencies(iw_output[0], beta=prm.beta)