def calc_momentum_distribution(self, mu, beta, with_Sigma, with_dc): things_to_read = ['n_k', 'n_orbitals', 'proj_mat', 'hopping', 'n_parproj', 'proj_mat_all'] value_read = self.read_input_from_hdf( subgrp=self.bands_data, things_to_read=things_to_read) den = numpy.zeros([self.n_k, 2-self.SO, self.n_orbitals[0, 0], self.n_orbitals[0, 0]], numpy.complex_) spn = self.spin_block_names[self.SO] ikarray = numpy.array(list(range(self.n_k))) for ik in mpi.slice_array(ikarray): g_latt = self.lattice_gf( ik=ik, mu=mu, iw_or_w="iw", beta=beta, with_Sigma=with_Sigma, with_dc=with_dc) den0 = g_latt.density() g_latt.invert() for isp in range(len(spn)): den[ik, isp, :, :] = den0[spn[isp]][:, :] # # eigenvalue # # ev[ik, isp, :] = numpy.linalg.eigvalsh(g_latt[spn[isp]].data[len(g_latt[spn[isp]].mesh)//2, :, :]) # # Collect density matrix across processes # den = mpi.all_reduce(mpi.world, den, lambda x, y: x + y) return den
def HT(res): import triqs.utility.mpi as mpi # First compute the eps_hat array eps_hat = epsilon_hat( self.dos.eps) if epsilon_hat else numpy.array( [x * numpy.identity(N1) for x in self.dos.eps]) assert eps_hat.shape[0] == self.dos.eps.shape[ 0], "epsilon_hat function behaves incorrectly" assert eps_hat.shape[1] == eps_hat.shape[ 2], "epsilon_hat function behaves incorrectly (result not a square matrix)" assert N1 == eps_hat.shape[ 1], "Size of Sigma and of epsilon_hat mismatch" res.zero() # Perform the sum over eps[i] tmp, tmp2 = res.copy(), res.copy() tmp << iOmega_n + mu + eta * 1j if not (Sigma_fnt): tmp -= Sigma if field != None: tmp -= field # I slice all the arrays on the node. Cf reduce operation below. for d, e_h, e in zip(*[ mpi.slice_array(A) for A in [self.rho_for_sum, eps_hat, self.dos.eps] ]): tmp2.copy_from(tmp) tmp2 -= e_h if Sigma_fnt: tmp2 -= Sigma(e) tmp2.invert() tmp2 *= d res += tmp2 # sum the res GF of all nodes and returns the results on all nodes... # Cf Boost.mpi.python, collective communicator for documentation. # The point is that res is pickable, hence can be transmitted between nodes without further code... res << mpi.all_reduce(mpi.world, res, lambda x, y: x + y) mpi.barrier()
def __call__(self, Sigma, mu=0, eta=0, field=None, epsilon_hat=None, result=None, selected_blocks=()): """ - Computes: result <- \[ \sum_k (\omega + \mu - field - t(k) - Sigma(k,\omega)) \] if result is None, it returns a new GF with the results. otherwise, result must be a GF, in which the calculation is done, and which is then returned. (this allows chain calculation: SK(mu = mu,Sigma = Sigma, result = G).total_density() which computes the sumK into G, and returns the density of G. - Sigma can be a X, or a function k-> X or a function k,eps ->X where: - k is expected to be a 1d-numpy array of size self.dim of float, containing the k vector in the basis of the RBZ (i.e. -0.5< k_i <0.5) - eps is t(k) - X is anything such that X[BlockName] can be added/subtracted to a GFBloc for BlockName in selected_blocks. e.g. X can be a BlockGf(with at least the selected_blocks), or a dictionnary Blockname -> array if the array has the same dimension as the GF blocks (for example to add a static Sigma). - field: Any k independant object to be added to the GF - epsilon_hat: a function of eps_k returning a matrix, the dimensions of Sigma - selected_blocks: The calculation is done with the SAME t(k) for all blocks. If this list is not None only the blocks in this list are calculated. e.g. G and Sigma have block indices 'up' and 'down'. if selected_blocks ==None: 'up' and 'down' are calculated if selected_blocks == ['up']: only 'up' is calculated. 'down' is 0. """ assert selected_blocks == (), "selected_blocks not supported for now" #S = Sigma.view_selected_blocks(selected_blocks) if selected_blocks else Sigma #Gres = result if result else Sigma.copy() #G = Gres.view_selected_blocks(selected_blocks) if selected_blocks else Gres # check Sigma # case 1) Sigma is a BlockGf if isinstance(Sigma, BlockGf): model = Sigma Sigma_fnt = False # case 2) Sigma is a function returning a BlockGf else: assert callable( Sigma), "If Sigma is not a BlockGf it must be a function" Sigma_Nargs = len(inspect.getargspec(Sigma)[0]) assert Sigma_Nargs <= 2, "Sigma must be a function of k or of k and epsilon" if Sigma_Nargs == 1: model = Sigma(self.bz_points[0]) elif Sigma_Nargs == 2: model = Sigma(self.bz_points[0], self.hopping[0]) Sigma_fnt = True G = result if result else model.copy() assert isinstance(G, BlockGf), "G must be a BlockGf" # check input assert self.orthogonal_basis, "Local_G: must be orthogonal. non ortho cases not checked." assert len(list(set([g.target_shape[0] for i, g in G]))) == 1 assert self.bz_weights.shape[0] == self.n_kpts(), "Internal Error" no = list(set([g.target_shape[0] for i, g in G]))[0] # Initialize G.zero() tmp, tmp2 = G.copy(), G.copy() mupat = mu * numpy.identity(no, numpy.complex_) tmp << iOmega_n if field != None: tmp -= field if not Sigma_fnt: tmp -= Sigma # substract Sigma once for all # Loop on k points... for w, k, eps_k in zip(*[ mpi.slice_array(A) for A in [self.bz_weights, self.bz_points, self.hopping] ]): eps_hat = epsilon_hat(eps_k) if epsilon_hat else eps_k tmp2 << tmp tmp2 -= tmp2.n_blocks * [eps_hat - mupat] if Sigma_fnt: if Sigma_Nargs == 1: tmp2 -= Sigma(k) elif Sigma_Nargs == 2: tmp2 -= Sigma(k, eps_k) tmp2.invert() tmp2 *= w G += tmp2 G << mpi.all_reduce(mpi.world, G, lambda x, y: x + y) mpi.barrier() return G
def get_G_w_from_A_w(A_w, w_points, np_interp_A=None, np_omega=2000, w_min=-10, w_max=10, broadening_factor=1.0): r""" Use Kramers-Kronig to determine the retarded Green function :math:`G(\omega)` This calculates :math:`G(\omega)` from the spectral function :math:`A(\omega)`. A numerical broadening of :math:`bf * i\Delta\omega` is used, with the adjustable broadening factor bf (default is 1). This function normalizes :math:`A(\omega)`. Use mpi to save time. Parameters ---------- A_w : array Real-frequency spectral function. w_points : array Real-frequency grid points. np_interp_A : int Number of grid points A_w should be interpolated on before G_w is calculated. The interpolation is performed on a linear grid with np_interp_A points from min(w_points) to max(w_points). np_omega : int Number of equidistant grid points of the output Green function. w_min : float Start point of output Green function. w_max : float End point of output Green function. broadening_factor : float Factor multiplying the broadening :math:`i\Delta\omega` Returns ------- G_w : GfReFreq TRIQS retarded Green function. """ shape_A = np.shape(A_w) if len(shape_A) == 1: indices = [0] matrix_valued = False elif (len(shape_A) == 3) and (shape_A[0] == shape_A[1]): indices = list(range(0, shape_A[0])) matrix_valued = True else: raise Exception('A_w has wrong shape, must be n x n x n_w') if w_min > w_max: raise Exception('w_min must be smaller than w_max') if np_interp_A: w_points_interp = np.linspace(np.min(w_points), np.max(w_points), np_interp_A) if matrix_valued: A_temp = np.zeros((shape_A[0], shape_A[1], np_interp_A), dtype=complex) for i in range(shape_A[0]): for j in range(shape_A[1]): A_temp[i, j, :] = np.interp(w_points_interp, w_points, A_w[i, j, :]) A_w = A_temp else: A_w = np.interp(w_points_interp, w_points, A_w) w_points = w_points_interp G_w = GfReFreq(indices=indices, window=(w_min, w_max), n_points=np_omega) G_w.zero() iw_points = np.array(list(range(len(w_points)))) for iw in mpi.slice_array(iw_points): domega = (w_points[min(len(w_points) - 1, iw + 1)] - w_points[max(0, iw - 1)]) * 0.5 if matrix_valued: for i in range(shape_A[0]): for j in range(shape_A[1]): G_w[i, j] << G_w[i, j] + A_w[i, j, iw] * \ inverse(Omega - w_points[iw] + 1j * domega * broadening_factor) * domega else: G_w << G_w + A_w[iw] * \ inverse(Omega - w_points[iw] + 1j * domega * broadening_factor) * domega G_w << mpi.all_reduce(mpi.world, G_w, lambda x, y: x + y) mpi.barrier() return G_w
def mpi_all_reduce_g(g): g << mpi.all_reduce(mpi.world, g, lambda x, y: x + y) return g
for isp in range(SK.n_spin_blocks[SK.SO])] block_ind_list = [block for block, inner in gf_struct] glist = lambda: [ GfImFreq(indices=inner, mesh=mesh) for block, inner in gf_struct ] G_latt_orb = BlockGf(name_list=block_ind_list, block_list=glist(), make_copies=False) G_latt_orb.zero() for ik in mpi.slice_array(ikarray): G_latt_KS = SK.lattice_gf(ik=ik, beta=beta) G_latt_KS *= SK.bz_weights[ik] for bname, gf in G_latt_orb: add_g_ik = gf.copy() add_g_ik.zero() add_g_ik << SK.downfold( ik, 0, bname, G_latt_KS[bname], gf, shells='csc', ir=None) gf << gf + add_g_ik G_latt_orb << mpi.all_reduce(mpi.world, G_latt_orb, lambda x, y: x + y) mpi.barrier() if mpi.is_master_node(): ar['DMFT_results']['Iterations']['G_latt_orb_it' + str(iteration_offset - 1)] = G_latt_orb if mpi.is_master_node(): del ar
def extract_G_loc(self, mu=None, iw_or_w='iw', with_Sigma=True, with_dc=True, broadening=None): r""" """ # +++ADDED # print_time function is inserted in several places for benchmark import time start = [time.time(), time.time()] def print_time(txt): # now = time.time() # print("time {:>8.5f}sec {:>8.5f}sec @ {}".format(now-start[0], now-start[1], txt)) # start[0] = now pass # print("\n=====================") # print("Start extract_G_loc") print_time("start") if mu is None: mu = self.chemical_potential if iw_or_w == "iw": G_loc = [ self.Sigma_imp_iw[icrsh].copy() for icrsh in range(self.n_corr_shells) ] # this list will be returned beta = G_loc[0].mesh.beta G_loc_inequiv = [ BlockGf(name_block_generator=[ (block, GfImFreq(indices=inner, mesh=G_loc[0].mesh)) for block, inner in self.gf_struct_solver[ish].items() ], make_copies=False) for ish in range(self.n_inequiv_shells) ] elif iw_or_w == "w": G_loc = [ self.Sigma_imp_w[icrsh].copy() for icrsh in range(self.n_corr_shells) ] # this list will be returned mesh = G_loc[0].mesh G_loc_inequiv = [ BlockGf(name_block_generator=[ (block, GfReFreq(indices=inner, mesh=mesh)) for block, inner in self.gf_struct_solver[ish].items() ], make_copies=False) for ish in range(self.n_inequiv_shells) ] for icrsh in range(self.n_corr_shells): G_loc[icrsh].zero() # initialize to zero print_time("k-sum start") ikarray = numpy.array(list(range(self.n_k))) for ik in mpi.slice_array(ikarray): print_time("in k-loop: k-sum") if iw_or_w == 'iw': G_latt = self.lattice_gf(ik=ik, mu=mu, iw_or_w=iw_or_w, with_Sigma=with_Sigma, with_dc=with_dc, beta=beta) elif iw_or_w == 'w': mesh_parameters = (G_loc[0].mesh.omega_min, G_loc[0].mesh.omega_max, len(G_loc[0].mesh)) G_latt = self.lattice_gf(ik=ik, mu=mu, iw_or_w=iw_or_w, with_Sigma=with_Sigma, with_dc=with_dc, broadening=broadening, mesh=mesh_parameters) print_time("in k-loop: lattice_gf") G_latt *= self.bz_weights[ik] print_time("in k-loop: *bz_weights") for icrsh in range(self.n_corr_shells): # init temporary storage # tmp = G_loc[icrsh].copy() # for bname, gf in tmp: # tmp[bname] << self.downfold( # ik, icrsh, bname, G_latt[bname], gf) # G_loc[icrsh] += tmp # +++MODIFIED # Sum up directly into G_loc (no temporary storage is introduced) for bname, gf in G_loc[icrsh]: self.downfold(ik, icrsh, bname, G_latt[bname], gf, overwrite_gf_inp=True, fac=+1) print_time("in k-loop: downfold") print_time("k-sum end") # Collect data from mpi for icrsh in range(self.n_corr_shells): G_loc[icrsh] << mpi.all_reduce(mpi.world, G_loc[icrsh], lambda x, y: x + y) mpi.barrier() print_time("mpi.all_reduce") # G_loc[:] is now the sum over k projected to the local orbitals. # here comes the symmetrisation, if needed: if self.symm_op != 0: G_loc = self.symmcorr.symmetrize(G_loc) # G_loc is rotated to the local coordinate system: if self.use_rotations: for icrsh in range(self.n_corr_shells): for bname, gf in G_loc[icrsh]: G_loc[icrsh][bname] << self.rotloc( icrsh, gf, direction='toLocal') # transform to CTQMC blocks: for ish in range(self.n_inequiv_shells): for block, inner in self.gf_struct_solver[ish].items(): for ind1 in inner: for ind2 in inner: block_sumk, ind1_sumk = self.solver_to_sumk[ish][( block, ind1)] block_sumk, ind2_sumk = self.solver_to_sumk[ish][( block, ind2)] G_loc_inequiv[ish][block][ind1, ind2] << G_loc[ self.inequiv_to_corr[ish]][block_sumk][ind1_sumk, ind2_sumk] print_time("symm, rotations, solver_to_sumk") # print("End extract_G_loc") # print("=====================\n") # return only the inequivalent shells: return G_loc_inequiv