Пример #1
0
    def __init__(self, beta, w, dos):
        try:
            nw, norbitals, nspins = dos.shape
        except ValueError:
            raise ValueError("dos must be a nw, norbital, nspins array")
        if w.shape != (nw, ):
            raise ValueError("w and dos are not consistent in shape")

        Lattice.__init__(self, beta, norbitals, nspins)

        integrate = lambda fw: scipy.integrate.trapz(fw, w)
        cum_int = lambda fw: scipy.integrate.cumtrapz(fw, w, initial=0)

        if (dos < 0).any() or dos.imag.any():
            warn("dos is not a positive real function.", UserWarning, 2)

        dos_w_last = dos.transpose(1, 2, 0)
        norm = integrate(dos_w_last)
        if not np.allclose(norm, 1):
            warn("dos seems not to be properly normalised.\n Norms: %s" % norm,
                 UserWarning, 2)

        self.w = w
        self.dos = dos
        self.int_dos = cum_int(dos_w_last).transpose(2, 0, 1)

        self.hloc = integrate(dos_w_last * w)
        self.hmom2 = integrate(dos_w_last * w**2)

        self.hloc = orbspin.promote_diagonal(self.hloc)
        self.hmom2 = orbspin.promote_diagonal(self.hmom2)
Пример #2
0
    def __init__(self, beta, half_bw, crystalfield=None):
        # crystalfield marks the centers of the DOS (hmean)
        if crystalfield is None:
            crystalfield = np.zeros_like(half_bw)

        self.crystalfield = np.asarray(crystalfield)
        self.d = np.asarray(half_bw)

        norbitals, nspins = self.d.shape
        Lattice.__init__(self, beta, norbitals, nspins)

        # add dummy iw dimension to satisfy requirements for promote_diagonal
        tstar2 = self.d**2 / 4.
        self.hloc = orbspin.promote_diagonal(self.crystalfield)
        self.hmom2 = orbspin.promote_diagonal(tstar2) + self.hloc**2
Пример #3
0
    def load_old(self, oldfile, olditer=-1):
        hf = hdf5.File(oldfile, "r")
        file_version = tuple(hf.attrs["outfile-version"])

        if olditer == -1:
            oldit = hf["dmft-last"]
        else:
            oldit = hf["dmft-%03d" % olditer]

        ineqs = [
            node for name, node in sorted(oldit.iteritems())
            if name.startswith("ineq-")
        ]
        if not ineqs:
            raise ValueError("No impurity results found in iteration")

        mu = oldit["mu/value"].value
        smom_dd = None
        dc_latt = None

        if file_version >= (2, 1):
            siw_dd = [
                ineq["siw-full/value"].value.transpose(4, 0, 1, 2, 3)
                for ineq in ineqs
            ]
            smom_dd = [
                ineq["smom-full/value"].value.transpose(4, 0, 1, 2, 3)
                for ineq in ineqs
            ]
            try:
                dc_latt = oldit["dc-latt/value"].value
            except KeyError:
                pass
        elif file_version >= (2, 0):
            # FIXME: double-counting for old runs
            siw_dd = [
                orbspin.promote_diagonal(ineq["siw/value"].value.transpose(
                    2, 0, 1)) for ineq in ineqs
            ]
        else:
            # FIXME: double-counting for very old runs
            siw_dd = [
                orbspin.promote_diagonal(siw_ineq.transpose(2, 0, 1))
                for siw_ineq in oldit["siw/value"].value
            ]

        hf.close()
        return mu, siw_dd, smom_dd, dc_latt
