mirror of
https://github.com/triqs/dft_tools
synced 2024-12-22 12:23:41 +01:00
Simplify SK construction
* recompute maps every time SK called rather than saving them * user saves and feeds in chemical potential and dc manually * set_dc sets dc to known values (eg from previous calculations) while calc_dc computes them * find_mu -> calc_mu to match API for other functions
This commit is contained in:
parent
172de04bff
commit
b90e1e80e2
@ -70,7 +70,7 @@ for Iteration_Number in range(1,Loops+1):
|
|||||||
|
|
||||||
# Compute the SumK, possibly fixing mu by dichotomy
|
# Compute the SumK, possibly fixing mu by dichotomy
|
||||||
if SK.density_required and (Iteration_Number > 0):
|
if SK.density_required and (Iteration_Number > 0):
|
||||||
Chemical_potential = SK.find_mu( precision = 0.01 )
|
Chemical_potential = SK.calc_mu( precision = 0.01 )
|
||||||
else:
|
else:
|
||||||
mpi.report("No adjustment of chemical potential\nTotal density = %.3f"%SK.total_density(mu=Chemical_potential))
|
mpi.report("No adjustment of chemical potential\nTotal density = %.3f"%SK.total_density(mu=Chemical_potential))
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ for Iteration_Number in range(1,Loops+1):
|
|||||||
dm = S.G.density()
|
dm = S.G.density()
|
||||||
|
|
||||||
if ((Iteration_Number==1)and(previous_present==False)):
|
if ((Iteration_Number==1)and(previous_present==False)):
|
||||||
SK.set_dc( dens_mat=dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type, use_val=use_val)
|
SK.calc_dc( dens_mat=dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type, use_val=use_val)
|
||||||
|
|
||||||
# set atomic levels:
|
# set atomic levels:
|
||||||
eal = SK.eff_atomic_levels()[0]
|
eal = SK.eff_atomic_levels()[0]
|
||||||
@ -119,7 +119,7 @@ for Iteration_Number in range(1,Loops+1):
|
|||||||
|
|
||||||
# after the Solver has finished, set new double counting:
|
# after the Solver has finished, set new double counting:
|
||||||
dm = S.G.density()
|
dm = S.G.density()
|
||||||
SK.set_dc( dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type , use_val=use_val)
|
SK.calc_dc( dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type , use_val=use_val)
|
||||||
# correlation energy calculations:
|
# correlation energy calculations:
|
||||||
correnerg = 0.5 * (S.G * S.Sigma).total_density()
|
correnerg = 0.5 * (S.G * S.Sigma).total_density()
|
||||||
mpi.report("Corr. energy = %s"%correnerg)
|
mpi.report("Corr. energy = %s"%correnerg)
|
||||||
@ -153,7 +153,7 @@ for Iteration_Number in range(1,Loops+1):
|
|||||||
|
|
||||||
# find exact chemical potential
|
# find exact chemical potential
|
||||||
if (SK.density_required):
|
if (SK.density_required):
|
||||||
SK.chemical_potential = SK.find_mu( precision = 0.000001 )
|
SK.chemical_potential = SK.calc_mu( precision = 0.000001 )
|
||||||
dN,d = SK.calc_density_correction(filename = dft_filename+'.qdmft')
|
dN,d = SK.calc_density_correction(filename = dft_filename+'.qdmft')
|
||||||
|
|
||||||
mpi.report("Trace of Density Matrix: %s"%d)
|
mpi.report("Trace of Density Matrix: %s"%d)
|
||||||
|
@ -92,7 +92,7 @@ set up the loop over DMFT iterations and the self-consistency condition::
|
|||||||
for iteration_number in range(n_loops) : # start the DMFT loop
|
for iteration_number in range(n_loops) : # start the DMFT loop
|
||||||
|
|
||||||
SK.put_Sigma(Sigma_imp = [ S.Sigma ]) # Put self energy to the SumK class
|
SK.put_Sigma(Sigma_imp = [ S.Sigma ]) # Put self energy to the SumK class
|
||||||
chemical_potential = SK.find_mu() # find the chemical potential for the given density
|
chemical_potential = SK.calc_mu() # calculate the chemical potential for the given density
|
||||||
S.G << SK.extract_G_loc()[0] # extract the local Green function
|
S.G << SK.extract_G_loc()[0] # extract the local Green function
|
||||||
S.G0 << inverse(S.Sigma + inverse(S.G)) # finally get G0, the input for the Solver
|
S.G0 << inverse(S.Sigma + inverse(S.G)) # finally get G0, the input for the Solver
|
||||||
|
|
||||||
@ -101,13 +101,13 @@ set up the loop over DMFT iterations and the self-consistency condition::
|
|||||||
length_cycle=200,n_warmup_cycles=1000)
|
length_cycle=200,n_warmup_cycles=1000)
|
||||||
|
|
||||||
dm = S.G.density() # Density matrix of the impurity problem
|
dm = S.G.density() # Density matrix of the impurity problem
|
||||||
SK.set_dc( dm, U_interact = U, J_hund = J, use_dc_formula = 0) # Set the double counting term
|
SK.calc_dc( dm, U_interact = U, J_hund = J, use_dc_formula = 0) # Set the double counting term
|
||||||
SK.save(['chemical_potential','dc_imp','dc_energ']) # Save data in the hdf5 archive
|
SK.save(['chemical_potential','dc_imp','dc_energ']) # Save data in the hdf5 archive
|
||||||
|
|
||||||
These basic steps are enough to set up the basic DMFT Loop. For a detailed description of the :class:`SumkDFT` routines,
|
These basic steps are enough to set up the basic DMFT Loop. For a detailed description of the :class:`SumkDFT` routines,
|
||||||
see the reference manual. After the self-consistency steps, the solution of the Anderson impurity problem is calculation by CTQMC.
|
see the reference manual. After the self-consistency steps, the solution of the Anderson impurity problem is calculation by CTQMC.
|
||||||
Different to model calculations, we have to do a few more steps after this, because of the double-counting correction. We first
|
Different to model calculations, we have to do a few more steps after this, because of the double-counting correction. We first
|
||||||
calculate the density of the impurity problem. Then, the routine `set_dc` takes as parameters this density matrix, the
|
calculate the density of the impurity problem. Then, the routine `calc_dc` takes as parameters this density matrix, the
|
||||||
Coulomb interaction, Hund's rule coupling, and the type of double-counting that should be used. Possible values for `use_dc_formula` are:
|
Coulomb interaction, Hund's rule coupling, and the type of double-counting that should be used. Possible values for `use_dc_formula` are:
|
||||||
|
|
||||||
* `0`: Full-localised limit
|
* `0`: Full-localised limit
|
||||||
|
@ -89,14 +89,14 @@ previous section, with some additional refinement::
|
|||||||
SK.symm_deg_gf(S.Sigma,orb=0) # symmetrise Sigma
|
SK.symm_deg_gf(S.Sigma,orb=0) # symmetrise Sigma
|
||||||
SK.put_Sigma(Sigma_imp = [ S.Sigma ]) # put Sigma into the SumK class:
|
SK.put_Sigma(Sigma_imp = [ S.Sigma ]) # put Sigma into the SumK class:
|
||||||
|
|
||||||
chemical_potential = SK.find_mu( precision = prec_mu ) # find the chemical potential
|
chemical_potential = SK.calc_mu( precision = prec_mu ) # find the chemical potential
|
||||||
S.G << SK.extract_G_loc()[0] # calculation of the local Green function
|
S.G << SK.extract_G_loc()[0] # calculation of the local Green function
|
||||||
mpi.report("Total charge of Gloc : %.6f"%S.G.total_density())
|
mpi.report("Total charge of Gloc : %.6f"%S.G.total_density())
|
||||||
|
|
||||||
if ((iteration_number==1)and(previous_present==False)):
|
if ((iteration_number==1)and(previous_present==False)):
|
||||||
# Init the DC term and the real part of Sigma, if no previous run was found:
|
# Init the DC term and the real part of Sigma, if no previous run was found:
|
||||||
dm = S.G.density()
|
dm = S.G.density()
|
||||||
SK.set_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
SK.calc_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
||||||
S.Sigma << SK.dc_imp[0]['up'][0,0]
|
S.Sigma << SK.dc_imp[0]['up'][0,0]
|
||||||
|
|
||||||
S.G0 << inverse(S.Sigma + inverse(S.G))
|
S.G0 << inverse(S.Sigma + inverse(S.G))
|
||||||
@ -141,7 +141,7 @@ previous section, with some additional refinement::
|
|||||||
|
|
||||||
# Now set new double counting:
|
# Now set new double counting:
|
||||||
dm = S.G.density()
|
dm = S.G.density()
|
||||||
SK.set_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
SK.calc_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
||||||
|
|
||||||
#Save stuff:
|
#Save stuff:
|
||||||
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
||||||
|
@ -34,7 +34,7 @@ Now we calculate the modified charge density::
|
|||||||
|
|
||||||
# find exact chemical potential
|
# find exact chemical potential
|
||||||
SK.put_Sigma(Sigma_imp = [ S.Sigma ])
|
SK.put_Sigma(Sigma_imp = [ S.Sigma ])
|
||||||
chemical_potential = SK.find_mu( precision = 0.000001 )
|
chemical_potential = SK.calc_mu( precision = 0.000001 )
|
||||||
dN, d = SK.calc_density_correction(filename = dft_filename+'.qdmft')
|
dN, d = SK.calc_density_correction(filename = dft_filename+'.qdmft')
|
||||||
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
||||||
|
|
||||||
|
@ -73,14 +73,14 @@ for iteration_number in range(1,loops+1):
|
|||||||
|
|
||||||
SK.symm_deg_gf(S.Sigma_iw,orb=0) # symmetrise Sigma
|
SK.symm_deg_gf(S.Sigma_iw,orb=0) # symmetrise Sigma
|
||||||
SK.put_Sigma(Sigma_imp = [ S.Sigma_iw ]) # put Sigma into the SumK class
|
SK.put_Sigma(Sigma_imp = [ S.Sigma_iw ]) # put Sigma into the SumK class
|
||||||
chemical_potential = SK.find_mu( precision = prec_mu ) # find the chemical potential for the given density
|
chemical_potential = SK.calc_mu( precision = prec_mu ) # find the chemical potential for the given density
|
||||||
S.G_iw << SK.extract_G_loc()[0] # extract the local Green function
|
S.G_iw << SK.extract_G_loc()[0] # extract the local Green function
|
||||||
mpi.report("Total charge of Gloc : %.6f"%S.G_iw.total_density())
|
mpi.report("Total charge of Gloc : %.6f"%S.G_iw.total_density())
|
||||||
|
|
||||||
if ((iteration_number==1)and(previous_present==False)):
|
if ((iteration_number==1)and(previous_present==False)):
|
||||||
# Init the DC term and the real part of Sigma, if no previous run was found:
|
# Init the DC term and the real part of Sigma, if no previous run was found:
|
||||||
dm = S.G_iw.density()
|
dm = S.G_iw.density()
|
||||||
SK.set_dc(dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
SK.calc_dc(dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
||||||
S.Sigma_iw << SK.dc_imp[0]['up'][0,0]
|
S.Sigma_iw << SK.dc_imp[0]['up'][0,0]
|
||||||
|
|
||||||
# now calculate new G0_iw to input into the solver:
|
# now calculate new G0_iw to input into the solver:
|
||||||
@ -126,7 +126,7 @@ for iteration_number in range(1,loops+1):
|
|||||||
|
|
||||||
dm = S.G_iw.density() # compute the density matrix of the impurity problem
|
dm = S.G_iw.density() # compute the density matrix of the impurity problem
|
||||||
# Set the double counting
|
# Set the double counting
|
||||||
SK.set_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
SK.calc_dc( dm, U_interact = U, J_hund = J, orb = 0, use_dc_formula = dc_type)
|
||||||
|
|
||||||
# Save stuff into the dft_output group of hdf5 archive in case of rerun:
|
# Save stuff into the dft_output group of hdf5 archive in case of rerun:
|
||||||
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
SK.save(['chemical_potential','dc_imp','dc_energ'])
|
||||||
|
@ -3,7 +3,6 @@ from scipy.misc import factorial as fact
|
|||||||
from itertools import product
|
from itertools import product
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
# The interaction matrix in desired basis
|
# The interaction matrix in desired basis
|
||||||
# U^{spherical}_{m1 m2 m3 m4} = \sum_{k=0}^{2l} F_k angular_matrix_element(l, k, m1, m2, m3, m4)
|
# U^{spherical}_{m1 m2 m3 m4} = \sum_{k=0}^{2l} F_k angular_matrix_element(l, k, m1, m2, m3, m4)
|
||||||
def U_matrix(l, radial_integrals=None, U_int=None, J_hund=None, basis="spherical", T=None):
|
def U_matrix(l, radial_integrals=None, U_int=None, J_hund=None, basis="spherical", T=None):
|
||||||
@ -207,7 +206,6 @@ def clebsch_gordan(jm1, jm2, jm3):
|
|||||||
# column 0 for 1st dim,
|
# column 0 for 1st dim,
|
||||||
# columns 2 and 3 for 2nd dim,
|
# columns 2 and 3 for 2nd dim,
|
||||||
# columns 0,1,2 and 3 for 3rd dim.
|
# columns 0,1,2 and 3 for 3rd dim.
|
||||||
#def subarray(a,idxlist,n=len(a.shape)-1) :
|
|
||||||
def subarray(a,idxlist,n=None) :
|
def subarray(a,idxlist,n=None) :
|
||||||
if n is None: n = len(a.shape)-1
|
if n is None: n = len(a.shape)-1
|
||||||
sa = a[tuple(slice(x) for x in a.shape[:n]) + (idxlist[n],)]
|
sa = a[tuple(slice(x) for x in a.shape[:n]) + (idxlist[n],)]
|
||||||
|
@ -13,7 +13,7 @@ and to restore it to the original post-converter state.
|
|||||||
|
|
||||||
filename = sys.argv[1]
|
filename = sys.argv[1]
|
||||||
A = h5py.File(filename)
|
A = h5py.File(filename)
|
||||||
for group in ['dft_output','dmft_output']:
|
for group in ['dft_output','user_data']:
|
||||||
if group in A: del(A[group])
|
if group in A: del(A[group])
|
||||||
A.close()
|
A.close()
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ class SumkDFT:
|
|||||||
"""This class provides a general SumK method for combining ab-initio code and pytriqs."""
|
"""This class provides a general SumK method for combining ab-initio code and pytriqs."""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, hdf_file, mu = 0.0, h_field = 0.0, use_dft_blocks = False,
|
def __init__(self, hdf_file, h_field = 0.0, use_dft_blocks = False,
|
||||||
dft_data = 'dft_input', symmcorr_data = 'dft_symmcorr_input', parproj_data = 'dft_parproj_input',
|
dft_data = 'dft_input', symmcorr_data = 'dft_symmcorr_input', parproj_data = 'dft_parproj_input',
|
||||||
symmpar_data = 'dft_symmpar_input', bands_data = 'dft_bands_input', dft_output = 'dft_output'):
|
symmpar_data = 'dft_symmpar_input', bands_data = 'dft_bands_input'):
|
||||||
"""
|
"""
|
||||||
Initialises the class from data previously stored into an HDF5
|
Initialises the class from data previously stored into an HDF5
|
||||||
"""
|
"""
|
||||||
@ -48,16 +48,16 @@ class SumkDFT:
|
|||||||
self.parproj_data = parproj_data
|
self.parproj_data = parproj_data
|
||||||
self.symmpar_data = symmpar_data
|
self.symmpar_data = symmpar_data
|
||||||
self.bands_data = bands_data
|
self.bands_data = bands_data
|
||||||
self.dft_output = dft_output
|
|
||||||
self.G_upfold = None
|
self.G_upfold = None
|
||||||
self.h_field = h_field
|
self.h_field = h_field
|
||||||
|
|
||||||
# read input from HDF:
|
# Read input from HDF:
|
||||||
things_to_read = ['energy_unit','n_k','k_dep_projection','SP','SO','charge_below','density_required',
|
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',
|
'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',
|
'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']
|
'n_inequiv_shells', 'corr_to_inequiv', 'inequiv_to_corr']
|
||||||
self.subgroup_present, self.value_read = self.read_input_from_hdf(subgrp = self.dft_data, things_to_read = things_to_read)
|
self.subgroup_present, self.value_read = self.read_input_from_hdf(subgrp = self.dft_data, things_to_read = things_to_read)
|
||||||
|
if self.symm_op: self.symmcorr = Symmetry(hdf_file,subgroup=self.symmcorr_data)
|
||||||
|
|
||||||
if self.SO and (abs(self.h_field) > 0.000001):
|
if self.SO and (abs(self.h_field) > 0.000001):
|
||||||
self.h_field = 0.0
|
self.h_field = 0.0
|
||||||
@ -65,7 +65,7 @@ class SumkDFT:
|
|||||||
|
|
||||||
self.spin_block_names = [ ['up','down'], ['ud'] ]
|
self.spin_block_names = [ ['up','down'], ['ud'] ]
|
||||||
self.n_spin_blocks = [2,1]
|
self.n_spin_blocks = [2,1]
|
||||||
# convert spin_block_names to indices -- if spin polarized, differentiate up and down blocks
|
# Convert spin_block_names to indices -- if spin polarized, differentiate up and down blocks
|
||||||
self.spin_names_to_ind = [{}, {}]
|
self.spin_names_to_ind = [{}, {}]
|
||||||
for iso in range(2): # SO = 0 or 1
|
for iso in range(2): # SO = 0 or 1
|
||||||
for isp in range(self.n_spin_blocks[iso]):
|
for isp in range(self.n_spin_blocks[iso]):
|
||||||
@ -75,18 +75,10 @@ class SumkDFT:
|
|||||||
# Most general form allowing for all hybridisation, i.e. largest blocks possible
|
# Most general form allowing for all hybridisation, i.e. largest blocks possible
|
||||||
self.gf_struct_sumk = [ [ (sp, range( self.corr_shells[icrsh]['dim'])) for sp in self.spin_block_names[self.corr_shells[icrsh]['SO']] ]
|
self.gf_struct_sumk = [ [ (sp, range( 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) ]
|
for icrsh in range(self.n_corr_shells) ]
|
||||||
|
# First set a standard gf_struct solver:
|
||||||
#-----
|
|
||||||
# If these quantities are not in HDF, set them up
|
|
||||||
optional_things = ['gf_struct_solver','sumk_to_solver','solver_to_sumk','solver_to_sumk_block','chemical_potential','dc_imp','dc_energ','deg_shells']
|
|
||||||
self.subgroup_present, self.value_read = self.read_input_from_hdf(subgrp = self.dft_output, things_to_read = [],
|
|
||||||
optional_things = optional_things)
|
|
||||||
if (not self.subgroup_present) or (not self.value_read['gf_struct_solver']):
|
|
||||||
# No gf_struct was stored in HDF, so first set a standard one:
|
|
||||||
self.gf_struct_solver = [ dict([ (sp, range(self.corr_shells[self.inequiv_to_corr[ish]]['dim']) )
|
self.gf_struct_solver = [ dict([ (sp, range(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)
|
for ish in range(self.n_inequiv_shells) ]
|
||||||
]
|
|
||||||
# Set standard (identity) maps from gf_struct_sumk <-> gf_struct_solver
|
# Set standard (identity) maps from gf_struct_sumk <-> gf_struct_solver
|
||||||
self.sumk_to_solver = [ {} for ish in range(self.n_inequiv_shells) ]
|
self.sumk_to_solver = [ {} for ish in range(self.n_inequiv_shells) ]
|
||||||
self.solver_to_sumk = [ {} for ish in range(self.n_inequiv_shells) ]
|
self.solver_to_sumk = [ {} for ish in range(self.n_inequiv_shells) ]
|
||||||
@ -97,28 +89,19 @@ class SumkDFT:
|
|||||||
for inner in inner_list:
|
for inner in inner_list:
|
||||||
self.sumk_to_solver[ish][(block,inner)] = (block,inner)
|
self.sumk_to_solver[ish][(block,inner)] = (block,inner)
|
||||||
self.solver_to_sumk[ish][(block,inner)] = (block,inner)
|
self.solver_to_sumk[ish][(block,inner)] = (block,inner)
|
||||||
|
self.deg_shells = [ [] for ish in range(self.n_inequiv_shells) ] # assume no shells are degenerate
|
||||||
|
|
||||||
if (not self.subgroup_present) or (not self.value_read['dc_imp']):
|
self.chemical_potential = 0.0 # initialise mu
|
||||||
self.__init_dc() # initialise the double counting
|
self.init_dc() # initialise the double counting
|
||||||
|
|
||||||
if (not self.subgroup_present) or (not self.value_read['chemical_potential']):
|
# Analyse the block structure and determine the smallest gf_struct blocks and maps, if desired
|
||||||
self.chemical_potential = mu
|
if use_dft_blocks: self.analyse_block_structure()
|
||||||
|
|
||||||
if (not self.subgroup_present) or (not self.value_read['deg_shells']):
|
|
||||||
self.deg_shells = [ [] for ish in range(self.n_inequiv_shells)]
|
|
||||||
#-----
|
|
||||||
|
|
||||||
if self.symm_op:
|
|
||||||
self.symmcorr = Symmetry(hdf_file,subgroup=self.symmcorr_data)
|
|
||||||
|
|
||||||
# Analyse the block structure and determine the smallest blocks, if desired
|
|
||||||
if use_dft_blocks: dm = self.analyse_block_structure()
|
|
||||||
|
|
||||||
################
|
################
|
||||||
# HDF5 FUNCTIONS
|
# HDF5 FUNCTIONS
|
||||||
################
|
################
|
||||||
|
|
||||||
def read_input_from_hdf(self, subgrp, things_to_read=[], optional_things=[]):
|
def read_input_from_hdf(self, subgrp, things_to_read):
|
||||||
"""
|
"""
|
||||||
Reads data from the HDF file
|
Reads data from the HDF file
|
||||||
"""
|
"""
|
||||||
@ -126,7 +109,6 @@ class SumkDFT:
|
|||||||
value_read = True
|
value_read = True
|
||||||
# initialise variables on all nodes to ensure mpi broadcast works at the end
|
# initialise variables on all nodes to ensure mpi broadcast works at the end
|
||||||
for it in things_to_read: setattr(self,it,0)
|
for it in things_to_read: setattr(self,it,0)
|
||||||
for it in optional_things: setattr(self,it,0)
|
|
||||||
subgroup_present = 0
|
subgroup_present = 0
|
||||||
|
|
||||||
if mpi.is_master_node():
|
if mpi.is_master_node():
|
||||||
@ -140,16 +122,6 @@ class SumkDFT:
|
|||||||
else:
|
else:
|
||||||
mpi.report("Loading %s failed!"%it)
|
mpi.report("Loading %s failed!"%it)
|
||||||
value_read = False
|
value_read = False
|
||||||
|
|
||||||
if value_read and (len(optional_things) > 0):
|
|
||||||
# if successfully read necessary items, read optional things:
|
|
||||||
value_read = {}
|
|
||||||
for it in optional_things:
|
|
||||||
if it in ar[subgrp]:
|
|
||||||
setattr(self,it,ar[subgrp][it])
|
|
||||||
value_read['%s'%it] = True
|
|
||||||
else:
|
|
||||||
value_read['%s'%it] = False
|
|
||||||
else:
|
else:
|
||||||
if (len(things_to_read) != 0): mpi.report("Loading failed: No %s subgroup in HDF5!"%subgrp)
|
if (len(things_to_read) != 0): mpi.report("Loading failed: No %s subgroup in HDF5!"%subgrp)
|
||||||
subgroup_present = False
|
subgroup_present = False
|
||||||
@ -158,26 +130,41 @@ class SumkDFT:
|
|||||||
del ar
|
del ar
|
||||||
# now do the broadcasting:
|
# now do the broadcasting:
|
||||||
for it in things_to_read: setattr(self,it,mpi.bcast(getattr(self,it)))
|
for it in things_to_read: setattr(self,it,mpi.bcast(getattr(self,it)))
|
||||||
for it in optional_things: setattr(self,it,mpi.bcast(getattr(self,it)))
|
|
||||||
subgroup_present = mpi.bcast(subgroup_present)
|
subgroup_present = mpi.bcast(subgroup_present)
|
||||||
value_read = mpi.bcast(value_read)
|
value_read = mpi.bcast(value_read)
|
||||||
|
|
||||||
return subgroup_present, value_read
|
return subgroup_present, value_read
|
||||||
|
|
||||||
|
|
||||||
def save(self,things_to_save):
|
def save(self, things_to_save, subgrp='user_data'):
|
||||||
"""Saves given quantities into the 'dft_output' subgroup of the HDF5 archive"""
|
"""Saves given quantities into the subgroup ('user_data' by default) of the HDF5 archive"""
|
||||||
|
|
||||||
if not (mpi.is_master_node()): return # do nothing on nodes
|
if not (mpi.is_master_node()): return # do nothing on nodes
|
||||||
ar = HDFArchive(self.hdf_file,'a')
|
ar = HDFArchive(self.hdf_file,'a')
|
||||||
if not self.dft_output in ar: ar.create_group(self.dft_output)
|
if not subgrp in ar: ar.create_group(subgrp)
|
||||||
for it in things_to_save:
|
for it in things_to_save:
|
||||||
try:
|
try:
|
||||||
ar[self.dft_output][it] = getattr(self,it)
|
ar[subgrp][it] = getattr(self,it)
|
||||||
except:
|
except:
|
||||||
mpi.report("%s not found, and so not stored."%it)
|
mpi.report("%s not found, and so not saved."%it)
|
||||||
del ar
|
del ar
|
||||||
|
|
||||||
|
|
||||||
|
def load(self, things_to_load, subgrp='user_data'):
|
||||||
|
"""Loads given quantities from the subgroup ('user_data' by default) of the HDF5 archive"""
|
||||||
|
|
||||||
|
if not (mpi.is_master_node()): return # do nothing on nodes
|
||||||
|
ar = HDFArchive(self.hdf_file,'a')
|
||||||
|
if not subgrp in ar: mpi.report("Loading %s failed!"%subgrp)
|
||||||
|
list_to_return = []
|
||||||
|
for it in things_to_load:
|
||||||
|
try:
|
||||||
|
list_to_return.append(ar[subgrp][it])
|
||||||
|
except:
|
||||||
|
raise ValueError, "%s not found, and so not loaded."%it
|
||||||
|
del ar
|
||||||
|
return list_to_return
|
||||||
|
|
||||||
################
|
################
|
||||||
# CORE FUNCTIONS
|
# CORE FUNCTIONS
|
||||||
################
|
################
|
||||||
@ -431,7 +418,7 @@ class SumkDFT:
|
|||||||
self.solver_to_sumk[ish][(block_solv,inner_solv)] = (block_sumk,inner_sumk)
|
self.solver_to_sumk[ish][(block_solv,inner_solv)] = (block_sumk,inner_sumk)
|
||||||
self.solver_to_sumk_block[ish][block_solv] = block_sumk
|
self.solver_to_sumk_block[ish][block_solv] = block_sumk
|
||||||
|
|
||||||
# now calculate degeneracies of orbitals:
|
# Now calculate degeneracies of orbitals
|
||||||
dm = {}
|
dm = {}
|
||||||
for block,inner in self.gf_struct_solver[ish].iteritems():
|
for block,inner in self.gf_struct_solver[ish].iteritems():
|
||||||
# get dm for the blocks:
|
# get dm for the blocks:
|
||||||
@ -446,9 +433,9 @@ class SumkDFT:
|
|||||||
for block2 in self.gf_struct_solver[ish].iterkeys():
|
for block2 in self.gf_struct_solver[ish].iterkeys():
|
||||||
if dm[block1].shape == dm[block2].shape:
|
if dm[block1].shape == dm[block2].shape:
|
||||||
if ( (abs(dm[block1] - dm[block2]) < threshold).all() ) and (block1 != block2):
|
if ( (abs(dm[block1] - dm[block2]) < threshold).all() ) and (block1 != block2):
|
||||||
# check if it was already there:
|
|
||||||
ind1 = -1
|
ind1 = -1
|
||||||
ind2 = -2
|
ind2 = -2
|
||||||
|
# check if it was already there:
|
||||||
for n,ind in enumerate(self.deg_shells[ish]):
|
for n,ind in enumerate(self.deg_shells[ish]):
|
||||||
if block1 in ind: ind1 = n
|
if block1 in ind: ind1 = n
|
||||||
if block2 in ind: ind2 = n
|
if block2 in ind: ind2 = n
|
||||||
@ -459,11 +446,6 @@ class SumkDFT:
|
|||||||
elif (ind1 < 0) and (ind2 < 0):
|
elif (ind1 < 0) and (ind2 < 0):
|
||||||
self.deg_shells[ish].append([block1,block2])
|
self.deg_shells[ish].append([block1,block2])
|
||||||
|
|
||||||
things_to_save = ['gf_struct_solver','sumk_to_solver','solver_to_sumk','solver_to_sumk_block','deg_shells']
|
|
||||||
self.save(things_to_save)
|
|
||||||
|
|
||||||
return dens_mat
|
|
||||||
|
|
||||||
|
|
||||||
def density_matrix(self, method = 'using_gf', beta = 40.0):
|
def density_matrix(self, method = 'using_gf', beta = 40.0):
|
||||||
"""Calculate density matrices in one of two ways:
|
"""Calculate density matrices in one of two ways:
|
||||||
@ -506,6 +488,8 @@ class SumkDFT:
|
|||||||
else:
|
else:
|
||||||
MMat[isp][inu,inu] = 0.0
|
MMat[isp][inu,inu] = 0.0
|
||||||
|
|
||||||
|
else: raise ValueError, "density_matrix: the method '%s' is not supported."%method
|
||||||
|
|
||||||
for icrsh in range(self.n_corr_shells):
|
for icrsh in range(self.n_corr_shells):
|
||||||
for isp, sp in enumerate(self.spin_block_names[self.corr_shells[icrsh]['SO']]):
|
for isp, sp in enumerate(self.spin_block_names[self.corr_shells[icrsh]['SO']]):
|
||||||
isp = self.spin_names_to_ind[self.corr_shells[icrsh]['SO']][sp]
|
isp = self.spin_names_to_ind[self.corr_shells[icrsh]['SO']][sp]
|
||||||
@ -550,7 +534,8 @@ class SumkDFT:
|
|||||||
|
|
||||||
# Chemical Potential:
|
# Chemical Potential:
|
||||||
for ish in range(self.n_inequiv_shells):
|
for ish in range(self.n_inequiv_shells):
|
||||||
for ii in eff_atlevels[ish]: eff_atlevels[ish][ii] *= -self.chemical_potential
|
for ii in eff_atlevels[ish]:
|
||||||
|
eff_atlevels[ish][ii] *= -self.chemical_potential
|
||||||
|
|
||||||
# double counting term:
|
# double counting term:
|
||||||
for ish in range(self.n_inequiv_shells):
|
for ish in range(self.n_inequiv_shells):
|
||||||
@ -599,9 +584,8 @@ class SumkDFT:
|
|||||||
return eff_atlevels
|
return eff_atlevels
|
||||||
|
|
||||||
|
|
||||||
def __init_dc(self):
|
def init_dc(self):
|
||||||
|
""" Initialise the double counting terms to have the correct shape."""
|
||||||
# construct the density matrix dm_imp and double counting arrays
|
|
||||||
self.dc_imp = [ {} for icrsh in range(self.n_corr_shells)]
|
self.dc_imp = [ {} for icrsh in range(self.n_corr_shells)]
|
||||||
for icrsh in range(self.n_corr_shells):
|
for icrsh in range(self.n_corr_shells):
|
||||||
dim = self.corr_shells[icrsh]['dim']
|
dim = self.corr_shells[icrsh]['dim']
|
||||||
@ -610,46 +594,45 @@ class SumkDFT:
|
|||||||
self.dc_energ = [0.0 for icrsh in range(self.n_corr_shells)]
|
self.dc_energ = [0.0 for icrsh in range(self.n_corr_shells)]
|
||||||
|
|
||||||
|
|
||||||
def set_dc(self,dens_mat,U_interact,J_hund,orb=0,use_dc_formula=0,use_val=None):
|
def set_dc(self,dc_imp,dc_energ):
|
||||||
"""Sets the double counting term for inequiv orbital orb:
|
"""Sets double counting terms dc_imp and dc_energ to known values."""
|
||||||
|
|
||||||
|
self.dc_imp = dc_imp
|
||||||
|
self.dc_energ = dc_energ
|
||||||
|
|
||||||
|
|
||||||
|
def calc_dc(self,dens_mat,orb=0,U_interact=None,J_hund=None,use_dc_formula=0,use_dc_value=None):
|
||||||
|
"""Sets the double counting corrections in the correct form for inequiv orbital orb:
|
||||||
|
1) either using U_interact, J_hund and
|
||||||
use_dc_formula = 0: fully-localised limit (FLL),
|
use_dc_formula = 0: fully-localised limit (FLL),
|
||||||
use_dc_formula = 1: Held's formula,
|
use_dc_formula = 1: Held's formula,
|
||||||
use_dc_formula = 2: around mean-field (AMF).
|
use_dc_formula = 2: around mean-field (AMF).
|
||||||
|
2) or using a given dc value in use_dc_value.
|
||||||
Be sure that you are using the correct interaction Hamiltonian!"""
|
Be sure that you are using the correct interaction Hamiltonian!"""
|
||||||
|
|
||||||
for icrsh in range(self.n_corr_shells):
|
for icrsh in range(self.n_corr_shells):
|
||||||
|
|
||||||
iorb = self.corr_to_inequiv[icrsh] # iorb is the index of the inequivalent shell corresponding to icrsh
|
ish = self.corr_to_inequiv[icrsh] # ish is the index of the inequivalent shell corresponding to icrsh
|
||||||
|
if ish != orb: continue # ignore this orbital
|
||||||
if iorb != orb: continue # ignore this orbital
|
|
||||||
|
|
||||||
Ncr = {}
|
|
||||||
dim = self.corr_shells[icrsh]['dim'] #*(1+self.corr_shells[icrsh]['SO'])
|
dim = self.corr_shells[icrsh]['dim'] #*(1+self.corr_shells[icrsh]['SO'])
|
||||||
|
|
||||||
spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
|
spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
|
||||||
|
|
||||||
|
Ncr = { sp: 0.0 for sp in spn }
|
||||||
|
for block,inner in self.gf_struct_solver[ish].iteritems():
|
||||||
|
bl = self.solver_to_sumk_block[ish][block]
|
||||||
|
Ncr[bl] += dens_mat[block].real.trace()
|
||||||
|
Ncrtot = sum(Ncr.itervalues())
|
||||||
for sp in spn:
|
for sp in spn:
|
||||||
self.dc_imp[icrsh][sp] = numpy.identity(dim,numpy.float_)
|
self.dc_imp[icrsh][sp] = numpy.identity(dim,numpy.float_)
|
||||||
Ncr[sp] = 0.0
|
if self.SP == 0: # average the densities if there is no SP:
|
||||||
|
Ncr[sp] = Ncrtot / len(spn)
|
||||||
for block,inner in self.gf_struct_solver[iorb].iteritems():
|
elif self.SP == 1 and self.SO == 1: # correction for SO: we have only one block in this case, but in DC we need N/2
|
||||||
bl = self.solver_to_sumk_block[iorb][block]
|
Ncr[sp] = Ncrtot / 2.0
|
||||||
Ncr[bl] += dens_mat[block].real.trace()
|
|
||||||
|
|
||||||
Ncrtot = 0.0
|
|
||||||
|
|
||||||
spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
|
|
||||||
for sp in spn:
|
|
||||||
Ncrtot += Ncr[sp]
|
|
||||||
|
|
||||||
# average the densities if there is no SP:
|
|
||||||
if self.SP == 0:
|
|
||||||
for sp in spn: Ncr[sp] = Ncrtot / len(spn)
|
|
||||||
# correction for SO: we have only one block in this case, but in DC we need N/2
|
|
||||||
elif self.SP == 1 and self.SO == 1:
|
|
||||||
for sp in spn: Ncr[sp] = Ncrtot / 2.0
|
|
||||||
|
|
||||||
if use_val is None:
|
if use_val is None:
|
||||||
|
|
||||||
|
if U_interact is None and J_hund is None: raise ValueError, "set_dc: either provide U_interact and J_hund or set use_val to dc value."
|
||||||
|
|
||||||
if use_dc_formula == 0: # FLL
|
if use_dc_formula == 0: # FLL
|
||||||
|
|
||||||
self.dc_energ[icrsh] = U_interact / 2.0 * Ncrtot * (Ncrtot-1.0)
|
self.dc_energ[icrsh] = U_interact / 2.0 * Ncrtot * (Ncrtot-1.0)
|
||||||
@ -676,16 +659,13 @@ class SumkDFT:
|
|||||||
self.dc_energ[icrsh] -= (U_interact + (dim-1)*J_hund)/dim * 0.5 * Ncr[sp] * Ncr[sp]
|
self.dc_energ[icrsh] -= (U_interact + (dim-1)*J_hund)/dim * 0.5 * Ncr[sp] * Ncr[sp]
|
||||||
mpi.report("DC for shell %(icrsh)i and block %(sp)s = %(Uav)f"%locals())
|
mpi.report("DC for shell %(icrsh)i and block %(sp)s = %(Uav)f"%locals())
|
||||||
|
|
||||||
# output:
|
|
||||||
mpi.report("DC energy for shell %s = %s"%(icrsh,self.dc_energ[icrsh]))
|
mpi.report("DC energy for shell %s = %s"%(icrsh,self.dc_energ[icrsh]))
|
||||||
|
|
||||||
else:
|
else: # use value provided for user to determine dc_energ and dc_imp
|
||||||
|
|
||||||
self.dc_energ[icrsh] = use_val * Ncrtot
|
self.dc_energ[icrsh] = use_val * Ncrtot
|
||||||
for sp in spn:
|
for sp in spn: self.dc_imp[icrsh][sp] *= use_val
|
||||||
self.dc_imp[icrsh][sp] *= use_val
|
|
||||||
|
|
||||||
# output:
|
|
||||||
mpi.report("DC for shell %(icrsh)i = %(use_val)f"%locals())
|
mpi.report("DC for shell %(icrsh)i = %(use_val)f"%locals())
|
||||||
mpi.report("DC energy = %s"%self.dc_energ[icrsh])
|
mpi.report("DC energy = %s"%self.dc_energ[icrsh])
|
||||||
|
|
||||||
@ -745,7 +725,7 @@ class SumkDFT:
|
|||||||
self.chemical_potential = mu
|
self.chemical_potential = mu
|
||||||
|
|
||||||
|
|
||||||
def find_mu(self, precision = 0.01):
|
def calc_mu(self, precision = 0.01):
|
||||||
"""
|
"""
|
||||||
Searches for mu in order to give the desired charge
|
Searches for mu in order to give the desired charge
|
||||||
A desired precision can be specified in precision.
|
A desired precision can be specified in precision.
|
||||||
@ -840,8 +820,8 @@ class SumkDFT:
|
|||||||
# FIXME LEAVE UNDOCUMENTED
|
# FIXME LEAVE UNDOCUMENTED
|
||||||
################
|
################
|
||||||
|
|
||||||
# FIXME Merge with find_mu?
|
# FIXME Merge with calc_mu?
|
||||||
def find_mu_nonint(self, dens_req, orb = None, precision = 0.01):
|
def calc_mu_nonint(self, dens_req, orb = None, precision = 0.01):
|
||||||
|
|
||||||
def F(mu):
|
def F(mu):
|
||||||
gnonint = self.extract_G_loc(mu = mu, with_Sigma = False)
|
gnonint = self.extract_G_loc(mu = mu, with_Sigma = False)
|
||||||
@ -873,7 +853,7 @@ class SumkDFT:
|
|||||||
mu = self.chemical_potential
|
mu = self.chemical_potential
|
||||||
|
|
||||||
def F(dc):
|
def F(dc):
|
||||||
self.set_dc(dens_mat = dens_mat, U_interact = 0, J_hund = 0, orb = orb, use_val = dc)
|
self.calc_dc(dens_mat = dens_mat, U_interact = 0, J_hund = 0, orb = orb, use_val = dc)
|
||||||
if dens_req is None:
|
if dens_req is None:
|
||||||
return self.total_density(mu = mu)
|
return self.total_density(mu = mu)
|
||||||
else:
|
else:
|
||||||
|
@ -32,11 +32,11 @@ class SumkDFTTools(SumkDFT):
|
|||||||
"""Extends the SumkDFT class with some tools for analysing the data."""
|
"""Extends the SumkDFT class with some tools for analysing the data."""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, hdf_file, mu = 0.0, h_field = 0.0, use_dft_blocks = False, dft_data = 'dft_input', symmcorr_data = 'dft_symmcorr_input',
|
def __init__(self, hdf_file, h_field = 0.0, use_dft_blocks = False, dft_data = 'dft_input', symmcorr_data = 'dft_symmcorr_input',
|
||||||
parproj_data = 'dft_parproj_input', symmpar_data = 'dft_symmpar_input', bands_data = 'dft_bands_input'):
|
parproj_data = 'dft_parproj_input', symmpar_data = 'dft_symmpar_input', bands_data = 'dft_bands_input'):
|
||||||
|
|
||||||
self.G_upfold_refreq = None
|
self.G_upfold_refreq = None
|
||||||
SumkDFT.__init__(self, hdf_file=hdf_file, mu=mu, h_field=h_field, use_dft_blocks=use_dft_blocks,
|
SumkDFT.__init__(self, hdf_file=hdf_file, h_field=h_field, use_dft_blocks=use_dft_blocks,
|
||||||
dft_data=dft_data, symmcorr_data=symmcorr_data, parproj_data=parproj_data,
|
dft_data=dft_data, symmcorr_data=symmcorr_data, parproj_data=parproj_data,
|
||||||
symmpar_data=symmpar_data, bands_data=bands_data)
|
symmpar_data=symmpar_data, bands_data=bands_data)
|
||||||
|
|
||||||
|
@ -62,15 +62,18 @@ for old, new in old_to_new.iteritems():
|
|||||||
A.copy(old,new)
|
A.copy(old,new)
|
||||||
del(A[old])
|
del(A[old])
|
||||||
|
|
||||||
# Move output items from dft_input to dft_output
|
# Move output items from dft_input to user_data
|
||||||
move_to_output = ['gf_struct_solver','map_inv','map',
|
move_to_output = ['chemical_potential','dc_imp','dc_energ']
|
||||||
'chemical_potential','dc_imp','dc_energ','deg_shells',
|
|
||||||
'h_field']
|
|
||||||
for obj in move_to_output:
|
for obj in move_to_output:
|
||||||
if obj in A['dft_input'].keys():
|
if obj in A['dft_input'].keys():
|
||||||
if not 'dft_output' in A: A.create_group('dft_output')
|
if 'user_data' not in A: A.create_group('user_data')
|
||||||
print "Moving %s to dft_output ..."%obj
|
print "Moving %s to user_data ..."%obj
|
||||||
A.copy('dft_input/'+obj,'dft_output/'+obj)
|
A.copy('dft_input/'+obj,'user_data/'+obj)
|
||||||
|
del(A['dft_input'][obj])
|
||||||
|
# Delete obsolete quantities
|
||||||
|
to_delete = ['gf_struct_solver','map_inv','map','deg_shells','h_field']
|
||||||
|
for obj in to_delete:
|
||||||
|
if obj in A['dft_input'].keys():
|
||||||
del(A['dft_input'][obj])
|
del(A['dft_input'][obj])
|
||||||
|
|
||||||
# Update shells and corr_shells to list of dicts
|
# Update shells and corr_shells to list of dicts
|
||||||
@ -87,6 +90,7 @@ HDFArchive(filename,'a')['dft_input']['corr_shells'] = corr_shells
|
|||||||
A = h5py.File(filename)
|
A = h5py.File(filename)
|
||||||
|
|
||||||
# Add shell equivalency quantities
|
# Add shell equivalency quantities
|
||||||
|
if 'n_inequiv_shells' not in A['dft_input']:
|
||||||
equiv_shell_info = det_shell_equivalence(corr_shells)
|
equiv_shell_info = det_shell_equivalence(corr_shells)
|
||||||
A['dft_input']['n_inequiv_shells'] = equiv_shell_info[0]
|
A['dft_input']['n_inequiv_shells'] = equiv_shell_info[0]
|
||||||
A['dft_input']['corr_to_inequiv'] = equiv_shell_info[1]
|
A['dft_input']['corr_to_inequiv'] = equiv_shell_info[1]
|
||||||
@ -97,6 +101,7 @@ groups = ['dft_symmcorr_input','dft_symmpar_input']
|
|||||||
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if group not in A.keys(): continue
|
if group not in A.keys(): continue
|
||||||
|
if 'n_s' not in group: continue
|
||||||
print "Changing n_s to n_symm ..."
|
print "Changing n_s to n_symm ..."
|
||||||
A[group].move('n_s','n_symm')
|
A[group].move('n_s','n_symm')
|
||||||
# Convert orbits to list of dicts
|
# Convert orbits to list of dicts
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user