! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !
! @@                                                                @@ !
! @@       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 PPcharge__set( ppchg, Ro, RF )
  use ac_misc_module

  implicit none
  type(PPcharge_type), intent(out) :: ppchg
  real(8), intent(in)  :: Ro(3)
  type(RadialFunc_type), intent(in), target :: RF

  ppchg%Ro = Ro
  ppchg%Rc = RF%Rc
  ppchg%RF => RF

  return
end subroutine PPcharge__set

subroutine PPcharge__W( W, ppchg, Rg )
  use ac_misc_module

  implicit none
  type(PPcharge_type), intent(in) :: ppchg
  real(8), intent(in) :: Rg(3)

  real(8), intent(out)  :: W
  real(8) :: R(3)
  real(8)  :: dR

  R  = Rg-ppchg%Ro
  dR = sqrt(dot_product(R,R))

  if( dR > ppchg%Rc ) then
     W = 0.d0
     return
  end if

  W  = Spline__evaluate( ppchg%RF%fR, dR )

  return
end subroutine PPcharge__W

subroutine PPcharge__gW( gW, ppchg, Rg )
  use ac_misc_module

  implicit none
  type(PPcharge_type), intent(in) :: ppchg
  real(8), intent(in) :: Rg(3)

  real(8), intent(out)  :: gW(3)
  real(8) :: R(3)
  real(8)  :: dR

  R  = Rg-ppchg%Ro
  dR = sqrt(dot_product(R,R))

    if( dR < 1.d-14 ) then
     gW = 0.0d0
  else
     gW = Spline__derivative( ppchg%RF%fR, dR ) / dR * R
  end if

  return
end subroutine PPcharge__gW

subroutine Density__addVal( rrhoval, polarization )
  use ac_misc_module

  implicit none
  type(PPcharge_type), intent(in) :: rrhoval
  real(8)  :: polarization

  integer        :: spin
  integer        :: ia, ib, ic
  integer        :: ia0, ib0, ic0
  real(8) :: R(3)
  real(8)        :: rhoat, zeta(2)
  integer        :: range(6)

  call Param__Cell__getRange( range, rrhoval%Ro, rrhoval%Rc )
  
  if( .not. Param%Option%spin_polar ) then
     zeta(1) = 1.0d0
  else
     zeta(1) = 0.5d0*(1.0d0+polarization)
     zeta(2) = 0.5d0*(1.0d0-polarization)
  end if

  do ic = range(5), range(6)
     ic0 = modp(ic,Param%Cell%Nc)
     do ib = range(3), range(4)
        ib0 = modp(ib,Param%Cell%Nb)
        do ia = range(1), range(2)
           ia0 = modp(ia,Param%Cell%Na)

           call Param__Cell__R(R,ia,ib,ic)
           call PPcharge__W(rhoat,rrhoval,R)

           if( Param%Option%na ) then
              Density%rhoval(ia0,ib0,ic0) = &
                   Density%rhoval(ia0,ib0,ic0) + rhoat
           end if

           if( Param%Option%spin_orbit ) then
              Density%rhoLS(1,ia0,ib0,ic0) = &
                   Density%rhoLS(1,ia0,ib0,ic0) + rhoat*zeta(1)
              Density%rhoLS(4,ia0,ib0,ic0) = &
                   Density%rhoLS(4,ia0,ib0,ic0) + rhoat*zeta(2)
           else
              do spin=1, Param%Option%nspin
                 Density%rho(spin,ia0,ib0,ic0) = &
                      Density%rho(spin,ia0,ib0,ic0) + rhoat*zeta(spin)
              end do
           end if

        end do
     end do
  end do

  return
end subroutine Density__addVal

