! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !
! @@                                                                @@ !
! @@       PROGRAM  ASCOT 2014.440 (ver.4.40)                       @@ !
! @@     "Abinitio Simulation Code for Quantum Transport"           @@ !
! @@                                                                @@ !
! @@                                                                @@ !
! @@  AUTHOR(S): Naoki WATANABE, Nobutaka NISHIKAWA (Mizuho I.R.)   @@ !
! @@             Hisashi KONDO (Univ. Tokyo)                        @@ !
! @@                                                09/May/2014     @@ !
! @@                                                                @@ !
! @@  Contact address: Phase System Consortium                      @@ !
! @@                                                                @@ !
! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !

subroutine DensityMatrix__calc
  use ac_misc_module
  use ac_mpi_module
  implicit none

  integer :: k, m
  integer :: spin, ispin, jspin
  integer :: l
  integer :: a, i, i1
  integer :: b, j, j1

  complex(8) :: bloch

  complex(8) :: ci, cj
  real(8)    :: E, F

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           if( Param%Option%spin_orbit ) then
              Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDMLS(:,:,:) = 0.d0
              if( Param%Option%optimize ) then
                 Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDMLS(:,:) = 0.d0
              end if
           else
              Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDM(:,:,:) = 0.d0
              if( Param%Option%optimize ) then
                 Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDM(:,:) = 0.d0
              end if
           end if
        end do
     end do
  end do

  do k=1, Param%SCF%nK
     if( Param%SCF%i_vK(k) >= 0 ) then
        cycle
     end if
     do a=MPI%isatom, MPI%ieatom
        i=Base%vipao(a)

        do b=1, Param%Data%natom
           j=Base%vipao(b)

           do i1=MPI%ispao(a), MPI%iepao(a)
              do j1=1, Base%vnpao(b)

                 do l=0, Param%Cell%nL-1

                    bloch = Param%SCF%vbloch(k,l)/Param%SCF%nK * dfloat(-Param%SCF%i_vK(k))

                    if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                       cycle
                    end if

                    if( Param%Option%spin_orbit ) then
                       Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDMLS(j1,i1,:) = &
                            Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDMLS(j1,i1,:) &
                            + bloch*Hamiltonian%vBandMatrix(k)%H(j+j1-1,i+i1-1,:)

                       if( Param%Option%optimize ) then
                          Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDMLS(j1,i1) = &
                               Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDMLS(j1,i1) &
                               + real(bloch*Hamiltonian%vBandMatrix(k)%S(j+j1-1,i+i1-1))
                       end if
                    else
                       Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDM(j1,i1,:) = &
                            Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDM(j1,i1,:) &
                            + real(bloch*Hamiltonian%vBandMatrix(k)%H(j+j1-1,i+i1-1,:))
                       if( Param%Option%optimize ) then
                          Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDM(j1,i1) = &
                               Hamiltonian%vAtomMatrix(b,a,l)%Ptr%EDM(j1,i1) &
                               + real(bloch*Hamiltonian%vBandMatrix(k)%S(j+j1-1,i+i1-1))
                       end if
                    endif

                 end do

              end do
           end do
        end do
     end do
  end do

  return
end subroutine DensityMatrix__calc

subroutine DensityMatrix__update( dEden, iter )
  use ac_misc_module
  implicit none
  real(8), intent(inout) :: dEden
  integer, intent(in)    :: iter

  select case( Param%SCF%mix_type )
  case('Simple')
     call DensityMatrix__updateSimple  ( dEden, iter )
  case('Pulay')
     call DensityMatrix__updatePulay   ( dEden, iter )
  case('Anderson')
     call DensityMatrix__updateAnderson( dEden, iter )
  end select

  return
end subroutine DensityMatrix__update

