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 : !!***
|