subroutine Density__addPCC( rrhopcc )
  use ac_misc_module

  implicit none
  type(PPcharge_type), intent(in) :: rrhopcc

  integer        :: ia, ib, ic
  integer        :: ia0, ib0, ic0
  real(8) :: R(3)
  integer        :: range(6)

  real(8)        :: rhoat

  call Param__Cell__getRange( range, rrhopcc%Ro, rrhopcc%Rc )

  do ic = range(5), range(6)
     ic0 = modp(ic,Param%Cell%Nc)
     do ib = range(3), range(4)
        ib0 = modp(ib,Param%Cell%Nb)
        do ia = range(1), range(2)
           ia0 = modp(ia,Param%Cell%Na)

           call Param__Cell__R(R,ia,ib,ic)

           call PPcharge__W(rhoat,rrhopcc,R)

           Density%rhopcc(ia0,ib0,ic0) = Density%rhopcc(ia0,ib0,ic0) + rhoat
        end do
     end do
  end do

  return
end subroutine Density__addPCC

subroutine Density__setup
  use ac_misc_module

  implicit none
  integer :: a
  type(Element_type), pointer :: elem
  type(PPcharge_type) :: rrhoval
  type(PPcharge_type) :: rrhopcc

  call Density__deallocate

  if( Param%Option%spin_orbit ) then
     allocate(Density%rhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc))
     Density%rhoLS = 0.d0
  else
     allocate(Density%rho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc))
     Density%rho   = 0.d0
  end if

  if( Param%Option%na ) then
     allocate(Density%rhoval(Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc))
     Density%rhoval = 0.d0
  end if

  Param%Option%pcc = .false.

  do a=1, Param%Data%natom
     elem => Param__Data__getElement( Param%Data%vatom(a)%name )

     call PPcharge__set( rrhoval, Param%Data%vatom(a)%Ro, elem%rhoval )
     call Density__addVal( rrhoval, Param%Data%vatom(a)%polarization );

     if( .not. associated(Density%rhopcc) ) then
        allocate(Density%rhopcc(Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc))
        Density%rhopcc = 0.d0
     end if
     if( elem%pcc ) then
        Param%Option%pcc = .true.
!!        if( .not. associated(Density%rhopcc) ) then
!!           allocate(Density%rhopcc(Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc))
!!           Density%rhopcc = 0.d0
!!        end if

        call PPcharge__set( rrhopcc, Param%Data%vatom(a)%Ro, elem%rhopcc )
        call Density__addPCC( rrhopcc )
     end if
  end do

  return
end subroutine Density__setup

