Branch data Line data Source code
1 : : !!****m* ABINIT/m_dynmat
2 : : !! NAME
3 : : !! m_dynmat
4 : : !!
5 : : !! FUNCTION
6 : : !! This module provides low-level tools to operate on the dynamical matrix
7 : : !!
8 : : !! COPYRIGHT
9 : : !! Copyright (C) 2014-2026 ABINIT group (XG, JCC, MJV, NH, RC, MVeithen, MM, MG, MT, DCA)
10 : : !! This file is distributed under the terms of the
11 : : !! GNU General Public License, see ~abinit/COPYING
12 : : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : : !!
14 : : !! TODO
15 : : !! Use more explicative names for the procedures!
16 : : !!
17 : : !! SOURCE
18 : :
19 : : #if defined HAVE_CONFIG_H
20 : : #include "config.h"
21 : : #endif
22 : :
23 : : #include "abi_common.h"
24 : :
25 : : module m_dynmat
26 : :
27 : : use, intrinsic :: iso_c_binding
28 : : use defs_basis
29 : : use m_abicore
30 : : use m_errors
31 : : use m_linalg_interfaces
32 : : use m_xmpi
33 : :
34 : : use m_fstrings, only : itoa, sjoin
35 : : use m_numeric_tools, only : wrap2_pmhalf, mkherm
36 : : use m_matrix, only : mati3inv, matr3inv
37 : : use m_symtk, only : littlegroup_q
38 : : use m_cgtools, only : fxphas_seq
39 : : use m_crystal, only : crystal_t
40 : : use m_ewald, only : ewald9, ewald9_2D
41 : : use m_time, only : timab
42 : : use m_ifc_supercell, only : ifc_supercell_type
43 : :
44 : : implicit none
45 : :
46 : : private
47 : :
48 : : public :: asria_calc ! Calculate the correction for the Acoustic sum rule on
49 : : ! the InterAtomic Forces or on the dynamical matrix directly
50 : : public :: asria_corr ! Imposition of the Acoustic sum rule on the InterAtomic Forces
51 : : ! or on the dynamical matrix directly from the previously calculated d2asr
52 : : public :: asrprs ! Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry
53 : : public :: cart29 ! Transform a second-derivative matrix from reduced coordinates to cartesian coordinates, and also
54 : : ! 1) add the ionic part of the effective charges,
55 : : ! 2) normalize the electronic dielectric tensor, and add the vacuum polarisation
56 : : public :: cart39 ! Transform a vector from reduced coordinates to cartesian coordinates,
57 : : ! taking into account the perturbation from which it was derived,
58 : : ! and also check the existence of the new values.
59 : : public :: d2cart_to_red ! Transform a second-derivative matrix
60 : : ! from cartesian to reduced coordinate.
61 : : public :: chkph3 ! Check the completeness of the dynamical matrix
62 : : public :: chneu9 ! Imposition of the charge neutrality sum rule on the Effective charges
63 : : public :: d2sym3 ! Build (nearly) all the other matrix elements that can be build using symmetries.
64 : : public :: q0dy3_apply ! Takes care of the inclusion of the ewald q=0 term in the dynamical matrix
65 : : public :: q0dy3_calc ! Calculate the q=0 correction term to the dynamical matrix
66 : : ! TODO: 3 routines to symmetrize. Clarify different use cases
67 : : public :: symdyma ! Symmetrize the dynamical matrices
68 : : public :: dfpt_sygra ! Symmetrize derivatives of energy with respect to coordinates,
69 : : public :: dfpt_sydy ! Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
70 : : public :: wings3 ! Suppress the wings of the cartesian 2DTE for which the diagonal element is not known
71 : : public :: asrif9 ! Imposes the Acoustic Sum Rule to Interatomic Forces
72 : : public :: get_bigbox_and_weights ! Compute
73 : : public :: bigbx9 ! Generates a Big Box of R points for the Fourier Transforms the dynamical matrix
74 : : public :: make_bigbox ! Helper functions that faciliates the generation of a Big Box containing
75 : : public :: canat9 ! From reduced to canonical coordinates
76 : : public :: canct9 ! Convert from canonical coordinates to cartesian coordinates
77 : : public :: chkrp9 ! Check if the rprim used for the definition of the unit cell (in the
78 : : ! inputs) are consistent with the rprim used in the routine generating the Big Box
79 : : public :: dist9 ! Compute the distance between atoms in the big box
80 : : public :: ftifc_q2r ! Fourier transform of the dynamical matrices to obtain interatomic forces (real space).
81 : : public :: ftifc_r2q ! Fourier transform of the interatomic forces to obtain dynamical matrices (reciprocal space).
82 : : public :: dynmat_dq ! Compute the derivative D(q)/dq via Fourier transform of the interatomic forces
83 : : public :: ifclo9 ! Convert from cartesian coordinates to local coordinates
84 : : public :: wght9 ! Generates a weight to each R points of the Big Box and for each pair of atoms
85 : : public :: d3sym ! Given a set of calculated elements of the 3DTE matrix,
86 : : ! build (nearly) all the other matrix elements that can be build using symmetries.
87 : : public :: sytens ! Determines the set of irreductible elements of the nonlinear optical susceptibility
88 : : ! and Raman tensors
89 : : public :: axial9 ! Generates the local coordinates system from the knowledge of the first vector (longitudinal) and
90 : : ! the ifc matrix in cartesian coordinates
91 : : public :: dymfz9 ! Multiply the dynamical matrix by a phase shift to account for normalized canonical coordinates.
92 : : public :: ifc_atom_phase ! Phase factor e^{i 2pi k.dtau} associated with an atom-position difference dtau (dymfz9's building block).
93 : : public :: nanal9 ! Subtract/Add the non-analytical part from one dynamical matrix with number iqpt.
94 : : public :: gtdyn9 ! Generates a dynamical matrix from interatomic force constants and
95 : : ! long-range electrostatic interactions.
96 : : public :: dfpt_phfrq ! Diagonalize IFC(q), return phonon frequencies and eigenvectors.
97 : : ! If q is Gamma, the non-analytical behaviour can be included.
98 : : public :: pheigvec_normalize ! Normalize input eigenvectors in cartesian coordinates.
99 : : public :: phdispl_from_eigvec ! Phonon displacements from eigenvectors
100 : : public :: phangmom_from_eigvec ! compute phonon angular momentum for one q-point from eigenvectors
101 : : public :: dfpt_prtph ! Print phonon frequencies
102 : : public :: massmult_and_breaksym ! Multiply IFC(q) by atomic masses.
103 : : public :: massmult_and_breaksym_cplx ! Version for complex array
104 : :
105 : : ! TODO: Change name,
106 : : public :: ftgam
107 : : public :: ftgam_init
108 : :
109 : : public :: msria_calc ! Calculate the correction for the Acoustic sum rule
110 : : ! + rotational invariance on the IFCs in reciprocal space
111 : : public :: msria_apply ! Apply the correction for the Acoustic sum rule + rotational invariance
112 : : ! If IFCs derivatives calculated both from LW driver and Fourier, correct the interpolation
113 : :
114 : : ! *************************************************************************
115 : :
116 : : contains
117 : : !!***
118 : :
119 : : !!****f* m_dynmat/asria_calc
120 : : !! NAME
121 : : !! asria_calc
122 : : !!
123 : : !! FUNCTION
124 : : !! Calculate the correction for the Acoustic sum rule on the InterAtomic Forces
125 : : !! or on the dynamical matrix directly
126 : : !!
127 : : !! INPUTS
128 : : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
129 : : !! 5 => impose hermitian solution using lapack call)
130 : : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
131 : : !! mpert =maximum number of ipert
132 : : !! natom=number of atom
133 : : !!
134 : : !! OUTPUT
135 : : !! d2asr=matrix used to store the correction needed to fulfill
136 : : !! the acoustic sum rule.
137 : : !!
138 : : !! SOURCE
139 : :
140 : 286 : subroutine asria_calc(asr,d2asr,d2cart,mpert,natom)
141 : :
142 : : !Arguments -------------------------------
143 : : !scalars
144 : : integer,intent(in) :: asr,mpert,natom
145 : : !arrays
146 : : real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
147 : : real(dp),intent(out) :: d2asr(2,3,natom,3,natom)
148 : :
149 : : !Local variables-------------------------------
150 : : !scalars
151 : : integer :: idir1,idir2,ii,ipert1,ipert2
152 : : integer :: constrank, imatelem, iconst, nconst, nd2_packed, info
153 : : !character(len=500) :: msg
154 : : !arrays
155 : 286 : integer, allocatable :: packingindex(:,:,:,:)
156 : 286 : real(dp), allocatable :: constraints(:,:,:)
157 : 286 : real(dp), allocatable :: d2cart_packed(:,:)
158 : 286 : real(dp), allocatable :: singvals(:)
159 : 286 : real(dp), allocatable :: constr_rhs(:,:)
160 : 286 : real(dp), allocatable :: work(:,:),rwork(:)
161 : : ! *********************************************************************
162 : :
163 [ + + + + : 127546 : d2asr = zero
+ + + + +
+ ]
164 : :
165 [ + - ]: 286 : if (asr==0) return
166 : :
167 : : !call wrtout(std_out,' asria_calc: calculation of the correction to the ASR for the interatomic forces.')
168 [ + + ]: 1156 : do ipert1=1,natom
169 [ + + ]: 3766 : do idir1=1,3
170 [ + + ]: 11310 : do idir2=1,3
171 : :
172 : : ! Compute d2asr
173 [ + + ]: 47574 : do ipert2=1,natom
174 : : d2asr(:,idir1,ipert1,idir2,ipert1)=&
175 : : & d2asr(:,idir1,ipert1,idir2,ipert1)+&
176 [ + + ]: 119232 : & d2cart(:,idir1,ipert1,idir2,ipert2)
177 : : end do
178 : : end do
179 : : end do
180 : : end do
181 : :
182 : : !holistic method: overwrite d2asr with hermitian solution
183 [ - + ]: 286 : if (asr == 5) then
184 : 0 : nconst = 9*natom
185 : 0 : nd2_packed = 3*natom*(3*natom+1)/2
186 [ # # # # : 0 : ABI_MALLOC(constraints,(2,nconst, nd2_packed))
# # # # #
# # # # #
# # ]
187 [ # # # # : 0 : ABI_MALLOC(d2cart_packed,(2,nd2_packed))
# # # # #
# # # ]
188 [ # # # # : 0 : ABI_MALLOC(constr_rhs,(2,nd2_packed))
# # # # ]
189 [ # # # # : 0 : ABI_MALLOC(singvals,(nconst))
# # # # #
# # # ]
190 [ # # # # : 0 : ABI_MALLOC(work,(2,3*nd2_packed))
# # # # #
# # # #
# ]
191 [ # # # # : 0 : ABI_MALLOC(rwork,(5*nd2_packed))
# # # # #
# # # #
# ]
192 [ # # # # : 0 : ABI_MALLOC(packingindex,(3,natom,3,natom))
# # # # #
# # # # #
# # # # ]
193 : 0 : ii=1
194 [ # # # # : 0 : packingindex=-1
# # # # ]
195 [ # # ]: 0 : do ipert2=1,natom
196 [ # # ]: 0 : do idir2=1,3
197 [ # # ]: 0 : do ipert1=1,ipert2-1
198 [ # # ]: 0 : do idir1=1,3
199 : 0 : packingindex(idir1,ipert1,idir2,ipert2) = ii
200 : 0 : ii = ii+1
201 : : end do
202 : : end do
203 [ # # ]: 0 : do idir1=1,idir2
204 : 0 : packingindex(idir1,ipert2,idir2,ipert2) = ii
205 : 0 : ii = ii+1
206 : : end do
207 : : end do
208 : : end do
209 : : ! setup constraint matrix
210 [ # # # # : 0 : constraints = zero
# # ]
211 [ # # ]: 0 : do ipert1=1,natom
212 [ # # ]: 0 : do idir1=1,3
213 [ # # ]: 0 : do idir2=1,3
214 : 0 : iconst = idir2+3*(idir1-1 + 3*(ipert1-1))
215 : : ! set all atom forces, this component
216 [ # # ]: 0 : do ipert2=1,natom
217 : 0 : imatelem = packingindex(idir1,ipert1,idir2,ipert2)
218 [ # # ]: 0 : if (imatelem == -1) then
219 : 0 : imatelem = packingindex(idir2,ipert2,idir1,ipert1)
220 : : end if
221 : 0 : constraints(1,iconst,imatelem) = one
222 : : end do
223 : : end do
224 : : end do
225 : : end do
226 : :
227 [ # # # # ]: 0 : d2cart_packed = -999.0d0
228 [ # # ]: 0 : do ipert2=1,natom
229 [ # # ]: 0 : do idir2=1,3
230 [ # # ]: 0 : do ipert1=1,natom
231 [ # # ]: 0 : do idir1=1,3
232 : 0 : imatelem = packingindex(idir1,ipert1,idir2,ipert2)
233 [ # # ]: 0 : if (imatelem == -1) cycle
234 [ # # ]: 0 : d2cart_packed(:,imatelem) = d2cart(:,idir1,ipert1,idir2,ipert2)
235 : : end do
236 : : end do
237 : : end do
238 : : end do
239 [ # # # # ]: 0 : constr_rhs = zero
240 [ # # # # : 0 : constr_rhs(1,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(1,:))
# # ]
241 [ # # # # : 0 : constr_rhs(2,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(2,:))
# # ]
242 : :
243 : : ! lwork = 3*nd2_packed
244 : : call zgelss (nconst,nd2_packed,1,constraints,nconst,constr_rhs,nd2_packed,&
245 : 0 : & singvals,-one,constrank,work,3*nd2_packed,rwork,info)
246 [ # # ]: 0 : ABI_CHECK(info == 0, sjoin('zgelss returned:', itoa(info)))
247 : :
248 : : ! unpack
249 [ # # ]: 0 : do ipert2=1,natom
250 [ # # ]: 0 : do idir2=1,3
251 [ # # ]: 0 : do ipert1=1,natom
252 [ # # ]: 0 : do idir1=1,3
253 : 0 : imatelem = packingindex(idir1,ipert1,idir2,ipert2)
254 [ # # ]: 0 : if (imatelem == -1) then
255 : 0 : imatelem = packingindex(idir2,ipert2,idir1,ipert1)
256 : : ! NOTE: should complex conjugate the correction below.
257 : : end if
258 [ # # ]: 0 : d2asr(:,idir1,ipert1,idir2,ipert2) = constr_rhs(:,imatelem)
259 : : end do
260 : : end do
261 : : end do
262 : : end do
263 : :
264 [ # # ]: 0 : ABI_FREE(constraints)
265 [ # # ]: 0 : ABI_FREE(d2cart_packed)
266 [ # # ]: 0 : ABI_FREE(singvals)
267 [ # # ]: 0 : ABI_FREE(constr_rhs)
268 [ # # ]: 0 : ABI_FREE(work)
269 [ # # ]: 0 : ABI_FREE(rwork)
270 [ # # ]: 0 : ABI_FREE(packingindex)
271 : : end if
272 : :
273 : : end subroutine asria_calc
274 : : !!***
275 : :
276 : : !----------------------------------------------------------------------
277 : :
278 : : !!****f* m_dynmat/asria_corr
279 : : !! NAME
280 : : !! asria_corr
281 : : !!
282 : : !! FUNCTION
283 : : !! Imposition of the Acoustic sum rule on the InterAtomic Forces
284 : : !! or on the dynamical matrix directly from the previously calculated d2asr
285 : : !!
286 : : !! INPUTS
287 : : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
288 : : !! 5 => impose hermitian solution using lapack call)
289 : : !! d2asr=matrix used to store the correction needed to fulfill
290 : : !! the acoustic sum rule.
291 : : !! mpert =maximum number of ipert
292 : : !! natom=number of atom
293 : : !!
294 : : !! OUTPUT
295 : : !! Input/Output:
296 : : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
297 : : !!
298 : : !! SOURCE
299 : :
300 : 255 : subroutine asria_corr(asr,d2asr,d2cart,mpert,natom)
301 : :
302 : : !Arguments -------------------------------
303 : : !scalars
304 : : integer,intent(in) :: asr,mpert,natom
305 : : !arrays
306 : : real(dp),intent(in) :: d2asr(2,3,natom,3,natom)
307 : : real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
308 : :
309 : : !Local variables-------------------------------
310 : : !scalars
311 : : integer :: idir1,idir2,ipert1,ipert2
312 : : ! *********************************************************************
313 : :
314 [ + - ]: 255 : if (asr==0) return
315 : : !call wrtout(std_out,' asria_corr: imposition of the ASR for the interatomic forces.')
316 : :
317 : : ! Remove d2asr
318 [ + + ]: 961 : do ipert2=1,natom
319 [ + + ]: 3079 : do idir2=1,3
320 [ + + ]: 11518 : do ipert1=1,natom
321 [ + + ]: 36894 : do idir1=1,3
322 [ + + ]: 86940 : d2cart(:,idir1,ipert1,idir2,ipert2)= d2cart(:,idir1,ipert1,idir2,ipert2) - d2asr(:,idir1,ipert1,idir2,ipert2)
323 : : end do
324 : : end do
325 : : end do
326 : : end do
327 : :
328 : : end subroutine asria_corr
329 : : !!***
330 : :
331 : : !----------------------------------------------------------------------
332 : :
333 : : !!****f* m_dynmat/asrprs
334 : : !! NAME
335 : : !! asrprs
336 : : !!
337 : : !! FUNCTION
338 : : !! Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry
339 : : !!
340 : : !! INPUTS
341 : : !! asr=(3 => 1D systems, all elements are modified to give ASR and
342 : : !! rotational symmetry)
343 : : !! (4 => 0D systems, all elements are modified to give ASR and
344 : : !! rotational symmetry)
345 : : !! asrflg=(1 => the correction to enforce asr is computed from
346 : : !! d2cart, but NOT applied;
347 : : !! 2 => one uses the previously determined correction)
348 : : !! minvers=previously calculated inverted coefficient matrix
349 : : !! mpert =maximum number of ipert
350 : : !! natom=number of atom
351 : : !! rotinv=(1,2,3 => for linear systems along x,y,z
352 : : !! 4 => non-linear molecule
353 : : !! xcart=cartesian coordinates of the ions
354 : : !!
355 : : !! OUTPUT
356 : : !! (see side effects)
357 : : !!
358 : : !! SIDE EFFECTS
359 : : !! Input/Output:
360 : : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
361 : : !! minvers=inverse of the supermatrix for future application of the corrections
362 : : !!
363 : : !! SOURCE
364 : :
365 : 24 : subroutine asrprs(asr,asrflag,rotinv,uinvers,vtinvers,singular,d2cart,mpert,natom,xcart)
366 : :
367 : : !Arguments ------------------------------------
368 : : !scalars
369 : : integer,intent(in) :: asr,asrflag,mpert,natom,rotinv
370 : : !arrays
371 : : real(dp),intent(in) :: xcart(3,natom)
372 : : real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
373 : : real(dp),intent(inout) :: singular(1:3*natom*(3*natom-1)/2)
374 : : real(dp),intent(inout) :: uinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
375 : : real(dp),intent(inout) :: vtinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
376 : :
377 : : !Local variables-------------------------------
378 : : !scalars
379 : : integer :: column,idir1,idir2,ii,info,ipert1,ipert2,jj,n3,row,superdim
380 : : real(dp) :: rcond,test
381 : : ! real(dp) :: tau ! tau is present but commented out in this routine
382 : : character(len=500) :: msg
383 : : !arrays
384 : 48 : integer :: check(3,natom,3)
385 : 48 : real(dp) :: tmp(natom,3,3),weightf(1:natom,1:natom)
386 : 24 : real(dp),allocatable :: d2cartold(:,:,:,:,:),d2vecc(:),d2veccnew(:),d2vecr(:)
387 : 24 : real(dp),allocatable :: d2vecrnew(:),superm(:,:),umatrix(:,:),vtmatrix(:)
388 : 24 : real(dp),allocatable :: work(:)
389 : : ! *********************************************************************
390 : :
391 [ - + ]: 24 : if(asr/=3 .and. asr/=4)then
392 : : write(msg,'(3a,i0)')&
393 : 0 : 'The argument asr should be 3 or 4,',ch10, 'however, asr = ',asr
394 : 0 : ABI_BUG(msg)
395 : : end if
396 : :
397 [ + - ]: 24 : if (asr==3.or.asr==4)then
398 : 24 : write(msg, '(a,a)' ) ch10, &
399 : 48 : 'asrprs: imposition of the ASR for the interatomic forces and rotational invariance'
400 : 24 : call wrtout(std_out,msg)
401 : : end if
402 : :
403 : 24 : write(msg,'(a,i0)')' asrflag is ', asrflag
404 [ + + ]: 72 : call wrtout([std_out, ab_out], msg)
405 : :
406 : : !variables for the dimensions of the matrices
407 : :
408 : : !n1=3*natom*(3*natom-1)/2
409 : : !n2=9*natom
410 : 24 : n3=3*natom
411 : :
412 : 24 : superdim=9*natom*(natom-1)/2+n3
413 : :
414 [ - + + - : 72 : ABI_MALLOC(d2vecr,(1:superdim))
+ - + - -
+ - + ]
415 [ - + + - : 48 : ABI_MALLOC(d2vecc,(1:superdim))
- + - + ]
416 [ + + ]: 384 : d2vecr=0d0
417 [ + + ]: 384 : d2vecc=0d0
418 : :
419 : : !should be changed set to delta function for debugging
420 [ + + + + ]: 168 : weightf=1d0
421 : : !tau=1d-10
422 [ + + ]: 72 : do ii=1, natom
423 : : ! do jj=1, ii-1
424 : : ! weightf(ii,jj)= &
425 : : ! & ((xcart(1,ii)-xcart(1,jj))**2+(xcart(2,ii)-xcart(2,jj))**2+(xcart(3,ii)-xcart(3,jj))**2)**tau
426 : : ! enddo
427 : 72 : weightf(ii,ii)=0d0
428 : : end do
429 : :
430 [ - + + - : 120 : ABI_MALLOC(d2cartold,(2,3,mpert,3,mpert))
+ - - + +
- + - + -
- + - + ]
431 : :
432 [ - + + + : 163488 : d2cartold=d2cart
+ + + + +
+ + + ]
433 : :
434 : : !setup vector with uncorrected derivatives
435 : :
436 [ + + ]: 72 : do ipert1=1, natom
437 [ + + ]: 96 : do ipert2=1, ipert1-1
438 [ + + ]: 144 : do idir1=1,3
439 [ + + ]: 312 : do idir2=1,3
440 : 216 : row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
441 [ + + ]: 216 : if(abs(d2cart(1,idir1,ipert1,idir2,ipert2))<1d-6)then
442 : 110 : d2cart(1,idir1,ipert1,idir2,ipert2)=0d0
443 : : else
444 : 106 : d2vecr(row)=4*weightf(ipert1,ipert2)*d2cart(1,idir1,ipert1,idir2,ipert2)
445 : : end if
446 [ + + ]: 288 : if(abs(d2cart(2,idir1,ipert1,idir2,ipert2))<1d-6) then
447 : 126 : d2cart(2,idir1,ipert1,idir2,ipert2)=0d0
448 : : else
449 : 90 : d2vecc(row)=4*weightf(ipert1,ipert2)*d2cart(2,idir1,ipert1,idir2,ipert2)
450 : : end if
451 : : end do
452 : : end do
453 : : end do
454 : : end do
455 : :
456 [ + + ]: 24 : if(asrflag==1) then !calculate the pseudo-inverse of the supermatrix
457 [ - + + - : 8 : ABI_MALLOC(superm,(1:superdim,1:superdim))
- + + - +
- + - - +
- + ]
458 : :
459 [ + + + + ]: 482 : superm=0d0
460 : :
461 : : ! Setting up the supermatrix containing G, A, D
462 : :
463 [ + + ]: 6 : do ipert1=1, natom
464 [ + + ]: 16 : do idir1=1, 3
465 : : ! Setting up G
466 : 12 : idir2=mod(idir1,3)+1
467 : 12 : row=3*(ipert1-1)+idir1
468 [ + + ]: 18 : do ipert2=1, ipert1-1
469 : 6 : column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
470 : 6 : superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
471 : 6 : column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir2
472 : 18 : superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
473 : : end do
474 [ + + ]: 22 : do ipert2=ipert1+1, natom
475 : 6 : column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir1-1)+rotinv
476 : 6 : superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
477 : 6 : column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir2-1)+rotinv
478 : 18 : superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
479 : : end do
480 : : end do
481 [ + + ]: 18 : do idir1=1, 3
482 : : ! Setting up D
483 : 12 : idir2=mod(idir1,3)+1
484 : 12 : ii=mod(idir1+1,3)+1
485 [ + + ]: 18 : do ipert2=1, ipert1-1
486 : 6 : row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
487 : 6 : column=9*natom*(natom-1)/2+3*(ipert1-1)+idir1
488 : 6 : superm(column,row)=superm(column,row)+xcart(idir2,ipert2)-xcart(idir2,ipert1)
489 : 6 : column=9*natom*(natom-1)/2+3*(ipert1-1)+ii
490 : 6 : superm(column,row)=superm(column,row)+xcart(ii,ipert1)-xcart(ii,ipert2)
491 : 6 : row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+rotinv
492 : 6 : column=9*natom*(natom-1)/2+3*(ipert2-1)+idir1
493 : 6 : superm(column,row)=superm(column,row)+xcart(idir2,ipert1)-xcart(idir2,ipert2)
494 : 6 : column=9*natom*(natom-1)/2+3*(ipert2-1)+ii
495 : 18 : superm(column,row)=superm(column,row)+xcart(ii,ipert2)-xcart(ii,ipert1)
496 : : end do
497 : : ! Setting up A
498 [ + + ]: 52 : do idir2=1, 3
499 [ + + ]: 66 : do ipert2=1, ipert1-1
500 : 18 : column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
501 : 18 : row=n3+column
502 : 54 : superm(column,row)=4*weightf(ipert1,ipert2)
503 : : end do
504 : : end do
505 : : end do
506 : : end do
507 : :
508 : : ! calculate the pseudo-inverse of the supermatrix
509 : :
510 [ - + + - : 6 : ABI_MALLOC(work,(1:6*superdim))
+ - + - -
+ - + ]
511 [ - + + - : 4 : ABI_MALLOC(vtmatrix,(1:superdim))
- + - + ]
512 [ - + + - : 6 : ABI_MALLOC(umatrix,(1:superdim,1:superdim))
- + + - -
+ - + ]
513 : :
514 : : ! singular value decomposition of superm
515 : :
516 : : call dgesvd('A','O',superdim,superdim,superm,superdim,singular,umatrix,superdim, &
517 : 2 : vtmatrix, 1, work,6*superdim,info)
518 [ - + ]: 2 : ABI_CHECK(info == 0, sjoin('dgesvd returned:', itoa(info)))
519 : :
520 [ - + ]: 2 : ABI_FREE(vtmatrix)
521 [ - + ]: 2 : ABI_FREE(work)
522 : :
523 : 2 : write(msg, '(a,es16.8,es16.8)' )' Largest and smallest values from svd', singular(1), singular(superdim)
524 [ + + ]: 6 : call wrtout([std_out, ab_out], msg)
525 : :
526 : : ! Invert U and V**T, orthogonal matrices
527 : :
528 [ + + + + ]: 482 : uinvers = transpose(umatrix)
529 [ + + + + ]: 482 : vtinvers = transpose(superm)
530 : :
531 [ - + ]: 2 : ABI_FREE(umatrix)
532 [ - + ]: 2 : ABI_FREE(superm)
533 : :
534 : 2 : write(msg,'(a,a)')' asrprs: done with asrflag 1', ch10
535 : 2 : call wrtout(std_out,msg)
536 : :
537 : : end if !asrflag=1
538 : :
539 [ + + ]: 24 : if(asrflag==2) then
540 : :
541 [ - + + - : 66 : ABI_MALLOC(d2vecrnew,(1:superdim))
+ - + - -
+ - + ]
542 [ - + + - : 44 : ABI_MALLOC(d2veccnew,(1:superdim))
- + - + ]
543 : :
544 : : ! Calculate V**T**-1 Sigma**-1 U**-1 *rhs
545 : :
546 [ + - - + : 5632 : d2vecrnew = matmul(uinvers, d2vecr)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + + + +
+ + ]
547 [ + - - + : 5632 : d2veccnew = matmul(uinvers, d2vecc)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + + + +
+ + ]
548 : :
549 : 22 : rcond=1d-10*singular(1)
550 [ + + ]: 352 : do ii=1, superdim
551 [ + + ]: 352 : if(singular(ii)>rcond) then
552 : 286 : d2vecrnew(ii)=d2vecrnew(ii)/singular(ii)
553 : 286 : d2veccnew(ii)=d2veccnew(ii)/singular(ii)
554 : : else
555 : 44 : d2vecrnew(ii)=0d0
556 : 44 : d2veccnew(ii)=0d0
557 : : end if
558 : : end do
559 : :
560 [ + + ]: 352 : do ii=1, superdim
561 : 330 : d2vecr(ii)=0d0
562 : 330 : d2vecc(ii)=0d0
563 [ + + ]: 5302 : do jj=1, superdim
564 : 4950 : d2vecr(ii)=d2vecr(ii)+vtinvers(ii,jj)*d2vecrnew(jj)
565 : 5280 : d2vecc(ii)=d2vecc(ii)+vtinvers(ii,jj)*d2veccnew(jj)
566 : : end do
567 : : end do
568 : :
569 : : ! Store vector back into the matrix of 2nd order derivates
570 : :
571 [ + + ]: 66 : do ipert1=1, natom
572 [ + + ]: 88 : do ipert2=1, ipert1-1
573 [ + + ]: 132 : do idir1=1,3
574 [ + + ]: 286 : do idir2=1,3
575 : 198 : row=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
576 : 198 : d2cart(1,idir1,ipert1,idir2,ipert2)=d2vecr(row)
577 : 198 : d2cart(2,idir1,ipert1,idir2,ipert2)=d2vecc(row)
578 : 198 : d2cart(1,idir2,ipert2,idir1,ipert1)=d2vecr(row)
579 : 264 : d2cart(2,idir2,ipert2,idir1,ipert1)=d2vecc(row)
580 : : end do
581 : : end do
582 : : end do
583 : : end do
584 : :
585 [ - + ]: 22 : ABI_FREE(d2vecrnew)
586 [ - + ]: 22 : ABI_FREE(d2veccnew)
587 : :
588 [ + + + + : 616 : check=0
+ + ]
589 : :
590 [ + + ]: 66 : do ipert1=1, natom
591 [ + + ]: 198 : do idir1=1, 3
592 [ + + ]: 572 : do idir2=1, 3
593 : 396 : d2cart(1,idir1,ipert1,idir2,ipert1)=0d0
594 : 396 : d2cart(2,idir1,ipert1,idir2,ipert1)=0d0
595 : 396 : tmp(ipert1,idir1,idir2)=0d0
596 [ + + ]: 1320 : do ipert2=1, natom
597 [ + + ]: 1188 : if(ipert2/=ipert1) then
598 : : tmp(ipert1,idir1,idir2)=tmp(ipert1,idir1,idir2) &
599 : : & -d2cart(1,idir1,ipert1,idir2,ipert2) &
600 : 396 : & -d2cart(1,idir2,ipert2,idir1,ipert1)
601 : : end if
602 : : end do
603 : : end do
604 : : end do
605 : : end do
606 : :
607 [ + + ]: 66 : do ipert1=1, natom
608 [ + + ]: 198 : do idir1=1, 3
609 [ + + ]: 572 : do idir2=1, 3
610 : 396 : d2cart(1,idir1,ipert1,idir2,ipert1)=tmp(ipert1,idir1,idir2)/2
611 : 528 : d2cart(1,idir2,ipert1,idir1,ipert1)=d2cart(1,idir1,ipert1,idir2,ipert1)
612 : : end do
613 : : end do
614 : : end do
615 : :
616 : 22 : write(std_out,*) 'this should all be zero'
617 : :
618 [ + + ]: 66 : do ipert1=1, natom
619 [ + + ]: 198 : do idir1=1, 3
620 [ + + ]: 572 : do idir2=1, 3
621 : 396 : test=0d0
622 [ + + ]: 1188 : do ipert2=1, natom
623 : 1188 : test=test+d2cart(1,idir1,ipert1,idir2,ipert2)+d2cart(1,idir2,ipert2,idir1,ipert1)
624 : : end do
625 : 396 : write(std_out,'(i3,i3,i3,es11.3)') idir1,ipert1,idir2,test
626 : :
627 : 396 : write(msg, '(i3,i3,i3,es11.3)' ) idir1,ipert1,idir2,test
628 : 528 : call wrtout(ab_out,msg)
629 : : end do
630 : : end do
631 : : end do
632 : :
633 : 22 : write(std_out,*) 'these as well'
634 [ + + ]: 66 : do ipert2=1, natom
635 [ + + ]: 198 : do idir1=1, 3
636 [ + + ]: 572 : do idir2=1, 3
637 : 396 : test=0d0
638 [ + + ]: 1188 : do ipert1=1, natom
639 : 1188 : test=test+d2cart(1,idir1,ipert1,idir2,ipert2)
640 : : end do
641 : 528 : write(std_out,'(i3,i3,i3,i3,es11.3)') idir1,ipert1,idir2,ipert2,test
642 : : end do
643 : : end do
644 : : end do
645 : :
646 : 22 : write(msg,'(a,a)')' asrprs: done with asrflag 2', ch10
647 : 22 : call wrtout(std_out,msg)
648 : :
649 : : end if !ends asrflag=2
650 : :
651 [ - + ]: 24 : ABI_FREE(d2vecr)
652 [ - + ]: 24 : ABI_FREE(d2vecc)
653 [ - + ]: 24 : ABI_FREE(d2cartold)
654 : :
655 : 24 : end subroutine asrprs
656 : : !!***
657 : :
658 : : !----------------------------------------------------------------------
659 : :
660 : : !!****f* m_dynmat/cart29
661 : : !! NAME
662 : : !! cart29
663 : : !!
664 : : !!
665 : : !! FUNCTION
666 : : !! Transform a second-derivative matrix from reduced
667 : : !! coordinates to cartesian coordinates, and also
668 : : !! 1) add the ionic part of the effective charges,
669 : : !! 2) normalize the electronic dielectric tensor, and
670 : : !! add the vacuum polarisation
671 : : !!
672 : : !! INPUTS
673 : : !! blkflg(3,mpert,3,mpert,nblok)=
674 : : !! ( 1 if the element of the dynamical matrix has been calculated ;
675 : : !! 0 otherwise )
676 : : !! blkval(2,3,mpert,3,mpert,nblok)=DDB values
677 : : !! gprimd(3,3)=basis vector in the reciprocal space
678 : : !! iblok=number of the blok that will be transformed
679 : : !! mpert =maximum number of ipert
680 : : !! natom=number of atom
681 : : !! nblok=number of blocks (dimension of blkflg and blkval)
682 : : !! ntypat=number of atom types
683 : : !! rprimd(3,3)=basis vector in the real space
684 : : !! typat(natom)=integer label of each type of atom (1,2,...)
685 : : !! ucvol=unit cell volume
686 : : !! zion(ntypat)=charge corresponding to the atom type
687 : : !!
688 : : !! OUTPUT
689 : : !! carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
690 : : !! 2DTE matrix has been calculated correctly ; 0 otherwise )
691 : : !! d2cart(2,3,mpert,3,mpert)=
692 : : !! dynamical matrix, effective charges, dielectric tensor,....
693 : : !! all in cartesian coordinates
694 : : !!
695 : : !! SOURCE
696 : :
697 : 2315 : subroutine cart29(blkflg,blkval,carflg,d2cart,&
698 : 2315 : & gprimd,iblok,mpert,natom,nblok,ntypat,rprimd,typat,ucvol,zion)
699 : :
700 : : !Arguments -------------------------------
701 : : !scalars
702 : : integer,intent(in) :: iblok,mpert,natom,nblok,ntypat
703 : : real(dp),intent(in) :: ucvol
704 : : !arrays
705 : : integer,intent(in) :: blkflg(3,mpert,3,mpert,nblok),typat(natom)
706 : : integer,intent(out) :: carflg(3,mpert,3,mpert)
707 : : real(dp),intent(in) :: blkval(2,3,mpert,3,mpert,nblok),gprimd(3,3),rprimd(3,3)
708 : : real(dp),intent(in) :: zion(ntypat)
709 : : real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert)
710 : :
711 : : !Local variables -------------------------
712 : : !scalars
713 : : integer :: idir1,idir2,ii,ipert1,ipert2
714 : : !arrays
715 : : integer :: flg1(3),flg2(3)
716 : 4630 : integer :: mflg(3,mpert,3,mpert)
717 : : real(dp) :: vec1(3),vec2(3)
718 : : ! *********************************************************************
719 : :
720 : : !First, copy the data blok in place.
721 [ + + + + : 21429833 : d2cart(:,:,:,:,:)=blkval(:,:,:,:,:,iblok)
+ + + + +
+ ]
722 : :
723 : : !Cartesian coordinates transformation (in two steps)
724 : : !First step
725 [ + + ]: 40862 : do ipert1=1,mpert
726 [ + + ]: 749973 : do ipert2=1,mpert
727 [ + + ]: 2165880 : do ii=1,2
728 [ + + ]: 6381999 : do idir1=1,3
729 [ + + ]: 17018664 : do idir2=1,3
730 : 12763998 : vec1(idir2)=d2cart(ii,idir1,ipert1,idir2,ipert2)
731 : : ! Note here blkflg
732 : 17018664 : flg1(idir2)=blkflg(idir1,ipert1,idir2,ipert2,iblok)
733 : : end do
734 : 4254666 : call cart39(flg1,flg2,gprimd,ipert2,natom,rprimd,vec1,vec2)
735 [ + + ]: 18436886 : do idir2=1,3
736 : 12763998 : d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2)
737 : : ! And here carflg
738 : 17018664 : carflg(idir1,ipert1,idir2,ipert2)=flg2(idir2)
739 : : end do
740 : : end do
741 : : end do
742 : : end do
743 : : end do
744 : :
745 : : !Second step
746 [ + + ]: 40862 : do ipert1=1,mpert
747 [ + + ]: 749973 : do ipert2=1,mpert
748 [ + + ]: 2165880 : do ii=1,2
749 [ + + ]: 6381999 : do idir2=1,3
750 [ + + ]: 17018664 : do idir1=1,3
751 : 12763998 : vec1(idir1)=d2cart(ii,idir1,ipert1,idir2,ipert2)
752 : : ! Note here carflg
753 : 17018664 : flg1(idir1)=carflg(idir1,ipert1,idir2,ipert2)
754 : : end do
755 : 4254666 : call cart39(flg1,flg2,gprimd,ipert1,natom,rprimd,vec1,vec2)
756 [ + + ]: 18436886 : do idir1=1,3
757 : 12763998 : d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1)
758 : : ! And here carflg again
759 : 17018664 : carflg(idir1,ipert1,idir2,ipert2)=flg2(idir1)
760 : : end do
761 : : end do
762 : : end do
763 : : end do
764 : : end do
765 : :
766 : : !For the dielectric tensor, takes into account the volume
767 : : !of the unit cell, and add the unit matrix (polarization of the vacuum)
768 [ + + ]: 9260 : do idir1=1,3
769 [ + + ]: 30095 : do idir2=1,3
770 [ + + ]: 69450 : do ii=1,2
771 : : d2cart(ii,idir1,natom+2,idir2,natom+2)=&
772 : 62505 : & -four_pi/ucvol*d2cart(ii,idir1,natom+2,idir2,natom+2)
773 : : end do
774 : : end do
775 : : end do
776 : :
777 [ + + ]: 9260 : do idir1=1,3
778 : : d2cart(1,idir1,natom+2,idir1,natom+2)=&
779 : 9260 : & 1.0_dp+d2cart(1,idir1,natom+2,idir1,natom+2)
780 : : end do
781 : :
782 : : !Add the ionic charges to delta z to get the effective charges
783 [ + + ]: 10172 : do ipert1=1,natom
784 [ + + ]: 33743 : do idir1=1,3
785 : : d2cart(1,idir1,ipert1,idir1,natom+2)=&
786 : 31428 : & zion(typat(ipert1))+d2cart(1,idir1,ipert1,idir1,natom+2)
787 : : end do
788 : : end do
789 [ + + ]: 10172 : do ipert2=1,natom
790 [ + + ]: 33743 : do idir2=1,3
791 : : d2cart(1,idir2,natom+2,idir2,ipert2)=&
792 : 31428 : & zion(typat(ipert2))+d2cart(1,idir2,natom+2,idir2,ipert2)
793 : : end do
794 : : end do
795 : :
796 : : !For the piezoelectric tensor, takes into account the volume of the unit cell
797 [ + + ]: 6945 : do ipert2=natom+3,natom+4
798 [ + + ]: 20835 : do idir1=1,3
799 [ + + ]: 60190 : do idir2=1,3
800 [ + + ]: 138900 : do ii=1,2
801 : : d2cart(ii,idir1,natom+2,idir2,ipert2)=&
802 : 83340 : & (1.0_dp/ucvol)*d2cart(ii,idir1,natom+2,idir2,ipert2)
803 : : d2cart(ii,idir2,ipert2,idir1,natom+2)=&
804 : 125010 : & (1.0_dp/ucvol)*d2cart(ii,idir2,ipert2,idir1,natom+2)
805 : : end do
806 : : end do
807 : : end do
808 : : end do
809 : :
810 : : !MRoyo: For magnetic Zeeman perturbations, apply a negative sign to get induced magnetic moments.
811 : : !Macroscopic Zeeman
812 [ + + + + : 8665835 : mflg= 0
+ + + + ]
813 : 2315 : ipert1=natom+5
814 [ + + ]: 9260 : do idir1=1,3
815 [ + + ]: 74501 : do ipert2= 1, natom+6 !exclude local Zeemans, to be done below
816 [ + + ]: 267909 : do idir2=1,3
817 [ + + ]: 195723 : if (mflg(idir1,ipert1,idir2,ipert2)==0) then
818 [ + + ]: 566334 : do ii=1,2
819 : : d2cart(ii,idir1,ipert1,idir2,ipert2)=&
820 : 377556 : & -one*d2cart(ii,idir1,ipert1,idir2,ipert2)
821 : 566334 : mflg(idir1,ipert1,idir2,ipert2)=1
822 : : end do
823 : : end if
824 [ + + ]: 260964 : if (mflg(idir2,ipert2,idir1,ipert1)==0) then
825 [ + + ]: 545499 : do ii=1,2
826 : : d2cart(ii,idir2,ipert2,idir1,ipert1)=&
827 : 363666 : & -one*d2cart(ii,idir2,ipert2,idir1,ipert1)
828 : 545499 : mflg(idir2,ipert2,idir1,ipert1)=1
829 : : end do
830 : : end if
831 : : end do
832 : : end do
833 : : end do
834 : :
835 : : !Local Zeemans
836 [ + + ]: 2315 : if (mpert>natom+MPERT_MAX) then
837 [ + + ]: 8854 : do ipert1= natom+12,2*natom+11
838 [ + + ]: 29785 : do idir1=1,3
839 [ + + ]: 466319 : do ipert2= 1, mpert
840 [ + + ]: 1774575 : do idir2=1,3
841 [ + + ]: 1315233 : if (mflg(idir1,ipert1,idir2,ipert2)==0) then
842 [ + + ]: 3508713 : do ii=1,2
843 : : d2cart(ii,idir1,ipert1,idir2,ipert2)=&
844 : 2339142 : & -one*d2cart(ii,idir1,ipert1,idir2,ipert2)
845 : 3508713 : mflg(idir1,ipert1,idir2,ipert2)=1
846 : : end do
847 : : end if
848 [ + + ]: 1753644 : if (mflg(idir2,ipert2,idir1,ipert1)==0) then
849 [ + + ]: 3445920 : do ii=1,2
850 : : d2cart(ii,idir2,ipert2,idir1,ipert1)=&
851 : 2297280 : & -one*d2cart(ii,idir2,ipert2,idir1,ipert1)
852 : 3445920 : mflg(idir2,ipert2,idir1,ipert1)=1
853 : : end do
854 : : end if
855 : : end do
856 : : end do
857 : : end do
858 : : end do
859 : : end if
860 : :
861 : : !For magnetoelectric and magnetic susceptibility apply a 1/ucvol factor
862 : 2315 : ipert1= natom + 2
863 : 2315 : ipert2= natom + 5
864 [ + + ]: 9260 : do idir1= 1, 3
865 [ + + ]: 30095 : do idir2= 1, 3
866 [ + + ]: 69450 : do ii=1,2
867 : : d2cart(ii,idir1,ipert1,idir2,ipert2)=&
868 : 41670 : & d2cart(ii,idir1,ipert1,idir2,ipert2)/ucvol
869 : : d2cart(ii,idir2,ipert2,idir1,ipert1)=&
870 : 41670 : & d2cart(ii,idir2,ipert2,idir1,ipert1)/ucvol
871 : : d2cart(ii,idir1,ipert2,idir2,ipert2)=&
872 : 62505 : & d2cart(ii,idir1,ipert2,idir2,ipert2)/ucvol
873 : : end do
874 : : end do
875 : : end do
876 : :
877 : 2315 : end subroutine cart29
878 : : !!***
879 : :
880 : : !----------------------------------------------------------------------
881 : :
882 : : !!****f* m_dynmat/cart39
883 : : !! NAME
884 : : !! cart39
885 : : !!
886 : : !!
887 : : !! FUNCTION
888 : : !! Transform a vector from reduced coordinates to cartesian coordinates,
889 : : !! taking into account the perturbation from which it was derived,
890 : : !! and also check the existence of the new values.
891 : : !!
892 : : !! INPUTS
893 : : !! flg1(3)=tell if information of each component of vec1 is valid
894 : : !! gprimd(3,3)=basis vector in the reciprocal space
895 : : !! ipert=number of the perturbation
896 : : !! natom=number of atom
897 : : !! rprimd(3,3)=basis vector in the real space
898 : : !! vec1(3)=input vector, in reduced coordinates
899 : : !!
900 : : !! OUTPUT
901 : : !! flg2(3)=tell if information of each component of vec2 is valid
902 : : !! vec2(3)=output vector, in cartesian coordinates
903 : : !!
904 : : !! SOURCE
905 : :
906 : 18234876 : subroutine cart39(flg1,flg2,gprimd,ipert,natom,rprimd,vec1,vec2)
907 : :
908 : : !Arguments -------------------------------
909 : : !scalars
910 : : integer,intent(in) :: ipert,natom
911 : : !arrays
912 : : integer,intent(in) :: flg1(3)
913 : : integer,intent(out) :: flg2(3)
914 : : real(dp),intent(in) :: gprimd(3,3),rprimd(3,3),vec1(3)
915 : : real(dp),intent(out) :: vec2(3)
916 : :
917 : : !Local variables -------------------------
918 : : !scalars
919 : : integer :: idir,ii
920 : : ! *********************************************************************
921 : :
922 : : !Treat phonon-type perturbation
923 [ + - + + ]: 18234876 : if(ipert>=1.and.ipert<=natom)then
924 : :
925 [ + + ]: 17947560 : do idir=1,3
926 : 13460670 : vec2(idir)=zero
927 : 13460670 : flg2(idir)=1
928 [ + + ]: 53842680 : do ii=1,3
929 [ + + ]: 53842680 : if(abs(gprimd(idir,ii))>1.0d-10)then
930 [ + + ]: 19988040 : if(flg1(ii)==1)then
931 : 5585401 : vec2(idir)=vec2(idir)+gprimd(idir,ii)*vec1(ii)
932 : : else
933 : 14402639 : flg2(idir)=0
934 : : end if
935 : : end if
936 : : end do
937 [ + + ]: 17947560 : if(flg2(idir)==0)vec2(idir)=zero
938 : : end do
939 : :
940 : : ! Treat electric field and qvec perturbations
941 [ + + + + ]: 13747986 : else if(ipert==natom+2.or.ipert==natom+8) then
942 : : ! OCL SCALAR
943 [ + + ]: 7786224 : do idir=1,3
944 : 5839668 : vec2(idir)=zero
945 : 5839668 : flg2(idir)=1
946 : : ! OCL SCALAR
947 [ + + ]: 23358672 : do ii=1,3
948 [ + + ]: 23358672 : if(abs(rprimd(idir,ii))>1.0d-10)then
949 [ + + ]: 8569860 : if(flg1(ii)==1)then
950 : 1366773 : vec2(idir)=vec2(idir)+rprimd(idir,ii)*vec1(ii)/two_pi
951 : : else
952 : 7203087 : flg2(idir)=0
953 : : end if
954 : : end if
955 : : end do
956 [ + + ]: 7786224 : if(flg2(idir)==0)vec2(idir)=zero
957 : : end do
958 : :
959 : : ! Treat other perturbations
960 : : else
961 [ + + ]: 47205720 : do idir=1,3
962 : 35404290 : vec2(idir)=vec1(idir)
963 : 47205720 : flg2(idir)=flg1(idir)
964 : : end do
965 : : end if
966 : :
967 : 18234876 : end subroutine cart39
968 : : !!***
969 : :
970 : : !----------------------------------------------------------------------
971 : :
972 : : !!****f* m_dynmat/d2cart_to_red
973 : : !! NAME
974 : : !! d2cart_to_red
975 : : !!
976 : : !!
977 : : !! FUNCTION
978 : : !! Transform a second-derivative matrix from cartesian
979 : : !! coordinates to reduced coordinate. Also,
980 : : !! 1) remove the ionic part of the effective charges,
981 : : !! 2) remove the vacuum polarisation from the dielectric tensor
982 : : !! and scale it with the unit cell volume
983 : : !! In short, does the inverse operation of cart29.
984 : : !!
985 : : !! INPUTS
986 : : !! d2cart(2,3,mpert,3,mpert)=
987 : : !! second-derivative matrix in cartesian coordinates
988 : : !! gprimd(3,3)=basis vector in the reciprocal space
989 : : !! rprimd(3,3)=basis vector in the real space
990 : : !! mpert =maximum number of ipert
991 : : !! natom=number of atom
992 : : !!
993 : : !! OUTPUT
994 : : !! d2red(2,3,mpert,3,mpert)=
995 : : !! second-derivative matrix in reduced coordinates
996 : : !!
997 : : !! SOURCE
998 : :
999 : 2223 : subroutine d2cart_to_red(d2cart, d2red, gprimd, rprimd, mpert, natom, &
1000 : 2223 : & ntypat,typat,ucvol,zion)
1001 : :
1002 : : !Arguments -------------------------------
1003 : : !scalars
1004 : : integer,intent(in) :: mpert,natom,ntypat
1005 : : real(dp),intent(in) :: ucvol
1006 : : !arrays
1007 : : integer,intent(in) :: typat(natom)
1008 : : real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
1009 : : real(dp),intent(out) :: d2red(2,3,mpert,3,mpert)
1010 : : real(dp),intent(in) :: gprimd(3,3),rprimd(3,3)
1011 : : real(dp),intent(in) :: zion(ntypat)
1012 : :
1013 : : !Local variables -------------------------
1014 : : !scalars
1015 : : integer :: idir1,idir2,ii,ipert1,ipert2
1016 : : real(dp) :: fac
1017 : : !arrays
1018 : : integer :: flg1(3),flg2(3)
1019 : : real(dp) :: vec1(3),vec2(3)
1020 : : real(dp) :: gprimdt(3,3),rprimdt(3,3)
1021 : : ! *********************************************************************
1022 : :
1023 [ + + ]: 8892 : flg1 = one
1024 [ + + ]: 8892 : flg2 = one
1025 : :
1026 [ + + + + : 4996765 : d2red = d2cart
+ + + + +
+ ]
1027 : :
1028 : : !Remove the ionic charges to z to get the change in effective charges
1029 [ + + ]: 7322 : do ipert1=1,natom
1030 [ + + ]: 22619 : do idir1=1,3
1031 : : d2red(1,idir1,ipert1,idir1,natom+2)=&
1032 : 20396 : & d2red(1,idir1,ipert1,idir1,natom+2) - zion(typat(ipert1))
1033 : : end do
1034 : : end do
1035 [ + + ]: 7322 : do ipert2=1,natom
1036 [ + + ]: 22619 : do idir2=1,3
1037 : : d2red(1,idir2,natom+2,idir2,ipert2)=&
1038 : 20396 : & d2red(1,idir2,natom+2,idir2,ipert2) - zion(typat(ipert2))
1039 : : end do
1040 : : end do
1041 : :
1042 : : ! Remove the vacuum polarizability from the dielectric tensor
1043 [ + + ]: 8892 : do idir1=1,3
1044 : : d2red(1,idir1,natom+2,idir1,natom+2)=&
1045 : 8892 : & d2red(1,idir1,natom+2,idir1,natom+2) - 1.0_dp
1046 : : end do
1047 : :
1048 : : ! Scale the dielectric tensor with the volue of the unit cell
1049 [ + + ]: 8892 : do idir1=1,3
1050 [ + + ]: 28899 : do idir2=1,3
1051 [ + + ]: 66690 : do ii=1,2
1052 : : d2red(ii,idir1,natom+2,idir2,natom+2)=&
1053 : 60021 : & - (ucvol / four_pi) * d2red(ii,idir1,natom+2,idir2,natom+2)
1054 : : end do
1055 : : end do
1056 : : end do
1057 : :
1058 : : !For the piezoelectric tensor, takes into account the volume of the unit cell
1059 [ + + ]: 6669 : do ipert2=natom+3,natom+4
1060 [ + + ]: 20007 : do idir1=1,3
1061 [ + + ]: 57798 : do idir2=1,3
1062 [ + + ]: 133380 : do ii=1,2
1063 : : d2red(ii,idir1,natom+2,idir2,ipert2)=&
1064 : 80028 : & (ucvol)*d2red(ii,idir1,natom+2,idir2,ipert2)
1065 : : d2red(ii,idir2,ipert2,idir1,natom+2)=&
1066 : 120042 : & (ucvol)*d2red(ii,idir2,ipert2,idir1,natom+2)
1067 : : end do
1068 : : end do
1069 : : end do
1070 : : end do
1071 : :
1072 : : ! Reduced coordinates transformation (in two steps)
1073 : : ! Note that rprimd and gprimd are swapped, compared to what cart39 expects
1074 : : ! A factor of (2pi) ** 2 is added to transform the electric field perturbations
1075 : :
1076 [ + + + + ]: 28899 : rprimdt = transpose(rprimd)
1077 [ + + + + ]: 28899 : gprimdt = transpose(gprimd)
1078 : :
1079 : : !First step
1080 [ + + ]: 20716 : do ipert1=1,mpert
1081 [ + + ]: 18493 : fac = one; if (ipert1==natom+2) fac = two_pi ** 2
1082 : :
1083 [ + + ]: 184735 : do ipert2=1,mpert
1084 [ + + ]: 510550 : do ii=1,2
1085 [ + + ]: 1476171 : do idir1=1,3
1086 [ + + ]: 3936456 : do idir2=1,3
1087 : 3936456 : vec1(idir2)=d2red(ii,idir1,ipert1,idir2,ipert2)
1088 : : end do
1089 : : ! Transform vector from cartesian to reduced coordinates
1090 : 984114 : call cart39(flg1,flg2,rprimdt,ipert1,natom,gprimdt,vec1,vec2)
1091 [ + + ]: 4264494 : do idir2=1,3
1092 : 3936456 : d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2) * fac
1093 : : end do
1094 : : end do
1095 : : end do
1096 : : end do
1097 : : end do
1098 : :
1099 : : !Second step
1100 [ + + ]: 20716 : do ipert1=1,mpert
1101 [ + + ]: 184735 : do ipert2=1,mpert
1102 [ + + ]: 164019 : fac = one; if (ipert2==natom+2) fac = two_pi ** 2
1103 : :
1104 [ + + ]: 510550 : do ii=1,2
1105 [ + + ]: 1476171 : do idir2=1,3
1106 [ + + ]: 3936456 : do idir1=1,3
1107 : 3936456 : vec1(idir1)=d2red(ii,idir1,ipert1,idir2,ipert2)
1108 : : end do
1109 : : ! Transform vector from cartesian to reduced coordinates
1110 : 984114 : call cart39(flg1,flg2,rprimdt,ipert2,natom,gprimdt,vec1,vec2)
1111 [ + + ]: 4264494 : do idir1=1,3
1112 : 3936456 : d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1) * fac
1113 : : end do
1114 : : end do
1115 : : end do
1116 : : end do
1117 : : end do
1118 : :
1119 : :
1120 : 2223 : end subroutine d2cart_to_red
1121 : : !!***
1122 : :
1123 : : !----------------------------------------------------------------------
1124 : :
1125 : : !!****f* m_dynmat/chkph3
1126 : : !! NAME
1127 : : !! chkph3
1128 : : !!
1129 : : !! FUNCTION
1130 : : !! Check the completeness of the dynamical matrix and eventually send a warning
1131 : : !!
1132 : : !! INPUTS
1133 : : !! carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
1134 : : !! 2DTE matrix has been calculated correctly ; 0 otherwise )
1135 : : !! idir = direction of the eventual electric field
1136 : : !! mpert =maximum number of ipert
1137 : : !! natom=number of atoms in unit cell
1138 : : !!
1139 : : !! OUTPUT
1140 : : !! eventually send a warning message
1141 : : !!
1142 : : !! SOURCE
1143 : :
1144 : 601 : subroutine chkph3(carflg,idir,mpert,natom)
1145 : :
1146 : : !Arguments -------------------------------
1147 : : !scalars
1148 : : integer,intent(in) :: idir,mpert,natom
1149 : : !arrays
1150 : : integer,intent(in) :: carflg(3,mpert,3,mpert)
1151 : :
1152 : : !Local variables -------------------------
1153 : : !scalars
1154 : : integer :: idir1,idir2,ipert1,ipert2,send
1155 : : character(len=500) :: msg
1156 : : ! *********************************************************************
1157 : :
1158 : 601 : send=0
1159 : :
1160 : : !Check the elements of the analytical part of the dynamical matrix
1161 [ + + ]: 1852 : do ipert2=1,natom
1162 [ + + ]: 5605 : do idir2=1,3
1163 [ + + ]: 14967 : do ipert1=1,natom
1164 [ + + ]: 43605 : do idir1=1,3
1165 [ + + ]: 39852 : if(carflg(idir1,ipert1,idir2,ipert2)==0)then
1166 : 8501 : send=1
1167 : : end if
1168 : : end do
1169 : : end do
1170 : : end do
1171 : : end do
1172 : :
1173 : : !If some electric field is present
1174 [ + + ]: 601 : if(idir/=0)then
1175 : :
1176 : : ! Check the dielectric constant
1177 [ - + ]: 219 : if(carflg(idir,natom+2,idir,natom+2)==0)then
1178 : 0 : send=1
1179 : : end if
1180 : :
1181 : : ! Check the effective charges
1182 [ + + ]: 707 : do ipert1=1,natom
1183 [ + + ]: 2171 : do idir1=1,3
1184 [ + + ]: 1952 : if(carflg(idir1,ipert1,idir,natom+2)==0)then
1185 : 39 : send=1
1186 : : end if
1187 : : end do
1188 : : end do
1189 : :
1190 : : end if
1191 : :
1192 : : ! If needed, send the message
1193 [ + + ]: 601 : if(send==1)then
1194 : : write(msg, '(a,a,a,a)' )&
1195 : 75 : & ' chkph3 : WARNING -',ch10,&
1196 : 150 : & ' Dynamical matrix incomplete, phonon frequencies may be wrong, see the log file for more explanations.'
1197 : 75 : call wrtout(ab_out,msg)
1198 : : write(msg, '(11a)' )&
1199 : 75 : & ' chkph3 : WARNING -',ch10,&
1200 : 75 : & ' Dynamical matrix incomplete, phonon frequencies may be wrong.',ch10,&
1201 : 75 : & ' Likely due to a list of perturbations, as defined by rfatpol and rfdir, that does not include',ch10,&
1202 : 75 : & ' all displacements of all atoms and (if non-metallic material) electric field type perturbation.',ch10,&
1203 : 75 : & ' Then, the dynamical matrix includes zeroes when the matrix element is not computed.',ch10,&
1204 : 150 : & ' This is allowed for testing purposes. But the phonon frequencies may be wrong.'
1205 : 75 : call wrtout(std_out,msg)
1206 : : write(msg, '(9a)' )&
1207 : 75 : & ' If there are symmetries, perhaps these matrix elements are zero by symmetry anyhow, and phonon frequencies might be right.',ch10,&
1208 : 75 : & ' Please check the input variables rfatpol and rfdir, to determine whether abinit is doing what you intend it to do.',ch10,&
1209 : 75 : & ' Note that ANADDB is able to detect whether the symmetries allow one to reconstruct the full dynamical matrix from',ch10,&
1210 : 75 : & ' an incomplete one. In this case, passing to ANADDB the delivered _DDB file might confirm (or not) that',ch10,&
1211 : 150 : & ' phonon frequencies are right.'
1212 : 75 : call wrtout(std_out,msg)
1213 : : end if
1214 : :
1215 : 601 : end subroutine chkph3
1216 : : !!***
1217 : :
1218 : : !----------------------------------------------------------------------
1219 : :
1220 : : !!****f* m_dynmat/chneu9
1221 : : !! NAME
1222 : : !! chneu9
1223 : : !!
1224 : : !! FUNCTION
1225 : : !! Imposition of the charge neutrality sum rule on the Effective charges
1226 : : !! and suppress the imaginary part of the dynamical matrix
1227 : : !!
1228 : : !! INPUTS
1229 : : !! chneut=(0 => no ASR, 1 => equal repartition, 2 => weighted repartition )
1230 : : !! mpert =maximum number of ipert
1231 : : !! natom=number of atom
1232 : : !! ntypat=number of types of atoms in unit cell
1233 : : !! selectz=selection of some parts of the effective charge tensor attached to one atom.
1234 : : !! (0=> no selection, 1=> trace only, 2=> symmetric part only)
1235 : : !! typat(natom)=type of the atom
1236 : : !! zion(ntypat)=atomic charge for every type of atom
1237 : : !!
1238 : : !! SIDE EFFECTS
1239 : : !! Input/Output
1240 : : !! d2cart=matrix of second derivatives of total energy, in cartesian
1241 : : !! coordinates
1242 : : !!
1243 : : !! SOURCE
1244 : :
1245 : 194 : subroutine chneu9(chneut,d2cart,mpert,natom,ntypat,selectz,typat,zion)
1246 : :
1247 : : !Arguments -------------------------------
1248 : : !scalars
1249 : : integer,intent(in) :: chneut,mpert,natom,ntypat,selectz
1250 : : !arrays
1251 : : integer,intent(in) :: typat(natom)
1252 : : real(dp),intent(in) :: zion(ntypat)
1253 : : real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
1254 : :
1255 : : !Local variables -------------------------
1256 : : !scalars
1257 : : integer :: idir1,idir2,ii,ipert1,ipert2
1258 : : character(len=500) :: msg
1259 : : !arrays
1260 : : real(dp) :: sumwght(2)
1261 : 194 : real(dp),allocatable :: wghtat(:)
1262 : : ! *********************************************************************
1263 : :
1264 [ - + + - : 582 : ABI_MALLOC(wghtat,(natom))
+ - + - -
+ - + ]
1265 : :
1266 : : !In case of acoustic sum rule imposition, compute the weights on each atom.
1267 [ + + ]: 194 : if (chneut==1)then
1268 : :
1269 : : ! The weight is the same for all atom
1270 [ + + ]: 659 : do ipert1=1,natom
1271 : 659 : wghtat(ipert1)=1./natom
1272 : : end do
1273 : :
1274 [ + + ]: 22 : else if (chneut==2) then
1275 : :
1276 : : ! The weight is proportional to the diagonal electronic screening charge of the atom
1277 : 11 : sumwght(1)=zero
1278 [ + + ]: 66 : do ipert1=1,natom
1279 : 55 : wghtat(ipert1)=zero
1280 [ + + ]: 220 : do idir1=1,3
1281 : : wghtat(ipert1)=wghtat(ipert1)+&
1282 : : & d2cart(1,idir1,ipert1,idir1,natom+2)+&
1283 : 220 : & d2cart(1,idir1,natom+2,idir1,ipert1)-2*zion(typat(ipert1))
1284 : : end do
1285 : 66 : sumwght(1)=sumwght(1)+wghtat(ipert1)
1286 : : end do
1287 : :
1288 : : ! Normalize the weights to unity
1289 [ + + ]: 66 : wghtat(1:natom) = wghtat(1:natom) / sumwght(1)
1290 : : end if
1291 : :
1292 : : !Calculation of the violation of the charge neutrality
1293 : : !and imposition of the charge neutrality condition
1294 [ + + ]: 194 : if (chneut/=0)then
1295 : : write(msg, '(a,a,a,a,a,a,a)' )&
1296 : 183 : ' The violation of the charge neutrality conditions',ch10,&
1297 : 183 : ' by the effective charges is as follows :',ch10,&
1298 : 183 : ' atom electric field',ch10,&
1299 : 366 : ' displacement direction '
1300 : 183 : call wrtout(ab_out,msg)
1301 [ + + ]: 732 : do idir1=1,3
1302 [ + + ]: 2379 : do idir2=1,3
1303 [ + + ]: 4941 : do ii=1,2
1304 : 3294 : sumwght(ii)=zero
1305 [ + + ]: 13050 : do ipert1=1,natom
1306 : 13050 : sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir2,natom+2)
1307 : : end do
1308 [ + + ]: 14697 : do ipert1=1,natom
1309 : : d2cart(ii,idir1,ipert1,idir2,natom+2)=&
1310 : 13050 : d2cart(ii,idir1,ipert1,idir2,natom+2)-sumwght(ii)*wghtat(ipert1)
1311 : : end do
1312 : : end do
1313 : 1647 : write(msg, '(i8,i16,2f16.6)' ) idir1,idir2,sumwght(1),sumwght(2)
1314 : 2196 : call wrtout(ab_out,msg)
1315 : : end do
1316 : : end do
1317 : 183 : write(msg, '(a)' )' '
1318 : 183 : call wrtout(ab_out,msg)
1319 : :
1320 : : ! The same for the symmetrical part
1321 [ + + ]: 732 : do idir1=1,3
1322 [ + + ]: 2379 : do idir2=1,3
1323 [ + + ]: 5490 : do ii=1,2
1324 : 3294 : sumwght(ii)=zero
1325 [ + + ]: 13050 : do ipert2=1,natom
1326 : 13050 : sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir2,ipert2)
1327 : : end do
1328 [ + + ]: 14697 : do ipert2=1,natom
1329 : : d2cart(ii,idir1,natom+2,idir2,ipert2)=&
1330 : 13050 : d2cart(ii,idir1,natom+2,idir2,ipert2)-sumwght(ii)*wghtat(ipert2)
1331 : : end do
1332 : : end do
1333 : : end do
1334 : : end do
1335 : : end if
1336 : :
1337 : : !Selection of the trace of the effective charge tensor attached to each atom
1338 [ - + ]: 194 : if(selectz==1)then
1339 [ # # ]: 0 : do ipert1=1,natom
1340 [ # # ]: 0 : do ii=1,2
1341 : 0 : sumwght(ii)=zero
1342 [ # # ]: 0 : do idir1=1,3
1343 : 0 : sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir1,natom+2)
1344 : : end do
1345 [ # # ]: 0 : do idir1=1,3
1346 [ # # ]: 0 : do idir2=1,3
1347 : 0 : d2cart(ii,idir1,ipert1,idir2,natom+2)=zero
1348 : : end do
1349 : : end do
1350 [ # # ]: 0 : do idir1=1,3
1351 : 0 : d2cart(ii,idir1,ipert1,idir1,natom+2)=sumwght(ii)/3.0_dp
1352 : : end do
1353 : : end do
1354 : : end do
1355 : : ! Do the same for the symmetrical part of d2cart
1356 [ # # ]: 0 : do ipert2=1,natom
1357 [ # # ]: 0 : do ii=1,2
1358 : 0 : sumwght(ii)=zero
1359 [ # # ]: 0 : do idir1=1,3
1360 : 0 : sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir1,ipert2)
1361 : : end do
1362 [ # # ]: 0 : do idir1=1,3
1363 [ # # ]: 0 : do idir2=1,3
1364 : 0 : d2cart(ii,idir1,natom+2,idir2,ipert2)=zero
1365 : : end do
1366 : : end do
1367 [ # # ]: 0 : do idir1=1,3
1368 : 0 : d2cart(ii,idir1,natom+2,idir1,ipert2)=sumwght(ii)/3.0_dp
1369 : : end do
1370 : : end do
1371 : : end do
1372 : : end if
1373 : :
1374 : : !Selection of the symmetric part of the effective charge tensor attached to each atom
1375 [ - + ]: 194 : if(selectz==2)then
1376 [ # # ]: 0 : do ipert1=1,natom
1377 [ # # ]: 0 : do ii=1,2
1378 [ # # ]: 0 : do idir1=1,3
1379 [ # # ]: 0 : do idir2=1,3
1380 : : sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
1381 : 0 : & +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
1382 : 0 : d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
1383 : 0 : d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
1384 : : end do
1385 : : end do
1386 : : end do
1387 : : end do
1388 : : ! Do the same for the symmetrical part of d2cart
1389 [ # # ]: 0 : do ipert1=1,natom
1390 [ # # ]: 0 : do ii=1,2
1391 [ # # ]: 0 : do idir1=1,3
1392 [ # # ]: 0 : do idir2=1,3
1393 : : sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
1394 : 0 : & +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
1395 : 0 : d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
1396 : 0 : d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
1397 : : end do
1398 : : end do
1399 : : end do
1400 : : end do
1401 : : end if
1402 : :
1403 : : !Write the effective charge tensor
1404 : : write(msg, '(a,a,a,a,a,a,a)' )&
1405 : 194 : ' Effective charge tensors after ',ch10,&
1406 : 194 : ' imposition of the charge neutrality (if requested by user),',ch10,&
1407 : 194 : ' and eventual restriction to some part :',ch10,&
1408 : 388 : ' atom displacement '
1409 : 194 : call wrtout(ab_out,msg)
1410 : :
1411 [ + + ]: 770 : do ipert1=1,natom
1412 [ + + ]: 2498 : do idir1=1,3
1413 [ + - + + ]: 6912 : write(msg, '(2i10,3es16.6)' )ipert1,idir1,(d2cart(1,idir1,ipert1,idir2,natom+2),idir2=1,3)
1414 : 2304 : call wrtout(ab_out,msg)
1415 : : end do
1416 : : end do
1417 : :
1418 : : !Zero the imaginary part of the dynamical matrix
1419 : 194 : write(msg, '(a)' )' Now, the imaginary part of the dynamical matrix is zeroed '
1420 : 194 : call wrtout(ab_out,msg)
1421 : 194 : call wrtout(std_out,msg)
1422 : :
1423 [ + + + + : 32474 : d2cart(2, 1:3, 1:natom, 1:3, 1:natom) = zero
+ + + + ]
1424 : :
1425 [ - + ]: 194 : ABI_FREE(wghtat)
1426 : :
1427 : 194 : end subroutine chneu9
1428 : : !!***
1429 : :
1430 : : !----------------------------------------------------------------------
1431 : :
1432 : : !!****f* m_dynmat/d2sym3
1433 : : !! NAME
1434 : : !! d2sym3
1435 : : !!
1436 : : !! FUNCTION
1437 : : !! Given a set of calculated elements of the 2DTE matrix d2,
1438 : : !! build (nearly) all the other matrix elements that can be build using symmetries.
1439 : : !!
1440 : : !! 1. Perform first some completion by symmetrisation (exchange)
1441 : : !! over the two defining perturbations
1442 : : !! 2. For each element, uses every symmetry, and build the element, in case
1443 : : !! EITHER all the needed elements are available,
1444 : : !! OR the only missing is itself
1445 : : !! OR the perturbation is the electric field, in a diamond
1446 : : !! symmetry (the last case was coded rather dirty)
1447 : : !!
1448 : : !! INPUTS
1449 : : !! indsym(4,nsym,natom)=indirect indexing array : for each
1450 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
1451 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
1452 : : !! translations which must be subtracted after the transformation to get back
1453 : : !! to the original unit cell.
1454 : : !! mpert =maximum number of ipert
1455 : : !! natom= number of atoms
1456 : : !! nsym=number of space group symmetries
1457 : : !! qpt(3)=wavevector of the perturbation
1458 : : !! symq(4,2,nsym)= (integer) three first numbers define the G vector ;
1459 : : !! fourth number is zero if the q-vector is not preserved,
1460 : : !! is 1 otherwise
1461 : : !! second index is one without time-reversal symmetry,
1462 : : !! two with time-reversal symmetry
1463 : : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
1464 : : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
1465 : : !! timrev=1 if the time-reversal symmetry preserves the wavevector,
1466 : : !! modulo a reciprocal lattice vector, timrev=0 otherwise
1467 : : !! zero_by_symm= if 1, set blkflg to 1 for the elements that must be zero by symmetry, and zero them.
1468 : : !! This has the indirect effect of being able to resymmetrize the whole matrix, thus
1469 : : !! enforcing better the symmetry for the 2DTE.
1470 : : !!
1471 : : !! SIDE EFFECTS
1472 : : !! Input/Output
1473 : : !! d2(2,3,mpert,3,mpert)= matrix of the 2DTE
1474 : : !! blkflg(3,mpert,3,mpert)= ( 1 if the element of the dynamical
1475 : : !! matrix has been calculated ; 0 otherwise)
1476 : : !!
1477 : : !! NOTES
1478 : : !! The complete search would be to have the possibility
1479 : : !! of a set of missing elements. See notes of July 2, 1994,
1480 : : !! in the blue notebook 'computer codes'
1481 : : !! The partial solution adopted here takes into
1482 : : !! account some mirror symmetries
1483 : : !! as well as the tetrahedral symmetry of the diamond lattice
1484 : : !! On 010331, replaced the loops up to mpert by loops up to
1485 : : !! natom+2, because of a crash bug under Windows. However,
1486 : : !! the problem lies likely in the use of the indsym array.
1487 : : !!
1488 : : !! SOURCE
1489 : :
1490 : 174682 : subroutine d2sym3(blkflg,d2,indsym,mpert,natom,nsym,qpt,symq,symrec,symrel,timrev,zero_by_symm,eta)
1491 : :
1492 : : !Arguments -------------------------------
1493 : : !scalars
1494 : : integer,intent(in) :: mpert,natom,nsym,timrev,zero_by_symm
1495 : : !arrays
1496 : : integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym)
1497 : : integer,intent(in),target :: symrec(3,3,nsym),symrel(3,3,nsym)
1498 : : integer,intent(inout) :: blkflg(3,mpert,3,mpert)
1499 : : real(dp),intent(in) :: qpt(3)
1500 : : real(dp),intent(inout) :: d2(2,3,mpert,3,mpert)
1501 : : real(dp),optional,intent(in) :: eta
1502 : :
1503 : : !Local variables -------------------------
1504 : : !scalars
1505 : : logical, parameter :: do_final_sym=.true.
1506 : : logical :: qzero
1507 : : integer :: exch12,found,idir1,idir2,idisy1,idisy2,ipert1,ipert2
1508 : : integer :: ipesy1,ipesy2,isgn,isym,ithree,itirev,nblkflg_is_one,noccur,nsym_used,quit,quit1
1509 : : real(dp) :: arg1,arg2,im,norm,eta_,re,sumi,sumr,xi,xr
1510 : : !arrays
1511 : 174682 : integer,pointer :: sym1_(:,:,:),sym2_(:,:,:)
1512 : 174682 : real(dp),allocatable :: d2tmp1(:,:,:),d2tmp2(:,:,:),d2work(:,:,:,:,:)
1513 : : ! *********************************************************************
1514 : :
1515 : 174682 : qzero=(qpt(1)**2+qpt(2)**2+qpt(3)**2<tol16)
1516 : :
1517 : : !Here look after exchange of 1 and 2 axis,
1518 : : !for electric field in diamond symmetry
1519 : 174682 : exch12=0
1520 : 174682 : if (qzero) then
1521 [ + + ]: 1467356 : do isym=1,nsym
1522 : 1466947 : exch12=1
1523 [ + + ]: 1466947 : if(symrel(1,1,isym)/=0)exch12=0
1524 [ + + ]: 1466947 : if(symrel(1,2,isym)/=1)exch12=0
1525 [ + + ]: 1466947 : if(symrel(1,3,isym)/=0)exch12=0
1526 [ + + ]: 1466947 : if(symrel(2,1,isym)/=1)exch12=0
1527 [ + + ]: 1466947 : if(symrel(2,2,isym)/=0)exch12=0
1528 [ + + ]: 1466947 : if(symrel(2,3,isym)/=0)exch12=0
1529 [ + + ]: 1466947 : if(symrel(3,1,isym)/=0)exch12=0
1530 [ + + ]: 1466947 : if(symrel(3,2,isym)/=0)exch12=0
1531 [ + + ]: 1466947 : if(symrel(3,3,isym)/=1)exch12=0
1532 : : ! if(exch12==1) write(std_out,*)' d2sym3 : found exchange 1 2 =',isym
1533 [ + + ]: 390083 : if(exch12==1)exit
1534 : : end do
1535 : : end if
1536 : :
1537 [ + + ]: 174682 : eta_=zero; if(present(eta)) eta_=eta
1538 : :
1539 : : !Consider two cases : either time-reversal symmetry
1540 : : !conserves the wavevector, or not
1541 [ + + - + ]: 174682 : if(timrev==0.and.abs(eta_)<tol8)then
1542 : :
1543 [ + + ]: 530536 : do ipert1=1,mpert !See notes
1544 : : ! do ipert1=1,min(natom+2,mpert)
1545 [ + + ]: 1763503 : do idir1=1,3
1546 : :
1547 : : ! Since the matrix is hermitian, the diagonal elements are real
1548 : 1232967 : d2(2,idir1,ipert1,idir1,ipert1)=zero
1549 : :
1550 [ + + ]: 7223125 : do ipert2=1,mpert !See notes
1551 : : ! do ipert2=1,min(natom+2,mpert)
1552 [ + + ]: 23549643 : do idir2=1,3
1553 : :
1554 : : ! FIXME use is_type functions
1555 : : ! If an element exists
1556 [ + + ]: 22316676 : if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
1557 : :
1558 : : ! Either complete the symmetric missing element
1559 [ + + ]: 2028269 : if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
1560 : :
1561 : 1207 : d2(1,idir2,ipert2,idir1,ipert1)= d2(1,idir1,ipert1,idir2,ipert2)
1562 : 1207 : d2(2,idir2,ipert2,idir1,ipert1)=-d2(2,idir1,ipert1,idir2,ipert2)
1563 : :
1564 : 1207 : blkflg(idir2,ipert2,idir1,ipert1)=1
1565 : :
1566 : : ! Or symmetrize (the matrix is hermitian) in case both exists
1567 : : ! (Note : this opportunity has been disabled for more
1568 : : ! obvious search for bugs in the code )
1569 : : ! else
1570 : : ! sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
1571 : : ! sumi=d2(1,idir2,ipert2,idir1,ipert1)-d2(1,idir1,ipert1,idir2,ipert2)
1572 : : ! d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
1573 : : ! d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
1574 : : ! d2(2,idir2,ipert2,idir1,ipert1)=half*sumi
1575 : : ! d2(2,idir1,ipert1,idir2,ipert2)=-half*sumi
1576 : : end if
1577 : : end if
1578 : :
1579 : : end do
1580 : : end do
1581 : :
1582 : : end do
1583 : : end do
1584 : :
1585 : : ! Here, case with time-reversal symmetry
1586 : : else
1587 : :
1588 [ + + ]: 233391 : do ipert1=1,mpert !See notes
1589 : : ! do ipert1=1,min(natom+2,mpert)
1590 [ + + ]: 768159 : do idir1=1,3
1591 [ + + ]: 2623184 : do ipert2=1,mpert !See notes
1592 : : ! do ipert2=1,min(natom+2,mpert)
1593 [ + + ]: 8175408 : do idir2=1,3
1594 : 5730480 : d2(2,idir1,ipert1,idir2,ipert2)=zero
1595 : :
1596 : : ! If an element exists
1597 [ + + ]: 7640640 : if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
1598 : :
1599 : : ! Either complete the symmetric missing element
1600 [ + + ]: 777582 : if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
1601 : :
1602 : 7372 : d2(1,idir2,ipert2,idir1,ipert1)=d2(1,idir1,ipert1,idir2,ipert2)
1603 : 7372 : blkflg(idir2,ipert2,idir1,ipert1)=1
1604 : :
1605 : : ! Or symmetrize (the matrix is hermitian) in case both exists
1606 : : ! (Note : this opportunity has been disabled for more
1607 : : ! obvious search for bugs in the code )
1608 : : ! else
1609 : : ! sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
1610 : : ! d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
1611 : : ! d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
1612 : : end if
1613 : :
1614 : : end if
1615 : : end do
1616 : : end do
1617 : : end do
1618 : : end do
1619 : : end if
1620 : :
1621 : : !Big Big Loop : symmetrize three times, because
1622 : : !of some cases in which one element is not yet available
1623 : : !at the first pass, and even at the second one !
1624 [ + + ]: 698728 : do ithree=1,3
1625 : :
1626 : : ! Big loop on all elements
1627 [ + + ]: 2466463 : do ipert1=1,mpert !See notes
1628 : : ! do ipert1=1,min(natom+2,mpert)
1629 : :
1630 : : ! Select the symmetries according to pertubation 1
1631 [ + + ]: 1767735 : if (ipert1<=natom)then
1632 : 642897 : sym1_ => symrec
1633 : : else
1634 : 1124838 : sym1_ => symrel
1635 : : end if
1636 : :
1637 [ + + ]: 7594986 : do idir1=1,3
1638 [ + + ]: 29538927 : do ipert2=1,mpert !See notes
1639 : : ! do ipert2=1,min(natom+2,mpert)
1640 : :
1641 : : ! Select the symmetries according to pertubation 2
1642 [ + + ]: 22467987 : if (ipert2<=natom)then
1643 : 7575489 : sym2_ => symrec
1644 : : else
1645 : 14892498 : sym2_ => symrel
1646 : : end if
1647 : :
1648 [ + + ]: 95175153 : do idir2=1,3
1649 : :
1650 : : ! Will get element (idir1,ipert1,idir2,ipert2)
1651 : : ! so this element should not yet be present ...
1652 [ + + ]: 89871948 : if(blkflg(idir1,ipert1,idir2,ipert2)/=1)then
1653 : :
1654 : 57508094 : d2(1,idir1,ipert1,idir2,ipert2)=zero
1655 : 57508094 : d2(2,idir1,ipert1,idir2,ipert2)=zero
1656 : :
1657 : : ! Loop on all symmetries, including time-reversal
1658 : 57508094 : quit1=0
1659 [ + + ]: 2174508361 : do isym=1,nsym
1660 [ + + ]: 6351736674 : do itirev=1,2
1661 : 4234736407 : isgn=3-2*itirev
1662 : :
1663 [ + + ]: 6351736674 : if(symq(4,itirev,isym)/=0)then
1664 : 1817820617 : found=1
1665 : :
1666 : : ! Here select the symmetric of ipert1
1667 [ + + ]: 1817820617 : if(ipert1<=natom)then
1668 : 415311059 : ipesy1=indsym(4,isym,ipert1)
1669 [ + + + + ]: 1402509558 : else if(ipert1==(natom+2).and.qzero)then
1670 : : ipesy1=ipert1
1671 : : else
1672 : 1122607581 : found=0
1673 : : end if
1674 : :
1675 : : ! Here select the symmetric of ipert2
1676 [ + + ]: 1817820617 : if(ipert2<=natom)then
1677 : 417907445 : ipesy2=indsym(4,isym,ipert2)
1678 [ + + + + ]: 1399913172 : else if(ipert2==(natom+2).and.qzero)then
1679 : : ipesy2=ipert2
1680 : : else
1681 : : found=0
1682 : : end if
1683 : :
1684 : : ! Now that a symmetric perturbation has been obtained,
1685 : : ! including the expression of the symmetry matrix, see
1686 : : ! if the symmetric values are available
1687 [ + + ]: 695213036 : if( found==1 ) then
1688 : :
1689 : : sumr=zero
1690 : : sumi=zero
1691 : : noccur=0
1692 : : nblkflg_is_one=0
1693 : : quit=0
1694 [ + + ]: 505121346 : do idisy1=1,3
1695 [ + + ]: 1465486933 : do idisy2=1,3
1696 [ + + + + ]: 1465486933 : if(sym1_(idir1,idisy1,isym)/=0 .and. sym2_(idir2,idisy2,isym)/=0 )then
1697 [ + + ]: 273775434 : if(blkflg(idisy1,ipesy1,idisy2,ipesy2)==1)then
1698 : 40998557 : nblkflg_is_one=nblkflg_is_one+1
1699 : : sumr=sumr+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
1700 : 40998557 : & d2(1,idisy1,ipesy1,idisy2,ipesy2)
1701 : : sumi=sumi+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
1702 : 40998557 : & d2(2,idisy1,ipesy1,idisy2,ipesy2)
1703 : :
1704 : : ! Here, in case the symmetric of the element
1705 : : ! is the element, or the symmetric with
1706 : : ! respect to permutation of perturbations
1707 : : ! (some more conditions on the time-reversal
1708 : : ! symmetry must be fulfilled although)
1709 : : else if( idisy1==idir1 .and. ipesy1==ipert1&
1710 : : & .and. idisy2==idir2 .and. ipesy2==ipert2&
1711 [ + + + + : 232776877 : & .and.(isgn==1 .or. timrev==1 &
+ + + + +
+ ]
1712 : : & .or. (idir1==idir2 .and. ipert1==ipert2)))&
1713 : : & then
1714 : 58712890 : noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1715 : : else if( idisy1==idir2 .and. ipesy1==ipert2&
1716 : : & .and. idisy2==idir1 .and. ipesy2==ipert1&
1717 [ + + + + : 174063987 : & .and.(isgn==-1 .or. timrev==1&
+ + + + -
+ ]
1718 : : & .or. (idir1==idir2 .and. ipert1==ipert2)))&
1719 : : & then
1720 : 12296011 : noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1721 : :
1722 : : ! Here, electric field case
1723 : : else if( exch12==1 .and. &
1724 : : & ipert1==natom+2 .and. ipert2==natom+2&
1725 [ + + + + : 161767976 : & .and.(( idisy1+idir1 ==3 &
+ + + + +
+ + + + +
+ + + + +
+ + + ]
1726 : : & .and. idisy2==3 .and. idir2==3)&
1727 : : & .or. ( idisy1+idir2 ==3&
1728 : : & .and. idisy2==3 .and. idir1==3)&
1729 : : & .or. ( idisy2+idir2 ==3&
1730 : : & .and. idisy1==3 .and. idir1==3)&
1731 : : & .or. ( idisy2+idir1 ==3&
1732 : : & .and. idisy1==3 .and. idir2==3)))&
1733 : : & then
1734 : 15375464 : noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1735 : :
1736 : : else
1737 : : ! Not found
1738 : : found=0
1739 : : quit=1
1740 : : exit
1741 : : end if
1742 : :
1743 : : end if
1744 : : end do
1745 [ + + ]: 505121346 : if(quit==1)exit
1746 : : end do
1747 : : end if
1748 : :
1749 : : ! In case zero_by_symm==0, the computed matrix element must be associated to at least one really computed matrix element
1750 [ + + ]: 1817820617 : if(zero_by_symm==0 .and. nblkflg_is_one==0)then
1751 : : found=0
1752 : : endif
1753 : :
1754 : : ! Now, if still found and associated to at least one really computed matrix element, put the correct value into array d2
1755 [ + + ]: 1817786153 : if(found==1)then
1756 : :
1757 : : ! In case of phonons, need to take into account the
1758 : : ! time-reversal symmetry, and the shift back to the unit cell
1759 : : !
1760 : : ! XG990712 : I am not sure this must be kept for electric field ...
1761 : : ! 1) Consider time-reversal symmetry
1762 : 59422310 : sumi=isgn*sumi
1763 : :
1764 [ + + + + ]: 59422310 : if(ipert1<=natom .and. ipert2<=natom)then
1765 : : ! 2) Shift the atoms back to the unit cell.
1766 : : arg1=two_pi*( qpt(1)*indsym(1,isym,ipert1)&
1767 : : & +qpt(2)*indsym(2,isym,ipert1)&
1768 : 199758 : & +qpt(3)*indsym(3,isym,ipert1) )
1769 : : arg2=two_pi*( qpt(1)*indsym(1,isym,ipert2)&
1770 : : & +qpt(2)*indsym(2,isym,ipert2)&
1771 : 199758 : & +qpt(3)*indsym(3,isym,ipert2) )
1772 : 199758 : re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
1773 : : ! XG010117 Must use isgn
1774 : 199758 : im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
1775 : : else
1776 : : re=one
1777 : : im=zero
1778 : : end if
1779 : :
1780 : : ! Final check, could still fail if the
1781 : : ! element was its own symmetric
1782 [ + + - + ]: 59422310 : if (abs(1.0_dp-re*noccur)< 1.0d-6.and.abs(im*noccur) <1.0d-6) then
1783 : : found=0
1784 : : end if
1785 : :
1786 : : end if
1787 : :
1788 : : if(found==1)then
1789 : :
1790 [ + + ]: 735390 : if(noccur==0)then
1791 : 600529 : d2(1,idir1,ipert1,idir2,ipert2)=re*sumr-im*sumi
1792 : 600529 : d2(2,idir1,ipert1,idir2,ipert2)=re*sumi+im*sumr
1793 : : else
1794 : : ! See page July 2, 1994 in computer codes notebook
1795 : 134861 : xr=re*sumr-im*sumi
1796 : 134861 : xi=re*sumi+im*sumr
1797 : 134861 : norm=one+noccur**2-two*re*noccur
1798 : 134861 : xr=xr/norm
1799 : 134861 : xi=xi/norm
1800 : : d2(1,idir1,ipert1,idir2,ipert2)=&
1801 : 134861 : & (one-re*noccur)*xr-im*noccur*xi
1802 : : d2(2,idir1,ipert1,idir2,ipert2)=&
1803 : 134861 : & (one-re*noccur)*xi+im*noccur*xr
1804 : : end if
1805 : :
1806 : : ! The element has been constructed !
1807 : 735390 : blkflg(idir1,ipert1,idir2,ipert2)=1
1808 : :
1809 : : quit1=1
1810 : : exit ! Exit loop on symmetry operations
1811 : : end if
1812 : :
1813 : : ! End loop on all symmetries + time-reversal
1814 : : end if
1815 : : end do
1816 : 56772704 : if(quit1==1)exit
1817 : : end do
1818 : :
1819 : : end if
1820 : : end do ! End big loop on all elements
1821 : : end do
1822 : : end do
1823 : : end do
1824 : :
1825 : : end do ! End Big Big Loop
1826 : :
1827 : : !MT oct. 20, 2014:
1828 : : !Once the matrix has been built, it does not necessarily fulfill the correct symmetries.
1829 : : !It has just been filled up from rows or columns that only fulfill symmetries preserving
1830 : : !one particular perturbation.
1831 : : !An additional symmetrization might solve this (do not consider TR-symmetry)
1832 : : if (do_final_sym) then
1833 [ - + ]: 174682 : ABI_MALLOC(d2tmp1,(2,3,3))
1834 [ - + ]: 174682 : ABI_MALLOC(d2tmp2,(2,3,3))
1835 [ - + + - : 873410 : ABI_MALLOC(d2work,(2,3,mpert,3,mpert))
+ - - + +
- + - + -
- + - + ]
1836 [ + + + + : 77424952 : d2work(:,:,:,:,:)=d2(:,:,:,:,:)
+ + + + +
+ ]
1837 [ + + ]: 763927 : do ipert1=1,mpert
1838 : : !do ipert1=1,min(natom+2,mpert)
1839 [ + + + + : 589245 : if ((ipert1==natom+1.or.ipert1==natom+10.or.ipert1==natom+11).or.(ipert1==natom+2.and.(.not.qzero))) cycle
+ + + + +
+ ]
1840 [ + + ]: 291628 : if (ipert1<=natom)then
1841 : 214299 : sym1_ => symrec
1842 : : else
1843 : 77329 : sym1_ => symrel
1844 : : end if
1845 [ + + ]: 1894154 : do ipert2=1,mpert
1846 : : !do ipert2=1,min(natom+2,mpert)
1847 : : ! if (any(blkflg(:,ipert1,:,ipert2)==0)) cycle
1848 [ + + + + : 1427844 : if ((ipert2==natom+1.or.ipert2==natom+10.or.ipert2==natom+11).or.(ipert2==natom+2.and.(.not.qzero))) cycle
+ + + + +
+ ]
1849 [ + + ]: 913608 : if (ipert2<=natom)then
1850 : 464406 : sym2_ => symrec
1851 : : else
1852 : 449202 : sym2_ => symrel
1853 : : end if
1854 : 913608 : nsym_used=0
1855 [ + + + + : 28321848 : d2tmp2(:,:,:)=zero
+ + ]
1856 [ + + ]: 30619939 : do isym=1,nsym
1857 [ + + ]: 30619939 : if (symq(4,1,isym)==1) then
1858 [ + + ]: 16085572 : ipesy1=ipert1;if (ipert1<=natom) ipesy1=indsym(4,isym,ipert1)
1859 [ + + ]: 16085572 : ipesy2=ipert2;if (ipert2<=natom) ipesy2=indsym(4,isym,ipert2)
1860 : : ! The condition on next line is too severe, since some elements of sym1_ or sym2_ might be zero,
1861 : : ! which means not all blkflg(:,ipesy1,:,ipesy2) would need to be 1 to symmetrize the matrix.
1862 : : ! However, coding something more refined is really more difficult.
1863 : : ! This condition then has the side effect that more symmetries can be applied when zero_by_symm==1,
1864 : : ! since blkflg can be set to 1 when the symmetries guarantee the matrix element to be zero.
1865 [ + + + + : 82408363 : if (all(blkflg(:,ipesy1,:,ipesy2)==1)) then
+ + + + ]
1866 : 5523960 : nsym_used=nsym_used+1
1867 : 5523960 : re=one;im=zero
1868 [ + + + + : 5523960 : if (ipert1<=natom.and.ipert2<=natom.and.(.not.qzero)) then
+ + ]
1869 : : arg1=two_pi*(qpt(1)*(indsym(1,isym,ipert1)-indsym(1,isym,ipert2)) &
1870 : : & +qpt(2)*(indsym(2,isym,ipert1)-indsym(2,isym,ipert2)) &
1871 : 2626726 : & +qpt(3)*(indsym(3,isym,ipert1)-indsym(3,isym,ipert2)))
1872 : 2626726 : re=cos(arg1);im=sin(arg1)
1873 : : end if
1874 [ + + + + : 171242760 : d2tmp1(:,:,:)=zero
+ + ]
1875 [ + + ]: 22095840 : do idir2=1,3 !kappa
1876 [ + + ]: 71811480 : do idir1=1,3 !mu
1877 [ + + ]: 215434440 : do idisy1=1,3 !nu
1878 : : d2tmp1(:,idir1,idir2)=d2tmp1(:,idir1,idir2) &
1879 [ + + ]: 497156400 : & +sym1_(idir1,idisy1,isym)*d2(:,idisy1,ipesy1,idir2,ipesy2)
1880 : : end do
1881 : : end do
1882 : : end do
1883 [ + + ]: 22095840 : do idir2=1,3 !mu
1884 [ + + ]: 71811480 : do idir1=1,3 !kappa
1885 [ + + ]: 215434440 : do idisy2=1,3 !nu
1886 : : d2tmp2(1,idir1,idir2)=d2tmp2(1,idir1,idir2) &
1887 : 149146920 : & +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*re-d2tmp1(2,idir1,idisy2)*im)
1888 : : d2tmp2(2,idir1,idir2)=d2tmp2(2,idir1,idir2) &
1889 : 198862560 : & +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*im+d2tmp1(2,idir1,idisy2)*re)
1890 : : end do
1891 : : end do
1892 : : end do
1893 : : end if
1894 : : end if
1895 : : end do ! isym
1896 [ + + + + : 10897233 : if (nsym_used>0) d2work(:,1:3,ipert1,1:3,ipert2)=d2tmp2(:,1:3,1:3)/dble(nsym_used)
+ + + + ]
1897 : : end do !ipert2
1898 : : end do !ipert1
1899 [ + - + + : 10400248 : if (mpert>=natom) d2(:,1:3,1:natom,1:3,1:natom)=d2work(:,1:3,1:natom,1:3,1:natom)
+ + + + +
+ + + ]
1900 [ + + ]: 174682 : if (mpert>=natom+2) then
1901 [ + + + + : 6801530 : d2(:,1:3,natom+2,1:3,1:natom)=d2work(:,1:3,natom+2,1:3,1:natom)
+ + + + ]
1902 [ + + + + : 7111082 : d2(:,1:3,1:natom,1:3,natom+2)=d2work(:,1:3,1:natom,1:3,natom+2)
+ + + + ]
1903 [ + + + + : 5407733 : d2(:,1:3,natom+2,1:3,natom+2)=d2work(:,1:3,natom+2,1:3,natom+2)
+ + ]
1904 : : end if
1905 [ - + ]: 174682 : ABI_FREE(d2tmp1)
1906 [ - + ]: 174682 : ABI_FREE(d2tmp2)
1907 [ - + ]: 174682 : ABI_FREE(d2work)
1908 : : end if
1909 : :
1910 [ + + ]: 174682 : end subroutine d2sym3
1911 : : !!***
1912 : :
1913 : : !----------------------------------------------------------------------
1914 : :
1915 : : !!****f* m_dynmat/q0dy3_apply
1916 : : !! NAME
1917 : : !! q0dy3_apply
1918 : : !!
1919 : : !! FUNCTION
1920 : : !! Takes care of the inclusion of the ewald q=0 term in the dynamical
1921 : : !! matrix - corrects the dyew matrix provided as input
1922 : : !! See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
1923 : : !! get the left hand side.
1924 : : !!
1925 : : !! INPUTS
1926 : : !! dyewq0(3,3,natom) = part needed to correct the dynamical matrix for atom self-interaction.
1927 : : !! natom= number of atom in the unit cell
1928 : : !!
1929 : : !! SIDE EFFECTS
1930 : : !! dyew(2,3,natom,3,natom)= dynamical matrix corrected on output
1931 : : !!
1932 : : !! NOTES
1933 : : !! Should be used just after each call to dfpt_ewald, for both
1934 : : !! q==0 and the real wavelength.
1935 : : !!
1936 : : !! The q0dy3_apply should be used in conjunction with the subroutine dfpt_ewald (or ewald9):
1937 : : !! First, the call of dfpt_ewald with q==0 should be done,
1938 : : !! then the call to q0dy3_calc will produce
1939 : : !! the dyewq0 matrix from the (q=0) dyew matrix
1940 : : !! Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
1941 : : !! should be done, then the call to q0dy3_apply
1942 : : !! will produce the correct dynamical matrix dyew starting from
1943 : : !! the previously calculated dyewq0 and the bare(non-corrected)
1944 : : !! dyew matrix
1945 : : !!
1946 : : !! SOURCE
1947 : :
1948 : 176672 : subroutine q0dy3_apply(natom,dyewq0,dyew)
1949 : :
1950 : : !Arguments -------------------------------
1951 : : !scalars
1952 : : integer,intent(in) :: natom
1953 : : !arrays
1954 : : real(dp),intent(in) :: dyewq0(3,3,natom)
1955 : : real(dp),intent(inout) :: dyew(2,3,natom,3,natom)
1956 : :
1957 : : !Local variables -------------------------
1958 : : !scalars
1959 : : integer :: ia,mu,nu
1960 : : ! *********************************************************************
1961 : :
1962 [ + + ]: 706688 : do mu=1,3
1963 [ + + ]: 2296736 : do nu=1,3
1964 [ + + ]: 5657631 : do ia=1,natom
1965 : 5127615 : dyew(1,mu,ia,nu,ia)=dyew(1,mu,ia,nu,ia)-dyewq0(mu,nu,ia)
1966 : : end do
1967 : : end do
1968 : : end do
1969 : :
1970 : 176672 : end subroutine q0dy3_apply
1971 : : !!***
1972 : :
1973 : : !----------------------------------------------------------------------
1974 : :
1975 : : !!****f* m_dynmat/q0dy3_calc
1976 : : !! NAME
1977 : : !! q0dy3_calc
1978 : : !!
1979 : : !! FUNCTION
1980 : : !! Calculate the q=0 correction term to the dynamical matrix
1981 : : !! See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], the sum over \kappa"
1982 : : !!
1983 : : !! INPUTS
1984 : : !! dyew(2,3,natom,3,natom)= dynamical matrix
1985 : : !! input, non-corrected, for q=0 if option=1 or 2
1986 : : !! natom= number of atom in the unit cell
1987 : : !! option= either 1 or 2:
1988 : : !! 1: use dyew to calculate dyewq0 symmetrical form
1989 : : !! 2: use dyew to calculate dyewq0 symmetrical form
1990 : : !!
1991 : : !! OUTPUT
1992 : : !! dyewq0(3,3,natom) = part needed to correct
1993 : : !! the dynamical matrix for atom self-interaction.
1994 : : !!
1995 : : !! NOTES
1996 : : !! Should be used just after each call to dfpt_ewald, for both
1997 : : !! q==0 and the real wavelength.
1998 : : !!
1999 : : !! If option=1 or 2, q0dy3_calc uses an Ewald dynamical matrix at q=0,
2000 : : !! called dyew, to produce a contracted form called dyewq0 :
2001 : : !! either:
2002 : : !! in an unsymmetrical form (if option=1), or
2003 : : !! in a symmetrical form (if option=2).
2004 : : !!
2005 : : !! The q0dy3_calc should be used in conjunction with the subroutine dfpt_ewald (or ewald9).
2006 : : !! First, the call of dfpt_ewald with q==0 should be done ,
2007 : : !! then the call to q0dy3_calc will produce
2008 : : !! the dyewq0 matrix from the (q=0) dyew matrix
2009 : : !! Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
2010 : : !! should be done, then the call to q0dy3_apply
2011 : : !! will produce the correct dynamical matrix dyew starting from
2012 : : !! the previously calculated dyewq0 and the bare(non-corrected)
2013 : : !! dyew matrix
2014 : : !!
2015 : : !! SOURCE
2016 : :
2017 : 608 : subroutine q0dy3_calc(natom,dyewq0,dyew,option)
2018 : :
2019 : : !Arguments -------------------------------
2020 : : !scalars
2021 : : integer,intent(in) :: natom,option
2022 : : !arrays
2023 : : real(dp),intent(in) :: dyew(2,3,natom,3,natom)
2024 : : real(dp),intent(out) :: dyewq0(3,3,natom)
2025 : :
2026 : : !Local variables -------------------------
2027 : : !scalars
2028 : : integer :: ia,ib,mu,nu
2029 : : character(len=500) :: msg
2030 : : ! *********************************************************************
2031 : :
2032 [ + - ]: 608 : if(option==1.or.option==2.or.option==6)then
2033 [ + + ]: 2432 : do mu=1,3
2034 [ + + ]: 7904 : do nu=1,3
2035 [ + + ]: 19419 : do ia=1,natom
2036 : 12123 : dyewq0(mu,nu,ia)=zero
2037 [ + + ]: 56160 : do ib=1,natom
2038 : 50688 : dyewq0(mu,nu,ia)=dyewq0(mu,nu,ia)+dyew(1,mu,ia,nu,ib)
2039 : : end do
2040 : : end do
2041 : : end do
2042 : : end do
2043 : : else
2044 : : write (msg, '(3a)')&
2045 : 0 : & 'option should be 1 or 2 or 6.',ch10,&
2046 : 0 : & 'action: correct calling routine'
2047 : 0 : ABI_BUG(msg)
2048 : : end if
2049 : :
2050 [ + + ]: 608 : if(option==2)then
2051 [ + + ]: 141 : do ia=1,natom
2052 [ + + ]: 477 : do mu=1,3
2053 [ + + ]: 1120 : do nu=mu,3
2054 : 672 : dyewq0(mu,nu,ia)=(dyewq0(mu,nu,ia)+dyewq0(nu,mu,ia))/2
2055 : 1008 : dyewq0(nu,mu,ia)=dyewq0(mu,nu,ia)
2056 : : end do
2057 : : end do
2058 : : end do
2059 : : end if
2060 : :
2061 : 608 : end subroutine q0dy3_calc
2062 : : !!***
2063 : :
2064 : : !----------------------------------------------------------------------
2065 : :
2066 : : !!****f* m_dynmat/symdyma
2067 : : !!
2068 : : !! NAME
2069 : : !! symdyma
2070 : : !!
2071 : : !! FUNCTION
2072 : : !! Symmetrize the dynamical matrices
2073 : : !!
2074 : : !! INPUTS
2075 : : !! indsym(4,nsym*natom)=indirect indexing array : for each
2076 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
2077 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
2078 : : !! translations which must be subtracted after the transformation to get back
2079 : : !! to the original unit cell.
2080 : : !! natom=number of atoms in unit cell
2081 : : !! nsym=number of space group symmetries
2082 : : !! qptn(3)=normalized phonon wavevector
2083 : : !! rprimd(3,3)=dimensional primitive translations (bohr)
2084 : : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
2085 : : !!
2086 : : !! SIDE EFFECTS
2087 : : !! Input/Output
2088 : : !! dmati(2*3*natom*3*natom)=dynamical matrices in cartesian coordinates relative to the q
2089 : : !! points of the B.Z. sampling
2090 : : !!
2091 : : !! NOTES
2092 : : !! the procedure of the symmetrization of the dynamical matrix follows the
2093 : : !! equations in: Hendrikse et al., Computer Phys. Comm. 86, 297 (1995) [[cite:Hendrikse1995]]
2094 : : !!
2095 : : !! TODO
2096 : : !! A full description of the equations should be included
2097 : : !!
2098 : : !! SOURCE
2099 : :
2100 : 185469 : subroutine symdyma(dmati,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
2101 : :
2102 : : !Arguments -------------------------------
2103 : : !scalars
2104 : : integer,intent(in) :: natom,nsym
2105 : : !arrays
2106 : : integer,intent(in) :: indsym(4,nsym,natom),symrel(3,3,nsym)
2107 : : integer,intent(in) :: symafm(nsym)
2108 : : real(dp),intent(in) :: qptn(3),rprimd(3,3)
2109 : : real(dp),intent(inout) :: dmati(2*3*natom*3*natom)
2110 : :
2111 : : !Local variables -------------------------
2112 : : !scalars
2113 : : integer :: i1,i2,iat,idir,ii,index,isgn,isym,itirev,jat,jdir,jj,kk,ll
2114 : : integer :: niat,njat,timrev
2115 : : real(dp) :: arg1,arg2,dmint,im,re,sumi,sumr
2116 : : !arrays
2117 : 370938 : integer :: indij(natom,natom),symq(4,2,nsym),symrec(3,3,nsym)
2118 : 370938 : real(dp) :: TqR(3,3),TqS_(3,3),dynmat(2,3,natom,3,natom)
2119 : 370938 : real(dp) :: dynmatint(2*nsym,2,3,natom,3,natom),gprimd(3,3)
2120 : 370938 : real(dp) :: symcart(3,3,nsym)
2121 : : ! *********************************************************************
2122 : : !FIXME Disabling optimization with NVHPC in this routine
2123 : : ! because of significant numerical divergence
2124 : : !nvf$r opt=0
2125 : :
2126 : : ! 0) initializations
2127 : 185469 : call matr3inv(rprimd,gprimd)
2128 [ + + ]: 5012344 : do isym=1,nsym
2129 : 5012344 : call mati3inv(symrel(:,:,isym),symrec(:,:,isym))
2130 : : end do
2131 : :
2132 : : TqR=zero
2133 : : TqS_=zero
2134 [ + + + + : 31597195 : dynmat=zero
+ + + + +
+ ]
2135 : :
2136 : : !Note: dynmat is used as work space here
2137 : : i1=0
2138 [ + + ]: 546778 : do iat=1,natom
2139 [ + + ]: 1630705 : do idir=1,3
2140 : 1083927 : i1=i1+1
2141 : 1083927 : i2=0
2142 [ + + ]: 4441885 : do jat=1,natom
2143 [ + + ]: 13070523 : do jdir=1,3
2144 : 8989947 : i2=i2+1
2145 : 8989947 : index=i1+3*natom*(i2-1)
2146 : 8989947 : dynmat(1,idir,iat,jdir,jat)=dmati(2*index-1)
2147 : 11986596 : dynmat(2,idir,iat,jdir,jat)=dmati(2*index )
2148 : : end do
2149 : : end do
2150 : : end do
2151 : : end do
2152 : :
2153 : : !Transform symrel to cartesian coordinates (RC coding)
2154 : : !do isym=1,nsym
2155 : : !symcart(:,:,isym)=matmul(rprimd,matmul(dble(symrel(:,:,isym)),gprimd))
2156 : : !end do
2157 : :
2158 : : !Coding from symdm9
2159 [ + + ]: 5012344 : do isym=1,nsym
2160 [ + + ]: 19492969 : do jj=1,3
2161 [ + + ]: 57922500 : symcart(:,jj,isym)=zero
2162 [ + + ]: 62749375 : do kk=1,3
2163 [ + + ]: 188248125 : do ll=1,3
2164 [ + + ]: 564744375 : symcart(:,jj,isym)=symcart(:,jj,isym)+rprimd(:,kk)*gprimd(jj,ll)*symrel(kk,ll,isym)
2165 : : end do
2166 : : end do
2167 : : end do
2168 : : end do
2169 : :
2170 : : ! Get the symq of the CURRENT Q POINT
2171 : : ! mjv: set prtvol=0 for production runs.
2172 : 185469 : call littlegroup_q(nsym,qptn,symq,symrec,symafm,timrev,prtvol=0)
2173 : :
2174 [ + + + + ]: 1545661 : indij(:,:)=0
2175 [ + + + + : 662790919 : dynmatint=zero
+ + + + +
+ + + ]
2176 : :
2177 [ + + ]: 5012344 : do isym=1,nsym ! loop over all the symmetries
2178 : : ! write(std_out,*) 'current symmetry',isym
2179 [ + + ]: 14666094 : do itirev=1,2 ! loop over the time-reversal symmetry
2180 : 9653750 : isgn=3-2*itirev
2181 : : ! write(std_out,*) 'timereversal',isgn
2182 : :
2183 [ + + ]: 14480625 : if (symq(4,itirev,isym)==1) then ! isym belongs to the wave vector point group
2184 : : ! write(std_out,*) 'isym belongs to the wave vector point group'
2185 [ + + ]: 2266859 : do iat=1,natom
2186 [ + + ]: 6392247 : do jat=1,natom
2187 : 4125388 : niat=indsym(4,isym,iat) ! niat={R|t}iat
2188 : 4125388 : njat=indsym(4,isym,jat) ! njat={R|t}jat
2189 : 4125388 : indij(niat,njat)=indij(niat,njat)+1
2190 : : ! write(std_out,'(a,5i5)') 'current status:',iat,jat,niat,njat,indij(niat,njat)
2191 : : ! phase calculation, arg1 and arg2 because of two-atom derivative
2192 : : arg1=two_pi*( qptn(1)*indsym(1,isym,iat)+&
2193 : : qptn(2)*indsym(2,isym,iat)+&
2194 : 4125388 : qptn(3)*indsym(3,isym,iat) )
2195 : : arg2=two_pi*( qptn(1)*indsym(1,isym,jat)+&
2196 : : qptn(2)*indsym(2,isym,jat)+&
2197 : 4125388 : qptn(3)*indsym(3,isym,jat) )
2198 : :
2199 : 4125388 : re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
2200 : 4125388 : im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
2201 : :
2202 [ + + ]: 17996858 : do idir=1,3 ! loop over displacements
2203 [ + + ]: 53630044 : do jdir=1,3 ! loop over displacements
2204 : : ! we pick the (iat,jat) (3x3) block of the dyn.mat.
2205 : : sumr=zero
2206 : : sumi=zero
2207 [ + + ]: 148513968 : do ii=1,3
2208 [ + + ]: 482670396 : do jj=1,3
2209 : 334156428 : sumr=sumr+symcart(idir,ii,isym)*dynmat(1,ii,niat,jj,njat)*symcart(jdir,jj,isym)
2210 : 445541904 : sumi=sumi+symcart(idir,ii,isym)*dynmat(2,ii,niat,jj,njat)*symcart(jdir,jj,isym)
2211 : : end do
2212 : : end do
2213 : 37128492 : sumi=isgn*sumi
2214 : :
2215 : 37128492 : dynmatint(nsym*(itirev-1)+isym,1,idir,iat,jdir,jat)=re*sumr-im*sumi
2216 : 49504656 : dynmatint(nsym*(itirev-1)+isym,2,idir,iat,jdir,jat)=re*sumi+im*sumr
2217 : : end do
2218 : : end do
2219 : : end do
2220 : : end do ! end treatment of the (iat,jat) (3x3) block of dynmat
2221 : : end if ! symmetry check
2222 : : end do ! time-reversal
2223 : : end do ! symmetries
2224 : :
2225 : : !4) make the average, get the final symmetric dynamical matrix
2226 [ + + ]: 546778 : do iat=1,natom
2227 [ + + ]: 1545661 : do jat=1,natom
2228 [ + + ]: 4356841 : do idir=1,3
2229 [ + + ]: 12985479 : do jdir=1,3
2230 : : dmint=zero
2231 [ + + ]: 324586809 : do isym=1,2*nsym
2232 : 324586809 : dmint=dmint+dynmatint(isym,1,idir,iat,jdir,jat)
2233 : : end do
2234 : 8989947 : dynmat(1,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
2235 : 8989947 : dmint=zero
2236 [ + + ]: 324586809 : do isym=1,2*nsym
2237 : 324586809 : dmint=dmint+dynmatint(isym,2,idir,iat,jdir,jat)
2238 : : end do
2239 : 11986596 : dynmat(2,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
2240 : : end do
2241 : : end do
2242 : : end do
2243 : : end do
2244 : :
2245 : : i1=0
2246 [ + + ]: 546778 : do iat=1,natom
2247 [ + + ]: 1630705 : do idir=1,3
2248 : 1083927 : i1=i1+1
2249 : 1083927 : i2=0
2250 [ + + ]: 4441885 : do jat=1,natom
2251 [ + + ]: 13070523 : do jdir=1,3
2252 : 8989947 : i2=i2+1
2253 : 8989947 : index=i1+3*natom*(i2-1)
2254 : 8989947 : dmati(2*index-1)=dynmat(1,idir,iat,jdir,jat)
2255 : 11986596 : dmati(2*index )=dynmat(2,idir,iat,jdir,jat)
2256 : : end do
2257 : : end do
2258 : : end do
2259 : : end do
2260 : :
2261 : 185469 : end subroutine symdyma
2262 : : !!***
2263 : :
2264 : : !!****f* m_dynmat/dfpt_sygra
2265 : : !!
2266 : : !! NAME
2267 : : !! dfpt_sygra
2268 : : !!
2269 : : !! FUNCTION
2270 : : !! Symmetrize derivatives of energy with respect to coordinates,
2271 : : !! as appearing in phonon calculations.
2272 : : !! Unsymmetrized gradients are input as deunsy; symmetrized grads are then placed in desym.
2273 : : !! If nsym=1 simply copy deunsy into desym (only symmetry is identity).
2274 : : !! The index of the initial perturbation is needed, in case there is a change
2275 : : !! of atom position (moved in another cell) due to the symmetry operation.
2276 : : !!
2277 : : !! INPUTS
2278 : : !! natom=number of atoms in cell
2279 : : !! deunsy(2,3,natom)=unsymmetrized gradients wrt dimensionless tn (hartree)
2280 : : !! note: there is a real and a imaginary part ...
2281 : : !! indsym(4,nsym,natom)=label given by subroutine symatm, indicating atom
2282 : : !! label which gets rotated into given atom by given symmetry
2283 : : !! (first three elements are related primitive translation--
2284 : : !! see symatm where this is computed)
2285 : : !! nsym=number of symmetry operators in group
2286 : : !! ipert=index of the initial perturbation
2287 : : !! qpt(3)= wavevector of the phonon, in reduced coordinates
2288 : : !! symrec(3,3,nsym)=symmetries of group in terms of operations on
2289 : : !! reciprocal space primitive translations--see comments below
2290 : : !!
2291 : : !! OUTPUT
2292 : : !! desym(2,3,natom)=symmetrized gradients wrt dimensionless tn (hartree)
2293 : : !!
2294 : : !! NOTES
2295 : : !! Written by X. Gonze starting from sygrad, written by D.C. Allan:
2296 : : !! introduction of the q vector for phonon symmetrization
2297 : : !! This routine should once be merged with sygrad...
2298 : : !!
2299 : : !! SOURCE
2300 : :
2301 : 2545 : subroutine dfpt_sygra(natom,desym,deunsy,indsym,ipert,nsym,qpt,symrec)
2302 : :
2303 : : !Arguments -------------------------------
2304 : : !scalars
2305 : : integer,intent(in) :: ipert,natom,nsym
2306 : : !arrays
2307 : : integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym)
2308 : : real(dp),intent(in) :: deunsy(2,3,natom),qpt(3)
2309 : : real(dp),intent(out) :: desym(2,3,natom)
2310 : :
2311 : : !Local variables -------------------------
2312 : : !scalars
2313 : : integer :: ia,ind,isym,mu
2314 : : real(dp) :: arg,im,re,sumi,sumr
2315 : : ! *********************************************************************
2316 : :
2317 [ + + ]: 2545 : if (nsym==1) then
2318 : :
2319 : : ! Only symmetry is identity so simply copy
2320 [ + + + + : 46002 : desym(:,:,:)=deunsy(:,:,:)
+ + ]
2321 : :
2322 : : else
2323 : :
2324 : : ! Actually conduct symmetrization
2325 : : ! write(std_out,*)' dfpt_sygra : desym(:2,:3,:natom),qpt(:)',desym(:2,:3,:natom),qpt(:)
2326 [ + + ]: 2249 : do ia=1,natom
2327 : : ! write(std_out,*)' dfpt_sygra : ia=',ia
2328 [ + + ]: 7067 : do mu=1,3
2329 : : sumr=zero
2330 : : sumi=zero
2331 : : ! write(std_out,*)' dfpt_sygra : mu=',mu
2332 [ + + ]: 23760 : do isym=1,nsym
2333 : 18942 : ind=indsym(4,isym,ia)
2334 : : ! Must shift the atoms back to the unit cell.
2335 : : ! arg=two_pi*( qpt(1)*indsym(1,isym,ia)&
2336 : : ! & +qpt(2)*indsym(2,isym,ia)&
2337 : : ! & +qpt(3)*indsym(3,isym,ia) )
2338 : : ! Selection of non-zero q point, to avoid ipert being outside the 1 ... natom range
2339 [ + + ]: 18942 : if(qpt(1)**2+qpt(2)**2+qpt(3)**2 > tol16)then
2340 : : arg=two_pi*( qpt(1)*(indsym(1,isym,ia)-indsym(1,isym,ipert))&
2341 : : & +qpt(2)* (indsym(2,isym,ia)-indsym(2,isym,ipert))&
2342 : 1896 : & +qpt(3)* (indsym(3,isym,ia)-indsym(3,isym,ipert)))
2343 : : else
2344 : : arg=zero
2345 : : end if
2346 : :
2347 : : re=dble(symrec(mu,1,isym))*deunsy(1,1,ind)+&
2348 : : & dble(symrec(mu,2,isym))*deunsy(1,2,ind)+&
2349 : 18942 : & dble(symrec(mu,3,isym))*deunsy(1,3,ind)
2350 : : im=dble(symrec(mu,1,isym))*deunsy(2,1,ind)+&
2351 : : & dble(symrec(mu,2,isym))*deunsy(2,2,ind)+&
2352 : 18942 : & dble(symrec(mu,3,isym))*deunsy(2,3,ind)
2353 : 18942 : sumr=sumr+re*cos(arg)-im*sin(arg)
2354 : 23760 : sumi=sumi+re*sin(arg)+im*cos(arg)
2355 : : ! sumr=sumr+re
2356 : : ! sumi=sumi+im
2357 : : ! write(std_out,*)' dfpt_sygra : isym,indsym(4,isym,ia),arg,re,im,sumr,sumi',&
2358 : : ! & isym,indsym(4,isym,ia),arg,re,im,sumr,sumi
2359 : : end do
2360 : 4818 : desym(1,mu,ia)=sumr/dble(nsym)
2361 : 6424 : desym(2,mu,ia)=sumi/dble(nsym)
2362 : : ! write(std_out,*)' dfpt_sygra : desym(:,mu,ia)',desym(:,mu,ia)
2363 : : end do
2364 : : end do
2365 : : end if
2366 : :
2367 : 2545 : end subroutine dfpt_sygra
2368 : : !!***
2369 : :
2370 : : !!****f* m_dynmat/dfpt_sydy
2371 : : !! NAME
2372 : : !! dfpt_sydy
2373 : : !!
2374 : : !! FUNCTION
2375 : : !! Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
2376 : : !! Unsymmetrized dynamical matrix is input as dyfrow;
2377 : : !! symmetrized dynamical matrix is then placed in sdyfro.
2378 : : !! If nsym=1 simply copy dyfrow into sdyfro.
2379 : : !!
2380 : : !! INPUTS
2381 : : !! cplex=1 if dynamical matrix is real, 2 if it is complex
2382 : : !! dyfrow(3,3,natom,1+(natom-1)*nondiag)=unsymmetrized dynamical matrix
2383 : : !! indsym(4,msym*natom)=indirect indexing array: for each
2384 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
2385 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
2386 : : !! translations which must be subtracted after the transformation to get back
2387 : : !! to the original unit cell.
2388 : : !! natom=number of atoms in cell.
2389 : : !! nondiag=0 if dynamical matrix is diagonal with respect to atoms
2390 : : ! 1 if dynamical matrix is non diagonal with respect to atoms
2391 : : !! nsym=number of symmetry operators in group.
2392 : : !! qphon(3)=wavevector of the phonon
2393 : : !! symq(4,2,nsym)=1 if symmetry preserves present qpoint. From littlegroup_q
2394 : : !! symrec(3,3,nsym)=symmetries of group in terms of operations on real
2395 : : !! space primitive translations (integers).
2396 : : !!
2397 : : !! OUTPUT
2398 : : !! sdyfro(3,3,natom,1+(natom-1)*nondiag)=symmetrized dynamical matrix
2399 : : !!
2400 : : !! NOTES
2401 : : !! Symmetrization of gradients with respect to reduced
2402 : : !! coordinates tn is conducted according to the expression
2403 : : !! $[d(e)/d(t(n,a))]_{symmetrized} = (1/Nsym)*Sum(S)*symrec(n,m,S)*
2404 : : !! [d(e)/d(t(m,b))]_{unsymmetrized}$
2405 : : !! where $t(m,b)= (symrel^{-1})(m,n)*(t(n,a)-tnons(n))$ and tnons
2406 : : !! is a possible nonsymmorphic translation. The label "b" here
2407 : : !! refers to the atom which gets rotated into "a" under symmetry "S".
2408 : : !! symrel is the symmetry matrix in real space, which is the inverse
2409 : : !! transpose of symrec. symrec is the symmetry matrix in reciprocal
2410 : : !! space. $sym_{cartesian} = R * symrel * R^{-1} = G * symrec * G^{-1}$
2411 : : !! where the columns of R and G are the dimensional primitive translations
2412 : : !! in real and reciprocal space respectively.
2413 : : !! Note the use of "symrec" in the symmetrization expression above.
2414 : : !!
2415 : : !! SOURCE
2416 : :
2417 : 1350 : subroutine dfpt_sydy(cplex,dyfrow,indsym,natom,nondiag,nsym,qphon,sdyfro,symq,symrec)
2418 : :
2419 : : !Arguments -------------------------------
2420 : : !scalars
2421 : : integer,intent(in) :: cplex,natom,nondiag,nsym
2422 : : !arrays
2423 : : integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym),symrec(3,3,nsym)
2424 : : real(dp),intent(in) :: dyfrow(cplex,3,3,natom,1+(natom-1)*nondiag),qphon(3)
2425 : : real(dp),intent(out) :: sdyfro(cplex,3,3,natom,1+(natom-1)*nondiag)
2426 : :
2427 : : !Local variables -------------------------
2428 : : !scalars
2429 : : integer :: ia,indi,indj,isym,ja,kappa,mu,natom_nondiag,nsym_used,nu
2430 : : logical :: qeq0
2431 : : real(dp) :: arg,div,phasei,phaser
2432 : : !arrays
2433 : 2700 : real(dp) :: work(cplex,3,3)
2434 : : ! *********************************************************************
2435 : :
2436 [ + + ]: 1350 : if (nsym==1) then
2437 : :
2438 : : ! Only symmetry is identity so simply copy
2439 [ + + + + : 17883 : sdyfro(:,:,:,:,:)=dyfrow(:,:,:,:,:)
+ + + + +
+ ]
2440 : :
2441 : : else
2442 : :
2443 : : ! Actually carry out symmetrization
2444 [ + + + + : 57491 : sdyfro(:,:,:,:,:)=zero
+ + + + +
+ ]
2445 : 999 : qeq0=(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)
2446 : : ! === Diagonal dyn. matrix OR q=0
2447 [ + + + + ]: 999 : if (nondiag==0.or.qeq0) then
2448 [ + + ]: 985 : natom_nondiag=1;if (nondiag==1) natom_nondiag=natom
2449 [ + + ]: 2045 : do ja=1,natom_nondiag
2450 [ + + ]: 4493 : do ia=1,natom
2451 [ + + ]: 59594 : do isym=1,nsym
2452 : 56086 : indi=indsym(4,isym,ia)
2453 [ + + ]: 56086 : indj=1;if (nondiag==1) indj=indsym(4,isym,ja)
2454 [ + + + + : 1233892 : work(:,:,:)=zero
+ + ]
2455 [ + + ]: 224344 : do mu=1,3
2456 [ + + ]: 729118 : do nu=1,3
2457 [ + + ]: 2187354 : do kappa=1,3
2458 [ + + ]: 3533418 : work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
2459 : : end do
2460 : : end do
2461 : : end do
2462 [ + + ]: 226792 : do mu=1,3
2463 [ + + ]: 729118 : do nu=1,3
2464 [ + + ]: 2187354 : do kappa=1,3
2465 [ + + ]: 3533418 : sdyfro(:,kappa,mu,ia,ja)=sdyfro(:,kappa,mu,ia,ja)+symrec(mu,nu,isym)*work(:,kappa,nu)
2466 : : end do
2467 : : end do
2468 : : end do
2469 : : end do
2470 : : end do
2471 : : end do
2472 : 985 : div=one/dble(nsym)
2473 [ + + + + : 55901 : sdyfro(:,:,:,:,:)=div*sdyfro(:,:,:,:,:)
+ + + + +
+ ]
2474 : : ! === Non diagonal dyn. matrix AND q<>0
2475 : : else
2476 [ + + ]: 40 : do ja=1,natom
2477 [ + + ]: 90 : do ia=1,natom
2478 : : nsym_used=0
2479 [ + + ]: 1298 : do isym=1,nsym
2480 [ + + ]: 1298 : if (symq(4,1,isym)==1) then
2481 : : arg=two_pi*(qphon(1)*(indsym(1,isym,ia)-indsym(1,isym,ja)) &
2482 : : & +qphon(2)*(indsym(2,isym,ia)-indsym(2,isym,ja)) &
2483 : 256 : & +qphon(3)*(indsym(3,isym,ia)-indsym(3,isym,ja)))
2484 : 256 : phaser=cos(arg);phasei=sin(arg)
2485 : 256 : nsym_used=nsym_used+1
2486 : 256 : indi=indsym(4,isym,ia)
2487 : 256 : indj=indsym(4,isym,ja)
2488 [ + + + + : 7936 : work(:,:,:)=zero
+ + ]
2489 [ + + ]: 1024 : do mu=1,3
2490 [ + + ]: 3328 : do nu=1,3
2491 [ + + ]: 9984 : do kappa=1,3
2492 [ + + ]: 23040 : work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
2493 : : end do
2494 : : end do
2495 : : end do
2496 [ + + ]: 1024 : do mu=1,3
2497 [ + + ]: 3328 : do nu=1,3
2498 [ + + ]: 9984 : do kappa=1,3
2499 : : sdyfro(1,kappa,mu,ia,ja)=sdyfro(1,kappa,mu,ia,ja) &
2500 : 9216 : & +symrec(mu,nu,isym)*(work(1,kappa,nu)*phaser-work(2,kappa,nu)*phasei)
2501 : : end do
2502 : : end do
2503 : : end do
2504 [ + - ]: 256 : if (cplex==2) then
2505 [ + + ]: 1024 : do mu=1,3
2506 [ + + ]: 3328 : do nu=1,3
2507 [ + + ]: 9984 : do kappa=1,3
2508 : : sdyfro(2,kappa,mu,ia,ja)=sdyfro(2,kappa,mu,ia,ja) &
2509 : 9216 : & +symrec(mu,nu,isym)*(work(1,kappa,nu)*phasei+work(2,kappa,nu)*phaser)
2510 : : end do
2511 : : end do
2512 : : end do
2513 : : end if
2514 : : end if
2515 : : end do
2516 : 50 : div=one/dble(nsym_used)
2517 [ + + + + : 1576 : sdyfro(:,:,:,ia,ja)=div*sdyfro(:,:,:,ia,ja)
+ + ]
2518 : : end do
2519 : : end do
2520 : : end if
2521 : :
2522 : : end if
2523 : :
2524 : 1350 : end subroutine dfpt_sydy
2525 : : !!***
2526 : :
2527 : : ! CODE TO BE EVENTUALLY REUSED
2528 : : ! Sym preserves direction and atom
2529 : : ! if (symq(1,1,isym)==0.and.symq(2,1,isym)==0.and.symq(3,1,isym)==0.and.symq(4,1,isym)==1)then
2530 : : ! if (ipert==indsym(4,isym,ipert)) then
2531 : : ! tok=1
2532 : : ! do idir1=1,3
2533 : : ! if ((idir1==idir.and.symrec(idir,idir1,isym)/=1).or.&
2534 : : ! & (idir1/=idir.and.symrec(idir,idir1,isym)/=0)) tok=0
2535 : : ! end do
2536 : : ! end if
2537 : : ! end if
2538 : : ! div=one/dble(count(symq(4,1,:)==1))
2539 : :
2540 : : !----------------------------------------------------------------------
2541 : :
2542 : : !!****f* m_dynmat/wings3
2543 : : !! NAME
2544 : : !! wings3
2545 : : !!
2546 : : !! FUNCTION
2547 : : !! Suppress the wings of the cartesian 2DTE for which
2548 : : !! the diagonal element is not known
2549 : : !!
2550 : : !! INPUTS
2551 : : !! carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
2552 : : !! 2DTE matrix has been calculated correctly ; 0 otherwise )
2553 : : !! d2cart(2,3,mpert,3,mpert)=
2554 : : !! dynamical matrix, effective charges, dielectric tensor,....
2555 : : !! all in cartesian coordinates
2556 : : !! mpert =maximum number of ipert
2557 : : !!
2558 : : !! OUTPUT
2559 : : !! d2cart(2,3,mpert,3,mpert) without the wings
2560 : : !!
2561 : : !! SOURCE
2562 : :
2563 : 382 : subroutine wings3(carflg,d2cart,mpert)
2564 : :
2565 : : !Arguments -------------------------------
2566 : : !scalars
2567 : : integer,intent(in) :: mpert
2568 : : !arrays
2569 : : integer,intent(inout) :: carflg(3,mpert,3,mpert)
2570 : : real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
2571 : :
2572 : : !Local variables -------------------------
2573 : : !scalars
2574 : : integer :: idir,idir1,ipert,ipert1
2575 : : ! *********************************************************************
2576 : :
2577 [ + + ]: 3849 : do ipert=1,mpert
2578 [ + + ]: 14250 : do idir=1,3
2579 [ + + ]: 13868 : if(carflg(idir,ipert,idir,ipert)==0)then
2580 [ + + ]: 85788 : do ipert1=1,mpert
2581 [ + + ]: 318444 : do idir1=1,3
2582 : 232656 : carflg(idir,ipert,idir1,ipert1)=0
2583 : 232656 : carflg(idir1,ipert1,idir,ipert)=0
2584 : 232656 : d2cart(1,idir,ipert,idir1,ipert1)=zero
2585 : 232656 : d2cart(2,idir,ipert,idir1,ipert1)=zero
2586 : 232656 : d2cart(1,idir1,ipert1,idir,ipert)=zero
2587 : 310208 : d2cart(2,idir1,ipert1,idir,ipert)=zero
2588 : : end do
2589 : : end do
2590 : : end if
2591 : : end do
2592 : : end do
2593 : :
2594 : 382 : end subroutine wings3
2595 : : !!***
2596 : :
2597 : : !----------------------------------------------------------------------
2598 : :
2599 : : !!****f* m_dynmat/asrif9
2600 : : !!
2601 : : !! NAME
2602 : : !! asrif9
2603 : : !!
2604 : : !! FUNCTION
2605 : : !! Imposes the Acoustic Sum Rule to Interatomic Forces
2606 : : !!
2607 : : !! INPUTS
2608 : : !! asr= Option for the imposition of the ASR
2609 : : !! 0 => no ASR,
2610 : : !! 1 => modify "asymmetrically" the diagonal element
2611 : : !! 2 => modify "symmetrically" the diagonal element
2612 : : !! natom= Number of atoms in the unit cell
2613 : : !! nrpt= Number of R points in the Big Box
2614 : : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
2615 : : !! These coordinates are normalized (=> * acell(3)!!)
2616 : : !! wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
2617 : : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces
2618 : : !!
2619 : : !! OUTPUT
2620 : : !! atmfrc(3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces
2621 : : !!
2622 : : !! TODO
2623 : : !! List of ouput should be included.
2624 : : !!
2625 : : !! SOURCE
2626 : :
2627 : 269 : subroutine asrif9(asr,atmfrc,natom,nrpt,rpt,wghatm)
2628 : :
2629 : : !Arguments -------------------------------
2630 : : !scalars
2631 : : integer,intent(in) :: asr,natom,nrpt
2632 : : !arrays
2633 : : real(dp),intent(in) :: rpt(3,nrpt),wghatm(natom,natom,nrpt)
2634 : : real(dp),intent(inout) :: atmfrc(3,natom,3,natom,nrpt)
2635 : :
2636 : : !Local variables -------------------------
2637 : : !scalars
2638 : : integer :: found,ia,ib,irpt,izero,mu,nu
2639 : : real(dp) :: sumifc
2640 : : ! *********************************************************************
2641 : :
2642 [ + + ]: 269 : if(asr==1.or.asr==2)then
2643 : : found=0
2644 : : ! Search for the R vector which is equal to ( 0 , 0 , 0 )
2645 : : ! This vector leaves the atom a on itself !
2646 [ + - ]: 19687 : do irpt=1,nrpt
2647 [ + + + + : 23318 : if (all(abs(rpt(:,irpt))<=1.0d-10)) then
+ + ]
2648 : : found=1
2649 : : izero=irpt
2650 : : end if
2651 : 0 : if (found==1) exit
2652 : : end do
2653 : :
2654 [ - + ]: 268 : if(found==0)then
2655 : 0 : ABI_BUG('Not able to find the vector R=(0,0,0).')
2656 : : end if
2657 : :
2658 [ + + ]: 1072 : do mu=1,3
2659 [ + + ]: 3484 : do nu=1,3
2660 [ + + ]: 9867 : do ia=1,natom
2661 : : sumifc=zero
2662 [ + + ]: 36054 : do ib=1,natom
2663 : :
2664 : : ! Get the sumifc of interatomic forces acting on the atom ia,
2665 : : ! either in a symmetrical manner, or an unsymmetrical one.
2666 [ + + ]: 36054 : if(asr==1)then
2667 [ + + ]: 1831293 : do irpt=1,nrpt
2668 : 1831293 : sumifc=sumifc+wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)
2669 : : end do
2670 : : else if(asr==2)then
2671 [ + + ]: 6377454 : do irpt=1,nrpt
2672 : : sumifc=sumifc+&
2673 : : (wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)+&
2674 : 6377454 : wghatm(ia,ib,irpt)*atmfrc(nu,ia,mu,ib,irpt))/2
2675 : : end do
2676 : : end if
2677 : : end do
2678 : :
2679 : : ! Correct the self-interaction in order to fulfill the ASR
2680 : 6651 : atmfrc(mu,ia,nu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)-sumifc
2681 [ + + ]: 9063 : if (asr==2) atmfrc(nu,ia,mu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)
2682 : : end do
2683 : : end do
2684 : : end do
2685 : : end if
2686 : :
2687 : 269 : end subroutine asrif9
2688 : : !!***
2689 : :
2690 : : !----------------------------------------------------------------------
2691 : :
2692 : : !!****f* m_dynmat/get_bigbox_and_weights
2693 : : !! NAME
2694 : : !! get_bigbox_and_weights
2695 : : !!
2696 : : !! NOTE
2697 : : !! Not called anymore: m_dvdb.F90's prepare_ftinterp, this routine's only caller, now
2698 : : !! builds its own ifc_supercell_type instance directly (SC%init, SC%calc_ws_wghatm),
2699 : : !! the same construction below, rather than going through this wrapper -- see there for
2700 : : !! why (avoids folding xred_unit back and forth between reduced and cartesian coordinates
2701 : : !! across a subroutine boundary, and the unused Rsh_cart/r_inscribed_sphere outputs).
2702 : : !! Kept here, unused, for reference, and for any future caller that wants the same
2703 : : !! Wigner-Seitz box together with the cutmode filtering below in one call.
2704 : : !!
2705 : : !! FUNCTION
2706 : : !! Compute the Big Box containing the R points in the cartesian real space needed to Fourier Transform
2707 : : !! the dynamical matrix into its corresponding interatomic force.
2708 : : !!
2709 : : !! Brav/acell-independent: the R-points and their weights are obtained from
2710 : : !! ifc_supercell_type%calc_ws_wghatm (m_ifc_supercell.F90) -- the same Wigner-Seitz
2711 : : !! construction ifc_init uses -- instead of the historical brav-specific
2712 : : !! make_bigbox/wght9 pair, which needed a diagonal, cubic-equal ngqpt and the
2713 : : !! dimensionless rprim/gprim convention (see canat9's docstring for the bug that
2714 : : !! convention caused at this routine's former caller, m_dvdb.F90).
2715 : : !!
2716 : : !! INPUTS
2717 : : !! crystal<crystal_t>= Crystal structure of the unit cell (rprimd, xred, ...).
2718 : : !! qptrlatt(3,3)= Integer matrix of the q-point lattice (as kptrlatt for k-points):
2719 : : !! columns are the primitive vectors of the lattice reciprocal to the q-mesh.
2720 : : !! Diagonal(ngqpt) for a simple, single-shift Monkhorst-Pack mesh. Use
2721 : : !! m_kpts/qmesh_from_brav_ngqpt to build it from the historical (brav, ngqpt) input,
2722 : : !! and, if the q-mesh has several shifts, m_kpts/kptrlatt_merge_shifts beforehand to
2723 : : !! merge them into this single, finer qptrlatt (not done here: m_dynmat/44_abitools
2724 : : !! cannot depend on m_kpts/56_recipspace; the caller must already live in, or above,
2725 : : !! 56_recipspace to reach kptrlatt_merge_shifts -- m_dvdb.F90/72_response does).
2726 : : !! xred_unit(3,natom)= Reduced atomic coordinates folded into ]-1/2,1/2] (see canat9).
2727 : : !! cutmode=Define the cutoff used to filter the output R-points according to their weights.
2728 : : !! 0 --> No cutoff (mainly for debugging)
2729 : : !! 1 --> Include only those R-points for which sum(abs(wg(:,:,irpt)) < tol20
2730 : : !! This is the approach used for the dynamical matrix.
2731 : : !! 2 --> Include only those R-points for which the trace over iatom of abs(wg(iat,iat,irpt)) < tol20
2732 : : !! This option is used for objects that depend on a single atomic index.
2733 : : !! comm= MPI communicator (unused now that the retry-on-tolerance loop wght9 needed is gone;
2734 : : !! kept in the API for backward compatibility with the caller).
2735 : : !!
2736 : : !! OUTPUT
2737 : : !! nrpt= Total Number of R points in the Big Box
2738 : : !! R_red(3,nrpt) Give the index of the the R point and irpt
2739 : : !! R_cart(3,nrpt)= Cartesian (bohr) coordinates of the R points.
2740 : : !! r_inscribed_sphere
2741 : : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
2742 : : !!
2743 : : !! SOURCE
2744 : :
2745 : 0 : subroutine get_bigbox_and_weights(crystal, qptrlatt, xred_unit, &
2746 : : cutmode, nrpt, R_cart, R_red, wghatm, r_inscribed_sphere, comm)
2747 : :
2748 : : !Arguments -------------------------------
2749 : : !scalars
2750 : : integer,intent(in) :: cutmode, comm
2751 : : integer,intent(out) :: nrpt
2752 : : real(dp),intent(out) :: r_inscribed_sphere
2753 : : type(crystal_t),intent(in) :: crystal
2754 : : !arrays
2755 : : integer,intent(in) :: qptrlatt(3,3)
2756 : : real(dp),intent(in) :: xred_unit(3, crystal%natom)
2757 : : integer,allocatable,intent(out) :: R_red(:,:)
2758 : : real(dp),allocatable,intent(out) :: R_cart(:,:), wghatm(:,:,:)
2759 : :
2760 : : !Local variables -------------------------
2761 : : !scalars
2762 : : integer :: ii, irpt, all_nrpt
2763 : 0 : type(ifc_supercell_type) :: SC
2764 : : !arrays
2765 : : real(dp) :: sc_matrix(3,3)
2766 : 0 : integer,allocatable :: all_R_red(:,:)
2767 : 0 : real(dp),allocatable :: all_wghatm(:,:,:)
2768 : : ! *********************************************************************
2769 : :
2770 : : ABI_UNUSED(comm)
2771 [ # # ]: 0 : ABI_CHECK(any(cutmode == [0, 1, 2]), "cutmode should be in [0, 1, 2]")
2772 : : ABI_UNUSED(xred_unit)
2773 : :
2774 : : ! Supercell (Born-von Karman box) dual to the q-mesh. If the q-mesh has several shifts, the
2775 : : ! caller must merge them beforehand into this single, finer qptrlatt (m_kpts/kptrlatt_merge_shifts
2776 : : ! -- not called from here, since m_dynmat/44_abitools cannot depend on m_kpts/56_recipspace).
2777 : : ! Rows of the supercell matrix are the supercell vectors, columns of kptrlatt.
2778 : : ! SC%init computes its own cartesian xcart_unit from crystal%xred (identical, by construction,
2779 : : ! to the caller's xred_unit folded and transformed by rprimd), so the argument is no longer needed.
2780 [ # # # # ]: 0 : sc_matrix = real(transpose(qptrlatt), kind=dp)
2781 : 0 : call SC%init(crystal, sc_matrix)
2782 : :
2783 : : ! Explicit list of R vectors in the Wigner-Seitz cell of the supercell for each atom pair,
2784 : : ! with 1/N weights for N tied images (see the docstring of calc_ws_wghatm).
2785 : 0 : call SC%calc_ws_wghatm(tol8, all_nrpt, all_R_red, all_wghatm)
2786 : 0 : r_inscribed_sphere = SC%shortest_vector_norm()
2787 : 0 : call SC%free()
2788 : :
2789 : : ! Only conserve the necessary points.
2790 : 0 : nrpt = 0
2791 [ # # ]: 0 : do irpt=1,all_nrpt
2792 [ # # ]: 0 : if (filterw(all_wghatm(:,:,irpt))) cycle
2793 : 0 : nrpt = nrpt + 1
2794 : : end do
2795 : :
2796 : : ! Allocate output arrays and transfer data.
2797 [ # # # # : 0 : ABI_MALLOC(R_cart, (3, nrpt))
# # # # #
# # # #
# ]
2798 [ # # # # : 0 : ABI_MALLOC(R_red, (3, nrpt))
# # # # #
# # # #
# ]
2799 [ # # # # : 0 : ABI_MALLOC(wghatm, (crystal%natom, crystal%natom, nrpt))
# # # # #
# # # # #
# # # # #
# # # ]
2800 : :
2801 : 0 : ii = 0
2802 [ # # ]: 0 : do irpt=1,all_nrpt
2803 [ # # ]: 0 : if (filterw(all_wghatm(:,:,irpt))) cycle
2804 : 0 : ii = ii + 1
2805 [ # # # # : 0 : R_cart(:, ii) = matmul(crystal%rprimd, real(all_R_red(:,irpt), kind=dp))
# # # # #
# ]
2806 [ # # # # ]: 0 : wghatm(:,:,ii) = all_wghatm(:,:,irpt)
2807 [ # # ]: 0 : R_red(:,ii) = all_R_red(:,irpt)
2808 : : end do
2809 : :
2810 [ # # ]: 0 : ABI_FREE(all_wghatm)
2811 [ # # # # : 0 : ABI_FREE(all_R_red)
# # # # #
# # # # #
# # ]
2812 : :
2813 : : contains
2814 : :
2815 : 0 : logical pure function filterw(wg)
2816 : :
2817 : : real(dp),intent(in) :: wg(crystal%natom,crystal%natom)
2818 : : integer :: iat
2819 : : real(dp) :: trace
2820 : :
2821 : 0 : select case (cutmode)
2822 : : case (1)
2823 [ # # # # ]: 0 : filterw = sum(abs(wg)) < tol20
2824 : : case (2)
2825 : : trace = zero
2826 [ # # ]: 0 : do iat=1,crystal%natom
2827 : 0 : trace = trace + abs(wg(iat,iat))
2828 : : end do
2829 : 0 : filterw = trace < tol20
2830 : : case default
2831 [ # # # ]: 0 : filterw = .False.
2832 : : end select
2833 : :
2834 : 0 : end function filterw
2835 : :
2836 : : end subroutine get_bigbox_and_weights
2837 : : !!***
2838 : :
2839 : : !----------------------------------------------------------------------
2840 : :
2841 : : !!****f* m_dynmat/make_bigbox
2842 : : !! NAME
2843 : : !! make_bigbox
2844 : : !!
2845 : : !! FUNCTION
2846 : : !! Helper functions to faciliate the generation of a Big Box containing
2847 : : !! all the R points in the cartesian real space needed to Fourier Transform
2848 : : !! the dynamical matrix into its corresponding interatomic force.
2849 : : !! See bigbx9 for the algorithm.
2850 : : !!
2851 : : !! INPUTS
2852 : : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
2853 : : !! ngqpt(3)= Numbers used to generate the q points to sample the
2854 : : !! Brillouin zone using an homogeneous grid
2855 : : !! nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
2856 : : !! When nqshft is not 1, but 2 or 4 (only other allowed values),
2857 : : !! the limits for the big box have to be extended by a factor of 2.
2858 : : !! rprim(3,3)= Normalized coordinates in real space !!! IS THIS CORRECT?
2859 : : !!
2860 : : !! OUTPUT
2861 : : !! cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
2862 : : !! nprt= Number of cells (R points) in the Big Box
2863 : : !! rpt(3,mrpt)= canonical coordinates of the cells (R points)
2864 : : !! These coordinates are normalized (=> * acell(3)!!)
2865 : : !! The array is allocated here with the proper dimension. Client code is responsible
2866 : : !! for the deallocation.
2867 : : !!
2868 : : !! SOURCE
2869 : :
2870 : 0 : subroutine make_bigbox(brav, cell, ngqpt, nqshft, rprim, nrpt, rpt)
2871 : :
2872 : : !Arguments -------------------------------
2873 : : !scalars
2874 : : integer,intent(in) :: brav,nqshft
2875 : : integer,intent(out) :: nrpt
2876 : : !arrays
2877 : : integer,intent(in) :: ngqpt(3)
2878 : : real(dp),intent(in) :: rprim(3,3)
2879 : : real(dp),allocatable,intent(out) :: rpt(:,:)
2880 : : integer,allocatable,intent(out) :: cell(:,:)
2881 : :
2882 : : !Local variables -------------------------
2883 : : !scalars
2884 : : integer :: choice,mrpt
2885 : : !arrays
2886 : : real(dp) :: dummy_rpt(3,1)
2887 : : integer:: dummy_cell(1,3)
2888 : : ! *********************************************************************
2889 : :
2890 : : ! Compute the number of points (cells) in real space
2891 : 0 : choice=0
2892 : 0 : call bigbx9(brav,dummy_cell,choice,1,ngqpt,nqshft,mrpt,rprim,dummy_rpt)
2893 : :
2894 : : ! Now we can allocate and calculate the points and the weights.
2895 : 0 : nrpt = mrpt
2896 [ # # # # : 0 : ABI_MALLOC(rpt,(3,nrpt))
# # # # #
# # # #
# ]
2897 [ # # # # : 0 : ABI_MALLOC(cell,(3,nrpt))
# # # # #
# # # #
# ]
2898 : :
2899 : 0 : choice=1
2900 : 0 : call bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
2901 : :
2902 : 0 : end subroutine make_bigbox
2903 : : !!***
2904 : :
2905 : : !----------------------------------------------------------------------
2906 : :
2907 : : !!****f* m_dynmat/bigbx9
2908 : : !! NAME
2909 : : !! bigbx9
2910 : : !!
2911 : : !! FUNCTION
2912 : : !! Generation of a Big Box containing all the R points (cells) in the
2913 : : !! cartesian real space needed to Fourier Transforms the dynamical
2914 : : !! matrix into its corresponding interatomic force.
2915 : : !!
2916 : : !! INPUTS
2917 : : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
2918 : : !! choice= if 0, simply count nrpt ; if 1, checks that the input mrpt
2919 : : !! is the same as nrpt, and generate rpt(3,mrpt)
2920 : : !! mrpt=dimension of rpt
2921 : : !! ngqpt(3)= Numbers used to generate the q points to sample the
2922 : : !! Brillouin zone using an homogeneous grid
2923 : : !! nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
2924 : : !! When nqshft is not 1, but 2 or 4 (only other allowed values),
2925 : : !! the limits for the big box have to be extended by a factor of 2.
2926 : : !! rprim(3,3)= Normalized coordinates in real space !!! IS THIS CORRECT?
2927 : : !!
2928 : : !! OUTPUT
2929 : : !! cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
2930 : : !! nprt= Number of cells (R points) in the Big Box
2931 : : !! rpt(3,mrpt)= canonical coordinates of the cells (R points)
2932 : : !! These coordinates are normalized (=> * acell(3)!!)
2933 : : !! (output only if choice=1)
2934 : : !!
2935 : : !! SOURCE
2936 : :
2937 : 0 : subroutine bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
2938 : :
2939 : : !Arguments -------------------------------
2940 : : !scalars
2941 : : integer,intent(in) :: brav,choice,mrpt,nqshft
2942 : : integer,intent(out) :: nrpt
2943 : : !arrays
2944 : : integer,intent(in) :: ngqpt(3)
2945 : : real(dp),intent(in) :: rprim(3,3)
2946 : : real(dp),intent(out) :: rpt(3,mrpt)
2947 : : integer,intent(out) :: cell(3,mrpt)
2948 : :
2949 : : !Local variables -------------------------
2950 : : !In some cases, the atoms coordinates are not packed in the
2951 : : ! [0,1]^3 cube. Then, the parameter "buffer" might be increased,
2952 : : !to search relevant pairs of atoms in bigger boxes than usual.
2953 : : !scalars
2954 : : integer,parameter :: buffer=1
2955 : : integer :: irpt,lim1,lim2,lim3,lqshft,r1,r2,r3
2956 : : character(len=500) :: msg
2957 : : ! *********************************************************************
2958 : :
2959 : 0 : lqshft=1
2960 [ # # ]: 0 : if(nqshft/=1)lqshft=2
2961 : :
2962 : :
2963 : : !Simple Cubic Lattice
2964 [ # # ]: 0 : if (abs(brav)==1) then
2965 : 0 : lim1=((ngqpt(1))+1)*lqshft+buffer
2966 : 0 : lim2=((ngqpt(2))+1)*lqshft+buffer
2967 : 0 : lim3=((ngqpt(3))+1)*lqshft+buffer
2968 : 0 : nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
2969 [ # # ]: 0 : if(choice/=0)then
2970 [ # # ]: 0 : if (nrpt/=mrpt) then
2971 : 0 : write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
2972 : 0 : ABI_BUG(msg)
2973 : : end if
2974 : 0 : irpt=0
2975 [ # # ]: 0 : do r1=-lim1,lim1
2976 [ # # ]: 0 : do r2=-lim2,lim2
2977 [ # # ]: 0 : do r3=-lim3,lim3
2978 : 0 : irpt=irpt+1
2979 : 0 : rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
2980 : 0 : rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
2981 : 0 : rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
2982 : 0 : cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
2983 : : end do
2984 : : end do
2985 : : end do
2986 : : end if
2987 : :
2988 : : ! Face Centered Cubic Lattice
2989 [ # # ]: 0 : else if (brav==2) then
2990 : 0 : lim1=((ngqpt(1)+3)/4)*lqshft+buffer
2991 : 0 : lim2=((ngqpt(2)+3)/4)*lqshft+buffer
2992 : 0 : lim3=((ngqpt(3)+3)/4)*lqshft+buffer
2993 : 0 : nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*4
2994 [ # # ]: 0 : if(choice/=0)then
2995 [ # # ]: 0 : if (nrpt/=mrpt) then
2996 : 0 : write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
2997 : 0 : ABI_BUG(msg)
2998 : : end if
2999 : 0 : irpt=0
3000 [ # # ]: 0 : do r1=-lim1,lim1
3001 [ # # ]: 0 : do r2=-lim2,lim2
3002 [ # # ]: 0 : do r3=-lim3,lim3
3003 : 0 : irpt=irpt+4
3004 : 0 : rpt(1,irpt-3)=r1
3005 : 0 : rpt(2,irpt-3)=r2
3006 : 0 : rpt(3,irpt-3)=r3
3007 : 0 : rpt(1,irpt-2)=r1
3008 : 0 : rpt(2,irpt-2)=r2+0.5
3009 : 0 : rpt(3,irpt-2)=r3+0.5
3010 : 0 : rpt(1,irpt-1)=r1+0.5
3011 : 0 : rpt(2,irpt-1)=r2
3012 : 0 : rpt(3,irpt-1)=r3+0.5
3013 : 0 : rpt(1,irpt)=r1+0.5
3014 : 0 : rpt(2,irpt)=r2+0.5
3015 : 0 : rpt(3,irpt)=r3
3016 : : !TEST_AM
3017 : : ! cell(irpt-3,1)=r1;cell(irpt-3,2)=r2;cell(irpt-3,3)=r3
3018 : 0 : cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
3019 : : end do
3020 : : end do
3021 : : end do
3022 : : end if
3023 : :
3024 : : ! Body Centered Cubic Lattice
3025 [ # # ]: 0 : else if (brav==3) then
3026 : 0 : lim1=((ngqpt(1)+3)/4)*lqshft+buffer
3027 : 0 : lim2=((ngqpt(2)+3)/4)*lqshft+buffer
3028 : 0 : lim3=((ngqpt(3)+3)/4)*lqshft+buffer
3029 : 0 : nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*2
3030 [ # # ]: 0 : if(choice/=0)then
3031 [ # # ]: 0 : if(nrpt/=mrpt) then
3032 : 0 : write(msg,'(2(a,i0))')' nrpt= ',nrpt,' is not equal to mrpt= ',mrpt
3033 : 0 : ABI_BUG(msg)
3034 : : end if
3035 : 0 : irpt=0
3036 [ # # ]: 0 : do r1=-lim1,lim1
3037 [ # # ]: 0 : do r2=-lim2,lim2
3038 [ # # ]: 0 : do r3=-lim3,lim3
3039 : 0 : irpt=irpt+2
3040 : 0 : rpt(1,irpt-1)=r1
3041 : 0 : rpt(2,irpt-1)=r2
3042 : 0 : rpt(3,irpt-1)=r3
3043 : 0 : rpt(1,irpt)=r1+0.5
3044 : 0 : rpt(2,irpt)=r2+0.5
3045 : 0 : rpt(3,irpt)=r3+0.5
3046 : : !TEST_AM
3047 : : ! cell(irpt-1,1)=r1;cell(irpt-1,2)=r2;cell(irpt-1,3)=r3
3048 : 0 : cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
3049 : : end do
3050 : : end do
3051 : : end do
3052 : : end if
3053 : :
3054 : : ! Hexagonal Lattice
3055 [ # # ]: 0 : else if (brav==4) then
3056 : 0 : lim1=(ngqpt(1)+1)*lqshft+buffer
3057 : 0 : lim2=(ngqpt(2)+1)*lqshft+buffer
3058 : 0 : lim3=((ngqpt(3)/2)+1)*lqshft+buffer
3059 : 0 : nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
3060 [ # # ]: 0 : if(choice/=0)then
3061 [ # # ]: 0 : if(nrpt/=mrpt)then
3062 : 0 : write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt=',mrpt
3063 : 0 : ABI_BUG(msg)
3064 : : end if
3065 : 0 : irpt=0
3066 [ # # ]: 0 : do r1=-lim1,lim1
3067 [ # # ]: 0 : do r2=-lim2,lim2
3068 [ # # ]: 0 : do r3=-lim3,lim3
3069 : 0 : irpt=irpt+1
3070 : 0 : rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
3071 : 0 : rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
3072 : 0 : rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
3073 : 0 : cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
3074 : : end do
3075 : : end do
3076 : : end do
3077 : : end if
3078 : :
3079 : : else
3080 : 0 : write(msg,'(a,i0,a)')' The value of brav= ',brav,' is not allowed (should be -1, 1, 2 or 4).'
3081 : 0 : ABI_BUG(msg)
3082 : : end if
3083 : :
3084 : 0 : end subroutine bigbx9
3085 : : !!***
3086 : :
3087 : : !----------------------------------------------------------------------
3088 : :
3089 : : !!****f* m_dynmat/canat9
3090 : : !! NAME
3091 : : !! canat9
3092 : : !!
3093 : : !! NOTE
3094 : : !! Not called anymore: m_dvdb.F90's prepare_ftinterp, this routine's former only caller,
3095 : : !! now inlines the two-line fold (wrap2_pmhalf + matmul(rprimd,...)) itself before building
3096 : : !! its own ifc_supercell_type instance, since the Rsh_cart output was unused there. Kept
3097 : : !! here, unused, for reference.
3098 : : !!
3099 : : !! FUNCTION
3100 : : !! Folds the reduced atomic coordinates into the unit cell ]-1/2,1/2], and
3101 : : !! returns the corresponding cartesian shift vector.
3102 : : !!
3103 : : !! Brav/acell-independent: unlike the historical implementation (still
3104 : : !! visible in the git history), the folding is a single generic
3105 : : !! component-wise wrap, valid for any Bravais lattice -- it does not need
3106 : : !! to know brav, and needs rprimd (dimensional, bohr) rather than the
3107 : : !! dimensionless rprim (which silently assumed the caller would later
3108 : : !! rescale by acell; see the docstring of get_bigbox_and_weights, which
3109 : : !! consumes xred_unit, for the bug this caused when acell(1:3) were not
3110 : : !! all equal or rprim was not diagonal).
3111 : : !!
3112 : : !! INPUTS
3113 : : !! natom= Number of atoms in the unit cell
3114 : : !! rprimd(3,3)= Dimensional primitive vectors (bohr)
3115 : : !! xred(3,natom)= Reduced atomic coordinates
3116 : : !!
3117 : : !! OUTPUT
3118 : : !! xred_unit(3,natom) = xred folded into ]-1/2,1/2] (reduced coordinates)
3119 : : !! Rsh_cart(3,natom) = Cartesian lattice vector such that
3120 : : !! xred(:,iatom) = xred_unit(:,iatom) + (reduced coordinates of Rsh_cart(:,iatom))
3121 : : !! i.e. matmul(rprimd, xred(:,iatom)) = matmul(rprimd, xred_unit(:,iatom)) + Rsh_cart(:,iatom)
3122 : : !!
3123 : : !! SOURCE
3124 : :
3125 : 0 : subroutine canat9(natom, rprimd, xred, xred_unit, Rsh_cart)
3126 : :
3127 : : !Arguments -------------------------------
3128 : : !scalars
3129 : : integer,intent(in) :: natom
3130 : : !arrays
3131 : : real(dp),intent(in) :: rprimd(3,3),xred(3,natom)
3132 : : real(dp),intent(out) :: xred_unit(3,natom),Rsh_cart(3,natom)
3133 : :
3134 : : !Local variables -------------------------
3135 : : !scalars
3136 : : integer :: iatom
3137 : : !arrays
3138 : 0 : real(dp) :: shift_red(3,natom)
3139 : : ! *********************************************************************
3140 : :
3141 : : ! Fold each reduced coordinate into ]-1/2,1/2]; shift_red is the (integer,
3142 : : ! in reduced units) lattice translation that was subtracted off.
3143 [ # # # # ]: 0 : call wrap2_pmhalf(xred, xred_unit, shift_red)
3144 : :
3145 [ # # ]: 0 : do iatom=1,natom
3146 [ # # # # : 0 : Rsh_cart(:,iatom) = matmul(rprimd, shift_red(:,iatom))
# # ]
3147 : : end do
3148 : :
3149 : 0 : end subroutine canat9
3150 : : !!***
3151 : :
3152 : : !----------------------------------------------------------------------
3153 : :
3154 : : !!****f* m_dynmat/canct9
3155 : : !!
3156 : : !! NAME
3157 : : !! canct9
3158 : : !!
3159 : : !! FUNCTION
3160 : : !! Convert from canonical coordinates to cartesian coordinates
3161 : : !! a vector defined by its index=ib+natom*(irpt-1)
3162 : : !!
3163 : : !! INPUTS
3164 : : !! index= index of the atom
3165 : : !! natom=number of atoms in unit cell
3166 : : !! nrpt= Number of R points in the Big Box
3167 : : !! rcan(3,natom)=cartesian coordinates of atoms
3168 : : !! rpt(3,nrpt)=cartesian coordinates of the points in the BigBox.
3169 : : !!
3170 : : !! OUTPUT
3171 : : !! ib=number of the atom in the unit cell
3172 : : !! irpt= number of the unit cell to which belong the atom
3173 : : !! rcart(3)=cartesian coordinate of the atom indexed by index.
3174 : : !!
3175 : : !! SOURCE
3176 : :
3177 : 20691 : subroutine canct9(ib,index,irpt,natom,nrpt,rcan,rcart,rpt)
3178 : :
3179 : : !Arguments -------------------------------
3180 : : !scalars
3181 : : integer,intent(in) :: index,natom,nrpt
3182 : : integer,intent(out) :: ib,irpt
3183 : : !arrays
3184 : : real(dp),intent(in) :: rcan(3,natom)
3185 : : real(dp),intent(in) :: rpt(3,nrpt)
3186 : : real(dp),intent(out) :: rcart(3)
3187 : :
3188 : : ! *********************************************************************
3189 : :
3190 : 20691 : irpt=(index-1)/natom+1
3191 : 20691 : ib=index-natom*(irpt-1)
3192 : :
3193 [ + + ]: 82764 : rcart(:) = rpt(:,irpt) + rcan(:,ib)
3194 : :
3195 : 20691 : end subroutine canct9
3196 : : !!***
3197 : :
3198 : : !----------------------------------------------------------------------
3199 : :
3200 : : !!****f* m_dynmat/chkrp9
3201 : : !! NAME
3202 : : !! chkrp9
3203 : : !!
3204 : : !! FUNCTION
3205 : : !! Check if the rprim used for the definition of the unit cell (in the
3206 : : !! inputs) are consistent with the rprim used in the routine generating
3207 : : !! the Big Box needed to generate the interatomic forces.
3208 : : !!
3209 : : !! INPUTS
3210 : : !! brav=bravais lattice (1 or -1=simple lattice,2=face centered lattice,
3211 : : !! 3=centered lattice,4=hexagonal lattice)
3212 : : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
3213 : : !!
3214 : : !! OUTPUT
3215 : : !! (only checking)
3216 : : !!
3217 : : !! SOURCE
3218 : :
3219 : 0 : subroutine chkrp9(brav,rprim)
3220 : :
3221 : : !Arguments -------------------------------
3222 : : !scalars
3223 : : integer,intent(in) :: brav
3224 : : !arrays
3225 : : real(dp),intent(in) :: rprim(3,3)
3226 : :
3227 : : !Local variables -------------------------
3228 : : !scalars
3229 : : integer :: ii,jj
3230 : : character(len=500) :: msg
3231 : : ! *********************************************************************
3232 : :
3233 [ # # ]: 0 : if (abs(brav)==1) then
3234 : : ! Simple Cubic Lattice No condition in this case !
3235 : : continue
3236 : :
3237 [ # # ]: 0 : else if (brav==2) then
3238 : : ! Face Centered Lattice
3239 [ # # ]: 0 : do ii=1,3
3240 [ # # ]: 0 : do jj=1,3
3241 [ # # # # : 0 : if ( ( ii==jj .and. abs(rprim(ii,jj))>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
# # # # ]
3242 : : write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3243 : 0 : 'The input variable rprim does not correspond to the',ch10,&
3244 : 0 : 'fixed rprim to be used with brav=2 and ifcflag=1 :',ch10,&
3245 : 0 : ' 0 1/2 1/2',ch10,&
3246 : 0 : ' 1/2 0 1/2',ch10,&
3247 : 0 : ' 1/2 1/2 0 ',ch10,&
3248 : 0 : 'Action: rebuild your DDB by using the latter rprim.'
3249 : 0 : ABI_ERROR(msg)
3250 : : end if
3251 : : end do
3252 : : end do
3253 : :
3254 [ # # ]: 0 : else if (brav==3) then
3255 : : ! Body Centered Cubic Lattice
3256 [ # # ]: 0 : do ii=1,3
3257 [ # # ]: 0 : do jj=1,3
3258 [ # # # # : 0 : if ( ( ii==jj .and. abs(rprim(ii,jj)+.5_dp)>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
# # # # ]
3259 : : write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3260 : 0 : 'The input variable rprim does not correspond to the',ch10,&
3261 : 0 : 'fixed rprim to be used with brav=3 and ifcflag=1 :',ch10,&
3262 : 0 : ' -1/2 1/2 1/2',ch10,&
3263 : 0 : ' 1/2 -1/2 1/2',ch10,&
3264 : 0 : ' 1/2 1/2 -1/2',ch10,&
3265 : 0 : 'Action: rebuild your DDB by using the latter rprim.'
3266 : 0 : ABI_ERROR(msg)
3267 : : end if
3268 : : end do
3269 : : end do
3270 : :
3271 [ # # ]: 0 : else if (brav==4) then
3272 : : ! Hexagonal Lattice
3273 : : if (abs(rprim(1,1)-1.0_dp)>tol10 .or. &
3274 : : abs(rprim(3,3)-1.0_dp)>tol10 .or. &
3275 : : abs(rprim(2,1) )>tol10 .or. &
3276 : : abs(rprim(3,1) )>tol10 .or. &
3277 : : abs(rprim(1,3) )>tol10 .or. &
3278 : : abs(rprim(2,3) )>tol10 .or. &
3279 : : abs(rprim(3,2) )>tol10 .or. &
3280 [ # # # # : 0 : abs(rprim(1,2)+0.5_dp)>tol10 .or. &
# # # # #
# # # # #
# # # # ]
3281 : : abs(rprim(2,2)-0.5_dp*sqrt(3.0_dp))>tol10 ) then
3282 : : write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3283 : 0 : 'The input variable rprim does not correspond to the',ch10,&
3284 : 0 : 'fixed rprim to be used with brav=4 and ifcflag=1 :',ch10,&
3285 : 0 : ' 1 0 0',ch10,&
3286 : 0 : ' -1/2 sqrt[3]/2 0',ch10,&
3287 : 0 : ' 0 0 1',ch10,&
3288 : 0 : 'Action: rebuild your DDB by using the latter rprim.'
3289 : 0 : ABI_ERROR(msg)
3290 : : end if
3291 : :
3292 : : else
3293 : : write(msg, '(a,i4,a,a,a,a,a)' )&
3294 : 0 : 'The value of brav=',brav,' is not allowed.',ch10,&
3295 : 0 : 'Only -1, 1,2,3 or 4 are allowed.',ch10,&
3296 : 0 : 'Action: change the value of brav in your input file.'
3297 : 0 : ABI_ERROR(msg)
3298 : : end if
3299 : :
3300 : 0 : end subroutine chkrp9
3301 : : !!***
3302 : :
3303 : : !----------------------------------------------------------------------
3304 : :
3305 : : !!****f* m_dynmat/dist9
3306 : : !! NAME
3307 : : !! dist9
3308 : : !!
3309 : : !! FUNCTION
3310 : : !! Compute the distance between atoms
3311 : : !!
3312 : : !! INPUTS
3313 : : !! dist(natom,natom,nrpt)=distances between atoms
3314 : : !! natom=number of atoms in unit cell
3315 : : !! nrpt= Number of R points in the Big Box
3316 : : !! rcan(3,natom)=cartesian coordinates of atoms
3317 : : !! rpt(3,nrpt)=cartesian coordinates of the points in the BigBox.
3318 : : !!
3319 : : !! OUTPUT
3320 : : !! dist(natom,natom,nrpt)=distances between atoms
3321 : : !!
3322 : : !! SOURCE
3323 : :
3324 : 83 : subroutine dist9(dist,natom,nrpt,rcan,rpt)
3325 : :
3326 : : !Arguments -------------------------------
3327 : : !scalars
3328 : : integer,intent(in) :: natom,nrpt
3329 : : !arrays
3330 : : real(dp),intent(in) :: rcan(3,natom)
3331 : : real(dp),intent(in) :: rpt(3,nrpt)
3332 : : real(dp),intent(out) :: dist(natom,natom,nrpt)
3333 : :
3334 : : !Local variables -------------------------
3335 : : !scalars
3336 : : integer :: ia,ib,irpt
3337 : : !arrays
3338 : : real(dp) :: rdiff(3)
3339 : : ! *********************************************************************
3340 : :
3341 : : !BIG loop on all generic atoms
3342 [ + + ]: 344 : do ia=1,natom
3343 [ + + ]: 1727 : do ib=1,natom
3344 [ + + ]: 614092 : do irpt=1,nrpt
3345 [ + + ]: 2449792 : rdiff(:) = rcan(:,ia) - rcan(:,ib) - rpt(:,irpt)
3346 : 613831 : dist(ia,ib,irpt)=(rdiff(1)**2+rdiff(2)**2+rdiff(3)**2)**0.5
3347 : : end do
3348 : : end do
3349 : : end do
3350 : :
3351 : 83 : end subroutine dist9
3352 : : !!***
3353 : :
3354 : : !----------------------------------------------------------------------
3355 : :
3356 : : !!****f* m_dynmat/ftifc_q2r
3357 : : !!
3358 : : !! NAME
3359 : : !! ftifc_q2r
3360 : : !!
3361 : : !! FUNCTION
3362 : : !! Generates the Fourier transform of the dynamical matrices
3363 : : !! to obtain interatomic forces (real space).
3364 : : !!
3365 : : !! INPUTS
3366 : : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
3367 : : !! gprim(3,3)= Normalized coordinates in reciprocal space
3368 : : !! natom= Number of atoms in the unit cell
3369 : : !! nqpt= Number of q points in the Brillouin zone
3370 : : !! nrpt= Number of R points in the Big Box
3371 : : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
3372 : : !! These coordinates are normalized (=> * acell(3)!!)
3373 : : !! spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
3374 : : !! comm=MPI communicator.
3375 : : !!
3376 : : !! OUTPUT
3377 : : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space.
3378 : : !!
3379 : : !! SOURCE
3380 : :
3381 : 201 : subroutine ftifc_q2r(atmfrc,dynmat,gprim,natom,nqpt,nrpt,rpt,spqpt,comm)
3382 : :
3383 : : !Arguments -------------------------------
3384 : : !scalars
3385 : : integer,intent(in) :: natom,nqpt,nrpt,comm
3386 : : !arrays
3387 : : real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
3388 : : real(dp),intent(out) :: atmfrc(3,natom,3,natom,nrpt)
3389 : : real(dp),intent(in) :: dynmat(2,3,natom,3,natom,nqpt)
3390 : :
3391 : : !Local variables -------------------------
3392 : : !scalars
3393 : : integer :: ia,ib,iqpt,irpt,mu,nu,nprocs,my_rank,ierr
3394 : : real(dp) :: im,kr,re
3395 : : !arrays
3396 : : real(dp) :: kk(3)
3397 : : ! *********************************************************************
3398 : :
3399 : 201 : nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
3400 : :
3401 : : ! Interatomic Forces from Dynamical Matrices
3402 [ + + + + : 4154000 : atmfrc = zero
+ + + + +
+ ]
3403 [ + + ]: 23976 : do irpt=1,nrpt
3404 [ + + ]: 23775 : if (mod(irpt, nprocs) /= my_rank) cycle ! mpi-parallelism
3405 [ + + ]: 5987958 : do iqpt=1,nqpt
3406 : :
3407 : : ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3408 [ + + + + ]: 77533950 : kk(:) = matmul(gprim, spqpt(:, iqpt))
3409 : :
3410 : : ! Product of k and r
3411 [ + + ]: 23856600 : kr=dot_product(kk,rpt(:,irpt))
3412 : :
3413 : : ! Get the phase factor
3414 : 5964150 : re=cos(two_pi*kr)
3415 : 5964150 : im=sin(two_pi*kr)
3416 : :
3417 : : ! Now, big inner loops on atoms and directions
3418 : : ! The indices are ordered to give better speed
3419 [ + + ]: 29481642 : do ib=1,natom
3420 [ + + ]: 99939018 : do nu=1,3
3421 [ + + ]: 411406215 : do ia=1,natom
3422 [ + + ]: 1340206539 : do mu=1,3
3423 : : ! Real part of the interatomic forces
3424 : : atmfrc(mu,ia,nu,ib,irpt)=atmfrc(mu,ia,nu,ib,irpt) &
3425 : : +re*dynmat(1,mu,ia,nu,ib,iqpt)&
3426 : 1269725388 : +im*dynmat(2,mu,ia,nu,ib,iqpt)
3427 : : !The imaginary part should be equal to zero !!!!!!
3428 : : !atmfrc(2,mu,ia,nu,ib,irpt)=atmfrc(2,mu,ia,nu,ib,irpt) &
3429 : : ! +re*dynmat(2,mu,ia,nu,ib,iqpt) &
3430 : : ! -im*dynmat(1,mu,ia,nu,ib,iqpt)
3431 : : end do
3432 : : end do
3433 : : end do
3434 : : end do
3435 : :
3436 : : end do
3437 : : end do
3438 : :
3439 : 201 : call xmpi_sum(atmfrc, comm, ierr)
3440 : : !The sumifc has to be weighted by a normalization factor of 1/nqpt
3441 [ + + + + : 4154000 : atmfrc = atmfrc/nqpt
+ + + + +
+ ]
3442 : :
3443 : 201 : end subroutine ftifc_q2r
3444 : : !!***
3445 : :
3446 : : !----------------------------------------------------------------------
3447 : :
3448 : : !!****f* m_dynmat/ftifc_r2q
3449 : : !!
3450 : : !! NAME
3451 : : !! ftifc_r2q
3452 : : !!
3453 : : !! FUNCTION
3454 : : !! Generates the Fourier transform of the interatomic forces
3455 : : !! to obtain dynamical matrices in reciprocal space: R --> q.
3456 : : !!
3457 : : !! INPUTS
3458 : : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
3459 : : !! gprim(3,3)= Normalized coordinates in reciprocal space
3460 : : !! natom= Number of atoms in the unit cell
3461 : : !! nqpt= Number of q points in the Brillouin zone
3462 : : !! nrpt= Number of R points in the Big Box
3463 : : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
3464 : : !! These coordinates are normalized (=> * acell(3)!!)
3465 : : !! spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
3466 : : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
3467 : : !! comm: MPI communicator
3468 : : !!
3469 : : !! OUTPUT
3470 : : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
3471 : : !!
3472 : : !! SOURCE
3473 : :
3474 : 197574 : subroutine ftifc_r2q(atmfrc, dynmat, gprim, natom, nqpt, nrpt, rpt, spqpt, wghatm, comm)
3475 : :
3476 : : !Arguments -------------------------------
3477 : : !scalars
3478 : : integer,intent(in) :: natom,nqpt,nrpt,comm
3479 : : !arrays
3480 : : real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
3481 : : real(dp),intent(in) :: wghatm(natom,natom,nrpt)
3482 : : real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
3483 : : real(dp),intent(out) :: dynmat(2,3,natom,3,natom,nqpt)
3484 : :
3485 : : !Local variables -------------------------
3486 : : !scalars
3487 : : integer :: ia,ib,iqpt,irpt,mu,nu,cnt,my_rank,nprocs, ierr
3488 : : real(dp) :: facti,factr,im,kr,re
3489 : : !real(dp) : w(2, natom, natom)
3490 : : !arrays
3491 : : real(dp) :: kk(3)
3492 : : ! *********************************************************************
3493 : :
3494 : 197574 : my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
3495 [ + + + + : 35609520 : dynmat = zero; cnt = 0
+ + + + +
+ + + ]
3496 : :
3497 : : ! MG: This is an hotspot. I don'tknow whether one should rewrite with BLAS1 dot or not.
3498 : : ! Note, however, that simply removing the check on the weights inside the loop over atoms.
3499 : : ! leads to a non-negligible speedup with intel (~30% if dipdip -1 is used)
3500 [ + + ]: 395148 : do iqpt=1,nqpt
3501 : :
3502 : : ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3503 [ + + + + ]: 2568462 : kk(:) = matmul(gprim, spqpt(:, iqpt))
3504 : :
3505 [ + + ]: 63710777 : do irpt=1,nrpt
3506 [ + - ]: 63315629 : cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! MPI parallelism.
3507 : :
3508 : : ! k.R
3509 [ + + ]: 253262516 : kr=dot_product(kk,rpt(:,irpt))
3510 : : ! Get phase factor
3511 : 63315629 : re = cos(two_pi*kr); im = sin(two_pi*kr)
3512 : :
3513 : : ! Inner loop on atoms and directions
3514 [ + + ]: 217064340 : do ib=1,natom
3515 [ + + ]: 716950481 : do ia=1,natom
3516 : : !if (abs(wghatm(ia,ib,irpt)) > tol10) then ! Commented by MG
3517 : 500083715 : factr = re * wghatm(ia,ib,irpt)
3518 : 500083715 : facti = im * wghatm(ia,ib,irpt)
3519 [ + + ]: 2153885997 : do nu=1,3
3520 [ + + ]: 6501088295 : do mu=1,3
3521 : : ! Real and imaginary part of the dynamical matrices
3522 : : ! Atmfrc should be real
3523 : 4500753435 : dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + factr * atmfrc(mu,ia,nu,ib,irpt)
3524 : 6001004580 : dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + facti * atmfrc(mu,ia,nu,ib,irpt)
3525 : : end do
3526 : : end do
3527 : : !end if
3528 : : end do
3529 : : end do
3530 : :
3531 : : ! MG: New version: I don't know if it's faster.
3532 : : !w(1,:,:) = re * wghatm(:,:,irpt)
3533 : : !w(2,:,:) = im * wghatm(:,:,irpt)
3534 : : !do ib=1,natom
3535 : : ! do nu=1,3
3536 : : ! do ia=1,natom
3537 : : ! do mu=1,3
3538 : : ! ! Real and imaginary part of the dynamical matrices
3539 : : ! ! Atmfrc should be real
3540 : : ! dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + w(1,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
3541 : : ! dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + w(2,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
3542 : : ! end do
3543 : : ! end do
3544 : : ! end do
3545 : : !end do
3546 : :
3547 : : end do
3548 : : end do
3549 : :
3550 [ - + ]: 197574 : if (nprocs > 1) call xmpi_sum(dynmat, comm, ierr)
3551 : :
3552 : 197574 : end subroutine ftifc_r2q
3553 : : !!***
3554 : :
3555 : : !----------------------------------------------------------------------
3556 : :
3557 : : !!****f* m_dynmat/dynmat_dq
3558 : : !!
3559 : : !! NAME
3560 : : !! dynmat_dq
3561 : : !!
3562 : : !! FUNCTION
3563 : : !! Compute the derivative D(q)/dq of the dynamical matrix via Fourier transform
3564 : : !! of the interatomic forces
3565 : : !!
3566 : : !! INPUTS
3567 : : !! qpt(3)= Reduced coordinates of the q vector in reciprocal space
3568 : : !! natom= Number of atoms in the unit cell
3569 : : !! gprim(3,3)= Primitive vectors of the reciprocal lattice, dual to the lattice of rpt (gprimd for cartesian rpt)
3570 : : !! nrpt= Number of R points in the Big Box
3571 : : !! rpt(3,nprt)= Coordinates of the R points (cartesian, in Bohr, for ifc_type)
3572 : : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
3573 : : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
3574 : : !!
3575 : : !! OUTPUT
3576 : : !! dddq(2,3,natom,3,natom,3)= Derivate of the dynamical matrix, in the coordinates of rpt
3577 : : !! (cartesian for cartesian rpt). The three directions are stored in the last dimension.
3578 : : !!
3579 : : !! SOURCE
3580 : :
3581 : 129533 : subroutine dynmat_dq(qpt,natom,gprim,nrpt,rpt,atmfrc,wghatm,dddq)
3582 : :
3583 : : !Arguments -------------------------------
3584 : : !scalars
3585 : : integer,intent(in) :: natom,nrpt
3586 : : !arrays
3587 : : real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt(3)
3588 : : real(dp),intent(in) :: wghatm(natom,natom,nrpt)
3589 : : real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
3590 : : real(dp),intent(out) :: dddq(2,3,natom,3,natom,3)
3591 : :
3592 : : !Local variables -------------------------
3593 : : !scalars
3594 : : integer :: ia,ib,irpt,mu,nu,ii
3595 : : real(dp) :: im,kr,re
3596 : : !arrays
3597 : : real(dp) :: kk(3),fact(2,3)
3598 : : ! *********************************************************************
3599 : :
3600 [ + + + + : 46226078 : dddq = zero
+ + + + +
+ + + ]
3601 [ + + ]: 46717662 : do irpt=1,nrpt
3602 : : ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3603 [ + + + + ]: 605645677 : kk(:) = matmul(gprim, qpt)
3604 : :
3605 : : ! Product of k and r
3606 [ + + ]: 186352516 : kr=dot_product(kk,rpt(:,irpt))
3607 : :
3608 : : ! Get phase factor
3609 : 46588129 : re=cos(two_pi*kr); im=sin(two_pi*kr)
3610 : :
3611 : : ! Inner loop on atoms and directions
3612 [ + + ]: 136178695 : do ib=1,natom
3613 [ + + ]: 317689899 : do ia=1,natom
3614 [ + + ]: 271101770 : if (abs(wghatm(ia,ib,irpt))>1.0d-10) then
3615 : : ! take into account rotation due to i.
3616 [ + + ]: 712541228 : fact(1,:) = -im * wghatm(ia,ib,irpt) * rpt(:,irpt)
3617 [ + + ]: 712541228 : fact(2,:) = re * wghatm(ia,ib,irpt) * rpt(:,irpt)
3618 [ + + ]: 712541228 : do nu=1,3
3619 [ + + ]: 2315758991 : do mu=1,3
3620 : : ! Real and imaginary part of the dynamical matrices
3621 : : ! Atmfrc should be real
3622 [ + + ]: 6947276973 : do ii=1,3
3623 : 4809653289 : dddq(1,mu,ia,nu,ib,ii) = dddq(1,mu,ia,nu,ib,ii) + fact(1,ii) * atmfrc(mu,ia,nu,ib,irpt)
3624 : 6412871052 : dddq(2,mu,ia,nu,ib,ii) = dddq(2,mu,ia,nu,ib,ii) + fact(2,ii) * atmfrc(mu,ia,nu,ib,irpt)
3625 : : end do
3626 : : end do
3627 : : end do
3628 : : end if
3629 : : end do
3630 : : end do
3631 : : end do
3632 : 129533 : end subroutine dynmat_dq
3633 : : !!***
3634 : :
3635 : : !----------------------------------------------------------------------
3636 : :
3637 : : !!****f* m_dynmat/ifclo9
3638 : : !! NAME
3639 : : !! ifclo9
3640 : : !!
3641 : : !! FUNCTION
3642 : : !! Convert from cartesian coordinates to local coordinates
3643 : : !! the 3*3 interatomic force constant matrix
3644 : : !!
3645 : : !! INPUTS
3646 : : !! ifccar(3,3)= matrix of interatomic force constants in cartesian
3647 : : !! coordinates
3648 : : !! vect1(3)= cartesian coordinates of the first local vector
3649 : : !! vect2(3)= cartesian coordinates of the second local vector
3650 : : !! vect3(3)= cartesian coordinates of the third local vector
3651 : : !!
3652 : : !! OUTPUT
3653 : : !! ifcloc(3,3)= matrix of interatomic force constants in local coordinates
3654 : : !!
3655 : : !! SOURCE
3656 : :
3657 : 29558 : subroutine ifclo9(ifccar,ifcloc,vect1,vect2,vect3)
3658 : :
3659 : : !Arguments -------------------------------
3660 : : !arrays
3661 : : real(dp),intent(in) :: ifccar(3,3),vect1(3),vect2(3),vect3(3)
3662 : : real(dp),intent(out) :: ifcloc(3,3)
3663 : :
3664 : : !Local variables -------------------------
3665 : : !scalars
3666 : : integer :: ii,jj
3667 : : !arrays
3668 : : real(dp) :: work(3,3)
3669 : : ! *********************************************************************
3670 : :
3671 [ + + ]: 118232 : do jj=1,3
3672 [ + + ]: 354696 : do ii=1,3
3673 : 354696 : work(jj,ii)=zero
3674 : : end do
3675 [ + + ]: 384254 : do ii=1,3
3676 : 266022 : work(jj,1)=work(jj,1)+ifccar(jj,ii)*vect1(ii)
3677 : 266022 : work(jj,2)=work(jj,2)+ifccar(jj,ii)*vect2(ii)
3678 : 354696 : work(jj,3)=work(jj,3)+ifccar(jj,ii)*vect3(ii)
3679 : : end do
3680 : : end do
3681 : :
3682 [ + + ]: 118232 : do jj=1,3
3683 [ + + ]: 354696 : do ii=1,3
3684 : 354696 : ifcloc(ii,jj)=zero
3685 : : end do
3686 [ + + ]: 384254 : do ii=1,3
3687 : 266022 : ifcloc(1,jj)=ifcloc(1,jj)+vect1(ii)*work(ii,jj)
3688 : 266022 : ifcloc(2,jj)=ifcloc(2,jj)+vect2(ii)*work(ii,jj)
3689 : 354696 : ifcloc(3,jj)=ifcloc(3,jj)+vect3(ii)*work(ii,jj)
3690 : : end do
3691 : : end do
3692 : :
3693 : 29558 : end subroutine ifclo9
3694 : : !!***
3695 : :
3696 : : !----------------------------------------------------------------------
3697 : :
3698 : : !!****f* m_dynmat/wght9
3699 : : !! NAME
3700 : : !! wght9
3701 : : !!
3702 : : !! NOTE
3703 : : !! Not called anymore: get_bigbox_and_weights (this module) now gets its R-points and
3704 : : !! weights from ifc_supercell_type%calc_ws_wghatm (m_ifc_supercell.F90), which is
3705 : : !! brav-independent and works for any supercell matrix, not just the diagonal,
3706 : : !! cubic-equal ngqpt this routine (and make_bigbox/bigbx9, its companion for the
3707 : : !! R-point list itself) requires. Kept here, unused, for reference.
3708 : : !!
3709 : : !! FUNCTION
3710 : : !! Generates a weight to each R point of the Big Box and for each pair of atoms
3711 : : !! For each R points included in the space generates by moving
3712 : : !! the unit cell around each atom; the weight will be one.
3713 : : !! Border conditions are provided.
3714 : : !! The R points outside the chosen space will have a 0 weight.
3715 : : !!
3716 : : !! INPUTS
3717 : : !! brav = Bravais lattice (1 or -1=S.C.;2=F.C.C.;4=Hex. -1 is for old algo to find weights, =1 is for Wigner-Seitz algo)
3718 : : !! gprim(3,3)= Normalized coordinates in reciprocal space
3719 : : !! natom= Number of atoms in the unit cell
3720 : : !! ngqpt(6)= Numbers used to sample the Brillouin zone
3721 : : !! nqpt= Number of q points used in the homogeneous grid
3722 : : !! sampling the Brillouin zone
3723 : : !! nqshft=number of shift vectors in the repeated cell
3724 : : !! nrpt=Number of R points in the Big Box
3725 : : !! qshft(3,nqshft)=vectors that will be used to determine
3726 : : !! the shifts from (0. 0. 0.)
3727 : : !! rcan(3,natom)=Atomic position in canonical coordinates
3728 : : !! rpt(3,nprt)=Canonical coordinates of the R points in the unit cell
3729 : : !! These coordinates are normalized (=> * acell(3))
3730 : : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
3731 : : !! toldist= Tolerance on the distance between two R points.
3732 : : !!
3733 : : !! OUTPUT
3734 : : !! wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
3735 : : !! The vector r(atom2)-r(atom1)+rpt should be inside the moving box
3736 : : !! r_inscribed_sphere= The radius of the sphere inscribed inside the big box.
3737 : : !! ngqpt(6)= can be modified
3738 : : !!
3739 : : !! SOURCE
3740 : :
3741 : 0 : subroutine wght9(brav,gprim,natom,ngqpt,nqpt,nqshft,nrpt,qshft,rcan,rpt,rprimd,toldist,r_inscribed_sphere,wghatm,ierr)
3742 : :
3743 : : !Arguments -------------------------------
3744 : : !scalars
3745 : : integer,intent(in) :: brav,natom,nqpt,nqshft,nrpt
3746 : : integer,intent(out) :: ierr
3747 : : real(dp),intent(out) :: r_inscribed_sphere
3748 : : real(dp),intent(in) :: toldist
3749 : : !arrays
3750 : : integer,intent(inout) :: ngqpt(9)
3751 : : real(dp),intent(in) :: gprim(3,3),qshft(3,4),rcan(3,natom),rpt(3,nrpt),rprimd(3,3)
3752 : : real(dp),intent(out) :: wghatm(natom,natom,nrpt)
3753 : :
3754 : : !Local variables -------------------------
3755 : : !scalars
3756 : : integer :: ia,ib,ii,jj,kk,iqshft,irpt,jqshft,nbordh,tok,nptws,nreq,idir
3757 : : real(dp) :: factor,sumwght,normsq,proj
3758 : : character(len=500) :: msg
3759 : : !arrays
3760 : : integer :: nbord(9)
3761 : : real(dp) :: rdiff(9),red(3,3),ptws(4, 729),pp(3),rdiff_tmp(3)
3762 : : ! *********************************************************************
3763 : :
3764 : 0 : ierr = 0
3765 : :
3766 : : ! First analyze the vectors qshft
3767 [ # # ]: 0 : if (nqshft /= 1) then
3768 : :
3769 [ # # ]: 0 : if (brav == 4) then
3770 : : write(msg,'(3a,i0,3a)' )&
3771 : 0 : 'For the time being, only nqshft=1',ch10,&
3772 : 0 : 'is allowed with brav=4, while it is nqshft=',nqshft,'.',ch10,&
3773 : 0 : 'Action: in the input file, correct either brav or nqshft.'
3774 : 0 : ABI_ERROR(msg)
3775 : : end if
3776 : :
3777 [ # # ]: 0 : if (nqshft == 2) then
3778 : : ! Make sure that the q vectors form a BCC lattice
3779 [ # # ]: 0 : do ii=1,3
3780 [ # # ]: 0 : if(abs(abs(qshft(ii,1)-qshft(ii,2))-.5_dp)>1.d-10)then
3781 : : write(msg, '(a,a,a,a,a,a,a)' )&
3782 : 0 : 'The test of the q1shft vectors shows that they',ch10,&
3783 : 0 : 'do not generate a body-centered lattice, which',ch10,&
3784 : 0 : 'is mandatory for nqshft=2.',ch10,&
3785 : 0 : 'Action: change the q1shft vectors in your input file.'
3786 : 0 : ABI_ERROR(msg)
3787 : : end if
3788 : : end do
3789 [ # # ]: 0 : else if (nqshft == 4) then
3790 : : ! Make sure that the q vectors form a FCC lattice
3791 [ # # ]: 0 : do iqshft=1,3
3792 [ # # ]: 0 : do jqshft=iqshft+1,4
3793 : : tok=0
3794 [ # # ]: 0 : do ii=1,3
3795 : : ! Test on the presence of a +-0.5 difference
3796 [ # # ]: 0 : if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-.5_dp) <1.d-10) tok=tok+1
3797 : : ! Test on the presence of a 0 or +-1.0 difference
3798 [ # # ]: 0 : if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-1._dp) <1.d-10 .or.&
3799 [ # # ]: 0 : abs(qshft(ii,iqshft)-qshft(ii,jqshft)) < 1.d-10) tok=tok+4
3800 : : end do
3801 : : ! Test 1 should be satisfied twice, and test 2 once
3802 [ # # ]: 0 : if(tok/=6)then
3803 : : write(msg, '(7a)' )&
3804 : 0 : 'The test of the q1shft vectors shows that they',ch10,&
3805 : 0 : 'do not generate a face-centered lattice, which',ch10,&
3806 : 0 : 'is mandatory for nqshft=4.',ch10,&
3807 : 0 : 'Action: change the q1shft vectors in your input file.'
3808 : 0 : ABI_ERROR(msg)
3809 : : end if
3810 : : end do
3811 : : end do
3812 : : else
3813 : : write(msg, '(a,i4,3a)' )&
3814 : 0 : 'nqshft must be 1, 2 or 4. It is nqshft=',nqshft,'.',ch10,&
3815 : 0 : 'Action: change nqshft in your input file.'
3816 : 0 : ABI_ERROR(msg)
3817 : : end if
3818 : : end if
3819 : :
3820 : 0 : factor=0.5_dp
3821 [ # # ]: 0 : if(brav==2 .or. brav==3) factor=0.25_dp
3822 [ # # ]: 0 : if(nqshft/=1)factor=factor*2
3823 : :
3824 [ # # ]: 0 : if (brav==1) then
3825 : : ! Does not support multiple shifts
3826 [ # # ]: 0 : if (nqshft/=1) then
3827 : 0 : ABI_ERROR('This version of the weights does not support nqshft/=1.')
3828 : : end if
3829 : :
3830 : : ! Find the points of the lattice given by ngqpt*acell. These are used to define
3831 : : ! a Wigner-Seitz cell around the origin. The origin is excluded from the list.
3832 : : ! TODO : in principle this should be only -1 to +1 for ii jj kk!
3833 : : nptws=0
3834 [ # # ]: 0 : do ii=-2,2
3835 [ # # ]: 0 : do jj=-2,2
3836 [ # # ]: 0 : do kk=-2,2
3837 [ # # ]: 0 : do idir=1,3
3838 : 0 : pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
3839 : : end do
3840 : 0 : normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
3841 [ # # ]: 0 : if (normsq > tol6) then
3842 : 0 : nptws = nptws + 1
3843 [ # # ]: 0 : ptws(:3,nptws) = pp(:)
3844 : 0 : ptws(4,nptws) = half*normsq
3845 : : end if
3846 : : end do
3847 : : end do
3848 : : end do
3849 : : end if ! end new_wght
3850 : : !write(std_out,*)'factor,ngqpt',factor,ngqpt(1:3)
3851 : :
3852 [ # # # # : 0 : r_inscribed_sphere = sum((matmul(rprimd(:,:),ngqpt(1:3)))**2)
# # # # ]
3853 [ # # ]: 0 : do ii=-1,1
3854 [ # # ]: 0 : do jj=-1,1
3855 [ # # ]: 0 : do kk=-1,1
3856 [ # # ]: 0 : if (ii==0 .and. jj==0 .and. kk==0) cycle
3857 [ # # ]: 0 : do idir=1,3
3858 : 0 : pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
3859 : : end do
3860 : 0 : normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
3861 : 0 : r_inscribed_sphere = min(r_inscribed_sphere, normsq)
3862 : : end do
3863 : : end do
3864 : : end do
3865 : 0 : r_inscribed_sphere = sqrt(r_inscribed_sphere)
3866 : :
3867 : :
3868 : : !Begin the big loop on ia and ib
3869 [ # # ]: 0 : do ia=1,natom
3870 [ # # ]: 0 : do ib=1,natom
3871 : :
3872 : : ! Simple Lattice
3873 [ # # ]: 0 : if (abs(brav)==1) then
3874 : : ! In this case, it is better to work in reduced coordinates
3875 : : ! As rcan is in canonical coordinates, => multiplication by gprim
3876 [ # # ]: 0 : do ii=1,3
3877 : 0 : red(1,ii)= rcan(1,ia)*gprim(1,ii) +rcan(2,ia)*gprim(2,ii) +rcan(3,ia)*gprim(3,ii)
3878 : 0 : red(2,ii)= rcan(1,ib)*gprim(1,ii) +rcan(2,ib)*gprim(2,ii) +rcan(3,ib)*gprim(3,ii)
3879 : : end do
3880 : : end if
3881 : :
3882 [ # # ]: 0 : do irpt=1,nrpt
3883 : :
3884 : : ! Initialization of the weights to 1.0
3885 : 0 : wghatm(ia,ib,irpt)=1.0_dp
3886 : :
3887 : : ! Compute the difference vector
3888 : :
3889 : : ! Simple Cubic Lattice
3890 [ # # ]: 0 : if (abs(brav)==1) then
3891 : : ! Change of rpt to reduced coordinates
3892 [ # # ]: 0 : do ii=1,3
3893 : 0 : red(3,ii)= rpt(1,irpt)*gprim(1,ii) +rpt(2,irpt)*gprim(2,ii) +rpt(3,irpt)*gprim(3,ii)
3894 : 0 : rdiff(ii)=red(2,ii)-red(1,ii)+red(3,ii)
3895 : : end do
3896 [ # # ]: 0 : if (brav==1) then
3897 : : ! rdiff in cartesian coordinates
3898 [ # # ]: 0 : do ii=1,3
3899 : 0 : rdiff_tmp(ii)=rdiff(1)*rprimd(ii,1)+rdiff(2)*rprimd(ii,2)+rdiff(3)*rprimd(ii,3)
3900 : : end do
3901 [ # # ]: 0 : rdiff(1:3)=rdiff_tmp(1:3)
3902 : : end if
3903 : :
3904 : : else
3905 : : ! Other lattices
3906 [ # # ]: 0 : do ii=1,3
3907 : 0 : rdiff(ii)=rcan(ii,ib)-rcan(ii,ia)+rpt(ii,irpt)
3908 : : end do
3909 : : end if
3910 : :
3911 : : ! Assignement of weights
3912 : :
3913 [ # # # # ]: 0 : if(nqshft==1 .and. brav/=4)then
3914 : :
3915 [ # # ]: 0 : if (brav/=1) then
3916 [ # # ]: 0 : do ii=1,3
3917 : : ! If the rpt vector is greater than the allowed space => weight = 0.0
3918 [ # # ]: 0 : if (abs(rdiff(ii))-tol10>factor*ngqpt(ii)) then
3919 : 0 : wghatm(ia,ib,irpt)=zero
3920 [ # # ]: 0 : else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
3921 : : ! If the point is in a boundary position => weight/2
3922 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
3923 : : end if
3924 : : end do
3925 : : else
3926 : : ! new weights
3927 : 0 : wghatm(ia,ib,irpt)=zero
3928 : 0 : nreq = 1
3929 [ # # ]: 0 : do ii=1,nptws
3930 : 0 : proj = rdiff(1)*ptws(1,ii)+rdiff(2)*ptws(2,ii)+rdiff(3)*ptws(3,ii)
3931 : : ! if rdiff closer to ptws than the origin the weight is zero
3932 : : ! if rdiff close to the origin with respect to all the other ptws the weight is 1
3933 : : ! if rdiff is equidistant from the origin and N other ptws the weight is 1/(N+1)
3934 [ # # ]: 0 : if (proj - ptws(4,ii) > toldist) then
3935 : : nreq = 0
3936 : : EXIT
3937 [ # # ]: 0 : else if(abs(proj-ptws(4,ii)) <= toldist) then
3938 : 0 : nreq=nreq+1
3939 : : end if
3940 : : end do
3941 [ # # ]: 0 : if (nreq>0) then
3942 : 0 : wghatm(ia,ib,irpt)=one/DBLE(nreq)
3943 : : end if
3944 : : end if
3945 : :
3946 [ # # ]: 0 : else if(brav==4)then
3947 : : ! Hexagonal
3948 : : ! Examination of the X and Y boundaries in order to form an hexagon
3949 : : ! First generate the relevant boundaries
3950 : 0 : rdiff(4)=0.5_dp*( rdiff(1)+sqrt(3.0_dp)*rdiff(2) )
3951 : 0 : ngqpt(4)=ngqpt(1)
3952 : 0 : rdiff(5)=0.5_dp*( rdiff(1)-sqrt(3.0_dp)*rdiff(2) )
3953 : 0 : ngqpt(5)=ngqpt(1)
3954 : :
3955 : : ! Test the four inequalities
3956 [ # # ]: 0 : do ii=1,5
3957 [ # # ]: 0 : if(ii/=2)then
3958 : :
3959 : 0 : nbord(ii)=0
3960 : : ! If the rpt vector is greater than the allowed space => weight = 0.0
3961 [ # # ]: 0 : if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
3962 : 0 : wghatm(ia,ib,irpt)=zero
3963 [ # # ]: 0 : else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
3964 : : ! If the point is in a boundary position increment nbord(ii)
3965 : 0 : nbord(ii)=1
3966 : : end if
3967 : :
3968 : : end if
3969 : : end do
3970 : :
3971 : : ! Computation of weights
3972 : 0 : nbordh=nbord(1)+nbord(4)+nbord(5)
3973 [ # # ]: 0 : if (nbordh==1) then
3974 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
3975 [ # # ]: 0 : else if (nbordh==2) then
3976 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
3977 [ # # ]: 0 : else if (nbordh/=0) then
3978 : 0 : ABI_BUG('There is a problem of borders and weights (hex).')
3979 : : end if
3980 [ # # ]: 0 : if (nbord(3)==1)then
3981 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
3982 : : end if
3983 : :
3984 [ # # ]: 0 : else if(nqshft==2 .and. brav/=4)then
3985 : :
3986 : : ! BCC packing of k-points
3987 : : ! First, generate the relevant boundaries
3988 : 0 : rdiff(4)= rdiff(1)+rdiff(2)
3989 : 0 : rdiff(5)= rdiff(1)-rdiff(2)
3990 : 0 : rdiff(6)= rdiff(1)+rdiff(3)
3991 : 0 : rdiff(7)= rdiff(1)-rdiff(3)
3992 : 0 : rdiff(8)= rdiff(3)+rdiff(2)
3993 : 0 : rdiff(9)= rdiff(3)-rdiff(2)
3994 [ # # # # ]: 0 : if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
3995 : : write(msg, '(a,a,a,3i6,a,a,a,a)' )&
3996 : 0 : 'In the BCC case, the three ngqpt numbers ',ch10,&
3997 : 0 : ' ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
3998 : 0 : 'should be equal.',ch10,&
3999 : 0 : 'Action: use identical ngqpt(1:3) in your input file.'
4000 : 0 : ABI_ERROR(msg)
4001 : : end if
4002 [ # # ]: 0 : do ii=4,9
4003 : 0 : ngqpt(ii)=ngqpt(1)
4004 : : end do
4005 : :
4006 : : ! Test the relevant inequalities
4007 : 0 : nbord(1)=0
4008 [ # # ]: 0 : do ii=4,9
4009 : : ! If the rpt vector is greater than the allowed space => weight = 0.0
4010 [ # # ]: 0 : if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
4011 : 0 : wghatm(ia,ib,irpt)=zero
4012 [ # # ]: 0 : else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4013 : : ! If the point is in a boundary position increment nbord(1)
4014 : 0 : nbord(1)=nbord(1)+1
4015 : : end if
4016 : : end do
4017 : :
4018 : : ! Computation of weights
4019 [ # # ]: 0 : if (nbord(1)==1) then
4020 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4021 [ # # ]: 0 : else if (nbord(1)==2) then
4022 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
4023 [ # # ]: 0 : else if (nbord(1)==3) then
4024 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
4025 [ # # ]: 0 : else if (nbord(1)==4) then
4026 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/6
4027 [ # # ]: 0 : else if (nbord(1)/=0) then
4028 : 0 : ABI_ERROR(' There is a problem of borders and weights (BCC).')
4029 : : end if
4030 : :
4031 [ # # ]: 0 : else if(nqshft==4 .and. brav/=4)then
4032 : :
4033 : : ! FCC packing of k-points
4034 : : ! First, generate the relevant boundaries
4035 : 0 : rdiff(4)= (rdiff(1)+rdiff(2)+rdiff(3))*2._dp/3._dp
4036 : 0 : rdiff(5)= (rdiff(1)-rdiff(2)+rdiff(3))*2._dp/3._dp
4037 : 0 : rdiff(6)= (rdiff(1)+rdiff(2)-rdiff(3))*2._dp/3._dp
4038 : 0 : rdiff(7)= (rdiff(1)-rdiff(2)-rdiff(3))*2._dp/3._dp
4039 [ # # # # ]: 0 : if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
4040 : : write(msg, '(a,a,a,3i6,a,a,a,a)' )&
4041 : 0 : 'In the FCC case, the three ngqpt numbers ',ch10,&
4042 : 0 : ' ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
4043 : 0 : 'should be equal.',ch10,&
4044 : 0 : 'Action: use identical ngqpt(1:3) in your input file.'
4045 : 0 : ABI_ERROR(msg)
4046 : : end if
4047 [ # # ]: 0 : do ii=4,7
4048 : 0 : ngqpt(ii)=ngqpt(1)
4049 : : end do
4050 : :
4051 : : ! Test the relevant inequalities
4052 : 0 : nbord(1)=0
4053 [ # # ]: 0 : do ii=1,7
4054 : : ! If the rpt vector is greater than the allowed space => weight = 0.0
4055 [ # # ]: 0 : if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
4056 : 0 : wghatm(ia,ib,irpt)=zero
4057 : : ! If the point is in a boundary position increment nbord(1)
4058 [ # # ]: 0 : else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4059 : 0 : nbord(1)=nbord(1)+1
4060 : : end if
4061 : : end do
4062 : :
4063 : : ! Computation of weights
4064 [ # # ]: 0 : if (nbord(1)==1) then
4065 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4066 [ # # ]: 0 : else if (nbord(1)==2) then
4067 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
4068 [ # # ]: 0 : else if (nbord(1)==3) then
4069 : 0 : wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
4070 [ # # # # ]: 0 : else if (nbord(1)/=0 .and. wghatm(ia,ib,irpt)>1.d-10) then
4071 : : ! Interestingly nbord(1)==4 happens for some points outside of the volume
4072 : 0 : ABI_BUG(' There is a problem of borders and weights (FCC).')
4073 : : end if
4074 : :
4075 : : else
4076 : : write(msg, '(3a,i0,a)' )&
4077 : 0 : 'One should not arrive here ... ',ch10,&
4078 : 0 : 'The value nqshft ',nqshft,' is not available'
4079 : 0 : ABI_BUG(msg)
4080 : : end if
4081 : : end do ! Assignement of weights is done
4082 : : end do ! End of the double loop on ia and ib
4083 : : end do
4084 : :
4085 : : ! Check the results
4086 [ # # ]: 0 : do ia=1,natom
4087 [ # # ]: 0 : do ib=1,natom
4088 : : sumwght=zero
4089 [ # # ]: 0 : do irpt=1,nrpt
4090 : : ! Check if the sum of the weights is equal to the number of q points
4091 : 0 : sumwght=sumwght+wghatm(ia,ib,irpt)
4092 : : !write(std_out,'(a,3(i0,1x))' )' atom1, atom2, irpt ; rpt ; wghatm ',ia,ib,irpt
4093 : : !write(std_out,'(3es16.6,es18.6)' )rpt(1,irpt),rpt(2,irpt),rpt(3,irpt),wghatm(ia,ib,irpt)
4094 : : end do
4095 [ # # ]: 0 : if (abs(sumwght-nqpt)>tol10) ierr = 1
4096 : : end do
4097 : : end do
4098 : :
4099 : 0 : end subroutine wght9
4100 : : !!***
4101 : :
4102 : : !----------------------------------------------------------------------
4103 : :
4104 : : !!****f* m_dynmat/d3sym
4105 : : !! NAME
4106 : : !! d3sym
4107 : : !!
4108 : : !! FUNCTION
4109 : : !! Given a set of calculated elements of the 3DTE matrix,
4110 : : !! build (nearly) all the other matrix elements that can be build using symmetries.
4111 : : !!
4112 : : !! INPUTS
4113 : : !! indsym(4,nsym,natom)=indirect indexing array : for each
4114 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
4115 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
4116 : : !! translations which must be subtracted after the transformation to get back
4117 : : !! to the original unit cell.
4118 : : !! mpert =maximum number of ipert
4119 : : !! natom= number of atoms
4120 : : !! nsym=number of space group symmetries
4121 : : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
4122 : : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
4123 : : !!
4124 : : !! SIDE EFFECTS
4125 : : !! Input/Output
4126 : : !! blkflg(3,mpert,3,mpert,3,mpert)= matrix that indicates if an
4127 : : !! element of d3 is available (1 if available, 0 otherwise)
4128 : : !! d3(2,3,mpert,3,mpert,3,mpert)= matrix of the 3DTE
4129 : : !!
4130 : : !! SOURCE
4131 : :
4132 : 41 : subroutine d3sym(blkflg,d3,indsym,mpert,natom,nsym,symrec,symrel)
4133 : :
4134 : : !Arguments -------------------------------
4135 : : !scalars
4136 : : integer,intent(in) :: mpert,natom,nsym
4137 : : !arrays
4138 : : integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4139 : : integer,intent(inout) :: blkflg(3,mpert,3,mpert,3,mpert)
4140 : : real(dp),intent(inout) :: d3(2,3,mpert,3,mpert,3,mpert)
4141 : :
4142 : : !Local variables -------------------------
4143 : : !scalars
4144 : : integer :: found,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert,idisy1,idisy2,idisy3
4145 : : integer :: ipesy1,ipesy2,ipesy3,isym,ithree
4146 : : real(dp) :: sumi,sumr
4147 : : !arrays
4148 : : integer :: sym1(3,3),sym2(3,3),sym3(3,3)
4149 : : ! *********************************************************************
4150 : :
4151 : : !DEBUG
4152 : : !write(std_out,*)'d3sym : enter'
4153 : : !do i1dir = 1, 3
4154 : : !do i2dir = 1, 3
4155 : : !do i3dir = 1, 3
4156 : : !write(std_out,*)i1dir,i2dir,i3dir,blkflg(i1dir,natom+2,i2dir,natom+2,i3dir,natom+2)
4157 : : !end do
4158 : : !end do
4159 : : !end do
4160 : : !stop
4161 : : !ENDDEBUG
4162 : :
4163 : : !First, take into account the permutations symmetry of
4164 : : !(i1pert,i1dir) and (i3pert,i3dir)
4165 [ + + ]: 397 : do i1pert = 1, mpert
4166 [ + + ]: 3665 : do i2pert = 1, mpert
4167 [ + + ]: 36068 : do i3pert = 1, mpert
4168 : :
4169 [ + + ]: 133044 : do i1dir = 1, 3
4170 [ + + ]: 421772 : do i2dir = 1, 3
4171 [ + + ]: 1265316 : do i3dir = 1, 3
4172 : :
4173 [ + + + + ]: 875988 : if ((blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1).and. &
4174 : 291996 : & (blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert)/=1)) then
4175 : :
4176 : : d3(:,i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = &
4177 [ + + ]: 3711 : & d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
4178 : :
4179 : 1237 : blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = 1
4180 : :
4181 : : end if
4182 : :
4183 : : end do
4184 : : end do
4185 : : end do
4186 : :
4187 : : end do
4188 : : end do
4189 : : end do
4190 : :
4191 : : !Big Big Loop : symmetrize three times, because
4192 : : !of some cases in which one element is not yet available
4193 : : !at the first pass, and even at the second one !
4194 : :
4195 [ + + ]: 164 : do ithree=1,3
4196 : :
4197 : : ! Loop over perturbations
4198 [ + + ]: 1232 : do i1pert = 1, mpert
4199 [ + + ]: 10995 : do i2pert = 1, mpert
4200 [ + + ]: 108204 : do i3pert = 1, mpert
4201 : :
4202 [ + + ]: 399132 : do i1dir = 1, 3
4203 [ + + ]: 1265316 : do i2dir = 1, 3
4204 [ + + ]: 3795948 : do i3dir = 1, 3
4205 : :
4206 : : ! Will get element (idir1,ipert1,idir2,ipert2)
4207 : : ! so this element should not yet be present ...
4208 [ + + ]: 3503952 : if(blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)/=1)then
4209 : :
4210 [ + + ]: 7831485 : d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 0_dp
4211 : :
4212 [ + + ]: 47609064 : do isym = 1, nsym
4213 : :
4214 : 44998569 : found = 1
4215 : :
4216 [ + + ]: 44998569 : if (i1pert <= natom) then
4217 : 8178639 : ipesy1 = indsym(4,isym,i1pert)
4218 [ + + + + ]: 106322307 : sym1(:,:) = symrec(:,:,isym)
4219 [ + + ]: 36819930 : else if (i1pert == natom + 2) then
4220 : 3953370 : ipesy1 = i1pert
4221 [ + + + + ]: 51393810 : sym1(:,:) = symrel(:,:,isym)
4222 : : else
4223 : : found = 0
4224 : : end if
4225 : :
4226 [ + + ]: 44998569 : if (i2pert <= natom) then
4227 : 8178639 : ipesy2 = indsym(4,isym,i2pert)
4228 [ + + + + ]: 106322307 : sym2(:,:) = symrec(:,:,isym)
4229 [ + + ]: 36819930 : else if (i2pert == natom + 2) then
4230 : 3953370 : ipesy2 = i2pert
4231 [ + + + + ]: 51393810 : sym2(:,:) = symrel(:,:,isym)
4232 : : else
4233 : : found = 0
4234 : : end if
4235 : :
4236 [ + + ]: 44998569 : if (i3pert <= natom) then
4237 : 8178639 : ipesy3 = indsym(4,isym,i3pert)
4238 [ + + + + ]: 106322307 : sym3(:,:) = symrec(:,:,isym)
4239 [ + + ]: 36819930 : else if (i3pert == natom + 2) then
4240 : 3953370 : ipesy3 = i3pert
4241 [ + + + + ]: 51393810 : sym3(:,:) = symrel(:,:,isym)
4242 : : else
4243 : : found = 0
4244 : : end if
4245 : :
4246 : 44998569 : sumr = 0_dp ; sumi = 0_dp;
4247 [ + + ]: 179994276 : do idisy1 = 1, 3
4248 [ + + ]: 584981397 : do idisy2 = 1, 3
4249 [ + + ]: 1754944191 : do idisy3 = 1, 3
4250 : :
4251 : : if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir,idisy2) /=0) &
4252 [ + + + + : 1619948484 : & .and.(sym3(i3dir,idisy3) /=0)) then
+ + ]
4253 : :
4254 [ + + ]: 189920457 : if (blkflg(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 1) then
4255 : :
4256 : : sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4257 : 144869984 : & sym3(i3dir,idisy3)*d3(1,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4258 : : sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4259 : 144869984 : & sym3(i3dir,idisy3)*d3(2,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4260 : :
4261 : : else
4262 : :
4263 : : found = 0
4264 : :
4265 : : end if
4266 : :
4267 : : end if
4268 : :
4269 : : end do
4270 : : end do
4271 : : end do
4272 : :
4273 [ + + ]: 47609064 : if (found == 1) then
4274 : 18245 : d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumr
4275 : 18245 : d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumi
4276 : 18245 : blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4277 : : end if
4278 : :
4279 : : end do ! isym
4280 : :
4281 : : end if ! blkflg
4282 : :
4283 : : ! Close loop over perturbations
4284 : : end do
4285 : : end do
4286 : : end do
4287 : : end do
4288 : : end do
4289 : : end do
4290 : :
4291 : : end do ! close loop over ithree
4292 : :
4293 : 41 : end subroutine d3sym
4294 : : !!***
4295 : :
4296 : : !----------------------------------------------------------------------
4297 : :
4298 : : !!****f* m_dynmat/sytens
4299 : : !!
4300 : : !! NAME
4301 : : !! sytens
4302 : : !!
4303 : : !! FUNCTION
4304 : : !! Determines the set of irreductible elements of the non-linear
4305 : : !! optical susceptibility and Raman tensors
4306 : : !!
4307 : : !! INPUTS
4308 : : !! indsym(4,nsym,natom)=indirect indexing array described above: for each
4309 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
4310 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
4311 : : !! translations which must be subtracted after the transformation to get back
4312 : : !! to the original unit cell.
4313 : : !! mpert =maximum number of ipert
4314 : : !! natom= number of atoms
4315 : : !! nsym=number of space group symmetries
4316 : : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
4317 : : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
4318 : : !!
4319 : : !! OUTPUT
4320 : : !! (see side effects)
4321 : : !!
4322 : : !! SIDE EFFECTS
4323 : : !! rfpert(3,mpert,3,mpert,3,mpert) = array defining the type of perturbations
4324 : : !! that have to be computed
4325 : : !! At the input :
4326 : : !! 1 -> element has to be computed explicitely
4327 : : !! At the output :
4328 : : !! 1 -> element has to be computed explicitely
4329 : : !! -1 -> use symmetry operations to obtain the corresponding element
4330 : : !! -2 -> element is zero by symmetry
4331 : : !!
4332 : : !! SOURCE
4333 : :
4334 : 46 : subroutine sytens(indsym,mpert,natom,nsym,rfpert,symrec,symrel)
4335 : :
4336 : : !Arguments -------------------------------
4337 : : !scalars
4338 : : integer,intent(in) :: mpert,natom,nsym
4339 : : !arrays
4340 : : integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4341 : : integer,intent(inout) :: rfpert(3,mpert,3,mpert,3,mpert)
4342 : :
4343 : : !Local variables -------------------------
4344 : : !scalars
4345 : : integer :: flag,found,i1dir,i1dir_,i1pert,i1pert_,i2dir,i2dir_,i2pert,i2pert_
4346 : : integer :: i3dir,i3dir_,i3pert,i3pert_,idisy1,idisy2,idisy3,ipesy1,ipesy2
4347 : : integer :: ipesy3,isym
4348 : : !arrays
4349 : : integer :: sym1(3,3),sym2(3,3),sym3(3,3)
4350 : 46 : integer,allocatable :: pertsy(:,:,:,:,:,:)
4351 : : !***********************************************************************
4352 : :
4353 [ - + + - : 322 : ABI_MALLOC(pertsy,(3,mpert,3,mpert,3,mpert))
+ - - + +
- + - - +
+ - + - +
- - + +
- ]
4354 [ + + + + : 1070750 : pertsy(:,:,:,:,:,:) = 0
+ + + + +
+ + + ]
4355 : :
4356 : : !Loop over perturbations
4357 : :
4358 [ + + ]: 386 : do i1pert_ = 1, mpert
4359 [ + + ]: 3302 : do i2pert_ = 1, mpert
4360 [ + + ]: 31988 : do i3pert_ = 1, mpert
4361 : :
4362 [ + + ]: 117844 : do i1dir_ = 1, 3
4363 [ + + ]: 373516 : do i2dir_ = 1, 3
4364 [ + + ]: 1120548 : do i3dir_ = 1, 3
4365 : :
4366 : 775764 : i1pert = (mpert - i1pert_ + 1)
4367 [ + + ]: 775764 : if (i1pert <= natom) i1pert = natom + 1 - i1pert
4368 : 775764 : i2pert = (mpert - i2pert_ + 1)
4369 [ + + ]: 775764 : if (i2pert <= natom) i2pert = natom + 1 - i2pert
4370 : 775764 : i3pert = (mpert - i3pert_ + 1)
4371 [ + + ]: 775764 : if (i3pert <= natom) i3pert = natom + 1 - i3pert
4372 : :
4373 [ + + ]: 775764 : if (i1pert <= natom) then
4374 : : i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
4375 [ + + ]: 618300 : else if (i2pert <= natom) then
4376 : : i1dir = i2dir_ ; i2dir = i1dir_ ; i3dir = i3dir_
4377 [ + + ]: 497556 : else if (i3pert <= natom) then
4378 : : i1dir = i3dir_ ; i2dir = i2dir_ ; i3dir = i1dir_
4379 : : else
4380 : 561060 : i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
4381 : : end if
4382 : :
4383 [ + + ]: 1034352 : if (rfpert(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) /= 0) then
4384 : :
4385 : : ! Loop over all symmetries
4386 : :
4387 : : flag = 0
4388 [ + + ]: 118983 : do isym = 1, nsym
4389 : :
4390 : 113997 : found = 1
4391 : :
4392 : : ! Select the symmetric element of i1pert,i2pert,i3pert
4393 : :
4394 [ + + ]: 113997 : if (i1pert <= natom) then
4395 : 31603 : ipesy1 = indsym(4,isym,i1pert)
4396 [ + + + + ]: 410839 : sym1(:,:) = symrec(:,:,isym)
4397 [ + - ]: 82394 : else if (i1pert == natom + 2) then
4398 : 82394 : ipesy1 = i1pert
4399 [ + + + + ]: 1071122 : sym1(:,:) = symrel(:,:,isym)
4400 : : else
4401 : : found = 0
4402 : : end if
4403 : :
4404 [ + + ]: 113997 : if (i2pert <= natom) then
4405 : 31603 : ipesy2 = indsym(4,isym,i2pert)
4406 [ + + + + ]: 410839 : sym2(:,:) = symrec(:,:,isym)
4407 [ + - ]: 82394 : else if (i2pert == natom + 2) then
4408 : 82394 : ipesy2 = i2pert
4409 [ + + + + ]: 1071122 : sym2(:,:) = symrel(:,:,isym)
4410 : : else
4411 : : found = 0
4412 : : end if
4413 : :
4414 [ + + ]: 113997 : if (i3pert <= natom) then
4415 : 31603 : ipesy3 = indsym(4,isym,i3pert)
4416 [ + + + + ]: 410839 : sym3(:,:) = symrec(:,:,isym)
4417 [ + - ]: 82394 : else if (i3pert == natom + 2) then
4418 : 82394 : ipesy3 = i3pert
4419 [ + + + + ]: 1071122 : sym3(:,:) = symrel(:,:,isym)
4420 : : else
4421 : : found = 0
4422 : : end if
4423 : :
4424 : : ! See if the symmetric element is available and check if some
4425 : : ! of the elements may be zeor. In the latter case, they do not need
4426 : : ! to be computed.
4427 : :
4428 : :
4429 : : if ((flag /= -1).and.&
4430 [ + - + - ]: 113997 : & (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
4431 : 113997 : flag = sym1(i1dir,i1dir)*sym2(i2dir,i2dir)*sym3(i3dir,i3dir)
4432 : : end if
4433 : :
4434 : :
4435 [ + + ]: 455988 : do idisy1 = 1, 3
4436 [ + + ]: 1481961 : do idisy2 = 1, 3
4437 [ + + ]: 4445883 : do idisy3 = 1, 3
4438 : :
4439 [ + + + + : 3077919 : if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir,idisy2) /= 0).and.&
+ + ]
4440 : : & (sym3(i3dir,idisy3) /= 0)) then
4441 [ + + ]: 394809 : if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
4442 : 3077919 : found = 0
4443 : : ! exit ! exit loop over symmetries
4444 : : end if
4445 : : end if
4446 : :
4447 : :
4448 [ + + + + : 3077919 : if ((flag == -1).and.&
+ + ]
4449 : 1025973 : & ((idisy1/=i1dir).or.(idisy2/=i2dir).or.(idisy3/=i3dir))) then
4450 [ + + + + : 127890 : if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir,idisy2)/=0).and.&
+ + ]
4451 : : & (sym3(i3dir,idisy3)/=0)) then
4452 : 3077919 : flag = 0
4453 : : end if
4454 : : end if
4455 : :
4456 : : end do
4457 : : end do
4458 : : end do
4459 : :
4460 [ + + ]: 113997 : if (found == 1) then
4461 : 42006 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -1
4462 : : end if
4463 : :
4464 : : ! In case a symmetry operation only changes the sign of an
4465 : : ! element, this element has to be equal to zero
4466 : :
4467 [ + + ]: 118983 : if (flag == -1) then
4468 : 2228 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -2
4469 : 2228 : exit
4470 : : end if
4471 : :
4472 : : end do ! close loop on symmetries
4473 : :
4474 : : ! If the elemetn i1pert,i2pert,i3pert is not symmetric
4475 : : ! to a basis element, it is a basis element
4476 : :
4477 [ + + ]: 7214 : if (pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) > -1) then
4478 : 2239 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4479 : : end if
4480 : :
4481 : : end if ! rfpert /= 0
4482 : :
4483 : : end do ! close loop over perturbations
4484 : : end do
4485 : : end do
4486 : : end do
4487 : : end do
4488 : : end do
4489 : :
4490 : : !Now, take into account the permutation of (i1pert,i1dir)
4491 : : !and (i3pert,i3dir)
4492 : :
4493 [ + + ]: 386 : do i1pert = 1, mpert
4494 [ + + ]: 3302 : do i2pert = 1, mpert
4495 [ + + ]: 31988 : do i3pert = 1, mpert
4496 : :
4497 [ + + ]: 117844 : do i1dir = 1, 3
4498 [ + + ]: 373516 : do i2dir = 1, 3
4499 [ + + ]: 1120548 : do i3dir = 1, 3
4500 : :
4501 [ + + ]: 1034352 : if ((i1pert /= i3pert).or.(i1dir /= i3dir)) then
4502 : :
4503 [ + + + + ]: 749520 : if ((pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) == 1).and.&
4504 : : & (pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) == 1)) then
4505 : 899 : pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = -1
4506 : : end if
4507 : :
4508 : : end if
4509 : :
4510 : : end do
4511 : : end do
4512 : : end do
4513 : :
4514 : : end do
4515 : : end do
4516 : : end do
4517 : :
4518 [ + + + + : 1070750 : rfpert(:,:,:,:,:,:) = pertsy(:,:,:,:,:,:)
+ + + + +
+ + + ]
4519 : :
4520 [ - + ]: 46 : ABI_FREE(pertsy)
4521 : :
4522 : 46 : end subroutine sytens
4523 : : !!***
4524 : :
4525 : :
4526 : : !----------------------------------------------------------------------
4527 : :
4528 : : !!****f* m_dynmat/axial9
4529 : : !!
4530 : : !! NAME
4531 : : !! axial9
4532 : : !!
4533 : : !! FUNCTION
4534 : : !! Generates the local coordinates system from the
4535 : : !! knowledge of the first vector (longitudinal) and
4536 : : !! the ifc matrix in cartesian coordinates
4537 : : !!
4538 : : !! INPUTS
4539 : : !! ifccar(3,3)= matrix of interatomic force constants in cartesian coordinates
4540 : : !! vect1(3)= cartesian coordinates of the first local vector
4541 : : !!
4542 : : !! OUTPUT
4543 : : !! vect2(3)= cartesian coordinates of the second local vector
4544 : : !! vect3(3)= cartesian coordinates of the third local vector
4545 : : !!
4546 : : !! SOURCE
4547 : :
4548 : 20196 : subroutine axial9(ifccar,vect1,vect2,vect3)
4549 : :
4550 : : !Arguments -------------------------------
4551 : : !arrays
4552 : : real(dp),intent(in) :: ifccar(3,3),vect1(3)
4553 : : real(dp),intent(out) :: vect2(3),vect3(3)
4554 : :
4555 : : !Local variables -------------------------
4556 : : !scalars
4557 : : integer :: flag,ii,itrial
4558 : : real(dp) :: innorm,scprod
4559 : : !arrays
4560 : : real(dp) :: work(3)
4561 : : ! *********************************************************************
4562 : :
4563 [ + + + + ]: 262548 : work (:) = matmul(ifccar,vect1)
4564 : :
4565 : : flag=0
4566 [ + - ]: 49015 : do itrial=1,4
4567 : : scprod=zero
4568 [ + + ]: 196060 : do ii=1,3
4569 : 196060 : scprod=scprod+work(ii)*vect1(ii)
4570 : : end do
4571 : :
4572 [ + + ]: 196060 : work(:)=work(:)-vect1(:)*scprod
4573 : :
4574 [ + + ]: 196060 : scprod=dot_product(work,work)
4575 : :
4576 [ + + ]: 49015 : if(scprod<1.0d-10)then
4577 : 28819 : work(1:3)=zero
4578 [ + + ]: 28819 : if(itrial>1)work(itrial-1)=1.0_dp
4579 : : else
4580 : : flag=1
4581 : : end if
4582 : :
4583 : 0 : if(flag==1)exit
4584 : : end do
4585 : :
4586 : 20196 : innorm=scprod**(-0.5_dp)
4587 [ + + ]: 80784 : vect2(:)=work(:)*innorm
4588 : :
4589 : 20196 : vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
4590 : 20196 : vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
4591 : 20196 : vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
4592 : :
4593 : 20196 : end subroutine axial9
4594 : : !!***
4595 : :
4596 : : !----------------------------------------------------------------------
4597 : :
4598 : : !!****f* m_dynmat/dymfz9
4599 : : !!
4600 : : !! NAME
4601 : : !! dymfz9
4602 : : !!
4603 : : !! FUNCTION
4604 : : !! As the subroutine canatm has transformed the coordinates of the
4605 : : !! atoms in normalized canonical coordinates, the corresponding
4606 : : !! dynamical matrix should be multiplied by a phase shift corresponding
4607 : : !! to the translation between New and Old coordinates of its two
4608 : : !! corresponding atoms.
4609 : : !!
4610 : : !! INPUTS
4611 : : !! dynmat = non-phase shifted dynamical matrices
4612 : : !! natom = number of atoms
4613 : : !! nqpt = number of qpoints
4614 : : !! gprim = reciprocal lattice vectors (cartesian but dimensionless)
4615 : : !! option=1 : the matrices are transformed from the old (tn)
4616 : : !! coordinate system to the new (normalized canonical)
4617 : : !! 2 : the matrices are restored from the normalized
4618 : : !! canonical coordinate system to the usual (tn) one...
4619 : : !! rcan = canonical coordinates of atoms
4620 : : !! spqpt = qpoint coordinates (reduced reciprocal)
4621 : : !! trans = Atomic translations : xred = rcan + trans
4622 : : !!
4623 : : !! OUTPUT
4624 : : !! dynmat = phase shifted dynamical matrices
4625 : : !!
4626 : : !! SOURCE
4627 : :
4628 : 586374 : subroutine dymfz9(dynmat,natom,nqpt,gprim,option,spqpt,trans)
4629 : :
4630 : : !Arguments -------------------------------
4631 : : !scalars
4632 : : integer,intent(in) :: natom,nqpt,option
4633 : : !arrays
4634 : : real(dp),intent(in) :: gprim(3,3),spqpt(3,nqpt),trans(3,natom)
4635 : : real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
4636 : :
4637 : : !Local variables -------------------------
4638 : : !scalars
4639 : : integer :: ia,ib,iqpt,mu,nu
4640 : : real(dp) :: im,re,phase_re,phase_im
4641 : : !arrays
4642 : : real(dp) :: kk(3)
4643 : : ! *********************************************************************
4644 : :
4645 [ + + ]: 1185527 : do iqpt=1,nqpt
4646 : : ! Definition of q in normalized reciprocal space
4647 [ + + + + ]: 7788989 : kk(:) = matmul(gprim, spqpt(:, iqpt))
4648 : :
4649 : :
4650 [ + + ]: 599153 : if(option==1)then
4651 [ + + ]: 51920 : kk(:)=-kk(:)
4652 : : end if
4653 : :
4654 [ + + ]: 2318879 : do ia=1,natom
4655 [ + + ]: 4462491 : do ib=1,natom
4656 : : ! Phase factor associated with the differences between the two atomic translations
4657 [ + + ]: 10919944 : call ifc_atom_phase(kk, trans(:,ia)-trans(:,ib), phase_re, phase_im)
4658 [ + + ]: 12053296 : do mu=1,3
4659 [ + + ]: 35489818 : do nu=1,3
4660 : 24569874 : re=dynmat(1,mu,ia,nu,ib,iqpt)
4661 : 24569874 : im=dynmat(2,mu,ia,nu,ib,iqpt)
4662 : : ! Transformation of the Old dynamical matrices by New ones by multiplication by a phase shift
4663 : 24569874 : dynmat(1,mu,ia,nu,ib,iqpt)=re*phase_re-im*phase_im
4664 : 32759832 : dynmat(2,mu,ia,nu,ib,iqpt)=re*phase_im+im*phase_re
4665 : : end do
4666 : : end do
4667 : : end do
4668 : : end do
4669 : : end do
4670 : :
4671 : 586374 : end subroutine dymfz9
4672 : : !!***
4673 : :
4674 : : !----------------------------------------------------------------------
4675 : :
4676 : : !!****f* m_dynmat/ifc_atom_phase
4677 : : !! NAME
4678 : : !! ifc_atom_phase
4679 : : !!
4680 : : !! FUNCTION
4681 : : !! Phase factor e^{i 2pi k.dtau} associated with a dynamical-matrix element
4682 : : !! D(q)_{ia,ib}, where dtau is the difference between the (real-space,
4683 : : !! reduced-coordinate-like) positions of the two atoms ia, ib -- i.e. the
4684 : : !! atom-position phase e^{i q.(tau_i - tau_j)} that converts between the
4685 : : !! two conventions for the Fourier transform of the dynamical matrix
4686 : : !! discussed by Gonze & Lee, PRB 55, 10355 (1997) [[cite:Gonze1997a]]: one
4687 : : !! using only the lattice-vector part of the atom separation (as
4688 : : !! ftifc_q2r/ftifc_r2q do), the other using the full atom-to-atom
4689 : : !! separation. This is exactly dymfz9's per-atom-pair building block,
4690 : : !! factored out so the same phase-factor computation is not duplicated at
4691 : : !! its other call sites (e.g. m_lwf.F90's lattice-Wannier-function gauge).
4692 : : !!
4693 : : !! INPUTS
4694 : : !! k(3) = wavevector, already expressed in the coordinate system dual to
4695 : : !! dtau (e.g. gprim.qpt, as computed by dymfz9's caller; the two must be
4696 : : !! in mutually consistent units so that k.dtau is a dimensionless phase
4697 : : !! divided by 2pi -- this routine does not perform any basis conversion)
4698 : : !! dtau(3) = atom-position difference tau_i - tau_j
4699 : : !!
4700 : : !! OUTPUT
4701 : : !! phase_re, phase_im = real and imaginary parts of e^{i 2pi k.dtau}
4702 : : !!
4703 : : !! SOURCE
4704 : :
4705 : 2730946 : pure subroutine ifc_atom_phase(k, dtau, phase_re, phase_im)
4706 : :
4707 : : !Arguments -------------------------------
4708 : : !arrays
4709 : : real(dp),intent(in) :: k(3), dtau(3)
4710 : : real(dp),intent(out) :: phase_re, phase_im
4711 : :
4712 : : !Local variables -------------------------
4713 : : !scalars
4714 : : real(dp) :: kdtau
4715 : : ! *********************************************************************
4716 : :
4717 : 2730946 : kdtau = k(1)*dtau(1) + k(2)*dtau(2) + k(3)*dtau(3)
4718 : 2730946 : phase_re = cos(two_pi*kdtau)
4719 : 2730946 : phase_im = sin(two_pi*kdtau)
4720 : :
4721 : 2730946 : end subroutine ifc_atom_phase
4722 : : !!***
4723 : :
4724 : : !----------------------------------------------------------------------
4725 : :
4726 : : !!****f* m_dynmat/nanal9
4727 : : !!
4728 : : !! NAME
4729 : : !! nanal9
4730 : : !!
4731 : : !! FUNCTION
4732 : : !! If plus=0 then substracts the non-analytical part from one dynamical
4733 : : !! matrices, with number iqpt.
4734 : : !! If plus=1 then adds the non-analytical part to the dynamical
4735 : : !! matrices, with number iqpt.
4736 : : !!
4737 : : !! For plus=0, see Eq.(76) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
4738 : : !! get the left hand side.
4739 : : !!
4740 : : !! INPUTS
4741 : : !! dyew(2,3,natom,3,natom)= Non-analytical part
4742 : : !! natom= Number of atoms in the unit cell
4743 : : !! iqpt= Referenced q point for the dynamical matrix
4744 : : !! nqpt= Number of q points
4745 : : !! plus= (see above)
4746 : : !!
4747 : : !! OUTPUT
4748 : : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
4749 : : !!
4750 : : !! SOURCE
4751 : :
4752 : 74804 : subroutine nanal9(dyew,dynmat,iqpt,natom,nqpt,plus)
4753 : :
4754 : : !Arguments -------------------------------
4755 : : !scalars
4756 : : integer,intent(in) :: iqpt,natom,nqpt,plus
4757 : : !arrays
4758 : : real(dp),intent(in) :: dyew(2,3,natom,3,natom)
4759 : : real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
4760 : :
4761 : : !Local variables -------------------------
4762 : : !scalars
4763 : : integer :: ia,ib,mu,nu
4764 : : character(len=500) :: msg
4765 : : ! *********************************************************************
4766 : :
4767 [ + + ]: 74804 : if (plus==0) then
4768 : :
4769 [ + + ]: 50715 : do ia=1,natom
4770 [ + + ]: 213548 : do ib=1,natom
4771 [ + + ]: 690463 : do mu=1,3
4772 [ + + ]: 2116829 : do nu=1,3
4773 : : ! The following four lines are OK
4774 : 1465497 : dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) - dyew(1,mu,ia,nu,ib)
4775 : 1953996 : dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) - dyew(2,mu,ia,nu,ib)
4776 : : end do
4777 : : end do
4778 : : end do
4779 : : end do
4780 : :
4781 [ + - ]: 63220 : else if (plus==1) then
4782 [ + + ]: 223272 : do ia=1,natom
4783 [ + + ]: 792728 : do ib=1,natom
4784 [ + + ]: 2437876 : do mu=1,3
4785 [ + + ]: 7402928 : do nu=1,3
4786 : 5125104 : dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) + dyew(1,mu,ia,nu,ib)
4787 : 6833472 : dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) + dyew(2,mu,ia,nu,ib)
4788 : : end do
4789 : : end do
4790 : : end do
4791 : : end do
4792 : :
4793 : : else
4794 : : write(msg,'(3a,i0,a)' )&
4795 : 0 : 'The argument "plus" must be equal to 0 or 1.',ch10,&
4796 : 0 : 'The value: ',plus,' is not available.'
4797 : 0 : ABI_BUG(msg)
4798 : : end if
4799 : :
4800 : 74804 : end subroutine nanal9
4801 : : !!***
4802 : :
4803 : : !----------------------------------------------------------------------
4804 : :
4805 : : !!****f* m_dynmat/gtdyn9
4806 : : !!
4807 : : !! NAME
4808 : : !! gtdyn9
4809 : : !!
4810 : : !! FUNCTION
4811 : : !! Generates a dynamical matrix from interatomic force
4812 : : !! constants and long-range electrostatic interactions.
4813 : : !!
4814 : : !! INPUTS
4815 : : !! atmfrc(3,natom,3,natom,nrpt) = Interatomic Forces in real space
4816 : : !! dielt(3,3) = dielectric tensor
4817 : : !! dipdip= if 0, no dipole-dipole interaction was subtracted in atmfrc
4818 : : !! if 1, atmfrc has been build without dipole-dipole part
4819 : : !! dyewq0(3,3,natom)= Ewald part of the dynamical matrix, at q=0.
4820 : : !! gmet(3,3)= metric tensor in reciprocal space.
4821 : : !! gprimd(3,3)= dimensional primitive translations in reciprocal space (bohr^-1)
4822 : : !! mpert =maximum number of ipert
4823 : : !! natom= Number of atoms in the unit cell
4824 : : !! nrpt= Number of R points in the Big Box
4825 : : !! qphnrm= Normalisation coefficient for qpt
4826 : : !! qpt(3)= Reduced coordinates of the q vectors in reciprocal space
4827 : : !! rmet(3,3)= Metric tensor in real space.
4828 : : !! rprimd(3,3)= dimensional primitive translations in real space (bohr)
4829 : : !! rpt(3,nprt)= cartesian coordinates of the R points in the unit cell
4830 : : !! trans(3,natom)= Atomic translations : xred = rcan + trans
4831 : : !! ucvol= unit cell volume
4832 : : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
4833 : : !! xred(3,natom)= relative coords of atoms in unit cell (dimensionless)
4834 : : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
4835 : : !! comm=MPI communicator.
4836 : : !! [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
4837 : : !! [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part
4838 : : !!
4839 : : !! OUTPUT
4840 : : !! d2cart(2,3,mpert,3,mpert)=dynamical matrix obtained for the wavevector qpt (normalized using qphnrm)
4841 : : !! eta: parameter used to split R and G-space summation
4842 : : !!
4843 : : !! SOURCE
4844 : :
4845 : 197574 : subroutine gtdyn9(atmfrc,dielt,dipdip,dyewq0,d2cart,gmet,gprimd,mpert,natom,&
4846 : 197574 : nrpt,qphnrm,qpt,rmet,rprimd,rpt,trans,ucvol,wghatm,xred,zeff,qdrp_cart,ewald_option,eta,comm,&
4847 : : sys_dim,dipquad,quadquad,dielt_env,dielt_thick) ! optional
4848 : :
4849 : : !Arguments -------------------------------
4850 : : !scalars
4851 : : integer,intent(in) :: dipdip,mpert,natom,nrpt,ewald_option,comm,sys_dim
4852 : : real(dp),intent(in) :: qphnrm,ucvol
4853 : : real(dp),optional,intent(in) :: dielt_env
4854 : : integer,optional,intent(in) :: dipquad, quadquad
4855 : : !arrays
4856 : : real(dp), optional,intent(in):: dielt_thick(2)
4857 : : real(dp),intent(in) :: dielt(3,3),gmet(3,3),gprimd(3,3),qpt(3)
4858 : : real(dp),intent(in) :: rmet(3,3),rprimd(3,3),rpt(3,nrpt)
4859 : : real(dp),intent(in) :: trans(3,natom),wghatm(natom,natom,nrpt),xred(3,natom)
4860 : : real(dp),intent(in) :: zeff(3,3,natom)
4861 : : real(dp),intent(in) :: qdrp_cart(3,3,3,natom)
4862 : : real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
4863 : : real(dp),intent(in) :: dyewq0(3,3,natom)
4864 : : real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert), eta
4865 : :
4866 : : !Local variables -------------------------
4867 : : !scalars
4868 : : integer,parameter :: nqpt1 = 1, option2 = 2, sumg0 = 0, plus1 = 1, iqpt1 = 1
4869 : : integer :: i1, i2, ib, nsize, dipquad_, quadquad_
4870 : : !arrays
4871 : : real(dp) :: qphon(3) !, tsec(2)
4872 : 197574 : real(dp),allocatable :: dq(:,:,:,:,:),dyew(:,:,:,:,:)
4873 : : ! *********************************************************************
4874 : :
4875 : : ! Keep track of time spent in gtdyn9
4876 : : !call timab(1750, 1, tsec)
4877 : :
4878 [ - + + - : 987870 : ABI_MALLOC(dq,(2,3,natom,3,natom))
+ - - + +
- + - + -
- + - + ]
4879 : :
4880 : : ! Define quadrupolar options
4881 [ + + ]: 197574 : dipquad_=0; if(present(dipquad)) dipquad_=dipquad
4882 [ + + ]: 197574 : quadquad_=0; if(present(quadquad)) quadquad_=quadquad
4883 : :
4884 : : ! Get the normalized wavevector
4885 [ + + ]: 197574 : if(abs(qphnrm)<1.0d-7)then
4886 : 18502 : qphon(1:3)=zero
4887 : : else
4888 [ + + ]: 716288 : qphon(1:3)=qpt(1:3)/qphnrm
4889 : : end if
4890 : :
4891 : : ! Generate the analytical part from the interatomic forces
4892 : 197574 : call ftifc_r2q(atmfrc, dq, gprimd, natom, nqpt1, nrpt, rpt, qphon, wghatm, comm)
4893 : :
4894 : : ! The analytical dynamical matrix dq has been generated
4895 : : ! in the normalized canonical coordinate system.
4896 : : ! Now, the phase is modified, in order to recover the usual (xred) coordinate of atoms.
4897 : 197574 : call dymfz9(dq,natom,nqpt1,gprimd,option2,qphon,trans)
4898 : :
4899 [ + + + + ]: 197574 : if (dipdip==1.or.dipquad_==1.or.quadquad_==1) then
4900 : : ! Add the non-analytical part
4901 : : ! Compute dyew(2,3,natom,3,natom)= Ewald part of the dynamical matrix,
4902 : : ! second energy derivative wrt xred(3,natom) in Hartrees (Denoted A-bar in the notes)
4903 [ - + + - : 189660 : ABI_MALLOC(dyew,(2,3,natom,3,natom))
- + + - -
+ - + ]
4904 [ + + ]: 63220 : if (sys_dim==1) then ! 3D case
4905 : : call ewald9(dielt,dyew,gmet,gprimd,natom,qphon,rmet,rprimd,sumg0,ucvol,xred,zeff,&
4906 : 62998 : qdrp_cart,eta,option=ewald_option,dipquad=dipquad_,quadquad=quadquad_)
4907 [ + - ]: 222 : elseif (sys_dim<5) then
4908 : 222 : call ewald9_2D(natom,rprimd,xred,dielt,dyew,qpt,zeff,qdrp_cart,dielt_env,dielt_thick,sys_dim)
4909 : : end if
4910 : :
4911 : 63220 : call q0dy3_apply(natom,dyewq0,dyew)
4912 : 63220 : call nanal9(dyew,dq,iqpt1,natom,nqpt1,plus1)
4913 : :
4914 [ - + ]: 63220 : ABI_FREE(dyew)
4915 : : end if
4916 : :
4917 : : ! Copy the dynamical matrix in the proper location
4918 : : ! First zero all the elements
4919 : 197574 : nsize=2*(3*mpert)**2
4920 [ + + + + : 799238072 : d2cart = zero
+ + + + +
+ ]
4921 : :
4922 : : ! Copy the elements from dq to d2cart
4923 [ + + + + : 35411946 : d2cart(:,:,1:natom,:,1:natom)=dq(:,:,1:natom,:,1:natom)
+ + + + +
+ ]
4924 : :
4925 : : ! In case we have the gamma point,
4926 [ + + ]: 197574 : if(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)then
4927 : : ! Copy the effective charge and dielectric constant in the final array
4928 [ + + ]: 77924 : do i1=1,3
4929 [ + + ]: 253253 : do i2=1,3
4930 : 175329 : d2cart(1,i1,natom+2,i2,natom+2)=dielt(i1,i2)
4931 [ + + ]: 587607 : do ib=1,natom
4932 : 353835 : d2cart(1,i1,natom+2,i2,ib)=zeff(i1,i2,ib)
4933 : 529164 : d2cart(1,i2,ib,i1,natom+2)=zeff(i1,i2,ib)
4934 : : end do
4935 : : end do
4936 : : end do
4937 : : end if
4938 : :
4939 [ - + ]: 197574 : ABI_FREE(dq)
4940 : :
4941 : : !call timab(1750, 2, tsec)
4942 : :
4943 : 197574 : end subroutine gtdyn9
4944 : : !!***
4945 : :
4946 : : !----------------------------------------------------------------------
4947 : :
4948 : : !!****f* m_dynmat/dfpt_phfrq
4949 : : !! NAME
4950 : : !! dfpt_phfrq
4951 : : !!
4952 : : !! FUNCTION
4953 : : !! Get the phonon frequencies and eigenvectors (as well as the corresponding displacements)
4954 : : !! If q is at Gamma, the non-analytical behaviour can be included.
4955 : : !! Then, the effective dielectric tensor, the effective charges
4956 : : !! and oscillator strengths for the limiting direction are also returned
4957 : : !!
4958 : : !! INPUTS
4959 : : !! amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
4960 : : !! d2cart(2,3,mpert,3,mpert)=dynamical matrix, effective charges, dielectric tensor,.... all in cartesian coordinates
4961 : : !! indsym(4,msym*natom)=indirect indexing array : for each
4962 : : !! isym,iatom, fourth element is label of atom into which iatom is sent by
4963 : : !! INVERSE of symmetry operation isym; first three elements are the primitive
4964 : : !! translations which must be subtracted after the transformation to get back to the original unit cell.
4965 : : !! mpert =maximum number of ipert
4966 : : !! msym=maximum number of symmetries
4967 : : !! natom=number of atoms in unit cell
4968 : : !! nsym=number of space group symmetries
4969 : : !! ntypat=number of atom types
4970 : : !! qphnrm=(described above)
4971 : : !! qphon(3)= to be divided by qphnrm, give the phonon wavevector;
4972 : : !! if qphnrm==0.0_dp, then the wavevector is zero (Gamma point)
4973 : : !! and qphon gives the direction of the induced electric field in **CARTESIAN** coordinates.
4974 : : !! in the latter case, if qphon is zero, no non-analytical contribution is included.
4975 : : !! rprimd(3,3)=dimensional primitive translations (bohr)
4976 : : !! symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
4977 : : !! symrel(3,3,nsym)=matrices of the group symmetries (real space)
4978 : : !! typat(natom)=integer label of each type of atom (1,2,...)
4979 : : !! ucvol=unit cell volume
4980 : : !!
4981 : : !! OUTPUT
4982 : : !! displ(2*3*natom*3*natom)= at the end, contains the displacements of atoms in cartesian coordinates.
4983 : : !! The first index means either the real or the imaginary part,
4984 : : !! The second index runs on the direction and the atoms displaced
4985 : : !! The third index runs on the modes.
4986 : : !! eigval(3*natom)=contains the eigenvalues of the dynamical matrix
4987 : : !! eigvec(2*3*natom*3*natom)= at the end, contains the eigenvectors of the dynamical matrix in cartesian coordinates.
4988 : : !! phfrq(3*natom)=phonon frequencies (square root of the dynamical matrix eigenvalues,
4989 : : !! except if these are negative, and in this case, give minus the square root of the absolute value
4990 : : !! of the matrix eigenvalues). Hartree units.
4991 : : !!
4992 : : !! NOTES
4993 : : !! 1) One makes the dynamical matrix hermitian...
4994 : : !! 2) In case of q=Gamma, only the real part is used.
4995 : : !! (MR: Modified since at finite omega imaginary components may arise
4996 : : !! also at Gamma in broken time-reversal symmetry crystals)
4997 : : !!
4998 : : !! SOURCE
4999 : :
5000 : 256072 : subroutine dfpt_phfrq(amu,displ,d2cart,eigval,eigvec,indsym,&
5001 : 256072 : & mpert,msym,natom,nsym,ntypat,phfrq,qphnrm,qphon,rprimd,&
5002 : 256072 : & symdynmat,symrel,symafm,typat,ucvol)
5003 : :
5004 : : !Arguments -------------------------------
5005 : : !scalars
5006 : : integer,intent(in) :: mpert,msym,natom,nsym,ntypat,symdynmat
5007 : : real(dp),intent(in) :: qphnrm,ucvol
5008 : : !arrays
5009 : : integer,intent(in) :: indsym(4,msym*natom),symrel(3,3,nsym),typat(natom)
5010 : : integer,intent(in) :: symafm(nsym)
5011 : : real(dp),intent(in) :: amu(ntypat),d2cart(2,3,mpert,3,mpert),rprimd(3,3)
5012 : : real(dp),intent(inout) :: qphon(3)
5013 : : real(dp),intent(out) :: displ(2*3*natom*3*natom),eigval(3*natom)
5014 : : real(dp),intent(out) :: eigvec(2*3*natom*3*natom),phfrq(3*natom)
5015 : :
5016 : : !Local variables -------------------------
5017 : : !scalars
5018 : : integer :: analyt,i1,i2,idir1,idir2,ier,ii,imode,ipert1,ipert2
5019 : : integer :: jmode,indexi,indexj,index
5020 : : real(dp) :: epsq,qphon2
5021 : : logical,parameter :: debug = .False.
5022 : : real(dp) :: sc_prod
5023 : : !arrays
5024 : : real(dp) :: qptn(3),dum(2,0) !, tsec(2)
5025 : 256072 : real(dp),allocatable :: matrx(:,:),zeff(:,:),zhpev1(:,:),zhpev2(:)
5026 : : ! *********************************************************************
5027 : :
5028 : : ! Keep track of time spent in dfpt_phfrq
5029 : : !call timab(1751, 1, tsec)
5030 : :
5031 : : ! GA: I find it strange that both msym and nsym are needed here.
5032 : : ! Moreover, there is an inconsistency in the dimensions of indsym
5033 : : ! when it is passed to symdyma.
5034 : : ! TODO: eliminate msym.
5035 : :
5036 : : ! Prepare the diagonalisation: analytical part.
5037 : : ! Note: displ is used as work space here
5038 : 256072 : i1=0
5039 [ + + ]: 791841 : do ipert1=1,natom
5040 [ + + ]: 2399148 : do idir1=1,3
5041 : 1607307 : i1=i1+1
5042 : 1607307 : i2=0
5043 [ + + ]: 6475583 : do ipert2=1,natom
5044 [ + + ]: 18937335 : do idir2=1,3
5045 : 12997521 : i2=i2+1
5046 : 12997521 : index=i1+3*natom*(i2-1)
5047 : 12997521 : displ(2*index-1)=d2cart(1,idir1,ipert1,idir2,ipert2)
5048 : 17330028 : displ(2*index )=d2cart(2,idir1,ipert1,idir2,ipert2)
5049 : : end do
5050 : : end do
5051 : : end do
5052 : : end do
5053 : :
5054 : : ! Determine the analyticity of the matrix.
5055 [ + + ]: 256072 : analyt=1; if(abs(qphnrm)<tol8) analyt=0
5056 [ + + + + : 256072 : if(abs(qphon(1))<tol8.and.abs(qphon(2))<tol8.and.abs(qphon(3))<tol8) analyt=2
+ + ]
5057 : :
5058 : : ! In case of q=Gamma, only the real part is used
5059 [ + + ]: 256072 : if(analyt==0 .or. analyt==2)then
5060 [ + + ]: 621158 : do i1=1,3*natom
5061 [ + + ]: 4464266 : do i2=1,3*natom
5062 : 3843108 : index=i1+3*natom*(i2-1)
5063 [ + + ]: 4384344 : if (abs(displ(2*index)) < tol14) displ(2*index)=zero
5064 : : end do
5065 : : end do
5066 : : end if
5067 : :
5068 : : ! In the case the non-analyticity is required:
5069 : : ! the tensor is in cartesian coordinates and this means that qphon must be in given in Cartesian coordinates.
5070 [ + + ]: 79922 : if(analyt==0)then
5071 : :
5072 : : ! Normalize the limiting direction
5073 : 78727 : qphon2=qphon(1)**2+qphon(2)**2+qphon(3)**2
5074 [ + + ]: 314908 : qphon(:)=qphon(:)/sqrt(qphon2)
5075 : :
5076 : : ! Get the dielectric constant for the limiting direction
5077 : : epsq=zero
5078 [ + + ]: 314908 : do idir1=1,3
5079 [ + + ]: 1023451 : do idir2=1,3
5080 : 944724 : epsq= epsq + qphon(idir1)*qphon(idir2) * d2cart(1,idir1,natom+2,idir2,natom+2)
5081 : : end do
5082 : : end do
5083 : :
5084 [ - + + - : 236181 : ABI_MALLOC(zeff,(3,natom))
+ - + - -
+ - + ]
5085 : :
5086 : : ! Get the effective charges for the limiting direction
5087 [ + + ]: 314908 : do idir1=1,3
5088 [ + + ]: 847738 : do ipert1=1,natom
5089 : 532830 : zeff(idir1,ipert1)=zero
5090 [ + + ]: 2367501 : do idir2=1,3
5091 : 2131320 : zeff(idir1,ipert1) = zeff(idir1,ipert1) + qphon(idir2)* d2cart(1,idir1,ipert1,idir2,natom+2)
5092 : : end do
5093 : : end do
5094 : : end do
5095 : :
5096 : : ! Get the non-analytical part of the dynamical matrix, and suppress its imaginary part.
5097 : : i1=0
5098 [ + + ]: 256337 : do ipert1=1,natom
5099 [ + + ]: 789167 : do idir1=1,3
5100 : 532830 : i1=i1+1
5101 : 532830 : i2=0
5102 [ + + ]: 1958770 : do ipert2=1,natom
5103 [ + + ]: 5526150 : do idir2=1,3
5104 : 3744990 : i2=i2+1
5105 : 3744990 : index=i1+3*natom*(i2-1)
5106 : 3744990 : displ(2*index-1)=displ(2*index-1)+four_pi/ucvol*zeff(idir1,ipert1)*zeff(idir2,ipert2)/epsq
5107 [ + - ]: 4993320 : if (abs(displ(2*index)) < tol14) displ(2*index)=zero
5108 : : end do
5109 : : end do
5110 : : end do
5111 : : end do
5112 : :
5113 [ - + ]: 78727 : ABI_FREE(zeff)
5114 : : end if ! End of the non-analyticity treatment
5115 : :
5116 : : ! Multiply IFC(q) by masses
5117 : 256072 : call massmult_and_breaksym(natom, ntypat, typat, amu, displ)
5118 : : ! ***********************************************************************
5119 : : ! Diagonalize the dynamical matrix
5120 : :
5121 : : !Symmetrize the dynamical matrix
5122 : : !FIXME: swap the next 2 lines and update test files to include symmetrization
5123 : : ! for Gamma point too (except in non-analytic case)
5124 : : !if (symdynmat==1 .and. analyt > 0) then
5125 [ + + + + ]: 256072 : if (symdynmat==1 .and. analyt == 1) then
5126 : 170657 : qptn(:)=qphon(:)
5127 [ + + ]: 682628 : if (analyt==1) qptn(:)=qphon(:)/qphnrm
5128 : 170657 : call symdyma(displ,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
5129 : : end if
5130 : :
5131 : 256072 : ii=1
5132 [ + - - + : 768216 : ABI_MALLOC(matrx,(2,(3*natom*(3*natom+1))/2))
+ - + - +
- - + -
+ ]
5133 [ + + ]: 1863379 : do i2=1,3*natom
5134 [ + + ]: 9165793 : do i1=1,i2
5135 : 7302414 : matrx(1,ii)=displ(1+2*(i1-1)+2*(i2-1)*3*natom)
5136 : 7302414 : matrx(2,ii)=displ(2+2*(i1-1)+2*(i2-1)*3*natom)
5137 : 8909721 : ii=ii+1
5138 : : end do
5139 : : end do
5140 : :
5141 [ + - - + : 768216 : ABI_MALLOC(zhpev1,(2,2*3*natom-1))
+ - + - +
- - + -
+ ]
5142 [ + - - + : 768216 : ABI_MALLOC(zhpev2,(3*3*natom-2))
+ - + - +
- - + -
+ ]
5143 : :
5144 : 256072 : call ZHPEV ('V','U',3*natom,matrx,eigval,eigvec,3*natom,zhpev1,zhpev2,ier)
5145 [ - + ]: 256072 : ABI_CHECK(ier == 0, sjoin('zhpev returned:', itoa(ier)))
5146 : :
5147 [ - + ]: 256072 : ABI_FREE(matrx)
5148 [ - + ]: 256072 : ABI_FREE(zhpev1)
5149 [ - + ]: 256072 : ABI_FREE(zhpev2)
5150 : :
5151 : : if (debug) then
5152 : : ! Check the orthonormality of the eigenvectors
5153 : : do imode=1,3*natom
5154 : : do jmode=imode,3*natom
5155 : : indexi=2*3*natom*(imode-1)
5156 : : indexj=2*3*natom*(jmode-1)
5157 : : sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
5158 : : write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
5159 : : end do
5160 : : end do
5161 : : end if
5162 : : !***********************************************************************
5163 : :
5164 : : ! Get the phonon frequencies (negative by convention, if the eigenvalue of the dynamical matrix is negative)
5165 [ + + ]: 1863379 : do imode=1,3*natom
5166 [ + + ]: 1863379 : if(eigval(imode)>=1.0d-16)then
5167 : 1405917 : phfrq(imode)=sqrt(eigval(imode))
5168 [ + + ]: 201390 : else if(eigval(imode)>=-1.0d-16)then
5169 : 142723 : phfrq(imode)=zero
5170 : : else
5171 : 58667 : phfrq(imode)=-sqrt(-eigval(imode))
5172 : : end if
5173 : : end do
5174 : :
5175 : : ! Fix the phase of the eigenvectors
5176 : 256072 : call fxphas_seq(eigvec,dum, 0, 0, 1, 3*natom*3*natom, 0, 3*natom, 3*natom, 0)
5177 : :
5178 : : ! Normalise the eigenvectors
5179 : 256072 : call pheigvec_normalize(natom, eigvec)
5180 : :
5181 : : ! Get the phonon displacements
5182 : 256072 : call phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
5183 : :
5184 : : if (debug) then
5185 : : write(std_out,'(a)')' Phonon eigenvectors and displacements '
5186 : : do imode=1,3*natom
5187 : : indexi=2*3*natom*(imode-1)
5188 : : write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' eigvec(1:6*natom)=',eigvec(indexi+1:indexi+6*natom)
5189 : : write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' displ(1:6*natom)=',displ(indexi+1:indexi+6*natom)
5190 : : end do
5191 : :
5192 : : ! Check the orthonormality of the eigenvectors
5193 : : do imode=1,3*natom
5194 : : do jmode=imode,3*natom
5195 : : indexi=2*3*natom*(imode-1)
5196 : : indexj=2*3*natom*(jmode-1)
5197 : : sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
5198 : : write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
5199 : : end do
5200 : : end do
5201 : : end if
5202 : :
5203 : : !call timab(1751, 2, tsec)
5204 : :
5205 : 256072 : end subroutine dfpt_phfrq
5206 : : !!***
5207 : :
5208 : : !----------------------------------------------------------------------
5209 : :
5210 : : !!****f* m_dynmat/pheigvec_normalize
5211 : : !!
5212 : : !! NAME
5213 : : !! pheigvec_normalize
5214 : : !!
5215 : : !! FUNCTION
5216 : : !! Normalize input eigenvectors in cartesian coordinates
5217 : : !!
5218 : : !! INPUTS
5219 : : !! natom: number of atoms in unit cell
5220 : : !!
5221 : : !! SIDE EFFECTS
5222 : : !! eigvec(2*3*natom*3*natom)=in output the normalized eigenvectors in cartesian coordinates.
5223 : : !!
5224 : : !! SOURCE
5225 : :
5226 : 256102 : pure subroutine pheigvec_normalize(natom, eigvec)
5227 : :
5228 : : !Arguments -------------------------------
5229 : : !scalars
5230 : : integer,intent(in) :: natom
5231 : : !arrays
5232 : : real(dp),intent(inout) :: eigvec(2*3*natom*3*natom)
5233 : :
5234 : : !Local variables -------------------------
5235 : : !scalars
5236 : : integer :: i1,idir1,imode,ipert1,index
5237 : : real(dp) :: norm
5238 : : ! *********************************************************************
5239 : :
5240 [ + + ]: 1863949 : do imode=1,3*natom
5241 : :
5242 : : norm=zero
5243 [ + + ]: 6431388 : do idir1=1,3
5244 [ + + ]: 19438629 : do ipert1=1,natom
5245 : 13007241 : i1=idir1+(ipert1-1)*3
5246 : 13007241 : index=i1+3*natom*(imode-1)
5247 : 17830782 : norm=norm+eigvec(2*index-1)**2+eigvec(2*index)**2
5248 : : end do
5249 : : end do
5250 : 1607847 : norm=sqrt(norm)
5251 : :
5252 [ + + ]: 6687490 : do idir1=1,3
5253 [ + + ]: 19438629 : do ipert1=1,natom
5254 : 13007241 : i1=idir1+(ipert1-1)*3
5255 : 13007241 : index=i1+3*natom*(imode-1)
5256 : 13007241 : eigvec(2*index-1)=eigvec(2*index-1)/norm
5257 : 17830782 : eigvec(2*index)=eigvec(2*index)/norm
5258 : : end do
5259 : : end do
5260 : :
5261 : : end do
5262 : :
5263 : 256102 : end subroutine pheigvec_normalize
5264 : : !!***
5265 : :
5266 : : !----------------------------------------------------------------------
5267 : :
5268 : : !!****f* m_dynmat/phdispl_from_eigvec
5269 : : !! NAME
5270 : : !! phdispl_from_eigvec
5271 : : !!
5272 : : !! FUNCTION
5273 : : !! Phonon displacements in cart coords from eigenvectors
5274 : : !!
5275 : : !! INPUTS
5276 : : !! natom: number of atoms in unit cell
5277 : : !! ntypat=number of atom types
5278 : : !! typat(natom)=integer label of each type of atom (1,2,...)
5279 : : !! amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
5280 : : !! eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.
5281 : : !!
5282 : : !! OUTPUT
5283 : : !! displ(2*3*natom*3*natom)=displacements of atoms in cartesian coordinates.
5284 : : !!
5285 : : !! SOURCE
5286 : :
5287 : 262927 : pure subroutine phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
5288 : :
5289 : : !Arguments -------------------------------
5290 : : !scalars
5291 : : integer,intent(in) :: natom, ntypat
5292 : : !arrays
5293 : : integer,intent(in) :: typat(natom)
5294 : : real(dp),intent(in) :: amu(ntypat)
5295 : : real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
5296 : : real(dp),intent(out) :: displ(2*3*natom*3*natom)
5297 : :
5298 : : !Local variables -------------------------
5299 : : !scalars
5300 : : integer :: i1,idir1,imode,ipert1, index
5301 : : ! *********************************************************************
5302 : :
5303 [ + + ]: 1909168 : do imode=1,3*natom
5304 : :
5305 [ + + ]: 6847891 : do idir1=1,3
5306 [ + + ]: 19814901 : do ipert1=1,natom
5307 : 13229937 : i1=idir1+(ipert1-1)*3
5308 : 13229937 : index=i1+3*natom*(imode-1)
5309 : 13229937 : displ(2*index-1)=eigvec(2*index-1) / sqrt(amu(typat(ipert1))*amu_emass)
5310 : 18168660 : displ(2*index )=eigvec(2*index ) / sqrt(amu(typat(ipert1))*amu_emass)
5311 : : end do
5312 : : end do
5313 : :
5314 : : end do
5315 : :
5316 : 262927 : end subroutine phdispl_from_eigvec
5317 : : !!***
5318 : :
5319 : : !!****f* m_dynmat/phangmom_from_eigvec
5320 : : !! NAME
5321 : : !! phangmom_from_eigvec
5322 : : !!
5323 : : !! FUNCTION
5324 : : !! Phonon angular momenta in cart coords from eigenvectors
5325 : : !!
5326 : : !! INPUTS
5327 : : !! natom: number of atoms in unit cell
5328 : : !! eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.
5329 : : !!
5330 : : !! OUTPUT
5331 : : !! phangmom(3*3*natom)= angular momentum of each phonon mode in cartesian coordinates.
5332 : : !! The first index runs on the direction,
5333 : : !! The second index runs on the modes.
5334 : : !!
5335 : : !! SOURCE
5336 : :
5337 : 3178 : pure subroutine phangmom_from_eigvec(natom, eigvec, phangmom)
5338 : :
5339 : : !Arguments -------------------------------
5340 : : !scalars
5341 : : integer,intent(in) :: natom
5342 : : !arrays
5343 : : real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
5344 : : real(dp),intent(out) :: phangmom(3*3*natom)
5345 : :
5346 : : !Local variables -------------------------
5347 : : !scalars
5348 : : integer :: imode,ipert, index
5349 : : !arrays
5350 : : real(dp) :: eigvecatom(2*3)
5351 : : ! *********************************************************************
5352 : :
5353 [ + + ]: 75907 : phangmom = zero
5354 : :
5355 [ + + ]: 27421 : do imode=1,3*natom
5356 [ + + ]: 110704 : do ipert=1,natom
5357 : 83283 : index = 3*natom*(imode-1) + 3*(ipert-1)
5358 [ + + ]: 582981 : eigvecatom = eigvec(2*index+1 : 2*index + 2*3) ! = Re(u_x), Im(u_x), Re(u_y), Im(u_y), Re(u_z), Im(u_z)
5359 : : phangmom(3*(imode-1)+1) = phangmom(3*(imode-1)+1)&
5360 : 83283 : + two * (eigvecatom(3) * eigvecatom(6) - eigvecatom(4) * eigvecatom(5)) ! Re(u_y)*Im(u_z) - Im(u_y)*Re(u_z)
5361 : : phangmom(3*(imode-1)+2) = phangmom(3*(imode-1)+2)&
5362 : 83283 : + two * (eigvecatom(5) * eigvecatom(2) - eigvecatom(6) * eigvecatom(1)) ! Re(u_z)*Im(u_x) - Im(u_z)*Re(u_x)
5363 : : phangmom(3*(imode-1)+3) = phangmom(3*(imode-1)+3)&
5364 : 107526 : + two * (eigvecatom(1) * eigvecatom(4) - eigvecatom(2) * eigvecatom(3)) ! Re(u_x)*Im(u_y) - Im(u_x)*Re(u_y)
5365 : : end do
5366 : : end do
5367 : :
5368 : 3178 : end subroutine phangmom_from_eigvec
5369 : : !!***
5370 : :
5371 : : !!****f* m_dynmat/dfpt_prtph
5372 : : !! NAME
5373 : : !! dfpt_prtph
5374 : : !!
5375 : : !! FUNCTION
5376 : : !! Print the phonon frequencies, on unit 6 as well as the printing
5377 : : !! unit (except if the associated number -iout- is negative),
5378 : : !! and for the latter, in Hartree, meV, Thz, Kelvin or cm-1.
5379 : : !! If eivec==1,2, also print the eigenmodes : displacements in cartesian coordinates.
5380 : : !! If eivec==4, generate output files for band2eps (drawing tool for the phonon band structure
5381 : : !!
5382 : : !! INPUTS
5383 : : !! displ(2,3*natom,3*natom)= contains the displacements of atoms in cartesian coordinates.
5384 : : !! The first index means either the real or the imaginary part,
5385 : : !! The second index runs on the direction and the atoms displaced
5386 : : !! The third index runs on the modes.
5387 : : !! eivec=(if eivec==0, the eigendisplacements are not printed,
5388 : : !! if eivec==1,2, the eigendisplacements are printed,
5389 : : !! if eivec==4, files for band2eps
5390 : : !! enunit=units for output of the phonon frequencies :
5391 : : !! 0=> Hartree and cm-1, 1=> eV and Thz, other=> Ha,Thz,eV,cm-1 and K
5392 : : !! iout= unit for long print (if negative, the routine only print on unit 6, and in Hartree only).
5393 : : !! natom= number of atom
5394 : : !! phfrq(3*natom)= phonon frequencies in Hartree
5395 : : !! qphnrm=phonon wavevector normalisation factor
5396 : : !! qphon(3)=phonon wavevector
5397 : : !!
5398 : : !! OUTPUT
5399 : : !! Only printing
5400 : : !!
5401 : : !! NOTES
5402 : : !! called by one processor only
5403 : : !!
5404 : : !! SOURCE
5405 : :
5406 : 1967 : subroutine dfpt_prtph(displ,eivec,enunit,iout,natom,phfrq,qphnrm,qphon)
5407 : :
5408 : : !Arguments -------------------------------
5409 : : !scalars
5410 : : integer,intent(in) :: eivec,enunit,iout,natom
5411 : : real(dp),intent(in) :: qphnrm
5412 : : !arrays
5413 : : real(dp),intent(in) :: displ(2,3*natom,3*natom),phfrq(3*natom),qphon(3)
5414 : :
5415 : : !Local variables -------------------------
5416 : : !scalars
5417 : : integer :: i,idir,ii,imode,jj
5418 : : real(dp) :: tolerance
5419 : : logical :: t_degenerate
5420 : : character(len=500) :: msg
5421 : : !arrays
5422 : : real(dp) :: vecti(3),vectr(3)
5423 : 3934 : character(len=1) :: metacharacter(3*natom)
5424 : : ! *********************************************************************
5425 : :
5426 : : !Check the value of eivec
5427 [ + - + + : 3829 : if (all(eivec /= [0,1,2,4])) then
- + ]
5428 : : write(msg, '(a,i0,a,a)' )&
5429 : 0 : 'In the calling subroutine, eivec is',eivec,ch10,&
5430 : 0 : 'but allowed values are between 0 and 4.'
5431 : 0 : ABI_BUG(msg)
5432 : : end if
5433 : :
5434 : : !write the phonon frequencies on unit std_out
5435 : 1967 : write(msg,'(4a)' )' ',ch10,' phonon wavelength (reduced coordinates) , ','norm, and energies in hartree'
5436 : 1967 : call wrtout(std_out,msg)
5437 : :
5438 : : !The next format should be rewritten
5439 : 1967 : write(msg,'(a,4f5.2)' )' ',(qphon(i),i=1,3),qphnrm
5440 : 1967 : call wrtout(std_out,msg)
5441 [ + - + + ]: 6726 : do jj=1,3*natom,5
5442 [ + + ]: 4759 : if (3*natom-jj<5) then
5443 : 1967 : write(msg,'(5es17.9)') (phfrq(ii),ii=jj,3*natom)
5444 : : else
5445 : 2792 : write(msg,'(5es17.9)') (phfrq(ii),ii=jj,jj+4)
5446 : : end if
5447 : 6726 : call wrtout(std_out,msg)
5448 : : end do
5449 [ + + ]: 20657 : write(msg,'(a,a,es17.9)') ch10,' Zero Point Motion energy (sum of freqs/2)=',sum(phfrq(1:3*natom))/2
5450 : 1967 : call wrtout(std_out,msg)
5451 : :
5452 : : !Put the wavevector in nice format
5453 [ + + ]: 1967 : if(iout>=0)then
5454 : 1931 : call wrtout(iout,' ')
5455 [ + + ]: 1931 : if(qphnrm/=0.0_dp)then
5456 : : write(msg, '(a,3f9.5)' )&
5457 [ + - + + ]: 6632 : ' Phonon wavevector (reduced coordinates) :',(qphon(i)/qphnrm+tol10,i=1,3)
5458 : : else
5459 : : write(msg, '(3a,3f9.5)' )&
5460 : 273 : ' Phonon at Gamma, with non-analyticity in the',ch10,&
5461 [ + + ]: 1365 : ' direction (cartesian coordinates)',qphon(1:3)+tol10
5462 : : end if
5463 : 1931 : call wrtout(iout,msg)
5464 : :
5465 : : ! Write it, in different units.
5466 [ + - ]: 1931 : if(enunit/=1)then
5467 : 1931 : write(iout, '(a)' )' Phonon energies in Hartree :'
5468 [ + - + + ]: 6582 : do jj=1,3*natom,5
5469 [ + + ]: 4651 : if (3*natom-jj<5) then
5470 : 1931 : write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,3*natom)
5471 : : else
5472 : 2720 : write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,jj+4)
5473 : : end if
5474 : 6582 : call wrtout(iout,msg)
5475 : : end do
5476 : : end if
5477 [ + + ]: 1931 : if(enunit/=0)then
5478 : 158 : write(iout, '(a)' )' Phonon energies in meV :'
5479 [ + - + + ]: 388 : do jj=1,3*natom,5
5480 [ + + ]: 230 : if (3*natom-jj<5) then
5481 [ + - + + ]: 488 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,3*natom)
5482 : : else
5483 [ + - + + ]: 432 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,jj+4)
5484 : : end if
5485 : 388 : call wrtout(iout,msg)
5486 : : end do
5487 : : end if
5488 [ + - ]: 1931 : if(enunit/=1)then
5489 : 1931 : write(iout, '(a)' )' Phonon frequencies in cm-1 :'
5490 [ + - + + ]: 6582 : do jj=1,3*natom,5
5491 [ + + ]: 4651 : if (3*natom-jj<5) then
5492 [ + - + + ]: 6577 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,3*natom)
5493 : : else
5494 [ + - + + ]: 16320 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,jj+4)
5495 : : end if
5496 : 6582 : call wrtout(iout,msg)
5497 : : end do
5498 : : end if
5499 [ + + ]: 1931 : if(enunit/=0)then
5500 : 158 : write(iout, '(a)' )' Phonon frequencies in Thz :'
5501 [ + - + + ]: 388 : do jj=1,3*natom,5
5502 [ + + ]: 230 : if (3*natom-jj<5) then
5503 [ + - + + ]: 488 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,3*natom)
5504 : : else
5505 [ + - + + ]: 432 : write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,jj+4)
5506 : : end if
5507 : 388 : call wrtout(iout,msg)
5508 : : end do
5509 : : end if
5510 [ + + ]: 1931 : if(enunit/=0.and.enunit/=1)then
5511 : 158 : write(iout, '(a)' )' Phonon energies in Kelvin :'
5512 [ + - + + ]: 388 : do jj=1,3*natom,5
5513 [ + + ]: 230 : if (3*natom-jj<5) then
5514 [ + - + + ]: 488 : write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,3*natom)
5515 : : else
5516 [ + - + + ]: 432 : write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,jj+4)
5517 : : end if
5518 : 388 : call wrtout(iout,msg)
5519 : : end do
5520 : : end if
5521 : : end if
5522 : :
5523 : : !Take care of the eigendisplacements
5524 [ + + ]: 1967 : if(eivec==1 .or. eivec==2)then
5525 : 83 : write(msg, '(a,a,a,a,a,a,a,a)' ) ch10,&
5526 : 83 : ' Eigendisplacements ',ch10,&
5527 : 83 : ' (will be given, for each mode : in cartesian coordinates',ch10,&
5528 : 83 : ' for each atom the real part of the displacement vector,',ch10,&
5529 : 166 : ' then the imaginary part of the displacement vector - absolute values smaller than 1.0d-7 are set to zero)'
5530 : 83 : call wrtout(std_out,msg)
5531 [ + - ]: 83 : if(iout>=0) then
5532 : 83 : call wrtout(iout,msg)
5533 : : end if
5534 : :
5535 : : ! Examine the degeneracy of each mode. The portability of the echo of the eigendisplacements
5536 : : ! is very hard to obtain, and has not been attempted.
5537 [ + + ]: 452 : do imode=1,3*natom
5538 : : ! The degenerate modes are not portable
5539 : 369 : t_degenerate=.false.
5540 [ + + ]: 369 : if(imode>1)then
5541 [ + + ]: 286 : if(phfrq(imode)-phfrq(imode-1)<tol6)t_degenerate=.true.
5542 : : end if
5543 [ + + ]: 369 : if(imode<3*natom)then
5544 [ + + ]: 286 : if(phfrq(imode+1)-phfrq(imode)<tol6)t_degenerate=.true.
5545 : : end if
5546 [ + + ]: 452 : metacharacter(imode)=';'; if(t_degenerate)metacharacter(imode)='-'
5547 : : end do
5548 : :
5549 [ + + ]: 452 : do imode=1,3*natom
5550 : 369 : write(msg,'(a,i4,a,es16.6)' )' Mode number ',imode,' Energy',phfrq(imode)
5551 : 369 : call wrtout(std_out,msg)
5552 [ + - ]: 369 : if(iout>=0)then
5553 : 369 : write(msg, '(a,i4,a,es16.6)' )' Mode number ',imode,' Energy',phfrq(imode)
5554 : 369 : call wrtout(iout,msg)
5555 : : end if
5556 : 369 : tolerance=1.0d-7
5557 [ + + ]: 369 : if(abs(phfrq(imode))<1.0d-5)tolerance=2.0d-7
5558 [ + + ]: 369 : if(phfrq(imode)<1.0d-5)then
5559 : 202 : write(msg,'(3a)' )' Attention : low frequency mode.',ch10,&
5560 : 404 : ' (Could be unstable or acoustic mode)'
5561 : 202 : call wrtout(std_out,msg)
5562 [ + - ]: 202 : if(iout>=0)then
5563 : 202 : write(iout, '(3a)' )' Attention : low frequency mode.',ch10,&
5564 : 404 : ' (Could be unstable or acoustic mode)'
5565 : : end if
5566 : : end if
5567 [ + + ]: 1277 : do ii=1,natom
5568 [ + + ]: 3300 : do idir=1,3
5569 : 2475 : vectr(idir)=displ(1,idir+(ii-1)*3,imode)
5570 [ + + ]: 2475 : if(abs(vectr(idir))<tolerance)vectr(idir)=0.0_dp
5571 : 2475 : vecti(idir)=displ(2,idir+(ii-1)*3,imode)
5572 [ + - ]: 3300 : if(abs(vecti(idir))<tolerance)vecti(idir)=0.0_dp
5573 : : end do
5574 : 825 : write(msg,'(i4,3es16.8,a,4x,3es16.8)' ) ii,vectr(:),ch10,vecti(:)
5575 : 825 : call wrtout(std_out,msg)
5576 [ + - ]: 1194 : if(iout>=0)then
5577 : 825 : write(msg,'(a,i3,3es16.8,2a,3x,3es16.8)') metacharacter(imode),ii,vectr(:),ch10,&
5578 : 1650 : metacharacter(imode), vecti(:)
5579 : 825 : call wrtout(iout,msg)
5580 : : end if
5581 : : end do
5582 : : end do
5583 : : end if
5584 : :
5585 : 1967 : end subroutine dfpt_prtph
5586 : : !!***
5587 : :
5588 : : !!****f* m_dynmat/massmult_and_breaksym
5589 : : !! NAME
5590 : : !! mult_masses_and_break_symms
5591 : : !!
5592 : : !! FUNCTION
5593 : : !! Multiply the IFC(q) by the atomic masses, slightly break symmetry to make tests more
5594 : : !! portable and make the matrix hermitian before returning.
5595 : : !!
5596 : : !! INPUTS
5597 : : !! amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
5598 : : !! natom=number of atoms in unit cell
5599 : : !! ntypat=number of atom types
5600 : : !! typat(natom)=integer label of each type of atom (1,2,...)
5601 : : !! [herm_opt]= 1 to hermitianize mat (default)
5602 : : !! 0 if no symmetrization should be performed
5603 : : !!
5604 : : !! SIDE EFFECTS
5605 : : !! mat(2*3*natom*3*natom)=Multiplies by atomic masses in output.
5606 : : !!
5607 : : !! SOURCE
5608 : :
5609 : 645355 : subroutine massmult_and_breaksym(natom, ntypat, typat, amu, mat, &
5610 : : herm_opt) ! optional
5611 : :
5612 : : !Arguments -------------------------------
5613 : : !scalars
5614 : : integer,intent(in) :: natom,ntypat
5615 : : integer,optional,intent(in) :: herm_opt
5616 : : !arrays
5617 : : integer,intent(in) :: typat(natom)
5618 : : real(dp),intent(in) :: amu(ntypat)
5619 : : real(dp),intent(inout) :: mat(2*3*natom*3*natom)
5620 : :
5621 : : !Local variables -------------------------
5622 : : !scalars
5623 : : integer :: i1,i2,idir1,idir2,index,ipert1,ipert2, herm_opt__
5624 : : real(dp),parameter :: break_symm=1.0d-12
5625 : : !real(dp),parameter :: break_symm=zero
5626 : : real(dp) :: fac
5627 : : !arrays
5628 : : real(dp) :: nearidentity(3,3)
5629 : : ! *********************************************************************
5630 : :
5631 [ - + ]: 645355 : herm_opt__ = 1; if (present(herm_opt)) herm_opt__ = herm_opt
5632 : :
5633 : : ! This slight breaking of the symmetry allows the results to be more portable between machines
5634 [ + + + + ]: 8389615 : nearidentity(:,:)=one
5635 : 645355 : nearidentity(1,1)=one+break_symm
5636 : 645355 : nearidentity(3,3)=one-break_symm
5637 : :
5638 : : ! Include the masses in the dynamical matrix
5639 [ + + ]: 1874445 : do ipert1=1,natom
5640 [ + + ]: 4756199 : do ipert2=1,natom
5641 : 2881754 : fac=1.0_dp/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
5642 [ + + ]: 12756106 : do idir1=1,3
5643 [ + + ]: 37462802 : do idir2=1,3
5644 : 25935786 : i1=idir1+(ipert1-1)*3
5645 : 25935786 : i2=idir2+(ipert2-1)*3
5646 : 25935786 : index=i1+3*natom*(i2-1)
5647 : 25935786 : mat(2*index-1)=mat(2*index-1)*fac*nearidentity(idir1,idir2)
5648 : 25935786 : mat(2*index )=mat(2*index )*fac*nearidentity(idir1,idir2)
5649 : : ! This is to break slightly the translation invariance, and make the automatic tests more portable
5650 [ + + ]: 34581048 : if(ipert1==ipert2 .and. idir1==idir2)then
5651 : 3687270 : mat(2*index-1)=mat(2*index-1)+break_symm*natom/amu_emass/idir1*0.01_dp
5652 : : end if
5653 : : end do
5654 : : end do
5655 : : end do
5656 : : end do
5657 : :
5658 : : ! Make the dynamical matrix hermitian
5659 [ + - ]: 645355 : if (herm_opt__ == 1) call mkherm(mat,3*natom)
5660 : :
5661 : 645355 : end subroutine massmult_and_breaksym
5662 : : !!***
5663 : :
5664 : : !!****f* m_dynmat/massmult_and_breaksym_cplx
5665 : : !! NAME
5666 : : !! mult_masses_and_break_symms_cplx
5667 : : !!
5668 : : !! FUNCTION
5669 : : !! Similar to massmult_and_breaksym, the only difference is that it receives complex array.
5670 : :
5671 : 0 : subroutine massmult_and_breaksym_cplx(natom, ntypat, typat, amu, cmat, &
5672 : : herm_opt) ! optional
5673 : :
5674 : : !Arguments -------------------------------
5675 : : !scalars
5676 : : integer,intent(in) :: natom,ntypat
5677 : : integer,optional,intent(in) :: herm_opt
5678 : : !arrays
5679 : : integer,intent(in) :: typat(natom)
5680 : : real(dp),intent(in) :: amu(ntypat)
5681 : : complex(dp),target,intent(inout) :: cmat(2*3*natom*3*natom)
5682 : :
5683 : : !Local variables -------------------------
5684 : : integer :: herm_opt__
5685 : : real(dp),pointer :: rmat_ptr(:)
5686 : : ! *************************************************************************
5687 : :
5688 [ # # ]: 0 : call C_F_pointer(c_loc(cmat), rmat_ptr, shape=[3*natom*3*natom])
5689 [ # # ]: 0 : herm_opt__ = 1; if (present(herm_opt)) herm_opt__ = herm_opt
5690 [ # # ]: 0 : call massmult_and_breaksym(natom, ntypat, typat, amu, rmat_ptr, herm_opt=herm_opt__)
5691 : :
5692 : 0 : end subroutine massmult_and_breaksym_cplx
5693 : : !!***
5694 : :
5695 : : !!****f* m_dynmat/ftgam
5696 : : !! NAME
5697 : : !! ftgam
5698 : : !!
5699 : : !! FUNCTION
5700 : : !! If qtor=1 (q->r):
5701 : : !! Generates the Fourier transform of the recip space gkk matrices
5702 : : !! to obtain the real space ones.
5703 : : !! If qtor=0 (r->q):
5704 : : !! Generates the Fourier transform of the real space gkk matrices
5705 : : !! to obtain the reciprocal space ones.
5706 : : !!
5707 : : !! INPUTS
5708 : : !! natom= Number of atoms in the unit cell
5709 : : !! nqpt= Number of q points in the Brillouin zone
5710 : : !! if qtor=0 this number is read in the input file
5711 : : !! nrpt= Number of R points in the Big Box
5712 : : !! qtor= ( q to r : see above )
5713 : : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
5714 : : !! These coordinates are normalized (=> * acell(3)!!)
5715 : : !! qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
5716 : : !! if qtor=0 these vectors are read in the input file
5717 : : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
5718 : : !!
5719 : : !! OUTPUT
5720 : : !! (see side effects)
5721 : : !!
5722 : : !! SIDE EFFECTS
5723 : : !! Input/output
5724 : : !! gam_qpt(2,3*natom*3*natom,nqpt)
5725 : : !! = gamma matrices in recip space coming from the Derivative Data Base
5726 : : !! gam_rpt(2,3*natom*3*natom,nrpt)
5727 : : !! = gamma matrices in real space stored in file unit_gkk_rpt
5728 : : !!
5729 : : !! NOTES
5730 : : !! copied from ftiaf9.f
5731 : : !! recip to real space: real space is forced to disk file unit_gkk_rpt
5732 : : !! recip space depends on gkqwrite and unitgkq3
5733 : : !! real to recip space: real space is forced to disk file unit_gkk_rpt
5734 : : !! recip space is necessarily in memory in gkk_qpt
5735 : : !!
5736 : : !! real space elements are complex, but could be reduced, as (-r) = (+r)*
5737 : : !!
5738 : : !! SOURCE
5739 : :
5740 : 26898 : subroutine ftgam (wghatm,gam_qpt,gam_rpt,natom,nqpt,nrpt,qtor,coskr, sinkr)
5741 : :
5742 : : !Arguments -------------------------------
5743 : : !scalars
5744 : : integer,intent(in) :: natom,nqpt,nrpt,qtor
5745 : : !arrays
5746 : : real(dp),intent(in) :: wghatm(natom,natom,nrpt)
5747 : : real(dp),intent(inout) :: gam_qpt(2,3*natom*3*natom,nqpt)
5748 : : real(dp),intent(inout) :: gam_rpt(2,3*natom*3*natom,nrpt)
5749 : : real(dp),intent(in) :: coskr(nqpt,nrpt)
5750 : : real(dp),intent(in) :: sinkr(nqpt,nrpt)
5751 : :
5752 : : !Local variables -------------------------
5753 : : !scalars
5754 : : integer :: iatom,idir,ip,iqpt,irpt,jatom,jdir
5755 : : real(dp) :: im,re
5756 : : character(len=500) :: msg
5757 : : ! *********************************************************************
5758 : :
5759 : 26898 : select case (qtor)
5760 : : case (1)
5761 : : ! Recip to real space
5762 [ + + + + : 428974 : gam_rpt(:,:,:) = zero
+ + ]
5763 [ + + ]: 11392 : do irpt=1,nrpt
5764 [ + + ]: 1387296 : do iqpt=1,nqpt
5765 : : ! Get the phase factor with normalization!
5766 : 1375904 : re=coskr(iqpt,irpt)
5767 : 1375904 : im=sinkr(iqpt,irpt)
5768 [ + + ]: 14078031 : do ip=1,3*natom*3*natom
5769 : : ! Real and imaginary part of the real-space gam matrices
5770 : 12690936 : gam_rpt(1,ip,irpt) = gam_rpt(1,ip,irpt) + re*gam_qpt(1,ip,iqpt) + im*gam_qpt(2,ip,iqpt)
5771 : 14066840 : gam_rpt(2,ip,irpt) = gam_rpt(2,ip,irpt) + re*gam_qpt(2,ip,iqpt) - im*gam_qpt(1,ip,iqpt)
5772 : : end do
5773 : : end do
5774 : : end do
5775 [ + + + + : 428974 : gam_rpt = gam_rpt/nqpt
+ + ]
5776 : :
5777 : : case (0)
5778 : : ! Recip space from real space
5779 [ + + + + : 1073346 : gam_qpt(:,:,:)=zero
+ + ]
5780 : :
5781 [ + + ]: 1590618 : do irpt=1,nrpt
5782 [ + + ]: 3154539 : do iqpt=1,nqpt
5783 : :
5784 [ + + ]: 4784088 : do iatom=1,natom
5785 [ + + ]: 5061063 : do jatom=1,natom
5786 : 1840896 : re = coskr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
5787 : 1840896 : im = sinkr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
5788 : :
5789 [ + + ]: 9019830 : do idir=1,3
5790 [ + + ]: 23931648 : do jdir=1,3
5791 : : ! Get phase factor
5792 : :
5793 : 16568064 : ip= jdir + (jatom-1)*3 + (idir-1)*3*natom + (iatom-1)*9*natom
5794 : : ! Real and imaginary part of the interatomic forces
5795 : 16568064 : gam_qpt(1,ip,iqpt) = gam_qpt(1,ip,iqpt) + re*gam_rpt(1,ip,irpt) - im*gam_rpt(2,ip,irpt)
5796 : 22090752 : gam_qpt(2,ip,iqpt) = gam_qpt(2,ip,iqpt) + im*gam_rpt(1,ip,irpt) + re*gam_rpt(2,ip,irpt)
5797 : : end do ! end jdir
5798 : : end do ! end idir
5799 : : end do
5800 : : end do ! end iatom
5801 : :
5802 : : end do ! end iqpt
5803 : : end do ! end irpt
5804 : :
5805 : : case default
5806 : 0 : write(msg,'(a,i0,a)' )'The only allowed values for qtor are 0 or 1, while qtor= ',qtor,' has been required.'
5807 [ + + - ]: 26898 : ABI_BUG(msg)
5808 : : end select
5809 : :
5810 : 26898 : end subroutine ftgam
5811 : : !!***
5812 : :
5813 : : !!****f* m_dynmat/ftgam_init
5814 : : !!
5815 : : !! NAME
5816 : : !! ftgam_init
5817 : : !!
5818 : : !! FUNCTION
5819 : : !! Generates the sin and cos phases for the Fourier transform of the gkk matrices
5820 : : !!
5821 : : !! INPUTS
5822 : : !! gprim = reciprocal space vectors to get cartesian coord for qpt
5823 : : !! nqpt= Number of q points in the Brillouin zone
5824 : : !! nrpt= Number of R points in the Big Box
5825 : : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
5826 : : !! These coordinates are normalized (=> * acell(3)!!)
5827 : : !! qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
5828 : : !! if qtor=0 these vectors are read in the input file
5829 : : !!
5830 : : !! OUTPUT
5831 : : !! coskr, sinkr = cosine and sine of phase factors for given r and q points
5832 : : !!
5833 : : !! SOURCE
5834 : :
5835 : 1715 : subroutine ftgam_init (gprim,nqpt,nrpt,qpt_full,rpt,coskr, sinkr)
5836 : :
5837 : : !Arguments -------------------------------
5838 : : !scalars
5839 : : integer,intent(in) :: nqpt,nrpt
5840 : : !arrays
5841 : : real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt_full(3,nqpt)
5842 : : real(dp),intent(out) :: coskr(nqpt,nrpt)
5843 : : real(dp),intent(out) :: sinkr(nqpt,nrpt)
5844 : :
5845 : : !Local variables -------------------------
5846 : : !scalars
5847 : : integer :: iqpt,irpt
5848 : : real(dp) :: kr
5849 : : !arrays
5850 : : real(dp) :: kk(3)
5851 : : ! *********************************************************************
5852 : :
5853 : : ! Prepare the phase factors
5854 [ + + ]: 10311 : do iqpt=1,nqpt
5855 : : ! Calculation of the k coordinates in Normalized Reciprocal coordinates
5856 [ + + + + ]: 111748 : kk(:) = matmul(gprim,qpt_full(:,iqpt))
5857 [ + + ]: 417383 : do irpt=1,nrpt
5858 : : ! Product of k and r
5859 [ + + ]: 1628288 : kr =dot_product(kk,rpt(:,irpt))
5860 : 407072 : coskr(iqpt,irpt)=cos(two_pi*kr)
5861 : 415668 : sinkr(iqpt,irpt)=sin(two_pi*kr)
5862 : : end do
5863 : : end do
5864 : :
5865 : 1715 : end subroutine ftgam_init
5866 : : !!***
5867 : :
5868 : : !----------------------------------------------------------------------
5869 : :
5870 : : !!****f* m_dynmat/msria_calc
5871 : : !! NAME
5872 : : !! msria_calc
5873 : : !!
5874 : : !! FUNCTION
5875 : : !! Calculate the corrections on the zone-center IFCs and their derivatives with respect to the phonon
5876 : : !! wavevector q to achieve both translational (acoustic sum rule) and rotational invariances,
5877 : : !! i.e. there is not remanent forces on the atoms if they are moved or rotated globablly.
5878 : : !! This function needs the dimensionality of the system (0D, 1D, 2D, ...) to work properly, as well
5879 : : !! as the moment of the IFCs, i.e. Phi^(1). It can be obtained by a long wave calculation
5880 : : !! or with the Fourier transform. Be careful for the second option that the non-analytical part
5881 : : !! is not (yet) treated for the 1D and 2D cases; ideally this routine should only impacts the
5882 : : !! short-range IFCs (and the long-range subtracted before entering this routine)
5883 : : !!
5884 : : !! INPUTS
5885 : : !! asr=(6 Impose accoustic sum rules + rotational invariance)
5886 : : !! crystal<type(crystal_t)>=Crystal structure parameters
5887 : : !! d2cart(2,3,natom,3,natom)= Dynamical matrices coming from the Derivative Data Base at Gamma
5888 : : !! d2dq (3,natom,3,natom,3): moment of IFCs (Phi^(1)) in cartesian coordinates
5889 : : !! sys_dim=System dimensionality (0D, 1D, ...) used for rotational invariance
5890 : : !! mpert =maximum number of ipert
5891 : : !! natom=number of atom
5892 : : !!
5893 : : !! OUTPUT
5894 : : !! d2asr= (2,3,natom,3,natom) matrix used to store the correction needed to fulfill
5895 : : !! the acoustic + rotational sum rule on IFCs.
5896 : : !! d2dqmsr= (3,natom,3,natom,3) matrix used to store the correction on IFCs moments
5897 : : !!
5898 : : !! SOURCE
5899 : :
5900 : : !!***
5901 : : !
5902 : 2 : subroutine msria_calc(asr,crystal,d2asr,d2cart,d2dq,d2dqdq,d2dqmsr,d2dqdqmsr,sys_dim,mpert,natom)
5903 : : !Arguments ------------------------------------
5904 : : !scalars
5905 : : integer,intent(in) :: sys_dim,asr,mpert,natom
5906 : : type(crystal_t),intent(in) :: crystal
5907 : : !arrays
5908 : : real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
5909 : : real(dp),intent(in) :: d2dq(3,natom,3,natom,3)
5910 : : real(dp),intent(in) :: d2dqdq(3,natom,3,3,3)
5911 : : real(dp),intent(out) :: d2asr(2,3,natom,3,natom)
5912 : : real(dp),intent(out) :: d2dqmsr(3,natom,3,natom,3)
5913 : : real(dp),intent(out) :: d2dqdqmsr(3,natom,3,natom,3,3)
5914 : : !Local variables-------------------------------
5915 : : !scalars
5916 : : integer :: idir1,idir2,idir3,idir4,idir5,info,ipert1,ipert2,col,ncol,nrow,row
5917 : : character(len=500) :: msg,msg2
5918 : : integer :: bool_kdir(3), bool_ldir(3)
5919 : : !arrays
5920 : 4 : real(dp) :: tmp,tmp2,Levi_Civita(3,3,3), d2dqdqcart(3,natom,3,natom,3,3)
5921 : 4 : real(dp) :: d2dqred(3,natom,3,natom,3),d2dqdqred(3,natom,3,natom,3,3)
5922 : 2 : real(dp),allocatable :: msr(:,:,:),msr_init(:,:,:)
5923 : 2 : real(dp),allocatable :: d2cart_vec(:),rcond(:,:),cond(:)
5924 : 2 : real(dp),allocatable :: mat_tmp(:,:),mat_tmp2(:,:),mat_tmp3(:,:),d2cart_sol(:),umat(:,:),vtmat(:,:)
5925 : 2 : real(dp),allocatable :: vmat(:,:),sing(:),work(:),sing1(:,:),sing2(:,:)
5926 : :
5927 : : ! *********************************************************************
5928 [ - + ]: 2 : if(asr/=6)then
5929 : : write(msg,'(3a,i0)')&
5930 : 0 : 'The argument asr should be 6,',ch10, 'however, asr = ',asr
5931 : 0 : ABI_BUG(msg)
5932 : : end if
5933 : :
5934 [ + - ]: 2 : if (asr==6)then
5935 : 2 : write(msg, '(a,a,a,a,a,a,a,a)' ) ch10, &
5936 : 2 : ' Imposition of the ASR + rotational invariance for the interatomic forces (AMSR)', ch10, &
5937 : 2 : ' Rotational invariance impose conditions on the IFCs moments and their derivatives',ch10,&
5938 : 2 : ' At the moment, because of missing long-range contributions to the second IFCs derivatives',ch10,&
5939 : 4 : ' rotational invariance is only imposed on the first-derivatives (first-order condition)'
5940 : 2 : call wrtout(std_out,msg)
5941 : : end if
5942 : 2 : bool_kdir = 0
5943 : 2 : bool_ldir = 0
5944 : : ! When periodic, additional variable spaces coming from dynamical matrices derivatives
5945 [ - - - + : 2 : if (sys_dim == 1) then ! 3D
- - - +
- ]
5946 [ # # ]: 0 : bool_kdir = 0 ; bool_ldir = 1
5947 : 0 : msg2=' 3D treatment'
5948 : : elseif (sys_dim == 2) then ! 2D yz
5949 : 0 : bool_kdir(1) = 1 ; bool_ldir(2) = 1 ; bool_ldir(3) = 1
5950 : 0 : msg2=' 2D with x as out-of-plane direction'
5951 : : elseif (sys_dim == 3) then ! 2D xz
5952 : 0 : bool_kdir(2) = 1 ; bool_ldir(1) = 1 ; bool_ldir(3) = 1
5953 : 0 : msg2=' 2D with y as out-of-plane direction'
5954 : : elseif (sys_dim == 4) then ! 2D xy
5955 : 1 : bool_kdir(3) = 1 ; bool_ldir(1) = 1 ; bool_ldir(2) = 1
5956 : 1 : msg2=' 2D with z as out-of-plane direction'
5957 : : elseif (sys_dim == 5) then ! 1D x
5958 : 0 : bool_kdir(2) = 1 ; bool_kdir(3) = 1 ; bool_ldir(1) = 1
5959 : 0 : msg2=' 1D with x as periodic direction'
5960 : : elseif (sys_dim == 6) then ! 1D y
5961 : 0 : bool_kdir(1) = 1 ; bool_kdir(2) = 1 ; bool_ldir(2) = 1
5962 : 0 : msg2=' 1D with y as periodic direction'
5963 : : elseif (sys_dim == 7) then ! 1D z
5964 : 0 : bool_kdir(1) = 1 ; bool_kdir(2) = 1 ; bool_ldir(3) = 1
5965 : 0 : msg2=' 1D with z as periodic direction'
5966 : : elseif (sys_dim == 8) then ! Molecule
5967 [ + + ]: 4 : bool_kdir = 1 ; bool_ldir = 0
5968 : 1 : msg2=' 0D treatment (molecules)'
5969 : : else
5970 : : write(msg,'(3a,i0)')&
5971 : 0 : 'The argument sys_dim should be between 1 and 8,',ch10, 'however, sys_dim = ',sys_dim
5972 : 0 : ABI_BUG(msg)
5973 : : end if
5974 : :
5975 : 2 : write(msg, '(a,a)' ) ch10, trim(msg2)
5976 : 2 : call wrtout(std_out,msg)
5977 : :
5978 : : ! Matrix sizing for pseudoinverse and alocation of corresponding matrix
5979 : 2 : nrow = 3+2*3*3*natom ! 9*natom conditions for ASR, 9*natom+3 conditions for MSR
5980 : 2 : nrow = nrow +4*(3*natom)**2 ! + Hermiticity
5981 : :
5982 : : ncol = (3*natom)**2 ! 9*natom**2 variable workspace (for dynamical matrices, initial)
5983 : : ncol = ncol + 3*(3*natom)**2 ! Aditional variable space coming from dD/dq (only for periodic systems)
5984 : 2 : ncol = ncol + 9*(3*natom)**2 ! d2D/dqdq
5985 [ - + + - : 8 : ABI_MALLOC(msr,(1:3,1:natom,1:3))
+ - + - +
- - + -
+ ]
5986 [ - + + - : 4 : ABI_MALLOC(msr_init,(1:3,1:natom,1:3))
- + - + ]
5987 [ - + + - : 6 : ABI_MALLOC(d2cart_vec,(1:ncol))
+ - + - -
+ - + ]
5988 [ - + + - : 4 : ABI_MALLOC(d2cart_sol,(1:ncol))
- + - + ]
5989 [ - + + - : 6 : ABI_MALLOC(cond,(1:nrow))
+ - + - -
+ - + ]
5990 [ - + + - : 8 : ABI_MALLOC(rcond,(1:nrow,1:ncol))
- + + - +
- + - - +
- + ]
5991 [ + + ]: 2927 : d2cart_vec=0d0
5992 [ + + ]: 2927 : d2cart_sol=0d0
5993 [ + + ]: 1034 : cond = 0d0
5994 [ + + + + ]: 1622792 : rcond = 0d0
5995 : :
5996 : 2 : Levi_Civita(:,:,:)=zero
5997 : 2 : Levi_Civita(1,2,3)=+1 ; Levi_Civita(2,3,1)=+1 ; Levi_Civita(3,1,2)=+1
5998 : 2 : Levi_Civita(3,2,1)=-1 ; Levi_Civita(1,3,2)=-1 ; Levi_Civita(2,1,3)=-1
5999 : :
6000 : : ! We only have access to \sum d^2 Phi(kappa alpha, kappa' beta)/dqdq through the
6001 : : ! long-wavelength driver, we need to construct the full tensor. Here we split
6002 : : ! an equal contribution on all atoms
6003 [ + + + + : 2978 : d2dqdqcart(:,:,:,:,:,:)=zero
+ + + + +
+ + + ]
6004 [ + + ]: 9 : do ipert1=1,natom
6005 [ + + ]: 30 : do idir1=1,3
6006 [ + + ]: 91 : do idir2=1,3
6007 [ + + ]: 309 : do ipert2=1,natom
6008 [ + + ]: 963 : do idir3=1,3
6009 : : d2dqdqcart(idir1,ipert1,idir2,ipert1,idir3,idir3)=&
6010 : 900 : -two*d2dqdq(idir1,ipert1,idir2,idir3,idir3)/dble(natom)
6011 : : end do
6012 : : end do
6013 : : end do
6014 : : end do
6015 : : end do
6016 : : ! Convert d2dq and d2dqdq in relative coordinates with respect to q
6017 [ + + + + : 992 : d2dqred = zero
+ + + + +
+ ]
6018 [ + + + + : 2978 : d2dqdqred = zero
+ + + + +
+ + + ]
6019 [ + + ]: 8 : do idir1=1,3
6020 [ + + ]: 26 : do idir2=1,3
6021 [ + + + + : 2970 : d2dqred(:,:,:,:,idir1)=d2dqred(:,:,:,:,idir1)+d2dq(:,:,:,:,idir2)*crystal%gprimd(idir2,idir1)
+ + + + ]
6022 [ + + ]: 78 : do idir3=1,3
6023 [ + + ]: 234 : do idir4=1,3
6024 : : d2dqdqred(:,:,:,:,idir2,idir4)=d2dqdqred(:,:,:,:,idir2,idir4)+&
6025 [ + + + + : 26784 : d2dqdqcart(:,:,:,:,idir1,idir3)*crystal%gprimd(idir1,idir2)*crystal%gprimd(idir3,idir4)
+ + + + ]
6026 : : end do
6027 : : end do
6028 : : end do
6029 : : end do
6030 : : ! Now building the condition matrix
6031 [ + + ]: 8 : do idir1=1,3
6032 [ + + ]: 29 : do ipert1=1,natom
6033 [ + + ]: 90 : do idir2=1,3
6034 [ + + ]: 309 : do ipert2=1,natom
6035 : 225 : col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6036 : 225 : d2cart_vec(col) = d2cart(1,idir1,ipert1,idir2,ipert2)
6037 : 225 : row= idir2+3*(ipert1-1)+3*natom*(idir1-1) ! Acoustic sum rule
6038 : 225 : rcond(row,col) = one ! Sum of IFCs along ipert2 = 0
6039 : : ! Rotational invariance
6040 [ + + ]: 900 : do idir3=1,3
6041 : : ! Treat separately confined and periodic directions
6042 [ + + ]: 675 : if ( bool_kdir(idir3) == 1) then ! confined direction
6043 [ + + ]: 1548 : do idir4 = 1,3
6044 : 1161 : col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6045 : 1161 : row = 9*natom+idir4+3*(ipert1-1)+3*natom*(idir1-1)
6046 : : rcond(row,col) = rcond(row,col)+ & ! first moment of IFCs
6047 : 1548 : (crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
6048 : : end do
6049 : : ! Conditions on the second moments of IFCs
6050 : : ! In molecules, already fulfilled with rotational invariance
6051 : : ! For 1D systems, should only consider pair of direction when 1 is
6052 : : ! periodic, the other is not. Currently desactivated
6053 : : if (idir1 == idir2 .and. bool_ldir(idir1) ==1) then !
6054 : : col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6055 : : row = 2*9*natom+idir2 ! second moment of IFCs
6056 : : ! Currently desactivated because long-range electrostatics, only need to uncomment
6057 : : ! when it will be available.
6058 : : !rcond(row,col) = -(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))**2
6059 : : col= ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
6060 : : !rcond(row,col) = -(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))**2
6061 : : end if
6062 : : end if
6063 [ + + ]: 900 : if ( bool_ldir(idir3) == 1 ) then ! periodic direction
6064 : : ! Initialize the IFCs derivatives
6065 : 288 : col= (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6066 : 288 : d2cart_vec(col) = d2dqred(idir1,ipert1,idir2,ipert2,idir3)
6067 [ + + ]: 1152 : do idir5 = 1,3
6068 [ + + ]: 3744 : do idir4 = 1,3
6069 : 2592 : row = 9*natom+idir4+3*(ipert1-1)+3*natom*(idir1-1)
6070 : 3456 : rcond(row,col) = rcond(row,col)+ Levi_Civita(idir2,idir5,idir4)*crystal%rprimd(idir5,idir3)!/two_pi
6071 : : end do
6072 : : end do
6073 [ + + ]: 1152 : do idir4=1,3
6074 : 288 : if ( bool_ldir(idir4) == 1 ) then ! periodic direction
6075 : : col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
6076 : 864 : (3*natom)**2*(idir3-1)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6077 : : !d2cart_vec(col) = d2dqdqred(idir1,ipert1,idir2,ipert2,idir3,idir4)
6078 : : end if
6079 : : end do
6080 [ + + + + ]: 288 : if (idir2 == idir1 .and. bool_kdir(idir1)==1) then
6081 [ + + ]: 128 : do idir4=1,3
6082 : : col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
6083 : 96 : (3*natom)**2*(idir4-1)+ipert2+natom*(idir1-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6084 : 96 : row = 2*9*natom+idir3 ! second moment of IFCs
6085 : : !rcond(row,col) = crystal%rprimd(idir4,idir3)**2!/two_pi
6086 : : col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
6087 : 128 : (3*natom)**2*(idir4-1)+ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir1-1)
6088 : : !rcond(row,col) = crystal%rprimd(idir4,idir3)**2!/two_pi
6089 : : end do
6090 : : end if
6091 : : end if
6092 : : end do
6093 : : ! Additionally, add the condition of matrix Hermiticity, both on IFCs and their derivatives
6094 : 225 : col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6095 : 225 : row= 3+2*(9*natom)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6096 : 225 : rcond(row,col) = rcond(row,col)+ one ! Hermicity
6097 : 225 : col= ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
6098 : 225 : rcond(row,col) = rcond(row,col)- one ! Hermicity
6099 [ + + ]: 963 : do idir3=1,3
6100 : 675 : row= 3+2*(9*natom)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)+9*natom**2*(idir3)
6101 : 675 : col= (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6102 : 675 : rcond(row,col) = rcond(row,col)+ one
6103 : 675 : col= (3*natom)**2*idir3+ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
6104 : 900 : rcond(row,col) = rcond(row,col)+ one
6105 : : end do
6106 : : end do
6107 : : end do
6108 : : end do
6109 : : end do
6110 : :
6111 : :
6112 : : ! Use LAPACK singular value decomposition
6113 [ - + + - : 4 : ABI_MALLOC(sing,(1:nrow))
- + - + ]
6114 [ - + + - : 8 : ABI_MALLOC(umat,(1:nrow,1:nrow))
- + + - +
- + - - +
- + ]
6115 [ - + + - : 8 : ABI_MALLOC(vtmat,(1:ncol,1:ncol))
- + + - +
- + - - +
- + ]
6116 [ - + + - : 6 : ABI_MALLOC(work,(1:5*max(nrow,ncol)))
+ - + - -
+ - + ]
6117 : : call dgesvd('A','A',nrow,ncol,rcond,nrow,sing,umat,nrow, &
6118 : 2 : vtmat, ncol, work,5*max(nrow,ncol),info)
6119 [ - + ]: 2 : ABI_CHECK(info == 0, sjoin('dgesvd returned:', itoa(info)))
6120 [ - + ]: 2 : ABI_FREE(umat)
6121 [ - + ]: 2 : ABI_FREE(work)
6122 : :
6123 : 2 : write(msg, '(a,es16.8,es16.8)' )' Largest and smallest values from Singular Value Decomposition', sing(1), sing(nrow)
6124 [ + + ]: 4 : call wrtout([std_out], msg)
6125 : :
6126 [ - + + - : 8 : ABI_MALLOC(vmat,(1:ncol,1:ncol))
- + + - +
- + - - +
- + ]
6127 [ - + + - : 8 : ABI_MALLOC(sing1,(1:nrow,1:ncol))
- + + - +
- + - - +
- + ]
6128 [ - + + - : 6 : ABI_MALLOC(sing2,(1:ncol,1:nrow))
- + + - -
+ - + ]
6129 [ + + + + ]: 4616120 : vmat = zero
6130 [ + + + + ]: 1622792 : sing1 = zero
6131 [ + + + + ]: 1620899 : sing2 = zero
6132 [ + + ]: 2927 : do ipert1=1,ncol
6133 [ + + ]: 4616120 : do ipert2 =1,ncol
6134 : 4616118 : vmat(ipert1,ipert2) = vtmat(ipert2,ipert1)
6135 : : end do
6136 : : end do
6137 : : ! To compute the pseudoinverse, product of the singular matrix with its inverse
6138 [ + + ]: 1034 : do ipert1=1,min(nrow,ncol)
6139 : 1032 : sing1(ipert1,ipert1) = sing(ipert1)
6140 [ + + ]: 1034 : if (sing(ipert1)>tol12) then ! Avoids numerical problems
6141 : 576 : sing2(ipert1,ipert1) = 1_dp/sing(ipert1)
6142 : : end if
6143 : : end do
6144 : :
6145 [ - + + - : 6 : ABI_MALLOC(mat_tmp,(1:ncol,1:ncol))
- + + - -
+ - + ]
6146 [ - + + - : 6 : ABI_MALLOC(mat_tmp2,(1:ncol,1:ncol))
- + + - -
+ - + ]
6147 [ - + + - : 6 : ABI_MALLOC(mat_tmp3,(1:ncol,1:ncol))
- + + - -
+ - + ]
6148 : :
6149 [ - + - - : 2 : mat_tmp = matmul(sing2,sing1)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - ]
6150 [ - + - - : 2 : mat_tmp2 = matmul(vmat,mat_tmp)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - -
- ]
6151 [ - + - - : 2 : mat_tmp3 = matmul(mat_tmp2,vtmat)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - ]
6152 : :
6153 : : ! Change of IFCs and its derivatives
6154 [ + - - + : 4619045 : d2cart_sol = matmul(mat_tmp3,d2cart_vec)
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + + + +
+ + ]
6155 [ - + ]: 2 : ABI_FREE(sing)
6156 [ - + ]: 2 : ABI_FREE(sing1)
6157 [ - + ]: 2 : ABI_FREE(vmat)
6158 [ - + ]: 2 : ABI_FREE(sing2)
6159 [ - + ]: 2 : ABI_FREE(mat_tmp)
6160 [ - + ]: 2 : ABI_FREE(mat_tmp2)
6161 [ - + ]: 2 : ABI_FREE(mat_tmp3)
6162 : :
6163 : : ! Now unravel the IFCs and derivatives in arrays
6164 : :
6165 [ + + + + : 780 : d2asr = zero
+ + + + +
+ ]
6166 [ + + + + : 992 : d2dqmsr = zero
+ + + + +
+ ]
6167 [ + + + + : 2978 : d2dqdqmsr = zero
+ + + + +
+ + + ]
6168 [ + + ]: 8 : do idir1=1,3
6169 [ + + ]: 29 : do ipert1=1, natom
6170 [ + + ]: 90 : do idir2=1,3
6171 [ + + ]: 309 : do ipert2=1, natom
6172 : 225 : col = ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6173 : 225 : d2asr(1,idir1,ipert1,idir2,ipert2) = d2cart_sol(col)
6174 [ + + ]: 963 : do idir3=1,3
6175 : 675 : col = (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6176 : 675 : d2dqmsr(idir1,ipert1,idir2,ipert2,idir3) = d2cart_sol(col)
6177 [ + + ]: 2925 : do idir4=1,3
6178 : : col = 4*(3*natom)**2+3*(3*natom)**2*(idir4-1)+&
6179 : 2700 : (3*natom)**2*(idir3-1)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
6180 : : !d2dqdqmsr(idir1,ipert1,idir2,ipert2,idir3,idir4) = d2cart_sol(col)
6181 : : end do
6182 : : end do
6183 : : end do
6184 : : end do
6185 : : end do
6186 : : end do
6187 : :
6188 : :
6189 [ + + + + : 92 : msr = zero
+ + ]
6190 [ + + + + : 92 : msr_init = zero
+ + ]
6191 [ + + ]: 9 : do ipert1=1, natom
6192 [ + + ]: 30 : do idir1=1,3
6193 [ + + ]: 91 : do idir2=1,3
6194 [ + + ]: 309 : do ipert2=1, natom
6195 [ + + ]: 963 : do idir3=1,3
6196 [ + + ]: 675 : if ( bool_kdir(idir3) == 1) then ! Contribution from zone-center
6197 : 387 : tmp = d2cart(1,idir1,ipert1,idir2,ipert2)
6198 : 387 : tmp2 = tmp-d2asr(1,idir1,ipert1,idir2,ipert2)
6199 [ + + ]: 1548 : do idir4 = 1,3
6200 : : msr_init(idir1,ipert1,idir4)=msr_init(idir1,ipert1,idir4)+&
6201 : 1161 : tmp*(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
6202 : : msr(idir1,ipert1,idir4)=msr(idir1,ipert1,idir4)+&
6203 : 1548 : tmp2*(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
6204 : : end do
6205 : : end if
6206 [ + + ]: 900 : if ( bool_ldir(idir3) == 1 ) then ! Contribution from dC/dq
6207 : 288 : tmp =d2dqred(idir1,ipert1,idir2,ipert2,idir3)
6208 : 288 : tmp2=tmp-d2dqmsr(idir1,ipert1,idir2,ipert2,idir3)
6209 [ + + ]: 1152 : do idir4 = 1,3
6210 [ + + ]: 3744 : do idir5 = 1,3
6211 : : msr_init(idir1,ipert1,idir4)=msr_init(idir1,ipert1,idir4)+&
6212 : 2592 : tmp*crystal%rprimd(idir5,idir3)*Levi_Civita(idir2,idir5,idir4)
6213 : : msr(idir1,ipert1,idir4)=msr(idir1,ipert1,idir4)+&
6214 : 3456 : tmp2*crystal%rprimd(idir5,idir3)*Levi_Civita(idir2,idir5,idir4)
6215 : : end do
6216 : : end do
6217 : : end if
6218 : : end do
6219 : : end do
6220 : : end do
6221 : : end do
6222 : : end do
6223 : 2 : write(msg, '(a,a,a,a)' ) ch10, &
6224 : 2 : ' Rotational invariance breaking, before and after imposition', ch10, &
6225 : 4 : ' ipert1 idir1 idir2 torque initial [Ha/Bohr] torque final [Ha/Bohr]'
6226 [ + + ]: 6 : call wrtout([std_out, ab_out],msg)
6227 [ + + ]: 9 : do ipert1=1,natom
6228 [ + + ]: 30 : do idir1=1,3
6229 [ + + ]: 91 : do idir4=1,3
6230 : 63 : write(msg, '(a,i0,a,i0,a,i0,a, es16.8,a,es16.8)') ' ', ipert1,' ', idir1, &
6231 : 126 : ' ', idir4 , ' ', msr_init(idir1,ipert1,idir4),' ', msr(idir1,ipert1,idir4)
6232 [ + + ]: 210 : call wrtout([std_out, ab_out],msg)
6233 : : end do
6234 : : end do
6235 : : end do
6236 : :
6237 [ - + ]: 2 : ABI_FREE(msr)
6238 [ - + ]: 2 : ABI_FREE(msr_init)
6239 [ - + ]: 2 : ABI_FREE(d2cart_vec)
6240 [ - + ]: 2 : ABI_FREE(d2cart_sol)
6241 [ - + ]: 2 : ABI_FREE(vtmat)
6242 [ - + ]: 2 : ABI_FREE(cond)
6243 [ - + ]: 2 : ABI_FREE(rcond)
6244 : :
6245 : 2 : end subroutine msria_calc
6246 : :
6247 : : !----------------------------------------------------------------------
6248 : :
6249 : : !!****f* m_dynmat/msria_apply
6250 : : !! NAME
6251 : : !! msria_corr
6252 : : !!
6253 : : !! FUNCTION
6254 : : !! Imposition of the Accoustic sum rule and rotational invariance on the InterAtomic Forces
6255 : : !! respecting crystal symmetries. Note that when IFCs derivatives are estimated previously
6256 : : !! based on the Fourier transforms, they do not strictly respect them; this is only solved
6257 : : !! when using the IFCs derivatives from the LW driver. Eventually, if the latter are available,
6258 : : !! correct the IFCs to match the ones from the LW driver close to the zone-center
6259 : : !!
6260 : : !! INPUTS
6261 : : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
6262 : : !! 5 => impose hermitian solution using lapack call, 6 => rotational invariance)
6263 : : !! d2asr=matrix used to store the correction needed to fulfill the acoustic sum rule.
6264 : : !! d2dqmsr = same, but for the first IFCs moment for rotational invariance
6265 : : !! d2dqdqmsr = same, but for the second IFCs moment for rotational invariance
6266 : : !! mpert =maximum number of ipert
6267 : : !! natom=number of atom
6268 : : !! qphon(3,3)=wavevectors for the three possible phonons
6269 : : !! crystal<type(crystal_t)>=Crystal structure parameters
6270 : : !!
6271 : : !! OUTPUT
6272 : : !! Input/Output:
6273 : : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
6274 : : !!
6275 : : !! SOURCE
6276 : :
6277 : 162 : subroutine msria_apply(asr,d2asr,d2dqmsr,d2cart,mpert,natom,qphon,crystal)
6278 : :
6279 : : !Arguments -------------------------------
6280 : : !scalars
6281 : : integer,intent(in) :: asr,mpert,natom
6282 : : type(crystal_t),intent(in) :: crystal
6283 : : !arrays
6284 : : real(dp),intent(in) :: d2dqmsr(3,natom,3,natom,3)!, d2dqdqmsr(3,natom,3,natom,3,3)
6285 : : real(dp),intent(in) :: d2asr(2,3,natom,3,natom), qphon(3,3)
6286 : : real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
6287 : : !Local variables-------------------------------
6288 : : !scalars
6289 : : integer :: idir1,idir2,ipert1,ipert2,idir3,ii,jj
6290 : 0 : integer :: tiat,tjat,isym,indij(natom,natom),indij2(natom,natom,3)
6291 : : integer :: isgn, itirev,acc,acc2
6292 : 324 : real(dp) :: qsym(3), qsym2(3), symcart(3,3,crystal%nsym),arg1,arg2
6293 : : real(dp) :: re,im,re2,im2,sumr,sumi,valr,vali,carttmp
6294 : 162 : real(dp), allocatable :: pert(:,:,:,:,:,:), pert2(:,:,:,:,:,:,:)
6295 : : real(dp) :: Levi_Civita(3,3,3)
6296 : : ! *********************************************************************
6297 [ - + + - : 972 : ABI_MALLOC(pert,(1:2,1:3,1:natom,1:3,1:natom,1:2*crystal%nsym))
+ - - + +
- - + + -
+ - + - -
+ - + ]
6298 [ - + + - : 972 : ABI_MALLOC(pert2,(1:2,1:3,1:natom,1:3,1:natom,1:2*crystal%nsym,1:3))
- + + - -
+ + - + -
+ - + - -
+ - + ]
6299 [ - + ]: 162 : if (asr/=6) return
6300 : : Levi_Civita(:,:,:)=zero
6301 : : Levi_Civita(1,2,3)=+1 ; Levi_Civita(2,3,1)=+1 ; Levi_Civita(3,1,2)=+1
6302 : : Levi_Civita(3,2,1)=-1 ; Levi_Civita(1,3,2)=-1 ; Levi_Civita(2,1,3)=-1
6303 : : ! By convention, Fourier transform in ABINIT is only using the cell
6304 : : ! coordinates, not the reduced coordinates of the atoms
6305 : : ! The code that follows already take this into account
6306 : : ! for sake of legibility
6307 : : ! Define symmetry tensor for IFCs
6308 [ + + ]: 1454 : do isym=1,crystal%nsym
6309 [ + + ]: 5330 : do idir1=1,3
6310 [ + + ]: 15504 : symcart(:,idir1,isym)=zero
6311 [ + + ]: 16796 : do idir2=1,3
6312 [ + + ]: 50388 : do idir3=1,3
6313 : : symcart(:,idir1,isym)=symcart(:,idir1,isym)+crystal%rprimd(:,idir2)&
6314 [ + + ]: 151164 : *crystal%gprimd(idir1,idir3)*crystal%symrel(idir2,idir3,isym)
6315 : : end do
6316 : : end do
6317 : : end do
6318 : : end do
6319 [ + + + + : 5130792 : pert = zero; pert2 = zero
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
6320 [ + + + + : 13576 : indij = 0 ; indij2 = 0
+ + + + +
+ ]
6321 : : ! Need to loop over symmetries to properly impose rotational invariance
6322 [ + + ]: 1454 : do isym=1,crystal%nsym
6323 [ + + ]: 4038 : do itirev=1,2 ! loop over the time-reversal symmetry
6324 : 2584 : isgn=3-2*itirev
6325 [ + + ]: 14204 : do ipert1=1,natom
6326 [ + + ]: 54200 : do ipert2=1,natom
6327 : 41288 : tiat = crystal%indsym(4,isym,ipert1) ! symmetric atom of i
6328 : 41288 : tjat = crystal%indsym(4,isym,ipert2) ! symmetric atom of j
6329 [ + + ]: 165152 : qsym(:) = crystal%indsym(1:3,isym,ipert2)-crystal%indsym(1:3,isym,ipert1)
6330 [ + + ]: 165152 : qsym= -isgn*qsym
6331 [ + + ]: 165152 : arg1 = two_pi*DOT_PRODUCT(qsym,qphon(:,1))
6332 : 41288 : acc=indij(tiat,tjat)+1
6333 : 41288 : indij(tiat,tjat)=acc
6334 [ + + ]: 165152 : do idir1=1,3
6335 [ + + ]: 536744 : do idir2=1,3
6336 : 371592 : sumr=zero
6337 : 371592 : re = cos(arg1)
6338 : 371592 : im = sin(arg1)
6339 [ + + ]: 1486368 : do ii=1,3
6340 [ + + ]: 4830696 : do jj=1,3
6341 : : ! Correction from on-site and first-neighbors in the same cells (or images)
6342 : 4459104 : sumr=sumr+symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*d2asr(1,ii,tiat,jj,tjat)
6343 : : ! Second order desactivated because of missing contribution from electrostatics
6344 : : ! simply uncomment when available
6345 : : !do idir3=1,3
6346 : : ! sumr=sumr-symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
6347 : : ! d2dqdqmsr(ii,tiat,jj,tjat,idir3,idir3)/four
6348 : : !end do
6349 : : end do
6350 : : end do
6351 : 371592 : valr = re*sumr
6352 : 371592 : vali = im*sumr
6353 : 371592 : pert(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym) = valr
6354 : 495456 : pert(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym) = vali
6355 : : end do
6356 : : end do
6357 [ + + ]: 175480 : do idir3=1,3
6358 : 123864 : acc2=indij2(tiat,tjat,idir3)+1
6359 : 123864 : indij2(tiat,tjat,idir3)=acc2
6360 [ + + ]: 495456 : qsym2(:) = crystal%symrel(:,idir3,isym)
6361 [ + + ]: 495456 : qsym2(:)=-isgn*(qsym2(:))
6362 [ + + ]: 495456 : arg2 = two_pi*DOT_PRODUCT(qsym2,qphon(:,1))
6363 [ + + ]: 536744 : do idir1=1,3
6364 [ + + ]: 1610232 : do idir2=1,3
6365 : : sumi=zero
6366 : 4459104 : sumr=zero
6367 [ + + ]: 4459104 : do ii=1,3
6368 [ + + ]: 14492088 : do jj=1,3
6369 : : ! second order desactivated
6370 : : !sumr=sumr+symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
6371 : : ! d2dqdqmsr(ii,tiat,jj,tjat,idir3,idir3)/four
6372 : : sumi=sumi+isgn*symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
6373 : 13377312 : d2dqmsr(ii,tiat,jj,tjat,idir3)
6374 : : end do
6375 : : end do
6376 : 1114776 : im = -cos(arg1)*sin(arg2)
6377 : 1114776 : re = sin(arg1)*sin(arg2)
6378 : 1114776 : re2 = cos(arg1)*cos(two*arg2)
6379 : 1114776 : im2 = sin(arg1)*cos(two*arg2)
6380 : 1114776 : valr = re*sumi+re2*sumr
6381 : 1114776 : vali = im*sumi+im2*sumr
6382 : 1114776 : pert2(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)= valr
6383 : 1486368 : pert2(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)= vali
6384 : : end do !idir1
6385 : : end do !idir2
6386 : : end do !idir3
6387 : : end do !ipert2
6388 : : end do !ipert1
6389 : : end do !itirev
6390 : : end do !isym
6391 [ + + ]: 809 : do ipert1=1,natom
6392 [ + + ]: 2750 : do idir1 =1,3
6393 [ + + ]: 8411 : do idir2=1,3
6394 [ + + ]: 31029 : do ipert2=1,natom
6395 [ + + ]: 214884 : do isym=1,crystal%nsym
6396 [ + + ]: 580653 : do itirev=1,2 ! loop over the time-reversal symmetry
6397 : 371592 : isgn=3-2*itirev
6398 : : carttmp = d2cart(1,idir1,ipert1,idir2,ipert2)- &
6399 : 371592 : pert(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym)/dble(indij(ipert1,ipert2))
6400 : 371592 : d2cart(1,idir1,ipert1,idir2,ipert2) = carttmp
6401 : : carttmp = d2cart(2,idir1,ipert1,idir2,ipert2)- &
6402 : 371592 : pert(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym)/dble(indij(ipert1,ipert2))
6403 : 371592 : d2cart(2,idir1,ipert1,idir2,ipert2) = carttmp
6404 [ + + ]: 1672164 : do idir3=1,3
6405 : : carttmp = d2cart(1,idir1,ipert1,idir2,ipert2)- &
6406 : 1114776 : pert2(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)/dble(indij2(ipert1,ipert2,idir3))
6407 : 1114776 : d2cart(1,idir1,ipert1,idir2,ipert2) = carttmp
6408 : : carttmp = d2cart(2,idir1,ipert1,idir2,ipert2)- &
6409 : 1114776 : pert2(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)/dble(indij2(ipert1,ipert2,idir3))
6410 : 1486368 : d2cart(2,idir1,ipert1,idir2,ipert2) = carttmp
6411 : : end do
6412 : : end do
6413 : : end do
6414 : : end do
6415 : : end do
6416 : : end do
6417 : : end do
6418 [ - + ]: 162 : ABI_FREE(pert)
6419 [ - + ]: 162 : ABI_FREE(pert2)
6420 [ # # # # ]: 0 : end subroutine msria_apply
6421 : : !!***
6422 : 0 : end module m_dynmat
|