Пример #4
0
def doublecounting_from_cfg(cfg, ineq_list, mylattice, atom_list, u_full):
    dc_type = cfg["General"]["dc"]

    # No double counting needed (d-only and max. 1 ineq atom and not
    # user-enforced)
    if len(ineq_list) == 1 and not np.any([atom.np for atom in atom_list]) \
       and not isinstance(dc_type, list):
        return doublecounting.Zero(mylattice.norbitals, mylattice.nspins)

    lda_dens = mylattice.densities
    if isinstance(dc_type, list):
        # user-supplied DC
        dc_user_values = np.array(dc_type, float)
        if dc_user_values.size != mylattice.norbitals:
            raise ValueError("Expected %d elements" % mylattice.norbitals)
        dc_user_values = np.repeat(dc_user_values[:, None], mylattice.nspins,
                                   1)
        dc_user_values = orbspin.promote_diagonal(dc_user_values)
        return doublecounting.UserSupplied(dc_user_values)
    elif dc_type == 'fll' or dc_type == 'anisimov':
        return doublecounting.FullyLocalisedLimit(lda_dens, atom_list, u_full)
    elif dc_type == 'amf':
        return doublecounting.AroundMeanField(lda_dens, atom_list, u_full)
    elif dc_type == 'siginfbar':
        return doublecounting.SigInfBar(ineq_list, lda_dens, atom_list, u_full)
    elif dc_type == 'sigzerobar':
        return doublecounting.SigZeroBar(ineq_list, lda_dens, atom_list,
                                         u_full)
    elif dc_type == 'trace':
        return doublecounting.Trace(ineq_list, lda_dens, atom_list, u_full)
    else:
        raise NotImplemented("Unknown double counting scheme")
Пример #5
0
 def gloc(self, iw, mu, siw, siw_gw=None):
     ziw = (1j * iw + mu)[:, None, None, None, None] * self.eye - siw
     orbspin.warn_offdiagonal(siw)
     zeta = orbspin.extract_diagonal(ziw - self.hloc)
     d2 = self.d[np.newaxis]**2
     glociw = 2 * zeta / d2 * (1 - np.sqrt(1 - d2 / zeta**2))
     glociw = orbspin.promote_diagonal(glociw)
     return glociw
Пример #6
0
    def from_shell(self, dc_shell):
        dc_diag = np.zeros((self.norbitals, self.nspins))
        for isl, sl in enumerate(self.slices):
            dc_diag[sl] = dc_shell[isl, np.newaxis]

        # note the minus sign!
        self.dc_shell = dc_shell
        self.dc_value = -orbspin.promote_diagonal(dc_diag)
Пример #7
0
    def get(self, siws=None, smoms=None, giws=None, occs=None):

        if giws is None:
            # initializing with FLL double counting... better than 0
            dc_fll = FullyLocalisedLimit(self.shell_av['densities'],
                                         self.shell_av['atom_list'],
                                         self.shell_av['u_full'])
            self.dc_value = dc_fll.get()
            return self.dc_value

        for ineq, giw, occ, occ0 in zip(self.ineq_list, giws, occs,
                                        self.d_dens_sum):
            # DOS as "approximated" by first Matsubara frequency
            iw0 = giw.shape[0] // 2
            dos_fermi_level = -1 / np.pi * orbspin.trace(giw[iw0].imag)

            # impurity density from double occupations.
            # TODO: this is tied to diagonal hybr
            dens_impurity = orbspin.promote_diagonal(
                orbspin.extract_diagonal(occ))
            dens_impurity = np.array(dens_impurity).astype(np.float)
            dens_impurity = np.sum(dens_impurity)

            # we do not use the non interacting density from Weiss field
            # but that from the DFT Hamiltonian.
            # that is a lot more stable

            # impurity non-interacting density (from Weiss field)
            #iw = tf.matfreq(beta, 'fermi', imp_result.problem.niwf)
            #eye = np.eye(imp_result.problem.norbitals * imp_result.problem.nspins) \
            #        .reshape(imp_result.problem.norbitals, imp_result.problem.nspins,
            #                 imp_result.problem.norbitals, imp_result.problem.nspins)
            #g0iw = orbspin.invert(imp_result.problem.g0iwinv)
            #g0iw_model = orbspin.invert(1j * iw * eye + imp_result.problem.muimp)
            #dens_model = lattice.fermi(-imp_result.problem.muimp) # FIXME offdiag
            #dens0_impurity = (g0iw - g0iw_model).real.sum(0) / imp_result.problem.beta \
            #                 + dens_model
            if ineq.occ_dc_number is not None:
                dens0_impurity = ineq.occ_dc_number
            else:
                dens0_impurity = occ0

            # If the DOS at the Fermi level is large, we do not want to adjust
            # too much for stability reasons (fudging)
            if dos_fermi_level > 1.:
                delta_dc = (dens0_impurity - dens_impurity) / dos_fermi_level
            else:
                delta_dc = dens0_impurity - dens_impurity

            # Fudging factor
            delta_dc *= 0.2

            delta_dc = delta_dc * np.eye(ineq.nd * self.nspins).reshape(
                ineq.nd, self.nspins, ineq.nd, self.nspins)
            ineq.d_setpart(self.dc_value,
                           ineq.d_downfold(self.dc_value) - delta_dc)
        return self.dc_value