subroutine Density__calc
  use ac_misc_module
  use ac_mpi_module
  implicit none
  integer :: a, i, i1
  integer :: l, b, j, j1

  real(8) :: lL(3)
  integer        :: na, nb, nc
  integer        :: range(6)

  integer :: spin
  integer :: ia, ib, ic
  integer :: ia0, ib0, ic0
  integer :: ja, jb, jc

  real(8), pointer :: vpaoiat(:)
  real(8), pointer :: vpaojat(:)
  real(8) :: wi, wj
  real(8) :: sum_t
  real(8) :: rhoat
  complex(8) :: sum_tLS
  complex(8) :: rhoatLS

  if( Param%Option%spin_orbit ) then
     Density%rhoLS = 0.d0
  else
     Density%rho   = 0.d0
  end if

  allocate( vpaoiat(Base%npao) )
  allocate( vpaojat(Base%npao) )

  do l=0, Param%Cell%nL-1
     do a=MPI%isatom, MPI%ieatom
        i=Base%vipao(a)

        lL = Param%Cell%vL(:,l)
        na = Param%Cell%vLna(l)
        nb = Param%Cell%vLnb(l)
        nc = Param%Cell%vLnc(l)

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

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

           if( .not. Param__Cell__mergeRange2( range, &
                Base%vpao(i)%Ro, Base%vpao(i)%Rc, &
                Base%vpao(j)%Ro, l, &
                Base%vpao(j)%Rc ) ) then
              cycle
           end if

           do ic = range(5), range(6)
              jc = ic-nc
              ic0 = modp(ic,Param%Cell%Nc)

              do ib = range(3), range(4)
                 jb = ib-nb
                 ib0 = modp(ib,Param%Cell%Nb)

                 do ia = range(1), range(2)
                    ja = ia-na
                    ia0 = modp(ia,Param%Cell%Na)

                    if( Base%vpao(i)%wave(ia,ib,ic) == 0.d0 ) cycle

                    if( Base%vpao(j)%wave(ja,jb,jc) == 0.d0 ) cycle

                    do i1=MPI%ispao(a), MPI%iepao(a)
                       vpaoiat(i+i1-1) = Base%vpao(i+i1-1)%wave(ia,ib,ic)
                    end do

                    do j1=1, Base%vnpao(b)
                       vpaojat(j+j1-1) = Base%vpao(j+j1-1)%wave(ja,jb,jc)
                    end do

                    do spin=1, Param%Option%nspin
                       if( Param%Option%spin_orbit ) then
                          rhoatLS = 0.d0
                          do i1=MPI%ispao(a), MPI%iepao(a)
                             wi = vpaoiat(i+i1-1)
                             if( wi == 0.d0 ) cycle

                             sum_tLS=0.d0
                             do j1=1, Base%vnpao(b)
                                wj = vpaojat(j+j1-1)
                                if( wj == 0.d0 ) cycle

                                sum_tLS = sum_tLS + &
                                     Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDMLS(j1,i1,spin) * wj
                             end do
                             rhoatLS = rhoatLS + wi*sum_tLS
                          end do

                          if( l==0 ) then
                             rhoatLS = rhoatLS*0.5d0
                          end if
                          Density%rhoLS(spin,ia0,ib0,ic0) = &
                               Density%rhoLS(spin,ia0,ib0,ic0) + rhoatLS

                       else
                          rhoat = 0.d0
                          do i1=MPI%ispao(a), MPI%iepao(a)
                             wi = vpaoiat(i+i1-1)
                             if( wi == 0.d0 ) cycle

                             sum_t=0.d0
                             do j1=1, Base%vnpao(b)
                                wj = vpaojat(j+j1-1)
                                if( wj == 0.d0 ) cycle

                                sum_t = sum_t + &
                                     Hamiltonian%vAtomMatrix(b,a,l)%Ptr%CDM(j1,i1,spin) * wj
                             end do
                             rhoat = rhoat + wi*sum_t
                          end do

                          if( l>0 ) then
                             rhoat = rhoat*2.d0
                          end if
                          Density%rho(spin,ia0,ib0,ic0) = &
                               Density%rho(spin,ia0,ib0,ic0) + rhoat
                       end if
                    end do
                 end do
              end do
           end do
        end do
     end do
  end do

  if(associated(vpaoiat)) deallocate( vpaoiat )
  if(associated(vpaojat)) deallocate( vpaojat )

  if( Param%Option%spin_orbit ) then
     Density%rhoLS(1,:,:,:) = &
          Density%rhoLS(1,:,:,:) + dconjg(Density%rhoLS(1,:,:,:))
     Density%rhoLS(4,:,:,:) = &
          Density%rhoLS(4,:,:,:) + dconjg(Density%rhoLS(4,:,:,:))
     Density%rhoLS(2,:,:,:) = &
          Density%rhoLS(2,:,:,:) + dconjg(Density%rhoLS(3,:,:,:))
     Density%rhoLS(3,:,:,:) = &
          dconjg(Density%rhoLS(2,:,:,:))

     call MPI__Allreduce_DensityLS( Density%rhoLS )
  else
     call MPI__Allreduce_Density( Density%rho )
  end if

  return
end subroutine Density__calc

subroutine Density__update( dEden, iter )
  use ac_misc_module

  implicit none
  integer, intent(in) :: iter
  real(8), intent(out) :: dEden

  select case( Param%SCF%mix_type )
  case('Simple')
     call Density__updateSimple( dEden, iter )
  case('Pulay')
     call Density__updatePulay( dEden, iter )
  case('Anderson')
     call Density__updateAnderson( dEden, iter )
  end select

  return
end subroutine Density__update

