Line data Source code
1 : !{\src2tex{textfont=tt}}
2 : !!****m* ABINIT/m_ddb_magpen
3 : !! NAME
4 : !! m_ddb_magpen
5 : !!
6 : !! FUNCTION
7 : !! Convert second- and -third (Berry curvatures) order total energy derivatives
8 : !! calculated with the magnetic penalty (constrained-B functional) into the
9 : !! corresponding quantities of different magnetic functionals:
10 : !! --constrained-M (fixed-spin)
11 : !! --constrained-H (relaxed spin)
12 : !! Calculate and write the ensuing clamped-ion susceptibilities. Lattice-mediated
13 : !! contributions are incorporated in m_ddb_omega_interpol.
14 : !!
15 : !! COPYRIGHT
16 : !! Copyright (C) 2023 ABINIT group (MR and MS)
17 : !! This file is distributed under the terms of the
18 : !! GNU General Public License, see ~abinit/COPYING
19 : !! or http://www.gnu.org/copyleft/gpl.txt .
20 : !!
21 : !! NOTES
22 : !!
23 : !! PARENTS
24 : !!
25 : !! CHILDREN
26 : !!
27 : !! SOURCE
28 :
29 : #if defined HAVE_CONFIG_H
30 : #include "config.h"
31 : #endif
32 :
33 : #include "abi_common.h"
34 :
35 : module m_ddb_magpen
36 :
37 : use defs_basis
38 : use m_abicore
39 : use m_profiling_abi
40 : use m_errors
41 : use m_ddb
42 : use m_fstrings, only : itoa, sjoin
43 : use m_macroave, only : POLINT
44 : use m_io_tools, only : open_file
45 : use m_cgtools, only : fxphas_seq
46 : use m_dynmat, only : pheigvec_normalize
47 : use m_numeric_tools, only : polcoe
48 :
49 : implicit none
50 :
51 : public :: ddb_magpen ! Convert the derivatives calculated with the magnetic penalty into the physically relevant ones.
52 : public :: local_spinsus ! Treat local spin susceptibility (2nd-order magnetic derivatives)
53 : public :: magmom ! Treat first-order magnetic moments (2nd-order mixed derivatives)
54 : public :: mp_d2etot ! Treat 2nd-order nonmagnetic derivatives
55 : public :: asrw0 ! Apply the ASR correction calculated at w=0 at any value of w
56 :
57 : private
58 :
59 : ! *************************************************************************
60 :
61 : contains
62 : !!***
63 :
64 : !!****f* m_ddb_magpen/ddb_magpen
65 : !! NAME
66 : !! ddb_magpen
67 : !!
68 : !! FUNCTION
69 : !! Convert the second- and possibly third-order derivatives calculated with the magnetic penalty
70 : !! into physically relevant quantities.
71 : !!
72 : !! INPUTS
73 : !! ddb (INOUT) = ddb block datastructure
74 : !! ddb_lw (INOUT) = ddb_lw block datastructure
75 : !! magpen = amplitude (in Ha) of the applied magnetic penalty
76 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
77 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
78 : !! mpert = maximum number of ipert
79 : !! mpopt = 1 calculate the frozen-magnetic second-order quantities
80 : !! 2 calculate the spin-relaxed second-order quantities
81 : !! natom= number of atoms in unit cell
82 : !! ntypat= number of atom types
83 : !! timdisp= 1 calculate the third-order Berry curvatures
84 : !! ucvol= unit cell volume
85 : !!
86 : !! OUTPUT
87 : !! ddb= ddb%val updated with the corrected second-order derivatives
88 : !!
89 : !! SOURCE
90 :
91 3 : subroutine ddb_magpen(ddb,ddb_lw,&
92 : & magpen,mpatpol,mpdir,mpert,mpopt,natom, &
93 3 : & prtvol,rftyp,ucvol,timdisp,xred)
94 :
95 : !Arguments -------------------------------
96 : !scalars
97 : integer,intent(in) :: mpert,mpopt,natom,prtvol,rftyp,timdisp
98 : real(dp),intent(in) :: magpen,ucvol
99 : !arrays
100 : type(ddb_type),intent(inout) :: ddb,ddb_lw
101 : integer,intent(in) :: mpatpol(2),mpdir(3)
102 : real(dp),intent(in) :: xred(3,natom)
103 :
104 : !Local variables -------------------------
105 : !scalars
106 : integer :: iblok,ii,jblok,kblok,lblok,nblok,ndim
107 : integer :: nmat,nmdir,optgb,prtopt
108 : character(len=500) :: msg
109 : logical :: qeq0
110 : !arrays
111 : integer :: rfelfd(4),rfphon(4),rfstrs(4),rfmagn(4),rffreq(4)
112 : real(dp) :: omega(3),qphnrm(3),qphon(3,3),qpt(3)
113 3 : complex(dpc), allocatable :: barmagsus(:,:),invbarmagsus(:,:)
114 3 : complex(dpc), allocatable :: invmagsus(:,:), magsus(:,:), invhmat(:,:)
115 3 : complex(dpc), allocatable :: barmmom(:,:),barmmom_tr(:,:),mmom(:,:),mmom_tr(:,:)
116 3 : complex(dpc), allocatable :: zfield(:,:), zfield_tr(:,:)
117 3 : complex(dpc), allocatable :: bc_barmagsus(:,:),bc_ss(:,:),bc_sp(:,:)
118 3 : complex(dpc), allocatable :: ifcmat(:,:),ifcmat_fm(:,:),zeff(:,:),zeff_tr(:,:)
119 3 : complex(dpc), allocatable :: fmzeff(:,:),fmzeff_tr(:,:)
120 3 : complex(dpc), allocatable :: lm_epsilon(:,:),dum_phongreen(:,:)
121 :
122 : ! *********************************************************************
123 246 : write(msg, '(2a,(80a),6a)' ) ch10,('=',ii=1,80),ch10,ch10,&
124 3 : ' Constrained DFPT section ',ch10,ch10,&
125 249 : ' (Quantities are in atomic units and along Cartesian directions)'
126 9 : call wrtout([std_out, ab_out], msg)
127 :
128 3 : prtopt=1
129 3 : if (magpen<zero) then
130 : nmat= 1
131 3 : else if (magpen>zero) then
132 3 : nmat= mpatpol(2) - mpatpol(1) + 1
133 : end if
134 12 : nmdir=sum(mpdir(:))
135 3 : ndim=nmat*nmdir
136 3 : optgb=1
137 12 : ABI_MALLOC(barmagsus,(ndim,ndim))
138 9 : ABI_MALLOC(magsus,(ndim,ndim))
139 9 : ABI_MALLOC(invbarmagsus,(ndim,ndim))
140 9 : ABI_MALLOC(invmagsus,(ndim,ndim))
141 9 : ABI_MALLOC(invhmat,(ndim,ndim))
142 12 : ABI_MALLOC(barmmom,(ndim,(natom+5)*3))
143 9 : ABI_MALLOC(barmmom_tr,((natom+5)*3,ndim))
144 9 : ABI_MALLOC(mmom,(ndim,(natom+5)*3))
145 9 : ABI_MALLOC(mmom_tr,((natom+5)*3,ndim))
146 9 : ABI_MALLOC(zfield,(ndim,(natom+5)*3))
147 9 : ABI_MALLOC(zfield_tr,((natom+5)*3,ndim))
148 :
149 12 : ABI_MALLOC(ddb%val_fs,(2,ddb%msize,ddb%nblok))
150 : ! if (mpopt==2) ABI_MALLOC(ddb%val_rs,(2,ddb%msize,ddb%nblok))
151 9 : ABI_MALLOC(ddb%val_rs,(2,ddb%msize,ddb%nblok))
152 :
153 15 : ABI_MALLOC(ifcmat,(3*natom,3*natom))
154 9 : ABI_MALLOC(ifcmat_fm,(3*natom,3*natom))
155 9 : ABI_MALLOC(fmzeff,(3,3*natom))
156 9 : ABI_MALLOC(fmzeff_tr,(3*natom,3))
157 6 : ABI_MALLOC(zeff,(3,3*natom))
158 6 : ABI_MALLOC(zeff_tr,(3*natom,3))
159 3 : ABI_MALLOC(lm_epsilon,(3,3))
160 9 : ABI_MALLOC(dum_phongreen,(3*natom,3*natom))
161 :
162 3 : nblok=ddb%nblok
163 7 : do kblok=1,nblok
164 :
165 : ! Look for the local spin-susceptibility block in the DDB
166 4 : omega=zero
167 4 : qphon=zero
168 16 : qphon(:,1)=ddb%qpt(1:3,kblok)
169 16 : qpt=qphon(:,1)
170 16 : qeq0=(sqrt(sum(qphon(:,1)**2))<tol8)
171 16 : qphnrm(:)=ddb%nrm(1,kblok)
172 4 : omega(1)=ddb%omega(1,kblok)
173 12 : rfphon(1:2)=0
174 12 : rfelfd(1:2)=0
175 12 : rfstrs(1:2)=0
176 4 : if (magpen<zero) then
177 0 : rfmagn(1:2)= 1
178 4 : else if (magpen>zero) then
179 12 : rfmagn(1:2)= 2
180 : end if
181 :
182 328 : write(msg, '(1a,(80a),2a,3f16.8,2a,f16.8,a)' ) ch10,('-',ii=1,80),ch10, &
183 4 : ' q point ', qphon(:,1),ch10,&
184 332 : ' frequency', ddb%omega(1,kblok), ch10
185 12 : call wrtout([std_out, ab_out], msg)
186 :
187 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, &
188 4 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn)
189 :
190 : ! Calculate and write the spin-susceptibility matrices
191 4 : if (iblok /= 0) then
192 4 : if (prtvol>1) then
193 4 : if (magpen<zero) then
194 0 : write(msg, '(2a)' ) ' Spin susceptibility (Uniform Zeeman) ',ch10
195 0 : call wrtout([std_out, ab_out], msg)
196 4 : else if (magpen>zero) then
197 4 : write(msg, '(2a)' ) ' Spin susceptibility (Local Zeeman) ',ch10
198 12 : call wrtout([std_out, ab_out], msg)
199 : end if
200 : end if
201 :
202 : call local_spinsus(barmagsus,ddb,iblok,invbarmagsus,invmagsus,invhmat,magpen,magsus,&
203 4 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtopt,prtvol,qpt,xred)
204 :
205 : end if
206 :
207 : ! Calculate and write the induced magnetic moments
208 4 : if (prtvol>1) then
209 328 : write(msg, '(2a,(80a),4a)' ) ch10,('-',ii=1,80),ch10,ch10,&
210 332 : ' First-order magnetic moments ',ch10
211 12 : call wrtout([std_out, ab_out], msg)
212 : end if
213 :
214 : ! First atomic-displacement
215 4 : rfphon(2)=1
216 12 : rfelfd(1:2)=0
217 12 : rfstrs(1:2)=0
218 4 : rfmagn(:)=0
219 4 : if (magpen<zero) then
220 0 : rfmagn(1)= 1
221 4 : else if (magpen>zero) then
222 4 : rfmagn(1)= 2
223 : end if
224 :
225 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, &
226 4 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn)
227 :
228 : ! Then electric field
229 : ! Look for the induced magnetic moments block in the DDB
230 4 : jblok=0
231 4 : if (qeq0) then
232 3 : rfphon(2)=0
233 3 : rfelfd(2)=2
234 9 : rfstrs(1:2)=0
235 3 : rfmagn(:)=0
236 3 : if (magpen<zero) then
237 0 : rfmagn(1)= 1
238 3 : else if (magpen>zero) then
239 3 : rfmagn(1)= 2
240 : end if
241 :
242 : call ddb%get_block(jblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, &
243 3 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn)
244 : end if
245 :
246 : ! Then macroscopic Zeeman field
247 : ! Look for the induced magnetic moments block in the DDB
248 : lblok=0
249 4 : rfphon(:)=0
250 4 : rfelfd(:)=0
251 12 : rfstrs(1:2)=0
252 4 : rfmagn(2)=1
253 4 : if (magpen<zero) then
254 0 : rfmagn(1)= 1
255 4 : else if (magpen>zero) then
256 4 : rfmagn(1)= 2
257 : end if
258 :
259 : call ddb%get_block(lblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, &
260 4 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn)
261 :
262 4 : if (iblok /= 0 .or. jblok /=0 .or. lblok/=0) then
263 : call magmom(barmmom,barmmom_tr,ddb,invbarmagsus,invhmat,iblok,jblok,lblok,magpen,magsus,mmom,mmom_tr,&
264 4 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtopt,prtvol,qpt,xred,zfield,zfield_tr)
265 : end if
266 :
267 : !Now calculate the non-magnetic second-order quantities
268 328 : write(msg, '(2a,(80a),4a)' ) ch10,('-',ii=1,80),ch10,ch10,&
269 332 : ' Second-order linear-response tensors ',ch10
270 12 : call wrtout([std_out, ab_out], msg)
271 :
272 : !Convert ddb%val to second-order energies
273 4 : call ddb%to_d2etot(ddb%val,kblok,0,qeq0,qphon,qphnrm,ucvol,optgb,omega=omega)
274 :
275 : !Convert second-order derivatives to diferent magnetic boundary conditions
276 : call mp_d2etot(barmagsus,ddb,kblok,magsus,mpert,mpopt,natom, &
277 4 : & ndim,zfield,zfield_tr)
278 :
279 : !Convert second-order energies to the physical quantities of ddb%val
280 4 : call ddb%to_d2etot(ddb%val,kblok,1,qeq0,qphon,qphnrm,ucvol,optgb,omega=omega)
281 4 : call ddb%to_d2etot(ddb%val_fs,kblok,1,qeq0,qphon,qphnrm,ucvol,optgb,omega=omega)
282 4 : if (mpopt==2) call ddb%to_d2etot(ddb%val_rs,kblok,1,qeq0,qphon,qphnrm,ucvol,optgb,omega=omega)
283 :
284 : !Print the physical quantities in the new magnetic boundary conditions
285 : if (prtopt==1) then
286 4 : if (mpopt==1) then
287 0 : call mp_d2etot_print(ddb,ddb%val_fs,kblok,mpert,natom,nblok,1,omega,qeq0,qphnrm,qphon,ddb%msize)
288 4 : else if (mpopt==2) then
289 4 : call mp_d2etot_print(ddb,ddb%val_rs,kblok,mpert,natom,nblok,2,omega,qeq0,qphnrm,qphon,ddb%msize)
290 : end if
291 : end if
292 :
293 4 : rfmagn(:)=0
294 4 : rfelfd(:)=0
295 7 : rfphon(:)=0
296 :
297 : end do
298 :
299 : ! BERRY CURVATURES
300 3 : if (timdisp==1) then
301 :
302 8 : ABI_MALLOC(ddb_lw%val_fs,(2,ddb_lw%msize,ddb_lw%nblok))
303 :
304 6 : ABI_MALLOC(bc_barmagsus,(ndim,ndim))
305 6 : ABI_MALLOC(bc_ss,(ndim,ndim))
306 6 : ABI_MALLOC(bc_sp,(ndim,(natom+5)*3))
307 :
308 164 : write(msg, '(2a,(80a),4a)' ) ch10,('=',ii=1,80),ch10,ch10,&
309 166 : ' Frequency-derivatives (Berry curvatures) constrained DFPT section ',ch10
310 6 : call wrtout([std_out, ab_out], msg)
311 :
312 2 : rffreq(:)=0
313 2 : nblok=ddb_lw%nblok
314 6 : do kblok=1,nblok
315 :
316 4 : if (ddb_lw%typ(kblok)/=33) cycle
317 :
318 : !Berry curvature of the penalized spin-susceptibility
319 2 : qphon=zero
320 8 : qphon(:,1)=ddb_lw%qpt(1:3,kblok)
321 8 : qpt= qphon(:,1)
322 8 : qphnrm(:)=ddb_lw%nrm(1,kblok)
323 8 : omega(:)=ddb_lw%omega(:,kblok)
324 8 : rfphon(1:3)=0
325 8 : rfelfd(1:3)=0
326 8 : rfstrs(1:3)=0
327 2 : rffreq(3)=1
328 2 : iblok=0
329 2 : if (magpen<zero) then
330 0 : rfmagn(1:2)= 1
331 2 : else if (magpen>zero) then
332 6 : rfmagn(1:2)= 2
333 : end if
334 :
335 164 : write(msg, '(a,(80a),a,3(a,3f16.8,a),3(a,f16.8,a))' ) ch10,('-',ii=1,80),ch10, &
336 2 : ' q point 1 ', qphon(:,1),ch10,&
337 2 : ' q point 2 ', qphon(:,2),ch10,&
338 2 : ' q point 3 ', qphon(:,3),ch10,&
339 2 : ' frequency 1', ddb_lw%omega(1,kblok), ch10,&
340 2 : ' frequency 2', ddb_lw%omega(2,kblok), ch10,&
341 166 : ' frequency 3', ddb_lw%omega(3,kblok), ch10
342 6 : call wrtout([std_out, ab_out], msg)
343 :
344 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, 33, &
345 2 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn,rffreq=rffreq)
346 :
347 2 : if (iblok /= 0) then
348 : call berrycurv_ss(bc_barmagsus,bc_ss,ddb_lw,iblok,invbarmagsus,mpatpol,mpdir,mpert,&
349 2 : & natom,ndim,nmdir,prtvol,qpt,xred)
350 : end if
351 :
352 : !Berry curvature of the induced Zeeman fields
353 :
354 : !First atomic-displacement
355 : iblok=0
356 2 : rfphon(2)=1
357 2 : rfmagn(:)=0
358 2 : if (magpen<zero) then
359 0 : rfmagn(1)= 1
360 2 : else if (magpen>zero) then
361 2 : rfmagn(1)= 2
362 : end if
363 :
364 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, 33, &
365 2 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn,rffreq=rffreq)
366 :
367 : ! Then electric field
368 2 : jblok=0
369 2 : if (qeq0) then
370 1 : rfphon(2)=0
371 1 : rfelfd(2)=2
372 :
373 : call ddb_lw%get_block(jblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, 33, &
374 1 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn,rffreq=rffreq)
375 : end if
376 :
377 : ! Then macroscopic Zeeman field
378 2 : lblok=0
379 2 : if (qeq0) then
380 1 : rfelfd(2)=0
381 1 : rfmagn(2)=1
382 :
383 : call ddb_lw%get_block(lblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, 33, &
384 1 : & mpatpol=mpatpol,mpdir=mpdir,omega=omega,rfmagn=rfmagn,rffreq=rffreq)
385 : end if
386 :
387 2 : if (iblok /= 0 .or. jblok /=0 .or. lblok /= 0) then
388 : call berrycurv_sp(barmmom,bc_sp,bc_ss,ddb_lw,iblok,invbarmagsus,jblok,lblok, &
389 2 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtvol,qpt,xred)
390 : end if
391 :
392 : !Berry curvature of other second-order quantites
393 : call berrycurv_pp(barmagsus,bc_barmagsus,bc_sp,ddb_lw,kblok, &
394 2 : & mpert,natom,ndim,qeq0,ucvol,zfield)
395 :
396 : !Print them
397 : call mp_d3etot_print(ddb_lw,ddb_lw%val_fs,kblok,mpert,natom,nblok,1,omega,&
398 6 : & prtvol,qeq0,qphnrm,qphon,ucvol,ddb_lw%msize)
399 :
400 : end do
401 2 : ABI_FREE(bc_ss)
402 2 : ABI_FREE(bc_sp)
403 2 : ABI_FREE(bc_barmagsus)
404 : end if
405 :
406 : !Deallocations
407 3 : ABI_FREE(barmagsus)
408 3 : ABI_FREE(barmmom)
409 3 : ABI_FREE(barmmom_tr)
410 3 : ABI_FREE(magsus)
411 3 : ABI_FREE(invbarmagsus)
412 3 : ABI_FREE(invmagsus)
413 3 : ABI_FREE(mmom)
414 3 : ABI_FREE(mmom_tr)
415 3 : ABI_FREE(zfield)
416 3 : ABI_FREE(zfield_tr)
417 3 : ABI_FREE(ifcmat)
418 3 : ABI_FREE(ifcmat_fm)
419 3 : ABI_FREE(zeff)
420 3 : ABI_FREE(zeff_tr)
421 3 : ABI_FREE(fmzeff)
422 3 : ABI_FREE(fmzeff_tr)
423 3 : ABI_FREE(lm_epsilon)
424 3 : ABI_FREE(dum_phongreen)
425 3 : ABI_FREE(invhmat)
426 :
427 3 : end subroutine ddb_magpen
428 : !!***
429 :
430 : !!****f* m_ddb_magpen/local_spinsus
431 : !! NAME
432 : !! local_spinsus
433 : !!
434 : !! FUNCTION
435 : !! Calculate the spin-susceptibility matrix and its inverse
436 : !!
437 : !! INPUTS
438 : !! ddb= Second-order derivative arrais
439 : !! iblok= index of the current block
440 : !! magpen = amplitude (in Ha) of the applied magnetic penalty
441 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
442 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
443 : !! mpert =maximum number of ipert
444 : !! natom= number of atoms in unit cell
445 : !! nblok= number of blocks in the DDB
446 : !! nmdir= number of directions along which the magnetic penalty was applied
447 : !! ndim= dimension of the square susceptibilities
448 : !! prtvol= control the volume of information written on output
449 : !! fs2rs= (optional) if 1, the routine starts from a precalculated blkval_fs
450 : !! blkval_fs(2,3,mpert,3,mpert)= fixed-spin 2nd-order derivatives
451 : !! xred(3,natom)= reduced atomic coordinates
452 : !!
453 : !! OUTPUT
454 : !! barmagsus(ndim,ndim)= Penalized spin-sussceptibility tensor
455 : !! invbarmagsus(ndim,ndim)= Inverse of the penalized spin-sussceptibility tensor
456 : !! magsus(ndim,ndim)= Spin-sussceptibility tensor
457 : !! invmagsus(ndim,ndim)= Inverse of spin-sussceptibility tensor
458 : !!
459 : !! SOURCE
460 :
461 68 : subroutine local_spinsus(barmagsus,ddb,iblok,invbarmagsus,invmagsus,invhmat,magpen,magsus, &
462 34 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtopt,prtvol,qphon,xred, &
463 30 : & fs2rs,blkval_fs) !optional
464 :
465 : !Arguments -------------------------------
466 : !scalars
467 : integer,intent(in) :: iblok,mpert,natom,ndim,nmdir
468 : integer,intent(in) :: prtopt,prtvol
469 : integer,intent(in),optional :: fs2rs
470 : real(dp),intent(in) :: magpen
471 : !arrays
472 : type(ddb_type),intent(inout) :: ddb
473 : integer,intent(in) :: mpatpol(2),mpdir(3)
474 : real(dp),intent(in),optional :: blkval_fs(2,3,mpert,3,mpert,1)
475 : real(dp),intent(in) :: qphon(3),xred(3,natom)
476 : complex(dpc),intent(out) :: barmagsus(ndim,ndim)
477 : complex(dpc),intent(out) :: invbarmagsus(ndim,ndim)
478 : complex(dpc),intent(out) :: invhmat(ndim,ndim)
479 : complex(dpc),intent(out) :: magsus(ndim,ndim)
480 : complex(dpc),intent(out) :: invmagsus(ndim,ndim)
481 :
482 : !Local variables -------------------------
483 : !scalars
484 : integer :: fs2rs_
485 : integer :: iat1,iat2,icol,idir1,idir2,index,info,ipert1,ipert2,irow,lwork
486 : integer :: ipert1_red,ipert2_red,idir1_red,idir2_red
487 : !real(dp) :: fac
488 : character(len=1000) :: msg
489 : !arrays
490 68 : complex(dpc) :: idty(ndim,ndim)
491 34 : integer :: indexat(ndim),indexdir(ndim)
492 34 : integer, allocatable :: ipiv(:)
493 34 : complex(dpc),allocatable :: work(:),work1(:,:),work2(:,:)
494 : character(len=1) :: cart(3)=(/'x','y','z'/)
495 :
496 : ! *********************************************************************
497 :
498 : !If fixed-spin case has been precalculated do less stuff
499 34 : fs2rs_=0; if (present(fs2rs)) fs2rs_=fs2rs
500 30 : if (fs2rs_==1) then
501 30 : if (.not.present(blkval_fs)) then
502 0 : write(msg, '(3a)' )' No fixed-spin array has been passed to local_spinsus', &
503 0 : & ' but fs2rs=1 ',ch10
504 0 : ABI_ERROR(msg)
505 : end if
506 : end if
507 :
508 : !Extract the penalized susceptibility
509 714 : idty=(zero,zero)
510 34 : ipert2_red= 0
511 102 : do iat2= mpatpol(1), mpatpol(2)
512 68 : ipert2= natom + 11 + iat2
513 68 : ipert2_red= ipert2_red + 1
514 68 : idir2_red= 0
515 306 : do idir2= 1, 3
516 204 : if (mpdir(idir2)==0) cycle
517 136 : idir2_red= idir2_red + 1
518 136 : icol=idir2_red+(ipert2_red-1)*nmdir
519 136 : indexat(icol)=iat2
520 136 : indexdir(icol)=idir2
521 136 : idty(icol,icol)=(one,zero)
522 136 : ipert1_red=0
523 476 : do iat1= mpatpol(1), mpatpol(2)
524 272 : ipert1= natom + 11 + iat1
525 272 : ipert1_red= ipert1_red + 1
526 272 : idir1_red= 0
527 1292 : do idir1= 1, 3
528 816 : if (mpdir(idir1)==0) cycle
529 544 : idir1_red=idir1_red+1
530 544 : irow=idir1_red+(ipert1_red-1)*nmdir
531 544 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
532 :
533 : !Apply a phase factor to adopt the same Gonze&Lee convention as for atomic
534 : !displacements at finite q (See M. Stengel PRB 2013).
535 816 : if (fs2rs_==0) then
536 : barmagsus(irow,icol)= &
537 : & cmplx(ddb%val(1,index,iblok),ddb%val(2,index,iblok),kind=dpc) &
538 256 : & * exp(two_pi*(0.d0,1.d0)*dot_product(qphon,xred(:,iat1)-xred(:,iat2)))
539 480 : else if (fs2rs_==1) then
540 : invmagsus(irow,icol)= &
541 : & cmplx(blkval_fs(1,idir1,ipert1,idir2,ipert2,iblok), &
542 480 : & blkval_fs(2,idir1,ipert1,idir2,ipert2,iblok),kind=dpc)
543 : end if
544 :
545 : end do
546 : end do
547 : end do
548 : end do
549 :
550 : !Use magsus to store the intermediate array
551 714 : magsus=idty-magpen*barmagsus
552 :
553 : !Invert the arrays
554 136 : ABI_MALLOC(work1,(ndim,ndim))
555 102 : ABI_MALLOC(work2,(ndim,ndim))
556 34 : if (fs2rs_==0) then
557 88 : work1=barmagsus
558 30 : else if (fs2rs_==1) then
559 660 : work1=invmagsus
560 : end if
561 748 : work2=magsus
562 :
563 102 : ABI_MALLOC(ipiv,(ndim))
564 34 : call zgetrf( ndim, ndim, work1, ndim, ipiv, info )
565 34 : ABI_CHECK(info == 0, sjoin('zgetrf returned:', itoa(info)))
566 :
567 34 : ABI_MALLOC(work,(2))
568 34 : call zgetri( ndim, work1, ndim, ipiv, work, -1, info )
569 34 : ABI_CHECK(info == 0, sjoin('zgetri returned:', itoa(info)))
570 34 : lwork=int(work(1))
571 :
572 102 : ABI_REMALLOC(work,(lwork))
573 34 : call zgetri( ndim, work1, ndim, ipiv, work, lwork, info )
574 34 : ABI_CHECK(info == 0, sjoin('zgetri returned:', itoa(info)))
575 :
576 34 : if (fs2rs_==1) then
577 630 : magsus=work1
578 30 : ABI_SFREE(ipiv)
579 30 : ABI_SFREE(work1)
580 30 : ABI_SFREE(work2)
581 30 : ABI_SFREE(work)
582 30 : return
583 : end if
584 :
585 4 : call zgetrf( ndim, ndim, work2, ndim, ipiv, info )
586 4 : ABI_CHECK(info == 0, sjoin('zgetrf returned:', itoa(info)))
587 :
588 4 : call zgetri( ndim, work2, ndim, ipiv, work, -1, info )
589 4 : ABI_CHECK(info == 0, sjoin('zgetri returned:', itoa(info)))
590 4 : lwork=int(work(1))
591 :
592 12 : ABI_REMALLOC(work,(lwork))
593 4 : call zgetri( ndim, work2, ndim, ipiv, work, lwork, info )
594 4 : ABI_CHECK(info == 0, sjoin('zgetri returned:', itoa(info)))
595 4 : ABI_FREE(work)
596 :
597 : !Write the results in meaningfull arrays
598 84 : invbarmagsus=work1
599 :
600 : !At last, calculate the susceptibility and its inverse
601 84 : invhmat=work2
602 420 : magsus=matmul(work2,barmagsus)
603 84 : invmagsus=invbarmagsus-magpen*idty
604 :
605 4 : ABI_FREE(ipiv)
606 4 : ABI_FREE(work1)
607 4 : ABI_FREE(work2)
608 :
609 4 : if (prtopt==1.and.prtvol>1) then
610 :
611 : !Write results in output
612 4 : if (magpen > zero) then
613 12 : call wrtout([ab_out,std_out], ' Local spin susceptibility ')
614 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
615 20 : do irow=1, ndim
616 84 : do icol=1, ndim
617 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
618 64 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
619 128 : & real(magsus(irow,icol)), aimag(magsus(irow,icol))
620 208 : call wrtout([ab_out,std_out], msg)
621 : end do
622 : end do
623 12 : call wrtout([ab_out,std_out], ' ')
624 :
625 12 : call wrtout([ab_out,std_out], ' Inverse of local spin susceptibility ')
626 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
627 20 : do irow=1, ndim
628 84 : do icol=1, ndim
629 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
630 64 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
631 128 : & real(invmagsus(irow,icol)), aimag(invmagsus(irow,icol))
632 208 : call wrtout([ab_out,std_out], msg)
633 : end do
634 : end do
635 12 : call wrtout([ab_out,std_out], ' ')
636 :
637 4 : if (prtvol > 2) then
638 12 : call wrtout([ab_out,std_out], ' Penalized local spin susceptibility ')
639 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
640 20 : do irow=1, ndim
641 84 : do icol=1, ndim
642 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
643 64 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
644 128 : & real(barmagsus(irow,icol)), aimag(barmagsus(irow,icol))
645 208 : call wrtout([ab_out,std_out], msg)
646 : end do
647 : end do
648 12 : call wrtout([ab_out,std_out], ' ')
649 :
650 12 : call wrtout([ab_out,std_out], ' Inverse of penalized local spin susceptibility ')
651 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
652 20 : do irow=1, ndim
653 84 : do icol=1, ndim
654 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
655 64 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
656 128 : & real(invbarmagsus(irow,icol)), aimag(invbarmagsus(irow,icol))
657 208 : call wrtout([ab_out,std_out], msg)
658 : end do
659 : end do
660 12 : call wrtout([ab_out,std_out], ' ')
661 :
662 12 : call wrtout([ab_out,std_out], ' Inverse of H matrix (I-alpha barchi)^{-1} ')
663 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
664 20 : do irow=1, ndim
665 84 : do icol=1, ndim
666 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
667 64 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
668 128 : & real(invhmat(irow,icol)), aimag(invhmat(irow,icol))
669 208 : call wrtout([ab_out,std_out], msg)
670 : end do
671 : end do
672 12 : call wrtout([ab_out,std_out], ' ')
673 : end if
674 :
675 : end if !magpen>zero
676 :
677 : end if !prtopt
678 :
679 : !Store the FS and RS flavors on the DDB array
680 : ipert2_red= 0
681 12 : do iat2= mpatpol(1), mpatpol(2)
682 8 : ipert2= natom + 11 + iat2
683 8 : ipert2_red= ipert2_red + 1
684 8 : idir2_red= 0
685 36 : do idir2= 1, 3
686 24 : if (mpdir(idir2)==0) cycle
687 16 : idir2_red= idir2_red + 1
688 16 : icol=idir2_red+(ipert2_red-1)*nmdir
689 16 : ipert1_red=0
690 56 : do iat1= mpatpol(1), mpatpol(2)
691 32 : ipert1= natom + 11 + iat1
692 32 : ipert1_red= ipert1_red + 1
693 32 : idir1_red= 0
694 152 : do idir1= 1, 3
695 96 : if (mpdir(idir1)==0) cycle
696 64 : idir1_red=idir1_red+1
697 64 : irow=idir1_red+(ipert1_red-1)*nmdir
698 64 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
699 :
700 64 : ddb%val_fs(1,index,iblok)=real(invmagsus(irow,icol))
701 64 : ddb%val_fs(2,index,iblok)=aimag(invmagsus(irow,icol))
702 :
703 64 : ddb%val_rs(1,index,iblok)=real(magsus(irow,icol))
704 128 : ddb%val_rs(2,index,iblok)=aimag(magsus(irow,icol))
705 :
706 : end do
707 : end do
708 : end do
709 : end do
710 :
711 64 : end subroutine local_spinsus
712 : !!***
713 :
714 : !!****f* m_ddb_magpen/magmom
715 : !! NAME
716 : !! magmom
717 : !!
718 : !! FUNCTION
719 : !! Calculate the first-order magnetic moments and the constrained
720 : !! Zeeman fields
721 : !!
722 : !! INPUTS
723 : !! ddb= Second-order derivative arrais
724 : !! invbarmagsus(ndim,ndim)= Inverse of the penalized spin-sussceptibility tensor
725 : !! iblok= index of the atomic displacement block
726 : !! jblok= index of the electric field block
727 : !! magsus(ndim,ndim)= Spin-sussceptibility tensor
728 : !! magpen = amplitude (in Ha) of the applied magnetic penalty
729 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
730 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
731 : !! mpert =maximum number of ipert
732 : !! natom= number of atoms in unit cell
733 : !! nblok= number of blocks in the DDB
734 : !! nmdir= number of directions along which the magnetic penalty was applied
735 : !! ndim= dimension of the square susceptibilities
736 : !! prtvol= control the volume of information written on output
737 : !! fs2rs= (optional) if 1, the routine starts from a precalculated blkval_fs
738 : !! blkval_fs(2,3,mpert,3,mpert)= fixed-spin 2nd-order derivatives
739 : !!
740 : !! OUTPUT
741 : !! barmmom(ndim,(natom+2)*3)= penalized first order magnetic moments on the atoms and
742 : !! directions of the penalty induced by atomic displacements and/or electric fields.
743 : !! mmom(ndim,(natom+2)*3)= first order magnetic moments on the atoms and
744 : !! directions of the penalty induced by atomic displacements and/or electric fields.
745 : !! zfield(ndim,(natom+2)*3)= Zeeman fields at constrained magnetic moments.
746 : !!
747 : !! SOURCE
748 :
749 68 : subroutine magmom(barmmom,barmmom_tr,ddb,invbarmagsus,invhmat,iblok,jblok,lblok,magpen,magsus,mmom,mmom_tr,&
750 34 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtopt,prtvol,qphon,xred,zfield,zfield_tr, &
751 30 : & fs2rs,blkval_fs) !optional
752 :
753 : !Arguments -------------------------------
754 : !scalars
755 : integer,intent(in) :: iblok,jblok,lblok,mpert,natom,ndim,nmdir,prtopt,prtvol
756 : integer,intent(in),optional :: fs2rs
757 : real(dp),intent(in) :: magpen
758 : !arrays
759 : type(ddb_type),intent(inout) :: ddb
760 : real(dp),intent(in) :: qphon(3),xred(3,natom)
761 : integer,intent(in) :: mpatpol(2),mpdir(3)
762 : real(dp),intent(in),optional :: blkval_fs(2,3,mpert,3,mpert,1)
763 : complex(dpc),intent(out) :: barmmom(ndim,(natom+5)*3)
764 : complex(dpc),intent(out) :: barmmom_tr((natom+5)*3,ndim)
765 : complex(dpc),intent(in) :: invbarmagsus(ndim,ndim)
766 : complex(dpc),intent(in) :: invhmat(ndim,ndim)
767 : complex(dpc),intent(in) :: magsus(ndim,ndim)
768 : complex(dpc),intent(out) :: mmom(ndim,(natom+5)*3)
769 : complex(dpc),intent(out) :: mmom_tr((natom+5)*3,ndim)
770 : complex(dpc),intent(out) :: zfield(ndim,(natom+5)*3)
771 : complex(dpc),intent(out) :: zfield_tr((natom+5)*3,ndim)
772 : !Local variables -------------------------
773 : !scalars
774 : integer :: fs2rs_
775 : integer :: iat1,icol,idir1,idir2,index,ipert1,ipert2,irow
776 : integer :: ipert1_red,idir1_red,jndex,zblok
777 : complex(dpc) :: qfac, qfac_tr
778 : character(len=1000) :: msg
779 : !arrays
780 68 : integer :: indexat1(ndim),indexdir1(ndim)
781 68 : integer :: indexat2((natom+5)*3),indexdir2((natom+5)*3)
782 34 : complex(dpc) :: mmom_alt(ndim,(natom+5)*3)
783 : character(len=1) :: cart(3)=(/'x','y','z'/)
784 :
785 : ! *********************************************************************
786 :
787 : !If fixed-spin case has been precalculated do less stuff
788 34 : fs2rs_=0; if (present(fs2rs)) fs2rs_=fs2rs
789 30 : if (fs2rs_==1) then
790 30 : if (.not.present(blkval_fs)) then
791 0 : write(msg, '(3a)' )' No fixed-spin array has been passed to magmom', &
792 0 : & ' but fs2rs=1 ',ch10
793 0 : ABI_ERROR(msg)
794 : end if
795 : end if
796 :
797 : !Extract the penalized moments
798 408 : do ipert2=1,natom+5
799 : !exclude strain perturbation
800 374 : if (ipert2==natom+3.or.ipert2==natom+4) cycle
801 1258 : do idir2=1,3
802 918 : icol=idir2+(ipert2-1)*3
803 918 : indexat2(icol)=ipert2
804 918 : indexdir2(icol)=idir2
805 :
806 918 : ipert1_red= 0
807 3128 : do iat1= mpatpol(1), mpatpol(2)
808 1836 : ipert1= natom + 11 + iat1
809 1836 : ipert1_red= ipert1_red + 1
810 1836 : idir1_red= 0
811 :
812 : !Apply a phase factor to adopt the same Gonze&Lee convention as for atomic
813 : !displacements at finite q (See M. Stengel PRB 2013).
814 7344 : qfac= exp(two_pi*(0.d0,1.d0)* dot_product(qphon,xred(:,iat1)))
815 7344 : qfac_tr= exp(-two_pi*(0.d0,1.d0)* dot_product(qphon,xred(:,iat1)))
816 8262 : do idir1= 1, 3
817 5508 : if (mpdir(idir1)==0) cycle
818 3672 : idir1_red= idir1_red + 1
819 3672 : irow=idir1_red+(ipert1_red-1)*nmdir
820 3672 : indexat1(irow)=iat1
821 3672 : indexdir1(irow)=idir1
822 3672 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
823 3672 : jndex= idir2 + 3*((ipert2-1)+mpert*((idir1-1)+3*(ipert1-1)))
824 :
825 5508 : if (fs2rs_==0) then
826 432 : if (iblok /=0 .and. ipert2 <= natom) then
827 288 : barmmom(irow,icol)= cmplx(ddb%val(1,index,iblok),ddb%val(2,index,iblok),kind=dpc) * qfac
828 288 : barmmom_tr(icol,irow)= cmplx(ddb%val(1,jndex,iblok),ddb%val(2,jndex,iblok),kind=dpc) * qfac_tr
829 144 : else if (jblok /=0 .and. ipert2 == natom+2) then
830 36 : barmmom(irow,icol)= cmplx(ddb%val(1,index,jblok),ddb%val(2,index,jblok),kind=dpc)
831 36 : barmmom_tr(icol,irow)= cmplx(ddb%val(1,jndex,jblok),ddb%val(2,jndex,jblok),kind=dpc)
832 108 : else if (lblok /=0 .and. ipert2 == natom+5) then
833 48 : barmmom(irow,icol)= cmplx(ddb%val(1,index,lblok),ddb%val(2,index,lblok),kind=dpc) * qfac
834 48 : barmmom_tr(icol,irow)= cmplx(ddb%val(1,jndex,lblok),ddb%val(2,jndex,lblok),kind=dpc) * qfac_tr
835 : end if
836 3240 : else if (fs2rs_==1) then
837 : zfield(irow,icol)= &
838 : & cmplx(blkval_fs(1,idir1,ipert1,idir2,ipert2,iblok), &
839 3240 : & blkval_fs(2,idir1,ipert1,idir2,ipert2,iblok),kind=dpc)
840 : zfield_tr(icol,irow)= &
841 : & cmplx(blkval_fs(1,idir2,ipert2,idir1,ipert1,iblok), &
842 3240 : & blkval_fs(2,idir2,ipert2,idir1,ipert1,iblok),kind=dpc)
843 : end if
844 :
845 : end do
846 : end do
847 : end do
848 : end do
849 :
850 : !Compute the Zeeman fields
851 34 : if (fs2rs_==0) then
852 4112 : zfield=-matmul(invbarmagsus,barmmom)
853 3300 : zfield_tr=-matmul(barmmom_tr,invbarmagsus)
854 : end if
855 :
856 : !Compute the moments
857 : if (fs2rs_==0) then
858 4112 : mmom=-matmul(magsus,zfield)
859 3436 : mmom_alt=matmul(invhmat,barmmom)
860 2740 : mmom_tr=matmul(barmmom_tr,invhmat)
861 30 : else if (fs2rs_==1) then
862 30840 : mmom=-matmul(magsus,zfield)
863 24750 : mmom_tr=-matmul(zfield_tr,magsus)
864 : return
865 : end if
866 :
867 4 : if (prtopt==1.and.prtvol>1) then
868 :
869 : !Write the results
870 4 : if (magpen > zero) then
871 :
872 : !Atomic displacements
873 4 : if (iblok /= 0) then
874 12 : call wrtout([ab_out,std_out], ' Local Zeeman fields induced by atomic displacements (at constrained magnetic moments)')
875 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
876 20 : do irow=1, ndim
877 308 : do icol=1, natom*3
878 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
879 288 : & indexat1(irow), cart(indexdir1(irow)), indexat2(icol), cart(indexdir2(icol)), &
880 576 : & real(zfield(irow,icol)), aimag(zfield(irow,icol))
881 880 : call wrtout([ab_out,std_out], msg)
882 : end do
883 : end do
884 12 : call wrtout([ab_out,std_out], ' ')
885 :
886 12 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by atomic displacements (from induced Zeeman fields)')
887 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
888 20 : do irow=1, ndim
889 308 : do icol=1, natom*3
890 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
891 288 : & indexat1(irow), cart(indexdir1(irow)), indexat2(icol), cart(indexdir2(icol)), &
892 576 : & real(mmom(irow,icol)), aimag(mmom(irow,icol))
893 880 : call wrtout([ab_out,std_out], msg)
894 : end do
895 : end do
896 12 : call wrtout([ab_out,std_out], ' ')
897 :
898 12 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by atomic displacements (from induced penalized moments)')
899 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
900 20 : do irow=1, ndim
901 308 : do icol=1, natom*3
902 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
903 288 : & indexat1(irow), cart(indexdir1(irow)), indexat2(icol), cart(indexdir2(icol)), &
904 576 : & real(mmom_alt(irow,icol)), aimag(mmom_alt(irow,icol))
905 880 : call wrtout([ab_out,std_out], msg)
906 : end do
907 : end do
908 12 : call wrtout([ab_out,std_out], ' ')
909 : end if
910 :
911 : !Electric field
912 4 : if (jblok /= 0) then
913 9 : call wrtout([ab_out,std_out], ' Local Zeeman fields induced by electric field (at constrained magnetic moments)')
914 9 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
915 15 : do irow=1, ndim
916 51 : do icol=(natom+1)*3+1, (natom+2)*3
917 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
918 36 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
919 72 : & real(zfield(irow,icol)), aimag(zfield(irow,icol))
920 120 : call wrtout([ab_out,std_out], msg)
921 : end do
922 : end do
923 9 : call wrtout([ab_out,std_out], ' ')
924 9 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by electric field (from induced Zeeman fields)')
925 9 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
926 15 : do irow=1, ndim
927 51 : do icol=(natom+1)*3+1, (natom+2)*3
928 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
929 36 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
930 72 : & real(mmom(irow,icol)), aimag(mmom(irow,icol))
931 120 : call wrtout([ab_out,std_out], msg)
932 : end do
933 : end do
934 9 : call wrtout([ab_out,std_out], ' ')
935 9 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by electric field (from induced penalized moments)')
936 9 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
937 15 : do irow=1, ndim
938 51 : do icol=(natom+1)*3+1, (natom+2)*3
939 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
940 36 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
941 72 : & real(mmom_alt(irow,icol)), aimag(mmom_alt(irow,icol))
942 120 : call wrtout([ab_out,std_out], msg)
943 : end do
944 : end do
945 9 : call wrtout([ab_out,std_out], ' ')
946 : end if
947 :
948 : !Macroscopic Zeeman
949 4 : if (lblok /= 0) then
950 12 : call wrtout([ab_out,std_out], ' Local Zeeman fields induced by macroscopic Zeeman field (at constrained magnetic moments)')
951 12 : call wrtout([ab_out,std_out], ' atom1 dir B-dir Real Imag')
952 20 : do irow=1, ndim
953 68 : do icol=(natom+4)*3+1, (natom+5)*3
954 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
955 48 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
956 96 : & real(zfield(irow,icol)), aimag(zfield(irow,icol))
957 160 : call wrtout([ab_out,std_out], msg)
958 : end do
959 : end do
960 12 : call wrtout([ab_out,std_out], ' ')
961 12 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by macroscopic Zeeman field (from induced Zeeman fields)')
962 12 : call wrtout([ab_out,std_out], ' atom1 dir B-dir Real Imag')
963 20 : do irow=1, ndim
964 68 : do icol=(natom+4)*3+1, (natom+5)*3
965 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
966 48 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
967 96 : & real(mmom(irow,icol)), aimag(mmom(irow,icol))
968 160 : call wrtout([ab_out,std_out], msg)
969 : end do
970 : end do
971 12 : call wrtout([ab_out,std_out], ' ')
972 12 : call wrtout([ab_out,std_out], ' Local magnetic moments induced by macroscopic Zeeman field (from induced penalized moments)')
973 12 : call wrtout([ab_out,std_out], ' atom1 dir B-dir Real Imag')
974 20 : do irow=1, ndim
975 68 : do icol=(natom+4)*3+1, (natom+5)*3
976 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
977 48 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
978 96 : & real(mmom_alt(irow,icol)), aimag(mmom_alt(irow,icol))
979 160 : call wrtout([ab_out,std_out], msg)
980 : end do
981 : end do
982 12 : call wrtout([ab_out,std_out], ' ')
983 : end if
984 :
985 4 : if (prtvol > 2) then
986 4 : if (iblok /= 0) then
987 12 : call wrtout([ab_out,std_out], ' Penalized local magnetic moments induced by atomic displacements ')
988 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
989 20 : do irow=1, ndim
990 308 : do icol=1, natom*3
991 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
992 288 : & indexat1(irow), cart(indexdir1(irow)), indexat2(icol), cart(indexdir2(icol)), &
993 576 : & real(barmmom(irow,icol)), aimag(barmmom(irow,icol))
994 880 : call wrtout([ab_out,std_out], msg)
995 : end do
996 : end do
997 12 : call wrtout([ab_out,std_out], ' ')
998 : end if
999 4 : if (jblok /= 0) then
1000 9 : call wrtout([ab_out,std_out], ' Penalized local magnetic moments induced by electric field ')
1001 9 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
1002 15 : do irow=1, ndim
1003 51 : do icol=(natom+1)*3+1, (natom+2)*3
1004 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
1005 36 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
1006 72 : & real(barmmom(irow,icol)), aimag(barmmom(irow,icol))
1007 120 : call wrtout([ab_out,std_out], msg)
1008 : end do
1009 : end do
1010 9 : call wrtout([ab_out,std_out], ' ')
1011 : end if
1012 4 : if (lblok /= 0) then
1013 12 : call wrtout([ab_out,std_out], ' Penalized local magnetic moments induced by macroscopic Zeeman field ')
1014 12 : call wrtout([ab_out,std_out], ' atom1 dir B-dir Real Imag')
1015 20 : do irow=1, ndim
1016 68 : do icol=(natom+4)*3+1, (natom+5)*3
1017 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
1018 48 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
1019 96 : & real(barmmom(irow,icol)), aimag(barmmom(irow,icol))
1020 160 : call wrtout([ab_out,std_out], msg)
1021 : end do
1022 : end do
1023 12 : call wrtout([ab_out,std_out], ' ')
1024 : end if
1025 : end if
1026 : end if
1027 : end if
1028 :
1029 : !Store the FS and RS flavors on the DDB array
1030 48 : do ipert2=1,natom+5
1031 180 : do idir2=1,3
1032 132 : icol=idir2+(ipert2-1)*3
1033 132 : indexat2(icol)=ipert2
1034 132 : indexdir2(icol)=idir2
1035 :
1036 132 : ipert1_red= 0
1037 440 : do iat1= mpatpol(1), mpatpol(2)
1038 264 : ipert1= natom + 11 + iat1
1039 264 : ipert1_red= ipert1_red + 1
1040 264 : idir1_red= 0
1041 1188 : do idir1= 1, 3
1042 792 : if (mpdir(idir1)==0) cycle
1043 528 : idir1_red= idir1_red + 1
1044 528 : irow=idir1_red+(ipert1_red-1)*nmdir
1045 528 : indexat1(irow)=iat1
1046 528 : indexdir1(irow)=idir1
1047 528 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1048 528 : jndex= idir2 + 3*((ipert2-1)+mpert*((idir1-1)+3*(ipert1-1)))
1049 :
1050 528 : zblok= 0
1051 528 : if (iblok /=0 .and. ipert2 <= natom) zblok= iblok
1052 528 : if (jblok /=0 .and. ipert2 == natom+2) zblok= jblok
1053 528 : if (lblok /=0 .and. ipert2 == natom+5) zblok= lblok
1054 792 : if (zblok /= 0) then
1055 372 : ddb%val_fs(1,index,zblok)=real(zfield(irow,icol))
1056 372 : ddb%val_fs(2,index,zblok)=aimag(zfield(irow,icol))
1057 372 : ddb%val_fs(1,jndex,zblok)=real(zfield_tr(icol,irow))
1058 372 : ddb%val_fs(2,jndex,zblok)=aimag(zfield_tr(icol,irow))
1059 :
1060 372 : ddb%val_rs(1,index,zblok)=real(mmom(irow,icol))
1061 372 : ddb%val_rs(2,index,zblok)=aimag(mmom(irow,icol))
1062 372 : ddb%val_rs(1,jndex,zblok)=real(mmom_tr(icol,irow))
1063 372 : ddb%val_rs(2,jndex,zblok)=aimag(mmom_tr(icol,irow))
1064 : end if
1065 :
1066 : end do
1067 : end do
1068 : end do
1069 : end do
1070 :
1071 34 : end subroutine magmom
1072 : !!***
1073 :
1074 : !!****f* m_ddb_magpen/mp_d2etot
1075 : !! NAME
1076 : !! mp_d2etot
1077 : !!
1078 : !! FUNCTION
1079 : !! Calculate the different magnetic flavors (see mpopt below) of the second-
1080 : !! order derivatives of total energy
1081 : !!
1082 : !! INPUTS
1083 : !! barmagsus(ndim,ndim)= Penalized spin-sussceptibility tensor (\bar{\chi})
1084 : !! (equal to barmom^{\dagger} in the nondissipative regime)
1085 : !! ddb= the ddb object
1086 : !! iblok= index of the IFCs block
1087 : !! invhmat(ndim,ndim)= (I-\alpha\bar{\chi})^-1 matrix
1088 : !! magsus(ndim,ndim)= Spin-sussceptibility tensor
1089 : !! magpen= magnetic penalty amplitude
1090 : !! mpert =maximum number of ipert
1091 : !! mpopt = 1 calculate the frozen-spin second-order quantities
1092 : !! 2 calculate the relaxed-spin second-order quantities
1093 : !! natom= number of atoms in unit cell
1094 : !! nblok= number of blocks in the DDB
1095 : !! ndim= number of local magnetic degres of freedom
1096 : !! qphon= momentum wave-vector
1097 : !! xred(3,natom)= reduced atomic coordinates
1098 : !! zfield(ndim,(natom+2)*3)= First-order induced Zeeman fields
1099 : !! zfield_tr(natom+2)*3,ndim)= Linear-responses to external Zeeman fields
1100 : !! (equal to zfield^{\dagger} in the nondissipative regime)
1101 : !! fs2rs= (optional) if 1, the routine starts from a precalculated blkval_fs
1102 : !! blkval_fs(2,3,mpert,3,mpert,1)= fixed-spin 2nd-order derivatives
1103 : !!
1104 : !! OUTPUT
1105 : !! ddb%val_fs(2,msize,nblok)= second-order derivatives at fixed spin.
1106 : !! ddb%val_rs(2,msize,nblok)= second-order derivatives at relaxed spin.
1107 : !! blkval_rs(2,3,mpert,3,mpert,1)= (optional) relaxed-spin 2nd-order derivatives
1108 : !!
1109 : !! SOURCE
1110 :
1111 68 : subroutine mp_d2etot(barmagsus,ddb,&
1112 34 : & iblok,magsus,mpert,mpopt,&
1113 34 : & natom,ndim,zfield,zfield_tr,&
1114 60 : & fs2rs,blkval_fs,blkval_rs) !optional
1115 :
1116 : !Arguments -------------------------------
1117 : !scalars
1118 : integer,intent(in) :: iblok,mpert,mpopt,natom,ndim
1119 : integer,intent(in),optional :: fs2rs
1120 : ! real(dp),intent(in) :: magpen
1121 : !arrays
1122 : type(ddb_type),intent(inout) :: ddb
1123 : real(dp),intent(in),optional :: blkval_fs(2,3,mpert,3,mpert,1)
1124 : real(dp),intent(out),optional :: blkval_rs(2,3,mpert,3,mpert,1)
1125 : complex(dpc),intent(in) :: barmagsus(ndim,ndim)
1126 : ! complex(dpc),intent(in) :: invhmat(ndim,ndim)
1127 : complex(dpc),intent(in) :: magsus(ndim,ndim)
1128 : complex(dpc),intent(in) :: zfield(ndim,(natom+5)*3)
1129 : complex(dpc),intent(in) :: zfield_tr((natom+5)*3,ndim)
1130 : !Local variables -------------------------
1131 : !scalars
1132 : integer :: fs2rs_
1133 : integer :: idir1,idir2,ipert1,ipert2,index,irow,icol
1134 : complex(dpc) :: val_ps,val_fs, val_rs
1135 : character(len=1000) :: msg
1136 : !arrays
1137 :
1138 : ! *********************************************************************
1139 :
1140 : !If fixed-spin case has been precalculated do less stuff
1141 34 : fs2rs_=0; if (present(fs2rs)) fs2rs_=fs2rs
1142 30 : if (fs2rs_==1) then
1143 30 : if (.not.present(blkval_fs)) then
1144 0 : write(msg, '(3a)' )' No fixed-spin array has been passed to mp_d2etot', &
1145 0 : & ' but fs2rs=1 ',ch10
1146 0 : ABI_ERROR(msg)
1147 : end if
1148 30 : if (.not.present(blkval_rs)) then
1149 0 : write(msg, '(3a)' )' No relaxed-spin array has been passed to mp_d2etot', &
1150 0 : & ' but fs2rs=1 ',ch10
1151 0 : ABI_ERROR(msg)
1152 : end if
1153 : end if
1154 :
1155 : !Extract the penalized/constrained quantities
1156 408 : do ipert2= 1, natom+5
1157 1530 : do idir2= 1, 3
1158 1122 : icol= (ipert2-1)*3 + idir2
1159 13838 : do ipert1= 1, natom+5
1160 50490 : do idir1= 1, 3
1161 37026 : irow= (ipert1-1)*3 + idir1
1162 37026 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1163 :
1164 37026 : if (fs2rs_==0) then
1165 : !Extract the penalized second-order derivatives
1166 4356 : val_ps= cmplx(ddb%val(1,index,iblok),ddb%val(2,index,iblok),kind=dpc)
1167 : !Calculate the fixed-spin flavor
1168 : val_fs= val_ps + &
1169 139392 : & sum( zfield_tr(irow,:) * matmul( barmagsus,zfield(:,icol) ) )
1170 4356 : ddb%val_fs(1,index,iblok)= real(val_fs)
1171 4356 : ddb%val_fs(2,index,iblok)= aimag(val_fs)
1172 32670 : else if (fs2rs_==1) then
1173 : val_fs= &
1174 : & cmplx(blkval_fs(1,idir1,ipert1,idir2,ipert2,iblok), &
1175 32670 : & blkval_fs(2,idir1,ipert1,idir2,ipert2,iblok),kind=dpc)
1176 : end if
1177 :
1178 49368 : if (mpopt==2) then
1179 : !Calculate the relaxed-spin flavor
1180 : val_rs= val_fs - &
1181 1184832 : & sum( zfield_tr(irow,:) * matmul( magsus,zfield(:,icol) ) )
1182 37026 : if (fs2rs_==0) then
1183 4356 : ddb%val_rs(1,index,iblok)= real(val_rs)
1184 4356 : ddb%val_rs(2,index,iblok)= aimag(val_rs)
1185 32670 : else if (fs2rs_==1) then
1186 32670 : blkval_rs(1,idir1,ipert1,idir2,ipert2,iblok)=real(val_rs)
1187 32670 : blkval_rs(2,idir1,ipert1,idir2,ipert2,iblok)=aimag(val_rs)
1188 : end if
1189 : end if
1190 :
1191 : end do
1192 : end do
1193 : end do
1194 : end do
1195 :
1196 64 : end subroutine mp_d2etot
1197 : !!***
1198 :
1199 : !!****f* m_ddb_magpen/mp_d2etot_print
1200 : !! NAME
1201 : !! mp_d2etot_print
1202 : !!
1203 : !! FUNCTION
1204 : !! Write on output file the fixed- and relaxed-spin susceptibilities
1205 : !!
1206 : !! INPUTS
1207 : !! blkval= 2nd-order susceptibilities matrix
1208 : !! kblok= index of the current block
1209 : !! opt= 1 write the frozen-spin second-order quantities
1210 : !! 2 write the relaxed-spin second-order quantities
1211 : !! omega= frequency of the perturbation
1212 : !! qphon= momentum wave-vector
1213 : !! ucvol= unit-cell volume
1214 : !!
1215 : !! OUTPUT
1216 : !!
1217 : !! SOURCE
1218 :
1219 16 : subroutine mp_d2etot_print(ddb,blkval,kblok,mpert,natom,nblok,opt,omega,qeq0,qphnrm,qphon,msize)
1220 :
1221 : !Arguments -------------------------------
1222 : !scalars
1223 : class(ddb_type),intent(in) :: ddb
1224 : integer,intent(in) :: kblok,mpert,natom,nblok,opt,msize
1225 : logical,intent(in) :: qeq0
1226 : !arrays
1227 : real(dp),intent(in) :: omega(3)
1228 : real(dp),intent(in) :: blkval(2,msize,nblok)
1229 : real(dp),intent(inout) :: qphnrm(3),qphon(3,3)
1230 :
1231 : !Local variables -------------------------
1232 : !scalars
1233 : integer :: iblok,idir1,idir2,ipert1,ipert2,irow,icol
1234 : integer :: rftyp,index
1235 : character(len=1000) :: msg
1236 : !arrays
1237 : integer :: rfelfd(4),rfmagn(4),rfphon(4),rfstrs(4)
1238 : real(dp) :: val(2)
1239 : character(len=1) :: cart(3)=(/'x','y','z'/)
1240 :
1241 : ! *********************************************************************
1242 :
1243 4 : rfelfd(:)=0
1244 4 : rfphon(:)=0
1245 4 : rfstrs(:)=0
1246 4 : rfmagn(:)=0
1247 4 : rftyp = 1
1248 :
1249 : !IFCs
1250 12 : rfphon(1:2)=1
1251 4 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega)
1252 4 : if (iblok/=0.and.iblok==kblok) then
1253 4 : if (opt==1) then
1254 0 : call wrtout([ab_out,std_out], ' Frozen-spin interatomic force constants')
1255 4 : else if (opt==2) then
1256 12 : call wrtout([ab_out,std_out], ' Relaxed-spin interatomic force constants')
1257 : end if
1258 12 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
1259 28 : do ipert1= 1, natom
1260 100 : do idir1= 1, 3
1261 72 : irow=( ipert1-1)*3 + idir1
1262 504 : do ipert2= 1, natom
1263 1800 : do idir2= 1, 3
1264 1296 : icol=( ipert2-1)*3 + idir2
1265 1296 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1266 3888 : val(:)=blkval(:,index,kblok)
1267 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)') &
1268 1296 : & ipert1, cart(idir1), ipert2, cart(idir2), val(1), val(2)
1269 4320 : call wrtout([ab_out,std_out], msg)
1270 : end do
1271 : end do
1272 240 : call wrtout([ab_out,std_out], ' ')
1273 : end do
1274 : end do
1275 : end if
1276 :
1277 4 : if (qeq0) then
1278 :
1279 : !Born charges
1280 9 : rfphon(1:2)=1
1281 9 : rfelfd(1:2)=2
1282 3 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega)
1283 3 : if (iblok/=0.and.iblok==kblok) then
1284 3 : if (opt==1) then
1285 0 : call wrtout([ab_out,std_out], ' Frozen-spin Born effective charges')
1286 3 : else if (opt==2) then
1287 9 : call wrtout([ab_out,std_out], ' Relaxed-spin Born effective charges')
1288 : end if
1289 9 : call wrtout([ab_out,std_out], ' E-dir atom dir Real Imag')
1290 3 : ipert1= natom + 2
1291 12 : do idir1= 1, 3
1292 63 : do ipert2= 1, natom
1293 225 : do idir2= 1, 3
1294 162 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1295 486 : val(:)=blkval(:,index,kblok)
1296 : write(msg,'(3x,a2,7x,i3,4x,a2,2x,2es18.9)') &
1297 162 : & cart(idir1), ipert2, cart(idir2), val(1), val(2)
1298 540 : call wrtout([ab_out,std_out], msg)
1299 : end do
1300 : end do
1301 30 : call wrtout([ab_out,std_out], ' ')
1302 : end do
1303 : end if
1304 :
1305 : !Dielectric tensor
1306 : iblok=0
1307 3 : rfphon(:)=0
1308 9 : rfelfd(1:2)=2
1309 3 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega)
1310 3 : if (iblok/=0.and.iblok==kblok) then
1311 3 : if (opt==1) then
1312 0 : call wrtout([ab_out,std_out], ' Frozen-spin clamped-ion dielectric tensor')
1313 3 : else if (opt==2) then
1314 9 : call wrtout([ab_out,std_out], ' Relaxed-spin clamped-ion dielectric tensor')
1315 : end if
1316 9 : call wrtout([ab_out,std_out], ' dir dir Real Imag')
1317 3 : ipert1= ddb%natom + 2
1318 3 : ipert2= ddb%natom + 2
1319 12 : do idir2= 1, 3
1320 36 : do idir1= 1, 3
1321 27 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1322 81 : val(:)=blkval(:,index,kblok)
1323 27 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
1324 54 : & val(1), val(2)
1325 90 : call wrtout([ab_out,std_out], msg)
1326 : end do
1327 30 : call wrtout([ab_out,std_out], ' ')
1328 : end do
1329 : end if
1330 :
1331 : !Magnetoelectric susceptibility
1332 : iblok=0
1333 3 : rfphon(:)=0
1334 3 : rfelfd(1)=0
1335 3 : rfelfd(2)=2
1336 3 : rfmagn(1)=1
1337 : rfmagn(2)=0
1338 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
1339 3 : & rfmagn=rfmagn)
1340 3 : if (iblok/=0.and.iblok==kblok) then
1341 3 : if (opt==1) then
1342 0 : call wrtout([ab_out,std_out], ' Frozen-spin clamped-ion magnetoelectric susceptibility')
1343 3 : else if (opt==2) then
1344 9 : call wrtout([ab_out,std_out], ' Relaxed-spin clamped-ion magnetoelectric susceptibility')
1345 : end if
1346 9 : call wrtout([ab_out,std_out], ' M-dir E-dir Real Imag')
1347 3 : ipert1= ddb%natom + 5
1348 3 : ipert2= ddb%natom + 2
1349 12 : do idir2= 1, 3
1350 36 : do idir1= 1, 3
1351 27 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1352 81 : val(:)=blkval(:,index,kblok)
1353 27 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
1354 54 : & val(1), val(2)
1355 90 : call wrtout([ab_out,std_out], msg)
1356 : end do
1357 30 : call wrtout([ab_out,std_out], ' ')
1358 : end do
1359 9 : call wrtout([ab_out,std_out], ' P-dir H-dir Real Imag')
1360 3 : ipert1= ddb%natom + 2
1361 3 : ipert2= ddb%natom + 5
1362 12 : do idir2= 1, 3
1363 36 : do idir1= 1, 3
1364 27 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1365 81 : val(:)=blkval(:,index,kblok)
1366 27 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
1367 54 : & val(1), val(2)
1368 90 : call wrtout([ab_out,std_out], msg)
1369 : end do
1370 30 : call wrtout([ab_out,std_out], ' ')
1371 : end do
1372 : end if
1373 :
1374 : end if
1375 :
1376 : !Magnetic susceptibility
1377 : iblok=0
1378 4 : rfphon(:)=0
1379 4 : rfelfd(:)=0
1380 4 : rfmagn(1)=1
1381 4 : rfmagn(2)=1
1382 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
1383 4 : & rfmagn=rfmagn)
1384 4 : if (iblok/=0.and.iblok==kblok) then
1385 4 : if (opt==1) then
1386 0 : call wrtout([ab_out,std_out], ' Frozen-spin clamped-ion magnetic susceptibility')
1387 4 : else if (opt==2) then
1388 12 : call wrtout([ab_out,std_out], ' Relaxed-spin clamped-ion magnetic susceptibility')
1389 : end if
1390 12 : call wrtout([ab_out,std_out], ' dir dir Real Imag')
1391 4 : ipert1= ddb%natom + 5
1392 4 : ipert2= ddb%natom + 5
1393 16 : do idir2= 1, 3
1394 48 : do idir1= 1, 3
1395 36 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1396 108 : val(:)=blkval(:,index,kblok)
1397 36 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
1398 72 : & val(1), val(2)
1399 120 : call wrtout([ab_out,std_out], msg)
1400 : end do
1401 40 : call wrtout([ab_out,std_out], ' ')
1402 : end do
1403 : end if
1404 :
1405 : !Magnetic Born effective charges
1406 : iblok=0
1407 4 : rfphon(1)=1
1408 4 : rfelfd(:)=0
1409 4 : rfmagn(1)=0
1410 : rfmagn(2)=1
1411 : call ddb%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
1412 4 : & rfmagn=rfmagn)
1413 4 : if (iblok/=0.and.iblok==kblok) then
1414 4 : if (opt==1) then
1415 0 : call wrtout([ab_out,std_out], ' Frozen-spin magnetic Born effective charges')
1416 4 : else if (opt==2) then
1417 12 : call wrtout([ab_out,std_out], ' Relaxed-spin magnetic Born effective charges')
1418 : end if
1419 12 : call wrtout([ab_out,std_out], ' B-dir atom dir Real Imag')
1420 :
1421 4 : ipert1= ddb%natom + 5
1422 16 : do idir1= 1, 3
1423 84 : do ipert2= 1, natom
1424 300 : do idir2= 1, 3
1425 216 : index= idir1 + 3*((ipert1-1)+mpert*((idir2-1)+3*(ipert2-1)))
1426 648 : val(:)=blkval(:,index,kblok)
1427 : write(msg,'(3x,a2,7x,i3,4x,a2,2x,2es18.9)') &
1428 216 : & cart(idir1), ipert2, cart(idir2), val(1), val(2)
1429 720 : call wrtout([ab_out,std_out], msg)
1430 : end do
1431 : end do
1432 40 : call wrtout([ab_out,std_out], ' ')
1433 : end do
1434 : end if
1435 :
1436 4 : end subroutine mp_d2etot_print
1437 : !!***
1438 :
1439 : !!****f* m_ddb_magpen/asrw0
1440 : !! NAME
1441 : !! asrw0
1442 : !!
1443 : !! FUNCTION
1444 : !! Impose the Acoustic Sum Rule from the w=0 IFCs
1445 : !!
1446 : !! INPUTS
1447 : !! natom= namber of atoms
1448 : !! option= if 0, this is the w=0 case, calculate delta_asrw0
1449 : ! if 1, use the previously calculated delta_asrw0
1450 : !!
1451 : !! OUTPUT
1452 : !! ifcmat(3*natom,3*natom)= IFC matrix after ASR has been applied.
1453 : !! delta_asrw0(3*natom,3)= Amount to remove in order to enforce ASR.
1454 : !!
1455 : !! SOURCE
1456 :
1457 0 : subroutine asrw0(delta_asrw0,ifcmat,natom,option)
1458 :
1459 : !Arguments -------------------------------
1460 : !scalars
1461 : integer,intent(in) :: natom,option
1462 : !arrays
1463 : real(dp),intent(inout) :: delta_asrw0(3*natom,3)
1464 : complex(dpc),intent(inout) :: ifcmat(3*natom,3*natom)
1465 : !Local variables -------------------------
1466 : !scalars
1467 : integer :: icol,idir1,idir2,ipert1,ipert2,irow
1468 : !arrays
1469 :
1470 : ! *********************************************************************
1471 :
1472 : !Calculate the ASR correction
1473 0 : if (option == 0) then
1474 0 : delta_asrw0= zero
1475 0 : do idir1= 1, 3
1476 0 : do ipert1= 1, natom
1477 0 : irow= (ipert1-1)*3 + idir1
1478 0 : do idir2= 1, 3
1479 0 : do ipert2= 1, natom
1480 0 : icol= (ipert2-1)*3 + idir2
1481 : delta_asrw0(irow,idir2)=delta_asrw0(irow,idir2) + &
1482 0 : & real(ifcmat(irow,icol))
1483 : end do
1484 : end do
1485 : end do
1486 : end do
1487 : end if
1488 :
1489 : !Apply the ASR
1490 0 : do idir1= 1, 3
1491 0 : do ipert1= 1, natom
1492 0 : irow= (ipert1-1)*3 + idir1
1493 0 : do idir2= 1, 3
1494 0 : icol= (ipert1-1)*3 + idir2
1495 0 : ifcmat(irow,icol)= ifcmat(irow,icol) - delta_asrw0(irow,idir2)
1496 : end do
1497 : end do
1498 : end do
1499 :
1500 0 : end subroutine asrw0
1501 : !!***
1502 :
1503 : !!****f* m_ddb_magpen/berrycurv_ss
1504 : !! NAME
1505 : !! berrycurv_ss
1506 : !!
1507 : !! FUNCTION
1508 : !! Calculate the Berry curvature of the inverse magnetic susceptibility
1509 : !! (this is equivalent to the G^(ss) matrix of S.Ren et al.)
1510 : !!
1511 : !! INPUTS
1512 : !! blkval(2,3*mpert*3*mpert*3*mpert,nblok)= Third-order derivative matrices
1513 : !! In our case, the nblok is restricted to iblok
1514 : !! iblok= index of the current block
1515 : !! invbarmagsus(ndim,ndim)= Inverse of the penalized spin-sussceptibility tensor
1516 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
1517 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
1518 : !! mpert =maximum number of ipert
1519 : !! natom= number of atoms in unit cell
1520 : !! nblok= number of blocks in the DDB
1521 : !! nmdir= number of directions along which the magnetic penalty was applied
1522 : !! ndim= dimension of the square susceptibilities
1523 : !! prtvol= control the volume of information written on output
1524 : !!
1525 : !! OUTPUT
1526 : !! bc_ss(ndim,ndim)= Berry-curvature of the inverse local-spin susceptibility
1527 : !!
1528 : !! SOURCE
1529 :
1530 2 : subroutine berrycurv_ss(bc_barmagsus,bc_ss,ddb_lw,iblok,invbarmagsus,&
1531 2 : & mpatpol,mpdir,mpert,natom,ndim,nmdir,prtvol,qphon,xred)
1532 :
1533 : !Arguments -------------------------------
1534 : !scalars
1535 : integer,intent(in) :: iblok,mpert,natom,ndim,nmdir,prtvol
1536 : !arrays
1537 : type(ddb_type),intent(inout) :: ddb_lw
1538 : integer,intent(in) :: mpatpol(2),mpdir(3)
1539 : real(dp),intent(in) :: qphon(3),xred(3,natom)
1540 : complex(dpc),intent(in) :: invbarmagsus(ndim,ndim)
1541 : complex(dpc),intent(out) :: bc_ss(ndim,ndim)
1542 : complex(dpc),intent(out) :: bc_barmagsus(ndim,ndim)
1543 : !Local variables -------------------------
1544 : !scalars
1545 : integer :: iat1,iat2,icol,idir1,idir2,idir3,index
1546 : integer :: ipert1,ipert2,ipert3,irow
1547 : integer :: ipert1_red,ipert2_red,idir1_red,idir2_red
1548 : complex(dpc), parameter :: ione=(0.d0,1.d0)
1549 : character(len=1000) :: msg
1550 : !arrays
1551 4 : complex(dpc) :: idty(ndim,ndim)
1552 2 : integer :: indexat(ndim),indexdir(ndim)
1553 : character(len=1) :: cart(3)=(/'x','y','z'/)
1554 :
1555 : ! *********************************************************************
1556 :
1557 : !Extract the Berry-curvature of the penalized susceptibility
1558 42 : idty=(zero,zero)
1559 2 : ipert3= natom + 9
1560 2 : idir3= 1
1561 2 : ipert2_red= 0
1562 6 : do iat2= mpatpol(1), mpatpol(2)
1563 4 : ipert2= natom + 11 + iat2
1564 4 : ipert2_red= ipert2_red + 1
1565 4 : idir2_red= 0
1566 18 : do idir2= 1, 3
1567 12 : if (mpdir(idir2)==0) cycle
1568 8 : idir2_red= idir2_red + 1
1569 8 : icol=idir2_red+(ipert2_red-1)*nmdir
1570 8 : indexat(icol)=iat2
1571 8 : indexdir(icol)=idir2
1572 8 : idty(icol,icol)=(one,zero)
1573 8 : ipert1_red=0
1574 28 : do iat1= mpatpol(1), mpatpol(2)
1575 16 : ipert1= natom + 11 + iat1
1576 16 : ipert1_red= ipert1_red + 1
1577 16 : idir1_red= 0
1578 76 : do idir1= 1, 3
1579 48 : if (mpdir(idir1)==0) cycle
1580 32 : idir1_red=idir1_red+1
1581 32 : irow=idir1_red+(ipert1_red-1)*nmdir
1582 : index = idir1 + &
1583 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
1584 32 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1585 :
1586 : !Apply a phase factor to adopt the same Gonze&Lee convention as for atomic
1587 : !displacements at finite q (See M. Stengel PRB 2013).
1588 : bc_barmagsus(irow,icol)= -one* & !To convert from d3etot to local susc.
1589 : & cmplx(ddb_lw%val(1,index,iblok),ddb_lw%val(2,index,iblok),kind=dpc) &
1590 160 : & * exp(two_pi*(0.d0,1.d0)*dot_product(qphon,xred(:,iat1)-xred(:,iat2)))
1591 :
1592 : end do
1593 : end do
1594 : end do
1595 : end do
1596 :
1597 : !Calculate the Berry-curvature of the inverse magnetic susceptibility
1598 600 : bc_ss=-matmul(invbarmagsus,matmul(bc_barmagsus,invbarmagsus))
1599 :
1600 2 : if (prtvol>1) then
1601 6 : call wrtout([ab_out,std_out], ' Fixed-spin Berry curvature of the inverse spin susceptibility ')
1602 6 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
1603 10 : do irow=1, ndim
1604 42 : do icol=1, ndim
1605 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
1606 32 : & indexat(irow), cart(indexdir(irow)), indexat(icol), cart(indexdir(icol)), &
1607 64 : & real(bc_ss(irow,icol)), aimag(bc_ss(irow,icol))
1608 104 : call wrtout([ab_out,std_out], msg)
1609 : end do
1610 : end do
1611 6 : call wrtout([ab_out,std_out], ' ')
1612 : end if
1613 :
1614 : !Store the FM flavor in the DDB object
1615 : ipert2_red= 0
1616 6 : do iat2= mpatpol(1), mpatpol(2)
1617 4 : ipert2= natom + 11 + iat2
1618 4 : ipert2_red= ipert2_red + 1
1619 4 : idir2_red= 0
1620 18 : do idir2= 1, 3
1621 12 : if (mpdir(idir2)==0) cycle
1622 8 : idir2_red= idir2_red + 1
1623 8 : icol=idir2_red+(ipert2_red-1)*nmdir
1624 8 : ipert1_red=0
1625 28 : do iat1= mpatpol(1), mpatpol(2)
1626 16 : ipert1= natom + 11 + iat1
1627 16 : ipert1_red= ipert1_red + 1
1628 16 : idir1_red= 0
1629 76 : do idir1= 1, 3
1630 48 : if (mpdir(idir1)==0) cycle
1631 32 : idir1_red=idir1_red+1
1632 32 : irow=idir1_red+(ipert1_red-1)*nmdir
1633 : index = idir1 + &
1634 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
1635 32 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1636 :
1637 32 : ddb_lw%val_fs(1,index,iblok)= real(bc_ss(irow,icol))
1638 64 : ddb_lw%val_fs(2,index,iblok)= aimag(bc_ss(irow,icol))
1639 : end do
1640 : end do
1641 : end do
1642 : end do
1643 :
1644 2 : end subroutine berrycurv_ss
1645 : !!***
1646 :
1647 : !!****f* m_ddb_magpen/berrycurv_sp
1648 : !! NAME
1649 : !! berrycurv_sp
1650 : !!
1651 : !! FUNCTION
1652 : !! Calculate the Berry curvature of the spin-phonon Hessian
1653 : !! (equivalent to the Berry curvature of the induced Zeeman fields at constrained
1654 : !! magnetic moments)
1655 : !!
1656 : !! INPUTS
1657 : !! ddb_lw= Third-order derivative ddb
1658 : !! In our case, the nblok is restricted to iblok
1659 : !! iblok= index of the current block
1660 : !! invbarmagsus(ndim,ndim)= Inverse of the penalized spin-sussceptibility tensor
1661 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
1662 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
1663 : !! mpert =maximum number of ipert
1664 : !! natom= number of atoms in unit cell
1665 : !! nblok= number of blocks in the DDB
1666 : !! nmdir= number of directions along which the magnetic penalty was applied
1667 : !! ndim= dimension of the square susceptibilities
1668 : !! prtvol= control the volume of information written on output
1669 : !!
1670 : !! OUTPUT
1671 : !!
1672 : !! SOURCE
1673 :
1674 2 : subroutine berrycurv_sp(barmmom,bc_sp,bc_ss,ddb_lw,iblok,invbarmagsus,&
1675 2 : & jblok,lblok,mpatpol,mpdir,mpert,natom,ndim,nmdir,prtvol,qphon,xred)
1676 :
1677 : !Arguments -------------------------------
1678 : !scalars
1679 : integer,intent(in) :: iblok,jblok,lblok,mpert,natom,ndim,nmdir,prtvol
1680 : !arrays
1681 : type(ddb_type),intent(inout) :: ddb_lw
1682 : integer,intent(in) :: mpatpol(2),mpdir(3)
1683 : real(dp),intent(in) :: qphon(3),xred(3,natom)
1684 : complex(dpc),intent(in) :: barmmom(ndim,(natom+5)*3)
1685 : complex(dpc),intent(in) :: bc_ss(ndim,ndim)
1686 : complex(dpc),intent(in) :: invbarmagsus(ndim,ndim)
1687 : complex(dpc),intent(out) :: bc_sp(ndim,(natom+5)*3)
1688 : !Local variables -------------------------
1689 : !scalars
1690 : integer :: iat1,icol,idir1,idir2,idir3,index,ipert1,ipert2,ipert3,irow
1691 : integer :: ipert1_red,idir1_red,jndex
1692 : complex(dpc), parameter :: ione=(0.d0,1.d0)
1693 : complex(dpc) :: qfac
1694 : character(len=1000) :: msg
1695 : !arrays
1696 4 : integer :: indexat1(ndim),indexdir1(ndim)
1697 4 : integer :: indexat2((natom+5)*3),indexdir2((natom+5)*3)
1698 2 : complex(dpc) :: bc_barsp(ndim,(natom+5)*3)
1699 : ! complex(dpc) :: bc_ps((natom+2)*3,ndim)
1700 : character(len=1) :: cart(3)=(/'x','y','z'/)
1701 :
1702 : ! *********************************************************************
1703 :
1704 : !Extract the berry curvature of the penalized moments
1705 332 : bc_barsp=(zero,zero)
1706 : ipert3= natom + 9
1707 : idir3= 1
1708 24 : do ipert2=1,natom+5
1709 90 : do idir2=1,3
1710 66 : icol=idir2+(ipert2-1)*3
1711 66 : indexat2(icol)=ipert2
1712 66 : indexdir2(icol)=idir2
1713 :
1714 66 : ipert1_red= 0
1715 220 : do iat1= mpatpol(1), mpatpol(2)
1716 132 : ipert1= natom + 11 + iat1
1717 132 : ipert1_red= ipert1_red + 1
1718 132 : idir1_red= 0
1719 :
1720 : !Apply a phase factor to adopt the same Gonze&Lee convention as for atomic
1721 : !displacements at finite q (See M. Stengel PRB 2013).
1722 528 : qfac= exp(two_pi*(0.d0,1.d0)* dot_product(qphon,xred(:,iat1)))
1723 594 : do idir1= 1, 3
1724 396 : if (mpdir(idir1)==0) cycle
1725 264 : idir1_red= idir1_red + 1
1726 264 : irow=idir1_red+(ipert1_red-1)*nmdir
1727 264 : indexat1(irow)=iat1
1728 264 : indexdir1(irow)=idir1
1729 : index = idir1 + &
1730 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
1731 264 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1732 :
1733 396 : if (iblok /=0 .and. ipert2 <= natom) then
1734 : bc_barsp(irow,icol)= -one* & !To go from d3etot to induced local field
1735 144 : & cmplx(ddb_lw%val(1,index,iblok),ddb_lw%val(2,index,iblok),kind=dpc) * qfac
1736 120 : else if (jblok /=0 .and. ipert2 == natom+2) then
1737 : bc_barsp(irow,icol)= -one* &
1738 12 : & cmplx(ddb_lw%val(1,index,jblok),ddb_lw%val(2,index,jblok),kind=dpc)
1739 108 : else if (lblok /=0 .and. ipert2 == natom+5) then
1740 : bc_barsp(irow,icol)= -one* &
1741 12 : & cmplx(ddb_lw%val(1,index,lblok),ddb_lw%val(2,index,lblok),kind=dpc) * qfac
1742 : end if
1743 :
1744 : end do
1745 : end do
1746 : end do
1747 : end do
1748 :
1749 : !Calculate the Berry curvature of the induced Zeeman fields
1750 3774 : bc_sp= -matmul(bc_ss,barmmom) - matmul(invbarmagsus,bc_barsp)
1751 :
1752 2 : if (prtvol > 1) then
1753 2 : if (iblok /= 0) then
1754 6 : call wrtout([ab_out,std_out], ' Fixed-spin Berry curvature of the Zeeman fields induced by atomic displacements')
1755 6 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
1756 10 : do irow=1, ndim
1757 154 : do icol=1, natom*3
1758 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)' ) &
1759 144 : & indexat1(irow), cart(indexdir1(irow)), indexat2(icol), cart(indexdir2(icol)), &
1760 288 : & real(bc_sp(irow,icol)), aimag(bc_sp(irow,icol))
1761 440 : call wrtout([ab_out,std_out], msg)
1762 : end do
1763 : end do
1764 6 : call wrtout([ab_out,std_out], ' ')
1765 : end if
1766 2 : if (jblok /= 0) then
1767 3 : call wrtout([ab_out,std_out], ' Fixed-spin Berry curvature of the Zeeman fields induced by electric field')
1768 3 : call wrtout([ab_out,std_out], ' atom1 dir E-dir Real Imag')
1769 5 : do irow=1, ndim
1770 17 : do icol=(natom+1)*3+1, (natom+2)*3
1771 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
1772 12 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
1773 24 : & real(bc_sp(irow,icol)), aimag(bc_sp(irow,icol))
1774 40 : call wrtout([ab_out,std_out], msg)
1775 : end do
1776 : end do
1777 3 : call wrtout([ab_out,std_out], ' ')
1778 : end if
1779 2 : if (lblok /= 0) then
1780 3 : call wrtout([ab_out,std_out], ' Fixed-spin Berry curvature of the Zeeman fields induced by macroscopic Zeeman field')
1781 3 : call wrtout([ab_out,std_out], ' atom1 dir B-dir Real Imag')
1782 5 : do irow=1, ndim
1783 17 : do icol=(natom+4)*3+1, (natom+5)*3
1784 : write(msg,'(i4,4x,a2,4x,a2,6x,2es18.9)' ) &
1785 12 : & indexat1(irow), cart(indexdir1(irow)), cart(indexdir2(icol)), &
1786 24 : & real(bc_sp(irow,icol)), aimag(bc_sp(irow,icol))
1787 40 : call wrtout([ab_out,std_out], msg)
1788 : end do
1789 : end do
1790 3 : call wrtout([ab_out,std_out], ' ')
1791 : end if
1792 : end if
1793 :
1794 : !Store the FM flavor in the DDB object
1795 24 : do ipert2=1,natom+5
1796 90 : do idir2=1,3
1797 66 : icol=idir2+(ipert2-1)*3
1798 66 : indexat2(icol)=ipert2
1799 66 : indexdir2(icol)=idir2
1800 :
1801 66 : ipert1_red= 0
1802 220 : do iat1= mpatpol(1), mpatpol(2)
1803 132 : ipert1= natom + 11 + iat1
1804 132 : ipert1_red= ipert1_red + 1
1805 132 : idir1_red= 0
1806 594 : do idir1= 1, 3
1807 396 : if (mpdir(idir1)==0) cycle
1808 264 : idir1_red= idir1_red + 1
1809 264 : irow=idir1_red+(ipert1_red-1)*nmdir
1810 : index = idir1 + &
1811 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
1812 264 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1813 : jndex = idir2 + &
1814 : & 3*((ipert2 - 1) + mpert*((idir1 - 1) + &
1815 264 : & 3*((ipert1 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1816 :
1817 396 : if (iblok /=0 .and. ipert2 <= natom) then
1818 144 : ddb_lw%val_fs(1,index,iblok)=real(bc_sp(irow,icol))
1819 144 : ddb_lw%val_fs(2,index,iblok)=aimag(bc_sp(irow,icol))
1820 144 : ddb_lw%val_fs(1,jndex,iblok)=real(bc_sp(irow,icol))
1821 144 : ddb_lw%val_fs(2,jndex,iblok)=-aimag(bc_sp(irow,icol))
1822 120 : else if (jblok /=0 .and. ipert2 == natom+2) then
1823 12 : ddb_lw%val_fs(1,index,jblok)=real(bc_sp(irow,icol))
1824 12 : ddb_lw%val_fs(2,index,jblok)=aimag(bc_sp(irow,icol))
1825 12 : ddb_lw%val_fs(1,jndex,jblok)=real(bc_sp(irow,icol))
1826 12 : ddb_lw%val_fs(2,jndex,jblok)=-aimag(bc_sp(irow,icol))
1827 108 : else if (lblok /=0 .and. ipert2 == natom+5) then
1828 12 : ddb_lw%val_fs(1,index,lblok)=real(bc_sp(irow,icol))
1829 12 : ddb_lw%val_fs(2,index,lblok)=aimag(bc_sp(irow,icol))
1830 12 : ddb_lw%val_fs(1,jndex,lblok)=real(bc_sp(irow,icol))
1831 12 : ddb_lw%val_fs(2,jndex,lblok)=-aimag(bc_sp(irow,icol))
1832 : end if
1833 :
1834 : end do
1835 : end do
1836 : end do
1837 : end do
1838 :
1839 2 : end subroutine berrycurv_sp
1840 : !!***
1841 :
1842 : !!****f* m_ddb_magpen/berrycurv_pp
1843 : !! NAME
1844 : !! berrycurv_pp
1845 : !!
1846 : !! FUNCTION
1847 : !! Calculate the Berry curvature of the phonon-phonon Hessian
1848 : !! (at constrained magnetic moments)
1849 : !!
1850 : !! INPUTS
1851 : !! blkval(2,3*mpert*3*mpert*3*mpert,nblok)= Third-order derivative matrices
1852 : !! In our case, the nblok is restricted to iblok
1853 : !! kblok= index of the current block
1854 : !! invbarmagsus(ndim,ndim)= Inverse of the penalized spin-sussceptibility tensor
1855 : !! mpatpol(2) = Atoms on which the magnetic penalty has been applied
1856 : !! mpdir(3) = Directions along which the spin-degrees of freedom have been stiffened
1857 : !! mpert =maximum number of ipert
1858 : !! natom= number of atoms in unit cell
1859 : !! nblok= number of blocks in the DDB
1860 : !! nmdir= number of directions along which the magnetic penalty was applied
1861 : !! ndim= dimension of the square susceptibilities
1862 : !! prtvol= control the volume of information written on output
1863 : !!
1864 : !! OUTPUT
1865 : !!
1866 : !! SOURCE
1867 :
1868 2 : subroutine berrycurv_pp(barmagsus,bc_barmagsus,bc_sp,ddb_lw,kblok,&
1869 2 : & mpert,natom,ndim,qeq0,ucvol,zfield)
1870 :
1871 : !Arguments -------------------------------
1872 : !scalars
1873 : integer,intent(in) :: kblok,mpert,natom,ndim
1874 : real(dp),intent(in) :: ucvol
1875 : logical,intent(in) :: qeq0
1876 : !arrays
1877 : type(ddb_type),intent(inout) :: ddb_lw
1878 : complex(dpc),intent(in) :: barmagsus(ndim,ndim)
1879 : complex(dpc),intent(in) :: bc_barmagsus(ndim,ndim)
1880 : complex(dpc),intent(in) :: bc_sp(ndim,(natom+5)*3)
1881 : complex(dpc),intent(in) :: zfield(ndim,(natom+5)*3)
1882 : !Local variables -------------------------
1883 : !scalars
1884 : integer :: icol,idir1,idir2,idir3,index,ipert1,ipert2,ipert3,irow
1885 : complex(dpc), parameter :: ione=(0.d0,1.d0)
1886 : complex(dpc) :: cval
1887 : !arrays
1888 4 : complex(dpc) :: bc_barpp((natom+5)*3,(natom+5)*3), bc_pp((natom+5)*3,(natom+5)*3)
1889 4 : complex(dpc) :: term((natom+5)*3,(natom+5)*3,3)
1890 :
1891 : ! *********************************************************************
1892 :
1893 : !Extract the frequency derivative of the penalized 2nd order nonmagnetic quantities
1894 2 : ipert3= natom + 9
1895 2 : idir3= 1
1896 24 : do ipert2= 1, natom+5
1897 90 : do idir2= 1, 3
1898 66 : icol=( ipert2-1)*3 + idir2
1899 814 : do ipert1= 1, natom+5
1900 2970 : do idir1= 1, 3
1901 2178 : irow=( ipert1-1)*3 + idir1
1902 : index = idir1 + &
1903 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
1904 2178 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
1905 :
1906 2904 : bc_barpp(irow,icol)= cmplx(ddb_lw%val(1,index,kblok),ddb_lw%val(2,index,kblok),kind=dpc)
1907 :
1908 : end do
1909 : end do
1910 : end do
1911 : end do
1912 :
1913 : !Calculate the different terms entering the Berry curvature
1914 23646 : term(:,:,1)=matmul(transpose(conjg(bc_sp)),matmul(barmagsus,zfield))
1915 23644 : term(:,:,2)=matmul(transpose(conjg(zfield)),matmul(bc_barmagsus,zfield))
1916 23644 : term(:,:,3)=matmul(transpose(conjg(zfield)),matmul(barmagsus,bc_sp))
1917 :
1918 2246 : bc_pp(:,:)= bc_barpp(:,:) + term(:,:,1) + term(:,:,2) + term(:,:,3)
1919 :
1920 : !Apply factors to convert derivatives of energy into susceptibilities
1921 : !Born charges
1922 2 : if (qeq0) then
1923 7 : ipert1= natom + 2
1924 7 : do ipert2= 1, natom
1925 25 : do idir2= 1, 3
1926 18 : icol=(ipert2-1)*3 + idir2
1927 78 : do idir1= 1, 3
1928 54 : irow=(ipert1-1)*3 + idir1
1929 54 : cval=bc_pp(irow,icol)
1930 54 : bc_pp(irow,icol)=-one*cval
1931 54 : cval=bc_pp(icol,irow)
1932 72 : bc_pp(icol,irow)=-one*cval
1933 : end do
1934 : end do
1935 : end do
1936 : end if
1937 :
1938 : !MR: Not sure why this is different from the electrical charges, | --------------------------------------------------------------------------------
1939 : !but is needed to reproduce freqflag=3 numbers
1940 : !Magnetic charges induced by atomic displacement
1941 : ! ipert1= natom + 5
1942 : ! do ipert2= 1, natom
1943 : ! do idir2= 1, 3
1944 : ! icol=( ipert2-1)*3 + idir2
1945 : ! do idir1= 1, 3
1946 : ! irow=( ipert1-1)*3 + idir1
1947 : ! cval=bc_pp(irow,icol)
1948 : ! bc_pp(irow,icol)=-cval
1949 : ! cval=bc_pp(icol,irow)
1950 : ! bc_pp(icol,irow)=-cval
1951 : ! end do
1952 : ! end do
1953 : ! end do
1954 :
1955 : !Dielectric tensor
1956 2 : if (qeq0) then
1957 4 : ipert1= natom + 2
1958 4 : ipert2= natom + 2
1959 4 : do idir2= 1, 3
1960 3 : icol=( ipert2-1)*3 + idir2
1961 13 : do idir1= 1, 3
1962 9 : irow=( ipert1-1)*3 + idir1
1963 9 : cval=bc_pp(irow,icol)
1964 12 : bc_pp(irow,icol)=-four_pi/ucvol*cval
1965 : end do
1966 : end do
1967 : end if
1968 :
1969 : !Magnetoelectric susceptibility
1970 2 : if (qeq0) then
1971 4 : ipert1= natom + 5
1972 4 : ipert2= natom + 2
1973 4 : do idir2= 1, 3
1974 3 : icol=( ipert2-1)*3 + idir2
1975 13 : do idir1= 1, 3
1976 9 : irow=( ipert1-1)*3 + idir1
1977 9 : cval=bc_pp(irow,icol)
1978 9 : bc_pp(irow,icol)=-cval/ucvol
1979 9 : cval=bc_pp(icol,irow)
1980 12 : bc_pp(icol,irow)=-cval/ucvol
1981 : end do
1982 : end do
1983 : end if
1984 :
1985 : !Magnetic susceptibility
1986 8 : ipert1= natom + 5
1987 8 : ipert2= natom + 5
1988 8 : do idir2= 1, 3
1989 6 : icol=( ipert2-1)*3 + idir2
1990 26 : do idir1= 1, 3
1991 18 : irow=( ipert1-1)*3 + idir1
1992 18 : cval=bc_pp(irow,icol)
1993 24 : bc_pp(irow,icol)=-cval/ucvol
1994 : end do
1995 : end do
1996 :
1997 : !Store the FM flavor in the DDB object
1998 24 : do ipert2= 1, natom+5
1999 90 : do idir2= 1, 3
2000 66 : icol=( ipert2-1)*3 + idir2
2001 814 : do ipert1= 1, natom+5
2002 2970 : do idir1= 1, 3
2003 2178 : irow=( ipert1-1)*3 + idir1
2004 : index = idir1 + &
2005 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2006 2178 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2007 2178 : ddb_lw%val_fs(1,index,kblok)=real(bc_pp(irow,icol))
2008 2904 : ddb_lw%val_fs(2,index,kblok)=aimag(bc_pp(irow,icol))
2009 : end do
2010 : end do
2011 : end do
2012 : end do
2013 :
2014 2 : end subroutine berrycurv_pp
2015 : !!***
2016 :
2017 : !!****f* m_ddb_magpen/mp_d3etot_print
2018 : !! NAME
2019 : !! mp_d3etot_print
2020 : !!
2021 : !! FUNCTION
2022 : !! Write on output file the fixed- and relaxed-spin susceptibilities
2023 : !! Only macroscopic quantities are printed if prtvol=1
2024 : !!
2025 : !! INPUTS
2026 : !! blkval= 2nd-order susceptibilities matrix
2027 : !! kblok= index of the current block
2028 : !! opt= 1 write the frozen-spin second-order quantities
2029 : !! 2 write the relaxed-spin second-order quantities
2030 : !! omega= frequency of the perturbation
2031 : !! qphon= momentum wave-vector
2032 : !! ucvol= unit-cell volume
2033 : !!
2034 : !! OUTPUT
2035 : !!
2036 : !! SOURCE
2037 :
2038 6 : subroutine mp_d3etot_print(ddb_lw,blkval,kblok,mpert,natom,nblok,opt,omega,prtvol,qeq0,qphnrm,qphon,ucvol,msize)
2039 :
2040 : !Arguments -------------------------------
2041 : !scalars
2042 : class(ddb_type),intent(in) :: ddb_lw
2043 : integer,intent(in) :: kblok,mpert,natom,nblok,opt,prtvol,msize
2044 : logical,intent(in) :: qeq0
2045 : real(dp),intent(in) :: ucvol
2046 : !arrays
2047 : real(dp),intent(in) :: omega(3)
2048 : real(dp),intent(in) :: blkval(2,msize,nblok)
2049 : real(dp),intent(inout) :: qphnrm(3),qphon(3,3)
2050 :
2051 : !Local variables -------------------------
2052 : !scalars
2053 : integer :: iblok,idir1,idir2,idir3,ipert1,ipert2,ipert3,irow,icol
2054 : integer :: rftyp,index,tmp
2055 : character(len=1000) :: msg
2056 : !arrays
2057 : integer :: rfelfd(4),rfmagn(4),rfphon(4),rfstrs(4),rffreq(4)
2058 : real(dp) :: val(2)
2059 : character(len=1) :: cart(3)=(/'x','y','z'/)
2060 :
2061 : ! *********************************************************************
2062 :
2063 2 : rfelfd(:)=0
2064 2 : rfphon(:)=0
2065 2 : rfstrs(:)=0
2066 2 : rfmagn(:)=0
2067 2 : rffreq(:)=0
2068 2 : rffreq(3)=1
2069 2 : rftyp = 33
2070 :
2071 2 : ipert3= natom + 9
2072 2 : idir3= 1
2073 2 : tmp=opt !
2074 : !IFCs
2075 2 : if (prtvol>1) then
2076 6 : rfphon(1:2)=1
2077 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2078 2 : & rffreq=rffreq)
2079 2 : if (iblok/=0.and.iblok==kblok) then
2080 : ! if (opt==1) then
2081 6 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of interatomic force constants')
2082 : ! else if (opt==2) then
2083 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of interatomic force constants')
2084 : ! end if
2085 6 : call wrtout([ab_out,std_out], ' atom1 dir atom2 dir Real Imag')
2086 14 : do ipert1= 1, natom
2087 50 : do idir1= 1, 3
2088 36 : irow=( ipert1-1)*3 + idir1
2089 252 : do ipert2= 1, natom
2090 900 : do idir2= 1, 3
2091 648 : icol=( ipert2-1)*3 + idir2
2092 : index = idir1 + &
2093 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2094 648 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2095 1944 : val(:)=blkval(:,index,kblok)
2096 : write(msg,'(2(i4,4x,a2,2x),2x,2es18.9)') &
2097 648 : & ipert1, cart(idir1), ipert2, cart(idir2), val(1), val(2)
2098 2160 : call wrtout([ab_out,std_out], msg)
2099 : end do
2100 : end do
2101 120 : call wrtout([ab_out,std_out], ' ')
2102 : end do
2103 : end do
2104 : end if
2105 : end if
2106 :
2107 2 : if (qeq0) then
2108 :
2109 : !Born charges
2110 3 : rfphon(1:2)=1
2111 3 : rfelfd(1:2)=2
2112 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2113 1 : & rffreq=rffreq)
2114 1 : if (iblok/=0.and.iblok==kblok) then
2115 : ! if (opt==1) then
2116 3 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of Born effective charges')
2117 : ! else if (opt==2) then
2118 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of Born effective charges')
2119 : ! end if
2120 3 : call wrtout([ab_out,std_out], ' E-dir atom dir Real Imag')
2121 1 : ipert1= natom + 2
2122 4 : do idir1= 1, 3
2123 21 : do ipert2= 1, natom
2124 75 : do idir2= 1, 3
2125 : index = idir1 + &
2126 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2127 54 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2128 162 : val(:)=blkval(:,index,kblok)
2129 : write(msg,'(3x,a2,7x,i3,4x,a2,2x,2es18.9)') &
2130 54 : & cart(idir1), ipert2, cart(idir2), val(1), val(2)
2131 180 : call wrtout([ab_out,std_out], msg)
2132 : end do
2133 : end do
2134 10 : call wrtout([ab_out,std_out], ' ')
2135 : end do
2136 : end if
2137 :
2138 : !Dielectric tensor
2139 : iblok=0
2140 1 : rfphon(:)=0
2141 3 : rfelfd(1:2)=2
2142 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2143 1 : & rffreq=rffreq)
2144 1 : if (iblok/=0.and.iblok==kblok) then
2145 : ! if (opt==1) then
2146 3 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of clamped-ion dielectric tensor')
2147 : ! else if (opt==2) then
2148 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of clamped-ion dielectric tensor')
2149 : ! end if
2150 3 : call wrtout([ab_out,std_out], ' dir dir Real Imag')
2151 1 : ipert1= ddb_lw%natom + 2
2152 1 : ipert2= ddb_lw%natom + 2
2153 4 : do idir2= 1, 3
2154 12 : do idir1= 1, 3
2155 : index = idir1 + &
2156 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2157 9 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2158 27 : val(:)=blkval(:,index,kblok)
2159 9 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
2160 18 : & val(1), val(2)
2161 30 : call wrtout([ab_out,std_out], msg)
2162 : end do
2163 10 : call wrtout([ab_out,std_out], ' ')
2164 : end do
2165 : end if
2166 :
2167 : !Magnetoelectric susceptibility
2168 : iblok=0
2169 1 : rfphon(:)=0
2170 1 : rfelfd(1)=0
2171 1 : rfelfd(2)=2
2172 1 : rfmagn(1)=1
2173 : rfmagn(2)=0
2174 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2175 1 : & rfmagn=rfmagn,rffreq=rffreq)
2176 1 : if (iblok/=0.and.iblok==kblok) then
2177 : ! if (opt==1) then
2178 3 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of clamped-ion magnetoelectric susceptibility')
2179 : ! else if (opt==2) then
2180 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of clamped-ion magnetoelectric susceptibility')
2181 : ! end if
2182 3 : call wrtout([ab_out,std_out], ' M-dir E-dir Real Imag')
2183 1 : ipert1= ddb_lw%natom + 5
2184 1 : ipert2= ddb_lw%natom + 2
2185 4 : do idir2= 1, 3
2186 12 : do idir1= 1, 3
2187 : index = idir1 + &
2188 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2189 9 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2190 27 : val(:)=blkval(:,index,kblok)/ucvol
2191 9 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
2192 18 : & val(1), val(2)
2193 30 : call wrtout([ab_out,std_out], msg)
2194 : end do
2195 10 : call wrtout([ab_out,std_out], ' ')
2196 : end do
2197 : end if
2198 :
2199 : end if
2200 :
2201 : !Magnetic susceptibility
2202 : iblok=0
2203 2 : rfphon(:)=0
2204 2 : rfelfd(:)=0
2205 2 : rfmagn(1)=1
2206 2 : rfmagn(2)=1
2207 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2208 2 : & rfmagn=rfmagn,rffreq=rffreq)
2209 2 : if (iblok/=0.and.iblok==kblok) then
2210 : ! if (opt==1) then
2211 6 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of clamped-ion magnetic susceptibility')
2212 : ! else if (opt==2) then
2213 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of clamped-ion magnetic susceptibility')
2214 : ! end if
2215 6 : call wrtout([ab_out,std_out], ' dir dir Real Imag')
2216 2 : ipert1= ddb_lw%natom + 5
2217 2 : ipert2= ddb_lw%natom + 5
2218 8 : do idir2= 1, 3
2219 24 : do idir1= 1, 3
2220 : index = idir1 + &
2221 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2222 18 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2223 54 : val(:)=blkval(:,index,kblok)/ucvol
2224 18 : write(msg,'(2x,a2,3x,a2,2x,2es18.9)' ) cart(idir1), cart(idir2), &
2225 36 : & val(1), val(2)
2226 60 : call wrtout([ab_out,std_out], msg)
2227 : end do
2228 20 : call wrtout([ab_out,std_out], ' ')
2229 : end do
2230 : end if
2231 :
2232 : !Magnetic Born effective charges
2233 : iblok=0
2234 2 : rfphon(1)=1
2235 2 : rfelfd(:)=0
2236 2 : rfmagn(1)=0
2237 : rfmagn(2)=1
2238 : call ddb_lw%get_block(iblok, qphon, qphnrm, rfphon, rfelfd, rfstrs, rftyp, omega=omega, &
2239 2 : & rfmagn=rfmagn,rffreq=rffreq)
2240 2 : if (iblok/=0.and.iblok==kblok) then
2241 : ! if (opt==1) then
2242 6 : call wrtout([ab_out,std_out], ' Frozen-spin Berry curvature of magnetic Born effective charges')
2243 : ! else if (opt==2) then
2244 : ! call wrtout([ab_out,std_out], ' Relaxed-spin Berry curvature of magnetic Born effective charges')
2245 : ! end if
2246 6 : call wrtout([ab_out,std_out], ' atom dir B-dir Real Imag')
2247 :
2248 2 : ipert2= ddb_lw%natom + 5
2249 14 : do ipert1= 1, natom
2250 48 : do idir1= 1, 3
2251 156 : do idir2= 1, 3
2252 : index = idir1 + &
2253 : & 3*((ipert1 - 1) + mpert*((idir2 - 1) + &
2254 108 : & 3*((ipert2 -1 ) + mpert*((idir3 - 1) + 3*(ipert3 - 1)))))
2255 324 : val(:)=blkval(:,index,kblok)
2256 : write(msg,'(i3,4x,a2,7x,a2,2x,2es18.9)') &
2257 108 : & ipert1, cart(idir1), cart(idir2), val(1), val(2)
2258 360 : call wrtout([ab_out,std_out], msg)
2259 : end do
2260 : end do
2261 38 : call wrtout([ab_out,std_out], ' ')
2262 : end do
2263 : end if
2264 :
2265 2 : end subroutine mp_d3etot_print
2266 : !!***
2267 :
2268 41464 : end module m_ddb_magpen
2269 : !!***
|