3
0
mirror of https://github.com/triqs/dft_tools synced 2024-10-31 11:13:46 +01:00

Reading vasptriqs.h5 file; reading GAMMA file for non-collinear full csc

This commit is contained in:
Dario Fiore Mosca 2024-05-06 10:30:17 +02:00 committed by the-hampel
parent f57080a6af
commit 75fbb9cbdb
2 changed files with 543 additions and 328 deletions

View File

@ -1,4 +1,3 @@
################################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
@ -44,6 +43,7 @@ from h5 import HDFArchive
log = logging.getLogger('plovasp.vaspio')
def read_lines(filename):
r"""
Generator of lines for a file
@ -57,6 +57,7 @@ def read_lines(filename):
for line in f:
yield line
################################################################################
################################################################################
#
@ -68,9 +69,21 @@ class VaspData:
"""
Container class for all VASP data.
"""
def __init__(self, vasp_dir, read_all=True, efermi_required=True):
self.vasp_dir = vasp_dir
# NEW vasptriqs.h5
vasptriqs = os.path.isfile(os.path.join(vasp_dir, 'vasptriqs.h5'))
if vasptriqs:
log.warning("Reading from vasptriqs.h5")
h5path = os.path.join(vasp_dir, 'vasptriqs.h5')
self.plocar = h5Plocar(h5path)
self.poscar = h5Poscar(h5path)
self.kpoints = h5Kpoints(h5path)
self.eigenval = h5Eigenval(h5path)
self.doscar = h5Doscar(h5path)
else:
self.plocar = Plocar()
self.poscar = Poscar()
self.kpoints = Kpoints()
@ -88,25 +101,27 @@ class VaspData:
self.eigenval.ferw = None
log.warning("Error reading from EIGENVAL, trying LOCPROJ...")
if efermi_required:
try:
with HDFArchive(vasp_dir + "vasptriqs.h5", 'r') as ar:
self.doscar.efermi = ar['triqs/efermi']
print(f'Fermi energy read from vasptriqs.h5: {self.doscar.efermi:.4f} eV')
self.doscar.from_file(vasp_dir)
except (IOError, StopIteration):
if efermi_required:
log.warning("Error reading Efermi from DOSCAR, trying LOCPROJ...")
try:
self.plocar.efermi
self.doscar.efermi = self.plocar.efermi
except NameError:
raise Exception("Efermi cannot be read from vasptriqs.h5 file")
raise Exception("Efermi cannot be read from DOSCAR or LOCPROJ")
else:
# TODO: This a hack. Find out a way to determine ncdij without DOSCAR
log.warning("Error reading Efermi from DOSCAR, taking from config")
self.doscar.ncdij = self.plocar.nspin
################################################################################
################################################################################
##########################
#
# class Plocar
#
################################################################################
################################################################################
##########################
class Plocar:
"""
Class containing raw PLO data from VASP.
@ -117,6 +132,7 @@ class Plocar:
- *ferw* (array(nion, ns, nk, nb)) : Fermi weights from VASP
"""
def __init__(self):
self.plo = None
self.proj_params = None
@ -141,7 +157,6 @@ class Plocar:
# self.proj_params, self.plo = self.temp_parser(projcar_filename=vasp_dir + "PROJCAR", locproj_filename=vasp_dir + "LOCPROJ")
self.proj_params, self.plo = self.locproj_parser(locproj_filename=vasp_dir + "LOCPROJ")
def locproj_parser(self, locproj_filename='LOCPROJ'):
r"""
Parses LOCPROJ (for VASP >= 5.4.2) to get VASP projectors.
@ -173,6 +188,11 @@ class Plocar:
self.nspin_band = 2 if self.ncdij == 2 else 1
try:
self.efermi = float(sline[4])
except:
log.warning("Error reading Efermi from LOCPROJ, trying DOSCAR...")
plo = np.zeros((nproj, self.nspin, nk, self.nband), dtype=complex)
proj_params = [{} for i in range(nproj)]
@ -244,7 +264,6 @@ class Plocar:
return proj_params, plo
def search_for(self, f, patt):
r"""
Reads file 'f' until pattern 'patt' is encountered and returns
@ -258,13 +277,11 @@ class Plocar:
return line
################################################################################
################################################################################
##########################
#
# class Poscar
#
################################################################################
################################################################################
##########################
class Poscar:
"""
Class containing POSCAR data from VASP.
@ -278,6 +295,7 @@ class Poscar:
- q_types ([numpy.array((nions, 3), dtype=float)]) : a list of
arrays each containing fractional coordinates of ions of a given type
"""
def __init__(self):
self.q_cart = None
@ -292,6 +310,7 @@ class Poscar:
plocar_filename (str) : filename [default = 'POSCAR']
"""
# Convenince local function
def readline_remove_comments():
return next(f).split('!')[0].split('#')[0].strip()
@ -370,19 +389,12 @@ class Poscar:
print(" Number of types:", self.ntypes)
print(" Number of ions for each type:", self.nions)
# print
# print " Coords:"
# for it in range(ntypes):
# print " Element:", el_names[it]
# print q_at[it]
################################################################################
################################################################################
##########################
#
# class Kpoints
#
################################################################################
################################################################################
##########################
class Kpoints:
"""
Class describing k-points and optionally tetrahedra.
@ -395,10 +407,12 @@ class Kpoints:
- volt (float) : volume of a tetrahedron (the k-grid is assumed to
be uniform)
"""
def __init__(self):
self.kpts = None
self.nktot = None
self.kwghts = None
#
# Reads IBZKPT file
#
@ -465,26 +479,17 @@ class Kpoints:
print(" No tetrahedron data found in %s. Skipping..." % (ibz_filename))
self.ntet = 0
# data = { 'nktot': nktot,
# 'kpts': kpts,
# 'ntet': ntet,
# 'itet': itet,
# 'volt': volt }
#
# return data
################################################################################
################################################################################
##########################
#
# class Eigenval
#
################################################################################
################################################################################
##########################
class Eigenval:
"""
Class containing Kohn-Sham-eigenvalues data from VASP (EIGENVAL file).
"""
def __init__(self):
self.eigs = None
self.ferw = None
@ -545,17 +550,16 @@ class Eigenval:
self.ferw[ik, ib, :] = tmp[self.ispin + 1:]
################################################################################
################################################################################
##########################
#
# class Doscar
#
################################################################################
################################################################################
##########################
class Doscar:
"""
Class containing some data from DOSCAR
"""
def __init__(self):
self.ncdij = None
self.efermi = None
@ -582,16 +586,18 @@ class Doscar:
sline = next(f).split()
self.efermi = float(sline[3])
# TODO: implement output of SYMMCAR in VASP and read it here
################################################################
##########################
#
# Reads SYMMCAR
#
################################################################
##########################
def read_symmcar(vasp_dir, symm_filename='SYMMCAR'):
"""
Reads SYMMCAR.
"""
# Shorthand for simple parsing
def extract_int_par(parname):
return int(re.findall(parname + '\s*=\s*(\d+)', line)[-1])
@ -654,3 +660,154 @@ def read_symmcar(vasp_dir, symm_filename='SYMMCAR'):
data.update({'nrot': nrot, 'ntrans': ntrans,
'lmax': lmax, 'nion': nion,
'sym_rots': rot_mats, 'perm_map': rot_map})
class h5Poscar:
def __init__(self, h5path):
# self.q_cart = None
with HDFArchive(h5path, 'a') as archive:
struct = archive['triqs']['structure']
ascale = struct['scale']
self.a_brav = struct['lattice_vectors']
self.nions = struct['number_ion_types']
self.el_names = struct['ion_types']
direct = struct['direct_coordinates']
qcoord = struct['position_ions']
if ascale < 0:
vscale = -ascale
vol = np.linalg.det(self.a_brav)
ascale = (vscale / vol) ** (1.0 / 3)
self.a_brav *= ascale
# determine reciprocal basis in units of 2*pi
self.kpt_basis = np.linalg.inv(self.a_brav.T)
# Set the number of atom sorts (types) and the total
# number of atoms in the unit cell
self.ntypes = len(self.nions)
self.nq = sum(self.nions)
# Read atomic positions
self.q_types = []
self.type_of_ion = []
for it in range(self.ntypes):
# Array mapping ion index to type
self.type_of_ion += self.nions[it] * [it]
q_at_it = np.zeros((self.nions[it], 3))
for iq in range(self.nions[it]):
if not direct:
qcoord = np.dot(self.kpt_basis, qcoord[iq + it])
q_at_it[iq, :] = qcoord[iq + it]
self.q_types.append(q_at_it)
print(" Total number of ions:", self.nq)
print(" Number of types:", self.ntypes)
print(" Number of ions for each type:", self.nions)
class h5Kpoints:
def __init__(self, h5path):
# h5path = './vasptriqs.h5'
with HDFArchive(h5path, 'a') as archive:
kpoints = archive['triqs']['kpoints']
self.nktot = kpoints['num_kpoints']
self.kpts = kpoints['kpoint_coords']
self.kwghts = kpoints['kpoints_symmetry_weight']
try:
self.ntet = kpoints['num_tetrahedra']
self.vtet = kpoints['volume_weight_tetrahedra']
self.itet = kpoints['coordinate_id_tetrahedra']
except StopIteration as ValueError:
print(" No tetrahedron data found in vasptriqs.h5. Skipping...")
self.ntet = 0
print()
print(" {0:>26} {1:d}".format("Total number of k-points:", self.nktot))
print(" {0:>26} {1:d}".format("Total number of tetrahedra:", self.ntet))
class h5Eigenval:
def __init__(self, h5path):
with HDFArchive(h5path, 'a') as archive:
self.eigs = archive['triqs']['eigenvalues']
self.ferw = archive['triqs']['fermi_weights']
# TODO Change the format in VASP to have [kpoints, bands, spin]
self.eigs = np.transpose(self.eigs, (1, 2, 0))
self.ferw = np.transpose(self.ferw, (1, 2, 0))
class h5Doscar:
def __init__(self, h5path):
with HDFArchive(h5path, 'a') as archive:
self.efermi = archive['triqs']['efermi']
class h5Plocar():
def __init__(self, h5path):
with HDFArchive(h5path, 'a') as archive:
plo = np.array(archive['triqs']['plo'])
self.nc_flag = int(archive['triqs']['noncoll'])
self.nproj = plo.shape[0]
self.ncdij = plo.shape[1]
nk = plo.shape[2]
self.nband = plo.shape[3]
self.nspin = self.ncdij if self.ncdij < 4 else 1
self.nspin_band = 2 if self.ncdij == 2 else 1
log.debug("ISPIN is {}".format(self.nspin))
log.debug("NC FLAG : {}".format(self.nc_flag))
# self.proj_params, self.plo = self.locproj_parser(locproj_filename=vasp_dir + "LOCPROJ")
orb_labels = ["s", "py", "pz", "px", "dxy", "dyz", "dz2", "dxz", "dx2-y2",
"fy(3x2-y2)", "fxyz", "fyz2", "fz3", "fxz2", "fz(x2-y2)", "fx(x2-3y2)"]
self.plo = np.zeros((self.nproj, self.nspin, nk, self.nband), dtype=complex)
for proj in range(self.nproj):
for spin in range(self.nspin):
for kpt in range(nk):
for band in range(self.nband):
real_plo = plo[proj, spin, kpt, band, 0] # Real part
imag_plo = plo[proj, spin, kpt, band, 1] # Imaginary part
self.plo[proj, spin, kpt, band] = complex(real_plo, imag_plo)
def lm_to_l_m(lm):
l = int(np.sqrt(lm))
m = lm - l * l
return l, m
self.proj_params = [{} for i in range(self.nproj)]
with HDFArchive(h5path, 'a') as archive:
for it in range(self.nproj):
projectors = archive['triqs']['plo_parameters'][str(it + 1)]
self.proj_params[it]['label'] = projectors['ang_type']
self.proj_params[it]['isite'] = projectors['site']
self.proj_params[it]['coord'] = projectors['coordinates']
for it in range(self.nproj):
lm = orb_labels.index(self.proj_params[it]['label'])
l, m = lm_to_l_m(lm)
self.proj_params[it]['l'] = l
if self.nc_flag == True:
if (it % 2) == 0:
self.proj_params[it]['m'] = 2 * m
else:
self.proj_params[it]['m'] = 2 * m + 1
else:
self.proj_params[it]['m'] = m
# assert ip == nproj, "Number of projectors in the header is wrong in LOCPROJ"
print("Read parameters: LOCPROJ")
for il, par in enumerate(self.proj_params):
print(il, " -> ", par)

