Skip to content

Commit

Permalink
STABLE: generic site-reduced density matrices
Browse files Browse the repository at this point in the history
Added a generic public subroutine to further reduce the cluster density matrix.

ed_get_reduced_dm(rdm,Nsites,[doprint,optional]), in ED_IO module.

It takes in the number of sites of the desired subsystem:
- Nsites = 1 gives you the local density matrix (cfr. Walsh et al.)
- Nsites = Nlat gives you the full-cluster density matrix (cdm)
- 1 < Nsites < Nlat scales in between

> NB] There is no choice on the "order" on which the sites are traced away.

The other get_*_dm() procedures have been slightly touched to conform with the new one and improve the usability (i.e. no more need to allocate the output variables).

> You can generally see how these density-matrix-related procedures are called and used looking at the HM-2DSQUARE driver.

=== >> TESTING << ===

Thorough testing has been successfully carried out on the 2d-square Hubbard model. For Nlat up to 5 (Nbath=Norb=1)...

+ We compare the local density matrix with the well-known analytical results in terms of the spin- and double-occupations
> match to machine precision

+ We perform a site-by-site consistency test comparing the directly-reduced matrix (where we trace _at once_ Nlat-Nsites sites) and the iteratively-reduced one (where we call Nlat-Nsites times an ad hoc subroutine[*] that traces away _a unique site_ from a generic-size dm, feeding each time the result of the previous iteration). We obtain:
 4-site REDUCED DENSITY MATRIX
 > match up to   0.0000000000000000
 3-site REDUCED DENSITY MATRIX
 > match up to   6.9388939039072284E-018
 2-site REDUCED DENSITY MATRIX
 > match up to   2.7755575615628914E-017
 1-site REDUCED DENSITY MATRIX
 > match up to   1.6653345369377348E-016
where is evident that the discrepancy increases, iteration by iteration, due to the accumulation of the numerical error in the ad hoc recipe, but nevertheless stays quite low, proving the robustness of the algorithm.

[*]subtrace() at the end of the hm-2dsquare driver; it will be deleted, for its purpose was just to carry on these tests.

--------

More extensive testing, e.g. Norb going up to 3, has been performed with artificial random sectors (so to avoid the diagonalization step), building on the original test-code by @aamaricci, that has been extended to develop the subtracing algorithm.

Everything is available, for record purposes, at < https://github.com/bellomia/TurboRDM-ED/commits/master >.

--------

We should be ready for production... Merry X-MAS! 🎄
  • Loading branch information
beddalumia committed Dec 23, 2021
1 parent 0bb4a6c commit ed4ba2d
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 63 deletions.
5 changes: 3 additions & 2 deletions CDMFT_ED.f90
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ MODULE CDMFT_ED
ed_get_g0and_matsubara , &
ed_get_delta_realaxis , &
ed_get_g0and_realaxis , &
ed_get_cluster_density_matrix , &
ed_get_single_particle_density_matrix , &
ed_get_cluster_dm , &
ed_get_reduced_dm , &
ed_get_sp_dm , &
ed_print_dm , &
ed_get_dens , &
ed_get_docc , &
Expand Down
25 changes: 19 additions & 6 deletions ED_IO.f90
Original file line number Diff line number Diff line change
Expand Up @@ -187,20 +187,30 @@ MODULE ED_IO
#endif
end interface ed_get_dph

interface ed_get_cluster_density_matrix


interface ed_get_cluster_dm
module procedure :: ed_get_cluster_density_matrix_single
#if __GFORTRAN__ && __GNUC__ > 8
module procedure :: ed_get_cluster_density_matrix_lattice
#endif
end interface ed_get_cluster_density_matrix
end interface ed_get_cluster_dm

interface ed_get_reduced_dm
module procedure :: ed_get_reduced_density_matrix_single
#if __GFORTRAN__ && __GNUC__ > 8
module procedure :: ed_get_reduced_density_matrix_lattice
#endif
end interface ed_get_reduced_dm

interface ed_get_single_particle_density_matrix
interface ed_get_sp_dm
module procedure :: ed_get_single_particle_density_matrix_single
#if __GFORTRAN__ && __GNUC__ > 8
module procedure :: ed_get_single_particle_density_matrix_lattice
#endif
end interface ed_get_single_particle_density_matrix
end interface ed_get_sp_dm



