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