TABLE OF CONTENTS


ABINIT/m_xc_noncoll [ Functions ]

[ Top ] [ Functions ]

NAME

 m_xc_noncoll

FUNCTION

  This module provides several routines used in non-collinear XC routines
  (rotation of the magnetization in order to align it)

COPYRIGHT

 Copyright (C) 2001-2024 ABINIT group (EB, MT, FR, SPr)
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .

INPUTS

OUTPUT

SOURCE

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 !===========================================================

ABINIT/m_xc_noncoll/test_rotations [ Functions ]

[ Top ] [ Functions ]

NAME

  test_rotations

FUNCTION

  Test three different methods in rotate_back_mag_dfpt

INPUTS

  option= types of tests to perform
          0=> only quick tests
          1=> quick and slow tests
  cplex = complex or real potential and first order magnetization

OUTPUT

SIDE EFFECTS

NOTES

  For debug purposes

SOURCE

 861 subroutine test_rotations(option,cplex)
 862 
 863 !Arguments ------------------------------------
 864  integer , intent(in)  :: option
 865  integer , intent(in)  :: cplex
 866 
 867 !Local variables-------------------------------
 868  real(dp) :: m0(1,3),vxc0(1,4),kxc(1,3)
 869  real(dp) :: n1(cplex,4),vxc1_in(cplex,4),vxc1_out(cplex,4)
 870  real(dp) :: delta_23(cplex,4) !,delta_12(cplex,4)
 871  real(dp) :: m0_norm,dvdn,dvdz,err23 !,wrong_comp!,err12
 872  real(dp) :: theta0,phi0,theta1,phi1,err,m1_norm
 873  integer  :: dir0,dir1
 874 ! *************************************************************************
 875 
 876  DBG_ENTER("COLL")
 877 
 878 ! if (option/=1 .and. option/=2 ) then
 879 !  write(msg,'(3a,i0)')&
 880 !&  'The argument option should be 1 or 2,',ch10,&
 881 !&  'however, option=',option
 882 !  ABI_BUG(msg)
 883 ! end if
 884 !
 885 ! if (sizein<1) then
 886 !  write(msg,'(3a,i0)')&
 887 !&  '  The argument sizein should be a positive number,',ch10,&
 888 !&  '  however, sizein=',sizein
 889 !  ABI_ERROR(msg)
 890 ! end if
 891 
 892  DBG_EXIT("COLL")
 893 
 894  !write(*,*)    'VXC_NONCOLL TESTS================================================================'
 895  if (cplex==1) then
 896     !write(*,*) '  cplex=1------------------------------------------------------------------------'
 897 
 898     !write(*,*) '    TEST: simple  m* orietnations, bxc^(1) part'
 899     dvdn=zero;dvdz=1.0!
 900     err23=zero
 901     do dir0=1,3
 902     m0=zero; n1=zero
 903       do dir1=2,4
 904         m0(1,dir0)=0.1
 905         m0_norm=sqrt(m0(1,1)**2+m0(1,2)**2+m0(1,3)**2)
 906         n1(1,dir1)=0.8     ! any number would do here
 907 
 908         vxc0=zero;     ! no bxc^(0) part at all
 909 
 910         vxc1_in(1,1)= dvdn+dvdz
 911         vxc1_in(1,2)= dvdn-dvdz
 912 
 913         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
 914         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
 915         delta_23=vxc1_out
 916         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
 917         delta_23=abs(delta_23-vxc1_out)
 918         err=max(delta_23(1,1),delta_23(1,2),delta_23(1,3),delta_23(1,4))
 919         if (err23<err) err23=err;
 920 
 921       enddo
 922     enddo
 923     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
 924 
 925     !write(*,*) '    TEST: simple  m* orietnations, bxc^(0) part'
 926 
 927     err23=zero
 928     dvdn=zero;dvdz=1.0
 929     do dir0=1,3
 930     m0=zero; n1=zero
 931       do dir1=2,4
 932         m0(1,dir0)=0.1
 933         m0_norm=sqrt(m0(1,1)**2+m0(1,2)**2+m0(1,3)**2)
 934         n1(1,dir1)=0.8     ! =m^1, any number would do here
 935 
 936         vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
 937         vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
 938         vxc0(1,3) = dvdz*m0(1,1)/m0_norm
 939         vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
 940 
 941         vxc1_in=zero !vxc^(1) collinear is zero
 942 
 943         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
 944         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
 945         delta_23=vxc1_out
 946         call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
 947         delta_23=abs(delta_23-vxc1_out)
 948         err=maxval(abs(delta_23(1,:)))
 949         if (err23<err) err23=err;
 950       enddo
 951     enddo
 952     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
 953 
 954     !write(*,*) '    TEST: general m0 orietnations, bxc^(0) part'
 955 
 956     theta0=zero
 957     err23=zero
 958     m0_norm=0.3
 959     do while(theta0<=pi)
 960       phi0=zero
 961       do while(phi0<=2*pi)
 962         m0(1,1)=m0_norm*sin(theta0)*cos(phi0)
 963         m0(1,2)=m0_norm*sin(theta0)*sin(phi0)
 964         m0(1,3)=m0_norm*cos(theta0)
 965 
 966         do  dir1=2,4
 967           n1=zero
 968           n1(1,dir1)=0.8     ! =m^1, any number would do here
 969 
 970           !vxc0=zero;     !
 971           vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
 972           vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
 973           vxc0(1,3) = dvdz*m0(1,1)/m0_norm
 974           vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
 975 
 976           vxc1_in=zero
 977 
 978           !call rotate_back_mag_dfpt(vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
 979           call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
 980           delta_23=vxc1_out
 981           call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
 982           delta_23=abs(delta_23-vxc1_out)
 983           err=maxval(abs(delta_23(1,:)))
 984           if (err23<err) err23=err;
 985         enddo
 986         phi0=phi0+2*pi/100.0
 987       enddo
 988       theta0=theta0+pi/100.0
 989     enddo
 990     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
 991 
 992     if(option==2) then
 993     !write(*,*) '    TEST: general m* orietnations, bxc^(0) part'
 994     dvdn=zero;dvdz=1.0
 995 
 996     theta0=zero
 997     err23=zero
 998     m0_norm=0.3
 999     m1_norm=10.5
1000     do while(theta0<=pi) !loops on orientation of m^(0)
1001       phi0=zero
1002       do while(phi0<=2*pi)
1003         m0(1,1)=m0_norm*sin(theta0)*cos(phi0)
1004         m0(1,2)=m0_norm*sin(theta0)*sin(phi0)
1005         m0(1,3)=m0_norm*cos(theta0)
1006 
1007         vxc0(1,1) = dvdn+dvdz*m0(1,3)/m0_norm
1008         vxc0(1,2) = dvdn-dvdz*m0(1,3)/m0_norm
1009         vxc0(1,3) = dvdz*m0(1,1)/m0_norm
1010         vxc0(1,4) =-dvdz*m0(1,2)/m0_norm
1011 
1012         vxc1_in=zero
1013 
1014         theta1=zero
1015         do while(theta1<=pi) !loops on orientation of m^(1)
1016           phi1=zero
1017           do while(phi1<=2*pi)
1018             n1(1,1)=zero
1019             n1(1,2)=m1_norm*sin(theta1)*cos(phi1)
1020             n1(1,3)=m1_norm*sin(theta1)*sin(phi1)
1021             n1(1,4)=m1_norm*cos(theta1)
1022 
1023             !vxc0=zero;     !
1024             !call rotate_back_mag_dfpt(vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=1)
1025             call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=2)
1026             delta_23=vxc1_out
1027             call rotate_back_mag_dfpt(1,vxc1_in,vxc1_out,vxc0,kxc,n1,m0,1,1,rot_method=3)
1028             delta_23=abs(delta_23-vxc1_out)
1029             err=maxval(abs(delta_23(1,:)))
1030             if (err23<err) err23=err;
1031             phi1=phi1+2*pi/100.0
1032           enddo
1033           theta1=theta1+pi/100.0
1034         enddo
1035 
1036         phi0=phi0+2*pi/100.0
1037       enddo
1038       theta0=theta0+pi/100.0
1039     enddo
1040     !write(*,*) '    maximum mismatch between methods 2 and 3:',err23
1041     endif
1042 
1043  !else !cplex=2
1044 
1045  endif
1046 
1047 end subroutine test_rotations