subroutine Density__updateSimple( dEden, iter )
  use ac_misc_module

  implicit none
  integer, intent(in) :: iter
  real(8), intent(out) :: dEden

  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
     allocate( Density%vpast(Param%SCF%mix_history) )

     if( Param%Option%spin_orbit ) then
        allocate( Density%vpast(1)% rhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        allocate( Density%vpast(1)%drhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )

        Density%vpast(1)%rhoLS = Density%rhoLS
        dEden = sum(cdabs(Density%vpast(1)%rhoLS)) * Param%Cell%dV/Param%Data%Ne
     else
        allocate( Density%vpast(1)% rho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        allocate( Density%vpast(1)%drho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )

        Density%vpast(1)%rho = Density%rho
        dEden = sum(abs(Density%vpast(1)%rho)) * Param%Cell%dV/Param%Data%Ne
     end if
     return
  end if

  if( Param%Option%spin_orbit ) then
     Density%vpast(1)%drhoLS = Density%rhoLS - Density%vpast(1)%rhoLS
     Density%rhoLS = Density%rhoLS + Density%vpast(1)%drhoLS * (Param%SCF%mix_weight-1.0)
     Density%vpast(1)%rhoLS = Density%rhoLS
     dEden = sum(cdabs(Density%vpast(1)%drhoLS)) * Param%Cell%dV/Param%Data%Ne
  else
     Density%vpast(1)%drho = Density%rho - Density%vpast(1)%rho
     Density%rho = Density%rho + Density%vpast(1)%drho * (Param%SCF%mix_weight-1.0)
     Density%vpast(1)%rho = Density%rho
     dEden = sum(abs(Density%vpast(1)%drho)) * Param%Cell%dV/Param%Data%Ne
  end if

  return
end subroutine Density__updateSimple

subroutine Density__updatePulay( dEden, iter )
  use ac_misc_module

  implicit none
  integer, intent(in) :: iter
  real(8), intent(out) :: dEden

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

  real(8) :: v3dp_t,v3dp_t1,v3dp_t2

  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
     allocate( Density%vpast(Param%SCF%mix_history) )

     if( Param%Option%spin_orbit ) then
        do n=1, Param%SCF%mix_history
           allocate( Density%vpast(n)% rhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
           allocate( Density%vpast(n)%drhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        end do

        Density%vpast(1)%rhoLS = Density%rhoLS
        dEden = sum(cdabs(Density%vpast(1)%rhoLS)) * Param%Cell%dV/Param%Data%Ne
     else
        do n=1, Param%SCF%mix_history
           allocate( Density%vpast(n)% rho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
           allocate( Density%vpast(n)%drho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        end do

        Density%vpast(1)%rho = Density%rho
        dEden = sum(abs(Density%vpast(1)%rho)) * Param%Cell%dV/Param%Data%Ne
     end if
     return
  end if

  if( Param%Option%spin_orbit ) then
     Density%vpast(1)%drhoLS = Density%rhoLS - Density%vpast(1)%rhoLS
  else
     Density%vpast(1)%drho = Density%rho - Density%vpast(1)%rho
  end if

  if( iter <= Param%SCF%mix_start ) then
     if( Param%Option%spin_orbit ) then
        Density%rhoLS = Density%rhoLS + Density%vpast(1)%drhoLS * (Param%SCF%mix_weight-1.0)
     else
        Density%rho = Density%rho + Density%vpast(1)%drho * (Param%SCF%mix_weight-1.0)
     end if

  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) )

     do n=1, Param%SCF%mix_history
        do m=n, Param%SCF%mix_history
           if( Param%Option%spin_orbit ) then
              matrix(n,m) = sum( Density%vpast(n)%drhoLS * Density%vpast(m)%drhoLS )
           else
              matrix(n,m) = sum( Density%vpast(n)%drho * Density%vpast(m)%drho )
           end if
        end do
     end do

     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

     if( Param%Option%spin_orbit ) then
        Density%rhoLS = 0.d0
        do n=1, Param%SCF%mix_history
           Density%rhoLS = Density%rhoLS + Density%vpast(n)%rhoLS * alpha(n)
           Density%rhoLS = Density%rhoLS + Density%vpast(n)%drhoLS * (alpha(n)*Param%SCF%mix_weight)
        end do
     else
        Density%rho = 0.d0
        do n=1, Param%SCF%mix_history
           Density%rho = Density%rho + Density%vpast(n)%rho * alpha(n)
           Density%rho = Density%rho + Density%vpast(n)%drho * (alpha(n)*Param%SCF%mix_weight)
        end do
     end if

     deallocate( matrix )
     deallocate( alpha )
     deallocate( ipiv )
     deallocate( work )
  end if

  if( Param%Option%spin_orbit ) then
     do n=Param%SCF%mix_history, 2, -1
        Density%vpast(n)%rhoLS  = Density%vpast(n-1)%rhoLS
        Density%vpast(n)%drhoLS = Density%vpast(n-1)%drhoLS
     end do
     Density%vpast(1)%rhoLS = Density%rhoLS

     dEden = sum(cdabs(Density%vpast(1)%drhoLS)) * Param%Cell%dV/Param%Data%Ne
  else
     do n=Param%SCF%mix_history, 2, -1
        Density%vpast(n)%rho  = Density%vpast(n-1)%rho
        Density%vpast(n)%drho = Density%vpast(n-1)%drho
     end do
     Density%vpast(1)%rho = Density%rho

     dEden = sum(abs(Density%vpast(1)%drho)) * Param%Cell%dV/Param%Data%Ne
  end if
  return
end subroutine Density__updatePulay

subroutine Density__updateAnderson( dEden, iter )
  use ac_misc_module

  implicit none
  integer, intent(in) :: iter
  real(8), intent(out) :: dEden

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

  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
     allocate( Density%vpast(Param%SCF%mix_history) )

     if( Param%Option%spin_orbit ) then
        do n=1, Param%SCF%mix_history
           allocate( Density%vpast(n)% rhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
           allocate( Density%vpast(n)%drhoLS(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        end do

        Density%vpast(1)%rhoLS = Density%rhoLS
        dEden = sum(cdabs(Density%vpast(1)%rhoLS)) * Param%Cell%dV/Param%Data%Ne
     else
        do n=1, Param%SCF%mix_history
           allocate( Density%vpast(n)% rho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
           allocate( Density%vpast(n)%drho(Param%Option%nspin,Param%Cell%Na,Param%Cell%Nb,Param%Cell%Nc) )
        end do

        Density%vpast(1)%rho = Density%rho
        dEden = sum(abs(Density%vpast(1)%rho))* Param%Cell%dV/Param%Data%Ne
     end if

     return
  end if

  if( Param%Option%spin_orbit ) then
     Density%vpast(1)%drhoLS = Density%rhoLS - Density%vpast(1)%rhoLS
     Density%vpast(2)%rhoLS  = Density%vpast(2)%rhoLS  - Density%vpast(1)%rhoLS
     Density%vpast(2)%drhoLS = Density%vpast(2)%drhoLS - Density%vpast(1)%drhoLS
  else
     Density%vpast(1)%drho = Density%rho - Density%vpast(0)%rho
     Density%vpast(2)%rho  = Density%vpast(2)%rho  - Density%vpast(1)%rho
     Density%vpast(2)%drho = Density%vpast(2)%drho - Density%vpast(1)%drho
  end if

  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
     if( Param%Option%spin_orbit ) then
        matrix(:,:) = 0.d0
        matrix(2,2) = matrix(2,2) + sum( Density%vpast(2)%drhoLS * Density%vpast(2)%drhoLS )
        matrix(2,1) = matrix(2,1) + sum( Density%vpast(2)%drhoLS * Density%vpast(1)%drhoLS )
        theta1 = -matrix(2,1)/matrix(2,2)
        theta2 = 0.0d0
     else
        matrix(:,:) = 0.d0
        matrix(2,2) = matrix(2,2) + sum( Density%vpast(2)%drho * Density%vpast(2)%drho )
        matrix(2,1) = matrix(2,1) + sum( Density%vpast(2)%drho * Density%vpast(1)%drho )
        theta1 = -matrix(2,1)/matrix(2,2)
        theta2 = 0.0d0
     end if
  else
     if( Param%Option%spin_orbit ) then
        matrix(:,:) = 0.d0
        matrix(2,2) = matrix(2,2) + sum( Density%vpast(2)%drhoLS * Density%vpast(2)%drhoLS )
        matrix(2,3) = matrix(2,3) + sum( Density%vpast(2)%drhoLS * Density%vpast(3)%drhoLS )
        matrix(3,3) = matrix(3,3) + sum( Density%vpast(3)%drhoLS * Density%vpast(3)%drhoLS )
        matrix(2,1) = matrix(2,1) + sum( Density%vpast(2)%drhoLS * Density%vpast(1)%drhoLS )
        matrix(3,1) = matrix(3,1) + sum( Density%vpast(3)%drhoLS * Density%vpast(1)%drhoLS )
     else
        matrix(:,:) = 0.d0
        matrix(2,2) = matrix(2,2) + sum( Density%vpast(2)%drho * Density%vpast(2)%drho )
        matrix(2,3) = matrix(2,3) + sum( Density%vpast(2)%drho * Density%vpast(3)%drho )
        matrix(3,3) = matrix(3,3) + sum( Density%vpast(3)%drho * Density%vpast(3)%drho )
        matrix(2,1) = matrix(2,1) + sum( Density%vpast(2)%drho * Density%vpast(1)%drho )
        matrix(3,1) = matrix(3,1) + sum( Density%vpast(3)%drho * Density%vpast(1)%drho )
     end if

     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
  
  if( Param%Option%spin_orbit ) then
     Density%rhoLS = Density%vpast(1)%rhoLS &
          + theta1*Density%vpast(2)%rhoLS  + theta2*Density%vpast(3)%rhoLS &
          + Param%SCF%mix_weight* &
          ( Density%vpast(1)%drhoLS &
          + theta1*Density%vpast(2)%drhoLS + theta2*Density%vpast(3)%drhoLS )

     Density%vpast(3)%rhoLS  = Density%vpast(2)%rhoLS
     Density%vpast(2)%rhoLS  = Density%vpast(1)%rhoLS
     Density%vpast(1)%rhoLS  = Density%rhoLS
     Density%vpast(3)%drhoLS = Density%vpast(2)%drhoLS
     Density%vpast(2)%drhoLS = Density%vpast(1)%drhoLS

     dEden = sum(cdabs(Density%vpast(1)%drhoLS)) * Param%Cell%dV/Param%Data%Ne
  else
     Density%rho = Density%vpast(1)%rho &
          + theta1*Density%vpast(2)%rho  + theta2*Density%vpast(3)%rho &
          + Param%SCF%mix_weight* &
          ( Density%vpast(1)%drho &
          + theta1*Density%vpast(2)%drho + theta2*Density%vpast(3)%drho )

     Density%vpast(3)%rho  = Density%vpast(2)%rho
     Density%vpast(2)%rho  = Density%vpast(1)%rho
     Density%vpast(1)%rho  = Density%rho
     Density%vpast(3)%drho = Density%vpast(2)%drho
     Density%vpast(2)%drho = Density%vpast(1)%drho

     dEden = sum(abs(Density%vpast(1)%drho)) * Param%Cell%dV/Param%Data%Ne
  end if

  return
end subroutine Density__updateAnderson

subroutine Density__deallocate
  use ac_misc_module

  implicit none
  integer :: n

  if( Param%Option%spin_orbit ) then
     if( associated(Density%rhoLS) ) deallocate(Density%rhoLS)
  else
     if( associated(Density%rho) ) deallocate(Density%rho)
  end if

  if( associated(Density%rhoval) ) deallocate(Density%rhoval)
  if( associated(Density%rhopcc) ) deallocate(Density%rhopcc)
  if( associated(Density%vpast) ) then
     if( Param%Option%spin_orbit ) then
        do n=1, size(Density%vpast)
           if(associated(Density%vpast(n)%rhoLS)) deallocate(Density%vpast(n)%rhoLS)
           if(associated(Density%vpast(n)%drhoLS)) deallocate(Density%vpast(n)%drhoLS)
        end do
     else
        do n=1, size(Density%vpast)
           if(associated(Density%vpast(n)%rho)) deallocate(Density%vpast(n)%rho)
           if(associated(Density%vpast(n)%drho)) deallocate(Density%vpast(n)%drho)
        end do
     end if
     deallocate(Density%vpast)
  end if

  return
end subroutine Density__deallocate