interface ed_gf_cluster
module procedure :: ed_gf_cluster_scalar
Expand Down Expand Up @@ -256,8 +266,9 @@ MODULE ED_IO
public :: ed_get_dse
public :: ed_get_dph

public :: ed_get_cluster_density_matrix
public :: ed_get_single_particle_density_matrix
public :: ed_get_cluster_dm
public :: ed_get_reduced_dm
public :: ed_get_sp_dm

public :: ed_read_impSigma
public :: ed_read_impG
Expand Down Expand Up @@ -320,6 +331,7 @@ MODULE ED_IO
include "ED_IO/get_eimp.f90"
include "ED_IO/get_doubles.f90"
include "ED_IO/get_cluster_dm.f90"
include "ED_IO/get_reduced_dm.f90"
include "ED_IO/get_sp_dm.f90"

#if __GFORTRAN__ && __GNUC__ > 8
Expand All @@ -329,6 +341,7 @@ MODULE ED_IO
include "ED_IO/lattice/get_eimp.f90"
include "ED_IO/lattice/get_doubles.f90"
include "ED_IO/lattice/get_cluster_dm.f90"
include "ED_IO/lattice/get_reduced_dm.f90"
include "ED_IO/lattice/get_sp_dm.f90"
#endif

Expand Down
11 changes: 6 additions & 5 deletions ED_IO/get_cluster_dm.f90
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
subroutine ed_get_cluster_density_matrix_single(dm,doprint)
complex(8),dimension(4**Nimp,4**Nimp),intent(out) :: dm
logical ,intent(in) ,optional :: doprint
logical :: doprint_
complex(8),allocatable,intent(out) :: dm(:,:)
logical ,intent(in) ,optional :: doprint
logical :: doprint_
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
if(.not.allocated(cluster_density_matrix))then
write(LOGfile,"(A)") "cluster_density_matrix is not allocated"
stop
stop "ERROR: cluster_density_matrix is not allocated"
endif
!
dm = cluster_density_matrix
Expand All @@ -22,3 +21,5 @@ end subroutine ed_get_cluster_density_matrix_single





70 changes: 70 additions & 0 deletions ED_IO/get_reduced_dm.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
!+---------------------------------------------------------------------+
!PURPOSE : further reduce the cdm by tracing out (Nlat-Nsites) sites
!+---------------------------------------------------------------------+
subroutine ed_get_reduced_density_matrix_single(rdm,Nsites,doprint)
complex(8),dimension(4**Nimp,4**Nimp) :: cdm
complex(8),dimension(:,:),allocatable,intent(out) :: rdm
integer ,intent(in) :: Nsites
logical ,intent(in),optional :: doprint
logical :: doprint_
integer :: i,j,io,jo,iUP,iDW,jUP,jDW
integer :: iIMPup,iIMPdw,jIMPup,jIMPdw
integer :: iREDup,iREDdw,jREDup,jREDdw
integer :: iTrUP,iTrDW,jTrUP,jTrDW,Nred
!
if(Nsites>Nlat)then
stop "ERROR: cannot request a density matrix reduced to more sites then Nlat"
endif
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
!Retrieve cdm from the global scope
if(.not.allocated(cluster_density_matrix))then
stop "ERROR: cluster_density_matrix is not allocated"
endif
cdm = cluster_density_matrix
!
Nred=Norb*Nsites !Number of levels associated to the Nsites-reduced system
allocate(rdm(4**Nred,4**Nred))
rdm=zero
!
!Trace the cdm to the requested Nsites-rdm
do iUP = 1,2**Nimp
do iDW = 1,2**Nimp
i = iUP + (iDW-1)*2**Nimp
iIMPup = iup-1
iIMPdw = idw-1
iREDup = Ibits(iIMPup,0,Nred)
iREDdw = Ibits(iIMPdw,0,Nred)
iTrUP = Ibits(iIMPup,Nred,Nimp)
iTrDW = Ibits(iIMPdw,Nred,Nimp)
do jUP = 1,2**Nimp
do jDW = 1,2**Nimp
j = jUP + (jDW-1)*2**Nimp
jIMPup = jup-1
jIMPdw = jdw-1
jREDup = Ibits(jIMPup,0,Nred)
jREDdw = Ibits(jIMPdw,0,Nred)
jTrUP = Ibits(jIMPup,Nred,Nimp)
jTrDW = Ibits(jIMPdw,Nred,Nimp)
if(jTrUP/=iTrUP.or.jTrDW/=iTrDW)cycle
io = (iREDup+1) + iREDdw*2**Nred
jo = (jREDup+1) + jREDdw*2**Nred
rdm(io,jo) = rdm(io,jo) + cdm(i,j)
enddo
enddo
enddo
enddo
!
!Print to file (if requested)
if(doprint_)then
call ed_print_dm(rdm,4**Nred)
endif
!
end subroutine ed_get_reduced_density_matrix_single

