Line data Source code
1 : !!****m* ABINIT/m_ifc
2 : !! NAME
3 : !! m_ifc
4 : !!
5 : !! FUNCTION
6 : !! This module contains the declaration of data types and methods
7 : !! used to handle interatomic force constants.
8 : !!
9 : !! COPYRIGHT
10 : !! Copyright (C) 2011-2026 ABINIT group (XG,MJV,EB,MG,GA)
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 : !! SOURCE
16 :
17 : #if defined HAVE_CONFIG_H
18 : #include "config.h"
19 : #endif
20 :
21 : #include "abi_common.h"
22 :
23 : MODULE m_ifc
24 :
25 : use defs_basis
26 : use m_errors
27 : use m_abicore
28 : use m_xmpi
29 : use m_sort
30 : use m_cgtools
31 : use m_ddb
32 : use m_ddb_hdr
33 : use m_symkpt
34 : use netcdf
35 : use m_nctk
36 :
37 : use m_io_tools, only : open_file
38 : use m_numeric_tools, only : arth
39 : use m_fstrings, only : ktoa, int2char4, sjoin, itoa, ltoa, ftoa
40 : use m_matrix, only : matr3inv
41 : use m_special_funcs, only : abi_derfc
42 : use m_time, only : cwtime, cwtime_report, timab
43 : use m_copy, only : alloc_copy
44 : use m_pptools, only : printbxsf
45 : use m_lebedev, only : lebedev_t, lebedev_ngrids
46 : use m_ewald, only : ewald9, ewald9_2D
47 : use m_crystal, only : crystal_t
48 : use m_geometry, only : phdispl_cart2red, normv, mkrdim
49 : use m_kpts, only : kpts_ibz_from_kptrlatt, smpbz
50 : use m_bz_mesh, only : kpath_t
51 : use m_dynmat, only : canct9, dist9 , ifclo9, axial9, q0dy3_apply, q0dy3_calc, asrif9, dynmat_dq, &
52 : make_bigbox, canat9, chkrp9, ftifc_q2r, wght9, nanal9, gtdyn9, dymfz9, &
53 : massmult_and_breaksym, dfpt_phfrq, dfpt_prtph, d2cart_to_red, ftifc_r2q
54 :
55 : implicit none
56 :
57 : private
58 :
59 : public :: defwrite_nonana_terms
60 : ! Write to ncfile the phonon frequencies and displacements for q --> 0
61 : ! in the presence of non-analytical behaviour.
62 : !!***
63 :
64 : !!****t* m_ifc/ifc_type
65 : !! NAME
66 : !! ifc_type
67 : !!
68 : !! FUNCTION
69 : !! Contains the necessary data to interpolate the
70 : !! phonon bandstructure and eigenvectors in reciprocal space (ie.
71 : !! interatomic force constants and corresponding real space grid info).
72 : !!
73 : !! SOURCE
74 :
75 : type,public :: ifc_type
76 :
77 : integer :: natom = -1
78 : ! Number of atoms in the unit cell.
79 :
80 : integer :: mpert = -1
81 : ! Maximum number of ipert.
82 :
83 : integer :: asr = -1
84 : ! Option for the treatment of the Acoustic Sum Rule.
85 :
86 : integer :: brav = -1
87 : ! Option for the sampling of the BZ (anaddb input variable)
88 :
89 : real(dp) :: dielt_env = one
90 : ! Dielectric constant of environment for 2D materials electrostatics
91 :
92 : real(dp) :: dielt_thick(2) = zero
93 : ! Dielectric thickness of the 2D materials for electrostatics
94 :
95 : integer :: sys_dim = 1
96 : ! System dimmensionality for electrostatic treatment + rotational invariance
97 :
98 : integer :: dipdip = -1
99 : ! dipole dipole interaction flag.
100 :
101 : integer :: dipquad = -1
102 : ! dipole quadrupole interaction flag.
103 :
104 : integer :: quadquad = -1
105 : ! dipole quadrupole interaction flag.
106 :
107 : integer :: symdynmat = -1
108 : ! If equal to 1, the dynamical matrix is symmetrized in dfpt_phfrq before the diagonalization.
109 :
110 : integer :: nqshft = -1
111 : ! Number of shifts in the q-mesh (usually 1 since the mesh is gamma-centered!)
112 :
113 : integer :: nqibz = -1
114 : ! Number of points in the IBZ
115 :
116 : integer :: nqbz = -1
117 : ! Number of points in the full BZ
118 :
119 : integer :: nrpt = -1
120 : ! Number of real space points used to integrate IFC (for interpolation of dynamical matrices)
121 :
122 : integer :: ngqpt(3) = -1
123 : ! Number of division in the Q mesh.
124 :
125 : integer :: ewald_option = -1
126 : ! Option for the ewald sum
127 :
128 : real(dp) :: eta = -one
129 : ! eta: parameter used to split R and G-space summation. See ewald9.
130 :
131 : real(dp) :: rprim(3,3),gprim(3,3),acell(3)
132 : ! These values are used to call anaddb routines that don't use rprimd, gprimd
133 :
134 : real(dp) :: dielt(3,3)
135 : ! Dielectric tensor (Cartesian coordinates)
136 :
137 : real(dp) :: omega_minmax(2)
138 : ! Min and max frequency obtained on the initial ab-initio q-mesh (-+ 30 cmm1)
139 : ! Used to generate frequency meshes for DOSes.
140 :
141 : real(dp) :: r_inscribed_sphere
142 : ! radius of biggest sphere inscribed in the WS supercell
143 :
144 : real(dp),allocatable :: amu(:)
145 : ! amu(ntypat)
146 : ! mass of the atoms (atomic mass unit)
147 :
148 : real(dp),allocatable :: atmfrc(:,:,:,:,:)
149 : ! atmfrc(3,natom,3,natom,nrpt)
150 : ! Inter atomic forces in real space
151 :
152 : integer,allocatable :: cell(:,:)
153 : ! cell(nrpt,3)
154 : ! Give the index of the cell and irpt
155 :
156 : real(dp),allocatable :: ewald_atmfrc(:,:,:,:,:)
157 : ! Ewald_atmfrc(3,natom,3,natom,nrpt)
158 : ! Ewald Inter atomic forces in real space
159 :
160 : real(dp),allocatable :: short_atmfrc(:,:,:,:,:)
161 : ! short_atmfrc(3,natom,3,natom,nrpt)
162 : ! Short range part of Inter atomic forces in real space
163 :
164 : real(dp),allocatable :: qshft(:,:)
165 : ! qshft(3,nqshft)
166 : ! The shifts of the q-mesh
167 :
168 : real(dp), allocatable :: rpt(:,:)
169 : ! rpt(3,nrpt)
170 : ! Real space points in canonical type coordinates.
171 :
172 : real(dp),allocatable :: wghatm(:,:,:)
173 : ! wghatm(natom,natom,nrpt)
174 : ! Weights for each point and atom in the Wigner Seitz supercell in real space.
175 :
176 : real(dp),allocatable :: rcan(:,:)
177 : ! rcan(3,natom)
178 : ! Atomic position in canonical coordinates.
179 :
180 : real(dp),allocatable :: trans(:,:)
181 : ! trans(3,natom)
182 : ! Atomic translations: xred = rcan + trans
183 :
184 : real(dp),allocatable :: dyewq0(:,:,:)
185 : ! dyewq0(3,3,natom)
186 : ! Atomic electrostatic self-interaction correction to the dynamical matrix (only when dipdip = 1).
187 :
188 : real(dp),allocatable :: zeff(:,:,:)
189 : ! zeff(3,3,natom)
190 : ! Born effective charge on each atom, versus electric field and atomic displacement.
191 : ! Cartesian coordinates
192 :
193 : real(dp),allocatable :: qdrp_cart(:,:,:,:)
194 : ! qdrp_cart(3,3,3,natom)
195 : ! Quadrupole tensor on each atom
196 : ! Cartesian coordinates
197 :
198 : real(dp),allocatable :: qibz(:,:)
199 : ! qibz(3,nqibz))
200 : ! List of q-points in the IBZ
201 :
202 : real(dp),allocatable :: wtq(:)
203 : ! wtq(nqibz))
204 : ! q-point Weights.
205 :
206 : real(dp),allocatable :: qbz(:,:)
207 : ! qbz(3,nqbz))
208 : ! List of q-points in the full BZ
209 :
210 : real(dp),allocatable :: dynmat(:,:,:,:,:,:)
211 : ! dynmat(2,3,natom,3,natom,nqbz))
212 : ! dynamical matrices relative to the q points of the BZ. sampling
213 : ! Note that the long-range dip-dip part has been removed if dipdip = 1
214 : ! Moreover the array is multiplied by a phase shift in mkifc9.
215 :
216 : contains
217 :
218 : procedure :: free => ifc_free
219 : ! Release memory.
220 :
221 : procedure :: print => ifc_print
222 : ! Print info on the object.
223 :
224 : procedure :: fourq => ifc_fourq
225 : ! Use Fourier interpolation to compute interpolated frequencies w(q) and eigenvectors e(q).
226 :
227 : procedure :: get_dcdq => ifc_get_dcdq
228 : ! Compute first derivative of reciprocal-space IFCs based on IFCs.
229 :
230 : procedure :: get_dwdq => ifc_get_dwdq
231 : ! Compute phonon group velocities at an arbitrary q-point.
232 :
233 : procedure :: get_phmesh => ifc_get_phmesh
234 : ! Build linear mesh for phonons.
235 :
236 : procedure :: speedofsound => ifc_speedofsound
237 : ! Compute the speed of sound by averaging phonon group velocities.
238 :
239 : procedure :: write => ifc_write
240 : ! Print the ifc (output, netcdf and text file).
241 :
242 : procedure :: outphbtrap => ifc_outphbtrap
243 : ! Print out phonon frequencies on regular grid for BoltzTrap code.
244 :
245 : procedure :: printbxsf => ifc_printbxsf
246 : ! Output phonon isosurface in Xcrysden format.
247 :
248 : procedure :: calcnwrite_nana_terms => ifc_calcnwrite_nana_terms
249 : ! Compute phonons for q--> 0 with LO-TO.
250 :
251 : procedure :: calcnwrite_nana_terms_qpath => ifc_calcnwrite_nana_terms_qpath
252 : ! Compute phonons for q--> 0 with LO-TO from qpath_t and write results to netcdf file.
253 :
254 : procedure :: init => ifc_init
255 : ! Constructor from DDB datatype.
256 :
257 : procedure :: from_file => ifc_from_file
258 : ! Constructor from filename.
259 :
260 : procedure :: to_ddb => ifc_to_ddb
261 : ! Construct a DDB object.
262 :
263 : end type ifc_type
264 : !!***
265 :
266 : !----------------------------------------------------------------------
267 :
268 : contains !===========================================================
269 : !!***
270 :
271 : !----------------------------------------------------------------------
272 :
273 : !!****f* m_ifc/ifc_free
274 : !! NAME
275 : !! ifc_free
276 : !!
277 : !! FUNCTION
278 : !! Deallocate memory for the ifc_type structure
279 : !!
280 : !! SOURCE
281 :
282 1536 : subroutine ifc_free(ifc)
283 :
284 : !Arguments ------------------------------------
285 : class(ifc_type),intent(inout) :: ifc
286 : ! ************************************************************************
287 :
288 1536 : ABI_SFREE(ifc%amu)
289 1536 : ABI_SFREE(ifc%atmfrc)
290 1536 : ABI_SFREE(ifc%cell)
291 1536 : ABI_SFREE(ifc%ewald_atmfrc)
292 1536 : ABI_SFREE(ifc%short_atmfrc)
293 1536 : ABI_SFREE(ifc%qshft)
294 1536 : ABI_SFREE(ifc%rpt)
295 1536 : ABI_SFREE(ifc%wghatm)
296 1536 : ABI_SFREE(ifc%rcan)
297 1536 : ABI_SFREE(ifc%trans)
298 1536 : ABI_SFREE(ifc%dyewq0)
299 1536 : ABI_SFREE(ifc%qibz)
300 1536 : ABI_SFREE(ifc%wtq)
301 1536 : ABI_SFREE(ifc%qbz)
302 1536 : ABI_SFREE(ifc%zeff)
303 1536 : ABI_SFREE(ifc%qdrp_cart)
304 1536 : ABI_SFREE(ifc%dynmat)
305 :
306 1536 : end subroutine ifc_free
307 : !!***
308 :
309 : !----------------------------------------------------------------------
310 :
311 : !!****f* m_ifc/ifc_init
312 : !! NAME
313 : !! ifc_init
314 : !!
315 : !! FUNCTION
316 : !! Initialize the dynamical matrix as well as the IFCs.
317 : !! taking into account the dipole-dipole, dipole-quadrupole and quadrupole-quadrupole interaction.
318 : !!
319 : !! INPUTS
320 : !! crystal<type(crystal_t)> = Information on the crystalline structure.
321 : !! ddb<type(ddb_type)> = Database with derivatives.
322 : !! brav=bravais lattice (1 or -1=simple lattice, 2=face centered lattice, 3=centered lattice, 4=hexagonal lattice)
323 : !! asr= Option for the imposition of the ASR
324 : !! 0 => no ASR,
325 : !! 1 => modify "asymmetrically" the diagonal element
326 : !! 2 => modify "symmetrically" the diagonal element
327 : !! symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
328 : !! dipdip=
329 : !! if 0, no dipole-dipole interaction was subtracted in atmfrc
330 : !! if 1, atmfrc has been build without dipole-dipole part
331 : !! rfmeth =
332 : !! 1 if non-stationary block
333 : !! 2 if stationary block
334 : !! 3 if third order derivatives
335 : !! dielt(3,3)=dielectric tensor.
336 : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
337 : !! prtsrlr: TODO: TO BE REMOVED
338 : !! enunit: TODO: TO BE REMOVED
339 : !! dielt(3,3)=dielectric tensor
340 : !! ngqpt_in = input values of ngqpt
341 : !! nqshft=Number of shifths in q-grid.
342 : !! q1shft(3,nqshft)=Shifts for q-grid
343 : !! nsphere=number of atoms to be included in the cut-off sphere for interatomic force constant.
344 : !! 0: maximum extent allowed by the grid.
345 : !! > 0: Apply cutoff
346 : !! -1: Analyze the effect of different nsphere values on the phonon spectrum, in particular the
347 : !! frequencies around gamma.
348 : !! rifcsph=radius for cutoff of IFC.
349 : !! comm=MPI communicator.
350 : !! [Ifc_coarse]=Optional.
351 : !! [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
352 : !! [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part
353 : !! prtout=write info to the output and log files.
354 : !!
355 : !! OUTPUT
356 : !! Ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
357 : !!
358 : !! SOURCE
359 :
360 242 : subroutine ifc_init(Ifc,crystal,ddb,brav,asr,symdynmat,dipdip,&
361 242 : rfmeth,ngqpt_in,nqshft,q1shft,dielt,zeff,qdrp_cart,nsphere,rifcsph,&
362 : prtsrlr,enunit,& ! TODO: TO BE REMOVED
363 : sys_dim,comm, &
364 : Ifc_coarse,dipquad,quadquad,dielt_env,dielt_thick,prtout) ! Optional
365 :
366 : !Arguments ------------------------------------
367 : class(ifc_type),intent(inout) :: Ifc
368 : integer,intent(in) :: asr,dipdip,symdynmat,nqshft,rfmeth,nsphere,comm,sys_dim
369 : real(dp),intent(in) :: rifcsph
370 : type(crystal_t),intent(in) :: Crystal
371 : type(ddb_type),intent(in) :: ddb
372 : type(ifc_type),optional,intent(in) :: Ifc_coarse
373 : integer,optional,intent(in) :: dipquad, quadquad
374 : logical, optional, intent(in) :: prtout
375 : real(dp), optional, intent(in) :: dielt_env,dielt_thick(2)
376 :
377 : !arrays
378 : integer,intent(in) :: ngqpt_in(3)
379 : real(dp),intent(in) :: q1shft(3,nqshft)
380 : real(dp),intent(in) :: dielt(3,3),zeff(3,3,Crystal%natom)
381 : real(dp),intent(in) :: qdrp_cart(3,3,3,Crystal%natom)
382 : !anaddb variables (TO BE REMOVED)
383 : integer,intent(in) :: prtsrlr,enunit,brav
384 :
385 : !Local variables -------------------------
386 : !scalars
387 : integer,parameter :: timrev1=1,iout0=0,chksymbreak0=0
388 : integer :: mpert,iout,iqpt,mqpt,nsym,ntypat,iq_ibz,iq_bz,ii,natom
389 : integer :: nqbz,option,plus,sumg0,irpt,irpt_new, nprocs,my_rank,my_ierr,ierr
390 : logical :: prtout_
391 : real(dp),parameter :: qphnrm=one
392 : real(dp) :: cpu,wall,gflops,xval,rcut_min,r_inscribed_sphere,toldist
393 : character(len=500*4) :: msg
394 1452 : type(ifc_type) :: ifc_tmp
395 : !arrays
396 : integer :: ngqpt(9),qptrlatt(3,3)
397 484 : integer,allocatable :: qmissing(:),ibz2bz(:),bz2ibz_smap(:,:)
398 : real(dp) :: gprim(3,3),rprim(3,3),qpt(3),rprimd(3,3), gprim_tmp(3,3), rprim_tmp(3,3)
399 968 : real(dp):: rcan(3,Crystal%natom),trans(3,Crystal%natom),dyewq0(3,3,Crystal%natom)
400 484 : real(dp) :: displ_cart(2*3*Crystal%natom*3*Crystal%natom)
401 484 : real(dp) :: phfrq(3*Crystal%natom)
402 484 : real(dp) :: eigvec(2,3,Crystal%natom,3,Crystal%natom)
403 484 : real(dp),allocatable :: dyew(:,:,:,:,:),out_d2cart(:,:,:,:,:)
404 242 : real(dp),allocatable :: dynmatfull(:,:,:,:,:,:),dynmat_sr(:,:,:,:,:,:),dynmat_lr(:,:,:,:,:,:) ! for OmegaSRLR
405 242 : real(dp),allocatable :: wtq(:),wtq_folded(:),qbz(:,:)
406 : !******************************************************************
407 : ! TODO
408 : ! - Remove brav
409 : ! - Separate into ifc_init and ifc_from_ddb
410 :
411 242 : nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
412 242 : call cwtime(cpu, wall, gflops, "start")
413 :
414 242 : mpert = ddb%mpert
415 242 : iout = ab_out
416 242 : prtout_ = .true.
417 242 : if (present(prtout)) prtout_ = prtout
418 :
419 242 : nsym = Crystal%nsym
420 242 : natom = Crystal%natom
421 242 : ntypat = Crystal%ntypat
422 3146 : rprimd = Crystal%rprimd
423 :
424 968 : ngqpt=0; ngqpt(1:3)=ngqpt_in(1:3)
425 :
426 : ! Copy important parameters in Ifc
427 242 : Ifc%natom = natom
428 242 : Ifc%mpert = mpert
429 242 : Ifc%asr = asr
430 242 : Ifc%brav = brav
431 242 : Ifc%dielt_env=0; if (present(dielt_env)) Ifc%dielt_env = dielt_env
432 836 : Ifc%dielt_thick(:)=0; if (present(dielt_thick)) Ifc%dielt_thick = dielt_thick(1:2)
433 242 : Ifc%sys_dim = sys_dim
434 242 : Ifc%dipdip = abs(dipdip)
435 242 : Ifc%dipquad=0; if (present(dipquad)) Ifc%dipquad = dipquad
436 242 : Ifc%quadquad=0; if (present(quadquad)) Ifc%quadquad = quadquad
437 242 : Ifc%symdynmat = symdynmat
438 968 : Ifc%ngqpt = ngqpt_in(1:3)
439 242 : Ifc%nqshft = nqshft
440 242 : call alloc_copy(q1shft(:,1:Ifc%nqshft),Ifc%qshft)
441 242 : Ifc%ewald_option = 0; if (dipdip < 0) Ifc%ewald_option = 1 !HM TODO: expose this in the init?
442 :
443 :
444 : ! These two ways of defining rprim, gprim, acell should be equivalent.
445 : ! Note that the crystal object does not know about acell.
446 3146 : Ifc%rprim = ddb%rprim
447 3146 : Ifc%gprim = ddb%gprim
448 968 : Ifc%acell = ddb%acell
449 : !Ifc%rprim = crystal%rprimd
450 : !Ifc%gprim = crystal%gprimd
451 : !Ifc%acell = one
452 : !
453 : !! When brav/=1, we need specific values of rprim.
454 : !if (abs(brav)/=1) then
455 : ! if (brav==2) then
456 : ! ! Face Centered Lattice
457 : ! fac = half_sqrt2
458 : ! else if (brav==3) then
459 : ! ! Body Centered Cubic Lattice
460 : ! fac = half_sqrt3
461 : ! else if (brav==4) then
462 : ! ! Hexagonal Lattice
463 : ! fac = one
464 : ! end if
465 : ! Ifc%acell(1) = sqrt(rprimd(1,1)**2 + rprimd(2,1)**2 + rprimd(3,1)**2) / fac
466 : ! Ifc%acell(2) = sqrt(rprimd(1,2)**2 + rprimd(2,2)**2 + rprimd(3,2)**2) / fac
467 : ! Ifc%acell(3) = sqrt(rprimd(1,3)**2 + rprimd(2,3)**2 + rprimd(3,3)**2) / fac
468 : ! do ii=1,3
469 : ! Ifc%rprim(ii, 1) = rprimd(ii, 1) / Ifc%acell(1)
470 : ! Ifc%rprim(ii, 2) = rprimd(ii, 2) / Ifc%acell(2)
471 : ! Ifc%rprim(ii, 3) = rprimd(ii, 3) / Ifc%acell(3)
472 : ! Ifc%gprim(ii, 1) = crystal%gprimd(ii, 1) * Ifc%acell(1)
473 : ! Ifc%gprim(ii, 2) = crystal%gprimd(ii, 2) * Ifc%acell(2)
474 : ! Ifc%gprim(ii, 3) = crystal%gprimd(ii, 3) * Ifc%acell(3)
475 : ! end do
476 : !
477 : !end if
478 :
479 : ! Check if the rprim are coherent with the choice used in the interatomic forces generation
480 242 : call chkrp9(Ifc%brav,Ifc%rprim)
481 :
482 6050 : rprim = Ifc%rprim; gprim = Ifc%gprim
483 :
484 : ! -------------------------------------------------------------------------- !
485 : ! Compute dyewq0, the correction to be applied to the Ewald, see Eq.(71) of PRB55, 10355 (1997).
486 8549 : dyewq0 = zero
487 242 : if ((Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1).and. (Ifc%asr==1.or.Ifc%asr==2.or.Ifc%asr==6)) then
488 : ! Calculation of the non-analytical part for q=0
489 158 : sumg0=0
490 158 : qpt(:)=zero
491 790 : ABI_MALLOC(dyew,(2,3,natom,3,natom))
492 158 : if (sys_dim==1) then
493 156 : if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
494 : call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
495 3 : Crystal%xred,zeff,qdrp_cart,ifc%eta,option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
496 : else
497 : call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
498 153 : Crystal%xred,zeff,qdrp_cart,ifc%eta, option=ifc%ewald_option)
499 : end if
500 : else
501 : ! 2D materials are embedded in a dielectric environment (typically vacuum in DFT calculations)
502 : ! which leads to a different long-range electrostatics than in 2D. The next routine allows
503 : ! to estimate it.
504 2 : call ewald9_2D(natom,ddb%acell,Crystal%xred,rprim,dielt,dyew,qpt,zeff,qdrp_cart,dielt_env,dielt_thick,sys_dim)
505 : end if
506 158 : call q0dy3_calc(natom,dyewq0,dyew,Ifc%asr)
507 158 : ABI_FREE(dyew)
508 : end if
509 :
510 : ! -------------------------------------------------------------------------- !
511 : ! Setup q-points
512 :
513 : ! Sample the Brillouin zone
514 242 : option=1
515 242 : qptrlatt = 0; qptrlatt(1,1)=ngqpt(1); qptrlatt(2,2)=ngqpt(2); qptrlatt(3,3)=ngqpt(3)
516 242 : mqpt=ngqpt(1)*ngqpt(2)*ngqpt(3)*nqshft
517 242 : if (Ifc%brav==2) mqpt=mqpt/2
518 242 : if (Ifc%brav==3) mqpt=mqpt/4
519 :
520 726 : ABI_MALLOC(qbz,(3,mqpt))
521 242 : call smpbz(Ifc%brav,ab_out,qptrlatt,mqpt,nqbz,nqshft,option,q1shft,qbz,prtout=prtout_)
522 :
523 : ! Find the irreducible zone (qibz)
524 726 : ABI_MALLOC(ibz2bz, (nqbz))
525 726 : ABI_MALLOC(wtq_folded, (nqbz))
526 484 : ABI_MALLOC(wtq, (nqbz))
527 26542 : wtq = one / nqbz ! Weights sum up to one
528 726 : ABI_MALLOC(bz2ibz_smap, (6, nqbz))
529 :
530 : ! FIXME: timrev1 should be set to 0 if TR cannot be used
531 : call symkpt(chksymbreak0,crystal%gmet,ibz2bz,iout0,qbz,nqbz,ifc%nqibz,crystal%nsym,&
532 242 : crystal%symrec,timrev1,wtq,wtq_folded, bz2ibz_smap, xmpi_comm_self)
533 :
534 242 : ABI_FREE(bz2ibz_smap)
535 :
536 726 : ABI_MALLOC(ifc%qibz, (3,ifc%nqibz))
537 726 : ABI_MALLOC(ifc%wtq, (ifc%nqibz))
538 3394 : do iq_ibz=1,ifc%nqibz
539 12608 : ifc%qibz(:,iq_ibz) = qbz(:, ibz2bz(iq_ibz))
540 3394 : ifc%wtq(iq_ibz) = wtq_folded(ibz2bz(iq_ibz))
541 : end do
542 242 : ABI_FREE(ibz2bz)
543 242 : ABI_FREE(wtq_folded)
544 242 : ABI_FREE(wtq)
545 :
546 : ! -------------------------------------------------------------------------- !
547 : ! Setup dynamical matrix and IFC matrix
548 :
549 1452 : ABI_MALLOC(Ifc%dynmat,(2,3,natom,3,natom,nqbz))
550 :
551 : ! This is needed to preserve the behavior of the old implementation with canonical coordinate.
552 242 : if (Ifc%brav == 1) then
553 2548 : gprim_tmp = Crystal%gprimd
554 196 : rprim_tmp = rprimd
555 : else
556 46 : gprim_tmp = gprim
557 46 : rprim_tmp = rprim
558 : endif
559 :
560 : ! Find symmetrical dynamical matrices
561 242 : if (.not.present(Ifc_coarse)) then
562 : ! Each q-point in the BZ mush be the symmetrical of one of the qpts in the ddb file.
563 : ! SP - gprimd and rprimd is required instead of gprim and rprim for non-diagonal supercells.
564 : call symdm9(ddb, &
565 : Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
566 241 : Crystal%symrec, Crystal%symrel, comm)
567 :
568 : else
569 : ! Symmetrize the qpts in the BZ using the q-points in the ddb.
570 : ! Then use Ifc_coarse to fill the missing entries with Fourier interpolated matrices.
571 : !
572 : ! TODO: The previous version of refineblk was hacking the DDB database to add the q-points in the **IBZ**
573 : ! Then D(q) was symmetrized in symdm9. This version avoids the symmetrization: the q-points
574 : ! in the BZ that are not in the coarse q-mesh are obtained by an explicit FT.
575 : ! This means that the final D(q) may break some symmetry in q-space if the FT does not preserve it.
576 : ! The most elegant approach would be to get D(q_ibz) via FT if q_ibz is not in the coarse mesh and then
577 : ! call symdm9 to get D(q) for each q point in the star of q_ibz.
578 1 : call wrtout(std_out,"Will fill missing qpoints in the full BZ using the coarse q-mesh")
579 :
580 : call symdm9(ddb, &
581 : Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
582 1 : Crystal%symrec,Crystal%symrel,comm, qmissing=qmissing)
583 :
584 : ! Compute dynamical matrix with Fourier interpolation on the coarse q-mesh.
585 1 : write(msg,"(a,i0,a)")"Will use Fourier interpolation to construct D(q) for ",size(qmissing)," q-points"
586 1 : call wrtout(std_out,msg)
587 :
588 4 : ABI_MALLOC(out_d2cart, (2,3,natom,3,natom))
589 97 : do ii=1,size(qmissing)
590 96 : iq_bz = qmissing(ii)
591 384 : qpt = qbz(:,iq_bz)
592 : ! TODO: check dipdip option and phase, but I think this is correct!
593 96 : call Ifc_coarse%fourq(Crystal,qpt,phfrq,displ_cart,out_d2cart=out_d2cart)
594 3361 : Ifc%dynmat(:,:,:,:,:,iq_bz) = out_d2cart
595 : end do
596 :
597 1 : ABI_FREE(qmissing)
598 1 : ABI_FREE(out_d2cart)
599 : end if
600 :
601 : ! OmegaSRLR: Store full dynamical matrix for decomposition into short- and long-range parts
602 968 : ABI_MALLOC(dynmatfull,(2,3,natom,3,natom,nqbz))
603 12537758 : dynmatfull=Ifc%dynmat
604 :
605 242 : if (Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1) then
606 : ! Take off the dipole-dipole part of the dynamical matrix
607 158 : if (prtout_) call wrtout(std_out, " Will extract the dipole-dipole part for every wavevector")
608 632 : ABI_MALLOC(dyew,(2,3,natom,3,natom))
609 :
610 11530 : do iqpt=1,nqbz
611 11372 : if (mod(iqpt, nprocs) /= my_rank) then ! mpi-parallelism
612 1988 : ifc%dynmat(:,:,:,:,:,iqpt) = zero; cycle
613 : end if
614 45472 : qpt(:)=qbz(:,iqpt)
615 11368 : sumg0=0
616 11368 : if (sys_dim==1) then
617 : ! 3D case
618 11031 : if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
619 : call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
620 : Crystal%xred,zeff,qdrp_cart, ifc%eta, &
621 48 : option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
622 : else
623 : call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
624 : Crystal%xred,zeff,qdrp_cart, ifc%eta, &
625 10983 : option=ifc%ewald_option)
626 : end if
627 : else
628 : ! 2D case
629 337 : call ewald9_2D(natom,ddb%acell,Crystal%xred,rprim,dielt,dyew,qpt,zeff,qdrp_cart,one,dielt_thick,sys_dim)
630 : end if
631 11368 : call q0dy3_apply(natom,dyewq0,dyew)
632 11368 : plus=0
633 : ! Implement Eq.(76) of Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], possibly generalized for quadrupoles
634 11526 : call nanal9(dyew,Ifc%dynmat,iqpt,natom,nqbz,plus)
635 : end do
636 :
637 158 : call xmpi_sum(ifc%dynmat, comm, ierr)
638 158 : ABI_FREE(dyew)
639 : !if (prtout_) call wrtout(std_out, " Done")
640 : end if
641 :
642 : ! OmegaSRLR: Store the short-range dynmat and compute long-range as difference
643 1452 : ABI_MALLOC(dynmat_sr,(2,3,natom,3,natom,nqbz))
644 968 : ABI_MALLOC(dynmat_lr,(2,3,natom,3,natom,nqbz))
645 12537758 : dynmat_sr=Ifc%dynmat
646 12537758 : dynmat_lr=dynmatfull-dynmat_sr
647 :
648 : ! Now, take care of the remaining part of the dynamical matrix
649 : ! Move to canonical normalized coordinates
650 242 : call canat9(Ifc%brav,natom,rcan,rprim,trans,Crystal%xred)
651 :
652 : ! Multiply the dynamical matrix by a phase shift
653 : option=1
654 242 : call dymfz9(Ifc%dynmat,natom,nqbz,gprim,option,qbz,trans)
655 :
656 : ! -------------------------------------------------------------------------- !
657 : ! Compute interatomic forces in real space
658 :
659 : ! Create the Big Box of R vectors in real space and compute the number of points (cells) in real space
660 242 : call make_bigbox(Ifc%brav,ifc_tmp%cell,ngqpt,nqshft,rprim,ifc_tmp%nrpt,ifc_tmp%rpt)
661 :
662 : ! Weights associated to these R points and to atomic pairs
663 1210 : ABI_MALLOC(ifc_tmp%wghatm, (natom, natom, ifc_tmp%nrpt))
664 :
665 : ! HM: this tolerance is highly dependent on the compilation/architecture
666 : ! numeric errors in the DDB text file. Try a few tolerances and check whether all the weights are found.
667 242 : toldist = tol8
668 243 : do while (toldist <= tol6)
669 : ! Note ngqpt(9) with intent(inout)!
670 : call wght9(Ifc%brav,gprim,natom,ngqpt,nqbz,nqshft,ifc_tmp%nrpt,q1shft,rcan,&
671 243 : ifc_tmp%rpt,rprimd,toldist,r_inscribed_sphere,ifc_tmp%wghatm,my_ierr)
672 243 : call xmpi_max(my_ierr, ierr, comm, ii)
673 243 : if (ierr > 0) toldist = toldist * 10
674 243 : if (ierr == 0) exit
675 : end do
676 :
677 242 : if (ierr > 0) then
678 : write(msg, '(3a,es14.4,2a,i0, 14a)' ) &
679 0 : 'The sum of the weight is not equal to nqpt.',ch10,&
680 0 : 'The sum of the weights is: ',sum(ifc_tmp%wghatm),ch10,&
681 0 : 'The number of q-points is: ',nqbz, ch10, &
682 0 : 'This might have several sources.',ch10,&
683 0 : 'If toldist is larger than 1.0e-8, the atom positions might be loose.',ch10,&
684 0 : 'and the q point weights not computed properly.',ch10,&
685 0 : 'Action: make input atomic positions more symmetric.',ch10,&
686 0 : 'Otherwise, you might increase "buffer" in m_dynmat.F90 see bigbx9 subroutine and recompile.',ch10,&
687 0 : 'Actually, this can also happen when ngqpt is 0 0 0,',ch10,&
688 0 : 'if abs(brav) /= 1, in this case you should change brav to 1. If brav is already set to 1 (default) try -1.'
689 0 : ABI_ERROR(msg)
690 : end if
691 :
692 : ! Fourier transform of the dynamical matrices (q-->R)
693 1452 : ABI_MALLOC(ifc_tmp%atmfrc, (3,natom,3,natom,ifc_tmp%nrpt))
694 242 : call ftifc_q2r(ifc_tmp%atmfrc,Ifc%dynmat,gprim,natom,nqbz,ifc_tmp%nrpt,ifc_tmp%rpt,qbz, comm)
695 :
696 : ! Eventually impose Acoustic Sum Rule on the interatomic forces
697 242 : if (Ifc%asr > 0) call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
698 :
699 : ! The interatomic forces have been calculated
700 242 : write(msg, '(2a)')ch10,' The interatomic forces have been obtained '
701 634 : if (prtout_) call wrtout([std_out, ab_out], msg)
702 242 : call cwtime_report(" ifc_init1", cpu, wall, gflops)
703 :
704 : ! Apply cutoff on ifc if needed
705 242 : if (nsphere > 0 .or. abs(rifcsph) > tol10) then
706 3 : call wrtout(std_out, ' Apply cutoff on IFCs.')
707 3 : call wrtout(std_out, sjoin(" nsphere:", itoa(nsphere), ", rifcsph:", ftoa(rifcsph)))
708 3 : call wrtout(std_out, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(r_inscribed_sphere)))
709 3 : call corsifc9(Ifc%acell,gprim,natom,ifc_tmp%nrpt,nsphere,rifcsph,rcan,rprim,ifc_tmp%rpt,rcut_min,ifc_tmp%wghatm)
710 3 : if (Ifc%asr > 0) then
711 3 : call wrtout(std_out, ' Enforcing ASR on cutoffed IFCs.')
712 3 : call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
713 : end if
714 : end if
715 :
716 : ! Only conserve the necessary points in rpt: in the FT algorithm the order of the points is unimportant
717 : ! In the case of effective potential, we need to keep all the points
718 242 : Ifc%nrpt = 0
719 552916 : do irpt=1,ifc_tmp%nrpt
720 11065688 : if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) Ifc%nrpt = Ifc%nrpt + 1
721 : end do
722 :
723 8689738 : ABI_CALLOC(Ifc%atmfrc,(3,natom,3,natom,Ifc%nrpt))
724 169430 : ABI_CALLOC(Ifc%rpt,(3,Ifc%nrpt))
725 169430 : ABI_CALLOC(Ifc%cell,(3,Ifc%nrpt))
726 851252 : ABI_CALLOC(Ifc%wghatm,(natom,natom,Ifc%nrpt))
727 8689738 : ABI_CALLOC(Ifc%short_atmfrc,(3,natom,3,natom,Ifc%nrpt))
728 8689496 : ABI_CALLOC(Ifc%ewald_atmfrc,(3,natom,3,natom,Ifc%nrpt))
729 :
730 : irpt_new = 1
731 552916 : do irpt = 1, ifc_tmp%nrpt
732 11065688 : if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) then
733 8688528 : Ifc%atmfrc(:,:,:,:,irpt_new) = ifc_tmp%atmfrc(:,:,:,:,irpt)
734 168704 : Ifc%rpt(:,irpt_new) = ifc_tmp%rpt(:,irpt)
735 850042 : Ifc%wghatm(:,:,irpt_new) = ifc_tmp%wghatm(:,:,irpt)
736 168704 : Ifc%cell(:,irpt_new) = ifc_tmp%cell(:,irpt)
737 42176 : Ifc%r_inscribed_sphere = r_inscribed_sphere
738 42176 : irpt_new = irpt_new + 1
739 : end if
740 : end do
741 :
742 : !write(std_out,*)"nrpt before filter:", ifc_tmp%nrpt, ", after: ", ifc%nrpt
743 : !do irpt=1,ifc%nrpt
744 : ! write(std_out,*)ifc%rpt(:,irpt), (ifc%wghatm(ii,ii,irpt), ii=1,natom)
745 : !end do
746 :
747 242 : call ifc_tmp%free()
748 :
749 : ! -------------------------------------------------------------------------- !
750 :
751 : ! Copy other useful arrays.
752 3146 : Ifc%dielt = dielt
753 242 : Ifc%nqbz = nqbz
754 :
755 242 : call alloc_copy(rcan, Ifc%rcan)
756 242 : call alloc_copy(trans, Ifc%trans)
757 242 : call alloc_copy(dyewq0, Ifc%dyewq0)
758 242 : call alloc_copy(qbz(:,1:nqbz), Ifc%qbz)
759 242 : call alloc_copy(zeff, Ifc%zeff)
760 242 : call alloc_copy(qdrp_cart, Ifc%qdrp_cart)
761 242 : call alloc_copy(crystal%amu, Ifc%amu)
762 :
763 : ! Compute min/max ph frequency with ab-initio q-mesh.
764 242 : ifc%omega_minmax(1) = huge(one); ifc%omega_minmax(2) = -huge(one)
765 3394 : do iq_ibz=1,ifc%nqibz
766 3152 : if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
767 3144 : call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), phfrq, displ_cart)
768 38088 : ifc%omega_minmax(1) = min(ifc%omega_minmax(1), minval(phfrq))
769 38338 : ifc%omega_minmax(2) = max(ifc%omega_minmax(2), maxval(phfrq))
770 : end do
771 242 : xval = ifc%omega_minmax(1); call xmpi_min(xval, ifc%omega_minmax(1), comm, ierr)
772 242 : xval = ifc%omega_minmax(2); call xmpi_max(xval, ifc%omega_minmax(2), comm, ierr)
773 : ! Enlarge boundaries by 30 cm-1
774 242 : ifc%omega_minmax(1) = ifc%omega_minmax(1) - 30.0_dp/Ha_cmm1
775 242 : ifc%omega_minmax(2) = ifc%omega_minmax(2) + 30.0_dp/Ha_cmm1
776 :
777 : ! TODO (This is to be suppressed in a future version)
778 242 : if (prtsrlr == 1) then
779 : ! Check that the starting values are well reproduced.
780 0 : write(msg, '(2a)' )' mkifc9 : now check that the starting values ',&
781 0 : ' are reproduced after the use of interatomic forces '
782 0 : if (prtout_) call wrtout(std_out, msg)
783 0 : do iqpt=1,nqbz
784 0 : qpt(:)=Ifc%qbz(:,iqpt)
785 0 : call ifc%fourq(Crystal,qpt,phfrq,displ_cart,out_eigvec=eigvec)
786 :
787 : ! OmegaSRLR: Perform decomposition of dynamical matrix
788 : ! MG: FIXME I don't think the implementation is correct when q !=0
789 : if (prtsrlr==1) then
790 0 : call omega_decomp(Ifc%amu,natom,ntypat,Crystal%typat,dynmatfull,dynmat_sr,dynmat_lr,iqpt,nqbz,eigvec)
791 : end if
792 : ! Write the phonon frequencies (this is for checking purposes).
793 : ! Note: these phonon frequencies are not written on unit iout, only on unit std_out.
794 0 : call dfpt_prtph(displ_cart,0,enunit,-1,natom,phfrq,qphnrm,qpt)
795 : end do
796 : end if
797 :
798 : ! OmegaSRLR: deallocate memory used by dynmat decomposition
799 242 : ABI_FREE(dynmatfull)
800 242 : ABI_FREE(dynmat_sr)
801 242 : ABI_FREE(dynmat_lr)
802 242 : ABI_FREE(qbz)
803 :
804 242 : if (nsphere == -1) call ifc_autocutoff(ifc, crystal, comm)
805 :
806 242 : call cwtime_report(" ifc_init2", cpu, wall, gflops)
807 :
808 1210 : end subroutine ifc_init
809 : !!***
810 :
811 : !----------------------------------------------------------------------
812 :
813 : !!****f* m_ifc/ifc_from_file
814 : !! NAME
815 : !! ifc_from_file
816 : !!
817 : !! FUNCTION
818 : !! Initialize instance from file.
819 : !!
820 : !! INPUTS
821 : !!
822 : !! OUTPUT
823 : !!
824 : !! SOURCE
825 :
826 0 : subroutine ifc_from_file(ifc, dielt, filename,natom,ngqpt,nqshift,qshift,ucell_ddb,zeff,qdrp_cart,comm)
827 :
828 : !Arguments ------------------------------------
829 : !scalars
830 : class(ifc_type),intent(out) :: Ifc
831 : integer,intent(in) :: nqshift,comm
832 : integer,intent(inout) :: natom
833 : !arrays
834 : integer,intent(in) :: ngqpt(3)
835 : real(dp),intent(in) :: qshift(3,nqshift)
836 : character(len=*),intent(in) :: filename
837 : real(dp),intent(inout) :: dielt(3,3)
838 : real(dp),allocatable,intent(inout) :: zeff(:,:,:)
839 : real(dp),allocatable,intent(inout) :: qdrp_cart(:,:,:,:)
840 : type(crystal_t),intent(out) :: ucell_ddb
841 :
842 : !Local variables -------------------------
843 : !scalars
844 : integer :: dipdip,i,iblok,iblok_tmp
845 : logical :: file_exists
846 : character(len=500) :: msg
847 0 : type(ddb_type) :: ddb
848 0 : type(ddb_hdr_type) :: ddb_hdr
849 : !******************************************************************
850 :
851 : !check if ddb file exists
852 0 : inquire(file=filename, exist=file_exists)
853 :
854 0 : if (file_exists .eqv. .true.)then
855 : !Reading the ddb
856 0 : call ddb%from_file(filename, ddb_hdr, ucell_ddb, comm)
857 0 : call ddb_hdr%free()
858 0 : natom = ddb%natom
859 : else
860 0 : ABI_ERROR(sjoin("File:", filename, "is not present in the directory"))
861 : end if
862 :
863 : ! Get Dielectric Tensor and Effective Charges
864 : ! (initialized to one_3D and zero if the derivatives are not available in the DDB file)
865 0 : ABI_MALLOC(zeff,(3,3,natom))
866 0 : iblok = ddb%get_dielt_zeff(ucell_ddb,1,1,0,dielt,zeff)
867 :
868 : ! Try to get dielt, in case just the DDE are present
869 0 : if (iblok == 0) then
870 0 : iblok_tmp = ddb%get_dielt(1,dielt)
871 : end if
872 :
873 0 : ABI_MALLOC(qdrp_cart,(3,3,3,natom))
874 0 : iblok = ddb%get_quadrupoles(ddb_hdr%ddb_version,1,BLKTYP_d3E_xx,qdrp_cart)
875 :
876 : ! ifc to be calculated for interpolation
877 0 : write(msg, '(a,a,(80a),a,a,a,a)' ) ch10,('=',i=1,80),ch10,ch10,' Calculation of the interatomic forces ',ch10
878 0 : call wrtout([std_out, ab_out], msg)
879 0 : if ((maxval(abs(zeff)) .lt. tol10) .OR. (maxval(dielt) .gt. 100000.0)) then
880 0 : dipdip=0
881 : else
882 0 : dipdip=1
883 : end if
884 0 : call ifc%init(ucell_ddb,ddb,1,1,1,dipdip,1,ngqpt,nqshift,qshift,dielt,zeff,qdrp_cart,0,0.0_dp,0,1,1,comm)
885 :
886 : ! Free them all
887 0 : call ddb%free()
888 :
889 0 : end subroutine ifc_from_file
890 : !!***
891 :
892 : !----------------------------------------------------------------------
893 :
894 : !!****f* m_ifc/ifc_print
895 : !! NAME
896 : !! ifc_print
897 : !!
898 : !! FUNCTION
899 : !! Print info on the object
900 : !!
901 : !! INPUTS
902 : !! units=Unit numbers for output
903 : !! [header]=String to be printed as header for additional info.
904 : !! [prtvol]=Verbosity level.
905 : !!
906 : !! SOURCE
907 :
908 326 : subroutine ifc_print(ifc, units, header, prtvol)
909 :
910 : !Arguments ------------------------------------
911 : !scalars
912 : class(ifc_type),intent(in) :: ifc
913 : integer,intent(in) :: units(:)
914 : integer,optional,intent(in) :: prtvol
915 : character(len=*),optional,intent(in) :: header
916 :
917 : !Local variables-------------------------------
918 : integer :: my_prtvol,iatom,ii,idir
919 : character(len=500) :: msg
920 : ! *********************************************************************
921 :
922 163 : my_prtvol = 0; if (present(prtvol)) my_prtvol = prtvol
923 :
924 163 : msg = ' ==== Info on the interatomic force constants ==== '
925 163 : if (present(header)) msg = ' ==== '//trim(adjustl(header))//' ==== '
926 163 : call wrtout(units, msg)
927 :
928 163 : call wrtout(units,' Real(R)+Recip(G) space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):')
929 652 : do ii=1,3
930 : write(msg,'(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)')&
931 489 : 'R(',ii,')=',ifc%rprim(:,ii),'G(',ii,')=',ifc%gprim(:,ii)
932 652 : call wrtout(units,msg)
933 : end do
934 163 : call wrtout(units, sjoin(" acell:", ltoa(ifc%acell)))
935 163 : call wrtout(units, sjoin(" Acoustic Sum Rule option (asr):", itoa(ifc%asr)))
936 163 : call wrtout(units, sjoin(" Option for the sampling of the BZ (brav):", itoa(ifc%brav)))
937 163 : call wrtout(units, sjoin(" Symmetrization flag (symdynmat):", itoa(ifc%symdynmat)))
938 163 : call wrtout(units, sjoin(" Dipole-dipole interaction flag (dipdip):", itoa(ifc%dipdip)))
939 163 : call wrtout(units, sjoin(" Dipole-quadrupole interaction flag (dipquad):", itoa(ifc%dipquad)))
940 163 : call wrtout(units, sjoin(" quadrupole-quadrupole interaction flag (quadquad):", itoa(ifc%quadquad)))
941 163 : call wrtout(units, sjoin(" Ewald option:", itoa(ifc%ewald_option)))
942 163 : call wrtout(units, sjoin(" Dielectric tensor: ", ch10, ltoa(reshape(ifc%dielt, [9]), fmt="f10.2")))
943 163 : call wrtout(units, " Effective charges:")
944 532 : do iatom=1,ifc%natom
945 532 : call wrtout(units, ltoa(reshape(ifc%zeff(:,:,iatom), [3*3]), fmt="f10.2"))
946 : end do
947 163 : call wrtout(units, " Quadrupolar terms:")
948 532 : do iatom=1,ifc%natom
949 1639 : do idir=1,3
950 1476 : call wrtout(units, ltoa(reshape(ifc%qdrp_cart(:,:,idir,iatom), [3*3]), fmt="f10.2"))
951 : end do
952 : end do
953 :
954 163 : call wrtout(units, sjoin(" Mass of the atoms (atomic mass unit): ", ltoa(ifc%amu)))
955 163 : call wrtout(units, sjoin(" Number of real-space points for IFC(R): ", itoa(ifc%nrpt)))
956 163 : call wrtout(units, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(ifc%r_inscribed_sphere)))
957 163 : call wrtout(units, " ")
958 163 : call wrtout(units, " Q-mesh:")
959 163 : call wrtout(units, sjoin(" ngqpt:", ltoa(ifc%ngqpt),", nqshft:", itoa(ifc%nqshft)))
960 337 : do ii=1,ifc%nqshft
961 337 : call wrtout(units, sjoin(" ", ktoa(ifc%qshft(:,ii))))
962 : end do
963 :
964 163 : end subroutine ifc_print
965 : !!***
966 :
967 : !----------------------------------------------------------------------
968 :
969 : !!****f* m_ifc/ifc_fourq
970 : !! NAME
971 : !! ifc_fourq
972 : !!
973 : !! FUNCTION
974 : !! Compute the phonon frequencies and the group velocities at the specified q-point by performing
975 : !! a Fourier transform on the IFCs matrix in real space.
976 : !!
977 : !! INPUTS
978 : !! Crystal<type(crystal_t)> = Information on the crystalline structure.
979 : !! qpt(3)=q-point in reduced coordinates (unless nanaqdir is specified)
980 : !! [nanaqdir]=If present, the qpt will be treated as a vector specifying the
981 : !! direction in q-space along which the non-analytic behaviour of the dynamical
982 : !! matrix will be treated. Possible values:
983 : !! "cart" if qpt defines a direction in Cartesian coordinates
984 : !! "reduced" if qpt defines a direction in reduced coordinates
985 : !! [comm]: MPI communicator
986 : !!
987 : !! OUTPUT
988 : !! phfrq(3*natom) = Phonon frequencies in Hartree
989 : !! displ_cart(2,3,natom,3*natom) = Phonon displacement in Cartesian coordinates
990 : !! [out_d2cart(2,3,3*natom,3,3*natom)] = The (interpolated) dynamical matrix for this q-point
991 : !! [out_eigvec(2*3*natom*3*natom) = The (interpolated) eigenvectors of the dynamical matrix in Cartesian coords.
992 : !! [out_displ_red(2*3*natom*3*natom) = The (interpolated) displacement in reduced coordinates.
993 : !! [dwdq(3,3*natom)] = Group velocities i.e. d(omega(q))/dq in Cartesian coordinates.
994 : !!
995 : !! SOURCE
996 :
997 310925 : subroutine ifc_fourq(ifc, crystal, qpt, phfrq, displ_cart, &
998 : nanaqdir, comm, & ! Optional [in]
999 303185 : out_d2cart, out_eigvec, out_displ_red, dwdq) ! Optional [out]
1000 :
1001 : !Arguments ------------------------------------
1002 : !scalars
1003 : class(ifc_type),intent(in) :: Ifc
1004 : character(len=*),optional,intent(in) :: nanaqdir
1005 : type(crystal_t),intent(in) :: Crystal
1006 : integer,optional,intent(in) :: comm
1007 : !arrays
1008 : real(dp),intent(in) :: qpt(3)
1009 : real(dp),intent(out) :: displ_cart(2,3,Crystal%natom,3*Crystal%natom)
1010 : real(dp),intent(out) :: phfrq(3*Crystal%natom)
1011 : real(dp),optional,intent(out) :: out_d2cart(2,3,Crystal%natom,3,Crystal%natom)
1012 : real(dp),optional,intent(out) :: out_eigvec(2,3,Crystal%natom,3*Crystal%natom)
1013 : real(dp),optional,intent(out) :: out_displ_red(2,3,Crystal%natom,3*Crystal%natom)
1014 : real(dp),optional,intent(out) :: dwdq(3,3*crystal%natom)
1015 :
1016 : !Local variables-------------------------------
1017 : !scalars
1018 : integer :: natom, comm_
1019 : real(dp) :: qphnrm, eta
1020 : !arrays
1021 621850 : real(dp) :: my_qpt(3),eigvec(2,3,Crystal%natom,3*Crystal%natom),eigval(3*Crystal%natom)
1022 621850 : real(dp) :: d2cart(2,3,Ifc%mpert,3,Ifc%mpert),tsec(2)
1023 : ! ************************************************************************
1024 :
1025 : ! Keep track of total time spent.
1026 310925 : call timab(1748, 1, tsec)
1027 :
1028 310925 : natom = Crystal%natom
1029 : ! TODO: Rewrite and Parallelize ewald9 in gtdyn9
1030 310925 : comm_ = xmpi_comm_self; if (present(comm)) comm_ = comm
1031 :
1032 : ! Use my_qpt because dfpt_phfrq can change the q-point (very bad design)
1033 310925 : qphnrm = one; my_qpt = qpt
1034 :
1035 310925 : if (present(nanaqdir)) then
1036 : ! This will break backward compatibility because qpt is **always** in reduced coordinates.
1037 : ! while dfpt_phfrq assume cartesian coordinates !!!!!!!!!!!
1038 : ! It does not make sense to change API just to treat this particular case
1039 : ! We should **alwayse use q-points in reduced coordinates.
1040 18434 : qphnrm = zero
1041 2 : select case (nanaqdir)
1042 : case ("reduced")
1043 : ! Convert to Cartesian.
1044 26 : my_qpt = matmul(Crystal%gprimd, qpt)
1045 : case ("cart")
1046 0 : continue
1047 : case default
1048 18434 : ABI_ERROR(sjoin("Wrong value for nanaqdir:", nanaqdir))
1049 : end select
1050 : end if
1051 :
1052 : ! The dynamical matrix d2cart is calculated here:
1053 : call gtdyn9(Ifc%acell,Ifc%atmfrc,Ifc%dielt,Ifc%dipdip,Ifc%dyewq0,d2cart,Crystal%gmet,Ifc%gprim,Ifc%mpert,natom,&
1054 : Ifc%nrpt,qphnrm,my_qpt,Crystal%rmet,Ifc%rprim,Ifc%rpt,Ifc%trans,Crystal%ucvol,Ifc%wghatm,Crystal%xred,Ifc%zeff,&
1055 : Ifc%qdrp_cart,Ifc%ewald_option,eta,comm_, Ifc%sys_dim,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad,&
1056 310925 : dielt_env=Ifc%dielt_env,dielt_thick=Ifc%dielt_thick)
1057 :
1058 : ! Calculate the eigenvectors and eigenvalues of the dynamical matrix
1059 : call dfpt_phfrq(Ifc%amu,displ_cart,d2cart,eigval,eigvec,Crystal%indsym,&
1060 : Ifc%mpert,Crystal%nsym,natom,Crystal%nsym,Crystal%ntypat,phfrq,qphnrm,my_qpt,&
1061 310925 : Crystal%rprimd,Ifc%symdynmat,Crystal%symrel,Crystal%symafm,Crystal%typat,Crystal%ucvol)
1062 :
1063 : ! OmegaSRLR: Perform decomposition of dynamical matrix
1064 : !if (srlr==1) call omega_decomp(amu,natom,ntypat,typat,dynmatfull,dynmatsr,dynmatlr,iqpt,nqpt,eigvec)
1065 :
1066 : ! Return the interpolated dynamical matrix and the eigenvector for this q-point
1067 10338725 : if (present(out_d2cart)) out_d2cart = d2cart(:,:,:natom,:,:natom)
1068 59527619 : if (present(out_eigvec)) out_eigvec = eigvec
1069 :
1070 : ! Return phonon displacement in reduced coordinates.
1071 310925 : if (present(out_displ_red)) call phdispl_cart2red(natom, crystal%gprimd, displ_cart, out_displ_red)
1072 :
1073 : ! Option to get vectors in reduced coordinates?
1074 : !call phdispl_cart2red(natom, crystal%gprimd, out_eigvec, out_eigvec_red)
1075 :
1076 : ! Compute group velocities.
1077 310925 : if (present(dwdq)) call ifc%get_dwdq(crystal, my_qpt, phfrq, eigvec, dwdq, comm_)
1078 :
1079 310925 : call timab(1748, 2, tsec)
1080 :
1081 341520 : end subroutine ifc_fourq
1082 : !!***
1083 :
1084 : !!****f* m_ifc/ifc_get_dcdq
1085 : !! NAME
1086 : !! ifc_get_dcdq
1087 : !!
1088 : !! FUNCTION
1089 : !! Compute the first-derivative of reciprocal space IFCs based on real-space IFCs.
1090 : !!
1091 : !! INPUTS
1092 : !! ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
1093 : !! crystal<crystal_t> = Information on the crystalline structure.
1094 : !! comm: MPI communicator
1095 : !!
1096 : !! OUTPUT
1097 : !! dcdq(2,3,natom,3,natom,3) = first derivatives of reciprocal-space IFCs in cartesian coordinates.
1098 : !!
1099 : !! NOTES
1100 : !! Using:
1101 : !!
1102 : !! dC/dq = \sum_b C(kappa alpha, kappa' beta) (0,b) (R_kappa'beta (b) - R_kappa alpha)
1103 : !!
1104 : !!
1105 : !! SOURCE
1106 :
1107 0 : subroutine ifc_get_dcdq(ifc, cryst, dcdq, dcdqdq, comm)
1108 :
1109 : !Arguments ------------------------------------
1110 : !scalars
1111 : class(ifc_type),intent(in) :: ifc
1112 : type(crystal_t),intent(in) :: cryst
1113 : integer,intent(in) :: comm!, dipdip
1114 : !arrays
1115 : real(dp), intent(inout) :: dcdq(3,cryst%natom,3,cryst%natom,3)
1116 : real(dp), intent(out) :: dcdqdq(3,cryst%natom,3,3,3)
1117 : !real(dp), intent(in) :: dyewq0(cryst%natom,3,cryst%natom,3)
1118 :
1119 : !Local variables-------------------------------
1120 : !scalars
1121 : integer :: ii,jj, mu, kk
1122 : real(dp) :: qpt(3)
1123 : !arrays
1124 0 : real(dp) :: dyntmp(2,3,cryst%natom,3,cryst%natom)
1125 0 : real(dp) :: dcdqcan(2,3,cryst%natom,3,cryst%natom,3)
1126 0 : real(dp) :: dcdqred(2,3,cryst%natom,3,cryst%natom,3)
1127 : ! ************************************************************************
1128 :
1129 : ABI_UNUSED((/comm/))
1130 0 : qpt=zero ; dyntmp = zero
1131 0 : dcdq=zero ; dcdqcan= zero ; dcdqred = zero
1132 0 : dcdqdq=zero
1133 : ! Compute the derivative based on the canonical coordinates
1134 0 : call dynmat_dq(qpt, cryst%natom, ifc%gprim, ifc%nrpt, ifc%rpt, ifc%atmfrc, ifc%wghatm, dcdqcan)
1135 : ! We have also to consider the phase factor introduced by the canonical coordinates (shift on
1136 : ! atoms coordinates in other unit cells)
1137 : ! Only a phase shift, but since we look at the derivative, this also have a contribution here
1138 0 : call ftifc_r2q(ifc%atmfrc,dyntmp, ifc%gprim, cryst%natom, 1, ifc%nrpt, ifc%rpt, qpt, ifc%wghatm, comm)
1139 : ! Move to reduced coordinates
1140 0 : do ii= 1,3
1141 0 : do jj=1,3
1142 0 : dcdqred(:,:,:,:,:,ii) = dcdqred(:,:,:,:,:,ii)+ifc%gprim(jj,ii)*dcdqcan(:,:,:,:,:,jj)
1143 : end do
1144 : end do
1145 0 : do ii=1,3
1146 0 : do mu =1,cryst%natom
1147 0 : do jj=1,3
1148 0 : do kk=1,3
1149 0 : dcdqred(2,ii,mu,jj,:,kk) = dcdqred(2,ii,mu,jj,:,kk)-dyntmp(1,ii,mu,jj,:)*(ifc%trans(kk,:)-ifc%trans(kk,mu))
1150 0 : dcdqred(2,ii,mu,jj,:,kk) = dcdqred(2,ii,mu,jj,:,kk)+dyntmp(1,ii,mu,jj,:)*(cryst%xred(kk,:)-cryst%xred(kk,mu))
1151 : end do
1152 : end do
1153 : end do
1154 : end do
1155 0 : if (ifc%dipdip==1) ABI_WARNING("2D electrostatics + IFCs derivatives from real-space IFCs not fully tested")
1156 : ! If long-range electrostatics are treated separately, we need to add here the contribution to the torque
1157 : ! Note that there is only a contribution coming from the zone-center IFCs here
1158 : ! In 3D the derivative diverges; in 2D it does not, so we can add it with finite difference
1159 : !if (dipdip==1 .and. (ifc%sys_dim==2 .or. ifc%sys_dim==3 .or. ifc%sys_dim==4)) then
1160 : !do kk=1,3
1161 : !if (kk /= ifc%sys_dim-1) then
1162 : !do jj=-1,1,2
1163 : !qtmp(:) = zero
1164 : !qtmp(kk)=jj*0.01_dp
1165 : !call ewald9_2D(cryst%natom,ifc%acell,cryst%xred,ifc%rprim,ifc%dielt,dyew_tmp,&
1166 : ! qtmp,ifc%zeff,ifc%qdrp_cart,ifc%dielt_env,ifc%dielt_thick,ifc%sys_dim)
1167 : !dcdqred(2,:,:,:,:,kk) = dcdqred(2,:,:,:,:,kk)+half*dyew_tmp(2,:,:,:,:)/qtmp(kk)
1168 : ! end do
1169 : ! end if
1170 : ! end do
1171 : !end if
1172 : ! Move to cartesian coordinates
1173 0 : do ii=1,3
1174 0 : do jj=1,3
1175 0 : dcdq(:,:,:,:,ii)=dcdq(:,:,:,:,ii)+dcdqred(2,:,:,:,:,jj)*cryst%rprimd(ii,jj)
1176 : end do
1177 : end do
1178 :
1179 0 : end subroutine ifc_get_dcdq
1180 : !!***
1181 :
1182 : !!****f* m_ifc/ifc_get_dwdq
1183 : !! NAME
1184 : !! ifc_get_dwdq
1185 : !!
1186 : !! FUNCTION
1187 : !! Compute phonon group velocities at an arbitrary q-point.
1188 : !!
1189 : !! INPUTS
1190 : !! crystal<crystal_t> = Information on the crystalline structure.
1191 : !! qpt(3)=q-point in reduced coordinates.
1192 : !! eigvec(2*3*natom*3*natom) = The eigenvectors of the dynamical matrix.
1193 : !! comm: MPI communicator
1194 : !!
1195 : !! OUTPUT
1196 : !! dwdq(3,3*natom) = Group velocities e.g. d(omega(q))/dq in Cartesian coordinates.
1197 : !!
1198 : !! NOTES
1199 : !! Using:
1200 : !!
1201 : !! D(q) u(q,nu) = w(q, nu)**2 and <u(q,nu) | u(q,nu')> = \delta_{nu, nu'}
1202 : !!
1203 : !! one can show, using the Hellman-Feynman theorem, that:
1204 : !!
1205 : !! \nabla_q w(q, nu) = 1/(2 w(q, nu)) <u(q, nu)| \nabla_q D(q) | u(q, nu)>
1206 : !!
1207 : !! SOURCE
1208 :
1209 227649 : subroutine ifc_get_dwdq(ifc, cryst, qpt, phfrq, eigvec, dwdq, comm)
1210 :
1211 : !Arguments ------------------------------------
1212 : !scalars
1213 : class(ifc_type),intent(in) :: ifc
1214 : type(crystal_t),intent(in) :: cryst
1215 : integer,intent(in) :: comm
1216 : !arrays
1217 : real(dp),intent(in) :: qpt(3)
1218 : real(dp),intent(in) :: phfrq(3*cryst%natom)
1219 : real(dp),intent(in) :: eigvec(2,3*cryst%natom,3*cryst%natom)
1220 : real(dp),intent(out) :: dwdq(3,3*cryst%natom)
1221 :
1222 : !Local variables-------------------------------
1223 : !scalars
1224 : !integer,save :: enough=0
1225 : integer,parameter :: nqpt1=1,option2=2,sumg0=0
1226 : integer :: ii,nu,natom3,jj
1227 : real(dp) :: hh, eta
1228 : !arrays
1229 455298 : real(dp) :: dddq(2,3*cryst%natom,3*cryst%natom,3),dot(2),qfd(3)
1230 455298 : real(dp) :: omat(2,3*cryst%natom,3*cryst%natom)
1231 455298 : real(dp) :: dyew(2,3*cryst%natom,3*cryst%natom)
1232 : ! ************************************************************************
1233 :
1234 : ABI_UNUSED((/comm/))
1235 227649 : natom3 = cryst%natom * 3
1236 :
1237 : ! Generate the analytical part from the interatomic forces
1238 227649 : call dynmat_dq(qpt, cryst%natom, ifc%gprim, ifc%nrpt, ifc%rpt, ifc%atmfrc, ifc%wghatm, dddq)
1239 :
1240 : ! The analytical dynamical matrix dq has been generated
1241 : ! in the normalized canonical coordinate system. Now, the
1242 : ! phase is modified, in order to recover the usual (xred) coordinate of atoms.
1243 910596 : do ii=1,3
1244 682947 : call dymfz9(dddq(:,:,:,ii), cryst%natom, nqpt1, ifc%gprim, option2, qpt, ifc%trans)
1245 124232646 : dddq(:,:,:,ii) = dddq(:,:,:,ii) * ifc%acell(ii)
1246 : end do
1247 :
1248 227649 : if (ifc%dipdip == 1.or.ifc%dipquad == 1.or.ifc%quadquad == 1) then
1249 : ! Add the gradient of the non-analytical part.
1250 : ! Note that dddq is in cartesian coordinates.
1251 : ! For the time being, the gradient is computed with finite difference and step hh.
1252 : ! TODO: should generalize ewald9 to compute dq.
1253 : !enough = enough + 1
1254 : !if (enough <= 5) ABI_WARNING("phonon velocities with dipdip==1 not yet tested.")
1255 : hh = 0.01_dp
1256 69388 : do ii=1,3
1257 331731 : do jj=-1,1,2
1258 : ! qcart --> qred
1259 104082 : qfd = zero; qfd(ii) = jj
1260 1665312 : qfd = matmul(cryst%rprimd, qfd); qfd = qfd / normv(qfd, cryst%gmet, "G")
1261 : !write(std_out,*)"normv:",normv(qfd, cryst%gmet, "G")
1262 416328 : qfd = qpt + hh * qfd
1263 :
1264 : call ewald9(ifc%acell,ifc%dielt,dyew,cryst%gmet,ifc%gprim,cryst%natom,qfd,&
1265 : cryst%rmet,ifc%rprim,sumg0,cryst%ucvol,cryst%xred,ifc%zeff,ifc%qdrp_cart, eta, &
1266 104082 : ifc%ewald_option,dipquad=ifc%dipquad,quadquad=ifc%quadquad)
1267 104082 : call q0dy3_apply(cryst%natom,ifc%dyewq0,dyew)
1268 11943351 : dddq(:,:,:,ii) = dddq(:,:,:,ii) + (jj * half / hh) * dyew
1269 : end do
1270 : end do
1271 : end if
1272 :
1273 910596 : do ii=1,3
1274 910596 : call massmult_and_breaksym(cryst%natom, cryst%ntypat, cryst%typat, ifc%amu, dddq(:,:,:,ii))
1275 : end do
1276 :
1277 : ! Compute 1/(2w(q)) <u(q)|dD(q)/dq|u(q)>
1278 910596 : do ii=1,3
1279 682947 : call zgemm('N','N',natom3,natom3,natom3,cone,dddq(:,:,:,ii),natom3,eigvec,natom3,czero,omat,natom3)
1280 5145393 : do nu=1,natom3
1281 4917744 : if (abs(phfrq(nu)) > tol12) then
1282 4234005 : dot = cg_zdotc(natom3, eigvec(1,1,nu), omat(1,1,nu))
1283 : ! abs(w) is needed to get the correct derivative if we have a purely imaginary solution.
1284 4234005 : dwdq(ii, nu) = dot(1) / (two * abs(phfrq(nu)))
1285 : else
1286 792 : dwdq(ii, nu) = zero
1287 : end if
1288 : end do
1289 : end do
1290 :
1291 227649 : end subroutine ifc_get_dwdq
1292 : !!***
1293 :
1294 : !----------------------------------------------------------------------
1295 :
1296 : !!****f* m_ifc/ifc_get_phmesh
1297 : !! NAME
1298 : !! ifc_get_phmesh
1299 : !!
1300 : !! FUNCTION
1301 : !! Build linear mesh for phonons.
1302 : !!
1303 : !! INPUTS
1304 : !!
1305 : !! OUTPUT
1306 : !!
1307 : !! SOURCE
1308 :
1309 65 : subroutine ifc_get_phmesh(ifc, ph_wstep, phmesh_size, phmesh)
1310 :
1311 : !Arguments ------------------------------------
1312 : !scalars
1313 : class(ifc_type),intent(in) :: ifc
1314 : real(dp),intent(in) :: ph_wstep
1315 : integer,intent(out) :: phmesh_size
1316 : !arrays
1317 : real(dp),allocatable,intent(out) :: phmesh(:)
1318 : !******************************************************************
1319 :
1320 65 : phmesh_size = nint((ifc%omega_minmax(2) - ifc%omega_minmax(1) ) / ph_wstep) + 1
1321 195 : ABI_MALLOC(phmesh, (phmesh_size))
1322 65 : phmesh = arth(ifc%omega_minmax(1), ph_wstep, phmesh_size)
1323 :
1324 65 : end subroutine ifc_get_phmesh
1325 : !!***
1326 :
1327 : !----------------------------------------------------------------------
1328 :
1329 : !!****f* m_ifc/ifc_speedofsound
1330 : !!
1331 : !! NAME
1332 : !! ifc_speedofsound
1333 : !!
1334 : !! FUNCTION
1335 : !! Calculate the speed of sound by averaging the phonon group velocities of the
1336 : !! three acoustic modes on a small sphere of radius qrad centered around Gamma.
1337 : !! Perform spherical integration with Lebedev-Laikov grids
1338 : !!
1339 : !! INPUTS
1340 : !! crystal<crystal_t> = Information on the crystalline structure.
1341 : !! qrad_tolkms(2):
1342 : !! qrad=Radius of the sphere in reciprocal space
1343 : !! atols_kms=Absolute tolerance in kilometer/second. The code generates spherical meshes
1344 : !! until the results are converged twice within atols_kms.
1345 : !! ncid=the id of the open NetCDF file. Use nctk_noid to disable netcdf output.
1346 : !! comm=MPI communicator.
1347 : !!
1348 : !! OUTPUT
1349 : !!
1350 : !! SOURCE
1351 :
1352 1 : subroutine ifc_speedofsound(ifc, crystal, qrad_tolkms, ncid, comm)
1353 :
1354 : !Arguments -------------------------------
1355 : !scalars
1356 : class(ifc_type),intent(in) :: ifc
1357 : integer,intent(in) :: comm,ncid
1358 : type(crystal_t),intent(in) :: crystal
1359 : !arrays
1360 : real(dp),intent(in) :: qrad_tolkms(2)
1361 :
1362 : !Local variables -------------------------
1363 : !scalars
1364 : integer,parameter :: master=0
1365 : integer :: ii,nu,igrid,my_rank,nprocs,ierr,converged,npts,num_negw,vs_ierr,ncerr
1366 : integer :: iatom,iatref,num_acoustic,isacoustic
1367 : real(dp) :: min_negw,cpu,wall,gflops, qrad,tolkms,diff
1368 : character(len=500) :: msg
1369 1 : type(lebedev_t) :: lgrid
1370 : !arrays
1371 : integer :: asnu(3)
1372 : real(dp) :: qred(3),qvers_cart(3),qvers_red(3),quad(3),prev_quad(3),vs(7,3)
1373 3 : real(dp) :: phfrqs(3*crystal%natom),dwdq(3,3*crystal%natom)
1374 2 : real(dp) :: displ_cart(2,3*crystal%natom,3*crystal%natom),eigvec(2,3*crystal%natom,3*crystal%natom)
1375 : ! *********************************************************************
1376 :
1377 1 : my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
1378 :
1379 1 : if (ifc%asr == 0) ABI_WARNING("Computing speed of sound with asr == 0! Use asr > 0")
1380 1 : qrad = qrad_tolkms(1); tolkms = qrad_tolkms(2)
1381 1 : ABI_CHECK(qrad > zero, "vs_qrad <= 0")
1382 1 : ABI_CHECK(tolkms > zero, "vs_tolkms <= 0")
1383 :
1384 1 : call cwtime(cpu, wall, gflops, "start")
1385 :
1386 : ! Find the index of the first acoustic modes (needed to handle systems with unstable branches at Gamma
1387 : ! In this case, indeed, we end up computing derivatives for the wrong branches, the integration becomes
1388 : ! unstable and difficult to converge.
1389 1 : qred = zero
1390 1 : call ifc%fourq(crystal, qred, phfrqs, displ_cart,out_eigvec=eigvec)
1391 : !write(std_out,*)"omega(q==Gamma): ",phfrqs
1392 :
1393 1 : num_acoustic = 0
1394 3 : do nu = 1, 3*crystal%natom
1395 : ! Check if this mode is acoustic like: scalar product of all displacement vectors are collinear
1396 12 : isacoustic = 1
1397 : ! Find reference atom with non-zero displacement
1398 12 : do iatom=1,crystal%natom
1399 93 : if(sum(displ_cart(:,(iatom-1)*3+1:(iatom-1)*3+3,nu)**2) >tol16)iatref=iatom
1400 : end do
1401 : ! Now compute scalar product, and check they are all positive
1402 12 : do iatom = 1, crystal%natom
1403 93 : if (sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3, nu)*eigvec(:,(iatref-1)*3+1:(iatref-1)*3+3, nu)) < tol16 ) isacoustic = 0
1404 : end do
1405 4 : if (isacoustic == 1) then
1406 3 : num_acoustic=num_acoustic+1
1407 3 : asnu(num_acoustic)=nu
1408 3 : if (num_acoustic==3) exit
1409 : end if
1410 : end do
1411 :
1412 1 : ABI_CHECK(num_acoustic == 3, sjoin("Wrong number of acoustic modes:", itoa(num_acoustic)))
1413 :
1414 1 : write(std_out,"(a,3i2,a)") "The bands with indices ",asnu(:)," will be used to calculate the sound velocities"
1415 :
1416 : ! Speed of sound along reduced directions.
1417 7 : do ii=1,6
1418 6 : qred = zero; qred(MOD(ii-1,3)+1) = one
1419 42 : if (ii >= 4 .and. ii <= 6) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
1420 : !if (ii >= 7 .and. ii <= 9) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
1421 24 : qvers_red = (qred / normv(qred, crystal%gmet, "G"))
1422 24 : qred = qrad * qvers_red
1423 : !write(std_out,*)"dir",normv(qred, crystal%gmet, "G"), qrad
1424 6 : call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
1425 :
1426 24 : do nu=1,3
1427 78 : vs(ii, nu) = sqrt(sum(dwdq(1:3,asnu(nu)) ** 2)) * Bohr_meter * 0.001_dp / Time_Sec
1428 : end do
1429 6 : write(std_out,"(a,3es12.4,a)")" ||vs(nu)||:",vs(ii,:), " [km/s]"
1430 :
1431 96 : qvers_cart = matmul(crystal%gprimd, qvers_red) * two_pi
1432 24 : do nu=1,3
1433 78 : vs(ii, nu) = dot_product(dwdq(1:3,asnu(nu)), qvers_cart) * Bohr_meter * 0.001_dp / Time_Sec
1434 : end do
1435 7 : write(std_out,"(a,3es12.4,a)")" <q|vs(nu)>:",vs(ii,:), " [km/s]"
1436 :
1437 : !do nu=1,3
1438 : ! write(std_out,"(a,3es12.4,a)")" vs(nu)_vect_red:",&
1439 : ! matmul(crystal%gprimd, dwdq(1:3,asnu(nu))) * Bohr_meter * 0.001_dp / Time_Sec, " [km/s]"
1440 : !end do
1441 : end do
1442 :
1443 : ! Spherical average with Lebedev-Laikov grids.
1444 1 : converged = 0
1445 5 : do igrid=1,lebedev_ngrids
1446 5 : call lgrid%from_index(igrid)
1447 5 : npts = lgrid%npts; quad = zero; num_negw = 0; min_negw = zero
1448 139 : do ii=1,npts
1449 134 : if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
1450 :
1451 : ! Build q-point on sphere of radius qrad. qcart --> qred
1452 1742 : qred = matmul(crystal%rprimd, lgrid%versors(:, ii))
1453 536 : qred = qrad * (qred / normv(qred, crystal%gmet, "G"))
1454 : !write(std_out,*)"lebe",normv(qred, crystal%gmet, "G"), qrad
1455 134 : call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
1456 536 : if (any(phfrqs(asnu) < -tol8)) then
1457 0 : num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs(asnu)))
1458 : end if
1459 :
1460 541 : do nu=1,3
1461 1742 : quad(nu) = quad(nu) + lgrid%weights(ii) * sqrt(sum(dwdq(1:3,asnu(nu)) ** 2))
1462 : !quad(nu) = quad(nu) + lgrid%weights(ii) * abs(dot_product(lgrid%versors(:,ii), dwdq(:,asnu(nu))))
1463 : end do
1464 : end do
1465 :
1466 : ! Will use km/sec unit for echo purposes
1467 20 : quad = quad * Bohr_meter * 0.001_dp / Time_Sec
1468 5 : call xmpi_sum(quad, comm, ierr)
1469 5 : call xmpi_sum(num_negw, comm, ierr)
1470 5 : call lgrid%free()
1471 :
1472 : write(std_out,'(2(a,i6),a,3es12.4,a,es12.4)') &
1473 20 : " Lebedev-Laikov grid: ",igrid,", npts: ", npts, " vs_sphavg(ac_modes): ",quad, " <vs>: ",sum(quad)/3
1474 :
1475 5 : if (igrid > 1) then
1476 : diff = zero
1477 16 : do nu=1,3
1478 16 : diff = diff + abs(quad(nu) - prev_quad(nu)) / 3
1479 : end do
1480 : !if (abs(sum(quad - prev_quad)/3) < tolkms) then
1481 4 : if (diff < tolkms) then
1482 2 : converged = converged + 1
1483 : else
1484 : converged = 0
1485 : end if
1486 : end if
1487 5 : prev_quad = quad
1488 20 : vs(7, :) = quad
1489 10 : if (converged == 2) exit
1490 : end do ! igrid
1491 :
1492 1 : if (my_rank == master) then
1493 : ! vs_err: 1 if not converged, < 0 if negative freqs, == 0 if success.
1494 1 : vs_ierr = 0
1495 4 : do ii=1,3
1496 4 : write(ab_out,"(a,3es12.4,a,i1)")" Speed of sound:",vs(ii,:)," [km/s] along reduced direction: ",ii
1497 : end do
1498 : write(ab_out,'(2(a,es12.4),a,i0)') &
1499 1 : " Lebedev-Laikov integration with qradius: ", qrad, " tolkms: ",tolkms, " [km/s], npts: ", npts
1500 4 : write(ab_out,"(a,3es12.4,a,es12.4)")" Spherical average:",vs(7,:)," [km/s], ",sum(vs(7,:))/3
1501 1 : if (converged /= 2) then
1502 0 : vs_ierr = 1
1503 0 : write(msg,'(a,es12.4,a)')" WARNING: Results are not converged within: ",tolkms, " [km/s]"
1504 0 : call wrtout(ab_out, msg)
1505 0 : ABI_WARNING(msg)
1506 : end if
1507 1 : if (num_negw > 0) then
1508 0 : vs_ierr = -num_negw
1509 : write(msg,'(a,i0,a,es12.4,3a)') &
1510 0 : " WARNING: Detected ",num_negw, " negative frequencies. Minimum was: ",min_negw * Ha_meV, "[meV]",ch10,&
1511 0 : " Speed of sound could be wrong"
1512 0 : call wrtout(ab_out, msg)
1513 0 : ABI_WARNING(msg)
1514 : end if
1515 :
1516 : ! Dump results to netcdf file.
1517 1 : if (ncid /= nctk_noid) then
1518 2 : ncerr = nctk_def_arrays(ncid, [nctkarr_t("vsound", "dp", "seven, three")], defmode=.True.)
1519 1 : NCF_CHECK(ncerr)
1520 2 : ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: "vsound_ierr"])
1521 1 : NCF_CHECK(ncerr)
1522 3 : ncerr = nctk_def_dpscalars(ncid, [character(len=nctk_slen) :: "vsound_qrad", "vsound_tolkms"])
1523 1 : NCF_CHECK(ncerr)
1524 2 : ncerr = nctk_def_arrays(ncid, [nctkarr_t("asnu", "i", "three")], defmode=.True.)
1525 1 : NCF_CHECK(ncerr)
1526 : ! Write data.
1527 1 : NCF_CHECK(nctk_set_datamode(ncid))
1528 1 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_ierr"), vs_ierr))
1529 1 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_qrad"), qrad))
1530 1 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_tolkms"), tolkms))
1531 1 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound"), vs))
1532 1 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "asnu"), asnu))
1533 : end if
1534 : end if
1535 :
1536 1 : call cwtime_report(" ifc_speedofsound", cpu, wall, gflops)
1537 :
1538 1 : end subroutine ifc_speedofsound
1539 : !!***
1540 :
1541 : !----------------------------------------------------------------------
1542 :
1543 : !!****f* m_ifc/ifc_autocutoff
1544 : !! NAME
1545 : !! ifc_autocutoff
1546 : !!
1547 : !! FUNCTION
1548 : !! Find the value of nsphere that gives non-negative frequencies around Gamma
1549 : !! in a small sphere of radius qrad.
1550 : !! Use bisection to reduce the number of attempts although there's no guarantee
1551 : !! that the number of negative frequencies is monotonic.
1552 : !!
1553 : !! INPUTS
1554 : !! crystal<crystal_t> = Information on the crystalline structure.
1555 : !! comm=MPI communicator
1556 : !!
1557 : !! SIDE EFFECTS
1558 : !! ifc%wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
1559 : !! with the last cutoff found by the bisection algorithm applied.
1560 : !! ifc%atmfrc(2,3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces
1561 : !!
1562 : !! SOURCE
1563 :
1564 1 : subroutine ifc_autocutoff(ifc, crystal, comm)
1565 :
1566 : !Arguments ------------------------------------
1567 : !scalars
1568 : class(ifc_type),intent(inout) :: ifc
1569 : type(crystal_t),intent(in) :: crystal
1570 : integer,intent(in) :: comm
1571 :
1572 : !Local variables-------------------------------
1573 : !scalars
1574 : integer,parameter :: master=0
1575 : integer :: iq_ibz,ierr,my_rank,nprocs,ii,nsphere,num_negw,jl,ju,jm,natom,nrpt
1576 : real(dp),parameter :: rifcsph0 = zero
1577 : real(dp) :: adiff,qrad,min_negw,xval,rcut_min
1578 1 : type(lebedev_t) :: lgrid
1579 : !arrays
1580 2 : real(dp) :: displ_cart(2*3*ifc%natom*3*ifc%natom)
1581 2 : real(dp) :: qred(3),qred_vers(3),phfrqs(3*ifc%natom) !,dwdq(3,3*ifc%natom)
1582 1 : real(dp),allocatable :: ref_phfrq(:,:),cut_phfrq(:,:), save_wghatm(:,:,:),save_atmfrc(:,:,:,:,:)
1583 : ! *********************************************************************
1584 :
1585 1 : my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
1586 1 : natom = ifc%natom; nrpt = ifc%nrpt
1587 :
1588 : ! Compute frequencies on the ab-initio q-mesh without cutoff.
1589 1828 : ABI_CALLOC(ref_phfrq, (3*natom, ifc%nqibz))
1590 97 : do iq_ibz=1,ifc%nqibz
1591 96 : if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
1592 97 : call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), ref_phfrq(:,iq_ibz), displ_cart)
1593 : end do
1594 1 : call xmpi_sum(ref_phfrq, comm, ierr)
1595 :
1596 5 : ABI_MALLOC(save_wghatm, (natom,natom,nrpt))
1597 6 : ABI_MALLOC(save_atmfrc, (3,natom,3,natom,ifc%nrpt))
1598 512503 : save_wghatm = ifc%wghatm; save_atmfrc = ifc%atmfrc
1599 :
1600 4 : ABI_MALLOC(cut_phfrq, (3*natom, ifc%nqibz))
1601 1 : qrad = 0.01
1602 1 : call lgrid%from_index(16)
1603 :
1604 1 : if (my_rank == master) then
1605 1 : write(ab_out, "(a)")" Apply cutoff on IFCs. Using bisection algorithm to find initial guess for nsphere."
1606 1 : write(ab_out, "(a,i0)")" Maximum number of atom-centered spheres: ",natom * nrpt
1607 1 : write(ab_out, "(a,i0,a,f5.3)")" Using Lebedev-Laikov grid with npts: ",lgrid%npts, ", qrad: ",qrad
1608 1 : write(ab_out, "(/,a)")" <adiff>: Average difference between ab-initio frequencies and frequencies with cutoff."
1609 1 : write(ab_out, "(a)")" num_negw: Number of negative freqs detected in small sphere around Gamma."
1610 1 : write(ab_out, "(a)")" min_negw: Min negative frequency on the small sphere."
1611 1 : write(ab_out, "(a,/,/)")" rifcsph: Effective cutoff radius corresponding to nsphere."
1612 1 : write(ab_out, "(a)")" nsphere <adiff>[meV] num_negw min_negw[meV] rifcsph"
1613 : end if
1614 :
1615 1 : jl = 0; ju = natom * nrpt + 1 ! Initialize lower and upper limits.
1616 39 : do
1617 14 : if (ju - jl <= 1) then
1618 : exit
1619 : end if
1620 13 : jm = (ju + jl) / 2 ! Compute a midpoint
1621 13 : nsphere = jm
1622 :
1623 6662539 : ifc%wghatm = save_wghatm; ifc%atmfrc = save_atmfrc
1624 13 : call corsifc9(ifc%acell,ifc%gprim, natom, nrpt,nsphere,rifcsph0,ifc%rcan,ifc%rprim,ifc%rpt,rcut_min,ifc%wghatm)
1625 13 : if (ifc%asr > 0) call asrif9(ifc%asr,ifc%atmfrc,ifc%natom,ifc%nrpt,ifc%rpt,ifc%wghatm)
1626 :
1627 23725 : cut_phfrq = zero
1628 1261 : do iq_ibz=1,ifc%nqibz
1629 1248 : if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
1630 1261 : call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), cut_phfrq(:,iq_ibz), displ_cart)
1631 : !write(std_out,*)cut_phfrq(1,iq_ibz),ref_phfrq(1,iq_ibz)
1632 : end do
1633 13 : call xmpi_sum(cut_phfrq, comm, ierr)
1634 :
1635 : ! Test whether there are negative frequencies around gamma, including reciprocal lattice vectors.
1636 13 : num_negw = 0; min_negw = zero
1637 5694 : do ii=1,lgrid%npts+3
1638 5681 : if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
1639 5681 : if (ii <= 3) then
1640 39 : qred = zero; qred(ii) = one
1641 : else
1642 73346 : qred = matmul(crystal%rprimd, lgrid%versors(:, ii-3))
1643 : end if
1644 22724 : qred_vers = (qred / normv(qred, crystal%gmet, "G"))
1645 22724 : qred = qrad * qred_vers
1646 5681 : call ifc%fourq(crystal, qred, phfrqs, displ_cart) !, dwdq=dwdq)
1647 96036 : if (any(phfrqs < +tol8)) then
1648 13240 : num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs))
1649 : end if
1650 : !do jj=1,3
1651 : ! xval = dot_product(dwdq(:,jj), matmul(crystal%gprimd, qred_vers))
1652 : ! if (xval < zero) num_negw = num_negw + 1
1653 : !end do
1654 : end do
1655 13 : call xmpi_sum(num_negw, comm, ierr)
1656 13 : xval = min_negw; call xmpi_min(xval, min_negw, comm, ierr)
1657 :
1658 23725 : adiff = sum(abs(cut_phfrq - ref_phfrq)) / (ifc%nqibz * 3 * natom)
1659 13 : if (my_rank == master) then
1660 : write(ab_out,"(a,i7,1x,es13.4,4x,i8,1x,es13.4,2x,es13.4)") &
1661 13 : "-",nsphere, adiff * Ha_meV, num_negw, min_negw * Ha_meV, rcut_min
1662 : end if
1663 :
1664 14 : if (num_negw == 0) then
1665 : jl = jm ! Replace lower limit
1666 : else
1667 9 : ju = jm ! Replace upper limit
1668 : end if
1669 : end do
1670 :
1671 1 : ABI_FREE(ref_phfrq)
1672 1 : ABI_FREE(cut_phfrq)
1673 1 : ABI_FREE(save_wghatm)
1674 1 : ABI_FREE(save_atmfrc)
1675 1 : call lgrid%free()
1676 :
1677 2 : end subroutine ifc_autocutoff
1678 : !!***
1679 :
1680 : !----------------------------------------------------------------------
1681 :
1682 : !!****f* m_ifc/corsifc9
1683 : !! NAME
1684 : !! corsifc9
1685 : !!
1686 : !! FUNCTION
1687 : !! Applies a cutoff on the ifc in real space
1688 : !!
1689 : !! INPUTS
1690 : !! acell(3)=length scales by which rprim is to be multiplied
1691 : !! gprim(3,3)=dimensionless primitive translations in reciprocal space
1692 : !! natom=number of atoms in unit cell
1693 : !! nrpt= Number of R points in the Big Box
1694 : !! rcan(3,natom)=canonical coordinates of atoms
1695 : !! rprim(3,3)=dimensionless primitive translations in real space
1696 : !! rpt(3,nrpt)=canonical coordinates of the points in the BigBox.
1697 : !! nsphere=number of atoms to be included in the cut-off sphere for interatomic
1698 : !! force constant; if = 0 : maximum extent allowed by the grid.
1699 : !! rifcsph=radius for cutoff of IFC
1700 : !! wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector.
1701 : !!
1702 : !! OUTPUT
1703 : !! wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
1704 : !! with the required cutoff applied.
1705 : !! rcut_min=Effective cutoff. Defined by the minimum cutoff radius over the natom sites.
1706 : !!
1707 : !! SOURCE
1708 :
1709 16 : subroutine corsifc9(acell,gprim,natom,nrpt,nsphere,rifcsph,rcan,rprim,rpt,rcut_min,wghatm)
1710 :
1711 : !Arguments -------------------------------
1712 : !scalars
1713 : integer,intent(in) :: natom,nrpt,nsphere
1714 : real(dp),intent(in) :: rifcsph
1715 : real(dp),intent(out) :: rcut_min
1716 : !arrays
1717 : real(dp),intent(in) :: acell(3), gprim(3,3),rcan(3,natom), rprim(3,3),rpt(3,nrpt)
1718 : real(dp),intent(inout) :: wghatm(natom,natom,nrpt)
1719 :
1720 : !Local variables -------------------------
1721 : !scalars
1722 : integer :: ia,ib,ii,index,irpt
1723 : real(dp) :: rmax,rsigma,r0
1724 : !arrays
1725 16 : integer,allocatable :: list(:)
1726 16 : real(dp),allocatable :: dist(:,:,:),wkdist(:)
1727 : ! *********************************************************************
1728 :
1729 : ! Compute the distances between atoms
1730 : ! dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
1731 80 : ABI_MALLOC(dist,(natom,natom,nrpt))
1732 16 : call dist9(acell,dist,gprim,natom,nrpt,rcan,rprim,rpt)
1733 :
1734 48 : ABI_MALLOC(list,(natom*nrpt))
1735 48 : ABI_MALLOC(wkdist,(natom*nrpt))
1736 :
1737 : ! loop on all generic atoms.
1738 16 : rcut_min = huge(one)
1739 99 : do ia=1,natom
1740 :
1741 166 : wkdist = reshape(dist(ia,:,:), [natom*nrpt])
1742 488916 : do ii=1,natom*nrpt
1743 488916 : list(ii)=ii
1744 : end do
1745 : ! This sorting algorithm is slow ...
1746 83 : call sort_dp(natom*nrpt,wkdist,list,tol14)
1747 83 : rmax = wkdist(natom*nrpt)
1748 :
1749 : ! zero the outside IFCs: act on wghatm
1750 :
1751 : ! fix number of spheres
1752 83 : if(nsphere/=0.and.nsphere<natom*nrpt)then
1753 80 : rcut_min = min(rcut_min, wkdist(nsphere+1))
1754 345170 : do ii=nsphere+1,natom*nrpt
1755 345090 : index=list(ii)
1756 345090 : irpt=(index-1)/natom+1
1757 345090 : ib=index-natom*(irpt-1)
1758 345170 : wghatm(ia,ib,irpt)=zero
1759 : end do
1760 : end if
1761 :
1762 : ! or fix radius of maximum ifc
1763 83 : if(rifcsph>tol10)then
1764 3648 : do ii=nsphere+1,natom*nrpt
1765 3645 : index=list(ii)
1766 : ! preserve weights for atoms inside sphere of radius rifcsph
1767 3645 : if (wkdist(ii) < rifcsph) cycle
1768 3464 : rcut_min = min(rcut_min, wkdist(ii))
1769 3464 : irpt=(index-1)/natom+1
1770 3464 : ib=index-natom*(irpt-1)
1771 3648 : wghatm(ia,ib,irpt)=zero
1772 : end do
1773 : end if
1774 :
1775 : ! filter smoothly to 0 at edge of WS cell
1776 99 : if (rifcsph < -tol10) then
1777 : ! Use different filter
1778 0 : r0 = abs(rifcsph) * rmax; rsigma = half*(rmax-r0) !one
1779 0 : rcut_min = r0 ! Set it to r0
1780 0 : do ii=nsphere+1,natom*nrpt
1781 0 : index=list(ii)
1782 0 : irpt=(index-1)/natom+1
1783 0 : ib=index-natom*(irpt-1)
1784 0 : wghatm(ia,ib,irpt) = wghatm(ia,ib,irpt) * half * abi_derfc((wkdist(ii) - r0) / rsigma)
1785 : end do
1786 : end if
1787 :
1788 : end do
1789 :
1790 16 : ABI_FREE(dist)
1791 16 : ABI_FREE(list)
1792 16 : ABI_FREE(wkdist)
1793 :
1794 16 : end subroutine corsifc9
1795 : !!***
1796 :
1797 : !----------------------------------------------------------------------
1798 :
1799 : !!****f* m_ifc/ifc_write
1800 : !! NAME
1801 : !! ifc_write
1802 : !!
1803 : !! FUNCTION
1804 : !! Adds the real-space interatomic force constants to:
1805 : !! the output file,
1806 : !! a NetCDF file which is already open on ncid
1807 : !! if prt_ifc==1, to the ifcinfo.out file
1808 : !! to a TDEP file named outfile.forceconstants_ABINIT
1809 : !!
1810 : !! INPUTS
1811 : !! ifcana= 0 => no analysis of ifc ; 1 => full analysis
1812 : !! atifcflg(natom) = atifcflg(ia) equals 1 if the analysis of ifc has to be done for atom ia; otherwise 0.
1813 : !! ifcout= Number of interatomic force constants written in the output file
1814 : !! prt_ifc = flag to print out ifc information for dynamical matrix (AI2PS)
1815 : !! ncid=the id of the open NetCDF file. Set to nctk_noid if netcdf output is not wanted.
1816 : !!
1817 : !! OUTPUT
1818 : !! written in the output file and in the NetCDF file
1819 : !!
1820 : !! NOTES
1821 : !! This routine should be executed by one processor only
1822 : !!
1823 : !! TODO:
1824 : !! 1) ifc_write should not have side effects
1825 : !!
1826 : !! 2) the code is unreadable and horrible - 3/4 different file formats for the
1827 : !! same stuff. We should make different subroutines, even if it duplicates some code
1828 : !!
1829 : !! 3) The name of the output files should respect the conventions of the code.
1830 : !! This routine should take a file prefix as argument.
1831 : !!
1832 : !! SOURCE
1833 :
1834 65 : subroutine ifc_write(Ifc,ifcana,atifcflg,ifcout,prt_ifc,ncid,prefix,&
1835 : unit_out) ! optional arguments
1836 :
1837 : !Arguments -------------------------------
1838 : !scalars
1839 : class(ifc_type),intent(inout) :: Ifc
1840 : integer,intent(in) :: ifcout,ifcana,prt_ifc,ncid
1841 : integer,optional,intent(in) :: unit_out
1842 : character(*),intent(in) :: prefix
1843 : !arrays
1844 : integer,intent(in) :: atifcflg(Ifc%natom)
1845 :
1846 : !Local variables -------------------------
1847 : !scalars
1848 : integer :: ia,ib,ii,ncerr,iatifc,ifcout1,mu,nu,iout, irpt, unit_ifc, unit_tdep
1849 : real(dp) :: detdlt, maxdist_tdep
1850 : character(len=fnlen) :: filename
1851 : character(len=500) :: msg
1852 : character(len=4) :: str1, str2
1853 : !arrays
1854 65 : integer,allocatable :: list(:),indngb(:)
1855 : real(dp) :: invdlt(3,3),ra(3),xred(3),dielt(3,3), gprimd(3,3),rprimd(3,3)
1856 65 : real(dp),allocatable :: dist(:,:,:),wkdist(:),rsiaf(:,:,:),sriaf(:,:,:),vect(:,:,:), posngb(:,:),wghia(:)
1857 : ! *********************************************************************
1858 :
1859 65 : iout = ab_out; if (present(unit_out)) iout = unit_out
1860 845 : dielt = ifc%dielt
1861 :
1862 : ! Compute the distances between atoms
1863 325 : ABI_MALLOC(dist,(Ifc%natom,Ifc%natom,Ifc%nrpt))
1864 65 : call dist9(Ifc%acell,dist,Ifc%gprim,Ifc%natom,Ifc%nrpt,Ifc%rcan,Ifc%rprim,Ifc%rpt)
1865 : ! Now dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
1866 :
1867 195 : ABI_MALLOC(list,(Ifc%natom*Ifc%nrpt))
1868 195 : ABI_MALLOC(wkdist,(Ifc%natom*Ifc%nrpt))
1869 :
1870 : ! Calculating the inverse (transpose) of the dielectric tensor
1871 65 : call matr3inv(dielt,invdlt)
1872 :
1873 : ! Calculating the determinant of the dielectric tensor
1874 : detdlt=dielt(1,1)*dielt(2,2)*dielt(3,3)+dielt(1,3)*dielt(2,1)*&
1875 : dielt(3,2)+dielt(1,2)*dielt(2,3)*dielt(3,1)-dielt(1,3)*&
1876 : dielt(2,2)*dielt(3,1)-dielt(1,1)*dielt(2,3)*dielt(3,2)-&
1877 65 : dielt(1,2)*dielt(2,1)*dielt(3,3)
1878 :
1879 : ! echo to log file
1880 65 : write(std_out,'(a)' )' ifc_write: analysis of interatomic force constants '
1881 65 : call mkrdim(Ifc%acell,Ifc%rprim,rprimd)
1882 65 : call matr3inv(rprimd,gprimd)
1883 :
1884 65 : if (iout > 0) then
1885 65 : write(iout, '(/,a,/)' )' Analysis of interatomic force constants '
1886 65 : if(Ifc%dipdip==1.and.Ifc%dipquad==0.and.Ifc%quadquad==0)then
1887 17 : write(iout, '(a)' )' Are given : column(1-3), the total force constant'
1888 17 : write(iout, '(a)' )' then column(4-6), the Ewald part'
1889 17 : write(iout, '(a)' )' then column(7-9), the short-range part'
1890 17 : write(iout, '(a)' )' Column 1, 4 and 7 are related to the displacement'
1891 17 : write(iout, '(a)' )' of the generic atom along x, '
1892 17 : write(iout, '(a)' )' column 2, 5 and 8 are related to the displacement'
1893 17 : write(iout, '(a)' )' of the generic atom along y, '
1894 17 : write(iout, '(a)' )' column 3, 6 and 9 are related to the displacement'
1895 17 : write(iout, '(a)')' of the generic atom along z. '
1896 48 : else if(Ifc%dipquad==1.or.Ifc%quadquad==1)then
1897 0 : write(iout, '(a)' )' Are given : column(1-3), ONLY the short-range part!!!!'
1898 0 : write(iout, '(a)' )' column 1 is related to the displacement'
1899 0 : write(iout, '(a)' )' of the generic atom along x, '
1900 0 : write(iout, '(a)' )' column 2 is related to the displacement'
1901 0 : write(iout, '(a)' )' of the generic atom along y, '
1902 0 : write(iout, '(a)' )' column 3 is related to the displacement'
1903 0 : write(iout, '(a)' )' of the generic atom along z, '
1904 48 : else if(Ifc%dipdip==0)then
1905 48 : write(iout, '(a)' )' column 1 is related to the displacement'
1906 48 : write(iout, '(a)' )' of the generic atom along x, '
1907 48 : write(iout, '(a)' )' column 2 is related to the displacement'
1908 48 : write(iout, '(a)' )' of the generic atom along y, '
1909 48 : write(iout, '(a)' )' column 3 is related to the displacement'
1910 48 : write(iout, '(a)' )' of the generic atom along z, '
1911 : end if
1912 : end if
1913 :
1914 65 : if (ifcout>Ifc%natom*Ifc%nrpt .or. ifcout == -1) then
1915 0 : ifcout1=Ifc%natom*Ifc%nrpt
1916 : write(msg, '(3a,i0,a)' )&
1917 0 : 'The value of ifcout exceeds the number of atoms in the big box.', ch10, &
1918 0 : 'Output limited to ',Ifc%natom*Ifc%nrpt,' atoms.'
1919 0 : ABI_WARNING(msg)
1920 : else
1921 65 : ifcout1=ifcout
1922 : end if
1923 :
1924 : ! set up file for real space ifc output, if required
1925 65 : if (prt_ifc == 1) then
1926 53 : filename = trim(prefix)//'_ifcinfo.dat'
1927 53 : if (open_file(trim(filename), msg, newunit=unit_ifc, status="replace") /= 0) then
1928 0 : ABI_ERROR(msg)
1929 : end if
1930 53 : write(iout, '(a,a)' )ch10,&
1931 106 : ' NOTE: Open file _ifcinfo.dat, for the output of interatomic force constants. This is because prt_ifc==1. '
1932 :
1933 53 : filename = trim(prefix)//'_forceconstants.dat'
1934 53 : if (open_file(trim(filename), msg, newunit=unit_tdep, status="replace") /= 0) then
1935 0 : ABI_ERROR(msg)
1936 : end if
1937 53 : write(iout, '(a,a,a)' )ch10,&
1938 53 : ' NOTE: Open file _forceconstants.dat, for the output of interatomic force',&
1939 106 : ' constants in TDEP format. This is because prt_ifc==1. '
1940 : ! Print necessary stuff for TDEP
1941 53 : write(unit_tdep,"(1X,I10,15X,'How many atoms per unit cell')") Ifc%natom
1942 :
1943 : ! look at all pairs, find furthest one with weight 1
1944 : ! do ia
1945 : !Ifc%wghatm(ia,ib,irpt)
1946 53 : maxdist_tdep = Ifc%r_inscribed_sphere !maxval(dist)*0.8_dp
1947 53 : write(unit_tdep,"(1X,F20.15,5X,'Realspace cutoff (A)')") maxdist_tdep*Bohr_Ang
1948 : end if
1949 :
1950 65 : if (ncid /= nctk_noid) then
1951 : ! initialize netcdf variables
1952 : ncerr = nctk_def_dims(ncid, [nctkdim_t("natifc", SUM(atifcflg)), nctkdim_t("number_of_r_points_big_box", Ifc%nrpt), &
1953 499 : nctkdim_t("number_of_atoms_big_box", Ifc%natom*Ifc%nrpt), nctkdim_t("ifcout", ifcout1)], defmode=.True.)
1954 65 : NCF_CHECK(ncerr)
1955 :
1956 : ncerr = nctk_def_arrays(ncid, [&
1957 : nctkarr_t('ifc_atoms_indices', "i", "natifc"),&
1958 : nctkarr_t('ifc_neighbours_indices', "i", "ifcout, natifc"),&
1959 : nctkarr_t('ifc_distances', "dp", "ifcout, natifc "),&
1960 : nctkarr_t('ifc_matrix_cart_coord', "dp", "number_of_cartesian_directions,number_of_cartesian_directions, ifcout, natifc"),&
1961 : nctkarr_t('ifc_atoms_cart_coord', "dp", "number_of_cartesian_directions,ifcout, natifc"),&
1962 455 : nctkarr_t('ifc_weights', "dp", "ifcout, natifc")])
1963 65 : NCF_CHECK(ncerr)
1964 :
1965 65 : if (Ifc%dipdip==1) then
1966 : ncerr = nctk_def_arrays(ncid, [&
1967 : nctkarr_t('ifc_matrix_cart_coord_short_range', "dp", &
1968 34 : "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
1969 17 : NCF_CHECK(ncerr)
1970 : end if
1971 :
1972 65 : if (ifcana==1) then
1973 : ncerr = nctk_def_arrays(ncid, [&
1974 128 : nctkarr_t('ifc_local_vectors', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
1975 64 : NCF_CHECK(ncerr)
1976 : end if
1977 :
1978 65 : NCF_CHECK(nctk_set_datamode(ncid))
1979 : end if
1980 :
1981 195 : ABI_MALLOC(rsiaf,(3,3,ifcout1))
1982 130 : ABI_MALLOC(sriaf,(3,3,ifcout1))
1983 130 : ABI_MALLOC(vect,(3,3,ifcout1))
1984 195 : ABI_MALLOC(indngb,(ifcout1))
1985 195 : ABI_MALLOC(posngb,(3,ifcout1))
1986 195 : ABI_MALLOC(wghia,(ifcout1))
1987 :
1988 65 : iatifc=0
1989 :
1990 : ! BIG loop on all generic atoms
1991 239 : do ia=1,Ifc%natom
1992 239 : if(atifcflg(ia)==1)then
1993 :
1994 141 : iatifc=iatifc+1
1995 :
1996 : ! First transform canonical coordinates to reduced coordinates
1997 564 : do ii=1,3
1998 564 : xred(ii)=Ifc%gprim(1,ii)*Ifc%rcan(1,ia)+Ifc%gprim(2,ii)*Ifc%rcan(2,ia)+Ifc%gprim(3,ii)*Ifc%rcan(3,ia)
1999 : end do
2000 : ! Then to cartesian coordinates
2001 564 : ra(:)=xred(1)*Ifc%acell(1)*Ifc%rprim(:,1)+ xred(2)*Ifc%acell(2)*Ifc%rprim(:,2)+ xred(3)*Ifc%acell(3)*Ifc%rprim(:,3)
2002 :
2003 : ! This sorting algorithm is slow ...
2004 282 : wkdist(:)=reshape(dist(ia,:,:),(/Ifc%natom*Ifc%nrpt/))
2005 383886 : do ii=1,Ifc%natom*Ifc%nrpt
2006 383886 : list(ii)=ii
2007 : end do
2008 141 : call sort_dp(Ifc%natom*Ifc%nrpt,wkdist,list,tol14)
2009 :
2010 141 : if (iout > 0) then
2011 141 : write(iout, '(a)' )
2012 141 : write(std_out,'(a,i4)' )' generic atom number',ia
2013 141 : write(iout, '(a,i4)' )' generic atom number',ia
2014 141 : write(std_out,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
2015 141 : write(iout,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
2016 141 : write(iout, '(a)' )
2017 : end if
2018 :
2019 : ! =========================================================================== !
2020 : ! Side effects happen here
2021 : ! The long-range part of the IFC (ewald_atmfrc) gets computed.
2022 :
2023 : ! BEGIN DEBUG
2024 : !write(*,*) 'ifc_write (1) : Writing atmfrc'
2025 : !write(*,*) 'atmfrc : ', Ifc%atmfrc
2026 : !call flush()
2027 : ! END DEBUG
2028 : call ifc_getiaf(Ifc,ifcana,ifcout1,iout,ifc%zeff,ia,ra,list,dist,invdlt,&
2029 141 : detdlt,rsiaf,sriaf,vect,indngb,posngb)
2030 :
2031 : ! =========================================================================== !
2032 :
2033 141 : if (prt_ifc == 1) then
2034 24220 : do ii=1,ifcout1
2035 24220 : if (wkdist(ii) > maxdist_tdep) exit
2036 : end do
2037 123 : ii = ii - 1
2038 123 : write(unit_tdep,"(1X,I10,15X,'How many neighbours does atom ',I3,' have')") ii, ia
2039 :
2040 24220 : do ii=1,ifcout1
2041 24097 : ib = indngb(ii)
2042 24097 : irpt = (list(ii)-1)/Ifc%natom+1
2043 24097 : wghia(ii) = Ifc%wghatm(ia,ib,irpt)
2044 : ! limit printing to maximum distance for tdep
2045 24097 : if (wkdist(ii) > maxdist_tdep) cycle
2046 :
2047 : !TDEP
2048 24097 : call int2char4(ii, str1)
2049 24097 : call int2char4(ia, str2)
2050 24097 : write(unit_tdep,"(1X,I10,15X,a,a,a,a)") ib, &
2051 24097 : & 'In the unit cell, what is the index of neighbour ', &
2052 48194 : & trim(str1), " of atom ", trim(str2)
2053 : ! The lattice vector needs to be in reduced coordinates?
2054 : ! TODO: check whether this is correct for TDEP: might need just lattice
2055 : ! vector part and not full vector, and could be in integers instead of
2056 : ! cartesian vector...
2057 313261 : write (unit_tdep,'(3es28.16)') matmul(Ifc%rpt(1:3,irpt),Ifc%gprim)
2058 :
2059 : !AI2PS
2060 24097 : write(unit_ifc,'(i6,i6)') ia,ii
2061 24097 : write(unit_ifc,'(3es28.16)') posngb(1:3,ii)
2062 96511 : do nu=1,3
2063 : !TDEp
2064 : ! And the actual short ranged forceconstant: TODO: check if
2065 : ! a transpose is needed or a swap between the nu and the mu
2066 : !write(unit_tdep,'(3f28.16)') (sriaf(nu,mu,ii)*Ha_eV/amu_emass, mu=1, 3)
2067 289164 : write(unit_tdep,'(3f28.16)') (Ifc%short_atmfrc(mu,ia,nu,ib,irpt)*Ha_eV/Bohr_Ang**2, mu=1, 3)
2068 :
2069 : !AI2PS
2070 96388 : write(unit_ifc,'(3f28.16)')(rsiaf(nu,mu,ii),mu=1,3)
2071 : end do
2072 : end do
2073 :
2074 123 : if (ncid /= nctk_noid) then
2075 246 : NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_indices"), ia, start=[iatifc]))
2076 615 : NCF_CHECK(nf90_put_var(ncid, vid("ifc_neighbours_indices"), indngb, start=[1,iatifc], count=[ifcout1,1]))
2077 615 : NCF_CHECK(nf90_put_var(ncid, vid("ifc_distances"), wkdist(:ifcout1), start=[1,iatifc],count=[ifcout1,1]))
2078 1107 : ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord"), rsiaf, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
2079 123 : NCF_CHECK(ncerr)
2080 861 : NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_cart_coord"), posngb, start=[1,1,iatifc], count=[3,ifcout1,1]))
2081 615 : NCF_CHECK(nf90_put_var(ncid, vid("ifc_weights"), wghia, start=[1,iatifc], count=[ifcout1,1]))
2082 :
2083 123 : if (Ifc%dipdip==1) then
2084 : ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord_short_range"), sriaf, &
2085 216 : start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
2086 24 : NCF_CHECK(ncerr)
2087 : end if
2088 123 : if (ifcana==1) then
2089 1107 : ncerr = nf90_put_var(ncid, vid("ifc_local_vectors"), vect, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
2090 123 : NCF_CHECK(ncerr)
2091 : end if
2092 : end if
2093 : end if
2094 : end if ! End the condition on atifcflg
2095 : end do ! End Big loop on atoms in the unit cell, and corresponding test
2096 :
2097 :
2098 : ! NB for future use: in TDEP the following can also be provided.
2099 : ! ! Print some auxiliary information, if it is there. Such as norm of
2100 : ! ! forceconstant per shell, which shells there are and so on.
2101 : ! if ( fc%npairshells .gt. 0 .and. allocated(fc%pairshell) ) then
2102 : ! write(u,"(1X,I10,15X,'Number of irreducible coordination shells')") fc%npairshells
2103 : ! do i=1,fc%npairshells
2104 : ! write(u,"(1X,I10,1X,F16.10,1X,F16.10,15X,'number atoms in shell, radius, norm of forceconstant',I0)") fc%pairshell(i)%n,fc%pairshell(i)%rad,fc%pairshell(i)%norm,i
2105 : ! enddo
2106 : ! do i=1,fc%npairshells
2107 : ! do j=1,fc%pairshell(i)%n
2108 : ! write(u,"(1X,3(1X,F18.12),2(1X,I0))") lo_chop(matmul(p%inv_latticevectors,fc%pairshell(i)%vec(:,j)),lo_sqtol),fc%pairshell(i)%atind(j),fc%pairshell(i)%pairind(j)
2109 : ! enddo
2110 : ! enddo
2111 : ! endif
2112 :
2113 65 : if (prt_ifc == 1) then
2114 53 : close(unit_ifc)
2115 53 : close(unit_tdep)
2116 :
2117 53 : filename = trim(prefix)//'_lotosplitting.dat'
2118 53 : if (open_file(trim(filename), msg, newunit=unit_tdep, status="replace") /= 0) then
2119 0 : ABI_ERROR(msg)
2120 : end if
2121 53 : write(unit_tdep,'(3es28.16)') dielt(:,1)
2122 53 : write(unit_tdep,'(3es28.16)') dielt(:,2)
2123 53 : write(unit_tdep,'(3es28.16)') dielt(:,3)
2124 183 : do ia = 1, Ifc%natom
2125 573 : do ii = 1, 3
2126 520 : write(unit_tdep,'(3es28.16)') ifc%zeff(:,ii,ia)
2127 : end do
2128 : end do
2129 53 : close(unit_tdep)
2130 : end if
2131 :
2132 65 : ABI_FREE(rsiaf)
2133 65 : ABI_FREE(sriaf)
2134 65 : ABI_FREE(vect)
2135 65 : ABI_FREE(indngb)
2136 65 : ABI_FREE(posngb)
2137 65 : ABI_FREE(dist)
2138 65 : ABI_FREE(list)
2139 65 : ABI_FREE(wkdist)
2140 65 : ABI_FREE(wghia)
2141 :
2142 : contains
2143 885 : integer function vid(vname)
2144 : character(len=*),intent(in) :: vname
2145 885 : vid = nctk_idname(ncid, vname)
2146 : end function vid
2147 :
2148 : end subroutine ifc_write
2149 : !!***
2150 :
2151 : !----------------------------------------------------------------------
2152 :
2153 : !!****f* m_ifc/ifc_getiaf
2154 : !!
2155 : !! NAME
2156 : !! ifc_getiaf
2157 : !!
2158 : !! FUNCTION
2159 : !! Extracts the IFCs needed for the output for one atom in the
2160 : !! unit cell. Accumulates the results for writing in the NetCDF file.
2161 : !! Prints to the output file
2162 : !!
2163 : !! INPUTS
2164 : !! ifcana= 0 => no analysis of ifc ; 1 => full analysis
2165 : !! ifcout= Number of interatomic force constants written in the output file
2166 : !! iout=unit number for nice output
2167 : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
2168 : !! ia=index of the atom in the unit cell for which the IFCs are being analyzed
2169 : !! ra(3)=position of atom ia in cartesian coordinates
2170 : !! list(ifcout)=index of permutation for distances from atom ia in ascending order
2171 : !! dist(natom,natom,nrpt)=distance from atom ia to atom ib in unit cell irpt.
2172 : !! invdlt(3,3)=inverse (transpose) of the dielectric tensor
2173 : !! detdlt=determinant of the dielectric tensor
2174 : !!
2175 : !! OUTPUT
2176 : !! rsiaf(3,3,ifcout)=list of real space IFCs
2177 : !! sriaf(3,3,ifcout)=list of the short range part of the real space IFCs
2178 : !! vect(3,3,ifcout)=base vectors for local coordinates (longitudinal/transverse), if ifc_getiaf is able to find
2179 : !! a third atom not aligned with the two atoms characterizing the IFC. If no, the second and third vectors are set to zero.
2180 : !! indngb(ifcout)=indices in the unit cell of the neighbouring atoms
2181 : !! posngb(3,ifcout)=position of the neighbouring atoms in cartesian coordinates
2182 : !! output file
2183 : !!
2184 : !! SIDE EFFECTS
2185 : !! The long-range part of the IFC (ewald_atmfrc) gets computed.
2186 : !!
2187 : !! NOTES
2188 : !! This routine should be executed by one processor only
2189 : !!
2190 : !! SOURCE
2191 :
2192 141 : subroutine ifc_getiaf(Ifc,ifcana,ifcout,iout,zeff,ia,ra,list,&
2193 141 : dist,invdlt,detdlt,rsiaf,sriaf,vect,indngb,posngb)
2194 :
2195 : !Arguments -------------------------------
2196 : !scalars
2197 : class(ifc_type),intent(inout) :: Ifc
2198 : integer,intent(in) :: ia,ifcana,ifcout,iout
2199 : real(dp), intent(in) :: detdlt
2200 : !arrays
2201 : real(dp),intent(in) :: invdlt(3,3),ra(3)
2202 : real(dp),intent(in) :: dist(Ifc%natom,Ifc%natom,Ifc%nrpt)
2203 : real(dp),intent(in) :: zeff(3,3,Ifc%natom)
2204 : integer,intent(in) :: list(Ifc%natom*Ifc%nrpt)
2205 : integer,intent(out) :: indngb(ifcout)
2206 : real(dp),intent(out) :: rsiaf(3,3,ifcout),sriaf(3,3,ifcout),vect(3,3,ifcout),posngb(3,ifcout)
2207 :
2208 : !Local variables -------------------------
2209 : !scalars
2210 : integer :: flag,ib,ii,index,jj,kk,mu,nu,irpt
2211 : real(dp) :: ew1,rsq,scprod,trace1,trace2,trace3, yy,dist1
2212 : character(len=500) :: msg
2213 : !arrays
2214 : real(dp) :: ewiaf0(3,3),ewiaf1(3,3),ewloc(3,3),ifcloc(3,3)
2215 : real(dp) :: rcart(3),rdiff(3),rsloc(3,3), srloc(3,3),vect1(3),vect2(3),vect3(3),work(3),xx(3)
2216 : ! *********************************************************************
2217 :
2218 141 : if(ifcana==1)then
2219 : ! Generate the local coordinate system for the atom ia
2220 138 : index=list(2)
2221 138 : write(std_out,*)index
2222 138 : call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
2223 138 : vect2(1)=rcart(1)-ra(1)
2224 138 : vect2(2)=rcart(2)-ra(2)
2225 138 : vect2(3)=rcart(3)-ra(3)
2226 138 : flag=0
2227 160 : do ii=3,Ifc%natom*Ifc%nrpt
2228 160 : index=list(ii)
2229 160 : call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
2230 160 : vect1(1)=(rcart(1)-ra(1))-vect2(1)
2231 160 : vect1(2)=(rcart(2)-ra(2))-vect2(2)
2232 160 : vect1(3)=(rcart(3)-ra(3))-vect2(3)
2233 160 : scprod=0.0_dp
2234 640 : do jj=1,3
2235 640 : scprod=scprod+vect1(jj)**2
2236 : end do
2237 640 : do jj=1,3
2238 640 : vect1(jj)=vect1(jj)/scprod**0.5
2239 : end do
2240 : scprod=0.0_dp
2241 640 : do jj=1,3
2242 640 : scprod=scprod+vect2(jj)*vect1(jj)
2243 : end do
2244 640 : do jj=1,3
2245 640 : work(jj)=vect2(jj)-vect1(jj)*scprod
2246 : end do
2247 : scprod=0.0_dp
2248 640 : do jj=1,3
2249 640 : scprod=scprod+work(jj)**2
2250 : end do
2251 160 : if(scprod>1.0d-10)then
2252 : flag=1
2253 : end if
2254 0 : if(flag==1)exit
2255 : end do
2256 138 : if(flag==0)then
2257 : write(msg, '(3a)' )&
2258 0 : 'Unable to find a third atom not aligned with the two selected ones.',ch10,&
2259 0 : 'The local analysis (longitudinal/transverse) will not be done. The two transverse vectors are set to zero.'
2260 0 : ABI_WARNING(msg)
2261 0 : vect2(:)=zero ; vect3(:)=zero
2262 : else
2263 138 : vect2(1)=work(1)/scprod**0.5
2264 138 : vect2(2)=work(2)/scprod**0.5
2265 138 : vect2(3)=work(3)/scprod**0.5
2266 138 : vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
2267 138 : vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
2268 138 : vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
2269 138 : if (iout > 0) then
2270 138 : write(iout, '(a)' )' Third atom defining local coordinates : '
2271 138 : write(iout, '(a,i4,a,i4)' )' ib = ',ib,' irpt = ',irpt
2272 : end if
2273 : endif
2274 : end if
2275 :
2276 : ! Analysis and output of force constants, ordered with respect to the distance from atom ia
2277 24596 : do ii=1,ifcout
2278 24455 : index=list(ii)
2279 24455 : call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,posngb(:,ii),Ifc%rprim,Ifc%rpt)
2280 24455 : indngb(ii)=ib
2281 24455 : dist1=dist(ia,ib,irpt)
2282 24455 : if (iout > 0) then
2283 24455 : write(iout, '(a)' )
2284 24455 : write(iout, '(i4,a,i6,a,i8)' )ii,' interaction with atom',ib,' cell',irpt
2285 97820 : write(iout, '(a,3es16.6)' )' with coordinates ',posngb(1:3,ii)*(one+tol8)
2286 24455 : write(iout, '(a,es16.6)' )' and distance ',dist1
2287 : end if
2288 :
2289 24455 : if(ifcana==1.and.ii/=1)then
2290 24257 : vect1(1)=(posngb(1,ii)-ra(1))/dist1
2291 24257 : vect1(2)=(posngb(2,ii)-ra(2))/dist1
2292 24257 : vect1(3)=(posngb(3,ii)-ra(3))/dist1
2293 : end if
2294 :
2295 24596 : if(Ifc%dipdip==0.or.Ifc%dipquad==1.or.Ifc%quadquad==1)then
2296 : ! Get the "total" force constants (=real space FC)
2297 : ! without taking into account the dipole-dipole interaction
2298 79140 : do mu=1,3
2299 257205 : do nu=1,3
2300 237420 : rsiaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt) * Ifc%wghatm(ia,ib,irpt)
2301 : end do
2302 : end do
2303 : ! Output of the ifcs in cartesian coordinates
2304 19785 : if (iout > 0) then
2305 79140 : do nu=1,3
2306 237420 : write(iout, '(1x,3f9.5)' )(rsiaf(mu,nu,ii)+tol10,mu=1,3)
2307 : ! transfer short range and long range
2308 257205 : do mu=1,3
2309 237420 : Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = rsiaf(mu,nu,ii) + tol10
2310 : end do
2311 :
2312 : end do
2313 : end if
2314 :
2315 19785 : if(ifcana==1)then
2316 : ! Further analysis
2317 19785 : trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
2318 19785 : if (iout > 0) then
2319 19785 : write(iout, '(a,f9.5)' ) ' Trace ',trace1+tol10
2320 : end if
2321 19785 : if(flag==1)then
2322 19785 : if(ii/=1)then
2323 19680 : call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
2324 : end if
2325 19785 : if (iout > 0) then
2326 19785 : write(iout, '(a)' )' Transformation to local coordinates '
2327 19785 : write(iout, '(a,3f16.6)' ) ' First local vector :',vect1
2328 19785 : write(iout, '(a,3f16.6)' ) ' Second local vector :',vect2
2329 19785 : write(iout, '(a,3f16.6)' ) ' Third local vector :',vect3
2330 : end if
2331 19785 : call ifclo9(rsiaf(:,:,ii),ifcloc,vect1,vect2,vect3)
2332 19785 : if (iout > 0) then
2333 79140 : do nu=1,3
2334 257205 : write(iout, '(1x,3f9.5)' )(ifcloc(mu,nu)+tol10,mu=1,3)
2335 : end do
2336 : end if
2337 : endif ! flag==1
2338 :
2339 79140 : vect(:,1,ii) = vect1
2340 79140 : vect(:,2,ii) = vect2
2341 79140 : vect(:,3,ii) = vect3
2342 :
2343 : end if ! Further analysis finished
2344 :
2345 4670 : else if(Ifc%dipdip==1)then
2346 :
2347 : !write(iout,'(a)')
2348 : !write(iout,'(a)')' Enter dipdip section, for debugging'
2349 : !write(iout,'(a)')
2350 :
2351 : ! Get the Coulomb part
2352 18680 : do jj=1,3
2353 18680 : rdiff(jj)=ra(jj)-posngb(jj,ii)
2354 : end do
2355 4670 : rsq=0.0_dp
2356 4670 : xx(1:3)=0.0_dp
2357 18680 : do jj=1,3
2358 60710 : do kk=1,3
2359 42030 : ewiaf0(jj,kk)=0.0_dp
2360 42030 : rsq=rsq+rdiff(jj)*invdlt(kk,jj)*rdiff(kk)
2361 56040 : xx(kk)=xx(kk)+invdlt(kk,jj)*rdiff(jj)
2362 : end do
2363 : end do
2364 4670 : yy=sqrt(rsq)
2365 : ! Avoid zero denominators in term:
2366 4670 : if (sqrt(rsq)>=tol12) then
2367 18536 : do mu=1,3
2368 60242 : do nu=1,3
2369 55608 : ewiaf0(mu,nu)=(-3*xx(nu)*xx(mu)+invdlt(nu,mu)*yy**2)/yy**5/sqrt(detdlt)
2370 : end do
2371 : end do
2372 : else
2373 36 : if (ia/=ib)then
2374 : write(msg, '(a,a,a,a,a,i5,a,i5,a)' )&
2375 0 : 'The distance between two atoms vanishes.',ch10,&
2376 0 : 'This is not allowed.',ch10,&
2377 0 : 'Action: check the input for the atoms number',ia,' and',ib,'.'
2378 0 : ABI_ERROR(msg)
2379 : end if
2380 : end if
2381 :
2382 : ! Take into account the effective charge tensor
2383 18680 : do mu=1,3
2384 60710 : do nu=1,3
2385 42030 : ew1=zero
2386 42030 : if(ii==1)then
2387 324 : ew1=-Ifc%dyewq0(mu,nu,ia)
2388 : end if
2389 168120 : do jj=1,3
2390 546390 : do kk=1,3
2391 504360 : ew1=ew1+zeff(jj,mu,ia)*(zeff(kk,nu,ib)* ewiaf0(jj,kk))
2392 : end do
2393 : end do
2394 56040 : ewiaf1(mu,nu)=ew1
2395 : end do
2396 : end do
2397 : ! Get the short-range force constants and the
2398 : ! "total" force constants (=real space FC)
2399 18680 : do mu=1,3
2400 60710 : do nu=1,3
2401 42030 : sriaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt)* Ifc%wghatm(ia,ib,irpt)
2402 56040 : rsiaf(mu,nu,ii)=ewiaf1(mu,nu)+sriaf(mu,nu,ii)
2403 : end do
2404 : end do
2405 :
2406 : ! Output of the results
2407 4670 : if (iout > 0) then
2408 18680 : do nu=1,3
2409 : write(iout, '(1x,3(3f9.5,1x))' )&
2410 56040 : (rsiaf(mu,nu,ii) +tol10,mu=1,3),&
2411 56040 : (ewiaf1(mu,nu)+tol10,mu=1,3),&
2412 168120 : (sriaf(mu,nu,ii) +tol10,mu=1,3)
2413 :
2414 : ! transfer short range and long range
2415 60710 : do mu=1,3
2416 42030 : Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = sriaf(mu,nu,ii) + tol10
2417 56040 : Ifc%ewald_atmfrc(mu,ia,nu,ib,irpt) = ewiaf1(mu,nu) + tol10
2418 : end do
2419 : end do
2420 : end if
2421 :
2422 4670 : if(ifcana==1)then
2423 : ! Further analysis
2424 4610 : if (iout > 0) then
2425 4610 : write(iout, '(a)' )' Traces (and ratios) :'
2426 : end if
2427 4610 : trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
2428 4610 : trace2=ewiaf1(1,1)+ewiaf1(2,2)+ewiaf1(3,3)
2429 4610 : trace3=sriaf(1,1,ii)+sriaf(2,2,ii)+sriaf(3,3,ii)
2430 4610 : if (iout > 0) then
2431 4610 : write(iout,'(3(f9.5,17x))')trace1+tol10,trace2+tol10,trace3+tol10
2432 4610 : write(iout,'(3(f9.5,17x))')1.0,(trace2+tol10)/(trace1+tol10),(trace3+tol10)/(trace1+tol10) !
2433 : end if
2434 :
2435 4610 : if(flag==1)then
2436 4610 : if(ii/=1)then
2437 4577 : call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
2438 : end if
2439 4610 : if (iout > 0) then
2440 4610 : write(iout, '(a)' )' Transformation to local coordinates '
2441 4610 : write(iout, '(a,3f16.6)' )' First local vector :',vect1
2442 4610 : write(iout, '(a,3f16.6)' )' Second local vector :',vect2
2443 4610 : write(iout, '(a,3f16.6)' )' Third local vector :',vect3
2444 : end if
2445 4610 : call ifclo9(rsiaf(:,:,ii),rsloc,vect1,vect2,vect3)
2446 4610 : call ifclo9(ewiaf1,ewloc,vect1,vect2,vect3)
2447 4610 : call ifclo9(sriaf(:,:,ii),srloc,vect1,vect2,vect3)
2448 4610 : if (iout > 0) then
2449 18440 : do nu=1,3
2450 : write(iout, '(1x,3(3f9.5,1x))' )&
2451 55320 : & (rsloc(mu,nu)+tol10,mu=1,3),&
2452 55320 : & (ewloc(mu,nu)+tol10,mu=1,3),&
2453 170570 : & (srloc(mu,nu)+tol10,mu=1,3)
2454 : end do
2455 4610 : if(ii/=1)then
2456 4577 : write(iout, '(a)' )' Ratio with respect to the longitudinal ifc'
2457 : else
2458 33 : write(iout, '(a)' )' Ratio with respect to the (1,1) element'
2459 : end if
2460 18440 : do nu=1,3
2461 : write(iout, '(1x,3(3f9.5,1x))' )&
2462 55320 : & (rsloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
2463 55320 : & (ewloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
2464 170570 : & (srloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3)
2465 : end do
2466 : end if
2467 : endif ! flag==1
2468 :
2469 18440 : vect(:,1,ii) = vect1
2470 18440 : vect(:,2,ii) = vect2
2471 18440 : vect(:,3,ii) = vect3
2472 :
2473 : end if ! Further analysis finished
2474 : end if ! End the condition on dipdip
2475 : end do ! End loop over all atoms in BigBox:
2476 :
2477 141 : end subroutine ifc_getiaf
2478 : !!***
2479 :
2480 : !----------------------------------------------------------------------
2481 :
2482 : !!****f* m_ifc/omega_decomp
2483 : !!
2484 : !! NAME
2485 : !! omega_decomp
2486 : !!
2487 : !! FUNCTION
2488 : !! Compute and return the eigenvalues (frequencies) of the short-range and
2489 : !! long-range part of the dynamical matrix See Europhys. Lett. 33 p.713 (1996) for details.
2490 : !! (included by U. Aschauer and EB)
2491 : !!
2492 : !! INPUTS
2493 : !!
2494 : !! OUTPUT
2495 : !!
2496 : !! SOURCE
2497 :
2498 0 : subroutine omega_decomp(amu,natom,ntypat,typat,dynmatfl,dynmatsr,dynmatlr,iqpt,nqpt,eigenvec)
2499 :
2500 : !Arguments -------------------------------
2501 : !scalars
2502 : integer,intent(in) :: natom,ntypat
2503 : integer,intent(in) :: iqpt,nqpt
2504 : !arrays
2505 : integer,intent(in) :: typat(natom)
2506 : real(dp),intent(in) :: amu(ntypat)
2507 : real(dp),intent(inout) :: dynmatfl(2,3,natom,3,natom,nqpt)
2508 : real(dp),intent(inout) :: dynmatsr(2,3,natom,3,natom,nqpt)
2509 : real(dp),intent(inout) :: dynmatlr(2,3,natom,3,natom,nqpt)
2510 : real(dp),intent(in) :: eigenvec(2*3*natom*3*natom)
2511 :
2512 : !Local variables -------------------------
2513 : !scalars
2514 : integer :: i1,i2,idir1,idir2,imode,ipert1,ipert2,index1,index2
2515 : real(dp),parameter :: break_symm=1.0d-12
2516 : real(dp) :: fac
2517 : !arrays
2518 : real(dp) :: omegafl, omegasr, omegalr, sumfl,sumlr,sumsr,asr
2519 : real(dp) :: nearidentity(3,3)
2520 : ! *********************************************************************
2521 :
2522 : !write(ab_out,*)''
2523 : !write(std_out,*) 'SR/LR decomposition: enter for wavevector number :',iqpt
2524 :
2525 : !apply asr (note the lr part is already asred by construction in mkifc9)
2526 0 : do ipert1=1,natom
2527 0 : do idir1=1,3
2528 0 : do idir2=1,3
2529 : asr=0.0d0
2530 0 : do ipert2=1,natom
2531 0 : asr=asr+dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)
2532 : end do
2533 0 : dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
2534 0 : dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
2535 : end do
2536 : end do
2537 : end do
2538 :
2539 : !This slight breaking of the symmetry allows the results to be more portable between machines
2540 0 : nearidentity(:,:)=1.0
2541 0 : nearidentity(1,1)=1.0+break_symm
2542 0 : nearidentity(3,3)=1.0-break_symm
2543 :
2544 : !Include Mass
2545 0 : do ipert1=1,natom
2546 0 : do ipert2=1,natom
2547 :
2548 0 : fac=1.0d0/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
2549 :
2550 0 : do idir1=1,3
2551 0 : do idir2=1,3
2552 :
2553 : dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2554 : & dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2555 0 : & fac*nearidentity(idir1,idir2)
2556 :
2557 : dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2558 : & dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2559 0 : & fac*nearidentity(idir1,idir2)
2560 :
2561 : dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2562 : & dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2563 0 : & fac*nearidentity(idir1,idir2)
2564 :
2565 : ! This is to break slightly the translation invariance, and make
2566 : ! the automatic tests more portable
2567 0 : if(ipert1==ipert2 .and. idir1==idir2)then
2568 : dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2569 : & dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2570 0 : & break_symm*natom/amu_emass/idir1*0.01d0
2571 :
2572 : dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2573 : & dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2574 0 : & break_symm*natom/amu_emass/idir1*0.01d0
2575 :
2576 : dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2577 : & dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2578 0 : & break_symm*natom/amu_emass/idir1*0.01d0
2579 : end if
2580 :
2581 : end do
2582 : end do
2583 : end do
2584 : end do
2585 :
2586 : !Calculation of <eigvec|Dyn_tot,Dyn_SR,Dyn_LR|eigenvec>=omega**2
2587 :
2588 : !write(ab_out,*)''
2589 : !write(ab_out,*)'==============================================================================='
2590 0 : write(ab_out,*)''
2591 0 : write(ab_out,*) 'Long-Range/Short-Range decomposed phonon freq. (cm-1)**2'
2592 0 : write(ab_out,*) 'at wavevector number:',iqpt
2593 0 : write(ab_out,*)''
2594 0 : write(ab_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
2595 0 : write(std_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
2596 : !write(ab_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
2597 : !write(std_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
2598 :
2599 0 : do imode=1,3*natom
2600 0 : sumfl=zero; sumlr=zero; sumsr=zero
2601 :
2602 0 : do ipert1=1,natom
2603 0 : do ipert2=1,natom
2604 0 : do i1=1,3
2605 0 : do i2=1,3
2606 :
2607 0 : index1=i1+(ipert1-1)*3+3*natom*(imode-1)
2608 0 : index2=i2+(ipert2-1)*3+3*natom*(imode-1)
2609 : ! MG FIXME: I don't think these expressions are correct when q != 0
2610 : ! We should also include the imaginary part
2611 :
2612 0 : sumfl = sumfl + eigenvec(2*index1-1) * dynmatfl(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2613 0 : sumlr = sumlr + eigenvec(2*index1-1) * dynmatlr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2614 0 : sumsr = sumsr + eigenvec(2*index1-1) * dynmatsr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2615 : end do
2616 : end do
2617 : end do
2618 : end do
2619 :
2620 0 : sumfl = sumfl * Ha_cmm1 * Ha_cmm1
2621 0 : sumsr = sumsr * Ha_cmm1 * Ha_cmm1
2622 0 : sumlr = sumlr * Ha_cmm1 * Ha_cmm1
2623 :
2624 : ! Compute omega=sqrt(omega**2)
2625 : if(sumfl>=1.0d-16)then
2626 : omegafl=sqrt(sumfl)
2627 : else if(sumfl>=-1.0d-16)then
2628 : omegafl=zero
2629 : else
2630 : omegafl=-sqrt(-sumfl)
2631 : end if
2632 :
2633 : if(sumsr>=1.0d-16)then
2634 : omegasr=sqrt(sumsr)
2635 : else if(sumsr>=-1.0d-16)then
2636 : omegasr=zero
2637 : else
2638 : omegasr=-sqrt(-sumsr)
2639 : end if
2640 :
2641 : if(sumlr>=1.0d-16)then
2642 : omegalr=sqrt(sumlr)
2643 : else if(sumlr>=-1.0d-16)then
2644 : omegalr=zero
2645 : else
2646 : omegalr=-sqrt(-sumlr)
2647 : end if
2648 :
2649 : ! Output
2650 0 : write(ab_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr !vz_d
2651 0 : write(std_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr !vz_d
2652 : ! write(ab_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
2653 : ! write(std_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
2654 : end do
2655 :
2656 0 : end subroutine omega_decomp
2657 : !!***
2658 :
2659 : !----------------------------------------------------------------------
2660 :
2661 : !!****f* m_ifc/ifc_outphbtrap
2662 : !! NAME
2663 : !! ifc_outphbtrap
2664 : !!
2665 : !! FUNCTION
2666 : !! Print out phonon frequencies on regular grid for BoltzTrap
2667 : !! Flag in input file is outboltztrap=1
2668 : !!
2669 : !! INPUTS
2670 : !! Crystal<crystal_t>=Info on the crystal structure
2671 : !! basename = file name for output to disk
2672 : !! ngqpt(3)=Divisions of the q-mesh
2673 : !! nqshft=Number of shifts
2674 : !! qshft(3,nqshft)=Shifts of the q-mesh.
2675 : !!
2676 : !! OUTPUT
2677 : !! only write to file. This routine should be called by a single processor.
2678 : !!
2679 : !! SOURCE
2680 :
2681 2 : subroutine ifc_outphbtrap(ifc, cryst, ngqpt, nqshft, qshft, basename)
2682 :
2683 : !Arguments -------------------------------
2684 : !scalars
2685 : class(ifc_type),intent(in) :: ifc
2686 : integer,intent(in) :: nqshft
2687 : character(len=*),intent(in) :: basename
2688 : type(crystal_t),intent(in) :: cryst
2689 : !arrays
2690 : integer,intent(in) :: ngqpt(3)
2691 : real(dp),intent(in) :: qshft(3,nqshft)
2692 :
2693 : !Local variables -------------------------
2694 : !scalars
2695 : integer,parameter :: qptopt1=1
2696 : integer :: natom,imode,iq_ibz,nqbz,nqibz, nreals,unit_btrap,iatom,idir
2697 : character(len=500) :: msg,format_nreals,format_line_btrap
2698 : character(len=fnlen) :: outfile
2699 : !arrays
2700 : integer :: qptrlatt(3,3)
2701 4 : real(dp) :: d2cart(2,3,cryst%natom,3,cryst%natom),displ(2*3*cryst%natom*3*cryst%natom)
2702 4 : real(dp) :: phfrq(3*cryst%natom),qphon(3)
2703 2 : real(dp),allocatable :: qbz(:,:),qibz(:,:),wtq(:)
2704 : ! *********************************************************************
2705 :
2706 : DBG_ENTER("COLL")
2707 2 : natom = cryst%natom
2708 :
2709 : ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
2710 2 : qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
2711 2 : call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
2712 :
2713 2 : outfile = trim(basename) // '_BTRAP'
2714 2 : write(msg, '(3a)')ch10,' Will write phonon FREQS in BoltzTrap format to file ',trim(outfile)
2715 6 : call wrtout([std_out, ab_out], msg)
2716 :
2717 2 : if (open_file(outfile,msg,newunit=unit_btrap,status="replace") /= 0) then
2718 0 : ABI_ERROR(msg)
2719 : end if
2720 :
2721 2 : write(unit_btrap,'(a)') '#'
2722 2 : write(unit_btrap,'(a)') '# ABINIT package : Boltztrap phonon file. With old BT versions remove this header before feeding to BT'
2723 2 : write(unit_btrap,'(a)') '# for compatibility with PHON output the freq are in Ry (before the square)'
2724 2 : write(unit_btrap,'(a)') '#'
2725 2 : write(unit_btrap,'(a)') '# nq, nband '
2726 2 : write(unit_btrap,'(a)') '# qx, qy, qz '
2727 2 : write(unit_btrap,'(a)') '# qpt weight '
2728 2 : write(unit_btrap,'(a)') '# freq_1^2, dynmat column for mode 1 '
2729 2 : write(unit_btrap,'(a)') '# etc for mode 2,3,4... qpt 2,3,4... '
2730 2 : write(unit_btrap,'(2I6)') nqibz, 3*natom
2731 :
2732 : ! Loop over irreducible q-points
2733 197 : do iq_ibz=1,nqibz
2734 780 : qphon(:)=qibz(:,iq_ibz)
2735 :
2736 195 : call ifc%fourq(cryst, qphon, phfrq, displ, out_d2cart=d2cart)
2737 :
2738 195 : write (unit_btrap,'(3E20.10)') qphon
2739 195 : write (unit_btrap,'(E20.10)') wtq(iq_ibz)
2740 195 : nreals=1+2*3*natom
2741 195 : call appdig(nreals,'(',format_nreals)
2742 195 : format_line_btrap=trim(format_nreals)//'E20.10)'
2743 442 : do iatom = 1, natom
2744 1175 : do idir = 1, 3
2745 735 : imode = idir + 3*(iatom-1)
2746 : ! factor two for Ry output - this may change in definitive BT and abinit formats
2747 980 : write (unit_btrap,trim(format_line_btrap))phfrq(imode)*two,d2cart(1:2,1:3,1:natom,idir,iatom)
2748 : end do
2749 : end do
2750 :
2751 : end do !irred q-points
2752 2 : close (unit_btrap)
2753 :
2754 2 : ABI_FREE(qibz)
2755 2 : ABI_FREE(qbz)
2756 2 : ABI_FREE(wtq)
2757 :
2758 : DBG_EXIT("COLL")
2759 :
2760 2 : end subroutine ifc_outphbtrap
2761 : !!***
2762 :
2763 : !----------------------------------------------------------------------
2764 :
2765 : !!****f* m_ifc/ifc_printbxsf
2766 : !! NAME
2767 : !! ifc_printbxsf
2768 : !!
2769 : !! FUNCTION
2770 : !! Output phonon isosurface in Xcrysden format.
2771 : !!
2772 : !! INPUTS
2773 : !! crystal<crystal_t>=Info on the crystal structure
2774 : !! ngqpt(3)=Divisions of the q-mesh
2775 : !! nqshft=Number of shifts
2776 : !! qshft(3,nqshft)=Shifts of the q-mesh.
2777 : !! path=File name for output to disk
2778 : !! comm=MPI communicator.
2779 : !!
2780 : !! OUTPUT
2781 : !! Only write to file
2782 : !!
2783 : !! SOURCE
2784 :
2785 1 : subroutine ifc_printbxsf(ifc, cryst, ngqpt, nqshft, qshft, path, comm)
2786 :
2787 : !Arguments -------------------------------
2788 : !scalars
2789 : class(ifc_type),intent(in) :: ifc
2790 : integer,intent(in) :: nqshft,comm
2791 : character(len=*),intent(in) :: path
2792 : type(crystal_t),intent(in) :: cryst
2793 : !arrays
2794 : integer,intent(in) :: ngqpt(3)
2795 : real(dp),intent(in) :: qshft(3,nqshft)
2796 :
2797 : !Local variables -------------------------
2798 : !scalars
2799 : integer,parameter :: nsppol1=1,master=0,qptopt1=1
2800 : integer :: my_rank,nprocs,iq_ibz,nqibz,nqbz,ierr
2801 : character(len=500) :: msg
2802 : !arrays
2803 2 : integer :: qptrlatt(3,3),dummy_symafm(cryst%nsym)
2804 2 : real(dp) :: displ_cart(2,3*cryst%natom,3*cryst%natom)
2805 1 : real(dp),allocatable :: qibz(:,:),wtq(:),qbz(:,:),freqs_qibz(:,:)
2806 : ! *********************************************************************
2807 :
2808 1 : my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
2809 :
2810 : ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
2811 1 : qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
2812 1 : call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
2813 1 : ABI_FREE(qbz)
2814 1 : ABI_FREE(wtq)
2815 :
2816 : ! Compute phonon frequencies in the irreducible wedge.
2817 585 : ABI_CALLOC(freqs_qibz, (3*cryst%natom, nqibz))
2818 :
2819 146 : do iq_ibz=1,nqibz
2820 145 : if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi parallelism.
2821 146 : call ifc%fourq(cryst, qibz(:,iq_ibz), freqs_qibz(:,iq_ibz), displ_cart)
2822 : end do
2823 1 : call xmpi_sum(freqs_qibz, comm, ierr)
2824 :
2825 : ! Output phonon isosurface.
2826 1 : if (my_rank == master) then
2827 49 : dummy_symafm = 1
2828 : call printbxsf(freqs_qibz, zero, zero, cryst%gprimd, qptrlatt, 3*cryst%natom,&
2829 1 : nqibz, qibz, cryst%nsym, .False., cryst%symrec, dummy_symafm, .True., nsppol1, qshft, nqshft, path, ierr)
2830 1 : if (ierr /=0) then
2831 0 : msg = "Cannot produce BXSF file with phonon isosurface, see log file for more info"
2832 0 : ABI_WARNING(msg)
2833 0 : call wrtout(ab_out, msg)
2834 : end if
2835 : end if
2836 :
2837 1 : ABI_FREE(freqs_qibz)
2838 1 : ABI_FREE(qibz)
2839 :
2840 1 : end subroutine ifc_printbxsf
2841 : !!***
2842 :
2843 : !----------------------------------------------------------------------
2844 :
2845 : !!****f* m_ifc/ifc_calcnwrite_nana_terms
2846 : !! NAME
2847 : !! ifc_calcnwrite_nana_terms
2848 : !!
2849 : !! FUNCTION
2850 : !! Compute frequencies and phonon displacement for q-->0 in the presence of non-analytical behaviour.
2851 : !!
2852 : !! INPUTS
2853 : !! nph2l=Number of qpoints.
2854 : !! qph2l(3,nph2l)=List of phonon wavevector directions along which the non-analytical correction
2855 : !! to the Gamma-point phonon frequencies will be calculated
2856 : !! The direction is in CARTESIAN COORDINATES
2857 : !! qnrml2(nph2l)=Normalization factor.
2858 : !!
2859 : !! OUTPUT
2860 : !! (Optional)
2861 : !! phfrq2l(3*crystal%natom,nph2l)=List of phonon frequencies
2862 : !! polarity2l(3,3*crystal%natom,nph2l)=List of mode-polarities
2863 : !! (see Eq.(41) of Veithen et al, PRB71, 125107 (2005) [[cite:Veithen2005]])
2864 : !!
2865 : !! NOTES:
2866 : !! This routine should be called by master node and when ifcflag == 1.
2867 : !!
2868 : !! SOURCE
2869 :
2870 32 : subroutine ifc_calcnwrite_nana_terms(ifc, crystal, nph2l, qph2l, &
2871 6 : qnrml2, ncid, phfrq2l, polarity2l) ! optional arguments
2872 :
2873 : !Arguments ------------------------------------
2874 : class(ifc_type),intent(in) :: ifc
2875 : integer,intent(in) :: nph2l
2876 : integer,optional,intent(in) :: ncid
2877 : type(crystal_t),intent(in) :: crystal
2878 : !arrays
2879 : real(dp),intent(in) :: qph2l(3, nph2l)
2880 : real(dp),optional,intent(in) :: qnrml2(nph2l)
2881 : real(dp),optional,intent(out) :: phfrq2l(3*crystal%natom,nph2l), polarity2l(3,3*crystal%natom,nph2l)
2882 :
2883 : !Local variables-------------------------------
2884 : !scalars
2885 : integer :: iatom,idir,imode,iphl2, ncerr
2886 : real(dp) :: eta
2887 : !arrays
2888 : real(dp) :: qphnrm(3),qphon(3,3)
2889 32 : real(dp),allocatable :: displ_cart(:,:,:),phfrq(:),d2cart(:,:,:),eigvec(:,:,:),eigval(:)
2890 : ! ************************************************************************
2891 :
2892 32 : if (nph2l == 0) return
2893 :
2894 : ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
2895 96 : ABI_MALLOC(phfrq, (3*crystal%natom))
2896 128 : ABI_MALLOC(displ_cart, (2, 3*crystal%natom, 3*crystal%natom))
2897 128 : ABI_MALLOC(d2cart, (2, 3*ifc%mpert, 3*ifc%mpert))
2898 96 : ABI_MALLOC(eigvec, (2, 3*crystal%natom, 3*crystal%natom))
2899 64 : ABI_MALLOC(eigval, (3*crystal%natom))
2900 :
2901 : ! Before examining every direction or the dielectric tensor, generates the dynamical matrix at gamma
2902 128 : qphon(:,1)=zero; qphnrm(1)=zero
2903 :
2904 : ! Generation of the dynamical matrix in cartesian coordinates
2905 : ! Get d2cart using the interatomic forces and the long-range coulomb interaction through Ewald summation
2906 : call gtdyn9(ifc%acell,ifc%atmfrc,ifc%dielt,ifc%dipdip, &
2907 : ifc%dyewq0,d2cart,crystal%gmet,ifc%gprim,ifc%mpert,crystal%natom, &
2908 : ifc%nrpt,qphnrm(1),qphon,crystal%rmet,ifc%rprim,ifc%rpt, &
2909 32 : ifc%trans,crystal%ucvol,ifc%wghatm,crystal%xred,ifc%zeff,ifc%qdrp_cart,ifc%ewald_option,eta,xmpi_comm_self,ifc%sys_dim)
2910 :
2911 32 : if (present(ncid)) then
2912 29 : iphl2 = 0
2913 29 : call defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, mode="define")
2914 : ! Add epsinf, Born effective charges and some useful metadata.
2915 : ncerr = nctk_def_arrays(ncid, [ &
2916 : nctkarr_t('emacro_cart', "dp", 'number_of_cartesian_directions, number_of_cartesian_directions'), &
2917 : nctkarr_t('becs_cart', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, number_of_atoms")], &
2918 87 : defmode=.True.)
2919 29 : NCF_CHECK(ncerr)
2920 : ! TODO chneut is missing
2921 : ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
2922 116 : "asr", "dipdip", "symdynmat"])
2923 29 : NCF_CHECK(ncerr)
2924 29 : NCF_CHECK(nctk_set_datamode(ncid))
2925 29 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'emacro_cart'), ifc%dielt))
2926 29 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'becs_cart'), ifc%zeff))
2927 : ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
2928 : "asr", "dipdip", "symdynmat"], &
2929 203 : [ifc%asr, ifc%dipdip, ifc%symdynmat])
2930 29 : NCF_CHECK(ncerr)
2931 : end if
2932 :
2933 : ! Examine every wavevector of this list
2934 60069 : do iphl2=1,nph2l
2935 : ! Initialisation of the phonon wavevector
2936 240148 : qphon(:,1) = qph2l(:,iphl2)
2937 60037 : qphnrm(1)=zero
2938 60037 : if(present(qnrml2)) qphnrm(1) = qnrml2(iphl2)
2939 :
2940 : ! Calculation of the eigenvectors and eigenvalues of the dynamical matrix
2941 : call dfpt_phfrq(ifc%amu,displ_cart,d2cart,eigval,eigvec,crystal%indsym, &
2942 : ifc%mpert,crystal%nsym,crystal%natom,crystal%nsym,crystal%ntypat,phfrq,qphnrm(1),qphon, &
2943 60037 : crystal%rprimd,ifc%symdynmat,crystal%symrel,crystal%symafm,crystal%typat,crystal%ucvol)
2944 :
2945 : ! Write the phonon frequencies
2946 : !call dfpt_prtph(displ_cart,inp%eivec,inp%enunit,ab_out,natom,phfrq,qphnrm(1),qphon)
2947 :
2948 480037 : if(present(phfrq2l)) phfrq2l(:,iphl2)=phfrq(:)
2949 :
2950 60037 : if(present(polarity2l))then
2951 1740000 : polarity2l(:,:,iphl2)=zero
2952 480000 : do imode=1,3*crystal%natom
2953 1500000 : do iatom=1,crystal%natom
2954 4500000 : do idir=1,3
2955 13260000 : polarity2l(:,imode,iphl2)=polarity2l(:,imode,iphl2)+ifc%zeff(:,idir,iatom)*displ_cart(1,idir+(iatom-1)*3,imode)
2956 : enddo
2957 : enddo
2958 : enddo
2959 : endif
2960 :
2961 60069 : if(present(ncid))then
2962 : ! Loop is not MPI-parallelized --> no need for MPI-IO API.
2963 37 : call defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, mode="write")
2964 : endif
2965 : end do ! iphl2
2966 :
2967 32 : ABI_FREE(phfrq)
2968 32 : ABI_FREE(displ_cart)
2969 32 : ABI_FREE(d2cart)
2970 32 : ABI_FREE(eigvec)
2971 32 : ABI_FREE(eigval)
2972 :
2973 35 : end subroutine ifc_calcnwrite_nana_terms
2974 : !!***
2975 :
2976 : !----------------------------------------------------------------------
2977 :
2978 1 : subroutine ifc_calcnwrite_nana_terms_qpath(ifc, qpath, cryst, ncid, units)
2979 :
2980 : !Arguments ------------------------------------
2981 : class(ifc_type),intent(in) :: ifc
2982 : integer,intent(in) :: ncid, units(:)
2983 : type(kpath_t),intent(in) :: qpath
2984 : type(crystal_t),intent(in) :: cryst
2985 :
2986 : !Local variables-------------------------------
2987 : !scalars
2988 : integer :: iq, nq_vers, natom3, nu
2989 : character(len=500) :: msg
2990 : !arrays
2991 2 : real(dp) :: phfreqs(3*cryst%natom), displ_cart(2,3,cryst%natom,3*cryst%natom)
2992 1 : real(dp),allocatable :: qvers_red(:,:), qvers_cart(:,:)
2993 : ! ************************************************************************
2994 :
2995 1 : natom3 = 3 * cryst%natom
2996 1 : call qpath%get_versors(nq_vers, qvers_red, qvers_cart)
2997 :
2998 3 : do iq=1,nq_vers
2999 2 : call ifc%fourq(cryst, qvers_red(:,iq), phfreqs, displ_cart, nanaqdir="reduced")
3000 :
3001 2 : call wrtout(units, sjoin("Phonon frequencies in meV along reduced direction:", ktoa(qvers_red(:,iq)), "(reciprocal space)"))
3002 2 : if (iq == 1) then
3003 1 : call defwrite_nonana_terms(ncid, iq, nq_vers, qvers_cart, cryst%natom, phfreqs, displ_cart, mode="define")
3004 : end if
3005 2 : call defwrite_nonana_terms(ncid, iq, nq_vers, qvers_cart, cryst%natom, phfreqs, displ_cart, mode="write")
3006 :
3007 15 : do nu=1,natom3
3008 12 : write(msg, "(1x,i0, es16.6)") nu, phfreqs(nu) * Ha_meV
3009 14 : call wrtout(units, msg)
3010 : end do
3011 : end do
3012 :
3013 1 : ABI_FREE(qvers_red)
3014 1 : ABI_FREE(qvers_cart)
3015 :
3016 1 : end subroutine ifc_calcnwrite_nana_terms_qpath
3017 : !!***
3018 :
3019 : !----------------------------------------------------------------------
3020 :
3021 : !!****f* m_ifc/ifc_to_ddb
3022 : !! NAME
3023 : !! ifc_to_ddb
3024 : !!
3025 : !! FUNCTION
3026 : !! Construct a DDB object from the IFC object.
3027 : !!
3028 : !! INPUTS
3029 : !! crystal = Crystal object
3030 : !!
3031 : !! OUTPUT
3032 : !! ddb = DDB object
3033 : !!
3034 : !! SOURCE
3035 :
3036 44 : subroutine ifc_to_ddb(ifc, ddb, crystal)
3037 :
3038 : !Arguments -----------------------------------
3039 : !scalars
3040 : class(ifc_type),intent(inout) :: ifc
3041 : type(ddb_type),intent(out) :: ddb
3042 : type(crystal_t),intent(in) :: crystal
3043 :
3044 : !Local variables-------------------------------
3045 : !scalars
3046 : integer,parameter :: qptopt=1, nqshft=1
3047 : integer :: jj,iqpt,idir1,idir2,ipert1,ipert2, mpert,msize, nqibz,nqbz
3048 : real(dp) :: qj,qptnrm
3049 : !arrays
3050 : integer :: qptrlatt(3,3)
3051 44 : integer,allocatable :: flg(:,:,:,:), flg_gamma(:,:,:,:)
3052 : real(dp) :: qpt(3), qshft(1,3)
3053 44 : real(dp),allocatable :: qibz(:,:),qbz(:,:), wtq(:), d2cart(:,:,:,:,:),d2red(:,:,:,:,:)
3054 : ! *********************************************************************
3055 :
3056 : ! Initialize DDB with minimal info
3057 : ! ================================
3058 :
3059 : ! Crystal info
3060 44 : ddb%natom = crystal%natom
3061 44 : ddb%ntypat = crystal%ntypat
3062 572 : ddb%rprim = ifc%rprim
3063 572 : ddb%gprim = ifc%gprim
3064 176 : ddb%acell = ifc%acell
3065 44 : call alloc_copy(crystal%amu, ddb%amu)
3066 :
3067 : ! Block size
3068 : ! GA: TODO need to compute mpert in a more transparent way.
3069 : ! Also, mpert should be consistent with ifc_init.
3070 44 : mpert = ddb%natom + 6
3071 44 : msize = 3*mpert*3*mpert
3072 44 : ddb%mpert = mpert
3073 44 : ddb%msize = msize
3074 :
3075 : ! Generate q-points
3076 44 : qshft = zero
3077 44 : qptrlatt = zero
3078 44 : qptrlatt(1,1)=ifc%ngqpt(1)
3079 44 : qptrlatt(2,2)=ifc%ngqpt(2)
3080 44 : qptrlatt(3,3)=ifc%ngqpt(3)
3081 :
3082 44 : call kpts_ibz_from_kptrlatt(crystal,qptrlatt,qptopt,nqshft,qshft, nqibz,qibz,wtq,nqbz,qbz)
3083 :
3084 44 : ddb%nblok = nqibz
3085 2166087 : ABI_MALLOC(ddb%flg,(msize,nqibz)) ; ddb%flg = one
3086 11911 : ABI_MALLOC(ddb%nrm,(3,nqibz)) ; ddb%nrm = zero ; ddb%nrm(1,:) = one
3087 23602 : ABI_MALLOC(ddb%qpt,(9,nqibz)) ; ddb%qpt = zero
3088 9476 : ABI_MALLOC(ddb%omega,(3,nqibz)) ; ddb%omega = zero
3089 6493215 : ABI_MALLOC(ddb%val,(2,msize,nqibz)); ddb%val = zero
3090 132 : ABI_MALLOC(ddb%typ,(nqibz))
3091 :
3092 2391 : do iqpt=1,nqibz
3093 2347 : ddb%typ(iqpt) = BLKTYP_d2E_ns
3094 9432 : do jj = 1,3
3095 7041 : qj = qibz(jj,iqpt)
3096 7041 : if (abs(qj).lt.tol8) qj = zero
3097 9388 : ddb%qpt(jj,iqpt) = qj
3098 : end do
3099 : end do
3100 :
3101 44 : ABI_FREE(wtq)
3102 44 : ABI_FREE(qibz)
3103 44 : ABI_FREE(qbz)
3104 :
3105 : ! Compute DDB by Fourier transform of the IFC
3106 : ! ===========================================
3107 :
3108 44 : qptnrm = one
3109 220 : ABI_MALLOC(d2cart,(2,3,mpert,3,mpert))
3110 132 : ABI_MALLOC(d2red,(2,3,mpert,3,mpert))
3111 :
3112 : ! Set up the flags
3113 42184 : ABI_CALLOC(flg,(3,mpert,3,mpert))
3114 42096 : ABI_CALLOC(flg_gamma,(3,mpert,3,mpert))
3115 150 : do ipert1=1,ddb%natom
3116 664 : do ipert2=1,ddb%natom
3117 2162 : do idir1=1,3
3118 6682 : do idir2=1,3
3119 4626 : flg(idir1,ipert1,idir2,ipert2) = one
3120 6168 : flg_gamma(idir1,ipert1,idir2,ipert2) = one
3121 : end do
3122 : end do
3123 : end do
3124 : end do
3125 :
3126 : ! Activate dielt and zeff flag if we have them
3127 44 : if (ifc%dipdip > 0) then
3128 :
3129 : ! Dielectric tensor
3130 5 : ipert1 = ddb%natom + 2; ipert2 = ddb%natom + 2;
3131 20 : do idir1=1,3
3132 65 : do idir2=1,3
3133 60 : flg_gamma(idir1,ipert1,idir2,ipert2) = one
3134 : end do
3135 : end do
3136 :
3137 : ! Born effective charges
3138 16 : ipert1 = ddb%natom + 2
3139 16 : do ipert2=1,ddb%natom
3140 49 : do idir1=1,3
3141 143 : do idir2=1,3
3142 99 : flg_gamma(idir1,ipert1,idir2,ipert2) = one
3143 132 : flg_gamma(idir1,ipert2,idir2,ipert1) = one
3144 : end do
3145 : end do
3146 : end do
3147 : end if
3148 :
3149 2391 : do iqpt=1,DDB%nblok
3150 :
3151 9388 : qpt(:) = DDB%qpt(1:3,iqpt)
3152 :
3153 : ! Get d2cart using the interatomic forces and the
3154 : ! long-range coulomb interaction through Ewald summation
3155 : call gtdyn9(ddb%acell,ifc%atmfrc,ifc%dielt,ifc%dipdip,ifc%dyewq0,d2cart, &
3156 : crystal%gmet,ddb%gprim,ddb%mpert,crystal%natom,ifc%nrpt,qptnrm,qpt,&
3157 : crystal%rmet,ddb%rprim,ifc%rpt,ifc%trans,crystal%ucvol, &
3158 : ifc%wghatm,crystal%xred,ifc%zeff,ifc%qdrp_cart,ifc%ewald_option, ifc%eta,&
3159 2347 : xmpi_comm_self,ifc%sys_dim)
3160 :
3161 : ! Impose the acoustic sum rule
3162 : !asrq0 = ddb%get_asrq0(1,1,crystal%xcart)
3163 : !call asrq0%apply(ddb%natom, ddb%mpert, ddb%msize, crystal%xcart, d2cart)
3164 :
3165 : ! Transform d2cart into reduced coordinates.
3166 : call d2cart_to_red(d2cart,d2red,crystal%gprimd,crystal%rprimd,ddb%mpert, &
3167 2347 : crystal%natom,crystal%ntypat,crystal%typat,crystal%ucvol,crystal%zion)
3168 :
3169 : ! Check if this q-point is Gamma
3170 2347 : call gamma9(jj, qpt, qptnrm, DDB_QTOL)
3171 :
3172 2391 : if (jj == 1) then
3173 44 : call ddb%set_d2matr(iqpt, d2red, flg_gamma)
3174 : else
3175 2303 : call ddb%set_d2matr(iqpt, d2red, flg)
3176 : end if
3177 :
3178 : end do
3179 :
3180 44 : ABI_FREE(d2cart)
3181 44 : ABI_FREE(d2red)
3182 44 : ABI_FREE(flg)
3183 44 : ABI_FREE(flg_gamma)
3184 :
3185 44 : end subroutine ifc_to_ddb
3186 : !!***
3187 :
3188 : !!****f* m_ifc/defwrite_nonana_terms
3189 : !! NAME
3190 : !! defwrite_nonana_terms
3191 : !!
3192 : !! FUNCTION
3193 : !! Write to ncfile the phonon frequencies and displacements for q --> 0 in the presence of non-analytical behaviour.
3194 : !!
3195 : !! INPUTS
3196 : !! ncid=netcdf file id.
3197 : !! iq_dir=Index of the q-point to be written to file
3198 : !! ndirs=Number of qpoints.
3199 : !! qdirs_cart(3,ndirs)=List of phonon wavevector directions along which the non-analytical correction
3200 : !! to the Gamma-point phonon frequencies will be calculated. The direction is in CARTESIAN COORDINATES
3201 : !! natom=Number of atoms
3202 : !! phfrq(3*natom)=Phonon frequencies in Ha
3203 : !! cart_displ(2,3*natom,3*natom)=displacements in CARTESIAN coordinates.
3204 : !!
3205 : !! OUTPUT
3206 : !! Only writing.
3207 : !!
3208 : !! SOURCE
3209 :
3210 130 : subroutine defwrite_nonana_terms(ncid, iq_dir, ndirs, qdirs_cart, natom, phfrq, cart_displ, mode)
3211 :
3212 : !Arguments ------------------------------------
3213 : !scalars
3214 : integer,intent(in) :: ncid,iq_dir,ndirs,natom
3215 : character(len=*),intent(in) :: mode
3216 : !arrays
3217 : real(dp),intent(in) :: qdirs_cart(3, ndirs), phfrq(3*natom), cart_displ(2,3*natom,3*natom)
3218 :
3219 : !Local variables-------------------------------
3220 : integer :: ncerr, na_phmodes_varid, na_phdispl_varid
3221 : ! *************************************************************************
3222 :
3223 54 : select case (mode)
3224 : case ("define")
3225 : !NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
3226 108 : ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_non_analytical_directions", ndirs)], defmode=.True.)
3227 54 : NCF_CHECK(ncerr)
3228 :
3229 : ncerr = nctk_def_arrays(ncid, [&
3230 : nctkarr_t('non_analytical_directions', "dp", "number_of_cartesian_directions, number_of_non_analytical_directions"),&
3231 : nctkarr_t('non_analytical_phonon_modes', "dp", "number_of_phonon_modes, number_of_non_analytical_directions"),&
3232 : nctkarr_t('non_analytical_phdispl_cart', "dp", &
3233 216 : "two, number_of_phonon_modes, number_of_phonon_modes, number_of_non_analytical_directions")])
3234 54 : NCF_CHECK(ncerr)
3235 :
3236 54 : NCF_CHECK(nctk_set_datamode(ncid))
3237 54 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "non_analytical_directions"), qdirs_cart))
3238 :
3239 : case ("write")
3240 76 : NCF_CHECK(nf90_inq_varid(ncid, "non_analytical_phonon_modes", na_phmodes_varid))
3241 1154 : NCF_CHECK(nf90_put_var(ncid,na_phmodes_varid,phfrq*Ha_eV,start=[1, iq_dir], count=[3*natom, 1]))
3242 76 : NCF_CHECK(nf90_inq_varid(ncid, "non_analytical_phdispl_cart", na_phdispl_varid))
3243 : ncerr = nf90_put_var(ncid,na_phdispl_varid,cart_displ*Bohr_Ang,&
3244 33426 : start=[1,1,1,iq_dir], count=[2,3*natom,3*natom, 1])
3245 76 : NCF_CHECK(ncerr)
3246 :
3247 : case default
3248 130 : ABI_ERROR(sjoin("Wrong value for mode", mode))
3249 : end select
3250 :
3251 130 : end subroutine defwrite_nonana_terms
3252 : !!***
3253 :
3254 : !----------------------------------------------------------------------
3255 :
3256 0 : end module m_ifc
3257 : !!***
|