m_xc_noncoll/rotate_back_mag [ Types ]

[ Top ] [ m_xc_noncoll ] [ Types ]

NAME

  rotate_back_mag

FUNCTION

  Rotate back a collinear XC potential (stored as up+dn) with respect to
   a magnetization and give a non-collinear XC potential
   (stored as up_up, dn_dn, Re[up_dn], Im[up_dn])
  Note: works only for cplex=1

INPUTS

  vxc_in(vectsize,2)=input collinear XC potential
  mag(vectsize,3)=gs magnetization used for projection
  vectsize=size of vector fields
  [mag_norm_in(vectsize)]= --optional-- norm of mag(:) at each point of the grid

OUTPUT

  vxc_out(vectsize,4)=output non-collinear XC potential

SOURCE

220 subroutine rotate_back_mag(vxc_in,vxc_out,mag,vectsize,&
221 &                          mag_norm_in) ! optional argument
222 
223 !Arguments ------------------------------------
224 !scalars
225  integer,intent(in) :: vectsize
226 !arrays
227  real(dp),intent(in)  :: vxc_in(vectsize,2),mag(vectsize,3)
228  real(dp),intent(out) :: vxc_out(vectsize,4)
229  real(dp),intent(in),optional :: mag_norm_in(vectsize)
230 
231 !Local variables-------------------------------
232 !scalars
233  integer :: ipt
234  logical :: has_mag_norm
235  real(dp) :: dvdn,dvdz,m_norm
236 !arrays
237 
238 ! *************************************************************************
239 
240 !DBG_ENTER("COLL")
241 
242  has_mag_norm=present(mag_norm_in)
243 
244  do ipt=1,vectsize
245    if (has_mag_norm) then
246      m_norm=mag_norm_in(ipt)
247    else
248      m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
249    end if
250 
251    dvdn=half*(vxc_in(ipt,1)+vxc_in(ipt,2))
252 
253    if (m_norm>m_norm_min) then
254      dvdz=half*(vxc_in(ipt,1)-vxc_in(ipt,2))/m_norm
255      vxc_out(ipt,1)=dvdn+mag(ipt,3)*dvdz
256      vxc_out(ipt,2)=dvdn-mag(ipt,3)*dvdz
257      vxc_out(ipt,3)= mag(ipt,1)*dvdz
258      vxc_out(ipt,4)=-mag(ipt,2)*dvdz
259    else
260      vxc_out(ipt,1:2)=dvdn
261      vxc_out(ipt,3:4)=zero
262    end if
263  end do
264 
265 !DBG_EXIT("COLL")
266 
267 end subroutine rotate_back_mag

m_xc_noncoll/rotate_back_mag_dfpt [ Types ]

[ Top ] [ m_xc_noncoll ] [ Types ]

NAME

  rotate_back_mag_dfpt

FUNCTION

  Rotate back a 1st-order collinear XC potential (stored as up+dn) with respect to
   a magnetization and give a 1st-order non-collinear XC potential
   (stored as up_up, dn_dn, Re{up_dn}, Im{up_dn}).

INPUTS

  mag(vectsize,3)=0-order magnetization used for projection
  rho1(vectsize,4)=1st-order non-collinear density and magnetization
  vxc(vectsize,4)=0-order non-collinear XC potential
  kxc(vectsize,nkxc)=0-order XC kernel (associated to vxc)
  vxc1_in(vectsize,2)=input 1st-order collinear XC potential
  vectsize=size of vector fields
  [mag_norm_in(vectsize)]= --optional-- norm of 0-order mag(:) at each point of the grid
  [rot_method]=Select method used to compute rotation matrix (1, 2 or 3)
  option=if 0, compute only the U^0 vxc^(1) U^0 part
         if 1, full first order xc potential

