LCOV - code coverage report
Current view: top level - shared/common/src/33_xc_lowlevel - m_xc_noncoll.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.9 % 413 239
Test Date: 2026-09-21 22:40:37 Functions: 75.0 % 4 3

            Line data    Source code
       1              : !!****f* ABINIT/m_xc_noncoll
       2              : !! NAME
       3              : !! m_xc_noncoll
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides several routines used in non-collinear XC routines
       7              : !!  (rotation of the magnetization in order to align it)
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2001-2026 ABINIT group (EB, MT, FR, SPr)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public License, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! INPUTS
      16              : !!
      17              : !! OUTPUT
      18              : !!
      19              : !! SOURCE
      20              : 
      21              : #if defined HAVE_CONFIG_H
      22              : #include "config.h"
      23              : #endif
      24              : 
      25              : #include "abi_common.h"
      26              : 
      27              : MODULE m_xc_noncoll
      28              : 
      29              :  use defs_basis
      30              :  use m_abicore
      31              :  use m_errors
      32              : 
      33              :  implicit none
      34              : 
      35              :  private
      36              : 
      37              : ! public procedures
      38              :  public :: rotate_mag           ! Rotate a non-collinear density wrt a magnetization
      39              :  public :: rotate_back_mag      ! Rotate back a collinear XC potential wrt a magnetization
      40              :  public :: rotate_back_mag_dfpt ! Rotate back a collinear 1st-order XC potential wrt a magnetization
      41              :  public :: test_rotations       ! test whether methods in rotate_back_mag_dfpt give similar results
      42              : 
      43              : !Tolerance on magnetization norm
      44              :  real(dp),parameter :: m_norm_min=tol8
      45              : 
      46              : !Default rotation method for DFPT
      47              :  integer,parameter :: rotation_method_default=3
      48              : 
      49              : CONTAINS
      50              : 
      51              : !===========================================================
      52              : !!***
      53              : 
      54              : !!****t* m_xc_noncoll/rotate_mag
      55              : !! NAME
      56              : !!  rotate_mag
      57              : !!
      58              : !! FUNCTION
      59              : !!  Project (rotate) a non-collinear density (stored as density+magn.)
      60              : !!  on a magnetization and give a collinear density (stored as [up,dn] or [up+dn,up]).
      61              : !!  Align both z-axis.
      62              : !!
      63              : !!
      64              : !! INPUTS
      65              : !!  rho_in(vectsize,4)=input non-collinear density and magnetization (1st or 0th order)
      66              : !!  mag(vectsize,3)=gs magnetization used for projection (0th order magnetization)
      67              : !!  vectsize=size of vector fields
      68              : !!  [mag_norm_in(vectsize)]= --optional-- norm of mag(:) at each point of the grid
      69              : !!  [rho_out_format]= 1=rho_out is stored as [up,dn]
      70              : !!                    2=rho_out is stored as [up+dn,up]
      71              : !!                    Default=1
      72              : ! OUTPUT
      73              : !!  rho_out(vectsize,2)=output (projected, collinear) (1st order if rho_in is 1st order NC density matrix)
      74              : !!  [mag_norm_out(vectsize)]= --optional-- norm of mag(:) at each point of the grid
      75              : !!
      76              : !!     Explicit formulae:
      77              : !!     rho_out_format=1
      78              : !!       rho_out(1) = half*( rho_in(1) + (mag,rho_in(2:4))/|mag|) // where (*,*) is scalar product
      79              : !!       rho_out(2) = half*( rho_in(1) - (mag,rho_in(2:4))/|mag|)
      80              : !!
      81              : !!     rho_out_format=2
      82              : !!       rho_out(1) = rho_in(1)
      83              : !!       rho_out(2) = half*( rho_in(1) + (mag,rho_in(2:4))/|mag|)
      84              : !!
      85              : !!
      86              : !! SOURCE
      87              : 
      88        34772 : subroutine rotate_mag(rho_in,rho_out,mag,vectsize,cplex,&
      89              : &                     mag_norm_in,mag_norm_out,rho_out_format) ! optional arguments
      90              : 
      91              : !Arguments ------------------------------------
      92              : !scalars
      93              :  integer,intent(in) :: vectsize
      94              :  integer,intent(in) :: cplex
      95              :  integer,intent(in),optional :: rho_out_format
      96              : !arrays
      97              :  real(dp),intent(in) ::  rho_in(cplex*vectsize,4),mag(vectsize,3)
      98              :  real(dp),intent(out) :: rho_out(cplex*vectsize,2)
      99              :  real(dp),intent(in),optional :: mag_norm_in(vectsize)
     100              :  real(dp),intent(out),optional :: mag_norm_out(vectsize)
     101              : 
     102              : !Local variables-------------------------------
     103              : !scalars
     104              :  integer :: ipt
     105              :  logical :: has_mag_norm,out_mag_norm
     106              :  real(dp) :: m_norm,mm,rho_up,rhoin_dot_mag
     107              :  real(dp) :: rhoin_dot_mag_re,rhoin_dot_mag_im
     108              : !arrays
     109              : 
     110              : ! *************************************************************************
     111              : 
     112              : !DBG_ENTER("COLL")
     113              : 
     114        34772 :  has_mag_norm=present(mag_norm_in)
     115        34772 :  out_mag_norm=present(mag_norm_out)
     116              : 
     117        34772 :  if(cplex==1) then
     118     38760325 :    do ipt=1,vectsize
     119     38726066 :      if (has_mag_norm) then
     120            0 :        m_norm=mag_norm_in(ipt)
     121              :      else
     122     38726066 :        m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     123              :      end if
     124              : 
     125              :      rhoin_dot_mag=rho_in(ipt,2)*mag(ipt,1)+rho_in(ipt,3)*mag(ipt,2) &
     126     38726066 : &                 +rho_in(ipt,4)*mag(ipt,3)
     127              : 
     128     38726066 :      if(m_norm>m_norm_min)then
     129     18094210 :        mm=rhoin_dot_mag/m_norm
     130     18094210 :        rho_out(ipt,1)=half*(rho_in(ipt,1)+mm)
     131     18094210 :        rho_out(ipt,2)=half*(rho_in(ipt,1)-mm)
     132              :      else
     133     20631856 :        rho_out(ipt,1)=half*rho_in(ipt,1)
     134     20631856 :        rho_out(ipt,2)=half*rho_in(ipt,1)
     135              :      end if
     136              : 
     137     38760325 :      if (out_mag_norm) then
     138      5895866 :        if (m_norm >m_norm_min) mag_norm_out(ipt)=m_norm
     139      5895866 :        if (m_norm<=m_norm_min) mag_norm_out(ipt)=zero
     140              :      end if
     141              : 
     142              :    end do
     143              : 
     144              :  else ! cplex==2
     145              : 
     146      2345473 :    do ipt=1,vectsize
     147      2344960 :      if (has_mag_norm) then
     148            0 :        m_norm=mag_norm_in(ipt)
     149              :      else
     150      2344960 :        m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     151              :      end if
     152              : 
     153              :      ! real part of m.m^(1)
     154              :      rhoin_dot_mag_re=rho_in(2*ipt-1,2)*mag(ipt,1)+rho_in(2*ipt-1,3)*mag(ipt,2) &
     155      2344960 : &                    +rho_in(2*ipt-1,4)*mag(ipt,3)
     156              :      ! imaginary part of m.m^(1)
     157              :      rhoin_dot_mag_im=rho_in(2*ipt  ,2)*mag(ipt,1)+rho_in(2*ipt  ,3)*mag(ipt,2) &
     158      2344960 : &                    +rho_in(2*ipt  ,4)*mag(ipt,3)
     159      2344960 :      if(m_norm>m_norm_min)then
     160      1684571 :        mm=rhoin_dot_mag_re/m_norm
     161      1684571 :        rho_out(2*ipt-1,1)=half*(rho_in(2*ipt-1,1)+mm)
     162      1684571 :        rho_out(2*ipt-1,2)=half*(rho_in(2*ipt-1,1)-mm)
     163      1684571 :        mm=rhoin_dot_mag_im/m_norm
     164      1684571 :        rho_out(2*ipt  ,1)=half*(rho_in(2*ipt ,1)+mm)
     165      1684571 :        rho_out(2*ipt  ,2)=half*(rho_in(2*ipt ,1)-mm)
     166              :      else
     167       660389 :        rho_out(2*ipt-1,1)=half*rho_in(2*ipt-1,1)
     168              : !MR: BUG FIXED HERE
     169              : !       rho_out(2*ipt-1,2)=half*rho_in(2*ipt-1,2)
     170       660389 :        rho_out(2*ipt-1,2)=half*rho_in(2*ipt-1,1)
     171       660389 :        rho_out(2*ipt  ,1)=half*rho_in(2*ipt  ,1)
     172              : !MR: BUG FIXED HERE
     173              : !       rho_out(2*ipt  ,2)=half*rho_in(2*ipt  ,2)
     174       660389 :        rho_out(2*ipt  ,2)=half*rho_in(2*ipt  ,1)
     175              :      end if
     176              : 
     177      2345473 :      if (out_mag_norm) then
     178      2344960 :        if (m_norm >m_norm_min) mag_norm_out(ipt)=m_norm
     179      2344960 :        if (m_norm<=m_norm_min) mag_norm_out(ipt)=zero
     180              :      end if
     181              : 
     182              :    end do
     183              : 
     184              :  end if
     185              : 
     186        34772 :  if (present(rho_out_format)) then
     187         1086 :    if (rho_out_format==2) then
     188      8009388 :      do ipt=1,cplex*vectsize
     189      8008302 :        rho_up=rho_out(ipt,1)
     190      8008302 :        rho_out(ipt,1)=rho_up+rho_out(ipt,2)
     191      8009388 :        rho_out(ipt,2)=rho_up
     192              :      end do
     193              :    end if
     194              :  end if
     195              : 
     196              : !DBG_EXIT("COLL")
     197              : 
     198        34772 : end subroutine rotate_mag
     199              : !!***
     200              : 
     201              : !----------------------------------------------------------------------
     202              : 
     203              : !!****t* m_xc_noncoll/rotate_back_mag
     204              : !! NAME
     205              : !!  rotate_back_mag
     206              : !!
     207              : !! FUNCTION
     208              : !!  Rotate back a collinear XC potential (stored as up+dn) with respect to
     209              : !!   a magnetization and give a non-collinear XC potential
     210              : !!   (stored as up_up, dn_dn, Re[up_dn], Im[up_dn])
     211              : !!  Note: works only for cplex=1
     212              : !!
     213              : !! INPUTS
     214              : !!  vxc_in(vectsize,2)=input collinear XC potential
     215              : !!  mag(vectsize,3)=gs magnetization used for projection
     216              : !!  vectsize=size of vector fields
     217              : !!  [mag_norm_in(vectsize)]= --optional-- norm of mag(:) at each point of the grid
     218              : !!
     219              : !! OUTPUT
     220              : !!  vxc_out(vectsize,4)=output non-collinear XC potential
     221              : !!
     222              : !! SOURCE
     223              : 
     224        71629 : subroutine rotate_back_mag(vxc_in,vxc_out,mag,vectsize,&
     225              : &                          mag_norm_in) ! optional argument
     226              : 
     227              : !Arguments ------------------------------------
     228              : !scalars
     229              :  integer,intent(in) :: vectsize
     230              : !arrays
     231              :  real(dp),intent(in)  :: vxc_in(vectsize,2),mag(vectsize,3)
     232              :  real(dp),intent(out) :: vxc_out(vectsize,4)
     233              :  real(dp),intent(in),optional :: mag_norm_in(vectsize)
     234              : 
     235              : !Local variables-------------------------------
     236              : !scalars
     237              :  integer :: ipt
     238              :  logical :: has_mag_norm
     239              :  real(dp) :: dvdn,dvdz,m_norm
     240              : !arrays
     241              : 
     242              : ! *************************************************************************
     243              : 
     244              : !DBG_ENTER("COLL")
     245              : 
     246        71629 :  has_mag_norm=present(mag_norm_in)
     247              : 
     248     98954912 :  do ipt=1,vectsize
     249     98883283 :    if (has_mag_norm) then
     250       908847 :      m_norm=mag_norm_in(ipt)
     251              :    else
     252     97974436 :      m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     253              :    end if
     254              : 
     255     98883283 :    dvdn=half*(vxc_in(ipt,1)+vxc_in(ipt,2))
     256              : 
     257     98954912 :    if (m_norm>m_norm_min) then
     258     62550572 :      dvdz=half*(vxc_in(ipt,1)-vxc_in(ipt,2))/m_norm
     259     62550572 :      vxc_out(ipt,1)=dvdn+mag(ipt,3)*dvdz
     260     62550572 :      vxc_out(ipt,2)=dvdn-mag(ipt,3)*dvdz
     261     62550572 :      vxc_out(ipt,3)= mag(ipt,1)*dvdz
     262     62550572 :      vxc_out(ipt,4)=-mag(ipt,2)*dvdz
     263              :    else
     264    108998133 :      vxc_out(ipt,1:2)=dvdn
     265    108998133 :      vxc_out(ipt,3:4)=zero
     266              :    end if
     267              :  end do
     268              : 
     269              : !DBG_EXIT("COLL")
     270              : 
     271        71629 : end subroutine rotate_back_mag
     272              : !!***
     273              : 
     274              : !!****t* m_xc_noncoll/rotate_back_mag_dfpt
     275              : !! NAME
     276              : !!  rotate_back_mag_dfpt
     277              : !!
     278              : !! FUNCTION
     279              : !!  Rotate back a 1st-order collinear XC potential (stored as up+dn) with respect to
     280              : !!   a magnetization and give a 1st-order non-collinear XC potential
     281              : !!   (stored as up_up, dn_dn, Re{up_dn}, Im{up_dn}).
     282              : !!
     283              : !! INPUTS
     284              : !!  mag(vectsize,3)=0-order magnetization used for projection
     285              : !!  rho1(vectsize,4)=1st-order non-collinear density and magnetization
     286              : !!  vxc(vectsize,4)=0-order non-collinear XC potential
     287              : !!  kxc(vectsize,nkxc)=0-order XC kernel (associated to vxc)
     288              : !!  vxc1_in(vectsize,2)=input 1st-order collinear XC potential
     289              : !!  vectsize=size of vector fields
     290              : !!  [mag_norm_in(vectsize)]= --optional-- norm of 0-order mag(:) at each point of the grid
     291              : !!  [rot_method]=Select method used to compute rotation matrix (1, 2 or 3)
     292              : !!  option=if 0, compute only the U^0 vxc^(1) U^0 part
     293              : !!         if 1, full first order xc potential
     294              : !!
     295              : !! NOTES
     296              : !!   cplex=1:
     297              : !!     V is stored as : V^11, V^22, Re[V^12], Im[V^12] (complex, hermitian)
     298              : !!     N is stored as : n, m_x, m_y, m_z               (real)
     299              : !!   cplex=2:
     300              : !!     V is stored as : V^11, V^22, V^12, i.V^21 (complex)
     301              : !!     N is stored as : n, m_x, m_y, mZ          (complex)
     302              : !!
     303              : !! OUTPUT
     304              : !!  vxc1_out(vectsize,4)=output 1st-order non-collinear XC potential
     305              : !!
     306              : !! SOURCE
     307              : 
     308          997 : subroutine rotate_back_mag_dfpt(option,vxc1_in,vxc1_out,vxc,kxc,rho1,mag,vectsize,cplex,&
     309              : &                               mag_norm_in,rot_method) ! optional arguments
     310              : 
     311              : !Arguments ------------------------------------
     312              : !scalars
     313              :  integer,intent(in) :: vectsize
     314              :  integer,intent(in) :: cplex
     315              :  integer,intent(in) :: option
     316              :  integer,intent(in),optional  :: rot_method
     317              : !arrays
     318              :  real(dp),intent(in)          :: kxc(:,:),mag(vectsize,3),vxc(vectsize,4)
     319              :  real(dp),intent(in)          :: rho1(cplex*vectsize,4)
     320              :  real(dp),intent(in)          :: vxc1_in(cplex*vectsize,2)
     321              :  real(dp),intent(in),optional :: mag_norm_in(vectsize)
     322              :  real(dp),intent(out)         :: vxc1_out(cplex*vectsize,4)
     323              : 
     324              : !Local variables-------------------------------
     325              : !scalars
     326              :  integer  :: ipt,rotation_method
     327              :  logical  :: has_mag_norm
     328              :  logical  :: small_angle
     329              :  real(dp) :: bxc_over_m,d1,d2,dvdn,dvdz,fact,m_dot_m1,m_norm
     330              :  ! d3 and d4 were computed below but never used, and caused test
     331              :  ! fail problems
     332              :  !real(dp) :: d3,d4
     333              :  real(dp) :: dvdn_re,dvdn_im,dvdz_re,dvdz_im
     334              :  complex(dp) :: rho_updn
     335              :  real(dp) :: mdirx,mdiry,mdirz,mxy,mx1,my1,mz1,wx,wy,wx1,wy1
     336              :  real(dp) :: theta0,theta1,theta1_re,theta1_im
     337              :  real(dp) :: wx1_re,wx1_im
     338              :  real(dp) :: wy1_re,wy1_im
     339              :  real(dp) :: mx1_re,mx1_im,my1_re,my1_im,mz1_re,mz1_im
     340              :  real(dp) :: m_dot_m1_re,m_dot_m1_im
     341              :  real(dp) :: bxc
     342              : !arrays
     343              :  real(dp)     :: vxc_diag(2),v21tmp(2)
     344              :  complex(dp) :: r1tmp(2,2),u0(2,2),u0_1(2,2),u0_1r1(2,2),u0v1(2,2)
     345              :  complex(dp) :: rho1_updn(2,2),v1tmp(2,2),vxc1tmp(2,2)
     346              :  complex(dp) :: rho1_offdiag(2)
     347              : ! *************************************************************************
     348              : 
     349              : !DBG_ENTER("COLL")
     350              : 
     351              : !Optional arguments
     352          997 :  has_mag_norm=present(mag_norm_in)
     353          997 :  rotation_method=rotation_method_default
     354          997 :  if (present(rot_method)) rotation_method=rot_method
     355              : 
     356              : !Check Kxc
     357         2991 :  if (size(kxc)>3*vectsize) then
     358            0 :      ABI_ERROR('Cannot use Kxc from GGA!')
     359              :  end if
     360              : 
     361          997 :  if((rotation_method==1.or.rotation_method==2).and.cplex==2) then
     362            0 :      ABI_ERROR('rotation_method=1 and 2 are not available for cplex=2 case! use ixcrot=3')
     363              :  endif
     364              : 
     365              : 
     366              :  select case (rotation_method)
     367              : 
     368              : !----------------------------------------
     369              : ! Taylor expansion of U rotation matrix
     370              : !----------------------------------------
     371              :  case (1)
     372              : 
     373       743583 :    do ipt=1,vectsize
     374              : 
     375       743445 :      if (has_mag_norm) then
     376       743445 :        m_norm=mag_norm_in(ipt)
     377              :      else
     378            0 :        m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     379              :      end if
     380              : 
     381       743583 :      if(m_norm>m_norm_min) then
     382              : 
     383              : !      Define the U^(0) transformation matrix
     384       701352 :        rho_updn=(mag(ipt,1)+(zero,one)*mag(ipt,2))
     385       701352 :        d1=sqrt(( m_norm+mag(ipt,3))**2+abs(rho_updn)**2)
     386       701352 :        d2=sqrt((-m_norm+mag(ipt,3))**2+abs(rho_updn)**2)
     387              :        ! d3 and d4 are computed here but never used
     388              :        !d3=sqrt(( m_norm-mag(ipt,3))**2+abs(rho_updn)**2)
     389              :        !d4=sqrt(( m_norm+mag(ipt,3))**2-abs(rho_updn)**2)
     390       701352 :        u0(1,1)=( m_norm+mag(ipt,3))/d1  ! ( m  + mz)/d1
     391       701352 :        u0(2,2)=rho_updn/d2              ! ( mx +imy)/d2
     392       701352 :        u0(1,2)=(-m_norm+mag(ipt,3))/d2  ! (-m  + mz)/d2
     393       701352 :        u0(2,1)=rho_updn/d1              ! ( mx +imy)/d1
     394              : 
     395              : !      Define the inverse of U^(0): U^(0)^-1
     396       701352 :        if (abs(rho_updn) > m_norm_min) then
     397       674325 :          u0_1(1,1)= half*d1/m_norm
     398       674325 :          u0_1(2,2)= half*d2*(m_norm+mag(ipt,3))/(m_norm*rho_updn)
     399       674325 :          u0_1(1,2)= half*d1*(m_norm-mag(ipt,3))/(m_norm*rho_updn)
     400       674325 :          u0_1(2,1)=-half*d2/m_norm
     401              :        else
     402        27027 :          u0 = zero
     403        27027 :          u0(1,1) = one
     404        27027 :          u0(2,2) = one
     405        27027 :          u0_1 = zero
     406        27027 :          u0_1(1,1) = one
     407        27027 :          u0_1(2,2) = one
     408              :        end if
     409              : 
     410              : !      Diagonalize the GS Vxc^(0): U^(0)^-1 Vxc^(0) U^(0)
     411              : !        (Remember the abinit notation for vxc!)
     412              :        vxc_diag(1)=half*(vxc(ipt,1)+vxc(ipt,2) &
     413              : &                 -sqrt((vxc(ipt,1)-vxc(ipt,2))**2 &
     414       701352 : &                 +four*(vxc(ipt,3)**2+vxc(ipt,4)**2)))
     415              :        vxc_diag(2)=half*(vxc(ipt,1)+vxc(ipt,2) &
     416              : &                 +sqrt((vxc(ipt,1)-vxc(ipt,2))**2 &
     417       701352 : &                 +four*(vxc(ipt,3)**2+vxc(ipt,4)**2)))
     418       701352 :        v1tmp(1,1)=cmplx(real(vxc1_in(ipt,1),kind=dp),zero)
     419       701352 :        v1tmp(2,2)=cmplx(real(vxc1_in(ipt,2),kind=dp),zero)
     420              : 
     421              :        !Transforming the rhor1 with U0
     422       701352 :        rho1_updn(1,1)=half*(rho1(ipt,1)+rho1(ipt,4))
     423       701352 :        rho1_updn(2,2)=half*(rho1(ipt,1)-rho1(ipt,4))
     424       701352 :        rho1_updn(1,2)=half*(rho1(ipt,2)-(zero,one)*rho1(ipt,3))
     425       701352 :        rho1_updn(2,1)=half*(rho1(ipt,2)+(zero,one)*rho1(ipt,3))
     426     10520280 :        u0_1r1=matmul(u0_1,rho1_updn)
     427     10520280 :        r1tmp=matmul(u0_1r1,u0)
     428       701352 :        rho1_offdiag(1)=r1tmp(1,2) ; rho1_offdiag(2)=r1tmp(2,1)
     429              : 
     430       701352 :        if (option==0) then ! for xccc alone
     431       449412 :          v1tmp(1,2)=cmplx(zero,zero)
     432       449412 :          v1tmp(2,1)=cmplx(zero,zero)
     433              :        else
     434       251940 :          v1tmp(1,2)=-(rho1_offdiag(1)/m_norm)*(vxc_diag(2)-vxc_diag(1))
     435       251940 :          v1tmp(2,1)= (rho1_offdiag(2)/m_norm)*(vxc_diag(1)-vxc_diag(2))
     436              :        endif
     437              : 
     438              :        !Rotate back the "diagonal" xc computing the term U^(0) Vxc1_^(1) U^(0)^-1
     439     10520280 :        u0v1=matmul(u0,v1tmp)
     440     10520280 :        vxc1tmp=matmul(u0v1,u0_1)
     441       701352 :        vxc1_out(ipt,1)=real(vxc1tmp(1,1),kind=dp)
     442       701352 :        vxc1_out(ipt,2)=real(vxc1tmp(2,2),kind=dp)
     443       701352 :        vxc1_out(ipt,3)=real( real(vxc1tmp(1,2)),kind=dp)
     444       701352 :        vxc1_out(ipt,4)=real(aimag(vxc1tmp(1,2)),kind=dp)
     445              : 
     446              :      else ! Magnetization is zero
     447        42093 :        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half
     448        42093 :        mx1=rho1(ipt,2) ; my1=rho1(ipt,3) ; mz1=rho1(ipt,4)
     449              : !      Compute Bxc/|m| from Kxc (zero limit)
     450        42093 :        bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
     451        42093 :        vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
     452        42093 :        vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
     453        42093 :        vxc1_out(ipt,3)= bxc_over_m*mx1
     454        42093 :        vxc1_out(ipt,4)=-bxc_over_m*my1
     455              :      end if
     456              : 
     457              :    end do ! ipt
     458              : 
     459              : !----------------------------------------
     460              : ! Analytical expression of U rotation matrix
     461              : !----------------------------------------
     462              :  case (2)
     463              :    !Alternative method (explicitly calculated rotation matrices)
     464              :    !Vxc^(1) =   phixc^(1).Id +                                               // <= change of "electrostatic" XC potential  (phixc^(1) is denoted dvdn)
     465              :    !          + bxc^(1)*( Udag^(0).sigma_z.U^(0) )  +                        // <= this part describes the change of XC magnetic field magnitude bxc^(1)
     466              :    !          + bxc^(0)*( Udag^(1).sigma_z.U^(0) + Udag^(0).sigma_z.U^(1) )  // <= remaining terms describe the cost of magnetization rotation
     467              : 
     468          748 :    select case(cplex)
     469              :    case(1)
     470       674436 :      do ipt=1,vectsize
     471              : 
     472       674325 :        if (has_mag_norm) then
     473       674325 :          m_norm=mag_norm_in(ipt)
     474              :        else
     475            0 :          m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     476              :        end if
     477              : 
     478              : 
     479       674325 :        mx1 =rho1(ipt,2);
     480       674325 :        my1 =rho1(ipt,3);
     481       674325 :        mz1 =rho1(ipt,4)
     482              : 
     483       674325 :        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half  !phixc^(1)
     484       674325 :        dvdz=(vxc1_in(ipt,1)-vxc1_in(ipt,2))*half  !bxc^(1)
     485              : 
     486       674436 :        if (m_norm>m_norm_min) then
     487              : 
     488       674325 :          mxy = dsqrt(mag(ipt,1)**2+mag(ipt,2)**2)
     489       674325 :          small_angle=(mxy/m_norm<tol8)            !condition for sin(x)~x to be valid
     490              :                                                   !even possible to set to tol6
     491       674325 :          mdirx=mag(ipt,1)/m_norm
     492       674325 :          mdiry=mag(ipt,2)/m_norm
     493       674325 :          mdirz=mag(ipt,3)/m_norm
     494              : 
     495              : !        dvdn is phixc^(1) (density only part)
     496              : !        dvdz is bxc^(1)   (magnetization magnitude part)
     497              : 
     498              :          !U^(0)*.Vxc1.U^(0) part
     499       674325 :          vxc1_out(ipt,1)= dvdn+dvdz*mdirz
     500       674325 :          vxc1_out(ipt,2)= dvdn-dvdz*mdirz
     501       674325 :          vxc1_out(ipt,3)= dvdz*mdirx   ! Real part
     502       674325 :          vxc1_out(ipt,4)=-dvdz*mdiry   ! Imaginary part, minus sign comes from sigma_y
     503              : 
     504              :          !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1) part
     505              : 
     506              :          !bxc = dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !bxc^(0)
     507       674325 :          bxc = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)*m_norm
     508       674325 :          if (.not.small_angle) then
     509       674325 :            wx     = mag(ipt,2)/mxy
     510       674325 :            wy     =-mag(ipt,1)/mxy
     511       674325 :            theta0 = dacos(mag(ipt,3)/m_norm)
     512              : 
     513       674325 :            theta1 = (mdirz*(mdirx*mx1+mdiry*my1))/mxy - mz1*mxy/m_norm**2
     514       674325 :            wx1    = (+mag(ipt,1)**2*my1 - mag(ipt,1)*mag(ipt,2)*mx1)/mxy**2/m_norm  ! wx1 multiplied by sin(theta)=mxy/m_norm
     515       674325 :            wy1    = (-mag(ipt,2)**2*mx1 + mag(ipt,1)*mag(ipt,2)*my1)/mxy**2/m_norm  ! wx1 multiplied by sin(theta)=mxy/m_norm
     516              : 
     517       674325 :            vxc1_out(ipt,1) = vxc1_out(ipt,1) - bxc*dsin(theta0)*theta1
     518       674325 :            vxc1_out(ipt,2) = vxc1_out(ipt,2) + bxc*dsin(theta0)*theta1
     519       674325 :            vxc1_out(ipt,3) = vxc1_out(ipt,3) - bxc*(wy1+dcos(theta0)*wy*theta1)
     520       674325 :            vxc1_out(ipt,4) = vxc1_out(ipt,4) - bxc*(wx1+dcos(theta0)*wx*theta1)
     521              :          else
     522              :            !zero order terms O(1)
     523            0 :            vxc1_out(ipt,3) = vxc1_out(ipt,3) + bxc*mx1/abs(mag(ipt,3))
     524            0 :            vxc1_out(ipt,4) = vxc1_out(ipt,4) - bxc*my1/abs(mag(ipt,3))
     525              :            !first order terms O(theta)
     526            0 :            fact = bxc/(mag(ipt,3)*abs(mag(ipt,3)))
     527            0 :            vxc1_out(ipt,1) = vxc1_out(ipt,1) - (mag(ipt,1)*mx1+mag(ipt,2)*my1)*fact
     528            0 :            vxc1_out(ipt,2) = vxc1_out(ipt,2) + (mag(ipt,1)*mx1+mag(ipt,2)*my1)*fact
     529            0 :            vxc1_out(ipt,3) = vxc1_out(ipt,3) -  mag(ipt,1)*mz1*fact
     530            0 :            vxc1_out(ipt,4) = vxc1_out(ipt,4) +  mag(ipt,2)*mz1*fact
     531              :          endif
     532              : 
     533              :        else ! Magnetization is zero
     534              : !        Compute Bxc/|m| from Kxc (zero limit)
     535            0 :          bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
     536            0 :          vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
     537            0 :          vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
     538            0 :          vxc1_out(ipt,3)= bxc_over_m*mx1
     539            0 :          vxc1_out(ipt,4)=-bxc_over_m*my1
     540              :        end if
     541              :      end do ! ipt
     542              : 
     543              :    case(2) !cplex=2
     544              : 
     545          111 :      do ipt=1,vectsize
     546              : 
     547            0 :        if (has_mag_norm) then
     548            0 :          m_norm=mag_norm_in(ipt)
     549              :        else
     550            0 :          m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     551              :        end if
     552              : 
     553            0 :        mx1_re= rho1(2*ipt-1,2); mx1_im= rho1(2*ipt,2)
     554            0 :        my1_re= rho1(2*ipt-1,3); my1_im= rho1(2*ipt,3)
     555            0 :        mz1_re= rho1(2*ipt-1,4); mz1_im= rho1(2*ipt,4)
     556              : 
     557            0 :        dvdn_re=(vxc1_in(2*ipt-1,1)+vxc1_in(2*ipt-1,2))*half
     558            0 :        dvdz_re=(vxc1_in(2*ipt-1,1)-vxc1_in(2*ipt-1,2))*half
     559            0 :        dvdn_im=(vxc1_in(2*ipt  ,1)+vxc1_in(2*ipt  ,2))*half
     560            0 :        dvdz_im=(vxc1_in(2*ipt  ,1)-vxc1_in(2*ipt  ,2))*half
     561              : 
     562            0 :        if (m_norm>m_norm_min) then
     563              : 
     564            0 :          mdirx=mag(ipt,1)/m_norm
     565            0 :          mdiry=mag(ipt,2)/m_norm
     566            0 :          mdirz=mag(ipt,3)/m_norm
     567              : 
     568            0 :          mxy = dsqrt(mag(ipt,1)**2+mag(ipt,2)**2)
     569            0 :          small_angle=(mxy/m_norm<tol8)            !condition for sin(x)~x to be valid
     570              :                                                   !
     571            0 :          mdirx=mag(ipt,1)/m_norm
     572            0 :          mdiry=mag(ipt,2)/m_norm
     573            0 :          mdirz=mag(ipt,3)/m_norm
     574              : 
     575              : !        dvdn is phixc^(1) (density only part)
     576              : !        dvdz is bxc^(1)   (magnetization magnitude part)
     577              : 
     578              :          !U^(0)*.Vxc1.U^(0) part
     579            0 :          vxc1_out(2*ipt-1,1)= dvdn_re+dvdz_re*mdirz
     580            0 :          vxc1_out(2*ipt  ,1)= dvdn_im+dvdz_im*mdirz
     581            0 :          vxc1_out(2*ipt-1,2)= dvdn_re-dvdz_re*mdirz
     582            0 :          vxc1_out(2*ipt  ,2)= dvdn_im-dvdz_im*mdirz
     583              :          !NOTE: change of definition of the potential matrix components
     584              :          !      vxc1_out(:,3) =   V_updn
     585              :          !      vxc1_out(:,4) = i.V_updn
     586            0 :          vxc1_out(2*ipt-1,3)= dvdz_re*mdirx + dvdz_im*mdiry   !Re[  V^12]
     587            0 :          vxc1_out(2*ipt  ,3)= dvdz_im*mdirx - dvdz_re*mdiry   !Im[  V^12]
     588              : 
     589              :          !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1) part
     590              :          !bxc = dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !bxc^(0)
     591            0 :          bxc = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)*m_norm
     592            0 :          if (.not.small_angle) then
     593            0 :            wx     = mag(ipt,2)/mxy
     594            0 :            wy     =-mag(ipt,1)/mxy
     595            0 :            theta0 = dacos(mag(ipt,3)/m_norm)
     596              : 
     597              : 
     598            0 :            theta1_re = (mdirz*(mdirx*mx1_re+mdiry*my1_re))/mxy - mz1_re*mxy/m_norm**2
     599            0 :            theta1_im = (mdirz*(mdirx*mx1_im+mdiry*my1_im))/mxy - mz1_im*mxy/m_norm**2
     600              : 
     601            0 :            wx1_re = (+mag(ipt,1)**2*my1_re - mag(ipt,1)*mag(ipt,2)*mx1_re)/mxy**2/m_norm  ! wx1 multiplied by sin(theta)=mxy/m_norm
     602            0 :            wx1_im = (+mag(ipt,1)**2*my1_im - mag(ipt,1)*mag(ipt,2)*mx1_im)/mxy**2/m_norm
     603            0 :            wy1_re = (-mag(ipt,2)**2*mx1_re + mag(ipt,1)*mag(ipt,2)*my1_re)/mxy**2/m_norm  ! wy1 multiplied by sin(theta)=mxy/m_norm
     604            0 :            wy1_im = (-mag(ipt,2)**2*mx1_im + mag(ipt,1)*mag(ipt,2)*my1_im)/mxy**2/m_norm
     605              : 
     606              :            !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1)
     607            0 :            vxc1_out(2*ipt-1,1) = vxc1_out(2*ipt-1,1) - bxc*dsin(theta0)*theta1_re
     608            0 :            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) - bxc*dsin(theta0)*theta1_im
     609            0 :            vxc1_out(2*ipt-1,2) = vxc1_out(2*ipt-1,2) + bxc*dsin(theta0)*theta1_re
     610            0 :            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + bxc*dsin(theta0)*theta1_im
     611              :            !cplex=1 part:
     612              :            !v12 +=   -(bxc)*(wy1+dcos(theta0)*wy*theta1)-
     613              :            !       -i.(bxc)*(wx1+dcos(theta0)*wx*theta1)
     614            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) - bxc*(wy1_re+dcos(theta0)*wy*theta1_re)
     615            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*(wx1_im+dcos(theta0)*wx*theta1_im)
     616            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*(wy1_im+dcos(theta0)*wy*theta1_im)
     617            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*(wx1_re+dcos(theta0)*wx*theta1_re)
     618              :          else
     619              :            !small theta case:
     620              :            !zero order terms O(1)
     621            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*mx1_re/abs(mag(ipt,3))
     622            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*my1_im/abs(mag(ipt,3))
     623            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc*mx1_im/abs(mag(ipt,3))
     624            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*my1_re/abs(mag(ipt,3))
     625              :            !first order terms:
     626            0 :            fact = bxc/(mag(ipt,3)*abs(mag(ipt,3)))
     627            0 :            vxc1_out(2*ipt-1,1) = vxc1_out(2*ipt-1,1) - (mag(ipt,1)*mx1_re+mag(ipt,2)*my1_re)*fact
     628            0 :            vxc1_out(2*ipt-1,2) = vxc1_out(2*ipt-1,2) + (mag(ipt,1)*mx1_re+mag(ipt,2)*my1_re)*fact
     629            0 :            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) - (mag(ipt,1)*mx1_im+mag(ipt,2)*my1_im)*fact
     630            0 :            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + (mag(ipt,1)*mx1_im+mag(ipt,2)*my1_im)*fact
     631              : 
     632            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) -  mag(ipt,1)*mz1_re*fact
     633            0 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) -  mag(ipt,2)*mz1_im*fact
     634            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) +  mag(ipt,2)*mz1_re*fact
     635            0 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) -  mag(ipt,1)*mz1_im*fact
     636              :          endif
     637              : 
     638              :        else ! Magnetization is practically zero
     639              : !        Compute Bxc/|m| from Kxc (zero limit)
     640            0 :          bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
     641            0 :          vxc1_out(2*ipt-1,1)= dvdn_re + bxc_over_m*mz1_re
     642            0 :          vxc1_out(2*ipt  ,1)= dvdn_im + bxc_over_m*mz1_im
     643            0 :          vxc1_out(2*ipt-1,2)= dvdn_re - bxc_over_m*mz1_re
     644            0 :          vxc1_out(2*ipt  ,2)= dvdn_im - bxc_over_m*mz1_im
     645            0 :          vxc1_out(2*ipt-1,3)= bxc_over_m*( mx1_re+my1_im)
     646            0 :          vxc1_out(2*ipt  ,3)= bxc_over_m*(-my1_re+mx1_im)
     647              :        end if
     648              :        !finally reconstruct i.V^12 from V^12
     649            0 :        vxc1_out(2*ipt-1,4) =  vxc1_out(2*ipt  ,3)  ! Re[i.V^21] = Im[V^12]
     650            0 :        vxc1_out(2*ipt  ,4) =  vxc1_out(2*ipt-1,3)  ! Im[i.V^21] = Re[V^12]
     651              : 
     652              :      end do ! ipt
     653              : 
     654              :    end select
     655              : 
     656              : !----------------------------------------
     657              : ! Explicit derivative of the rotated XC functional
     658              : !----------------------------------------
     659              :  case (3)
     660              :    ! Brute-force derivative of Vxc
     661              :    ! Explicit calculation of the rotated xc functional
     662              :    ! (derivatives of the analytical expression) (Eq. A)
     663              :    ! Vxc^(1) =   phixc^(1).Id +                    // <= change of "electrostatic" XC potential  (phixc^(1) is denoted dvdn)
     664              :    !           + bxc^(1)*(sigma,m^(0))/|m^(0)|  +  // <= this term is equivalent to ( Udag^(0).sigma_z.U^(0) ) term in rotation_method=2
     665              :    !           + bxc^(0)*(sigma,m^(1)))/|m^(0)| -  // <= the last terms are equivalent to ( Udag^(1).sigma_z.U^(0) + Udag^(0).sigma_z.U^(1) )
     666              :    !           - bxc^(0)*(sigma,m^(0))*(m^(1),m^(0))/|m^(0)|**3
     667          997 :    select case(cplex)
     668              :    case(1)
     669              : 
     670       992000 :      do ipt=1,vectsize
     671              : 
     672       991765 :        if (has_mag_norm) then
     673       991765 :          m_norm=mag_norm_in(ipt)
     674              :        else
     675            0 :          m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     676              :        end if
     677              : 
     678              : !      dvdn is phixc^(1) (density only part)
     679              : !      dvdz is bxc^(1)   (magnetization magnitude part)
     680       991765 :        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half
     681       991765 :        dvdz=(vxc1_in(ipt,1)-vxc1_in(ipt,2))*half
     682              : 
     683       991765 :        mx1=rho1(ipt,2) ; my1=rho1(ipt,3) ; mz1=rho1(ipt,4)
     684              : 
     685       992000 :        if(m_norm>m_norm_min) then
     686              : 
     687       798449 :          mdirx=mag(ipt,1)/m_norm; mdiry=mag(ipt,2)/m_norm; mdirz=mag(ipt,3)/m_norm
     688              : 
     689              :          !This part describes the change of the magnitude of the xc magnetic field
     690              :          !and the change of the scalar part of the xc electrostatic potential, 1st + 2nd term in Eq.A
     691              :          !phixc^(1).Id + bxc^(1) (sigma,m^(0))/|m^(0)|
     692       798449 :          vxc1_out(ipt,1)= dvdn+dvdz*mdirz
     693       798449 :          vxc1_out(ipt,2)= dvdn-dvdz*mdirz
     694       798449 :          vxc1_out(ipt,3)= dvdz*mdirx   ! Real part
     695       798449 :          vxc1_out(ipt,4)=-dvdz*mdiry   ! Imaginary part, minus sign comes from sigma_y
     696              : 
     697       798449 :          if (option/=0) then
     698              :            !Add remaining contributions coming from the change of magnetization direction
     699              :            !projection of m^(1) on gs magnetization direction
     700       255944 :            m_dot_m1=(mdirx*rho1(ipt,2)+mdiry*rho1(ipt,3)+mdirz*rho1(ipt,4))
     701              : 
     702       255944 :            bxc_over_m =-dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !this is bxc^(0)
     703       255944 :            bxc_over_m = bxc_over_m/m_norm
     704       255944 :            vxc1_out(ipt,1) = vxc1_out(ipt,1) + bxc_over_m*( mz1 - mdirz*m_dot_m1 ) !
     705       255944 :            vxc1_out(ipt,2) = vxc1_out(ipt,2) + bxc_over_m*(-mz1 + mdirz*m_dot_m1 ) !
     706       255944 :            vxc1_out(ipt,3) = vxc1_out(ipt,3) + bxc_over_m*( mx1 - mdirx*m_dot_m1 ) !
     707       255944 :            vxc1_out(ipt,4) = vxc1_out(ipt,4) + bxc_over_m*(-my1 + mdiry*m_dot_m1 ) !
     708              :          endif
     709              : 
     710              :        else
     711       193316 :          if (option/=0) then
     712              :            !Compute bxc^(0)/|m| from kxc (|m^(0)| -> zero limit)
     713        29621 :            bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
     714        29621 :            vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
     715        29621 :            vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
     716        29621 :            vxc1_out(ipt,3)= bxc_over_m*mx1
     717        29621 :            vxc1_out(ipt,4)=-bxc_over_m*my1
     718              :          else
     719       163695 :            vxc1_out(ipt,1)= dvdn
     720       163695 :            vxc1_out(ipt,2)= dvdn
     721       163695 :            vxc1_out(ipt,3)= zero
     722       163695 :            vxc1_out(ipt,4)= zero
     723              :          endif
     724              :        end if
     725              : 
     726              :      end do ! ipt
     727              : 
     728              :    case(2)
     729              :      !cplex=2 case
     730              : 
     731      2345708 :      do ipt=1,vectsize
     732              : 
     733      2344960 :        if (has_mag_norm) then
     734      2344960 :          m_norm=mag_norm_in(ipt)
     735              :        else
     736            0 :          m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
     737              :        end if
     738              : 
     739              : !      see cplex=1 case for details
     740      2344960 :        dvdn_re=(vxc1_in(2*ipt-1,1)+vxc1_in(2*ipt-1,2))*half
     741      2344960 :        dvdn_im=(vxc1_in(2*ipt  ,1)+vxc1_in(2*ipt  ,2))*half
     742      2344960 :        dvdz_re=(vxc1_in(2*ipt-1,1)-vxc1_in(2*ipt-1,2))*half
     743      2344960 :        dvdz_im=(vxc1_in(2*ipt  ,1)-vxc1_in(2*ipt  ,2))*half
     744              : 
     745      2344960 :        mx1_re=rho1(2*ipt-1,2); mx1_im=rho1(2*ipt,2)
     746      2344960 :        my1_re=rho1(2*ipt-1,3); my1_im=rho1(2*ipt,3)
     747      2344960 :        mz1_re=rho1(2*ipt-1,4); mz1_im=rho1(2*ipt,4)
     748              : 
     749      2344960 :        if(m_norm>m_norm_min) then
     750              : 
     751      1684571 :          mdirx=mag(ipt,1)/m_norm; mdiry=mag(ipt,2)/m_norm; mdirz=mag(ipt,3)/m_norm
     752              : 
     753              :          !first two terms:
     754      1684571 :          vxc1_out(2*ipt-1,1)= dvdn_re+dvdz_re*mdirz
     755      1684571 :          vxc1_out(2*ipt  ,1)= dvdn_im+dvdz_im*mdirz
     756      1684571 :          vxc1_out(2*ipt-1,2)= dvdn_re-dvdz_re*mdirz
     757      1684571 :          vxc1_out(2*ipt  ,2)= dvdn_im-dvdz_im*mdirz
     758              :          !NOTE: change of definition of the potential matrix components
     759              :          !      vxc1_out(:,3) =   V_updn
     760              :          !      vxc1_out(:,4) = i.V_dnup
     761              : 
     762              :          !  V^12 =   dvdz*mx/|m| - i.dvdz*my/|m| = (Re[dvdz]*mx/|m| + Im[dvdz]*my/|m|) + i.(Im[dvdz]*mx/|m| - Re[dvdz]*my/|m|) => vxc1(:,3)
     763              :          !  V^21 =   dvdz*mx/|m| + i.dvdz*my/|m| = (Re[dvdz]*mx/|m| - Im[dvdz]*my/|m|) + i.(Im[dvdz]*mx/|m| + Re[dvdz]*my/|m|)
     764      1684571 :          vxc1_out(2*ipt-1,3)= dvdz_re*mdirx + dvdz_im*mdiry   !Re[V^12]
     765      1684571 :          vxc1_out(2*ipt  ,3)= dvdz_im*mdirx - dvdz_re*mdiry   !Im[V^12]
     766      1684571 :          vxc1_out(2*ipt-1,4)= dvdz_re*mdirx - dvdz_im*mdiry   !Re[V^21]
     767      1684571 :          vxc1_out(2*ipt  ,4)= dvdz_im*mdirx + dvdz_re*mdiry   !Im[V^21]
     768      1684571 :          if (option/=0) then
     769              : 
     770              :            !remaining contributions:
     771       571295 :            m_dot_m1_re= mdirx*mx1_re + mdiry*my1_re + mdirz*mz1_re
     772       571295 :            m_dot_m1_im= mdirx*mx1_im + mdiry*my1_im + mdirz*mz1_im
     773              : 
     774       571295 :            bxc_over_m =-dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !this is bxc^(0)
     775       571295 :            bxc_over_m = bxc_over_m/m_norm
     776              :           !bxc_over_m = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)
     777              : 
     778       571295 :            vxc1_out(2*ipt-1,1) = vxc1_out(2*ipt-1,1) + bxc_over_m*( mz1_re - mdirz*m_dot_m1_re ) ! Re[V^11]
     779       571295 :            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) + bxc_over_m*( mz1_im - mdirz*m_dot_m1_im ) ! Im[V^11]
     780       571295 :            vxc1_out(2*ipt-1,2) = vxc1_out(2*ipt-1,2) + bxc_over_m*(-mz1_re + mdirz*m_dot_m1_re ) ! Re[V^22]
     781       571295 :            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + bxc_over_m*(-mz1_im + mdirz*m_dot_m1_im ) ! Im[V^22]
     782              : 
     783              :            !    v12  += bxc_over_m*(   (mx1    - mdirx*m_dot_m1   ) - i.( my1    - mdiry*m_dot_m1   )   )  <= see cplex=1
     784              :            ! Re[v12] += bxc_over_m*(   (mx1_re - mdirx*m_dot_m1_re) +   ( my1_im - mdiry*m_dot_m1_im)   )
     785              :            ! Im[v12] += bxc_over_m*(   (mx1_im - mdirx*m_dot_m1_im) +   (-my1_re + mdiry*m_dot_m1_re)   )
     786       571295 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc_over_m*( mx1_re - mdirx*m_dot_m1_re ) ! Re[V^12]
     787       571295 :            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc_over_m*( my1_im - mdiry*m_dot_m1_im ) ! Re[V^12]
     788       571295 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc_over_m*( mx1_im - mdirx*m_dot_m1_im ) ! Im[V^12]
     789       571295 :            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc_over_m*(-my1_re + mdiry*m_dot_m1_re ) ! Im[V^12]
     790              : 
     791              :            !    v21  += bxc_over_m*(   (mx1    - mdirx*m_dot_m1   ) + i.( my1    - mdiry*m_dot_m1   )   )
     792              :            ! Re[v21] += bxc_over_m*(   (mx1_re - mdirx*m_dot_m1_re) +   (-my1_im + mdiry*m_dot_m1_im)   )
     793              :            ! Im[v21] += bxc_over_m*(   (mx1_im - mdirx*m_dot_m1_im) +   ( my1_re - mdiry*m_dot_m1_re)   )
     794              :            ! the 4th component is actually not v21, but rather i.v21, this will be adjusted later
     795       571295 :            vxc1_out(2*ipt-1,4) = vxc1_out(2*ipt-1,4) + bxc_over_m*( mx1_re - mdirx*m_dot_m1_re ) ! Re[V^21]
     796       571295 :            vxc1_out(2*ipt-1,4) = vxc1_out(2*ipt-1,4) + bxc_over_m*(-my1_im + mdiry*m_dot_m1_im ) ! Re[V^21]
     797       571295 :            vxc1_out(2*ipt  ,4) = vxc1_out(2*ipt  ,4) + bxc_over_m*( mx1_im - mdirx*m_dot_m1_im ) ! Im[V^21]
     798       571295 :            vxc1_out(2*ipt  ,4) = vxc1_out(2*ipt  ,4) + bxc_over_m*( my1_re - mdiry*m_dot_m1_re ) ! Im[V^21]
     799              :          endif
     800              :        else
     801       660389 :          if(option/=0) then
     802              :            !Compute Bxc/|m| from Kxc (|m^(0)| -> zero limit)
     803        84065 :            bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
     804        84065 :            vxc1_out(2*ipt-1,1)= dvdn_re + bxc_over_m*mz1_re
     805        84065 :            vxc1_out(2*ipt-1,2)= dvdn_re - bxc_over_m*mz1_re
     806        84065 :            vxc1_out(2*ipt  ,1)= dvdn_im + bxc_over_m*mz1_im
     807        84065 :            vxc1_out(2*ipt  ,2)= dvdn_im - bxc_over_m*mz1_im
     808              : 
     809        84065 :            vxc1_out(2*ipt-1,3)= bxc_over_m*(mx1_re+my1_im)
     810        84065 :            vxc1_out(2*ipt  ,3)= bxc_over_m*(mx1_im-my1_re)
     811        84065 :            vxc1_out(2*ipt-1,4)= bxc_over_m*(mx1_re-my1_im)
     812        84065 :            vxc1_out(2*ipt  ,4)= bxc_over_m*(mx1_im+my1_re)
     813              :          else
     814       576324 :            vxc1_out(2*ipt-1,1)= dvdn_re
     815       576324 :            vxc1_out(2*ipt-1,2)= dvdn_re
     816       576324 :            vxc1_out(2*ipt  ,1)= dvdn_im
     817       576324 :            vxc1_out(2*ipt  ,2)= dvdn_im
     818              : 
     819       576324 :            vxc1_out(2*ipt-1,3)= zero
     820       576324 :            vxc1_out(2*ipt  ,3)= zero
     821       576324 :            vxc1_out(2*ipt-1,4)= zero
     822       576324 :            vxc1_out(2*ipt  ,4)= zero
     823              :          endif
     824              :        end if
     825              : 
     826              :        !finally reconstruct i.V^21 from V^21
     827      2344960 :        v21tmp(1) = vxc1_out(2*ipt-1,4) !Re[V^21]
     828      2344960 :        v21tmp(2) = vxc1_out(2*ipt  ,4) !Im[V^21]
     829              : 
     830      2344960 :        vxc1_out(2*ipt-1,4) =-v21tmp(2) ! Re[i.V^21]=-Im[V^21]
     831      2345473 :        vxc1_out(2*ipt  ,4) = v21tmp(1) ! Im[i.V^21]= Re[V^21]
     832              : 
     833              :      end do ! ipt
     834              : 
     835              :    end select !cplex
     836              : 
     837              :  end select ! rotation_method
     838              : 
     839              : !DBG_EXIT("COLL")
     840              : 
     841          997 : end subroutine rotate_back_mag_dfpt
     842              : !!***
     843              : 
     844              : 
     845              : !!****f* ABINIT/m_xc_noncoll/test_rotations
     846              : !! NAME
     847              : !!  test_rotations
     848              : !!
     849              : !! FUNCTION
     850              : !!  Test three different methods in rotate_back_mag_dfpt
     851              : !!
     852              : !! INPUTS
     853              : !!  option= types of tests to perform
     854              : !!          0=> only quick tests
     855              : !!          1=> quick and slow tests
     856              : !!  cplex = complex or real potential and first order magnetization
     857              : !!
     858              : !! OUTPUT
     859              : !!
     860              : !! SIDE EFFECTS
     861              : !!
     862              : !! NOTES
     863              : !!
     864              : !!  For debug purposes
     865              : !!
     866              : !! SOURCE
     867              : 
     868            0 : subroutine test_rotations(option,cplex)
     869              : 
     870              : !Arguments ------------------------------------
     871              :  integer , intent(in)  :: option
     872              :  integer , intent(in)  :: cplex
     873              : 
     874              : !Local variables-------------------------------
     875              :  real(dp) :: m0(1,3),vxc0(1,4),kxc(1,3)
     876            0 :  real(dp) :: n1(cplex,4),vxc1_in(cplex,4),vxc1_out(cplex,4)
     877            0 :  real(dp) :: delta_23(cplex,4) !,delta_12(cplex,4)
     878              :  real(dp) :: m0_norm,dvdn,dvdz,err23 !,wrong_comp!,err12
     879              :  real(dp) :: theta0,phi0,theta1,phi1,err,m1_norm
     880              :  integer  :: dir0,dir1
     881              : ! *************************************************************************
     882              : 
     883              :  DBG_ENTER("COLL")
     884              : 
     885              : ! if (option/=1 .and. option/=2 ) then
     886              : !  write(msg,'(3a,i0)')&
     887              : !&  'The argument option should be 1 or 2,',ch10,&
     888              : !&  'however, option=',option
     889              : !  ABI_BUG(msg)
     890              : ! end if
     891              : !
     892              : ! if (sizein<1) then
     893              : !  write(msg,'(3a,i0)')&
     894              : !&  '  The argument sizein should be a positive number,',ch10,&
     895              : !&  '  however, sizein=',sizein
     896              : !  ABI_ERROR(msg)
     897              : ! end if
     898              : 
     899              :  DBG_EXIT("COLL")
     900              : 
     901              :  !write(*,*)    'VXC_NONCOLL TESTS================================================================'
     902            0 :  if (cplex==1) then
     903              :     !write(*,*) '  cplex=1------------------------------------------------------------------------'
     904              : 
     905              :     !write(*,*) '    TEST: simple  m* orietnations, bxc^(1) part'
     906              :     dvdn=zero;dvdz=1.0!
     907              :     err23=zero
     908            0 :     do dir0=1,3
     909            0 :     m0=zero; n1=zero
     910            0 :       do dir1=2,4
     911            0 :         m0(1,dir0)=0.1
     912            0 :         m0_norm=sqrt(m0(1,1)**2+m0(1,2)**2+m0(1,3)**2)
     913            0 :         n1(1,dir1)=0.8     ! any number would do here
     914              : 
     915            0 :         vxc0=zero;     ! no bxc^(0) part at all
     916              : 
     917            0 :         vxc1_in(1,1)= dvdn+dvdz
     918            0 :         vxc1_in(1,2)= dvdn-dvdz
     919              : 
     920            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
     921            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
     922            0 :         delta_23=vxc1_out
     923            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
     924            0 :         delta_23=abs(delta_23-vxc1_out)
     925            0 :         err=max(delta_23(1,1),delta_23(1,2),delta_23(1,3),delta_23(1,4))
     926            0 :         if (err23<err) err23=err;
     927              : 
     928              :       enddo
     929              :     enddo
     930              :     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
     931              : 
     932              :     !write(*,*) '    TEST: simple  m* orietnations, bxc^(0) part'
     933              : 
     934              :     err23=zero
     935              :     dvdn=zero;dvdz=1.0
     936            0 :     do dir0=1,3
     937            0 :     m0=zero; n1=zero
     938            0 :       do dir1=2,4
     939            0 :         m0(1,dir0)=0.1
     940            0 :         m0_norm=sqrt(m0(1,1)**2+m0(1,2)**2+m0(1,3)**2)
     941            0 :         n1(1,dir1)=0.8     ! =m^1, any number would do here
     942              : 
     943            0 :         vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
     944            0 :         vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
     945            0 :         vxc0(1,3) = dvdz*m0(1,1)/m0_norm
     946            0 :         vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
     947              : 
     948            0 :         vxc1_in=zero !vxc^(1) collinear is zero
     949              : 
     950            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
     951            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
     952            0 :         delta_23=vxc1_out
     953            0 :         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
     954            0 :         delta_23=abs(delta_23-vxc1_out)
     955            0 :         err=maxval(abs(delta_23(1,:)))
     956            0 :         if (err23<err) err23=err;
     957              :       enddo
     958              :     enddo
     959              :     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
     960              : 
     961              :     !write(*,*) '    TEST: general m0 orietnations, bxc^(0) part'
     962              : 
     963              :     theta0=zero
     964              :     err23=zero
     965            0 :     m0_norm=0.3
     966            0 :     do while(theta0<=pi)
     967              :       phi0=zero
     968            0 :       do while(phi0<=2*pi)
     969            0 :         m0(1,1)=m0_norm*sin(theta0)*cos(phi0)
     970            0 :         m0(1,2)=m0_norm*sin(theta0)*sin(phi0)
     971            0 :         m0(1,3)=m0_norm*cos(theta0)
     972              : 
     973            0 :         do  dir1=2,4
     974            0 :           n1=zero
     975            0 :           n1(1,dir1)=0.8     ! =m^1, any number would do here
     976              : 
     977              :           !vxc0=zero;     !
     978            0 :           vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
     979            0 :           vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
     980            0 :           vxc0(1,3) = dvdz*m0(1,1)/m0_norm
     981            0 :           vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
     982              : 
     983            0 :           vxc1_in=zero
     984              : 
     985              :           !call rotate_back_mag_dfpt(vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
     986            0 :           call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
     987            0 :           delta_23=vxc1_out
     988            0 :           call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
     989            0 :           delta_23=abs(delta_23-vxc1_out)
     990            0 :           err=maxval(abs(delta_23(1,:)))
     991            0 :           if (err23<err) err23=err;
     992              :         enddo
     993            0 :         phi0=phi0+2*pi/100.0
     994              :       enddo
     995            0 :       theta0=theta0+pi/100.0
     996              :     enddo
     997              :     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
     998              : 
     999            0 :     if(option==2) then
    1000              :     !write(*,*) '    TEST: general m* orietnations, bxc^(0) part'
    1001              :     dvdn=zero;dvdz=1.0
    1002              : 
    1003              :     theta0=zero
    1004              :     err23=zero
    1005            0 :     m0_norm=0.3
    1006              :     m1_norm=10.5
    1007            0 :     do while(theta0<=pi) !loops on orientation of m^(0)
    1008              :       phi0=zero
    1009            0 :       do while(phi0<=2*pi)
    1010            0 :         m0(1,1)=m0_norm*sin(theta0)*cos(phi0)
    1011            0 :         m0(1,2)=m0_norm*sin(theta0)*sin(phi0)
    1012            0 :         m0(1,3)=m0_norm*cos(theta0)
    1013              : 
    1014            0 :         vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
    1015            0 :         vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
    1016            0 :         vxc0(1,3) = dvdz*m0(1,1)/m0_norm
    1017            0 :         vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
    1018              : 
    1019            0 :         vxc1_in=zero
    1020              : 
    1021              :         theta1=zero
    1022            0 :         do while(theta1<=pi) !loops on orientation of m^(1)
    1023              :           phi1=zero
    1024            0 :           do while(phi1<=2*pi)
    1025            0 :             n1(1,1)=zero
    1026            0 :             n1(1,2)=m1_norm*sin(theta1)*cos(phi1)
    1027            0 :             n1(1,3)=m1_norm*sin(theta1)*sin(phi1)
    1028            0 :             n1(1,4)=m1_norm*cos(theta1)
    1029              : 
    1030              :             !vxc0=zero;     !
    1031              :             !call rotate_back_mag_dfpt(vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
    1032            0 :             call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
    1033            0 :             delta_23=vxc1_out
    1034            0 :             call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
    1035            0 :             delta_23=abs(delta_23-vxc1_out)
    1036            0 :             err=maxval(abs(delta_23(1,:)))
    1037              :             if (err23<err) err23=err;
    1038            0 :             phi1=phi1+2*pi/100.0
    1039              :           enddo
    1040            0 :           theta1=theta1+pi/100.0
    1041              :         enddo
    1042              : 
    1043            0 :         phi0=phi0+2*pi/100.0
    1044              :       enddo
    1045            0 :       theta0=theta0+pi/100.0
    1046              :     enddo
    1047              :     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
    1048              :     endif
    1049              : 
    1050              :  !else !cplex=2
    1051              : 
    1052              :  endif
    1053              : 
    1054            0 : end subroutine test_rotations
    1055              : !!***
    1056              : 
    1057              : 
    1058              : !----------------------------------------------------------------------
    1059              : 
    1060              : END MODULE m_xc_noncoll
    1061              : !!***
        

Generated by: LCOV version 2.3-1