subroutine DensityMatrix__updateSimple( dEden, iter )
  use ac_misc_module
  use ac_mpi_module
  implicit none

  real(8), intent(inout) :: dEden
  integer, intent(in) :: iter

  integer :: a, b, l
  type(AtomMatrix_type), pointer :: amat

  integer :: i1, j1, ispin

  if( Param%SCF%mix_history /= 1 ) then
     open(unit=16,file=Param%Option%file_ac_tempout,position='append')
     write(16,*) '      ++++++ Warning!: mixing history should be 1 for Simple mixing'
     close(16)
     Param%SCF%mix_history = 1
  end if

  if( iter<0 ) then
     dEden = 0.d0
     return
  end if


  if( iter==0 ) then
     dEden = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 amat%vpast(1)%CDMLS(:,:,:) = amat%CDMLS(:,:,:)
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin)) ) then
                             dEden = cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              else
                 amat%vpast(1)%CDM(:,:,:) = amat%CDM(:,:,:)
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < abs(amat%vpast(1)%CDM(j1,i1,ispin)) ) then
                             dEden = abs(amat%vpast(1)%CDM(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              end if
           end do
        end do
     end do

     call MPI__Allreduce_Error_Max( dEden )

     return
  end if

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              amat%vpast(1)%dCDMLS(:,:,:) = amat%CDMLS(:,:,:) - amat%vpast(1)%CDMLS(:,:,:)
           else
              amat%vpast(1)%dCDM(:,:,:) = amat%CDM(:,:,:) - amat%vpast(1)%CDM(:,:,:)
           end if
        end do
     end do
  end do

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              amat%CDMLS(:,:,:) = amat%CDMLS(:,:,:) + amat%vpast(1)%dCDMLS(:,:,:) * (Param%SCF%mix_weight_s-1.0)
              amat%vpast(1)%CDMLS(:,:,:) = amat%CDMLS(:,:,:)
           else
              amat%CDM(:,:,:) = amat%CDM(:,:,:) + amat%vpast(1)%dCDM(:,:,:) * (Param%SCF%mix_weight_s-1.0)
              amat%vpast(1)%CDM(:,:,:) = amat%CDM(:,:,:)
           end if
        end do
     end do
  end do

  dEden = 0.d0

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin)) ) then
                          dEden = cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           else
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < abs(amat%vpast(1)%dCDM(j1,i1,ispin)) ) then
                          dEden = abs(amat%vpast(1)%dCDM(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           end if
        end do
     end do
  end do

  call MPI__Allreduce_Error_Max( dEden )

  return
end subroutine DensityMatrix__updateSimple

subroutine DensityMatrix__updatePulay( dEden, iter )
  use ac_misc_module
  use ac_mpi_module
  implicit none

  real(8), intent(inout) :: dEden
  integer, intent(in) :: iter

  integer :: a, b, l
  type(AtomMatrix_type), pointer :: amat

  real(8), allocatable :: matrix(:,:)
  real(8), allocatable :: alpha(:)
  integer, allocatable :: ipiv(:)
  real(8), allocatable :: work(:)
  integer :: n, m
  integer :: info
  real(8) :: sumalpha

  integer :: i1, j1, ispin

  if( Param%SCF%mix_start < Param%SCF%mix_history ) then
     open(unit=16,file=Param%Option%file_ac_tempout,position='append')
     write(16,*) '      ++++++ Warning!: too small mixing start for Pulay mixing'
     close(16)
     Param%SCF%mix_start = Param%SCF%mix_history
  end if

  if( iter<0 ) then
     dEden = 0.d0
     return
  end if

  if( iter==0 ) then
     dEden = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 amat%vpast(1)%CDMLS = amat%CDMLS
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin)) ) then
                             dEden = cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              else
                 amat%vpast(1)%CDM = amat%CDM
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < abs(amat%vpast(1)%CDM(j1,i1,ispin)) ) then
                             dEden = abs(amat%vpast(1)%CDM(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              end if
           end do
        end do
     end do

     call MPI__Allreduce_Error_Max( dEden )

     return
  end if

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              amat%vpast(1)%dCDMLS = amat%CDMLS - amat%vpast(1)%CDMLS
           else
              amat%vpast(1)%dCDM = amat%CDM - amat%vpast(1)%CDM
           end if
        end do
     end do
  end do

  if( iter <= Param%SCF%mix_start ) then
     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 amat%CDMLS = amat%CDMLS + amat%vpast(1)%dCDMLS * (Param%SCF%mix_weight_s-1.0)
              else
                 amat%CDM = amat%CDM + amat%vpast(1)%dCDM * (Param%SCF%mix_weight_s-1.0)
              end if
           end do
        end do
     end do

  else
     allocate( matrix(Param%SCF%mix_history,Param%SCF%mix_history) )
     allocate( alpha(Param%SCF%mix_history) )
     allocate( ipiv(Param%SCF%mix_history) )
     allocate( work(4*Param%SCF%mix_history) )

     matrix(:,:) = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr
              do n=1, Param%SCF%mix_history
                 do m=n, Param%SCF%mix_history
                    if( Param%Option%spin_orbit ) then
                       matrix(n,m) = matrix(n,m) + sum( dreal(dconjg(amat%vpast(n)%dCDMLS(:,:,1)) * amat%vpast(m)%dCDMLS(:,:,1) ))
                       matrix(n,m) = matrix(n,m) + sum( dreal(dconjg(amat%vpast(n)%dCDMLS(:,:,4)) * amat%vpast(m)%dCDMLS(:,:,4) ))
                    else
                       matrix(n,m) = matrix(n,m) + sum( amat%vpast(n)%dCDM * amat%vpast(m)%dCDM )
                    end if
                 end do
              end do
           end do
        end do
     end do

     call MPI__Allreduce_HistoryPulay( matrix )

     do n=1, Param%SCF%mix_history
        alpha(n) = 1.d0
     end do

     call dsysv( 'U', Param%SCF%mix_history, 1, matrix, &
          Param%SCF%mix_history, ipiv, alpha, &
          Param%SCF%mix_history, work, 4*Param%SCF%mix_history, info, 1 )

     sumalpha=0.d0
     do n=1, Param%SCF%mix_history
        sumalpha = sumalpha + alpha(n)
     end do
     sumalpha = 1.d0/sumalpha
     do n=1, Param%SCF%mix_history
        alpha(n) = alpha(n)*sumalpha
     end do

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle 
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 amat%CDMLS = 0.d0
                 do n=1, Param%SCF%mix_history
                    amat%CDMLS = amat%CDMLS + amat%vpast(n)%CDMLS * alpha(n)
                    amat%CDMLS = amat%CDMLS + amat%vpast(n)%dCDMLS * (alpha(n)*Param%SCF%mix_weight)
                 end do
              else
                 amat%CDM = 0.d0
                 do n=1, Param%SCF%mix_history
                    amat%CDM = amat%CDM + amat%vpast(n)%CDM * alpha(n)
                    amat%CDM = amat%CDM + amat%vpast(n)%dCDM * (alpha(n)*Param%SCF%mix_weight)
                 end do
              end if
           end do
        end do
     end do

     deallocate( matrix )
     deallocate( alpha )
     deallocate( ipiv )
     deallocate( work )

  end if

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           do n=Param%SCF%mix_history, 2, -1
              if( Param%Option%spin_orbit ) then
                 amat%vpast(n)%CDMLS  = amat%vpast(n-1)%CDMLS
                 amat%vpast(n)%dCDMLS = amat%vpast(n-1)%dCDMLS
              else
                 amat%vpast(n)%CDM  = amat%vpast(n-1)%CDM
                 amat%vpast(n)%dCDM = amat%vpast(n-1)%dCDM
              end if
           end do

           if( Param%Option%spin_orbit ) then
              amat%vpast(1)%CDMLS = amat%CDMLS
           else
              amat%vpast(1)%CDM = amat%CDM
           end if
        end do
     end do
  end do

  dEden = 0.d0

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin)) ) then
                          dEden = cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           else
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < abs(amat%vpast(1)%dCDM(j1,i1,ispin)) ) then
                          dEden = abs(amat%vpast(1)%dCDM(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           end if
        end do
     end do
  end do

  call MPI__Allreduce_Error_Max( dEden )

  return
end subroutine DensityMatrix__updatePulay

subroutine DensityMatrix__updateAnderson( dEden, iter )
  use ac_misc_module
  use ac_mpi_module
  implicit none

  real(8), intent(inout) :: dEden
  integer, intent(in) :: iter

  integer :: a, b, l
  type(AtomMatrix_type), pointer :: amat

  real(kind=8), parameter :: detol = 1d-9
  real(kind=8) :: theta1, theta2, det
  real(kind=8) :: matrix(2:3,3)

  integer :: i1, j1, ispin

  if( Param%SCF%mix_history /= 3 ) then
     open(unit=16,file=Param%Option%file_ac_tempout,position='append')
     write(16,*) '      ++++++ Warning!: mixing history should be 3 for Anderson mixing'
     close(16)
     Param%SCF%mix_history = 3
  end if

  if( iter<0 ) then
     dEden = 0.d0
     return
  end if

  if( iter==0 ) then
     dEden = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 amat%vpast(1)%CDMLS = amat%CDMLS
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin)) ) then
                             dEden = cdabs(amat%vpast(1)%CDMLS(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              else
                 amat%vpast(1)%CDM = amat%CDM
                 do ispin=1, Param%Option%nspin
                    do i1=MPI%ispao(a), MPI%iepao(a)
                       do j1=1, Base%vnpao(b)
                          if( dEden < abs(amat%vpast(1)%CDM(j1,i1,ispin)) ) then
                             dEden = abs(amat%vpast(1)%CDM(j1,i1,ispin))
                          end if
                       end do
                    end do
                 end do
              end if
           end do
        end do
     end do

     call MPI__Allreduce_Error_Max( dEden )

     return
  end if

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              amat%vpast(1)%dCDMLS = amat%CDMLS - amat%vpast(1)%CDMLS
              amat%vpast(2)%CDMLS  = amat%vpast(2)%CDMLS  - amat%vpast(1)%CDMLS
              amat%vpast(2)%dCDMLS = amat%vpast(2)%dCDMLS - amat%vpast(1)%dCDMLS
           else
              amat%vpast(1)%dCDM = amat%CDM - amat%vpast(1)%CDM
              amat%vpast(2)%CDM  = amat%vpast(2)%CDM  - amat%vpast(1)%CDM
              amat%vpast(2)%dCDM = amat%vpast(2)%dCDM - amat%vpast(1)%dCDM
           end if
        end do
     end do
  end do

  if( iter==1 .or. Param%SCF%mix_history == 1 ) then
     theta1 = 0.0d0
     theta2 = 0.0d0
  else if( iter==2 .or. Param%SCF%mix_history == 2 ) then
     matrix(:,:) = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 matrix(2,2) = matrix(2,2) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,1)) * amat%vpast(2)%dCDMLS(:,:,1)) )
                 matrix(2,2) = matrix(2,2) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,4)) * amat%vpast(2)%dCDMLS(:,:,4)) )
                 matrix(2,1) = matrix(2,1) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,1)) * amat%vpast(1)%dCDMLS(:,:,1)) )
                 matrix(2,1) = matrix(2,1) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,4)) * amat%vpast(1)%dCDMLS(:,:,4)) )
              else
                 matrix(2,2) = matrix(2,2) + sum( amat%vpast(2)%dCDM * amat%vpast(2)%dCDM )
                 matrix(2,1) = matrix(2,1) + sum( amat%vpast(2)%dCDM * amat%vpast(1)%dCDM )
              end if
           end do
        end do
     end do

     call MPI__Allreduce_HistoryAnderson( matrix )

     theta1 = -matrix(2,1)/matrix(2,2)
     theta2 = 0.0d0

  else
     matrix(:,:) = 0.d0

     do l=0, Param%Cell%nL-1
        do a=MPI%isatom, MPI%ieatom
           do b=1, Param%Data%natom
              if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
                 cycle
              end if

              amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

              if( Param%Option%spin_orbit ) then
                 matrix(2,2) = matrix(2,2) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,1)) * amat%vpast(2)%dCDMLS(:,:,1)) )
                 matrix(2,2) = matrix(2,2) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,4)) * amat%vpast(2)%dCDMLS(:,:,4)) )

                 matrix(2,3) = matrix(2,3) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,1)) * amat%vpast(3)%dCDMLS(:,:,1)) )
                 matrix(2,3) = matrix(2,3) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,4)) * amat%vpast(3)%dCDMLS(:,:,4)) )

                 matrix(3,3) = matrix(3,3) + sum( dreal(dconjg(amat%vpast(3)%dCDMLS(:,:,1)) * amat%vpast(3)%dCDMLS(:,:,1)) )
                 matrix(3,3) = matrix(3,3) + sum( dreal(dconjg(amat%vpast(3)%dCDMLS(:,:,4)) * amat%vpast(3)%dCDMLS(:,:,4)) )

                 matrix(2,1) = matrix(2,1) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,1)) * amat%vpast(1)%dCDMLS(:,:,1)) )
                 matrix(2,1) = matrix(2,1) + sum( dreal(dconjg(amat%vpast(2)%dCDMLS(:,:,4)) * amat%vpast(1)%dCDMLS(:,:,4)) )

                 matrix(3,1) = matrix(3,1) + sum( dreal(dconjg(amat%vpast(3)%dCDMLS(:,:,1)) * amat%vpast(1)%dCDMLS(:,:,1)) )
                 matrix(3,1) = matrix(3,1) + sum( dreal(dconjg(amat%vpast(3)%dCDMLS(:,:,4)) * amat%vpast(1)%dCDMLS(:,:,4)) )
              else
                 matrix(2,2) = matrix(2,2) + sum( amat%vpast(2)%dCDM * amat%vpast(2)%dCDM )
                 matrix(2,3) = matrix(2,3) + sum( amat%vpast(2)%dCDM * amat%vpast(3)%dCDM )
                 matrix(3,3) = matrix(3,3) + sum( amat%vpast(3)%dCDM * amat%vpast(3)%dCDM )
                 matrix(2,1) = matrix(2,1) + sum( amat%vpast(2)%dCDM * amat%vpast(1)%dCDM )
                 matrix(3,1) = matrix(3,1) + sum( amat%vpast(3)%dCDM * amat%vpast(1)%dCDM )
              end if
           end do
        end do
     end do

     call MPI__Allreduce_HistoryAnderson( matrix )

     det = matrix(2,2)*matrix(3,3) - matrix(2,3)*matrix(2,3)

     if( dabs(det/(matrix(2,2)*matrix(3,3))) < detol ) then
        theta1 = -matrix(2,1)/matrix(2,2)
        theta2 = 0.0d0
     else
        theta1 = (-matrix(3,3)*matrix(2,1)+matrix(2,3)*matrix(3,1))/det
        theta2 = (+matrix(2,3)*matrix(2,1)-matrix(2,2)*matrix(3,1))/det
     end if
  end if



  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              amat%CDMLS = amat%vpast(1)%CDMLS + theta1*amat%vpast(2)%CDMLS  + theta2*amat%vpast(3)%CDMLS &
                   + Param%SCF%mix_weight*( amat%vpast(1)%dCDMLS + theta1*amat%vpast(2)%dCDMLS + theta2*amat%vpast(3)%dCDMLS )

              amat%vpast(3)%CDMLS  = amat%vpast(2)%CDMLS
              amat%vpast(2)%CDMLS  = amat%vpast(1)%CDMLS
              amat%vpast(1)%CDMLS  = amat%CDMLS
              amat%vpast(3)%dCDMLS = amat%vpast(2)%dCDMLS
              amat%vpast(2)%dCDMLS = amat%vpast(1)%dCDMLS
           else
              amat%CDM = amat%vpast(1)%CDM + theta1*amat%vpast(2)%CDM  + theta2*amat%vpast(3)%CDM &
                   + Param%SCF%mix_weight*( amat%vpast(1)%dCDM + theta1*amat%vpast(2)%dCDM + theta2*amat%vpast(3)%dCDM )

              amat%vpast(3)%CDM  = amat%vpast(2)%CDM
              amat%vpast(2)%CDM  = amat%vpast(1)%CDM
              amat%vpast(1)%CDM  = amat%CDM
              amat%vpast(3)%dCDM = amat%vpast(2)%dCDM
              amat%vpast(2)%dCDM = amat%vpast(1)%dCDM
           end if
        end do
     end do
  end do

  dEden = 0.d0

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        do b=1, Param%Data%natom
           if( .not. associated(Hamiltonian%vAtomMatrix(b,a,l)%Ptr) ) then
              cycle
           end if

           amat => Hamiltonian%vAtomMatrix(b,a,l)%Ptr

           if( Param%Option%spin_orbit ) then
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin)) ) then
                          dEden = cdabs(amat%vpast(1)%dCDMLS(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           else
              do ispin=1, Param%Option%nspin
                 do i1=MPI%ispao(a), MPI%iepao(a)
                    do j1=1, Base%vnpao(b)
                       if( dEden < abs(amat%vpast(1)%dCDM(j1,i1,ispin)) ) then
                          dEden = abs(amat%vpast(1)%dCDM(j1,i1,ispin))
                       end if
                    end do
                 end do
              end do
           end if
        end do
     end do
  end do

  call MPI__Allreduce_Error_Max( dEden )

  return
end subroutine DensityMatrix__updateAnderson