View File

@ -1,4 +1,3 @@
##########################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
@ -122,26 +121,33 @@ class SumkDFT(object):
self.block_structure = BlockStructure()
# Read input from HDF:
req_things_to_read = ['energy_unit', 'n_k', 'k_dep_projection', 'SP', 'SO', 'charge_below', 'density_required',
'symm_op', 'n_shells', 'shells', 'n_corr_shells', 'corr_shells', 'use_rotations', 'rot_mat',
'rot_mat_time_inv', 'n_reps', 'dim_reps', 'T', 'n_orbitals', 'proj_mat', 'bz_weights', 'hopping',
req_things_to_read = ['energy_unit', 'n_k', 'k_dep_projection', 'SP', 'SO', 'charge_below',
'density_required',
'symm_op', 'n_shells', 'shells', 'n_corr_shells', 'corr_shells', 'use_rotations',
'rot_mat',
'rot_mat_time_inv', 'n_reps', 'dim_reps', 'T', 'n_orbitals', 'proj_mat', 'bz_weights',
'hopping',
'n_inequiv_shells', 'corr_to_inequiv', 'inequiv_to_corr']
self.subgroup_present, self.values_not_read = self.read_input_from_hdf(
subgrp=self.dft_data, things_to_read=req_things_to_read)
# test if all required properties have been found
if len(self.values_not_read) > 0 and mpi.is_master_node:
raise ValueError('ERROR: One or more necessary SumK input properties have not been found in the given h5 archive:', self.values_not_read)
raise ValueError(
'ERROR: One or more necessary SumK input properties have not been found in the given h5 archive:',
self.values_not_read)
# optional properties to load
# soon bz_weights is depraced and replaced by kpt_weights, kpts_basis and kpts will become required to read soon
optional_things_to_read = ['proj_mat_csc', 'proj_or_hk', 'kpt_basis', 'kpts', 'kpt_weights', 'dft_code']
subgroup_present, self.optional_values_not_read = self.read_input_from_hdf(subgrp=self.dft_data, things_to_read=optional_things_to_read)
subgroup_present, self.optional_values_not_read = self.read_input_from_hdf(subgrp=self.dft_data,
things_to_read=optional_things_to_read)
# warning if dft_code was not read (old h5 structure)
if 'dft_code' in self.optional_values_not_read:
self.dft_code = None
mpi.report('\nWarning: old h5 archive without dft_code input flag detected. Please specify sumk.dft_code manually!\n')
mpi.report(
'\nWarning: old h5 archive without dft_code input flag detected. Please specify sumk.dft_code manually!\n')
if self.symm_op:
self.symmcorr = Symmetry(hdf_file, subgroup=self.symmcorr_data)
@ -164,11 +170,13 @@ class SumkDFT(object):
# GF structure used for the local things in the k sums
# Most general form allowing for all hybridisation, i.e. largest
# blocks possible
self.gf_struct_sumk = [[(sp, self.corr_shells[icrsh]['dim']) for sp in self.spin_block_names[self.corr_shells[icrsh]['SO']]]
self.gf_struct_sumk = [
[(sp, self.corr_shells[icrsh]['dim']) for sp in self.spin_block_names[self.corr_shells[icrsh]['SO']]]
for icrsh in range(self.n_corr_shells)]
# First set a standard gf_struct solver (add _0 here for consistency with analyse_block_structure):
self.gf_struct_solver = [dict([(sp + '_0', self.corr_shells[self.inequiv_to_corr[ish]]['dim'])
for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]])
for sp in
self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]])
for ish in range(self.n_inequiv_shells)]
# Set standard (identity) maps from gf_struct_sumk <->
# gf_struct_solver
@ -653,9 +661,12 @@ class SumkDFT(object):
self.Sigma_imp = [self.block_structure.create_gf(ish=icrsh, mesh=Sigma_imp[icrsh].mesh, space='sumk')
for icrsh in range(self.n_corr_shells)]
SK_Sigma_imp = self.Sigma_imp
elif isinstance(self.mesh, MeshReFreq) and all(isinstance(gf, Gf) and isinstance(gf.mesh, MeshReFreq) and gf.mesh == self.mesh for bname, gf in Sigma_imp[0]):
elif isinstance(self.mesh, MeshReFreq) and all(
isinstance(gf, Gf) and isinstance(gf.mesh, MeshReFreq) and gf.mesh == self.mesh for bname, gf in
Sigma_imp[0]):
# Real frequency Sigma:
self.Sigma_imp = [self.block_structure.create_gf(ish=icrsh, mesh=Sigma_imp[icrsh].mesh, gf_function=Gf, space='sumk')
self.Sigma_imp = [
self.block_structure.create_gf(ish=icrsh, mesh=Sigma_imp[icrsh].mesh, gf_function=Gf, space='sumk')
for icrsh in range(self.n_corr_shells)]
SK_Sigma_imp = self.Sigma_imp
@ -677,8 +688,11 @@ class SumkDFT(object):
if self.min_band_energy is None or self.max_band_energy is None:
self.calculate_min_max_band_energies()
mesh = np.linspace(self.mesh.w_min, self.mesh.w_max, len(self.mesh))
if mesh[0] > (self.min_band_energy - self.chemical_potential) or mesh[-1] < (self.max_band_energy - self.chemical_potential):
warn('The given Sigma is on a mesh which does not cover the band energy range. The Sigma MeshReFreq runs from %f to %f, while the band energy (minus the chemical potential) runs from %f to %f'%(mesh[0], mesh[-1], self.min_band_energy, self.max_band_energy))
if mesh[0] > (self.min_band_energy - self.chemical_potential) or mesh[-1] < (
self.max_band_energy - self.chemical_potential):
warn(
'The given Sigma is on a mesh which does not cover the band energy range. The Sigma MeshReFreq runs from %f to %f, while the band energy (minus the chemical potential) runs from %f to %f' % (
mesh[0], mesh[-1], self.min_band_energy, self.max_band_energy))
def transform_to_sumk_blocks(self, Sigma_imp, Sigma_out=None):
r""" transform Sigma from solver to sumk space
@ -699,7 +713,8 @@ class SumkDFT(object):
"transform_to_sumk_blocks: give exactly one Sigma for each inequivalent corr. shell!"
if Sigma_out is None:
Sigma_out = [self.block_structure.create_gf(ish=icrsh, mesh=Sigma_imp[self.corr_to_inequiv[icrsh]].mesh, space='sumk')
Sigma_out = [self.block_structure.create_gf(ish=icrsh, mesh=Sigma_imp[self.corr_to_inequiv[icrsh]].mesh,
space='sumk')
for icrsh in range(self.n_corr_shells)]
else:
for icrsh in range(self.n_corr_shells):
@ -876,10 +891,12 @@ class SumkDFT(object):
"""
if dm is None:
warn("WARNING: No density matrix given. Calculating density matrix with default parameters. This will be deprecated in future releases.")
warn(
"WARNING: No density matrix given. Calculating density matrix with default parameters. This will be deprecated in future releases.")
dm = self.density_matrix(method='using_gf', transform_to_solver_blocks=False)
assert len(dm) == self.n_corr_shells, "The number of density matrices must be equal to the number of correlated shells."
assert len(
dm) == self.n_corr_shells, "The number of density matrices must be equal to the number of correlated shells."
dens_mat = [dm[self.inequiv_to_corr[ish]]
for ish in range(self.n_inequiv_shells)]
if hloc is None:
@ -894,7 +911,8 @@ class SumkDFT(object):
self.solver_to_sumk_block[ish] = {}
for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]:
assert sp in dens_mat[ish], f"The density matrix does not contain the block {sp}. Is the input dm given in sumk block structure?"
assert sp in dens_mat[
ish], f"The density matrix does not contain the block {sp}. Is the input dm given in sumk block structure?"
n_orb = self.corr_shells[self.inequiv_to_corr[ish]]['dim']
# gives an index list of entries larger that threshold
dmbool = (abs(dens_mat[ish][sp]) > threshold)
@ -994,7 +1012,8 @@ class SumkDFT(object):
# make a GfImTime from the supplied GfImFreq
if all(isinstance(g_sh.mesh, MeshImFreq) for g_sh in G):
gf = [BlockGf(name_block_generator=[(name, GfImTime(beta=block.mesh.beta,
indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh],
indices=block.indices, n_points=len(block.mesh) + 1))
for name, block in g_sh],
make_copies=False) for g_sh in G]
for ish in range(len(gf)):
for name, g in gf[ish]:
@ -1016,6 +1035,7 @@ class SumkDFT(object):
w0 = w
else:
return w - w0
gf = [BlockGf(name_block_generator=[(name, GfReFreq(
window=(-np.pi * (len(block.mesh) - 1) / (len(block.mesh) * get_delta_from_mesh(block.mesh)),
np.pi * (len(block.mesh) - 1) / (len(block.mesh) * get_delta_from_mesh(block.mesh))),
@ -1030,8 +1050,6 @@ class SumkDFT(object):
raise Exception("G must be a list of BlockGf of either GfImFreq, GfImTime, GfReFreq or GfReTime")
return gf
def analyse_block_structure_from_gf(self, G, threshold=1.e-5, include_shells=None, analyse_deg_shells=True):
r"""
Determines the block structure of local Green's functions by analysing
@ -1065,7 +1083,8 @@ class SumkDFT(object):
"""
assert isinstance(G, list), "G must be a list (with elements for each correlated shell)"
assert len(G) == self.n_corr_shells, "G must have one element for each correlated shell, run extract_G_loc with transform_to_solver_blocks=False to get the correct G"
assert len(
G) == self.n_corr_shells, "G must have one element for each correlated shell, run extract_G_loc with transform_to_solver_blocks=False to get the correct G"
gf = self._get_hermitian_quantity_from_gf(G)
@ -1079,7 +1098,8 @@ class SumkDFT(object):
self.solver_to_sumk[ish] = {}
self.solver_to_sumk_block[ish] = {}
for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]:
assert sp in gf[self.inequiv_to_corr[ish]].indices, f"The Green's function does not contain the block {sp}. Is the input G given in sumk block structure?"
assert sp in gf[self.inequiv_to_corr[
ish]].indices, f"The Green's function does not contain the block {sp}. Is the input G given in sumk block structure?"
n_orb = self.corr_shells[self.inequiv_to_corr[ish]]['dim']
# gives an index list of entries larger that threshold
@ -1248,13 +1268,15 @@ class SumkDFT(object):
# product to get a linear problem, which consists
# of finding the null space of M vec T = 0.
M = np.kron(np.eye(*gf1.target_shape),gf2.data[0])-np.kron(gf1.data[0].transpose(),np.eye(*gf1.target_shape))
M = np.kron(np.eye(*gf1.target_shape), gf2.data[0]) - np.kron(gf1.data[0].transpose(),
np.eye(*gf1.target_shape))
N = null(M, threshold)
# now we get the intersection of the null spaces
# of all values of tau
for i in range(1, len(gf1.data)):
M = np.kron(np.eye(*gf1.target_shape),gf2.data[i])-np.kron(gf1.data[i].transpose(),np.eye(*gf1.target_shape))
M = np.kron(np.eye(*gf1.target_shape), gf2.data[i]) - np.kron(gf1.data[i].transpose(),
np.eye(*gf1.target_shape))
# transform M into current null space
M = np.dot(M, N)
N = np.dot(N, null(M, threshold))
@ -1288,6 +1310,7 @@ class SumkDFT(object):
Then, it calculates the chi2 of
sum y[i] N[:,:,i] y[j].conjugate() N[:,:,j].conjugate().transpose() - eye.
"""
def chi2(y):
# reinterpret y as complex number
y = y.view(complex)
@ -1348,7 +1371,8 @@ class SumkDFT(object):
# C1(v1^dagger G1 v1) = C2(v2^dagger G2 v2)
if (ind1 < 0) and (ind2 >= 0):
if conjugate:
self.deg_shells[ish][ind2][block1] = np.dot(T.conjugate().transpose(), v2[0].conjugate()), not v2[1]
self.deg_shells[ish][ind2][block1] = np.dot(T.conjugate().transpose(),
v2[0].conjugate()), not v2[1]
else:
self.deg_shells[ish][ind2][block1] = np.dot(T.conjugate().transpose(), v2[0]), v2[1]
# the first block is already present
@ -1379,7 +1403,8 @@ class SumkDFT(object):
# a block was found, break out of the loop
break
def calculate_diagonalization_matrix(self, prop_to_be_diagonal='eal', calc_in_solver_blocks=True, write_to_blockstructure = True, shells=None):
def calculate_diagonalization_matrix(self, prop_to_be_diagonal='eal', calc_in_solver_blocks=True,
write_to_blockstructure=True, shells=None):
"""
Calculates the diagonalisation matrix, and (optionally) stores it in the BlockStructure.
@ -1515,12 +1540,12 @@ class SumkDFT(object):
for sp in dens_mat[icrsh]:
if self.rot_mat_time_inv[icrsh] == 1:
dens_mat[icrsh][sp] = dens_mat[icrsh][sp].conjugate()
dens_mat[icrsh][sp] = np.dot(np.dot(self.rot_mat[icrsh].conjugate().transpose(), dens_mat[icrsh][sp]),
dens_mat[icrsh][sp] = np.dot(
np.dot(self.rot_mat[icrsh].conjugate().transpose(), dens_mat[icrsh][sp]),
self.rot_mat[icrsh])
return dens_mat
def density_matrix(self, method='using_gf', mu=None, with_Sigma=True, with_dc=True, broadening=None,
transform_to_solver_blocks=True, show_warnings=True):
"""Calculate density matrices in one of two ways.
@ -1562,7 +1587,8 @@ class SumkDFT(object):
transform_to_solver_blocks, show_warnings)
dens_mat = [G.density() for G in Gloc]
elif method == "using_point_integration":
warn("WARNING: density_matrix: method 'using_point_integration' is deprecated. Use 'density_matrix_using_point_integration' instead. All additionally provided arguments are ignored.")
warn(
"WARNING: density_matrix: method 'using_point_integration' is deprecated. Use 'density_matrix_using_point_integration' instead. All additionally provided arguments are ignored.")
dens_mat = self.density_matrix_using_point_integration()
else:
raise ValueError("density_matrix: the method '%s' is not supported." % method)
@ -1637,7 +1663,8 @@ class SumkDFT(object):
if self.rot_mat_time_inv[icrsh] == 1:
self.Hsumk[icrsh][sp] = self.Hsumk[
icrsh][sp].conjugate()
self.Hsumk[icrsh][sp] = np.dot(np.dot(self.rot_mat[icrsh].conjugate().transpose(), self.Hsumk[icrsh][sp]),
self.Hsumk[icrsh][sp] = np.dot(
np.dot(self.rot_mat[icrsh].conjugate().transpose(), self.Hsumk[icrsh][sp]),
self.rot_mat[icrsh])
# add to matrix:
@ -1773,7 +1800,8 @@ class SumkDFT(object):
use_dc_formula = "sAMF"
for sp in spn:
DC_val, E_val = compute_DC_from_density(N_tot=Ncrtot,U=U_interact, J=J_hund, n_orbitals=dim, N_spin=Ncr[sp], method=use_dc_formula)
DC_val, E_val = compute_DC_from_density(N_tot=Ncrtot, U=U_interact, J=J_hund, n_orbitals=dim,
N_spin=Ncr[sp], method=use_dc_formula)
self.dc_imp[icrsh][sp] *= DC_val
self.dc_energ[icrsh] = E_val
@ -1968,9 +1996,11 @@ class SumkDFT(object):
beta = 1 / broadening
if isinstance(self.mesh, MeshReFreq):
def tot_den(bgf): return bgf.total_density(beta)
def tot_den(bgf):
return bgf.total_density(beta)
else:
def tot_den(bgf): return bgf.total_density()
def tot_den(bgf):
return bgf.total_density()
dens = 0.0
ikarray = np.array(list(range(self.n_k)))
@ -2030,6 +2060,7 @@ class SumkDFT(object):
within specified precision.
"""
def find_bounds(function, x_init, delta_x, max_loops=1000):
mpi.report("Finding bounds on chemical potential")
x = x_init
@ -2064,8 +2095,11 @@ class SumkDFT(object):
# previous implementation
def F_bisection(mu): return self.total_density(mu=mu, broadening=broadening, beta=beta).real
def F_bisection(mu):
return self.total_density(mu=mu, broadening=broadening, beta=beta).real
density = self.density_required - self.charge_below
# using scipy.optimize
def F_optimize(mu):
@ -2119,7 +2153,8 @@ class SumkDFT(object):
return self.chemical_potential
def calc_density_correction(self, filename=None, dm_type=None, spinave=False, kpts_to_write=None, broadening=None, beta=None):
def calc_density_correction(self, filename=None, dm_type=None, spinave=False, kpts_to_write=None, broadening=None,
beta=None):
r"""
Calculates the charge density correction and stores it into a file.
@ -2175,7 +2210,6 @@ class SumkDFT(object):
elif dm_type == 'qe':
filename = self.hdf_file
assert isinstance(filename, str), ("calc_density_correction: "
"filename has to be a string!")
@ -2203,7 +2237,6 @@ class SumkDFT(object):
for sp in spn:
dens_mat_dft[sp] = [fermi_weights[ik, ntoi[sp], :].astype(complex) for ik in range(self.n_k)]
# Set up deltaN:
deltaN = {}
for sp in spn:
@ -2240,13 +2273,15 @@ class SumkDFT(object):
G2 = np.sum(self.kpts_cart[ik, :] ** 2)
# Kerker mixing
mix_fac = self.charge_mixing_alpha * G2 / (G2 + self.charge_mixing_gamma ** 2)
deltaN[bname][ik][diag_inds] = (1.0 - mix_fac) * self.deltaNOld[bname][ik][diag_inds] + mix_fac * deltaN[bname][ik][diag_inds]
deltaN[bname][ik][diag_inds] = (1.0 - mix_fac) * self.deltaNOld[bname][ik][
diag_inds] + mix_fac * deltaN[bname][ik][diag_inds]
dens[bname] -= self.bz_weights[ik] * dens_mat_dft[bname][ik].sum().real
isp = ntoi[bname]
b1, b2 = band_window[isp][ik, :2]
nb = b2 - b1 + 1
assert nb == self.n_orbitals[ik, ntoi[bname]], "Number of bands is inconsistent at ik = %s" % (ik)
band_en_correction += np.dot(deltaN[bname][ik], self.hopping[ik, isp, :nb, :nb]).trace().real * self.bz_weights[ik]
band_en_correction += np.dot(deltaN[bname][ik], self.hopping[ik, isp, :nb, :nb]).trace().real * \
self.bz_weights[ik]
# mpi reduce:
for bname in deltaN:
@ -2256,8 +2291,6 @@ class SumkDFT(object):
self.deltaNOld = copy.copy(deltaN)
mpi.barrier()
band_en_correction = mpi.all_reduce(band_en_correction)
# now save to file:
@ -2328,6 +2361,11 @@ class SumkDFT(object):
f.write(" %i %i %i\n" % (index + 1, ib1, ib2))
for inu in range(self.n_orbitals[ik, 0]):
for imu in range(self.n_orbitals[ik, 0]):
if (self.SO == 1):
valre = (deltaN['ud'][ik][inu, imu].real) / 1.0
valim = (deltaN['ud'][ik][inu, imu].imag) / 1.0
f.write(" %.14f %.14f" % (valre, valim))
else:
valre = (deltaN['up'][ik][inu, imu].real + deltaN['down'][ik][inu, imu].real) / 2.0
valim = (deltaN['up'][ik][inu, imu].imag + deltaN['down'][ik][inu, imu].imag) / 2.0
f.write(" %.14f %.14f" % (valre, valim))
@ -2357,7 +2395,8 @@ class SumkDFT(object):
beta = self.mesh.beta * self.energy_unit
mu = self.chemical_potential / self.energy_unit
# ouput n_k, nspin and max orbitals - a check
f.write(" %d %d %d %.14f %.14f ! nkpt, nspin, nstmax, beta, mu\n"%(self.n_k, n_spin_blocks, nbmax, beta, mu))
f.write(" %d %d %d %.14f %.14f ! nkpt, nspin, nstmax, beta, mu\n" % (
self.n_k, n_spin_blocks, nbmax, beta, mu))
for ik in range(self.n_k):
for ispn in range(n_spin_blocks):
# Determine the SO density matrix band indices from the spinor band indices
@ -2375,8 +2414,10 @@ class SumkDFT(object):
for imu in range(self.n_orbitals[ik, ispn]):
# output non-magnetic or spin-averaged density matrix
if ((self.SP == 0) or (spinave)):
valre = (deltaN['up'][ik][inu, imu].real + deltaN['down'][ik][inu, imu].real) / 2.0
valim = (deltaN['up'][ik][inu, imu].imag + deltaN['down'][ik][inu, imu].imag) / 2.0
valre = (deltaN['up'][ik][inu, imu].real + deltaN['down'][ik][
inu, imu].real) / 2.0
valim = (deltaN['up'][ik][inu, imu].imag + deltaN['down'][ik][
inu, imu].imag) / 2.0
else:
valre = deltaN[spn[ispn]][ik][inu, imu].real
valim = deltaN[spn[ispn]][ik][inu, imu].imag
@ -2385,7 +2426,8 @@ class SumkDFT(object):
elif dm_type == 'qe':
if self.SP == 0:
mpi.report("SUMK calc_density_correction: WARNING! Averaging out spin-polarized correction in the density channel")
mpi.report(
"SUMK calc_density_correction: WARNING! Averaging out spin-polarized correction in the density channel")
subgrp = 'dft_update'
delta_N = np.zeros([self.n_k, max(self.n_orbitals[:, 0]), max(self.n_orbitals[:, 0])], dtype=complex)
@ -2482,38 +2524,50 @@ class SumkDFT(object):
# after introducing the block_structure class
def __get_gf_struct_sumk(self):
return self.block_structure.gf_struct_sumk
def __set_gf_struct_sumk(self, value):
self.block_structure.gf_struct_sumk = value
gf_struct_sumk = property(__get_gf_struct_sumk, __set_gf_struct_sumk)
def __get_gf_struct_solver(self):
return self.block_structure.gf_struct_solver
def __set_gf_struct_solver(self, value):
self.block_structure.gf_struct_solver = value
gf_struct_solver = property(__get_gf_struct_solver, __set_gf_struct_solver)
def __get_solver_to_sumk(self):
return self.block_structure.solver_to_sumk
def __set_solver_to_sumk(self, value):
self.block_structure.solver_to_sumk = value
solver_to_sumk = property(__get_solver_to_sumk, __set_solver_to_sumk)
def __get_sumk_to_solver(self):
return self.block_structure.sumk_to_solver
def __set_sumk_to_solver(self, value):
self.block_structure.sumk_to_solver = value
sumk_to_solver = property(__get_sumk_to_solver, __set_sumk_to_solver)
def __get_solver_to_sumk_block(self):
return self.block_structure.solver_to_sumk_block
def __set_solver_to_sumk_block(self, value):
self.block_structure.solver_to_sumk_block = value
solver_to_sumk_block = property(__get_solver_to_sumk_block, __set_solver_to_sumk_block)
def __get_deg_shells(self):
return self.block_structure.deg_shells
def __set_deg_shells(self, value):
self.block_structure.deg_shells = value
deg_shells = property(__get_deg_shells, __set_deg_shells)
@property
@ -2534,12 +2588,16 @@ class SumkDFT(object):
def __get_corr_to_inequiv(self):
return self.block_structure.corr_to_inequiv
def __set_corr_to_inequiv(self, value):
self.block_structure.corr_to_inequiv = value
corr_to_inequiv = property(__get_corr_to_inequiv, __set_corr_to_inequiv)
def __get_inequiv_to_corr(self):
return self.block_structure.inequiv_to_corr
def __set_inequiv_to_corr(self, value):
self.block_structure.inequiv_to_corr = value
inequiv_to_corr = property(__get_inequiv_to_corr, __set_inequiv_to_corr)