Пример #8
0
    def gloc(self, iw, mu, siw, siw_gw=None):
        orbspin.warn_offdiagonal(siw)
        siw = orbspin.extract_diagonal(siw)
        zeta = (1j * iw + mu)[:, None, None] - siw

        # compute  integral de N(e)/(zeta - e)
        glociw = self.integrator(
            self.dos.transpose(1, 2, 0)[None, :, :, :] /
            (zeta[:, :, :, None] - self.w[None, None, None, :]))
        glociw = orbspin.promote_diagonal(glociw)
        return glociw
Пример #9
0
 def lattice_convention(qtty):
     return orbspin.promote_diagonal(qtty.transpose(2, 0, 1))
Пример #10
0
    def set_problem(self, problem, compute_fourpoint=0):
        # problem
        self.problem = problem
        problem_params = self.config_to_pstring({
            "Hamiltonian":
            problem.interaction.name,
            "beta":
            problem.beta,
            "Nd":
            problem.norbitals,
            "ParaMag":
            int(problem.paramag),
            "QuantumNumbers":
            " ".join(problem.interaction.quantum_numbers),
            "Phonon":
            int(problem.use_phonons),
            "g_phonon":
            " ".join(problem.phonon_g),
            "omega0":
            " ".join(problem.phonon_omega0),
            "Screening":
            int(problem.use_screening),
            "Uw":
            self.Uw,
        })
        symm_params = self.symm_to_pstring(problem.symmetry_moves)
        all_params = self.param_string + problem_params + symm_params
        ctqmc.init_paras(all_params)
        ctqmc.fourpnt = compute_fourpoint

        # prepare parameters
        if self.config["QMC"]["offdiag"] == 0:
            self.ftau = orbspin.promote_diagonal(
                orbspin.extract_diagonal(self.problem.ftau))

        self.ftau = self.problem.ftau.transpose(1, 2, 3, 4, 0)

        # CT-HYB uses a different convention for muimp
        #self.muimp = -self.prepare_input(self.problem.muimp)
        self.muimp = -self.problem.muimp
        self.umatrix = self.problem.interaction.u_matrix.reshape(
            self.problem.nflavours, self.problem.nflavours,
            self.problem.nflavours, self.problem.nflavours)
        if self.Uw == 0:
            self.screening = self.problem.screening.transpose(1, 2, 3, 4,
                                                              0).real

        # START DYNAMICAL U
        if self.Uw == 1:
            #print " "
            #print "         ****************************"
            #print "         ****** U(w) is active ******"
            #print "         ****************************"
            ### ===> UPDATE This is now done in the init above.
            ### ===> UPDATE _Retarded2Shifts = dynamicalU.Replace_Retarded_Interaction_by_a_Shift_of_instantaneous_Potentials(problem.beta, self.umatrix, self.Uw_Mat)

            ### ===> UPDATE The umatrix shifting is now performed in config.py.
            ### ===> UPDATE The umatrix shifting is now performed in config.py.
            ### ===> # This should be executed for all atoms in the first iteration
            ### ===> try:
            ### ===>    self.iteration_ID    # Not defined for first DMFT iteration
            ### ===> except:
            ### ===>    self.umatrix_original = copy.copy(self.umatrix)
            ### ===>    self.iteration_ID = 1
            ### ===> if (self.umatrix==self.umatrix_original).all():
            ### ===>    self.umatrix = _Retarded2Shifts.shift_instantaneous_densitydensity_potentials(self.umatrix)
            ### ===> UPDATE The umatrix shifting is now performed in config.py.
            ### ===> UPDATE The umatrix shifting is now performed in config.py.

            ### ===> UPDATE This is now done in the init above.
            ### ===> UPDATE self.screening = _Retarded2Shifts.create_tau_dependent_UV_screening_function(problem.nftau, problem.beta, self.screening)

            # Perform chemical potential shift in each DMFT iteration
            if problem.norbitals == 1 and self.epsn == 0:
                self.muimp = self._Retarded2Shifts.shift_chemical_potential_for_single_band_case(
                    self.muimp, self.umatrix)