NOTES

   cplex=1:
     V is stored as : V^11, V^22, Re[V^12], Im[V^12] (complex, hermitian)
     N is stored as : n, m_x, m_y, m_z               (real)
   cplex=2:
     V is stored as : V^11, V^22, V^12, i.V^21 (complex)
     N is stored as : n, m_x, m_y, mZ          (complex)

OUTPUT

  vxc1_out(vectsize,4)=output 1st-order non-collinear XC potential

SOURCE

304 subroutine rotate_back_mag_dfpt(option,vxc1_in,vxc1_out,vxc,kxc,rho1,mag,vectsize,cplex,&
305 &                               mag_norm_in,rot_method) ! optional arguments
306 
307 !Arguments ------------------------------------
308 !scalars
309  integer,intent(in) :: vectsize
310  integer,intent(in) :: cplex
311  integer,intent(in) :: option
312  integer,intent(in),optional  :: rot_method
313 !arrays
314  real(dp),intent(in)          :: kxc(:,:),mag(vectsize,3),vxc(vectsize,4)
315  real(dp),intent(in)          :: rho1(cplex*vectsize,4)
316  real(dp),intent(in)          :: vxc1_in(cplex*vectsize,2)
317  real(dp),intent(in),optional :: mag_norm_in(vectsize)
318  real(dp),intent(out)         :: vxc1_out(cplex*vectsize,4)
319 
320 !Local variables-------------------------------
321 !scalars
322  integer  :: ipt,rotation_method
323  logical  :: has_mag_norm
324  logical  :: small_angle
325  real(dp) :: bxc_over_m,d1,d2,d3,d4,dvdn,dvdz,fact,m_dot_m1,m_norm
326  real(dp) :: dvdn_re,dvdn_im,dvdz_re,dvdz_im
327  complex(dpc) :: rho_updn
328  real(dp) :: mdirx,mdiry,mdirz,mxy,mx1,my1,mz1,wx,wy,wx1,wy1
329  real(dp) :: theta0,theta1,theta1_re,theta1_im
330  real(dp) :: wx1_re,wx1_im
331  real(dp) :: wy1_re,wy1_im
332  real(dp) :: mx1_re,mx1_im,my1_re,my1_im,mz1_re,mz1_im
333  real(dp) :: m_dot_m1_re,m_dot_m1_im
334  real(dp) :: bxc
335 !arrays
336  real(dp)     :: vxc_diag(2),v21tmp(2)
337  complex(dpc) :: r1tmp(2,2),u0(2,2),u0_1(2,2),u0_1r1(2,2),u0v1(2,2)
338  complex(dpc) :: rho1_updn(2,2),v1tmp(2,2),vxc1tmp(2,2)
339  complex(dpc) :: rho1_offdiag(2)
340 
341 ! *************************************************************************
342 
343 !DBG_ENTER("COLL")
344 
345 !Optional arguments
346  has_mag_norm=present(mag_norm_in)
347  rotation_method=rotation_method_default
348  if (present(rot_method)) rotation_method=rot_method
349 
350 !Check Kxc
351  if (size(kxc)>3*vectsize) then
352      ABI_ERROR('Cannot use Kxc from GGA!')
353  end if
354 
355  if((rotation_method==1.or.rotation_method==2).and.cplex==2) then
356      ABI_ERROR('rotation_method=1 and 2 are not available for cplex=2 case! use ixcrot=3')
357  endif
358 
359 
360  select case (rotation_method)
361 
362 !----------------------------------------
363 ! Taylor expansion of U rotation matrix
364 !----------------------------------------
365  case (1)
366 
367    do ipt=1,vectsize
368 
369      if (has_mag_norm) then
370        m_norm=mag_norm_in(ipt)
371      else
372        m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
373      end if
374 
375      if(m_norm>m_norm_min) then
376 
377 !      Define the U^(0) transformation matrix
378        rho_updn=(mag(ipt,1)+(zero,one)*mag(ipt,2))
379        d1=sqrt(( m_norm+mag(ipt,3))**2+abs(rho_updn)**2)
380        d2=sqrt((-m_norm+mag(ipt,3))**2+abs(rho_updn)**2)
381        d3=sqrt(( m_norm-mag(ipt,3))**2+abs(rho_updn)**2)
382        d4=sqrt(( m_norm+mag(ipt,3))**2-abs(rho_updn)**2)
383        u0(1,1)=( m_norm+mag(ipt,3))/d1  ! ( m  + mz)/d1
384        u0(2,2)=rho_updn/d2              ! ( mx +imy)/d2
385        u0(1,2)=(-m_norm+mag(ipt,3))/d2  ! (-m  + mz)/d2
386        u0(2,1)=rho_updn/d1              ! ( mx +imy)/d1
387 
388 !      Define the inverse of U^(0): U^(0)^-1
389        if (abs(rho_updn) > m_norm_min) then
390          u0_1(1,1)= half*d1/m_norm
391          u0_1(2,2)= half*d2*(m_norm+mag(ipt,3))/(m_norm*rho_updn)
392          u0_1(1,2)= half*d1*(m_norm-mag(ipt,3))/(m_norm*rho_updn)
393          u0_1(2,1)=-half*d2/m_norm
394        else
395          u0 = zero
396          u0(1,1) = one
397          u0(2,2) = one
398          u0_1 = zero
399          u0_1(1,1) = one
400          u0_1(2,2) = one
401        end if
402 
403 !      Diagonalize the GS Vxc^(0): U^(0)^-1 Vxc^(0) U^(0)
404 !        (Remember the abinit notation for vxc!)
405        vxc_diag(1)=half*(vxc(ipt,1)+vxc(ipt,2) &
406 &                 -sqrt((vxc(ipt,1)-vxc(ipt,2))**2 &
407 &                 +four*(vxc(ipt,3)**2+vxc(ipt,4)**2)))
408        vxc_diag(2)=half*(vxc(ipt,1)+vxc(ipt,2) &
409 &                 +sqrt((vxc(ipt,1)-vxc(ipt,2))**2 &
410 &                 +four*(vxc(ipt,3)**2+vxc(ipt,4)**2)))
411        v1tmp(1,1)=cmplx(real(vxc1_in(ipt,1),kind=dp),zero)
412        v1tmp(2,2)=cmplx(real(vxc1_in(ipt,2),kind=dp),zero)
413 
414        !Tranforming the rhor1 with U0
415        rho1_updn(1,1)=half*(rho1(ipt,1)+rho1(ipt,4))
416        rho1_updn(2,2)=half*(rho1(ipt,1)-rho1(ipt,4))
417        rho1_updn(1,2)=half*(rho1(ipt,2)-(zero,one)*rho1(ipt,3))
418        rho1_updn(2,1)=half*(rho1(ipt,2)+(zero,one)*rho1(ipt,3))
419        u0_1r1=matmul(u0_1,rho1_updn)
420        r1tmp=matmul(u0_1r1,u0)
421        rho1_offdiag(1)=r1tmp(1,2) ; rho1_offdiag(2)=r1tmp(2,1)
422 
423        if (option==0) then ! for xccc alone
424          v1tmp(1,2)=cmplx(zero,zero)
425          v1tmp(2,1)=cmplx(zero,zero)
426        else
427          v1tmp(1,2)=-(rho1_offdiag(1)/m_norm)*(vxc_diag(2)-vxc_diag(1))
428          v1tmp(2,1)= (rho1_offdiag(2)/m_norm)*(vxc_diag(1)-vxc_diag(2))
429        endif
430 
431        !Rotate back the "diagonal" xc computing the term U^(0) Vxc1_^(1) U^(0)^-1
432        u0v1=matmul(u0,v1tmp)
433        vxc1tmp=matmul(u0v1,u0_1)
434        vxc1_out(ipt,1)=real(vxc1tmp(1,1),kind=dp)
435        vxc1_out(ipt,2)=real(vxc1tmp(2,2),kind=dp)
436        vxc1_out(ipt,3)=real( real(vxc1tmp(1,2)),kind=dp)
437        vxc1_out(ipt,4)=real(aimag(vxc1tmp(1,2)),kind=dp)
438 
439      else ! Magnetization is zero
440        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half
441        mx1=rho1(ipt,2) ; my1=rho1(ipt,3) ; mz1=rho1(ipt,4)
442 !      Compute Bxc/|m| from Kxc (zero limit)
443        bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
444        vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
445        vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
446        vxc1_out(ipt,3)= bxc_over_m*mx1
447        vxc1_out(ipt,4)=-bxc_over_m*my1
448      end if
449 
450    end do ! ipt
451 
452 !----------------------------------------
453 ! Analytical expression of U rotation matrix
454 !----------------------------------------
455  case (2)
456    !Alternative method (explicitely calculated rotation matrices)
457    !Vxc^(1) =   phixc^(1).Id +                                               // <= change of "electrostatic" XC potential  (phixc^(1) is denoted dvdn)
458    !          + bxc^(1)*( Udag^(0).sigma_z.U^(0) )  +                        // <= this part describes the change of XC magnetic field magnitude bxc^(1)
459    !          + bxc^(0)*( Udag^(1).sigma_z.U^(0) + Udag^(0).sigma_z.U^(1) )  // <= remaining terms describe the cost of magnetization rotation
460 
461    select case(cplex)
462    case(1)
463      do ipt=1,vectsize
464 
465        if (has_mag_norm) then
466          m_norm=mag_norm_in(ipt)
467        else
468          m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
469        end if
470 
471 
472        mx1 =rho1(ipt,2);
473        my1 =rho1(ipt,3);
474        mz1 =rho1(ipt,4)
475 
476        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half  !phixc^(1)
477        dvdz=(vxc1_in(ipt,1)-vxc1_in(ipt,2))*half  !bxc^(1)
478 
479        if (m_norm>m_norm_min) then
480 
481          mxy = dsqrt(mag(ipt,1)**2+mag(ipt,2)**2)
482          small_angle=(mxy/m_norm<tol8)            !condition for sin(x)~x to be valid
483                                                   !even possible to set to tol6
484          mdirx=mag(ipt,1)/m_norm
485          mdiry=mag(ipt,2)/m_norm
486          mdirz=mag(ipt,3)/m_norm
487 
488 !        dvdn is phixc^(1) (density only part)
489 !        dvdz is bxc^(1)   (magnetization magnitude part)
490 
491          !U^(0)*.Vxc1.U^(0) part
492          vxc1_out(ipt,1)= dvdn+dvdz*mdirz
493          vxc1_out(ipt,2)= dvdn-dvdz*mdirz
494          vxc1_out(ipt,3)= dvdz*mdirx   ! Real part
495          vxc1_out(ipt,4)=-dvdz*mdiry   ! Imaginary part, minus sign comes from sigma_y
496 
497          !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1) part
498 
499          !bxc = dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !bxc^(0)
500          bxc = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)*m_norm
501          if (.not.small_angle) then
502            wx     = mag(ipt,2)/mxy
503            wy     =-mag(ipt,1)/mxy
504            theta0 = dacos(mag(ipt,3)/m_norm)
505 
506            theta1 = (mdirz*(mdirx*mx1+mdiry*my1))/mxy - mz1*mxy/m_norm**2
507            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
508            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
509 
510            vxc1_out(ipt,1) = vxc1_out(ipt,1) - bxc*dsin(theta0)*theta1
511            vxc1_out(ipt,2) = vxc1_out(ipt,2) + bxc*dsin(theta0)*theta1
512            vxc1_out(ipt,3) = vxc1_out(ipt,3) - bxc*(wy1+dcos(theta0)*wy*theta1)
513            vxc1_out(ipt,4) = vxc1_out(ipt,4) - bxc*(wx1+dcos(theta0)*wx*theta1)
514          else
515            !zero order terms O(1)
516            vxc1_out(ipt,3) = vxc1_out(ipt,3) + bxc*mx1/abs(mag(ipt,3))
517            vxc1_out(ipt,4) = vxc1_out(ipt,4) - bxc*my1/abs(mag(ipt,3))
518            !first order terms O(theta)
519            fact = bxc/(mag(ipt,3)*abs(mag(ipt,3)))
520            vxc1_out(ipt,1) = vxc1_out(ipt,1) - (mag(ipt,1)*mx1+mag(ipt,2)*my1)*fact
521            vxc1_out(ipt,2) = vxc1_out(ipt,2) + (mag(ipt,1)*mx1+mag(ipt,2)*my1)*fact
522            vxc1_out(ipt,3) = vxc1_out(ipt,3) -  mag(ipt,1)*mz1*fact
523            vxc1_out(ipt,4) = vxc1_out(ipt,4) +  mag(ipt,2)*mz1*fact
524          endif
525 
526        else ! Magnetization is zero
527 !        Compute Bxc/|m| from Kxc (zero limit)
528          bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
529          vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
530          vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
531          vxc1_out(ipt,3)= bxc_over_m*mx1
532          vxc1_out(ipt,4)=-bxc_over_m*my1
533        end if
534      end do ! ipt
535 
536    case(2) !cplex=2
537 
538      do ipt=1,vectsize
539 
540        if (has_mag_norm) then
541          m_norm=mag_norm_in(ipt)
542        else
543          m_norm=dsqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
544        end if
545 
546        mx1_re= rho1(2*ipt-1,2); mx1_im= rho1(2*ipt,2)
547        my1_re= rho1(2*ipt-1,3); my1_im= rho1(2*ipt,3)
548        mz1_re= rho1(2*ipt-1,4); mz1_im= rho1(2*ipt,4)
549 
550        dvdn_re=(vxc1_in(2*ipt-1,1)+vxc1_in(2*ipt-1,2))*half
551        dvdz_re=(vxc1_in(2*ipt-1,1)-vxc1_in(2*ipt-1,2))*half
552        dvdn_im=(vxc1_in(2*ipt  ,1)+vxc1_in(2*ipt  ,2))*half
553        dvdz_im=(vxc1_in(2*ipt  ,1)-vxc1_in(2*ipt  ,2))*half
554 
555        if (m_norm>m_norm_min) then
556 
557          mdirx=mag(ipt,1)/m_norm
558          mdiry=mag(ipt,2)/m_norm
559          mdirz=mag(ipt,3)/m_norm
560 
561          mxy = dsqrt(mag(ipt,1)**2+mag(ipt,2)**2)
562          small_angle=(mxy/m_norm<tol8)            !condition for sin(x)~x to be valid
563                                                   !
564          mdirx=mag(ipt,1)/m_norm
565          mdiry=mag(ipt,2)/m_norm
566          mdirz=mag(ipt,3)/m_norm
567 
568 !        dvdn is phixc^(1) (density only part)
569 !        dvdz is bxc^(1)   (magnetization magnitude part)
570 
571          !U^(0)*.Vxc1.U^(0) part
572          vxc1_out(2*ipt-1,1)= dvdn_re+dvdz_re*mdirz
573          vxc1_out(2*ipt  ,1)= dvdn_im+dvdz_im*mdirz
574          vxc1_out(2*ipt-1,2)= dvdn_re-dvdz_re*mdirz
575          vxc1_out(2*ipt  ,2)= dvdn_im-dvdz_im*mdirz
576          !NOTE: change of definition of the potential matrix components
577          !      vxc1_out(:,3) =   V_updn
578          !      vxc1_out(:,4) = i.V_updn
579          vxc1_out(2*ipt-1,3)= dvdz_re*mdirx + dvdz_im*mdiry   !Re[  V^12]
580          vxc1_out(2*ipt  ,3)= dvdz_im*mdirx - dvdz_re*mdiry   !Im[  V^12]
581 
582          !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1) part
583          !bxc = dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !bxc^(0)
584          bxc = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)*m_norm
585          if (.not.small_angle) then
586            wx     = mag(ipt,2)/mxy
587            wy     =-mag(ipt,1)/mxy
588            theta0 = dacos(mag(ipt,3)/m_norm)
589 
590 
591            theta1_re = (mdirz*(mdirx*mx1_re+mdiry*my1_re))/mxy - mz1_re*mxy/m_norm**2
592            theta1_im = (mdirz*(mdirx*mx1_im+mdiry*my1_im))/mxy - mz1_im*mxy/m_norm**2
593 
594            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
595            wx1_im = (+mag(ipt,1)**2*my1_im - mag(ipt,1)*mag(ipt,2)*mx1_im)/mxy**2/m_norm
596            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
597            wy1_im = (-mag(ipt,2)**2*mx1_im + mag(ipt,1)*mag(ipt,2)*my1_im)/mxy**2/m_norm
598 
599            !U^(1)*.Vxc0.U^(0) + U^(0)*.Vxc0.U^(1)
600            vxc1_out(2*ipt-1,1) = vxc1_out(2*ipt-1,1) - bxc*dsin(theta0)*theta1_re
601            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) - bxc*dsin(theta0)*theta1_im
602            vxc1_out(2*ipt-1,2) = vxc1_out(2*ipt-1,2) + bxc*dsin(theta0)*theta1_re
603            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + bxc*dsin(theta0)*theta1_im
604            !cplex=1 part:
605            !v12 +=   -(bxc)*(wy1+dcos(theta0)*wy*theta1)-
606            !       -i.(bxc)*(wx1+dcos(theta0)*wx*theta1)
607            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) - bxc*(wy1_re+dcos(theta0)*wy*theta1_re)
608            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*(wx1_im+dcos(theta0)*wx*theta1_im)
609            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*(wy1_im+dcos(theta0)*wy*theta1_im)
610            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*(wx1_re+dcos(theta0)*wx*theta1_re)
611          else
612            !small theta case:
613            !zero order terms O(1)
614            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*mx1_re/abs(mag(ipt,3))
615            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) + bxc*my1_im/abs(mag(ipt,3))
616            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc*mx1_im/abs(mag(ipt,3))
617            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) - bxc*my1_re/abs(mag(ipt,3))
618            !first order terms:
619            fact = bxc/(mag(ipt,3)*abs(mag(ipt,3)))
620            vxc1_out(2*ipt-1,1) = vxc1_out(2*ipt-1,1) - (mag(ipt,1)*mx1_re+mag(ipt,2)*my1_re)*fact
621            vxc1_out(2*ipt-1,2) = vxc1_out(2*ipt-1,2) + (mag(ipt,1)*mx1_re+mag(ipt,2)*my1_re)*fact
622            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) - (mag(ipt,1)*mx1_im+mag(ipt,2)*my1_im)*fact
623            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + (mag(ipt,1)*mx1_im+mag(ipt,2)*my1_im)*fact
624 
625            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) -  mag(ipt,1)*mz1_re*fact
626            vxc1_out(2*ipt-1,3) = vxc1_out(2*ipt-1,3) -  mag(ipt,2)*mz1_im*fact
627            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) +  mag(ipt,2)*mz1_re*fact
628            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) -  mag(ipt,1)*mz1_im*fact
629          endif
630 
631        else ! Magnetization is practically zero
632 !        Compute Bxc/|m| from Kxc (zero limit)
633          bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
634          vxc1_out(2*ipt-1,1)= dvdn_re + bxc_over_m*mz1_re
635          vxc1_out(2*ipt  ,1)= dvdn_im + bxc_over_m*mz1_im
636          vxc1_out(2*ipt-1,2)= dvdn_re - bxc_over_m*mz1_re
637          vxc1_out(2*ipt  ,2)= dvdn_im - bxc_over_m*mz1_im
638          vxc1_out(2*ipt-1,3)= bxc_over_m*( mx1_re+my1_im)
639          vxc1_out(2*ipt  ,3)= bxc_over_m*(-my1_re+mx1_im)
640        end if
641        !finally reconstruct i.V^12 from V^12
642        vxc1_out(2*ipt-1,4) =  vxc1_out(2*ipt  ,3)  ! Re[i.V^21] = Im[V^12]
643        vxc1_out(2*ipt  ,4) =  vxc1_out(2*ipt-1,3)  ! Im[i.V^21] = Re[V^12]
644 
645      end do ! ipt
646 
647    end select
648 
649 !----------------------------------------
650 ! Explicit derivative of the rotated XC functional
651 !----------------------------------------
652  case (3)
653    ! Brute-force derivative of Vxc
654    ! Explicit calculation of the rotated xc functional
655    ! (derivatives of the analytical expression) (Eq. A)
656    ! Vxc^(1) =   phixc^(1).Id +                    // <= change of "electrostatic" XC potential  (phixc^(1) is denoted dvdn)
657    !           + bxc^(1)*(sigma,m^(0))/|m^(0)|  +  // <= this term is equivalent to ( Udag^(0).sigma_z.U^(0) ) term in rotation_method=2
658    !           + 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) )
659    !           - bxc^(0)*(sigma,m^(0))*(m^(1),m^(0))/|m^(0)|**3
660    select case(cplex)
661    case(1)
662 
663      do ipt=1,vectsize
664 
665        if (has_mag_norm) then
666          m_norm=mag_norm_in(ipt)
667        else
668          m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
669        end if
670 
671 !      dvdn is phixc^(1) (density only part)
672 !      dvdz is bxc^(1)   (magnetization magnitude part)
673        dvdn=(vxc1_in(ipt,1)+vxc1_in(ipt,2))*half
674        dvdz=(vxc1_in(ipt,1)-vxc1_in(ipt,2))*half
675 
676        mx1=rho1(ipt,2) ; my1=rho1(ipt,3) ; mz1=rho1(ipt,4)
677 
678        if(m_norm>m_norm_min) then
679 
680          mdirx=mag(ipt,1)/m_norm; mdiry=mag(ipt,2)/m_norm; mdirz=mag(ipt,3)/m_norm
681 
682          !This part describes the change of the magnitude of the xc magnetic field
683          !and the change of the scalar part of the xc electrostatic potential, 1st + 2nd term in Eq.A
684          !phixc^(1).Id + bxc^(1) (sigma,m^(0))/|m^(0)|
685          vxc1_out(ipt,1)= dvdn+dvdz*mdirz
686          vxc1_out(ipt,2)= dvdn-dvdz*mdirz
687          vxc1_out(ipt,3)= dvdz*mdirx   ! Real part
688          vxc1_out(ipt,4)=-dvdz*mdiry   ! Imaginary part, minus sign comes from sigma_y
689 
690          if (option/=0) then
691            !Add remaining contributions comming from the change of magnetization direction
692            !projection of m^(1) on gs magnetization direction
693            m_dot_m1=(mdirx*rho1(ipt,2)+mdiry*rho1(ipt,3)+mdirz*rho1(ipt,4))
694 
695            bxc_over_m =-dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !this is bxc^(0)
696            bxc_over_m = bxc_over_m/m_norm
697            vxc1_out(ipt,1) = vxc1_out(ipt,1) + bxc_over_m*( mz1 - mdirz*m_dot_m1 ) !
698            vxc1_out(ipt,2) = vxc1_out(ipt,2) + bxc_over_m*(-mz1 + mdirz*m_dot_m1 ) !
699            vxc1_out(ipt,3) = vxc1_out(ipt,3) + bxc_over_m*( mx1 - mdirx*m_dot_m1 ) !
700            vxc1_out(ipt,4) = vxc1_out(ipt,4) + bxc_over_m*(-my1 + mdiry*m_dot_m1 ) !
701          endif
702 
703        else
704          if (option/=0) then
705            !Compute bxc^(0)/|m| from kxc (|m^(0)| -> zero limit)
706            bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
707            vxc1_out(ipt,1)= dvdn + bxc_over_m*mz1
708            vxc1_out(ipt,2)= dvdn - bxc_over_m*mz1
709            vxc1_out(ipt,3)= bxc_over_m*mx1
710            vxc1_out(ipt,4)=-bxc_over_m*my1
711          else
712            vxc1_out(ipt,1)= dvdn
713            vxc1_out(ipt,2)= dvdn
714            vxc1_out(ipt,3)= zero
715            vxc1_out(ipt,4)= zero
716          endif
717        end if
718 
719      end do ! ipt
720 
721    case(2)
722      !cplex=2 case
723 
724      do ipt=1,vectsize
725 
726        if (has_mag_norm) then
727          m_norm=mag_norm_in(ipt)
728        else
729          m_norm=sqrt(mag(ipt,1)**2+mag(ipt,2)**2+mag(ipt,3)**2)
730        end if
731 
732 !      see cplex=1 case for details
733        dvdn_re=(vxc1_in(2*ipt-1,1)+vxc1_in(2*ipt-1,2))*half
734        dvdn_im=(vxc1_in(2*ipt  ,1)+vxc1_in(2*ipt  ,2))*half
735        dvdz_re=(vxc1_in(2*ipt-1,1)-vxc1_in(2*ipt-1,2))*half
736        dvdz_im=(vxc1_in(2*ipt  ,1)-vxc1_in(2*ipt  ,2))*half
737 
738        mx1_re=rho1(2*ipt-1,2); mx1_im=rho1(2*ipt,2)
739        my1_re=rho1(2*ipt-1,3); my1_im=rho1(2*ipt,3)
740        mz1_re=rho1(2*ipt-1,4); mz1_im=rho1(2*ipt,4)
741 
742        if(m_norm>m_norm_min) then
743 
744          mdirx=mag(ipt,1)/m_norm; mdiry=mag(ipt,2)/m_norm; mdirz=mag(ipt,3)/m_norm
745 
746          !first two terms:
747          vxc1_out(2*ipt-1,1)= dvdn_re+dvdz_re*mdirz
748          vxc1_out(2*ipt  ,1)= dvdn_im+dvdz_im*mdirz
749          vxc1_out(2*ipt-1,2)= dvdn_re-dvdz_re*mdirz
750          vxc1_out(2*ipt  ,2)= dvdn_im-dvdz_im*mdirz
751          !NOTE: change of definition of the potential matrix components
752          !      vxc1_out(:,3) =   V_updn
753          !      vxc1_out(:,4) = i.V_dnup
754 
755          !  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)
756          !  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|)
757          vxc1_out(2*ipt-1,3)= dvdz_re*mdirx + dvdz_im*mdiry   !Re[V^12]
758          vxc1_out(2*ipt  ,3)= dvdz_im*mdirx - dvdz_re*mdiry   !Im[V^12]
759          vxc1_out(2*ipt-1,4)= dvdz_re*mdirx - dvdz_im*mdiry   !Re[V^21]
760          vxc1_out(2*ipt  ,4)= dvdz_im*mdirx + dvdz_re*mdiry   !Im[V^21]
761          if (option/=0) then
762 
763            !remaining contributions:
764            m_dot_m1_re= mdirx*mx1_re + mdiry*my1_re + mdirz*mz1_re
765            m_dot_m1_im= mdirx*mx1_im + mdiry*my1_im + mdirz*mz1_im
766 
767            bxc_over_m =-dsqrt(((vxc(ipt,1)-vxc(ipt,2))*half)**2+vxc(ipt,3)**2+vxc(ipt,4)**2) !this is bxc^(0)
768            bxc_over_m = bxc_over_m/m_norm
769           !bxc_over_m = (vxc(ipt,1)-vxc(ipt,2))*half/mag(ipt,3)
770 
771            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]
772            vxc1_out(2*ipt  ,1) = vxc1_out(2*ipt  ,1) + bxc_over_m*( mz1_im - mdirz*m_dot_m1_im ) ! Im[V^11]
773            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]
774            vxc1_out(2*ipt  ,2) = vxc1_out(2*ipt  ,2) + bxc_over_m*(-mz1_im + mdirz*m_dot_m1_im ) ! Im[V^22]
775 
776            !    v12  += bxc_over_m*(   (mx1    - mdirx*m_dot_m1   ) - i.( my1    - mdiry*m_dot_m1   )   )  <= see cplex=1
777            ! Re[v12] += bxc_over_m*(   (mx1_re - mdirx*m_dot_m1_re) +   ( my1_im - mdiry*m_dot_m1_im)   )
778            ! Im[v12] += bxc_over_m*(   (mx1_im - mdirx*m_dot_m1_im) +   (-my1_re + mdiry*m_dot_m1_re)   )
779            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]
780            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]
781            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc_over_m*( mx1_im - mdirx*m_dot_m1_im ) ! Im[V^12]
782            vxc1_out(2*ipt  ,3) = vxc1_out(2*ipt  ,3) + bxc_over_m*(-my1_re + mdiry*m_dot_m1_re ) ! Im[V^12]
783 
784            !    v21  += bxc_over_m*(   (mx1    - mdirx*m_dot_m1   ) + i.( my1    - mdiry*m_dot_m1   )   )
785            ! Re[v21] += bxc_over_m*(   (mx1_re - mdirx*m_dot_m1_re) +   (-my1_im + mdiry*m_dot_m1_im)   )
786            ! Im[v21] += bxc_over_m*(   (mx1_im - mdirx*m_dot_m1_im) +   ( my1_re - mdiry*m_dot_m1_re)   )
787            ! the 4th component is actually not v21, but rather i.v21, this will be adjusted later
788            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]
789            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]
790            vxc1_out(2*ipt  ,4) = vxc1_out(2*ipt  ,4) + bxc_over_m*( mx1_im - mdirx*m_dot_m1_im ) ! Im[V^21]
791            vxc1_out(2*ipt  ,4) = vxc1_out(2*ipt  ,4) + bxc_over_m*( my1_re - mdiry*m_dot_m1_re ) ! Im[V^21]
792          endif
793        else
794          if(option/=0) then
795            !Compute Bxc/|m| from Kxc (|m^(0)| -> zero limit)
796            bxc_over_m = half*(half*(kxc(ipt,1)+kxc(ipt,3))-kxc(ipt,2))
797            vxc1_out(2*ipt-1,1)= dvdn_re + bxc_over_m*mz1_re
798            vxc1_out(2*ipt-1,2)= dvdn_re - bxc_over_m*mz1_re
799            vxc1_out(2*ipt  ,1)= dvdn_im + bxc_over_m*mz1_im
800            vxc1_out(2*ipt  ,2)= dvdn_im - bxc_over_m*mz1_im
801 
802            vxc1_out(2*ipt-1,3)= bxc_over_m*(mx1_re+my1_im)
803            vxc1_out(2*ipt  ,3)= bxc_over_m*(mx1_im-my1_re)
804            vxc1_out(2*ipt-1,4)= bxc_over_m*(mx1_re-my1_im)
805            vxc1_out(2*ipt  ,4)= bxc_over_m*(mx1_im+my1_re)
806          else
807            vxc1_out(2*ipt-1,1)= dvdn_re
808            vxc1_out(2*ipt-1,2)= dvdn_re
809            vxc1_out(2*ipt  ,1)= dvdn_im
810            vxc1_out(2*ipt  ,2)= dvdn_im
811 
812            vxc1_out(2*ipt-1,3)= zero
813            vxc1_out(2*ipt  ,3)= zero
814            vxc1_out(2*ipt-1,4)= zero
815            vxc1_out(2*ipt  ,4)= zero
816          endif
817        end if
818 
819        !finally reconstruct i.V^21 from V^21
820        v21tmp(1) = vxc1_out(2*ipt-1,4) !Re[V^21]
821        v21tmp(2) = vxc1_out(2*ipt  ,4) !Im[V^21]
822 
823        vxc1_out(2*ipt-1,4) =-v21tmp(2) ! Re[i.V^21]=-Im[V^21]
824        vxc1_out(2*ipt  ,4) = v21tmp(1) ! Im[i.V^21]= Re[V^21]
825 
826      end do ! ipt
827 
828    end select !cplex
829 
830  end select ! rotation_method
831 
832 !DBG_EXIT("COLL")
833 
834 end subroutine rotate_back_mag_dfpt