! NB: the spin-factorization of the loops is paramount,
! since we build in such way the original cdm and the
! ordering of the basis states has to be preserved
! in order to trace along the proper matrix elements

9 changes: 4 additions & 5 deletions ED_IO/get_sp_dm.f90
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
subroutine ed_get_single_particle_density_matrix_single(dm,doprint)
complex(8),dimension(Nlat*Norb*Nspin,Nlat*Norb*Nspin),intent(out) :: dm
logical ,intent(in) ,optional :: doprint
logical :: doprint_
complex(8),allocatable,intent(out) :: dm(:,:)
logical ,intent(in) ,optional :: doprint
logical :: doprint_
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
if(.not.allocated(single_particle_density_matrix))then
write(LOGfile,"(A)") "single_particle_density_matrix is not allocated"
stop
stop "ERROR: single_particle_density_matrix is not allocated"
endif
!
!Impurity problem basis
Expand Down
18 changes: 8 additions & 10 deletions ED_IO/lattice/get_cluster_dm.f90
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@ subroutine ed_get_cluster_density_matrix_lattice(dm,doprint)
complex(8),allocatable,intent(out) :: dm(:,:,:)
logical ,intent(in) ,optional :: doprint
logical :: doprint_
integer :: isite,Nsites
integer :: ii,Nineq
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
Nsites=size(cluster_density_matrix_ii,1)
!
if(.not.allocated(cluster_density_matrix_ii))then
write(LOGfile,"(A)") "cluster_density_matrix_ii is not allocated"
stop
stop "ERROR: cluster_density_matrix_ii is not allocated"
endif
!
allocate(dm(Nsites,4**Nimp,4**Nimp)); dm=zero
Nineq=size(cluster_density_matrix_ii,1)
allocate(dm(Nineq,4**Nimp,4**Nimp)); dm=zero
!
do isite=1,Nsites
do ii=1,Nineq
!
dm(isite,:,:) = cluster_density_matrix_ii(isite,:,:)
dm(ii,:,:) = cluster_density_matrix_ii(ii,:,:)
!
!Print to file [ed_print_dm() is defined in ED_IO.f90]
!Print to file (if requested)
if(doprint_)then
call ed_print_dm(dm(isite,:,:),4**Nimp,ineq=isite)
call ed_print_dm(dm(ii,:,:),4**Nimp,ineq=ii)
endif
!
enddo
Expand Down
80 changes: 80 additions & 0 deletions ED_IO/lattice/get_reduced_dm.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
!+---------------------------------------------------------------------+
!PURPOSE : further reduce the cdms by tracing out (Nlat-Nsites) sites
!+---------------------------------------------------------------------+
subroutine ed_get_reduced_density_matrix_lattice(rdm,Nsites,doprint)
complex(8),allocatable :: cdm(:,:,:)
complex(8),allocatable,intent(out) :: rdm(:,:,:)
integer ,intent(in) :: Nsites
logical ,intent(in),optional :: doprint
logical :: doprint_
integer :: ii,Nineq
integer :: i,j,io,jo,iUP,iDW,jUP,jDW
integer :: iIMPup,iIMPdw,jIMPup,jIMPdw
integer :: iREDup,iREDdw,jREDup,jREDdw
integer :: iTrUP,iTrDW,jTrUP,jTrDW,Nred
!
if(Nsites>Nlat)then
stop "ERROR: cannot request a density matrix reduced to more sites then Nlat"
endif
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
if(.not.allocated(cluster_density_matrix_ii))then
stop "ERROR: cluster_density_matrix_ii is not allocated"
endif
!
Nineq=size(cluster_density_matrix_ii,1)
allocate(cdm(Nineq,4**Nimp,4**Nimp)); cdm=zero
Nred=Norb*Nsites
allocate(rdm(Nineq,4**Nred,4**Nred)); rdm=zero
!
do ii=1,Nineq
!
cdm(ii,:,:) = cluster_density_matrix_ii(ii,:,:)
!
!Trace the cdm(ii,:,:) to the requested Nsites-rdm(ii,:,:)
do iUP = 1,2**Nimp
do iDW = 1,2**Nimp
i = iUP + (iDW-1)*2**Nimp
iIMPup = iup-1
iIMPdw = idw-1
iREDup = Ibits(iIMPup,0,Nred)
iREDdw = Ibits(iIMPdw,0,Nred)
iTrUP = Ibits(iIMPup,Nred,Nimp)
iTrDW = Ibits(iIMPdw,Nred,Nimp)
do jUP = 1,2**Nimp
do jDW = 1,2**Nimp
j = jUP + (jDW-1)*2**Nimp
jIMPup = jup-1
jIMPdw = jdw-1
jREDup = Ibits(jIMPup,0,Nred)
jREDdw = Ibits(jIMPdw,0,Nred)
jTrUP = Ibits(jIMPup,Nred,Nimp)
jTrDW = Ibits(jIMPdw,Nred,Nimp)
if(jTrUP/=iTrUP.or.jTrDW/=iTrDW)cycle
io = (iREDup+1) + iREDdw*2**Nred
jo = (jREDup+1) + jREDdw*2**Nred
rdm(ii,io,jo) = rdm(ii,io,jo) + cdm(ii,i,j)
enddo
enddo
enddo
enddo
!
!Print to file (if requested)
if(doprint_)then
call ed_print_dm(rdm(ii,:,:),4**Nred,ineq=ii)
endif
!
enddo
!
deallocate(cdm)
!
end subroutine ed_get_reduced_density_matrix_lattice