Пример #11
0
    def postprocessing(self, siw_method="improved", smom_method="estimate"):
        # This function is disjoint from the initialisation, because it is a
        # "derived" quantity that should be computed after averaging over bins
        fallback = False

        if siw_method == "dyson":
            if self.g_diagonal_only:
                # If the solver is only capable of supplying the spin/orbital-
                # diagonal terms of the Green's function, we need to make sure
                # that also only the diagonal terms of G_0 are taken into
                # account in the Dyson equation, otherwise Sigma erroneously
                # "counteracts" these terms.  As an added performance benefit,
                # we can use 1/giw rather than the inversion in this case.
                self.siw = orbspin.promote_diagonal(
                    orbspin.extract_diagonal(self.problem.g0inviw) -
                    1 / orbspin.extract_diagonal(self.giw))
            else:
                self.siw = self.problem.g0inviw - orbspin.invert(self.giw)

        elif siw_method == "improved":
            if self.gsigmaiw is None:
                warn(
                    "Cannot compute improved estimators - GSigmaiw missing\n"
                    "Falling back to Dyson equation", UserWarning, 2)
                siw_method = "dyson"
                fallback = True

            raise NotImplementedError()  # FIXME

        elif siw_method == 'improved_worm':
            if self.gsigmaiw is None:
                warn(
                    "Cannot compute improved estimators - GSigmaiw missing\n"
                    "Falling back to Dyson equation", UserWarning, 2)
                siw_method = "dyson"
                fallback = True

            if self.g_diagonal_only:
                #TODO: check gsigma sign
                self.siw = -orbspin.promote_diagonal(
                    orbspin.extract_diagonal(self.gsigmaiw) /
                    orbspin.extract_diagonal(self.giw))
            else:
                raise NotImplementedError("Offdiagonal worm improved \n"
                                          "estimators not implemented")

        else:
            raise ValueError("unknown siw_method: %s" % siw_method)

        if smom_method == "extract":
            warn("Extracting moment of self-energy from the data", UserWarning,
                 2)
            self.smom = self.siw[:1].real.copy()
        elif smom_method == "estimate":
            if self.smom is None:
                warn(
                    "Cannot compute smom estimate - rho1 and rho2 missing\n"
                    "Falling back to extraction", UserWarning, 2)
                smom_method = "extract"
                fallback = True
        else:
            raise ValueError("unknown smom_method: %s" % smom_method)

        if fallback:
            self.postprocessing(siw_method, smom_method)