m_xc_noncoll/rotate_mag [ Types ]

[ Top ] [ m_xc_noncoll ] [ Types ]

NAME

  rotate_mag

FUNCTION

  Project (rotate) a non-collinear density (stored as density+magn.)
  on a magnetization and give a collinear density (stored as [up,dn] or [up+dn,up]).
  Align both z-axis.

INPUTS

  rho_in(vectsize,4)=input non-collinear density and magnetization (1st or 0th order)
  mag(vectsize,3)=gs magnetization used for projection (0th order magnetization)
  vectsize=size of vector fields
  [mag_norm_in(vectsize)]= --optional-- norm of mag(:) at each point of the grid
  [rho_out_format]= 1=rho_out is stored as [up,dn]
                    2=rho_out is stored as [up+dn,up]
                    Default=1
  rho_out(vectsize,2)=output (projected, collinear) (1st order if rho_in is 1st order NC density matrix)
  [mag_norm_out(vectsize)]= --optional-- norm of mag(:) at each point of the grid

     Explicit formulae:
     rho_out_format=1
       rho_out(1) = half*( rho_in(1) + (mag,rho_in(2:4))/|mag|) // where (*,*) is scalar product
       rho_out(2) = half*( rho_in(1) - (mag,rho_in(2:4))/|mag|)

     rho_out_format=2
       rho_out(1) = rho_in(1)
       rho_out(2) = half*( rho_in(1) + (mag,rho_in(2:4))/|mag|)