! NB: the spin-factorization of the loops is paramount,
! since we build in such way the original cdm and the
! ordering of the basis states has to be preserved
! in order to trace along the proper matrix elements



18 changes: 8 additions & 10 deletions ED_IO/lattice/get_sp_dm.f90
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,25 @@ subroutine ed_get_single_particle_density_matrix_lattice(dm,doprint)
complex(8),allocatable,intent(out) :: dm(:,:,:)
logical ,intent(in),optional :: doprint
logical :: doprint_
integer :: isite,Nsites
integer :: ii,Nineq
!
doprint_=.false.; if(present(doprint)) doprint_=doprint
!
Nsites=size(single_particle_density_matrix_ii,1)
!
if(.not.allocated(single_particle_density_matrix_ii))then
write(LOGfile,"(A)") "single_particle_density_matrix_ii is not allocated"
stop
stop "ERROR: single_particle_density_matrix_ii is not allocated"
endif
!
allocate(dm(Nsites,Nlat*Nspin*Norb,Nlat*Nspin*Norb)); dm=zero
Nineq=size(single_particle_density_matrix_ii,1)
allocate(dm(Nineq,Nlat*Nspin*Norb,Nlat*Nspin*Norb)); dm=zero
!
do isite=1,Nsites
do ii=1,Nineq
!
!Impurity problem basis
dm(isite,:,:) = nnn2lso_reshape(single_particle_density_matrix_ii(isite,:,:,:,:,:,:),Nlat,Nspin,Norb)
dm(ii,:,:) = nnn2lso_reshape(single_particle_density_matrix_ii(ii,:,:,:,:,:,:),Nlat,Nspin,Norb)
!
!Print to file [ed_print_dm() is defined in ED_IO.f90]
!Print to file (if requested)
if(doprint_)then
call ed_print_dm(dm(isite,:,:),Nlat*Nspin*Norb,ineq=isite)
call ed_print_dm(dm(ii,:,:),Nlat*Nspin*Norb,ineq=ii)
endif
!
enddo
Expand Down
Loading

0 comments on commit ed4ba2d

Please sign in to comment.