2013-07-23 19:49:42 +02:00
################################################################################
#
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
#
# Copyright (C) 2011 by M. Aichhorn, L. Pourovskii, V. Vildosola
#
# TRIQS is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# TRIQS. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from types import *
from symmetry import *
import numpy
import pytriqs . utility . dichotomy as dichotomy
from pytriqs . gf . local import *
from pytriqs . archive import *
import pytriqs . utility . mpi as mpi
class SumkLDA :
""" This class provides a general SumK method for combining ab-initio code and pytriqs. """
2014-11-07 00:55:40 +01:00
def __init__ ( self , hdf_file , mu = 0.0 , h_field = 0.0 , use_lda_blocks = False ,
lda_data = ' lda_input ' , symmcorr_data = ' lda_symmcorr_input ' , parproj_data = ' lda_parproj_input ' ,
symmpar_data = ' lda_symmpar_input ' , bands_data = ' lda_bands_input ' , lda_output = ' lda_output ' ) :
2013-07-23 19:49:42 +02:00
"""
Initialises the class from data previously stored into an HDF5
"""
2014-11-07 00:55:40 +01:00
if not ( type ( hdf_file ) == StringType ) :
2013-07-23 19:49:42 +02:00
mpi . report ( " Give a string for the HDF5 filename to read the input! " )
else :
self . hdf_file = hdf_file
self . lda_data = lda_data
2014-11-03 14:47:55 +01:00
self . symmcorr_data = symmcorr_data
self . parproj_data = parproj_data
self . symmpar_data = symmpar_data
2013-07-23 19:49:42 +02:00
self . bands_data = bands_data
2014-11-07 00:55:40 +01:00
self . lda_output = lda_output
2013-07-23 19:49:42 +02:00
self . block_names = [ [ ' up ' , ' down ' ] , [ ' ud ' ] ]
self . n_spin_blocks_gf = [ 2 , 1 ]
2014-10-28 16:19:28 +01:00
self . G_upfold = None
2013-07-23 19:49:42 +02:00
self . h_field = h_field
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# read input from HDF:
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 ' ]
2014-11-07 00:55:40 +01:00
self . subgroup_present , self . value_read = self . read_input_from_hdf ( subgrp = self . lda_data , things_to_read = things_to_read )
2013-07-23 19:49:42 +02:00
if ( self . SO ) and ( abs ( self . h_field ) > 0.000001 ) :
self . h_field = 0.0
2014-10-28 16:19:28 +01:00
mpi . report ( " For SO, the external magnetic field is not implemented, setting it to 0! " )
2013-07-23 19:49:42 +02:00
2014-09-22 19:24:33 +02:00
# determine the number of inequivalent correlated shells (self.n_inequiv_corr_shells)
# and related maps (self.shellmap, self.invshellmap)
self . inequiv_shells ( self . corr_shells )
2013-07-23 19:49:42 +02:00
# field to convert block_names to indices
self . names_to_ind = [ { } , { } ]
for ibl in range ( 2 ) :
2014-09-22 19:24:33 +02:00
for inm in range ( self . n_spin_blocks_gf [ ibl ] ) :
2014-11-07 00:55:40 +01:00
self . names_to_ind [ ibl ] [ self . block_names [ ibl ] [ inm ] ] = inm * self . SP
2013-07-23 19:49:42 +02:00
# GF structure used for the local things in the k sums
2014-10-28 16:19:28 +01:00
# Most general form allowing for all hybridisation, i.e. largest blocks possible
2014-09-22 19:24:33 +02:00
self . gf_struct_corr = [ [ ( al , range ( self . corr_shells [ i ] [ 3 ] ) ) for al in self . block_names [ self . corr_shells [ i ] [ 4 ] ] ]
2013-07-23 19:49:42 +02:00
for i in xrange ( self . n_corr_shells ) ]
2014-11-07 00:55:40 +01:00
#-----
# If these quantities are not in HDF, set them up and save into HDF
optional_things = [ ' gf_struct_solver ' , ' map_inv ' , ' map ' , ' chemical_potential ' , ' dc_imp ' , ' dc_energ ' , ' deg_shells ' ]
self . subgroup_present , self . value_read = self . read_input_from_hdf ( subgrp = self . lda_output , things_to_read = [ ] ,
optional_things = optional_things )
if ( not self . subgroup_present ) or ( not self . value_read [ ' gf_struct_solver ' ] ) :
2013-07-23 19:49:42 +02:00
# No gf_struct was stored in HDF, so first set a standard one:
2014-09-22 19:24:33 +02:00
self . gf_struct_solver = [ dict ( [ ( al , range ( self . corr_shells [ self . invshellmap [ i ] ] [ 3 ] ) )
for al in self . block_names [ self . corr_shells [ self . invshellmap [ i ] ] [ 4 ] ] ] )
for i in range ( self . n_inequiv_corr_shells )
]
2013-07-23 19:49:42 +02:00
self . map = [ { } for i in xrange ( self . n_inequiv_corr_shells ) ]
self . map_inv = [ { } for i in xrange ( self . n_inequiv_corr_shells ) ]
for i in xrange ( self . n_inequiv_corr_shells ) :
for al in self . block_names [ self . corr_shells [ self . invshellmap [ i ] ] [ 4 ] ] :
self . map [ i ] [ al ] = [ al for j in range ( self . corr_shells [ self . invshellmap [ i ] ] [ 3 ] ) ]
self . map_inv [ i ] [ al ] = al
2014-11-07 00:55:40 +01:00
if ( not self . subgroup_present ) or ( not self . value_read [ ' dc_imp ' ] ) :
2013-07-23 19:49:42 +02:00
# init the double counting:
self . __init_dc ( )
2014-11-07 00:55:40 +01:00
if ( not self . subgroup_present ) or ( not self . value_read [ ' chemical_potential ' ] ) :
2013-07-23 19:49:42 +02:00
self . chemical_potential = mu
2014-11-07 00:55:40 +01:00
if ( not self . subgroup_present ) or ( not self . value_read [ ' deg_shells ' ] ) :
2013-07-23 19:49:42 +02:00
self . deg_shells = [ [ ] for i in range ( self . n_inequiv_corr_shells ) ]
2014-11-07 00:55:40 +01:00
#-----
2013-07-23 19:49:42 +02:00
if self . symm_op :
#mpi.report("Do the init for symm:")
2014-11-07 00:55:40 +01:00
self . symmcorr = Symmetry ( hdf_file , subgroup = self . symmcorr_data )
2013-07-23 19:49:42 +02:00
2014-09-22 19:24:33 +02:00
# Analyse the block structure and determine the smallest blocs, if desired
2013-07-23 19:49:42 +02:00
if ( use_lda_blocks ) : dm = self . analyse_BS ( )
2014-11-07 00:55:40 +01:00
# Now save things again to HDF5:
# FIXME WHAT HAPPENS TO h_field? INPUT TO __INIT__? ADD TO OPTIONAL_THINGS?
things_to_save = [ ' chemical_potential ' , ' dc_imp ' , ' dc_energ ' , ' h_field ' ]
self . save ( things_to_save )
2014-09-22 19:24:33 +02:00
2014-11-07 00:55:40 +01:00
def read_input_from_hdf ( self , subgrp , things_to_read = [ ] , optional_things = [ ] ) :
2013-07-23 19:49:42 +02:00
"""
Reads data from the HDF file
"""
2014-09-22 19:24:33 +02:00
2014-11-07 00:55:40 +01:00
value_read = True
2014-10-31 18:52:32 +01:00
# init 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 optional_things : setattr ( self , it , 0 )
2014-09-22 19:24:33 +02:00
2014-11-07 00:55:40 +01:00
if mpi . is_master_node ( ) :
2013-07-23 19:49:42 +02:00
ar = HDFArchive ( self . hdf_file , ' a ' )
2014-11-07 00:55:40 +01:00
if subgrp in ar :
subgroup_present = True
2013-07-23 19:49:42 +02:00
# first read the necessary things:
for it in things_to_read :
2014-11-07 00:55:40 +01:00
if it in ar [ subgrp ] :
2014-10-31 18:52:32 +01:00
setattr ( self , it , ar [ subgrp ] [ it ] )
2013-07-23 19:49:42 +02:00
else :
mpi . report ( " Loading %s failed! " % it )
2014-11-07 00:55:40 +01:00
value_read = False
2014-09-22 19:24:33 +02:00
2014-11-07 00:55:40 +01:00
if ( value_read and ( len ( optional_things ) > 0 ) ) :
2013-07-23 19:49:42 +02:00
# if necessary things worked, now read optional things:
2014-11-07 00:55:40 +01:00
value_read = { }
2013-07-23 19:49:42 +02:00
for it in optional_things :
2014-11-07 00:55:40 +01:00
if it in ar [ subgrp ] :
2014-10-31 18:52:32 +01:00
setattr ( self , it , ar [ subgrp ] [ it ] )
2014-11-07 00:55:40 +01:00
value_read [ ' %s ' % it ] = True
2013-07-23 19:49:42 +02:00
else :
2014-11-07 00:55:40 +01:00
value_read [ ' %s ' % it ] = False
2013-07-23 19:49:42 +02:00
else :
2014-11-13 17:02:23 +01:00
if ( len ( things_to_read ) != 0 ) : mpi . report ( " Loading failed: No %s subgroup in HDF5! " % subgrp )
2014-11-07 00:55:40 +01:00
subgroup_present = False
value_read = False
2013-07-23 19:49:42 +02:00
del ar
# now do the broadcasting:
2014-10-31 18:52:32 +01:00
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 ) ) )
2014-11-07 00:55:40 +01:00
subgroup_present = mpi . bcast ( subgroup_present )
value_read = mpi . bcast ( value_read )
2013-07-23 19:49:42 +02:00
2014-11-07 00:55:40 +01:00
return ( subgroup_present , value_read )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
2014-11-07 00:55:40 +01:00
def save ( self , things_to_save ) :
2013-07-23 19:49:42 +02:00
""" Saves some quantities into an HDF5 arxiv """
if not ( mpi . is_master_node ( ) ) : return # do nothing on nodes
2014-11-07 00:55:40 +01:00
ar = HDFArchive ( self . hdf_file , ' a ' )
if not ( self . lda_output in ar ) : ar . create_group ( self . lda_output )
for it in things_to_save :
try :
ar [ self . lda_output ] [ it ] = getattr ( self , it )
except :
mpi . report ( " %s not found, and so not stored. " % it )
2014-09-22 19:24:33 +02:00
del ar
2013-07-23 19:49:42 +02:00
def downfold ( self , ik , icrsh , sig , gf_to_downfold , gf_inp ) :
""" Downfolding a block of the Greens function """
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
gf_downfolded = gf_inp . copy ( )
isp = self . names_to_ind [ self . SO ] [ sig ] # get spin index for proj. matrices
dim = self . corr_shells [ icrsh ] [ 3 ]
n_orb = self . n_orbitals [ ik , isp ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
gf_downfolded . from_L_G_R ( self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] , gf_to_downfold , self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] . conjugate ( ) . transpose ( ) ) # downfolding G
return gf_downfolded
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def upfold ( self , ik , icrsh , sig , gf_to_upfold , gf_inp ) :
""" Upfolding a block of the Greens function """
gf_upfolded = gf_inp . copy ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
isp = self . names_to_ind [ self . SO ] [ sig ] # get spin index for proj. matrices
dim = self . corr_shells [ icrsh ] [ 3 ]
n_orb = self . n_orbitals [ ik , isp ]
2014-09-22 19:24:33 +02:00
gf_upfolded . from_L_G_R ( self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] . conjugate ( ) . transpose ( ) , gf_to_upfold , self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] )
2013-07-23 19:49:42 +02:00
return gf_upfolded
def rotloc ( self , icrsh , gf_to_rotate , direction ) :
""" Local <-> Global rotation of a GF block.
direction : ' toLocal ' / ' toGlobal ' """
assert ( ( direction == ' toLocal ' ) or ( direction == ' toGlobal ' ) ) , " Give direction ' toLocal ' or ' toGlobal ' in rotloc! "
gf_rotated = gf_to_rotate . copy ( )
if ( direction == ' toGlobal ' ) :
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if ( ( self . rot_mat_time_inv [ icrsh ] == 1 ) and ( self . SO ) ) :
2014-10-28 16:19:28 +01:00
gf_rotated << gf_rotated . transpose ( )
2013-07-23 19:49:42 +02:00
gf_rotated . from_L_G_R ( self . rot_mat [ icrsh ] . conjugate ( ) , gf_rotated , self . rot_mat [ icrsh ] . transpose ( ) )
else :
gf_rotated . from_L_G_R ( self . rot_mat [ icrsh ] , gf_rotated , self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
elif ( direction == ' toLocal ' ) :
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if ( ( self . rot_mat_time_inv [ icrsh ] == 1 ) and ( self . SO ) ) :
2014-10-28 16:19:28 +01:00
gf_rotated << gf_rotated . transpose ( )
2013-07-23 19:49:42 +02:00
gf_rotated . from_L_G_R ( self . rot_mat [ icrsh ] . transpose ( ) , gf_rotated , self . rot_mat [ icrsh ] . conjugate ( ) )
else :
gf_rotated . from_L_G_R ( self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) , gf_rotated , self . rot_mat [ icrsh ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
return gf_rotated
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def lattice_gf_matsubara ( self , ik , mu , beta = 40 , with_Sigma = True ) :
""" Calculates the lattice Green function from the LDA hopping and the self energy at k-point number ik
and chemical potential mu . """
ntoi = self . names_to_ind [ self . SO ]
bln = self . block_names [ self . SO ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if ( not hasattr ( self , " Sigma_imp " ) ) : with_Sigma = False
2014-09-22 19:24:33 +02:00
if ( with_Sigma ) :
2013-07-23 19:49:42 +02:00
stmp = self . add_dc ( )
2014-10-31 18:52:32 +01:00
beta = self . Sigma_imp [ 0 ] . mesh . beta # override beta if Sigma is present
2013-07-23 19:49:42 +02:00
2014-10-28 16:19:28 +01:00
# Do we need to set up G_upfold?
2014-10-31 18:52:32 +01:00
set_up_G_upfold = False # assume not
if self . G_upfold == None : # yes if not G_upfold provided
2014-10-28 16:19:28 +01:00
set_up_G_upfold = True
2014-10-31 18:52:32 +01:00
else : # yes if inconsistencies present in existing G_upfold
2014-10-28 16:19:28 +01:00
GFsize = [ gf . N1 for sig , gf in self . G_upfold ]
2014-09-22 19:24:33 +02:00
unchangedsize = all ( [ self . n_orbitals [ ik , ntoi [ bln [ ib ] ] ] == GFsize [ ib ]
for ib in range ( self . n_spin_blocks_gf [ self . SO ] ) ] )
2014-10-31 18:52:32 +01:00
if ( ( not unchangedsize ) or ( self . G_upfold . mesh . beta != beta ) ) : set_up_G_upfold = True
2013-07-23 19:49:42 +02:00
2014-10-28 16:19:28 +01:00
# Set up G_upfold
if set_up_G_upfold :
2013-07-23 19:49:42 +02:00
BS = [ range ( self . n_orbitals [ ik , ntoi [ ib ] ] ) for ib in bln ]
gf_struct = [ ( bln [ ib ] , BS [ ib ] ) for ib in range ( self . n_spin_blocks_gf [ self . SO ] ) ]
2014-09-22 19:24:33 +02:00
a_list = [ a for a , al in gf_struct ]
2013-07-23 19:49:42 +02:00
if ( with_Sigma ) :
glist = lambda : [ GfImFreq ( indices = al , mesh = self . Sigma_imp [ 0 ] . mesh ) for a , al in gf_struct ]
else :
2014-09-22 19:24:33 +02:00
glist = lambda : [ GfImFreq ( indices = al , beta = beta ) for a , al in gf_struct ]
2014-10-28 16:19:28 +01:00
self . G_upfold = BlockGf ( name_list = a_list , block_list = glist ( ) , make_copies = False )
self . G_upfold . zero ( )
2013-07-23 19:49:42 +02:00
2014-10-31 18:52:32 +01:00
self . G_upfold << iOmega_n
2014-09-22 19:24:33 +02:00
idmat = [ numpy . identity ( self . n_orbitals [ ik , ntoi [ bl ] ] , numpy . complex_ ) for bl in bln ]
2013-07-23 19:49:42 +02:00
M = copy . deepcopy ( idmat )
2014-09-22 19:24:33 +02:00
for ibl in range ( self . n_spin_blocks_gf [ self . SO ] ) :
2013-07-23 19:49:42 +02:00
ind = ntoi [ bln [ ibl ] ]
n_orb = self . n_orbitals [ ik , ind ]
M [ ibl ] = self . hopping [ ik , ind , 0 : n_orb , 0 : n_orb ] - ( idmat [ ibl ] * mu ) - ( idmat [ ibl ] * self . h_field * ( 1 - 2 * ibl ) )
2014-10-28 16:19:28 +01:00
self . G_upfold - = M
2013-07-23 19:49:42 +02:00
if ( with_Sigma ) :
for icrsh in xrange ( self . n_corr_shells ) :
2014-10-28 16:19:28 +01:00
for sig , gf in self . G_upfold : gf - = self . upfold ( ik , icrsh , sig , stmp [ icrsh ] [ sig ] , gf )
2013-07-23 19:49:42 +02:00
2014-10-28 16:19:28 +01:00
self . G_upfold . invert ( )
2013-07-23 19:49:42 +02:00
2014-10-28 16:19:28 +01:00
return self . G_upfold
2013-07-23 19:49:42 +02:00
def simple_point_dens_mat ( self ) :
ntoi = self . names_to_ind [ self . SO ]
bln = self . block_names [ self . SO ]
2014-09-22 19:24:33 +02:00
MMat = [ numpy . zeros ( [ self . n_orbitals [ 0 , ntoi [ bl ] ] , self . n_orbitals [ 0 , ntoi [ bl ] ] ] , numpy . complex_ ) for bl in bln ]
2013-07-23 19:49:42 +02:00
dens_mat = [ { } for icrsh in xrange ( self . n_corr_shells ) ]
for icrsh in xrange ( self . n_corr_shells ) :
for bl in self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] :
dens_mat [ icrsh ] [ bl ] = numpy . zeros ( [ self . corr_shells [ icrsh ] [ 3 ] , self . corr_shells [ icrsh ] [ 3 ] ] , numpy . complex_ )
ikarray = numpy . array ( range ( self . n_k ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for ik in mpi . slice_array ( ikarray ) :
2014-09-22 19:24:33 +02:00
unchangedsize = all ( [ self . n_orbitals [ ik , ntoi [ bln [ ib ] ] ] == len ( MMat [ ib ] )
2013-07-23 19:49:42 +02:00
for ib in range ( self . n_spin_blocks_gf [ self . SO ] ) ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if ( not unchangedsize ) :
2014-09-22 19:24:33 +02:00
MMat = [ numpy . zeros ( [ self . n_orbitals [ ik , ntoi [ bl ] ] , self . n_orbitals [ ik , ntoi [ bl ] ] ] , numpy . complex_ ) for bl in bln ]
2013-07-23 19:49:42 +02:00
for ibl , bl in enumerate ( bln ) :
ind = ntoi [ bl ]
for inu in range ( self . n_orbitals [ ik , ind ] ) :
2014-10-28 16:19:28 +01:00
if ( ( self . hopping [ ik , ind , inu , inu ] - self . h_field * ( 1 - 2 * ibl ) ) < 0.0 ) : # ONLY WORKS FOR DIAGONAL HOPPING MATRIX (TRUE IN WIEN2K)
2013-07-23 19:49:42 +02:00
MMat [ ibl ] [ inu , inu ] = 1.0
else :
2014-09-22 19:24:33 +02:00
MMat [ ibl ] [ inu , inu ] = 0.0
2013-07-23 19:49:42 +02:00
for icrsh in range ( self . n_corr_shells ) :
for ibn , bn in enumerate ( self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] ) :
isp = self . names_to_ind [ self . corr_shells [ icrsh ] [ 4 ] ] [ bn ]
dim = self . corr_shells [ icrsh ] [ 3 ]
n_orb = self . n_orbitals [ ik , isp ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
#print ik, bn, isp
2014-09-22 19:24:33 +02:00
dens_mat [ icrsh ] [ bn ] + = self . bz_weights [ ik ] * numpy . dot ( numpy . dot ( self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] , MMat [ ibn ] ) ,
2013-07-23 19:49:42 +02:00
self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] . transpose ( ) . conjugate ( ) )
# get data from nodes:
for icrsh in range ( self . n_corr_shells ) :
for sig in dens_mat [ icrsh ] :
dens_mat [ icrsh ] [ sig ] = mpi . all_reduce ( mpi . world , dens_mat [ icrsh ] [ sig ] , lambda x , y : x + y )
mpi . barrier ( )
2014-09-22 19:24:33 +02:00
2014-11-07 00:55:40 +01:00
if ( self . symm_op != 0 ) : dens_mat = self . symmcorr . symmetrize ( dens_mat )
2013-07-23 19:49:42 +02:00
# Rotate to local coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
for bn in dens_mat [ icrsh ] :
if ( self . rot_mat_time_inv [ icrsh ] == 1 ) : dens_mat [ icrsh ] [ bn ] = dens_mat [ icrsh ] [ bn ] . conjugate ( )
2014-09-22 19:24:33 +02:00
dens_mat [ icrsh ] [ bn ] = numpy . dot ( numpy . dot ( self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) , dens_mat [ icrsh ] [ bn ] ) ,
2013-07-23 19:49:42 +02:00
self . rot_mat [ icrsh ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
return dens_mat
2014-10-28 16:19:28 +01:00
# calculate upfolded gf, then density matrix -- no assumptions on structure (ie diagonal or not)
2013-07-23 19:49:42 +02:00
def density_gf ( self , beta ) :
2014-09-22 19:24:33 +02:00
""" Calculates the density without setting up Gloc. It is useful for Hubbard I, and very fast. """
2013-07-23 19:49:42 +02:00
dens_mat = [ { } for icrsh in xrange ( self . n_corr_shells ) ]
for icrsh in xrange ( self . n_corr_shells ) :
for bl in self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] :
dens_mat [ icrsh ] [ bl ] = numpy . zeros ( [ self . corr_shells [ icrsh ] [ 3 ] , self . corr_shells [ icrsh ] [ 3 ] ] , numpy . complex_ )
ikarray = numpy . array ( range ( self . n_k ) )
for ik in mpi . slice_array ( ikarray ) :
2014-09-22 19:24:33 +02:00
2014-10-28 16:19:28 +01:00
G_upfold = self . lattice_gf_matsubara ( ik = ik , beta = beta , mu = self . chemical_potential )
G_upfold * = self . bz_weights [ ik ]
dm = G_upfold . density ( )
2013-07-23 19:49:42 +02:00
MMat = [ dm [ bl ] for bl in self . block_names [ self . SO ] ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for icrsh in range ( self . n_corr_shells ) :
for ibn , bn in enumerate ( self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] ) :
isp = self . names_to_ind [ self . corr_shells [ icrsh ] [ 4 ] ] [ bn ]
dim = self . corr_shells [ icrsh ] [ 3 ]
n_orb = self . n_orbitals [ ik , isp ]
#print ik, bn, isp
dens_mat [ icrsh ] [ bn ] + = numpy . dot ( numpy . dot ( self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] , MMat [ ibn ] ) ,
self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] . transpose ( ) . conjugate ( ) )
# get data from nodes:
for icrsh in range ( self . n_corr_shells ) :
for sig in dens_mat [ icrsh ] :
dens_mat [ icrsh ] [ sig ] = mpi . all_reduce ( mpi . world , dens_mat [ icrsh ] [ sig ] , lambda x , y : x + y )
mpi . barrier ( )
2014-11-07 00:55:40 +01:00
if ( self . symm_op != 0 ) : dens_mat = self . symmcorr . symmetrize ( dens_mat )
2013-07-23 19:49:42 +02:00
# Rotate to local coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
for bn in dens_mat [ icrsh ] :
if ( self . rot_mat_time_inv [ icrsh ] == 1 ) : dens_mat [ icrsh ] [ bn ] = dens_mat [ icrsh ] [ bn ] . conjugate ( )
2014-09-22 19:24:33 +02:00
dens_mat [ icrsh ] [ bn ] = numpy . dot ( numpy . dot ( self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) , dens_mat [ icrsh ] [ bn ] ) ,
2013-07-23 19:49:42 +02:00
self . rot_mat [ icrsh ] )
return dens_mat
def analyse_BS ( self , threshold = 0.00001 , include_shells = None , dm = None ) :
2014-09-22 19:24:33 +02:00
""" Determines the Green function block structure from simple point integration. """
2013-07-23 19:49:42 +02:00
if ( dm == None ) : dm = self . simple_point_dens_mat ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
dens_mat = [ dm [ self . invshellmap [ ish ] ] for ish in xrange ( self . n_inequiv_corr_shells ) ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if include_shells is None : include_shells = range ( self . n_inequiv_corr_shells )
for ish in include_shells :
2014-09-22 19:24:33 +02:00
self . gf_struct_solver [ ish ] = { }
2013-07-23 19:49:42 +02:00
gf_struct_temp = [ ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
a_list = [ a for a , al in self . gf_struct_corr [ self . invshellmap [ ish ] ] ]
for a in a_list :
2014-09-22 19:24:33 +02:00
dm = dens_mat [ ish ] [ a ]
2013-07-23 19:49:42 +02:00
dmbool = ( abs ( dm ) > threshold ) # gives an index list of entries larger that threshold
offdiag = [ ]
for i in xrange ( len ( dmbool ) ) :
for j in xrange ( i , len ( dmbool ) ) :
if ( ( dmbool [ i , j ] ) & ( i != j ) ) : offdiag . append ( [ i , j ] )
NBlocs = len ( dmbool )
blocs = [ [ i ] for i in range ( NBlocs ) ]
for i in range ( len ( offdiag ) ) :
if ( offdiag [ i ] [ 0 ] != offdiag [ i ] [ 1 ] ) :
for j in range ( len ( blocs [ offdiag [ i ] [ 1 ] ] ) ) : blocs [ offdiag [ i ] [ 0 ] ] . append ( blocs [ offdiag [ i ] [ 1 ] ] [ j ] )
del blocs [ offdiag [ i ] [ 1 ] ]
for j in range ( i + 1 , len ( offdiag ) ) :
if ( offdiag [ j ] [ 0 ] == offdiag [ i ] [ 1 ] ) : offdiag [ j ] [ 0 ] = offdiag [ i ] [ 0 ]
if ( offdiag [ j ] [ 1 ] == offdiag [ i ] [ 1 ] ) : offdiag [ j ] [ 1 ] = offdiag [ i ] [ 0 ]
if ( offdiag [ j ] [ 0 ] > offdiag [ i ] [ 1 ] ) : offdiag [ j ] [ 0 ] - = 1
if ( offdiag [ j ] [ 1 ] > offdiag [ i ] [ 1 ] ) : offdiag [ j ] [ 1 ] - = 1
offdiag [ j ] . sort ( )
NBlocs - = 1
for i in range ( NBlocs ) :
blocs [ i ] . sort ( )
2014-09-22 19:24:33 +02:00
self . gf_struct_solver [ ish ] . update ( [ ( ' %s _ %s ' % ( a , i ) , range ( len ( blocs [ i ] ) ) ) ] )
gf_struct_temp . append ( ( ' %s _ %s ' % ( a , i ) , blocs [ i ] ) )
2013-07-23 19:49:42 +02:00
# map is the mapping of the blocs from the SK blocs to the CTQMC blocs:
self . map [ ish ] [ a ] = range ( len ( dmbool ) )
for ibl in range ( NBlocs ) :
for j in range ( len ( blocs [ ibl ] ) ) :
2014-09-22 19:24:33 +02:00
self . map [ ish ] [ a ] [ blocs [ ibl ] [ j ] ] = ' %s _ %s ' % ( a , ibl )
self . map_inv [ ish ] [ ' %s _ %s ' % ( a , ibl ) ] = a
2013-07-23 19:49:42 +02:00
# now calculate degeneracies of orbitals:
dm = { }
for bl in gf_struct_temp :
bln = bl [ 0 ]
ind = bl [ 1 ]
# get dm for the blocks:
dm [ bln ] = numpy . zeros ( [ len ( ind ) , len ( ind ) ] , numpy . complex_ )
for i in range ( len ( ind ) ) :
for j in range ( len ( ind ) ) :
dm [ bln ] [ i , j ] = dens_mat [ ish ] [ self . map_inv [ ish ] [ bln ] ] [ ind [ i ] , ind [ j ] ]
for bl in gf_struct_temp :
for bl2 in gf_struct_temp :
if ( dm [ bl [ 0 ] ] . shape == dm [ bl2 [ 0 ] ] . shape ) :
if ( ( ( abs ( dm [ bl [ 0 ] ] - dm [ bl2 [ 0 ] ] ) < threshold ) . all ( ) ) and ( bl [ 0 ] != bl2 [ 0 ] ) ) :
# check if it was already there:
ind1 = - 1
ind2 = - 2
for n , ind in enumerate ( self . deg_shells [ ish ] ) :
if ( bl [ 0 ] in ind ) : ind1 = n
if ( bl2 [ 0 ] in ind ) : ind2 = n
if ( ( ind1 < 0 ) and ( ind2 > = 0 ) ) :
self . deg_shells [ ish ] [ ind2 ] . append ( bl [ 0 ] )
elif ( ( ind1 > = 0 ) and ( ind2 < 0 ) ) :
self . deg_shells [ ish ] [ ind1 ] . append ( bl2 [ 0 ] )
elif ( ( ind1 < 0 ) and ( ind2 < 0 ) ) :
self . deg_shells [ ish ] . append ( [ bl [ 0 ] , bl2 [ 0 ] ] )
2014-11-07 00:55:40 +01:00
things_to_save = [ ' gf_struct_solver ' , ' map ' , ' map_inv ' , ' deg_shells ' ]
self . save ( things_to_save )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
return dens_mat
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def symm_deg_gf ( self , gf_to_symm , orb ) :
""" Symmetrises a GF for the given degenerate shells self.deg_shells """
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for degsh in self . deg_shells [ orb ] :
#loop over degenerate shells:
ss = gf_to_symm [ degsh [ 0 ] ] . copy ( )
ss . zero ( )
Ndeg = len ( degsh )
for bl in degsh : ss + = gf_to_symm [ bl ] / ( 1.0 * Ndeg )
2014-10-28 16:19:28 +01:00
for bl in degsh : gf_to_symm [ bl ] << ss
2013-07-23 19:49:42 +02:00
2014-10-28 16:19:28 +01:00
# for simply dft input, get crystal field splittings.
2013-07-23 19:49:42 +02:00
def eff_atomic_levels ( self ) :
""" Calculates the effective atomic levels needed as input for the Hubbard I Solver. """
# define matrices for inequivalent shells:
eff_atlevels = [ { } for ish in range ( self . n_inequiv_corr_shells ) ]
for ish in range ( self . n_inequiv_corr_shells ) :
for bn in self . block_names [ self . corr_shells [ self . invshellmap [ ish ] ] [ 4 ] ] :
eff_atlevels [ ish ] [ bn ] = numpy . identity ( self . corr_shells [ self . invshellmap [ ish ] ] [ 3 ] , numpy . complex_ )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# Chemical Potential:
2014-09-22 19:24:33 +02:00
for ish in xrange ( self . n_inequiv_corr_shells ) :
2013-07-23 19:49:42 +02:00
for ii in eff_atlevels [ ish ] : eff_atlevels [ ish ] [ ii ] * = - self . chemical_potential
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# double counting term:
#if hasattr(self,"dc_imp"):
2014-09-22 19:24:33 +02:00
for ish in xrange ( self . n_inequiv_corr_shells ) :
2013-07-23 19:49:42 +02:00
for ii in eff_atlevels [ ish ] :
eff_atlevels [ ish ] [ ii ] - = self . dc_imp [ self . invshellmap [ ish ] ] [ ii ]
# sum over k:
if not hasattr ( self , " Hsumk " ) :
# calculate the sum over k. Does not depend on mu, so do it only once:
self . Hsumk = [ { } for ish in range ( self . n_corr_shells ) ]
for icrsh in range ( self . n_corr_shells ) :
2014-09-22 19:24:33 +02:00
for bn in self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] :
2013-07-23 19:49:42 +02:00
dim = self . corr_shells [ icrsh ] [ 3 ] #*(1+self.corr_shells[icrsh][4])
self . Hsumk [ icrsh ] [ bn ] = numpy . zeros ( [ dim , dim ] , numpy . complex_ )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for icrsh in range ( self . n_corr_shells ) :
dim = self . corr_shells [ icrsh ] [ 3 ]
for ibn , bn in enumerate ( self . block_names [ self . corr_shells [ icrsh ] [ 4 ] ] ) :
isp = self . names_to_ind [ self . corr_shells [ icrsh ] [ 4 ] ] [ bn ]
for ik in xrange ( self . n_k ) :
n_orb = self . n_orbitals [ ik , isp ]
MMat = numpy . identity ( n_orb , numpy . complex_ )
MMat = self . hopping [ ik , isp , 0 : n_orb , 0 : n_orb ] - ( 1 - 2 * ibn ) * self . h_field * MMat
2014-10-28 16:19:28 +01:00
self . Hsumk [ icrsh ] [ bn ] + = self . bz_weights [ ik ] * numpy . dot ( numpy . dot ( self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] , MMat ) ,
2013-07-23 19:49:42 +02:00
self . proj_mat [ ik , isp , icrsh , 0 : dim , 0 : n_orb ] . conjugate ( ) . transpose ( ) )
# symmetrisation:
2014-11-07 00:55:40 +01:00
if ( self . symm_op != 0 ) : self . Hsumk = self . symmcorr . symmetrize ( self . Hsumk )
2013-07-23 19:49:42 +02:00
# Rotate to local coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
for bn in self . Hsumk [ icrsh ] :
if ( self . rot_mat_time_inv [ icrsh ] == 1 ) : self . Hsumk [ icrsh ] [ bn ] = self . Hsumk [ icrsh ] [ bn ] . conjugate ( )
#if (self.corr_shells[icrsh][4]==0): self.Hsumk[icrsh][bn] = self.Hsumk[icrsh][bn].conjugate()
2014-09-22 19:24:33 +02:00
self . Hsumk [ icrsh ] [ bn ] = numpy . dot ( numpy . dot ( self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) , self . Hsumk [ icrsh ] [ bn ] ) ,
2013-07-23 19:49:42 +02:00
self . rot_mat [ icrsh ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# add to matrix:
2014-09-22 19:24:33 +02:00
for ish in xrange ( self . n_inequiv_corr_shells ) :
2013-07-23 19:49:42 +02:00
for bn in eff_atlevels [ ish ] :
eff_atlevels [ ish ] [ bn ] + = self . Hsumk [ self . invshellmap [ ish ] ] [ bn ]
return eff_atlevels
def __init_dc ( self ) :
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# construct the density matrix dm_imp and double counting arrays
#self.dm_imp = [ {} for i in xrange(self.n_corr_shells)]
self . dc_imp = [ { } for i in xrange ( self . n_corr_shells ) ]
for i in xrange ( self . n_corr_shells ) :
l = self . corr_shells [ i ] [ 3 ]
for j in xrange ( len ( self . gf_struct_corr [ i ] ) ) :
self . dc_imp [ i ] [ ' %s ' % self . gf_struct_corr [ i ] [ j ] [ 0 ] ] = numpy . zeros ( [ l , l ] , numpy . float_ )
self . dc_energ = [ 0.0 for i in xrange ( self . n_corr_shells ) ]
def set_dc ( self , dens_mat , U_interact , J_hund , orb = 0 , use_dc_formula = 0 , use_val = None ) :
2014-09-22 19:24:33 +02:00
""" Sets the double counting term for inequiv orbital orb:
use_dc_formula = 0 : LDA + U FLL double counting ,
use_dc_formula = 1 : Held ' s formula,
use_dc_formula = 2 : AMF .
Be sure that you are using the correct interaction Hamiltonian ! """
2014-01-21 16:25:44 +01:00
2013-07-23 19:49:42 +02:00
for icrsh in xrange ( self . n_corr_shells ) :
iorb = self . shellmap [ icrsh ] # iorb is the index of the inequivalent shell corresponding to icrsh
if ( iorb == orb ) :
# do this orbital
Ncr = { }
l = self . corr_shells [ icrsh ] [ 3 ] #*(1+self.corr_shells[icrsh][4])
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for j in xrange ( len ( self . gf_struct_corr [ icrsh ] ) ) :
self . dc_imp [ icrsh ] [ ' %s ' % self . gf_struct_corr [ icrsh ] [ j ] [ 0 ] ] = numpy . identity ( l , numpy . float_ )
blname = self . gf_struct_corr [ icrsh ] [ j ] [ 0 ]
Ncr [ blname ] = 0.0
2014-09-22 19:24:33 +02:00
for a , al in self . gf_struct_solver [ iorb ] . iteritems ( ) :
2014-01-21 16:25:44 +01:00
bl = self . map_inv [ iorb ] [ a ]
Ncr [ bl ] + = dens_mat [ a ] . real . trace ( )
2013-07-23 19:49:42 +02:00
M = self . corr_shells [ icrsh ] [ 3 ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
Ncrtot = 0.0
a_list = [ a for a , al in self . gf_struct_corr [ icrsh ] ]
for bl in a_list :
Ncrtot + = Ncr [ bl ]
# average the densities if there is no SP:
if ( self . SP == 0 ) :
for bl in a_list :
Ncr [ bl ] = Ncrtot / len ( a_list )
# 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 bl in a_list :
Ncr [ bl ] = Ncrtot / 2.0
if ( use_val is None ) :
2014-09-22 19:24:33 +02:00
if ( use_dc_formula == 0 ) : # FLL
2014-10-28 16:19:28 +01:00
2013-07-23 19:49:42 +02:00
self . dc_energ [ icrsh ] = U_interact / 2.0 * Ncrtot * ( Ncrtot - 1.0 )
for bl in a_list :
Uav = U_interact * ( Ncrtot - 0.5 ) - J_hund * ( Ncr [ bl ] - 0.5 )
2014-09-22 19:24:33 +02:00
self . dc_imp [ icrsh ] [ bl ] * = Uav
2013-07-23 19:49:42 +02:00
self . dc_energ [ icrsh ] - = J_hund / 2.0 * ( Ncr [ bl ] ) * ( Ncr [ bl ] - 1.0 )
mpi . report ( " DC for shell %(icrsh)i and block %(bl)s = %(Uav)f " % locals ( ) )
2014-10-28 16:19:28 +01:00
2014-09-22 19:24:33 +02:00
elif ( use_dc_formula == 1 ) : # Held's formula, with U_interact the interorbital onsite interaction
2014-10-28 16:19:28 +01:00
2014-03-31 18:13:48 +02:00
self . dc_energ [ icrsh ] = ( U_interact + ( M - 1 ) * ( U_interact - 2.0 * J_hund ) + ( M - 1 ) * ( U_interact - 3.0 * J_hund ) ) / ( 2 * M - 1 ) / 2.0 * Ncrtot * ( Ncrtot - 1.0 )
2013-07-23 19:49:42 +02:00
for bl in a_list :
2014-03-31 18:13:48 +02:00
Uav = ( U_interact + ( M - 1 ) * ( U_interact - 2.0 * J_hund ) + ( M - 1 ) * ( U_interact - 3.0 * J_hund ) ) / ( 2 * M - 1 ) * ( Ncrtot - 0.5 )
2014-09-22 19:24:33 +02:00
self . dc_imp [ icrsh ] [ bl ] * = Uav
2013-07-23 19:49:42 +02:00
mpi . report ( " DC for shell %(icrsh)i and block %(bl)s = %(Uav)f " % locals ( ) )
2014-10-28 16:19:28 +01:00
2014-09-22 19:24:33 +02:00
elif ( use_dc_formula == 2 ) : # AMF
2014-10-28 16:19:28 +01:00
2013-07-23 19:49:42 +02:00
self . dc_energ [ icrsh ] = 0.5 * U_interact * Ncrtot * Ncrtot
for bl in a_list :
Uav = U_interact * ( Ncrtot - Ncr [ bl ] / M ) - J_hund * ( Ncr [ bl ] - Ncr [ bl ] / M )
self . dc_imp [ icrsh ] [ bl ] * = Uav
self . dc_energ [ icrsh ] - = ( U_interact + ( M - 1 ) * J_hund ) / M * 0.5 * Ncr [ bl ] * Ncr [ bl ]
mpi . report ( " DC for shell %(icrsh)i and block %(bl)s = %(Uav)f " % locals ( ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# output:
mpi . report ( " DC energy for shell %s = %s " % ( icrsh , self . dc_energ [ icrsh ] ) )
2014-09-22 19:24:33 +02:00
else :
2013-07-23 19:49:42 +02:00
a_list = [ a for a , al in self . gf_struct_corr [ icrsh ] ]
for bl in a_list :
self . dc_imp [ icrsh ] [ bl ] * = use_val
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
self . dc_energ [ icrsh ] = use_val * Ncrtot
# output:
mpi . report ( " DC for shell %(icrsh)i = %(use_val)f " % locals ( ) )
mpi . report ( " DC energy = %s " % self . dc_energ [ icrsh ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def put_Sigma ( self , Sigma_imp ) :
""" Puts the impurity self energies for inequivalent atoms into the class, respects the multiplicity of the atoms. """
assert isinstance ( Sigma_imp , list ) , " Sigma_imp has to be a list of Sigmas for the correlated shells, even if it is of length 1! "
assert len ( Sigma_imp ) == self . n_inequiv_corr_shells , " give exactly one Sigma for each inequivalent corr. shell! "
# init self.Sigma_imp:
2014-10-28 16:19:28 +01:00
if all ( type ( g ) == GfImFreq for name , g in Sigma_imp [ 0 ] ) :
# Imaginary frequency Sigma:
self . Sigma_imp = [ BlockGf ( name_block_generator = [ ( a , GfImFreq ( indices = al , mesh = Sigma_imp [ 0 ] . mesh ) ) for a , al in self . gf_struct_corr [ i ] ] ,
make_copies = False ) for i in xrange ( self . n_corr_shells ) ]
elif all ( type ( g ) == GfReFreq for name , g in Sigma_imp [ 0 ] ) :
2013-07-23 19:49:42 +02:00
# Real frequency Sigma:
self . Sigma_imp = [ BlockGf ( name_block_generator = [ ( a , GfReFreq ( indices = al , mesh = Sigma_imp [ 0 ] . mesh ) ) for a , al in self . gf_struct_corr [ i ] ] ,
make_copies = False ) for i in xrange ( self . n_corr_shells ) ]
else :
2014-10-28 16:19:28 +01:00
raise ValueError , " This type of Sigma is not handled. "
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# transform the CTQMC blocks to the full matrix:
for icrsh in xrange ( self . n_corr_shells ) :
s = self . shellmap [ icrsh ] # s is the index of the inequivalent shell corresponding to icrsh
# setting up the index map:
map_ind = { }
cnt = { }
for blname in self . map [ s ] :
cnt [ blname ] = 0
2014-09-22 19:24:33 +02:00
for a , al in self . gf_struct_solver [ s ] . iteritems ( ) :
2013-07-23 19:49:42 +02:00
blname = self . map_inv [ s ] [ a ]
map_ind [ a ] = range ( len ( al ) )
for i in al :
map_ind [ a ] [ i ] = cnt [ blname ]
cnt [ blname ] + = 1
2014-09-22 19:24:33 +02:00
for bl , orblist in self . gf_struct_solver [ s ] . iteritems ( ) :
for i in range ( len ( orblist ) ) :
for j in range ( len ( orblist ) ) :
ind1 = orblist [ i ]
ind2 = orblist [ j ]
2013-07-23 19:49:42 +02:00
ind1_imp = map_ind [ bl ] [ ind1 ]
ind2_imp = map_ind [ bl ] [ ind2 ]
2014-10-28 16:19:28 +01:00
self . Sigma_imp [ icrsh ] [ self . map_inv [ s ] [ bl ] ] [ ind1_imp , ind2_imp ] << Sigma_imp [ s ] [ bl ] [ ind1 , ind2 ]
2013-07-23 19:49:42 +02:00
# rotation from local to global coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
2014-10-28 16:19:28 +01:00
for sig , gf in self . Sigma_imp [ icrsh ] : self . Sigma_imp [ icrsh ] [ sig ] << self . rotloc ( icrsh , gf , direction = ' toGlobal ' )
2013-07-23 19:49:42 +02:00
def add_dc ( self ) :
""" Substracts the double counting term from the impurity self energy. """
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# Be careful: Sigma_imp is already in the global coordinate system!!
sres = [ s . copy ( ) for s in self . Sigma_imp ]
for icrsh in xrange ( self . n_corr_shells ) :
for bl , gf in sres [ icrsh ] :
2014-10-28 16:19:28 +01:00
# Transform dc_imp to global coordinate system
2013-07-23 19:49:42 +02:00
dccont = numpy . dot ( self . rot_mat [ icrsh ] , numpy . dot ( self . dc_imp [ icrsh ] [ bl ] , self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) ) )
sres [ icrsh ] [ bl ] - = dccont
2014-10-28 16:19:28 +01:00
return sres # list of self energies corrected by DC
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def set_mu ( self , mu ) :
""" Sets a new chemical potential """
2014-11-07 00:55:40 +01:00
self . chemical_potential = mu
2013-07-23 19:49:42 +02:00
def inequiv_shells ( self , lst ) :
"""
The number of inequivalent shells is calculated from lst , and a mapping is given as
map ( i_corr_shells ) = i_inequiv_corr_shells
invmap ( i_inequiv_corr_shells ) = i_corr_shells
in order to put the Self energies to all equivalent shells , and for extracting Gloc
"""
tmp = [ ]
self . shellmap = [ 0 for i in range ( len ( lst ) ) ]
self . invshellmap = [ 0 ]
self . n_inequiv_corr_shells = 1
tmp . append ( lst [ 0 ] [ 1 : 3 ] )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
if ( len ( lst ) > 1 ) :
for i in range ( len ( lst ) - 1 ) :
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
fnd = False
for j in range ( self . n_inequiv_corr_shells ) :
if ( tmp [ j ] == lst [ i + 1 ] [ 1 : 3 ] ) :
fnd = True
self . shellmap [ i + 1 ] = j
if ( fnd == False ) :
self . shellmap [ i + 1 ] = self . n_inequiv_corr_shells
self . n_inequiv_corr_shells + = 1
tmp . append ( lst [ i + 1 ] [ 1 : 3 ] )
self . invshellmap . append ( i + 1 )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def total_density ( self , mu ) :
"""
2014-09-22 19:24:33 +02:00
Calculates the total charge for the energy window for a given mu . Since in general n_orbitals depends on k ,
2013-07-23 19:49:42 +02:00
the calculation is done in the following order :
2014-09-22 19:24:33 +02:00
G_aa ' (k,iw) -> n(k) = Tr G_aa ' ( k , iw ) - > sum_k n_k
2013-07-23 19:49:42 +02:00
mu : chemical potential
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
The calculation is done in the global coordinate system , if distinction is made between local / global !
"""
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
dens = 0.0
ikarray = numpy . array ( range ( self . n_k ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for ik in mpi . slice_array ( ikarray ) :
2014-09-22 19:24:33 +02:00
S = self . lattice_gf_matsubara ( ik = ik , mu = mu )
2013-07-23 19:49:42 +02:00
dens + = self . bz_weights [ ik ] * S . total_density ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# collect data from mpi:
dens = mpi . all_reduce ( mpi . world , dens , lambda x , y : x + y )
mpi . barrier ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
return dens
def find_mu ( self , precision = 0.01 ) :
""" Searches for mu in order to give the desired charge
A desired precision can be specified in precision . """
F = lambda mu : self . total_density ( mu = mu )
2014-11-07 00:55:40 +01:00
density = self . density_required - self . charge_below
2013-07-23 19:49:42 +02:00
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
self . chemical_potential = dichotomy . dichotomy ( function = F ,
2014-11-07 00:55:40 +01:00
x_init = self . chemical_potential , y_value = density ,
precision_on_y = precision , delta_x = 0.5 , max_loops = 100 ,
x_name = " Chemical Potential " , y_name = " Total Density " ,
2013-07-23 19:49:42 +02:00
verbosity = 3 ) [ 0 ]
return self . chemical_potential
def extract_G_loc ( self , mu = None , with_Sigma = True ) :
2014-09-22 19:24:33 +02:00
"""
2013-07-23 19:49:42 +02:00
extracts the local downfolded Green function at the chemical potential of the class .
2014-09-22 19:24:33 +02:00
At the end , the local G is rotated from the global coordinate system to the local system .
2013-07-23 19:49:42 +02:00
if with_Sigma = False : Sigma is not included = > non - interacting local GF
"""
if ( mu is None ) : mu = self . chemical_potential
2014-09-22 19:24:33 +02:00
Gloc = [ self . Sigma_imp [ icrsh ] . copy ( ) for icrsh in xrange ( self . n_corr_shells ) ] # this list will be returned
2013-07-23 19:49:42 +02:00
for icrsh in xrange ( self . n_corr_shells ) : Gloc [ icrsh ] . zero ( ) # initialize to zero
beta = Gloc [ 0 ] . mesh . beta
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
ikarray = numpy . array ( range ( self . n_k ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for ik in mpi . slice_array ( ikarray ) :
2014-09-22 19:24:33 +02:00
S = self . lattice_gf_matsubara ( ik = ik , mu = mu , with_Sigma = with_Sigma , beta = beta )
2013-07-23 19:49:42 +02:00
S * = self . bz_weights [ ik ]
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for icrsh in xrange ( self . n_corr_shells ) :
tmp = Gloc [ icrsh ] . copy ( ) # init temporary storage
2014-10-28 16:19:28 +01:00
for sig , gf in tmp : tmp [ sig ] << self . downfold ( ik , icrsh , sig , S [ sig ] , gf )
2013-07-23 19:49:42 +02:00
Gloc [ icrsh ] + = tmp
#collect data from mpi:
for icrsh in xrange ( self . n_corr_shells ) :
2014-10-28 16:19:28 +01:00
Gloc [ icrsh ] << mpi . all_reduce ( mpi . world , Gloc [ icrsh ] , lambda x , y : x + y )
2013-07-23 19:49:42 +02:00
mpi . barrier ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# Gloc[:] is now the sum over k projected to the local orbitals.
2014-09-22 19:24:33 +02:00
# here comes the symmetrisation, if needed:
2014-11-07 00:55:40 +01:00
if ( self . symm_op != 0 ) : Gloc = self . symmcorr . symmetrize ( Gloc )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# Gloc is rotated to the local coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
2014-10-28 16:19:28 +01:00
for sig , gf in Gloc [ icrsh ] : Gloc [ icrsh ] [ sig ] << self . rotloc ( icrsh , gf , direction = ' toLocal ' )
2013-07-23 19:49:42 +02:00
# transform to CTQMC blocks:
2014-09-22 19:24:33 +02:00
Glocret = [ BlockGf ( name_block_generator = [ ( a , GfImFreq ( indices = al , mesh = Gloc [ 0 ] . mesh ) ) for a , al in self . gf_struct_solver [ i ] . iteritems ( ) ] ,
2013-07-23 19:49:42 +02:00
make_copies = False ) for i in xrange ( self . n_inequiv_corr_shells ) ]
for ish in xrange ( self . n_inequiv_corr_shells ) :
# setting up the index map:
map_ind = { }
cnt = { }
for blname in self . map [ ish ] :
cnt [ blname ] = 0
2014-09-22 19:24:33 +02:00
for a , al in self . gf_struct_solver [ ish ] . iteritems ( ) :
2013-07-23 19:49:42 +02:00
blname = self . map_inv [ ish ] [ a ]
map_ind [ a ] = range ( len ( al ) )
for i in al :
map_ind [ a ] [ i ] = cnt [ blname ]
cnt [ blname ] + = 1
2014-09-22 19:24:33 +02:00
for bl , orblist in self . gf_struct_solver [ ish ] . iteritems ( ) :
for i in range ( len ( orblist ) ) :
for j in range ( len ( orblist ) ) :
ind1 = orblist [ i ]
ind2 = orblist [ j ]
2013-07-23 19:49:42 +02:00
ind1_imp = map_ind [ bl ] [ ind1 ]
ind2_imp = map_ind [ bl ] [ ind2 ]
2014-10-28 16:19:28 +01:00
Glocret [ ish ] [ bl ] [ ind1 , ind2 ] << Gloc [ self . invshellmap [ ish ] ] [ self . map_inv [ ish ] [ bl ] ] [ ind1_imp , ind2_imp ]
2013-07-23 19:49:42 +02:00
# return only the inequivalent shells:
return Glocret
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
def calc_density_correction ( self , filename = ' dens_mat.dat ' ) :
""" Calculates the density correction in order to feed it back to the DFT calculations. """
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
assert ( type ( filename ) == StringType ) , " filename has to be a string! "
ntoi = self . names_to_ind [ self . SO ]
bln = self . block_names [ self . SO ]
# Set up deltaN:
deltaN = { }
for ib in bln :
deltaN [ ib ] = [ numpy . zeros ( [ self . n_orbitals [ ik , ntoi [ ib ] ] , self . n_orbitals [ ik , ntoi [ ib ] ] ] , numpy . complex_ ) for ik in range ( self . n_k ) ]
ikarray = numpy . array ( range ( self . n_k ) )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
dens = { }
for ib in bln :
dens [ ib ] = 0.0
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
for ik in mpi . slice_array ( ikarray ) :
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
S = self . lattice_gf_matsubara ( ik = ik , mu = self . chemical_potential )
for sig , g in S :
deltaN [ sig ] [ ik ] = S [ sig ] . density ( )
dens [ sig ] + = self . bz_weights [ ik ] * S [ sig ] . total_density ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
#put mpi Barrier:
for sig in deltaN :
for ik in range ( self . n_k ) :
deltaN [ sig ] [ ik ] = mpi . all_reduce ( mpi . world , deltaN [ sig ] [ ik ] , lambda x , y : x + y )
dens [ sig ] = mpi . all_reduce ( mpi . world , dens [ sig ] , lambda x , y : x + y )
mpi . barrier ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
# now save to file:
if ( mpi . is_master_node ( ) ) :
if ( self . SP == 0 ) :
f = open ( filename , ' w ' )
else :
f = open ( filename + ' up ' , ' w ' )
f1 = open ( filename + ' dn ' , ' w ' )
# write chemical potential (in Rydberg):
f . write ( " %.14f \n " % ( self . chemical_potential / self . energy_unit ) )
if ( self . SP != 0 ) : f1 . write ( " %.14f \n " % ( self . chemical_potential / self . energy_unit ) )
# write beta in ryderg-1
f . write ( " %.14f \n " % ( S . mesh . beta * self . energy_unit ) )
if ( self . SP != 0 ) : f1 . write ( " %.14f \n " % ( S . mesh . beta * self . energy_unit ) )
if ( self . SP == 0 ) :
for ik in range ( self . n_k ) :
f . write ( " %s \n " % self . n_orbitals [ ik , 0 ] )
for inu in range ( self . n_orbitals [ ik , 0 ] ) :
for imu in range ( self . n_orbitals [ ik , 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
f . write ( " %.14f %.14f " % ( valre , valim ) )
f . write ( " \n " )
f . write ( " \n " )
f . close ( )
elif ( ( self . SP == 1 ) and ( self . SO == 0 ) ) :
for ik in range ( self . n_k ) :
f . write ( " %s \n " % self . n_orbitals [ ik , 0 ] )
for inu in range ( self . n_orbitals [ ik , 0 ] ) :
for imu in range ( self . n_orbitals [ ik , 0 ] ) :
f . write ( " %.14f %.14f " % ( deltaN [ ' up ' ] [ ik ] [ inu , imu ] . real , deltaN [ ' up ' ] [ ik ] [ inu , imu ] . imag ) )
f . write ( " \n " )
f . write ( " \n " )
f . close ( )
for ik in range ( self . n_k ) :
f1 . write ( " %s \n " % self . n_orbitals [ ik , 1 ] )
for inu in range ( self . n_orbitals [ ik , 1 ] ) :
for imu in range ( self . n_orbitals [ ik , 1 ] ) :
f1 . write ( " %.14f %.14f " % ( deltaN [ ' down ' ] [ ik ] [ inu , imu ] . real , deltaN [ ' down ' ] [ ik ] [ inu , imu ] . imag ) )
f1 . write ( " \n " )
f1 . write ( " \n " )
f1 . close ( )
else :
for ik in range ( self . n_k ) :
f . write ( " %s \n " % self . n_orbitals [ ik , 0 ] )
for inu in range ( self . n_orbitals [ ik , 0 ] ) :
for imu in range ( self . n_orbitals [ ik , 0 ] ) :
f . write ( " %.14f %.14f " % ( deltaN [ ' ud ' ] [ ik ] [ inu , imu ] . real , deltaN [ ' ud ' ] [ ik ] [ inu , imu ] . imag ) )
f . write ( " \n " )
f . write ( " \n " )
f . close ( )
for ik in range ( self . n_k ) :
f1 . write ( " %s \n " % self . n_orbitals [ ik , 0 ] )
for inu in range ( self . n_orbitals [ ik , 0 ] ) :
for imu in range ( self . n_orbitals [ ik , 0 ] ) :
f1 . write ( " %.14f %.14f " % ( deltaN [ ' ud ' ] [ ik ] [ inu , imu ] . real , deltaN [ ' ud ' ] [ ik ] [ inu , imu ] . imag ) )
f1 . write ( " \n " )
f1 . write ( " \n " )
f1 . close ( )
2014-09-22 19:24:33 +02:00
2013-07-23 19:49:42 +02:00
return deltaN , dens
2014-10-28 16:19:28 +01:00
################
# FIXME LEAVE UNDOCUMENTED
################
2014-10-31 18:52:32 +01:00
def find_mu_nonint ( self , dens_req , orb = None , beta = 40 , precision = 0.01 ) :
def F ( mu ) :
gnonint = self . extract_G_loc ( mu = mu , with_Sigma = False )
if ( orb is None ) :
dens = 0.0
for ish in range ( self . n_inequiv_corr_shells ) :
dens + = gnonint [ ish ] . total_density ( )
else :
dens = gnonint [ orb ] . total_density ( )
return dens
self . chemical_potential = dichotomy . dichotomy ( function = F ,
2014-11-07 00:55:40 +01:00
x_init = self . chemical_potential , y_value = dens_req ,
precision_on_y = precision , delta_x = 0.5 , max_loops = 100 ,
x_name = " Chemical Potential " , y_name = " Total Density " ,
verbosity = 3 ) [ 0 ]
2014-10-31 18:52:32 +01:00
return self . chemical_potential
2014-10-28 16:19:28 +01:00
def find_dc ( self , orb , guess , dens_mat , dens_req = None , precision = 0.01 ) :
""" Searches for DC in order to fulfill charge neutrality.
If dens_req is given , then DC is set such that the LOCAL charge of orbital
orb coincides with dens_req . """
mu = self . chemical_potential
def F ( dc ) :
self . set_dc ( dens_mat = dens_mat , U_interact = 0 , J_hund = 0 , orb = orb , use_val = dc )
if ( dens_req is None ) :
return self . total_density ( mu = mu )
else :
return self . extract_G_loc ( ) [ orb ] . total_density ( )
if ( dens_req is None ) :
2014-11-07 00:55:40 +01:00
density = self . density_required - self . charge_below
2014-10-28 16:19:28 +01:00
else :
2014-11-07 00:55:40 +01:00
density = dens_req
2014-10-28 16:19:28 +01:00
dcnew = dichotomy . dichotomy ( function = F ,
2014-11-07 00:55:40 +01:00
x_init = guess , y_value = density ,
2014-10-28 16:19:28 +01:00
precision_on_y = precision , delta_x = 0.5 ,
max_loops = 100 , x_name = " Double-Counting " , y_name = " Total Density " ,
verbosity = 3 ) [ 0 ]
return dcnew
# FIXME Check that dens matrix from projectors (DM=PPdagger) is correct (ie matches DFT)
def check_projectors ( self ) :
dens_mat = [ numpy . zeros ( [ self . corr_shells [ ish ] [ 3 ] , self . corr_shells [ ish ] [ 3 ] ] , numpy . complex_ )
for ish in range ( self . n_corr_shells ) ]
for ik in range ( self . n_k ) :
for ish in range ( self . n_corr_shells ) :
dim = self . corr_shells [ ish ] [ 3 ]
n_orb = self . n_orbitals [ ik , 0 ]
dens_mat [ ish ] [ : , : ] + = numpy . dot ( self . proj_mat [ ik , 0 , ish , 0 : dim , 0 : n_orb ] , self . proj_mat [ ik , 0 , ish , 0 : dim , 0 : n_orb ] . transpose ( ) . conjugate ( ) ) * self . bz_weights [ ik ]
2014-11-07 00:55:40 +01:00
if ( self . symm_op != 0 ) : dens_mat = self . symmcorr . symmetrize ( dens_mat )
2014-10-28 16:19:28 +01:00
# Rotate to local coordinate system:
if ( self . use_rotations ) :
for icrsh in xrange ( self . n_corr_shells ) :
if ( self . rot_mat_time_inv [ icrsh ] == 1 ) : dens_mat [ icrsh ] = dens_mat [ icrsh ] . conjugate ( )
dens_mat [ icrsh ] = numpy . dot ( numpy . dot ( self . rot_mat [ icrsh ] . conjugate ( ) . transpose ( ) , dens_mat [ icrsh ] ) ,
self . rot_mat [ icrsh ] )
return dens_mat
# FIXME DETERMINE EQUIVALENCY OF SHELLS
def sorts_of_atoms ( self , lst ) :
"""
This routine should determine the number of sorts in the double list lst
"""
sortlst = [ lst [ i ] [ 1 ] for i in xrange ( len ( lst ) ) ]
sortlst . sort ( )
sorts = 1
for i in xrange ( len ( sortlst ) - 1 ) :
if sortlst [ i + 1 ] > sortlst [ i ] : sorts + = 1
return sorts
def number_of_atoms ( self , lst ) :
"""
This routine should determine the number of atoms in the double list lst
"""
atomlst = [ lst [ i ] [ 0 ] for i in xrange ( len ( lst ) ) ]
atomlst . sort ( )
atoms = 1
for i in xrange ( len ( atomlst ) - 1 ) :
if atomlst [ i + 1 ] > atomlst [ i ] : atoms + = 1
return atoms