SOURCE

 88 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  has_mag_norm=present(mag_norm_in)
115  out_mag_norm=present(mag_norm_out)
116 
117  if(cplex==1) then
118    do ipt=1,vectsize
119      if (has_mag_norm) then
120        m_norm=mag_norm_in(ipt)
121      else
122        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 &                 +rho_in(ipt,4)*mag(ipt,3)
127 
128      if(m_norm>m_norm_min)then
129        mm=rhoin_dot_mag/m_norm
130        rho_out(ipt,1)=half*(rho_in(ipt,1)+mm)
131        rho_out(ipt,2)=half*(rho_in(ipt,1)-mm)
132      else
133        rho_out(ipt,1)=half*rho_in(ipt,1)
134        rho_out(ipt,2)=half*rho_in(ipt,1)
135      end if
136 
137      if (out_mag_norm) then
138        if (m_norm >m_norm_min) mag_norm_out(ipt)=m_norm
139        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    do ipt=1,vectsize
147      if (has_mag_norm) then
148        m_norm=mag_norm_in(ipt)
149      else
150        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 &                    +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 &                    +rho_in(2*ipt  ,4)*mag(ipt,3)
159      if(m_norm>m_norm_min)then
160        mm=rhoin_dot_mag_re/m_norm
161        rho_out(2*ipt-1,1)=half*(rho_in(2*ipt-1,1)+mm)
162        rho_out(2*ipt-1,2)=half*(rho_in(2*ipt-1,1)-mm)
163        mm=rhoin_dot_mag_im/m_norm
164        rho_out(2*ipt  ,1)=half*(rho_in(2*ipt ,1)+mm)
165        rho_out(2*ipt  ,2)=half*(rho_in(2*ipt ,1)-mm)
166      else
167        rho_out(2*ipt-1,1)=half*rho_in(2*ipt-1,1)
168        rho_out(2*ipt-1,2)=half*rho_in(2*ipt-1,2)
169        rho_out(2*ipt  ,1)=half*rho_in(2*ipt  ,1)
170        rho_out(2*ipt  ,2)=half*rho_in(2*ipt  ,2)
171      end if
172 
173      if (out_mag_norm) then
174        if (m_norm >m_norm_min) mag_norm_out(ipt)=m_norm
175        if (m_norm<=m_norm_min) mag_norm_out(ipt)=zero
176      end if
177 
178    end do
179 
180  end if
181 
182  if (present(rho_out_format)) then
183    if (rho_out_format==2) then
184      do ipt=1,cplex*vectsize
185        rho_up=rho_out(ipt,1)
186        rho_out(ipt,1)=rho_up+rho_out(ipt,2)
187        rho_out(ipt,2)=rho_up
188      end do
189    end if
190  end if
191 
192 !DBG_EXIT("COLL")
193 
194 end subroutine rotate_mag