Пример #12
0
    def set_siws(self,
                 siw_dd=None,
                 smom_dd=None,
                 dc_full=None,
                 init=False,
                 hartree_start=False,
                 giws=None,
                 occs=None):
        new_run = siw_dd is None and init

        nspins = self.lattice.nspins
        norbitals = self.lattice.norbitals

        if siw_dd is None:
            siw_dd = []
            smom_dd = []
            for ineq in self.ineq_list:
                siw_block = np.zeros(
                    (self.niwf, ineq.nd, nspins, ineq.nd, nspins), np.complex)
                if not self.paramag:
                    siw_block[:, :, 0, :, 0] += .5 * ineq.se_shift
                    siw_block[:, :, 1, :, 1] -= .5 * ineq.se_shift

                siw_dd.append(siw_block)
                smom_dd.append(siw_block[:2].real)

        if smom_dd is None:
            warn("extracting moments from Sigma. Better use siw_mom",
                 UserWarning, 2)
            smom_dd = [siw_block[:2].real for siw_block in siw_dd]

        # Enforce paramagnetic option
        if self.paramag:
            siw_dd = [orbspin.symm_spins(siw_block) for siw_block in siw_dd]
            smom_dd = [
                orbspin.symm_spins(smom_block) for smom_block in smom_dd
            ]

        # get double-counting if we do not force it to a value.
        # Note that the double-counting is essentially a correction to the
        # Hamiltonian and therefore present from the start.

        # fix for self consitent dc: If self.dc_full is present
        # (from last iteration or from init), then do not call the
        # standard dc call here but do it later
        # this implies that set_siws() can initialize dc with dc_full
        # exaclty once, which makes sense

        try:
            self.dc_full
        except AttributeError:
            if dc_full is None:
                self.dc_full = self.dc.get()
            else:
                self.dc_full = dc_full
                # We also have to set the double counting inside the
                # dc class so that trace double counting works
                self.dc.set(dc_full)

        if self.use_gw == 1:
            self.dc_full = self.dc_full * 0

        # Try to mimic the behaviour of the old code
        if new_run and hartree_start:
            self.sigma_hartree = -self.dc_full
            for ineq_no, ineq in enumerate(self.ineq_list):
                siw_dd[ineq_no][:] += ineq.d_downfold(self.sigma_hartree)
                ineq.d_setpart(self.sigma_hartree, 0)

        # Perform mixing of self-energy, its moments and
        # double-counting with the same mixer. This is important to
        # keep them "consistent", i.e., double-count correlations at
        # the same rate as switching them on, and with DIIS, the
        # mixing of all related quantities using the same mixer is
        # necessary in particular because the earlier values
        # themselves influence the ratios in which they are mixed in.
        self.dc_full, self.siw_dd, self.smom_dd = self.siw_mixer(
            self.dc_full, siw_dd, smom_dd)

        # Fix the distance between selected d-orbitals and the p-manifold to the original distance of the LDA/GW Hamiltonian
        if self.dc_dp == 1:
            self.dc_full = self.dc_full * 0
            dp_dc = doublecounting.Fixed_dp_Distance()
            self.dc_full = -dp_dc.get(self.dc_full, self.siw_dd, self.smom_dd,
                                      self.iwf, self.natoms,
                                      self.dc_dp_orbitals)

        # not doing mixing for self consistent dc
        # if we do want to mix... simply move this part above the mixing routine
        # if dc_full is not None, it comes from a restarted run. We do not want to
        # overwrite the restart value here!
        if self.dc.self_cons and (dc_full is None):
            # this currently should only work for trace dc
            # todo: fix siginfbar
            self.dc_full = self.dc.get(siws=siw_dd,
                                       smoms=smom_dd,
                                       giws=giws,
                                       occs=occs)
        # Upfold self-energy.
        self.siw_full = 0
        self.siw_moments = 0
        for ineq, siw_bl, siw_bl_mom in zip(self.ineq_list, self.siw_dd,
                                            self.smom_dd):
            # Here, we potentially encounter a memory problem (a set of
            # nflavours x nflavours x nfrequencies) object may very well
            # overflow, so we split the upfolded self-energy in frequency
            # "chunks"
            self.siw_full += ineq.d_upfold(siw_bl[self.my_slice])
            self.siw_moments += ineq.d_upfold(siw_bl_mom)

        # Add double-counting to the self-energy
        self.siw_full += self.dc_full
        self.siw_moments[0] += self.dc_full

        # This is an approximation: really, the partial densities and Hartree
        # self-energy an inter-dependent system. Here, we assume that the
        # partial densities won't change much adding  a static self-energy
        # shift...
        if not (hartree_start and new_run):
            if self.use_hartree:
                #self.siw2gloc() # computes densities as well
                hartree = np.einsum("isjt,jt->is",
                                    self.udp_full + self.upp_full,
                                    self.densities)
                self.sigma_hartree = orbspin.promote_diagonal(hartree)
            else:
                self.sigma_hartree = np.zeros(self.siw_full.shape[1:],
                                              dtype=self.siw_full.dtype)

        self.siw_full += self.sigma_hartree
        self.siw_moments[0] += self.sigma_hartree.real

        # Invalidate lattice quantities (call to siw2gloc necessary)
        self.glociw = None
        self.densities = None
        self.densmatrix = None

        # Only if the DMFT Self-Energy is non-zero, we add the GW Self-Energy
        if (self.use_gw == 1) and (np.sum(self.siw_full) !=
                                   0):  # siw_full is d+p siw_dd is d-only
            self.siw_gw, self.smom_gw = self.gw.get_GW_Sigma(
                self.beta, self.my_iwf)
            self.siw_gw = self.siw_gw.transpose(1, 0, 2, 3, 4, 5)
