def write_imp_problems(self, output): g0iw = [orbspin.invert(p.g0inviw) for p in self.imp_problems] output.write_quantity("g0iw-full", g0iw) output.write_quantity("g0iw", g0iw) output.write_quantity("fiw", [p.fiw for p in self.imp_problems]) output.write_quantity("fmom", [p.fmom for p in self.imp_problems]) output.write_quantity("ftau", [p.ftau for p in self.imp_problems]) output.write_quantity("ftau-full", [p.ftau for p in self.imp_problems]) output.write_quantity("muimp", [p.muimp for p in self.imp_problems]) output.write_quantity("muimp-full", [p.muimp for p in self.imp_problems])
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)
def gloc2fiw(self): self.imp_problems = [] if (self.use_gw == 1) and (np.sum(self.siw_full) != 0): muimp = (self.mu * self._eye - self.dc_full - self.lattice.hloc.real - self.sigma_hartree - np.sum(self.smom_gw, axis=0) / self.lattice.nkpoints) else: muimp = (self.mu * self._eye - self.dc_full - self.lattice.hloc.real - self.sigma_hartree) atom = 0 for ineq, siw_block, smom_block in zip(self.ineq_list, self.siw_dd, self.smom_dd): # extract d-d blocks and perform inversion. giw_block = ineq.d_downfold(self.glociw) g0inviw_block = orbspin.invert(giw_block) # Now we "undo" the frequency splitting in order to create # the same impurity problem for each core if self.mpi_comm is not None: g0inviw_block = self.mpi_strategy.allgather(g0inviw_block) # Remove self-energy using the Dyson equation. Note that in # d+p or general multi-site, the d-d block is extracted *before* # the inversion and therefore the impurity self-energy is used. g0inviw_block += siw_block # giorgio: Symmetrisierung von G0inviw g0inviw_block.real[:, ...] = 0.5 * (g0inviw_block.real[:, ...] + g0inviw_block.real[::-1, ...]) g0inviw_block.imag[:, ...] = 0.5 * (g0inviw_block.imag[:, ...] - g0inviw_block.imag[::-1, ...]) nbands = g0inviw_block.shape[1] niw = g0inviw_block.shape[0] g0inviw_block = g0inviw_block.reshape(niw, nbands * 2, nbands * 2) g0_new = np.zeros_like(g0inviw_block, dtype=complex) for i in range(0, niw): tmp = g0inviw_block[i, :, :] g0_new[i, :, :] = 0.5 * (tmp.transpose(1, 0) + tmp) g0_new = g0_new.reshape(niw, nbands, 2, nbands, 2) g0inviw_block = g0_new # giorgio ###### # in principle, since the bare impurity propagator reads: # `1/G_0(iw) = iw - muimp - F(iw)`, we have a freedom where to put # constant shifts. However, constant terms in `F(iw)` translate to # an unresolvable delta peak at `F(tau=0)`. Therefore, we want the # zero-th moment of `F(iw)` to vanish, which in turn fixes `muimp`. eye_block = ineq.d_downfold(self._eye) # The first moment of the hybridisation function is given as # - P <H>^2 P + (P <H> P)^2, where P is the downfolding projector, # (see Eq. (4.63b) in Markus' thesis), so we cannot simply downfold # the second moment of the DOS. hloc_block = ineq.d_downfold(self.lattice.hloc) # GW Inclusion and Inclusion of GW 0th Moment if (self.use_gw == 1) and (np.sum(self.siw_full) != 0): norbitals_per_atom = np.int(self.lattice.norbitals / self.natoms) orbits = slice(atom * norbitals_per_atom, (atom + 1) * norbitals_per_atom) # => Model based if self.use_gw_kaverage == 0: smom_gw2 = np.sum(self.smom_gw[:, orbits, :, orbits, :] * self.smom_gw[:, orbits, :, orbits, :], axis=0) / self.lattice.nkpoints fmom1_block = ( np.einsum("isjt,jtku->isku", hloc_block, hloc_block) - ineq.d_downfold(self.lattice.hmom2) ) #+ C1 - C2 - C3 - C4 - smom_gw2 # (-) CORRECT HERE! # => K-average based else: smom_gw2 = np.sum(self.smom_gw[:, orbits, :, orbits, :] * self.smom_gw[:, orbits, :, orbits, :], axis=0) / self.lattice.nkpoints fmom1_block = ( np.einsum("isjt,jtku->isku", hloc_block, hloc_block) - ineq.d_downfold(self.lattice.hmom2) ) - smom_gw2 # MINUS SIGN IS CORRECT HERE! # No GW in first iteration else: fmom1_block = ( np.einsum("isjt,jtku->isku", hloc_block, hloc_block) - ineq.d_downfold(self.lattice.hmom2)) muimp_block = ineq.d_downfold(muimp) # fiw is defined in the bath picture, which means that: # G0(iw)^{-1} = iw + muimp - F(-iw); F(-iw) = F*(iw) # TODO: check if that is still true with complex F(tau) fiw_block = -1j*self.iwf[:,None,None,None,None] * eye_block \ + muimp_block - g0inviw_block.conj() fiw_model = fmom1_block / (1j * self.iwf[:, None, None, None, None]) # GW Inclusion if (self.use_gw == 1) and (np.sum(self.siw_full) != 0) and (self.use_gw_kaverage == 0): extension_of = 1 fiw_block_asymptotic, fiw_model_asymptotic, model_mom1 = self.gw.Reach_asymptotics_for_Hybridization( fiw_block, fiw_model, self.iwf, extension_of) ftau_block = iw_to_tau_fast( fiw_block_asymptotic - fiw_model_asymptotic, self.nftau, self.beta, axis=0) - model_mom1 / 2. fmom_block = np.asarray( (np.zeros_like(model_mom1), model_mom1)) else: ftau_block = iw_to_tau_fast( fiw_block - fiw_model, self.nftau, self.beta, axis=0) - fmom1_block / 2. fmom_block = np.asarray( (np.zeros_like(fmom1_block), fmom1_block)) imp_problem = impurity.ImpurityProblem(self.beta, g0inviw_block, fiw_block, fmom_block, ftau_block, muimp_block, ineq.dd_int, None, None, ineq.symmetry_moves, self.paramag) self.imp_problems.append(imp_problem) atom = atom + 1