Пример #13
0
    def load_old(oldfile, olditer=-1):
        hf = hdf5.File(oldfile, "r")
        file_version = tuple(hf.attrs["outfile-version"])

        if olditer == -1:
            oldit = hf["dmft-last"]
        else:
            oldit = hf["dmft-%03d" % olditer]

        ineqs = [
            oldit[name] for name in sorted(oldit) if name.startswith("ineq-")
        ]
        if not ineqs:
            raise ValueError("No impurity results found in iteration")

        mu = oldit["mu/value"][()]
        smom_dd = None
        dc_latt = None
        beta = None

        if file_version >= (2, 1):
            siw_dd = [
                ineq["siw-full/value"][()].transpose(4, 0, 1, 2, 3)
                for ineq in ineqs
            ]
            smom_dd = [
                ineq["smom-full/value"][()].transpose(4, 0, 1, 2, 3)
                for ineq in ineqs
            ]

            # Fix shape of smom when reading old data files with only
            # one order (i.e. sigma_inf) written
            if any(smom_ineq.shape[0] == 1 for smom_ineq in smom_dd):
                smom_dd = [
                    np.broadcast_to(smom_ineq, [2] + list(smom_ineq.shape[1:]))
                    for smom_ineq in smom_dd
                ]

            try:
                dc_latt = oldit["dc-latt/value"][()]
            except KeyError:
                pass
        elif file_version >= (2, 0):
            # FIXME: double-counting for old runs
            siw_dd = [
                orbspin.promote_diagonal(ineq["siw/value"][()].transpose(
                    2, 0, 1)) for ineq in ineqs
            ]
        else:
            # FIXME: double-counting for very old runs
            siw_dd = [
                orbspin.promote_diagonal(siw_ineq.transpose(2, 0, 1))
                for siw_ineq in oldit["siw/value"][()]
            ]

        try:
            beta = hf[".config"].attrs["general.beta"]
        except KeyError:
            pass
        except AttributeError:
            pass

        hf.close()
        return mu, siw_dd, smom_dd, dc_latt, beta