Line data Source code
1 : !!****m* ABINIT/m_geometry
2 : !! NAME
3 : !! m_geometry
4 : !!
5 : !! FUNCTION
6 : !! This module contains basic tools to operate on vectors expressed in reduced coordinates.
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2008-2026 ABINIT group (MG, MT, FJ, TRangel, DCA, XG, AHR, DJA, DRH)
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 : !! SOURCE
15 :
16 : #if defined HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #include "abi_common.h"
21 :
22 : MODULE m_geometry
23 :
24 : use defs_basis
25 : use m_abicore
26 : use m_errors
27 : use m_atomdata
28 : use m_sort
29 :
30 : use m_io_tools, only : open_file
31 : use m_numeric_tools, only : uniformrandom, isinteger, set2unit
32 : use m_matrix, only : mati3inv, mati3det, matr3inv
33 : use m_symtk, only : symdet
34 : use m_hide_lapack, only : matr3eigval
35 : use m_pptools, only : prmat
36 : use m_numeric_tools, only : wrap2_pmhalf
37 : use m_hide_lapack, only : matrginv
38 :
39 : implicit none
40 :
41 : private
42 :
43 : public :: normv ! Norm of vector(s) in reduced coordinates either in real or reciprocal space.
44 : public :: vdotw ! Scalar product between two reduced vectors either in real or reciprocal space.
45 : public :: acrossb ! Cross product of two 3-vectors.
46 : public :: wigner_seitz ! Find the grid of points falling inside the Wigner-Seitz cell.
47 : public :: phdispl_cart2red ! Calculate the displacement vectors for all branches in reduced coordinates.
48 : public :: phdispl_cart2red_nmodes ! Calculate the displacement vectors for nmodes in reduced coordinates.
49 : public :: getspinrot ! Compute the components of the spinor rotation matrix
50 : public :: spinrot_cmat ! Construct 2x2 complex matrix representing rotation operator in spin-space.
51 : public :: rotmat ! Finds the rotation matrix.
52 : public :: fixsym ! Check that iatfix does not break symmetry.
53 : public :: det3r ! Compute determinant of a 3x3 real matrix
54 : public :: metric ! Compute metric matrices.
55 : public :: mkradim ! Make rprim and acell from rprimd
56 : public :: mkrdim ! Make rprimd from acell from rprim
57 : public :: chkrprimd ! Test if {rprim,acell,rprimd} are consistent
58 : public :: chkdilatmx ! check if dilatation of unit cell is consistent with initial G-sphere
59 : public :: xcart2xred ! From cart coords to reduced
60 : public :: xred2xcart ! From reduced coords to cart.
61 : public :: gred2fcart ! Convert reduced gradients into cartesian forces
62 : public :: fcart2gred ! Convert cartesian forces into reduced gradients
63 : public :: bonds_lgth_angles ! Write GEO file
64 : public :: randomcellpos ! Creates unit cell with random atomic positions.
65 : public :: ioniondist ! Compute ion-ion distances
66 : public :: dist2 ! Calculates the distance of v1 and v2 in a crystal by repeating the unit cell
67 : public :: shellstruct ! Calculates shell structure (multiplicities, radii)
68 : public :: remove_inversion ! Remove the inversion symmetry and improper rotations
69 : public :: reduce2primitive ! Find real space primitive vectors from non-primitive ones and set of translations
70 : public :: symredcart ! Convert a symmetry operation from reduced coordinates (integers) to cart coords (reals)
71 : public :: strainsym ! Symmetrize the strain tensor.
72 : public :: stresssym ! Symmetrize the stress tensor.
73 : public :: stress_voigt_to_mat! Build 3x3 symmetric stress tensor from stress vector in Voigt notation.
74 : public :: strconv ! Convert from symmetric storage mode in reduced coords to cart coords.
75 : public :: littlegroup_pert ! Determines the set of symmetries that leaves a perturbation invariant.
76 : public :: irreducible_set_pert ! Determines a set of perturbations that form a basis
77 : public :: wedge_basis ! compute rprimd x gprimd vectors needed for generalized cross product
78 : public :: wedge_product ! compute wedge product given wedge basis
79 : public :: d3lwsym
80 : public :: sylwtens ! Determines the set of irreductible elements of the spatial-dispersion tensors
81 : public :: cart2spinaxis ! Compute the rotation matrix from cartesian to spinaxis coordinate
82 : public :: vcart2ylm ! Convert Cartesian vector to spherical coordinates for Y_lm
83 :
84 : interface normv
85 : module procedure normv_rdp_vector
86 : module procedure normv_int_vector
87 : !module procedure normv_int_vector_array ! WARNING for the time being, do not use these 2 procedures,
88 : !module procedure normv_rdp_vector_array ! sunstudio12 is not able to resolve which sub should be called.
89 : end interface normv
90 :
91 : interface vdotw
92 : module procedure vdotw_rr_vector
93 : module procedure vdotw_rc_vector
94 : end interface vdotw
95 :
96 : CONTAINS !===========================================================
97 : !!***
98 :
99 : !!****f* m_geometry/normv_rdp_vector
100 : !! NAME
101 : !! normv_rdp_vector
102 : !!
103 : !! FUNCTION
104 : !! Compute the norm of a vector expressed in reduced coordinates using the metric met.
105 : !! The result is multiplied by 2pi in case of a vector in reciprocal space
106 : !! to take into account the correct normalisation of the reciprocal lattice vectors
107 : !!
108 : !! INPUTS
109 : !! xv(3)=Vector in reduced coordinates
110 : !! met(3,3)=Metric tensor
111 : !! space=Character defining whether we are working in real (r|R) or reciprocal space (g|G)
112 : !!
113 : !! OUTPUT
114 : !! normv_rdp_vector=norm of xv
115 : !!
116 : !! NOTES
117 : !! The routine is able to deal both with a single vector as well as arrays of vectors.
118 : !! Versions for integer and real vectors are provided.
119 : !!
120 : !! SOURCE
121 :
122 1762519429 : function normv_rdp_vector(xv,met,space) result(res)
123 :
124 : !Arguments ------------------------------------
125 : !scalars
126 : real(dp) :: res
127 : character(len=1),intent(in) :: space
128 : !arrays
129 : real(dp),intent(in) :: met(3,3),xv(3)
130 : ! *************************************************************************
131 :
132 : res = (xv(1)*met(1,1)*xv(1) + xv(2)*met(2,2)*xv(2) + xv(3)*met(3,3)*xv(3) &
133 1762519429 : & +two*(xv(1)*met(1,2)*xv(2) + xv(1)*met(1,3)*xv(3) + xv(2)*met(2,3)*xv(3)) )
134 :
135 2782949 : select case (space)
136 : case ('r','R')
137 2782949 : res=SQRT(res)
138 : case ('g','G')
139 1759736480 : res=two_pi*SQRT(res)
140 : case default
141 1762519429 : ABI_BUG('Wrong value for space')
142 : end select
143 :
144 1762519429 : end function normv_rdp_vector
145 : !!***
146 :
147 : !----------------------------------------------------------------------
148 :
149 : !!****f* m_geometry/normv_int_vector
150 : !! NAME
151 : !! normv_int_vector
152 : !!
153 : !! FUNCTION
154 : !! Returns the norm of an integer 3D vector expressed in reduced coordinates.
155 : !! either in real or reciprocal space. In the later case the factor 2pi has
156 : !! to be included, due to the conventions used in abinit to define the reciprocal lattice.
157 : !!
158 : !! INPUTS
159 : !!
160 : !! OUTPUT
161 : !!
162 : !! SOURCE
163 :
164 1115268 : function normv_int_vector(xv, met, space) result(res)
165 :
166 : !Arguments ------------------------------------
167 : !scalars
168 : real(dp) :: res
169 : character(len=1),intent(in) :: space
170 : !arrays
171 : real(dp),intent(in) :: met(3,3)
172 : integer,intent(in) :: xv(3)
173 : ! *************************************************************************
174 :
175 : res = ( xv(1)*met(1,1)*xv(1) + xv(2)*met(2,2)*xv(2) + xv(3)*met(3,3)*xv(3) &
176 1115268 : & +two*( xv(1)*met(1,2)*xv(2) + xv(1)*met(1,3)*xv(3) + xv(2)*met(2,3)*xv(3)) )
177 :
178 0 : select case (space)
179 : case ('r','R')
180 0 : res=SQRT(res)
181 : case ('g','G')
182 1115268 : res=two_pi*SQRT(res)
183 : case default
184 1115268 : ABI_BUG('Wrong value for space')
185 : end select
186 :
187 1115268 : end function normv_int_vector
188 : !!***
189 :
190 : !----------------------------------------------------------------------
191 :
192 : !!****f* m_geometry/normv_int_vector_array
193 : !! NAME
194 : !! normv_int_vector_array
195 : !!
196 : !! FUNCTION
197 : !! Returns the norm of an array of integer 3D vectors expressed in reduced coordinates.
198 : !! either in real or reciprocal space. In the later case the factor 2pi has
199 : !! to be included, due to the conventions used in abinit to define the reciprocal lattice.
200 : !!
201 : !! INPUTS
202 : !!
203 : !! OUTPUT
204 : !!
205 : !! SOURCE
206 :
207 : function normv_int_vector_array(xv,met,space) result(res)
208 :
209 : !Arguments ------------------------------------
210 : !scalars
211 : character(len=1),intent(in) :: space
212 : !arrays
213 : real(dp),intent(in) :: met(3,3)
214 : integer,intent(in) :: xv(:,:)
215 : !this awful trick is needed to avoid problems with abilint
216 : real(dp) :: res(SIZE(xv(1,:)))
217 : ! *************************************************************************
218 :
219 : res(:) = ( xv(1,:)*met(1,1)*xv(1,:) + xv(2,:)*met(2,2)*xv(2,:) + xv(3,:)*met(3,3)*xv(3,:) &
220 : +two*(xv(1,:)*met(1,2)*xv(2,:) + xv(1,:)*met(1,3)*xv(3,:) + xv(2,:)*met(2,3)*xv(3,:)) )
221 :
222 : select case (space)
223 : case ('r','R')
224 : res(:)=SQRT(res(:))
225 : case ('g','G')
226 : res(:)=two_pi*SQRT(res(:))
227 : case default
228 : ABI_BUG('Wrong value for space')
229 : end select
230 :
231 : end function normv_int_vector_array
232 : !!***
233 :
234 : !----------------------------------------------------------------------
235 :
236 : !!****f* m_geometry/normv_rdp_vector_array
237 : !! NAME
238 : !! normv_rdp_vector_array
239 : !!
240 : !! FUNCTION
241 : !! Returns the norm of an array of real 3D vectors expressed in reduced coordinates.
242 : !! either in real or reciprocal space. In the later case the factor 2pi has
243 : !! to be included, due to the conventions used in abinit to define the reciprocal lattice.
244 : !!
245 : !! INPUTS
246 : !!
247 : !! OUTPUT
248 : !!
249 : !! SOURCE
250 :
251 : function normv_rdp_vector_array(xv,met,space) result(res)
252 :
253 : !Arguments ------------------------------------
254 : !scalars
255 : character(len=1),intent(in) :: space
256 : !arrays
257 : real(dp),intent(in) :: met(3,3)
258 : real(dp),intent(in) :: xv(:,:)
259 : !this awful trick is needed to avoid problems with abilint
260 : real(dp) :: res(SIZE(xv(1,:)))
261 : !real(dp) :: res(SIZE(xv,DIM=2))
262 : ! *************************************************************************
263 :
264 : res(:) = ( xv(1,:)*met(1,1)*xv(1,:) + xv(2,:)*met(2,2)*xv(2,:) + xv(3,:)*met(3,3)*xv(3,:) &
265 : & +two*(xv(1,:)*met(1,2)*xv(2,:) + xv(1,:)*met(1,3)*xv(3,:) + xv(2,:)*met(2,3)*xv(3,:)) )
266 :
267 : select case (space)
268 : case ('r','R')
269 : res(:)=SQRT(res(:))
270 : case ('g','G')
271 : res(:)=two_pi*SQRT(res)
272 : case default
273 : ABI_BUG('Wrong value for space')
274 : end select
275 :
276 : end function normv_rdp_vector_array
277 : !!***
278 :
279 : !----------------------------------------------------------------------
280 :
281 : !!****f* m_geometry/vdotw_rr_vector
282 : !! NAME
283 : !! vdotw_rr_vector
284 : !!
285 : !! FUNCTION
286 : !! Compute the scalar product between two vectors expressed in reduced coordinates
287 : !! The result is multiplied by (2pi)**2 in case of vectors in reciprocal space
288 : !! to take into account the correct normalisation of the reciprocal lattice vectors
289 : !!
290 : !! INPUTS
291 : !! xv(3),xw(3)=Vectors in reduced coordinates
292 : !! met(3,3)=Metric tensor
293 : !! space=Character defining whether we are working in real (r) or reciprocal space (g)
294 : !!
295 : !! OUTPUT
296 : !! res=scalar product of xv and xw
297 : !!
298 : !! SOURCE
299 :
300 0 : real(dp) function vdotw_rr_vector(xv,xw,met,space) result(res)
301 :
302 : !Arguments ------------------------------------
303 : character(len=1),intent(in) :: space
304 : !arrays
305 : real(dp),intent(in) :: met(3,3),xv(3),xw(3)
306 : ! *************************************************************************
307 :
308 : res = ( met(1,1)* xv(1)*xw(1) &
309 : +met(2,2)* xv(2)*xw(2) &
310 : +met(3,3)* xv(3)*xw(3) &
311 : +met(1,2)*(xv(1)*xw(2) + xv(2)*xw(1)) &
312 : +met(1,3)*(xv(1)*xw(3) + xv(3)*xw(1)) &
313 0 : +met(2,3)*(xv(2)*xw(3) + xv(3)*xw(2)) )
314 :
315 : select case (space)
316 : case ('r', 'R')
317 0 : return
318 : case ('g', 'G')
319 0 : res= res * (two_pi**2)
320 : case default
321 0 : ABI_BUG('Wrong value for space')
322 : end select
323 :
324 : end function vdotw_rr_vector
325 : !!***
326 :
327 : !----------------------------------------------------------------------
328 :
329 : !!****f* m_geometry/vdotw_rc_vector
330 : !! NAME
331 : !! vdotw_rc_vector
332 : !!
333 : !! FUNCTION
334 : !! Compute the scalar product between two vectors expressed in reduced coordinates
335 : !! First vector is real, the second one is complex.
336 : !! The result is multiplied by (2pi)**2 in case of vectors in reciprocal space
337 : !! to take into account the correct normalisation of the reciprocal lattice vectors
338 : !!
339 : !! INPUTS
340 : !! xv(3),xw(3)=Vectors in reduced coordinates
341 : !! met(3,3)=Metric tensor
342 : !! space=Character defining whether we are working in real (r) or reciprocal space (g)
343 : !!
344 : !! OUTPUT
345 : !! res=complex scalar product of xv and xw
346 : !!
347 : !! SOURCE
348 :
349 78114 : complex(dp) function vdotw_rc_vector(xv, xw, met, space) result(res)
350 :
351 : !Arguments ------------------------------------
352 : character(len=1),intent(in) :: space
353 : !arrays
354 : real(dp),intent(in) :: met(3,3),xv(3)
355 : complex(dp),intent(in) :: xw(3)
356 : ! *************************************************************************
357 :
358 : res = ( met(1,1)* xv(1)*xw(1) &
359 : +met(2,2)* xv(2)*xw(2) &
360 : +met(3,3)* xv(3)*xw(3) &
361 : +met(1,2)*(xv(1)*xw(2) + xv(2)*xw(1)) &
362 : +met(1,3)*(xv(1)*xw(3) + xv(3)*xw(1)) &
363 78114 : +met(2,3)*(xv(2)*xw(3) + xv(3)*xw(2)) )
364 :
365 : select case (space)
366 : case ('r', 'R')
367 78114 : return
368 : case ('g', 'G')
369 78114 : res= res * (two_pi**2)
370 : case default
371 78114 : ABI_BUG('Wrong value for space')
372 : end select
373 :
374 : end function vdotw_rc_vector
375 : !!***
376 :
377 : !----------------------------------------------------------------------
378 :
379 : !!****f* m_geometry/acrossb
380 : !! NAME
381 : !! acrossb
382 : !!
383 : !! FUNCTION
384 : !! Calculates the cross product of two 3-vectors
385 : !!
386 : !! INPUTS
387 : !! a(3): real(dp) vector
388 : !! b(3): real(dp) vector
389 : !!
390 : !! OUTPUT
391 : !! c(3): real(dp) vector = a X b
392 : !!
393 : !! SOURCE
394 :
395 5439078 : subroutine acrossb(a,b,c)
396 :
397 : !Arguments ---------------------------------------------
398 : !arrays
399 : real(dp),intent(in) :: a(3),b(3)
400 : real(dp),intent(out) :: c(3)
401 : ! *********************************************************************
402 :
403 5439078 : c(1) = a(2)*b(3) - a(3)*b(2)
404 5439078 : c(2) = -a(1)*b(3) + a(3)*b(1)
405 5439078 : c(3) = a(1)*b(2) - b(1)*a(2)
406 :
407 5439078 : end subroutine acrossb
408 : !!***
409 :
410 : !!****f* m_geometry/wedge_basis
411 : !! NAME
412 : !! wedge_basis
413 : !!
414 : !! FUNCTION
415 : !! Calculates the basis vectors a ^ a* for a in rprimd and
416 : !! a* in gprimd, needed for some generalized cross products
417 : !!
418 : !! INPUTS
419 : !! rprimd(3,3) : real(dp) matrix
420 : !! gprimd(3,3) : real(dp) matrix
421 : !! normalize,optional : whether to normalize the output vectors
422 : !!
423 : !! OUTPUT
424 : !! wedge(3,3,3) : 9 basis vectors of rprimd ^ gprimd
425 : !!
426 : !! SOURCE
427 :
428 90 : subroutine wedge_basis(gprimd,rprimd,wedge,normalize)
429 :
430 : !Arguments ---------------------------------------------
431 : ! scalars
432 : logical,optional,intent(in) :: normalize
433 : !arrays
434 : real(dp),intent(in) :: gprimd(3,3),rprimd(3,3)
435 : real(dp),intent(out) :: wedge(3,3,3)
436 :
437 : ! local
438 : !scalars
439 : integer :: igprimd, irprimd
440 : real(dp) :: nfac
441 : logical :: nvec
442 : ! *********************************************************************
443 :
444 90 : if(present(normalize)) then
445 0 : nvec = normalize
446 : else
447 : nvec = .FALSE.
448 : end if
449 :
450 360 : do irprimd = 1, 3
451 1170 : do igprimd = 1, 3
452 810 : wedge(1,irprimd,igprimd) = rprimd(2,irprimd)*gprimd(3,igprimd) - rprimd(3,irprimd)*gprimd(2,igprimd)
453 810 : wedge(2,irprimd,igprimd) = rprimd(3,irprimd)*gprimd(1,igprimd) - rprimd(1,irprimd)*gprimd(3,igprimd)
454 1080 : wedge(3,irprimd,igprimd) = rprimd(1,irprimd)*gprimd(2,igprimd) - rprimd(2,irprimd)*gprimd(1,igprimd)
455 : end do
456 : end do
457 :
458 90 : if (nvec) then
459 0 : do irprimd = 1, 3
460 0 : do igprimd = 1, 3
461 0 : if(any(abs(wedge(1:3,irprimd,igprimd)).GT.tol8)) then
462 0 : nfac = NORM2(wedge(1:3,irprimd,igprimd))
463 0 : wedge(1:3,irprimd,igprimd) = wedge(1:3,irprimd,igprimd)/nfac
464 : end if
465 : end do
466 : end do
467 : end if
468 :
469 90 : end subroutine wedge_basis
470 : !!***
471 :
472 : !!****f* m_geometry/wedge_product
473 : !! NAME
474 : !! wedge_product
475 : !!
476 : !! FUNCTION
477 : !! Calculates the wedge product u^w, given the wedge product basis a^b
478 : !! typically u=(u1 a + u2 b + u3 c) and w = (w1 a* + w2 b* + w3 c*)
479 : !!
480 : !! INPUTS
481 : !! u(3) :: real(dp) input vector
482 : !! v(3) :: real(dp) input vector
483 : !! wedgebasis(3,3,3) :: real(dp) input matrix
484 : !!
485 : !! OUTPUT
486 : !! produv(3) :: real(dp) output vector
487 : !!
488 : !! SOURCE
489 :
490 5420008 : subroutine wedge_product(produv,u,v,wedgebasis)
491 :
492 : !Arguments ---------------------------------------------
493 : !arrays
494 : real(dp),intent(in) :: u(3),v(3),wedgebasis(3,3,3)
495 : real(dp),intent(out) :: produv(3)
496 :
497 : ! local
498 : integer :: igprimd, irprimd
499 : ! *********************************************************************
500 :
501 5420008 : produv(:) = zero
502 21680032 : do irprimd = 1, 3
503 70460104 : do igprimd = 1, 3
504 211380312 : produv(1:3) = produv(1:3) + u(irprimd)*v(igprimd)*wedgebasis(1:3,irprimd,igprimd)
505 : end do
506 : end do
507 :
508 5420008 : end subroutine wedge_product
509 : !!***
510 :
511 : !!****f* m_geometry/wigner_seitz
512 : !! NAME
513 : !! wigner_seitz
514 : !!
515 : !! FUNCTION
516 : !! Calculates a grid of points that falls inside of (and eventually on the surface of)
517 : !! the Wigner-Seitz supercell centered on the origin of the B lattice with primitive
518 : !! translations nmonkh(1)*a_1+nmonkh(2)*a_2+nmonkh(3)*a_3.
519 : !! Subroutine taken from the Wannier90 code.
520 : !! Modified by MG to fulfil abinit coding rules. API slightly changed wrt the wannier90 version.
521 : !!
522 : !! COPYRIGHT
523 : !! Copyright (C) 2007 Jonathan Yates, Arash Mostofi,
524 : !! Young-Su Lee, Nicola Marzari, Ivo Souza, David Vanderbilt.
525 : !! This file is distributed under the terms of the
526 : !! GNU General Public License, see ~abinit/COPYING
527 : !! or http://www.gnu.org/copyleft/gpl.txt .
528 : !!
529 : !! INPUTS
530 : !! center(3)=The Wigner-Seitz cell is centered on this point in reduced coordinates.
531 : !! rmet(3,3)=Real space metric ($\textrm{bohr}^{2}$).
532 : !! kptrlatt(3)=Values defining the supercell.
533 : !! prtvol=If different from 0 print out the points falling inside the W-S cell and the corresponding weights.
534 : !! lmax(3)=see Notes below.
535 : !!
536 : !! OUTPUT
537 : !! npts=number of points falling inside the Wigner-Seitz cell
538 : !! irvec(3,npts)=Reduced coordinated of the points inside the W-S cell (sorted by length)
539 : !! ndegen(npts)=Weights associated to each point.
540 : !! rmods(npts)=length of the irvec
541 : !!
542 : !! SIDE EFFECTS
543 : !! irvec, ndegen and rmods are allocated with the correct
544 : !! size inside the routine and returned to the caller.
545 : !!
546 : !! NOTES
547 : !! The Wannier functions live in a supercell of the real space unit cell.
548 : !! This supercell is mp_grid unit cells long in each direction
549 : !! The algorithm loops over grid points r on a unit cell that is 8 times larger than this
550 : !! primitive supercell.
551 : !! One of these points is in the W-S cell if it is closer to center(:)
552 : !! than any of the other points R where R are the translation vectors of the supercell.
553 : !! In the end npts contains the total number of grid points that have been found in the Wigner-Seitz cell
554 : !! The number of lattice vectors R along each direction of the supercell is defined by lmax.
555 : !!
556 : !! SOURCE
557 :
558 15 : subroutine wigner_seitz(center, lmax, kptrlatt, rmet, npts, irvec, ndegen, rmods, prtvol)
559 :
560 : !Arguments ------------------------------------
561 : !scalars
562 : integer,optional,intent(in) :: prtvol
563 : integer,intent(out) :: npts
564 : !arrays
565 : integer,intent(in) :: kptrlatt(3,3),lmax(3)
566 : integer,allocatable,intent(out) :: irvec(:,:),ndegen(:)
567 : real(dp),intent(in) :: center(3),rmet(3,3)
568 : real(dp),allocatable,intent(out) :: rmods(:)
569 :
570 : !Local variables-------------------------------
571 : !scalars
572 : integer :: in1,in2,in3,l1,l2,l3,ii,icount,n1,n2,n3
573 : integer :: l0,l1_max,l2_max,l3_max,nl,verbose,mm1,mm2,mm3,ir
574 : real(dp),parameter :: TOL_DIST=tol7
575 : real(dp) :: tot,dist_min
576 : character(len=500) :: msg
577 : !arrays
578 15 : integer,allocatable :: iperm(:), swap2(:,:), swap1(:)
579 : real(dp),parameter :: gammak(3) = zero
580 : real(dp) :: diff(3)
581 15 : real(dp),allocatable :: dist(:)
582 : ! *************************************************************************
583 :
584 15 : verbose = 0; if (present(prtvol)) verbose = prtvol
585 :
586 : if (kptrlatt(1,2) /= 0 .or. kptrlatt(2,1) /= 0 .or. &
587 : kptrlatt(1,3) /= 0 .or. kptrlatt(3,1) /= 0 .or. &
588 15 : kptrlatt(2,3) /= 0 .or. kptrlatt(3,2) /= 0 ) then
589 0 : ABI_ERROR('Off-diagonal elements of kptrlatt must be zero')
590 : end if
591 :
592 15 : n1 = kptrlatt(1,1); n2 = kptrlatt(2,2); n3 = kptrlatt(3,3)
593 15 : l1_max = lmax(1); l2_max = lmax(2); l3_max = lmax(3)
594 :
595 15 : nl = (2*l1_max+1)*(2*l2_max+1)*(2*l3_max+1)
596 15 : l0 = 1+l1_max*(1+(2*l2_max+1)**2+(2*l3_max+1)) ! Index of the origin.
597 45 : ABI_MALLOC(dist, (nl))
598 :
599 : ! Allocate with maximum size
600 15 : mm1 = 2 * n1 + 1
601 15 : mm2 = 2 * n2 + 1
602 15 : mm3 = 2 * n3 + 1
603 45 : ABI_MALLOC(irvec, (3, mm1*mm2*mm3))
604 45 : ABI_MALLOC(ndegen, (mm1*mm2*mm3))
605 :
606 15 : npts = 0
607 118 : do in1=-n1,n1
608 917 : do in2=-n2,n2
609 7869 : do in3=-n3,n3
610 :
611 : ! Loop over the nl points R. R=0 corresponds to l1=l2=l3=1, or icount=l0
612 6967 : icount = 0
613 41802 : do l1=-l1_max,l1_max
614 215977 : do l2=-l2_max,l2_max
615 1079885 : do l3=-l3_max,l3_max
616 : ! Calculate |r - R -r0|^2.
617 870875 : diff(1) = in1 - l1 * n1 - center(1)
618 870875 : diff(2) = in2 - l2 * n2 - center(2)
619 870875 : diff(3) = in3 - l3 * n3 - center(3)
620 870875 : icount = icount+1
621 14108175 : dist(icount) = DOT_PRODUCT(diff, MATMUL(rmet, diff))
622 : end do
623 : end do
624 : end do
625 :
626 884809 : dist_min = MINVAL(dist)
627 :
628 7766 : if (ABS(dist(l0) - dist_min) < TOL_DIST) then
629 903 : npts = npts + 1
630 903 : ndegen (npts) = 0
631 113778 : do ii=1,nl
632 113778 : if (ABS(dist(ii) - dist_min) < TOL_DIST) ndegen(npts) = ndegen(npts) + 1
633 : end do
634 3612 : irvec(:, npts) = [in1, in2, in3]
635 : end if
636 : end do !in3
637 : end do !in2
638 : end do !in1
639 :
640 15 : if (verbose >= 1) then
641 3 : write(msg,'(a,i0)')' lattice points in Wigner-Seitz supercell: ',npts
642 3 : call wrtout(std_out, msg)
643 262 : do ii=1,npts
644 259 : write(msg,'(a,3(i3,1x),a,i0)')' vector: ', irvec(:,ii),', degeneracy: ', ndegen(ii)
645 262 : call wrtout(std_out, msg)
646 : end do
647 : end if
648 :
649 : ! Check the "sum rule"
650 15 : tot = zero
651 918 : do ii=1,npts
652 918 : tot = tot + one/ndegen(ii)
653 : end do
654 15 : if (ABS(tot-(n1*n2*n3)) > tol8) then
655 0 : write(msg,'(a,es16.8,a,i0)')'Something wrong in the generation of the WS mesh: tot: ',tot,' /= n1*n2*n3: ',n1*n2*n3
656 0 : ABI_ERROR(msg)
657 : end if
658 :
659 15 : ABI_FREE(dist)
660 :
661 : ! Reallocate ndegen and irvec with correct size and sort by norm
662 45 : ABI_MALLOC(swap2, (3, npts))
663 3627 : swap2(:,:) = irvec(1:3, 1:npts)
664 15 : ABI_FREE(irvec)
665 :
666 15 : call sort_gvecs(npts, gammak, rmet, swap2, out_gvec=irvec, iperm=iperm)
667 15 : ABI_FREE(swap2)
668 :
669 45 : ABI_MALLOC(swap1, (npts))
670 918 : swap1(:) = ndegen(1:npts)
671 30 : ABI_REMALLOC(ndegen, (npts))
672 :
673 918 : do ir=1,npts
674 918 : ndegen(ir) = swap1(iperm(ir))
675 : end do
676 :
677 45 : ABI_MALLOC(rmods, (npts))
678 918 : do ir=1,npts
679 17172 : rmods(ir) = sqrt(dot_product(irvec(:,ir), matmul(rmet, irvec(:,ir))))
680 : end do
681 :
682 15 : ABI_FREE(swap1)
683 15 : ABI_FREE(iperm)
684 :
685 15 : end subroutine wigner_seitz
686 : !!***
687 :
688 : !----------------------------------------------------------------------
689 :
690 : !!****f* m_geometry/phdispl_cart2red
691 : !! NAME
692 : !! phdispl_cart2red
693 : !!
694 : !! FUNCTION
695 : !! Calculates the displacement vectors for all branches in reduced coordinates.
696 : !! $ displ_red = displ_cart \cdot gprimd $ for each phonon branch.
697 : !!
698 : !! INPUTS
699 : !! natom=Number of atoms.
700 : !! gprimd(3,3)=Dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
701 : !! displ_cart(2,3*natom,3*natom)=Phonon displacement in Cartesian coordinates.
702 : !!
703 : !! OUTPUT
704 : !! displ_red(2,3*natom,3*natom)=Phonon displacement in reduded coordinates.
705 : !!
706 : !! SOURCE
707 :
708 12085 : pure subroutine phdispl_cart2red(natom, gprimd, displ_cart, displ_red)
709 :
710 : !Arguments ------------------------------------
711 : !scalars
712 : integer,intent(in) :: natom
713 : !arrays
714 : real(dp),intent(in) :: gprimd(3,3)
715 : real(dp),intent(in) :: displ_cart(2,3*natom,3*natom)
716 : real(dp),intent(out) :: displ_red(2,3*natom,3*natom)
717 : ! *************************************************************************
718 :
719 12085 : call phdispl_cart2red_nmodes(natom, 3*natom, gprimd, displ_cart, displ_red)
720 :
721 12085 : end subroutine phdispl_cart2red
722 : !!***
723 :
724 : !!****f* m_geometry/phdispl_cart2red_nmodes
725 : !! NAME
726 : !! phdispl_cart2red_nmodes
727 : !!
728 : !! FUNCTION
729 : !! Similar to phdispl_cart2red but operates on nmodes instead of 3*natom
730 : !!
731 : !! SOURCE
732 :
733 13471 : pure subroutine phdispl_cart2red_nmodes(natom, nmodes, gprimd, displ_cart, displ_red)
734 :
735 : !Arguments ------------------------------------
736 : !scalars
737 : integer,intent(in) :: natom, nmodes
738 : !arrays
739 : real(dp),intent(in) :: gprimd(3,3)
740 : real(dp),intent(in) :: displ_cart(2,3*natom, nmodes)
741 : real(dp),intent(out) :: displ_red(2,3*natom, nmodes)
742 :
743 : !Local variables-------------------------
744 : integer :: jbranch,iatom,idir,ibranch,kdir,k1
745 : ! *************************************************************************
746 :
747 866119 : displ_red = zero
748 :
749 67675 : do jbranch=1,nmodes
750 : !
751 156391 : do iatom=1,natom
752 409068 : do idir=1,3
753 266148 : ibranch=idir+3*(iatom-1)
754 1153308 : do kdir=1,3
755 798444 : k1 = kdir+3*(iatom-1)
756 : ! WARNING: could be non-transpose of rprimd matrix : to be checked.
757 : ! 23 june 2004: rprimd becomes gprimd. could be gprim and then multiply by acell...
758 : ! Nope, checked and ok with gprimd 24 jun 2004
759 798444 : displ_red(1,ibranch,jbranch) = displ_red(1,ibranch,jbranch) + gprimd(kdir,idir) * displ_cart(1,k1,jbranch)
760 1064592 : displ_red(2,ibranch,jbranch) = displ_red(2,ibranch,jbranch) + gprimd(kdir,idir) * displ_cart(2,k1,jbranch)
761 :
762 : end do ! kdir
763 : end do ! idir
764 : end do ! iatom
765 : end do ! jbranch
766 :
767 13471 : end subroutine phdispl_cart2red_nmodes
768 : !!***
769 :
770 : !----------------------------------------------------------------------
771 :
772 : !!****f* m_geometry/getspinrot
773 : !! NAME
774 : !! getspinrot
775 : !!
776 : !! FUNCTION
777 : !! From the symmetry matrix symrel expressed in the coordinate system rprimd,
778 : !! compute the components of the spinor rotation matrix.
779 : !!
780 : !! INPUTS
781 : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
782 : !! symrel(3,3)=symmetry operation in real space in terms of primitive translations rprimd
783 : !!
784 : !! OUTPUT
785 : !! spinrot(4)=components of the spinor rotation matrix:
786 : !!
787 : !! spinrot(1)=$\cos \phi / 2$
788 : !! spinrot(2)=$\sin \phi / 2 \times u_x$
789 : !! spinrot(3)=$\sin \phi / 2 \times u_y$
790 : !! spinrot(4)=$\sin \phi / 2 \times u_z$
791 : !!
792 : !! where $\phi$ is the angle of rotation, and $(u_x,u_y,u_z)$ is the normalized direction of the rotation axis
793 : !!
794 : !! NOTES
795 : !! Only the proper part of the symmetry operation is taken into account:
796 : !! pure rotations, while the inversion part is taken away, if present.
797 : !! as inversion acts on spinors without affecting the spin index.
798 : !!
799 : !! The whole collection of symmetry matrices is call symrel(3,3,nsym)
800 : !! symrel1 contains just one of those matrices symrel1(3,3)
801 : !!
802 : !! SOURCE
803 :
804 753756 : subroutine getspinrot(rprimd, spinrot, symrel)
805 :
806 : !Arguments ------------------------------------
807 : !arrays
808 : integer,intent(in) :: symrel(3,3)
809 : real(dp),intent(in) :: rprimd(3,3)
810 : real(dp),intent(out) :: spinrot(4)
811 :
812 : !Local variables-------------------------------
813 : !scalars
814 : integer :: det
815 : real(dp) :: cos_phi,norminv,phi,scprod,sin_phi
816 : !character(len=500) :: msg
817 : !arrays
818 : integer :: identity(3,3),symrel1(3,3)
819 : real(dp) :: axis(3),coord(3,3),coordinvt(3,3),matr1(3,3),matr2(3,3)
820 : real(dp) :: rprimd_invt(3,3),vecta(3),vectb(3),vectc(3)
821 : !**************************************************************************
822 :
823 753756 : symrel1(:,:) = symrel(:,:)
824 :
825 : ! Compute determinant of the matrix
826 753756 : call mati3det(symrel1, det)
827 :
828 : ! Produce a rotation from an improper symmetry
829 5203668 : if (det==-1) symrel1(:,:) = -symrel1(:,:)
830 :
831 : ! Test the possibility of the unit matrix
832 753756 : identity(:,:)=0; identity(1,1)=1; identity(2,2)=1; identity(3,3)=1
833 :
834 9798828 : if (sum((symrel1(:,:) - identity(:,:))**2)/=0) then
835 :
836 : ! Transform symmetry matrix in the system defined by rprimd
837 702485 : call matr3inv(rprimd, rprimd_invt)
838 9132305 : coord=TRANSPOSE(rprimd_invt)
839 702485 : call matr3inv(coord,coordinvt)
840 36529220 : matr1(:,:) = MATMUL(symrel1,coord)
841 28099400 : matr2(:,:) = MATMUL(TRANSPOSE(coordinvt),matr1)
842 :
843 : ! Find the eigenvector with unit eigenvalue of the rotation matrix in cartesian coordinate, matr2
844 702485 : matr1(:,:)=matr2(:,:)
845 702485 : matr1(1,1)=matr1(1,1)-one
846 702485 : matr1(2,2)=matr1(2,2)-one
847 702485 : matr1(3,3)=matr1(3,3)-one
848 :
849 : ! Compute the axis of rotation and the cos and sin of rotation angle
850 2809940 : if(DOT_PRODUCT(matr1(:,1),matr1(:,1)) < tol8 )then
851 : ! The first direction is the axis
852 93604 : axis(1)=one ; axis(2)=zero ; axis(3)=zero
853 93604 : cos_phi=matr2(2,2)
854 93604 : sin_phi=matr2(3,2)
855 2435524 : else if(DOT_PRODUCT(matr1(:,2),matr1(:,2)) < tol8 )then
856 : ! The second direction is the axis
857 90153 : axis(1)=zero ; axis(2)=one ; axis(3)=zero
858 90153 : cos_phi=matr2(3,3)
859 90153 : sin_phi=matr2(1,3)
860 : else
861 : ! In this case, try use the first and second vector to build the
862 : ! rotation axis: compute their cross product
863 518728 : axis(1)=matr1(2,1)*matr1(3,2)-matr1(2,2)*matr1(3,1)
864 518728 : axis(2)=matr1(3,1)*matr1(1,2)-matr1(3,2)*matr1(1,1)
865 518728 : axis(3)=matr1(1,1)*matr1(2,2)-matr1(1,2)*matr1(2,1)
866 : ! Then, try to normalize it
867 2074912 : scprod=DOT_PRODUCT(axis(:), axis(:))
868 518728 : if(scprod<tol8)then
869 : ! The first and second vectors were linearly dependent
870 : ! Thus, use the first and third vectors
871 70465 : axis(1)=matr1(2,1)*matr1(3,3)-matr1(2,3)*matr1(3,1)
872 70465 : axis(2)=matr1(3,1)*matr1(1,3)-matr1(3,3)*matr1(1,1)
873 70465 : axis(3)=matr1(1,1)*matr1(2,3)-matr1(1,3)*matr1(2,1)
874 : ! Normalize the vector
875 281860 : scprod=DOT_PRODUCT(axis(:), axis(:))
876 70465 : if(scprod < tol8)then
877 0 : ABI_BUG('Cannot find the rotation axis.')
878 : end if
879 : end if
880 518728 : norminv=one/sqrt(scprod)
881 2074912 : axis(:)=axis(:)*norminv
882 :
883 : ! Project the axis vector out of the first unit vector,
884 : ! and renormalize the projected vector
885 : ! (the first vector cannot be the axis, as tested before)
886 518728 : vecta(1)=one-axis(1)**2
887 518728 : vecta(2)=-axis(1)*axis(2)
888 518728 : vecta(3)=-axis(1)*axis(3)
889 2074912 : scprod=DOT_PRODUCT(vecta(:),vecta(:))
890 518728 : norminv=one/sqrt(scprod)
891 2074912 : vecta(:)=vecta(:)*norminv
892 : ! Rotate the vector A, to get vector B
893 2074912 : vectb(:)=matr2(:,1)*vecta(1)+matr2(:,2)*vecta(2)+matr2(:,3)*vecta(3)
894 : ! Get dot product of vectors A and B, giving cos of the rotation angle
895 2074912 : cos_phi=DOT_PRODUCT(vecta(:),vectb(:))
896 : ! Compute the cross product of the axis and vector A
897 518728 : vectc(1)=axis(2)*vecta(3)-axis(3)*vecta(2)
898 518728 : vectc(2)=axis(3)*vecta(1)-axis(1)*vecta(3)
899 518728 : vectc(3)=axis(1)*vecta(2)-axis(2)*vecta(1)
900 : ! Get dot product of vectors B and C, giving sin of the rotation angle
901 2074912 : sin_phi=DOT_PRODUCT(vectb(:),vectc(:))
902 : end if
903 :
904 : ! Get the rotation angle, then the parameters of the spinor rotation
905 : ! Here, treat possible inaccurate values of the cosine of phi
906 702485 : if(cos_phi> one-tol8 )cos_phi= one-tol8
907 : if(cos_phi<-(one-tol8))cos_phi=-(one-tol8)
908 702485 : phi=acos(cos_phi)
909 702485 : if(sin_phi<zero)phi=-phi
910 : ! Rectify the angle, such that its absolute values corresponds to 180, 120, 90, 60, or 0 degrees
911 702485 : phi=(nint(six*phi/pi))/six*pi
912 : ! Compute components of the spinor matrix
913 702485 : spinrot(1)=cos(half*phi)
914 702485 : spinrot(2)=axis(1)*sin(half*phi)
915 702485 : spinrot(3)=axis(2)*sin(half*phi)
916 702485 : spinrot(4)=axis(3)*sin(half*phi)
917 :
918 : else
919 :
920 : ! Here, the case of the unit matrix
921 : axis(:)=zero
922 51271 : phi=zero
923 51271 : spinrot(1)=one
924 51271 : spinrot(2)=zero
925 51271 : spinrot(3)=zero
926 51271 : spinrot(4)=zero
927 :
928 : end if ! the case of the identity matrix
929 :
930 : !write(std_out,*)' getspinrot :'; write(std_out,*)' symre =',symrel(:,:)
931 : !write(std_out,*)' symrel1 =',symrel1(:,:); write(std_out,*)' rprimd =',rprimd(:,:)
932 : !write(std_out,*)' matr2 =',matr2(:,:); write(std_out,*)' matr1 =',matr1(:,:)
933 : !write(std_out,*)' phi (degree)=',phi*180._dp/pi; write(std_out,'(a,3d16.6)' )' axis=',axis(:)
934 : !write(std_out,*)' vecta=',vecta(:)
935 : !stop
936 :
937 753756 : end subroutine getspinrot
938 : !!***
939 :
940 : !!****f* m_geometry/spinrot_cmat
941 : !! NAME
942 : !! spinrot_cmat
943 : !!
944 : !! FUNCTION
945 : !! Construct 2x2 complex matrix representing the rotation operator in spin-space.
946 : !!
947 : !! INPUTS
948 : !! spinrot(4)=components of the spinor rotation matrix computed by getspinrot
949 : !!
950 : !! OUTPUT
951 : !! spinrot(2,2)=Rotation matrix (complex array)
952 : !!
953 : !! SOURCE
954 :
955 0 : pure function spinrot_cmat(spinrot)
956 :
957 : !Arguments ------------------------------------
958 : real(dp),intent(in) :: spinrot(4)
959 : complex(dp) :: spinrot_cmat(2,2)
960 : ! *************************************************************************
961 :
962 : ! Build rotation matrix from spinrot:
963 : !
964 : ! ( cos(phi/2) + i n_z sin(phi/2), (+n_y + i n_x) sin(phi/2) )
965 : ! ( (-n_y + i n_x) sin(phi/2) , cos(phi/2) - i n_z sin(phi/2) )
966 :
967 : ! spinrot(1)=cos(half*phi)
968 : ! spinrot(2)=axis(1)*sin(half*phi)
969 : ! spinrot(3)=axis(2)*sin(half*phi)
970 : ! spinrot(4)=axis(3)*sin(half*phi)
971 :
972 : ! Rotation in spinor space (same equations as in wfconv)
973 : ! TODO: Be careful here as wfconv uses symrel^T to map k-points (listkk)
974 : ! thus the inverse of the corresponding symrec.
975 : ! This may explain why all the terms with sin(phi/2) change sign (phi --> -phi)
976 :
977 0 : spinrot_cmat(1,1) = spinrot(1) + j_dpc*spinrot(4)
978 0 : spinrot_cmat(1,2) = spinrot(3) + j_dpc*spinrot(2)
979 0 : spinrot_cmat(2,1) =-spinrot(3) + j_dpc*spinrot(2)
980 0 : spinrot_cmat(2,2) = spinrot(1) - j_dpc*spinrot(4)
981 :
982 : ! My equation
983 : !spinrot_cmat(1,1) = spinrot(1) - j_dpc*spinrot(4)
984 : !spinrot_cmat(1,2) =-spinrot(3) - j_dpc*spinrot(2)
985 : !spinrot_cmat(2,1) = spinrot(3) - j_dpc*spinrot(2)
986 : !spinrot_cmat(2,2) = spinrot(1) + j_dpc*spinrot(4)
987 :
988 : end function spinrot_cmat
989 : !!***
990 :
991 : !----------------------------------------------------------------------
992 :
993 : !!****f* m_geometry/rotmat
994 : !! NAME
995 : !! rotmat
996 : !!
997 : !! FUNCTION
998 : !! Finds the rotation matrix.
999 : !!
1000 : !! INPUTS
1001 : !! xaxis(3)= vectors defining the x axis
1002 : !! zaxis(3)= vectors defining the z axis
1003 : !!
1004 : !! OUTPUT
1005 : !! inversion_flag = flag that indicates that an inversion operation
1006 : !! on the coordinate system should be done
1007 : !! umat(3,3)= matrix that rotates the x=(1 0 0) and z=(0 0 1) to the new
1008 : !! values defined in xaxis and zaxis
1009 : !!
1010 : !! NOTES
1011 : !! Here I set that the axe x is originally at the 1 0 0 direction and z is originally 0 0 1.
1012 : !! So calling rotmat(x',z') will find the rotation
1013 : !! matrix for the case in which we rotate the x and z
1014 : !! axes from their default values to x' and z'.
1015 : !!
1016 : !! SOURCE
1017 :
1018 4 : subroutine rotmat(xaxis, zaxis, inversion_flag, umat)
1019 :
1020 : !Arguments ------------------------------------
1021 : !scalars
1022 : integer,intent(out) :: inversion_flag
1023 : !arrays
1024 : real(dp),intent(in) :: xaxis(3),zaxis(3)
1025 : real(dp),intent(out) :: umat(3,3)
1026 :
1027 : !Local variables-------------------------------
1028 : !scalars
1029 : real(dp) :: cosine,xmod,zmod
1030 : character(len=500) :: msg
1031 : !arrays
1032 : real(dp) :: yaxis(3)
1033 : ! *************************************************************************
1034 :
1035 16 : xmod = NORM2(xaxis(:))
1036 16 : zmod = NORM2(zaxis(:))
1037 :
1038 4 : if(xmod < 1.d-8)then
1039 : write(msg,'(a,a,a,i0)')&
1040 0 : 'The module of the xaxis should be greater than 1.d-8,',ch10,'however, |xaxis|=',xmod
1041 0 : ABI_BUG(msg)
1042 : end if
1043 :
1044 4 : if(zmod < 1.d-8)then
1045 0 : write(msg,'(a,a,a,i0)')'The module of the zaxis should be greater than 1.d-8,',ch10,'however, |zaxis|=',zmod
1046 0 : ABI_ERROR(msg)
1047 : end if
1048 :
1049 : !verify that both axis are perpendicular
1050 16 : cosine = DOT_PRODUCT(xaxis,zaxis)/(xmod*zmod)
1051 :
1052 4 : if(abs(cosine) > 1.d-8)then
1053 0 : write(msg,'(a,a,a,i6)')'xaxis and zaxis should be perpendicular,',ch10,'however, cosine=',cosine
1054 0 : ABI_BUG(msg)
1055 : end if
1056 :
1057 : !new y axis as cross product
1058 4 : yaxis(1) = (zaxis(2)*xaxis(3) - xaxis(2)*zaxis(3))/(xmod*zmod)
1059 4 : yaxis(2) = (zaxis(3)*xaxis(1) - xaxis(3)*zaxis(1))/(xmod*zmod)
1060 4 : yaxis(3) = (zaxis(1)*xaxis(2) - xaxis(1)*zaxis(2))/(xmod*zmod)
1061 :
1062 : !hack to allow inversion operation on coordinate transformation
1063 : !uses unlikely large but legal values of proj_x and/or proj_z
1064 : !to flag inversion
1065 4 : inversion_flag=0
1066 4 : if(xmod>10._dp .or. zmod>10._dp) then
1067 0 : inversion_flag=1
1068 : write(msg, '(4a)' )&
1069 0 : 'inversion operation will be appended to axis transformation',ch10,&
1070 0 : 'Action: If you did not intend this, make |z|<10 and |x|<10 ',ch10
1071 0 : call wrtout(std_out,msg)
1072 : end if
1073 :
1074 16 : umat(1,:) = xaxis(:)/xmod
1075 16 : umat(2,:) = yaxis(:)
1076 16 : umat(3,:) = zaxis(:)/zmod
1077 :
1078 4 : end subroutine rotmat
1079 : !!***
1080 :
1081 : !!****f* m_geometry/fixsym
1082 : !! NAME
1083 : !! fixsym
1084 : !!
1085 : !! FUNCTION
1086 : !! Using input indsym which tells which atoms are related by symmetry,
1087 : !! check that iatfix consistently fixes (freezes) all atoms which are
1088 : !! related by symmetry, i.e. that iatfix does not break symmetry.
1089 : !!
1090 : !! INPUTS
1091 : !! iatfix(3,natom)=integer array with 1 in every position for which
1092 : !! the atom is to be kept fixed
1093 : !! NOTE that this is not the input data structure for iatfix but it is
1094 : !! the internal data structure used through most of the subroutines
1095 : !! indsym(4,nsym,natom)=indirect indexing array for symmetrically related
1096 : !! atoms; 4th element is label of symmetrically related atom
1097 : !! natom=number of atoms
1098 : !! nsym=number of symmetries (should be > 1 when this is called)
1099 : !!
1100 : !! OUTPUT
1101 : !! (only checking)
1102 : !!
1103 : !! NOTE
1104 : !! Stops execution with an error message if iatfix breaks symmetry.
1105 : !!
1106 : !! SOURCE
1107 :
1108 4536 : subroutine fixsym(iatfix,indsym,natom,nsym)
1109 :
1110 : !Arguments ------------------------------------
1111 : !scalars
1112 : integer,intent(in) :: natom,nsym
1113 : !arrays
1114 : integer,intent(in) :: iatfix(3,natom),indsym(4,nsym,natom)
1115 :
1116 : !Local variables-------------------------------
1117 : !scalars
1118 : integer :: iatom,isym,jatom
1119 : character(len=500) :: msg
1120 : ! *************************************************************************
1121 :
1122 4536 : if (nsym > 1) then
1123 14498 : do iatom=1,natom
1124 261882 : do isym=1,nsym
1125 : ! jatom is the label of a symmetrically related atom
1126 247384 : jatom=indsym(4,isym,iatom)
1127 : ! Thus the atoms jatom and iatom must be fixed along the same directions
1128 : if (iatfix(1,jatom) /= iatfix(1,iatom) .or. &
1129 247384 : iatfix(2,jatom) /= iatfix(2,iatom) .or. &
1130 9962 : iatfix(3,jatom) /= iatfix(3,iatom)) then
1131 : write(msg, '(a,i0,a,i0,7a)' )&
1132 0 : 'Atom number: ',jatom,' is symmetrically equivalent to atom number: ',iatom,',',ch10,&
1133 0 : 'but according to iatfix, iatfixx, iatfixy and iatfixz, they',ch10,&
1134 0 : 'are not fixed along the same directions, which is forbidden.',ch10,&
1135 0 : 'Action: modify either the symmetry or iatfix(x,y,z) and resubmit.'
1136 0 : ABI_ERROR(msg)
1137 : end if
1138 : end do
1139 : end do
1140 : end if
1141 :
1142 4536 : end subroutine fixsym
1143 : !!***
1144 :
1145 : !!****f* m_geometry/det3r
1146 : !! NAME
1147 : !! det3r
1148 : !!
1149 : !! FUNCTION
1150 : !! Compute determinant of a 3x3 real matrix
1151 : !!
1152 : !! SOURCE
1153 :
1154 0 : pure real(dp) function det3r(rprimd)
1155 :
1156 : !Arguments ------------------------------------
1157 : real(dp),intent(in) :: rprimd(3,3)
1158 : ! *************************************************************************
1159 :
1160 : ! Compute unit cell volume
1161 : det3r = rprimd(1,1)*(rprimd(2,2)*rprimd(3,3)-rprimd(3,2)*rprimd(2,3))+&
1162 : rprimd(2,1)*(rprimd(3,2)*rprimd(1,3)-rprimd(1,2)*rprimd(3,3))+&
1163 0 : rprimd(3,1)*(rprimd(1,2)*rprimd(2,3)-rprimd(2,2)*rprimd(1,3))
1164 :
1165 0 : end function det3r
1166 : !!***
1167 :
1168 : !!****f* m_geometry/metric
1169 : !! NAME
1170 : !! metric
1171 : !!
1172 : !! FUNCTION
1173 : !! Compute first dimensional primitive translation vectors in reciprocal space
1174 : !! gprimd from rprimd, and eventually writes out.
1175 : !! Then, computes metrics for real and recip space rmet and gmet using length
1176 : !! dimensional primitive translation vectors in columns of rprimd(3,3) and gprimd(3,3).
1177 : !! gprimd is the inverse transpose of rprimd.
1178 : !! i.e. $ rmet_{i,j}= \sum_k ( rprimd_{k,i}*rprimd_{k,j} ) $
1179 : !! $ gmet_{i,j}= \sum_k ( gprimd_{k,i}*gprimd_{k,j} ) $
1180 : !! Also computes unit cell volume ucvol in $\textrm{bohr}^3$
1181 : !!
1182 : !! INPUTS
1183 : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
1184 : !! iout=unit number of output file. If iout<0, do not write output.
1185 : !!
1186 : !! OUTPUT
1187 : !! gmet(3,3)=reciprocal space metric ($\textrm{bohr}^{-2}$).
1188 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
1189 : !! rmet(3,3)=real space metric ($\textrm{bohr}^{2}$).
1190 : !! ucvol=unit cell volume ($\textrm{bohr}^{3}$).
1191 : !!
1192 : !! SOURCE
1193 :
1194 1915833 : subroutine metric(gmet, gprimd, iout, rmet, rprimd, ucvol)
1195 :
1196 : !Arguments ------------------------------------
1197 : !scalars
1198 : integer,intent(in) :: iout
1199 : real(dp),intent(out) :: ucvol
1200 : !arrays
1201 : real(dp),intent(in) :: rprimd(3,3)
1202 : real(dp),intent(out) :: gmet(3,3),gprimd(3,3),rmet(3,3)
1203 :
1204 : !Local variables-------------------------------
1205 : !scalars
1206 : integer :: nu
1207 : character(len=500) :: msg
1208 : !arrays
1209 : real(dp) :: angle(3)
1210 : ! *************************************************************************
1211 :
1212 : ! Compute unit cell volume
1213 : ucvol=rprimd(1,1)*(rprimd(2,2)*rprimd(3,3)-rprimd(3,2)*rprimd(2,3))+&
1214 : rprimd(2,1)*(rprimd(3,2)*rprimd(1,3)-rprimd(1,2)*rprimd(3,3))+&
1215 1915833 : rprimd(3,1)*(rprimd(1,2)*rprimd(2,3)-rprimd(2,2)*rprimd(1,3))
1216 : !ucvol = det3r(rprimd)
1217 :
1218 : ! Check that the input primitive translations are not linearly dependent (and none is zero); i.e. ucvol~=0
1219 : ! Also ask that the mixed product is positive.
1220 1915833 : if (abs(ucvol)<tol12) then
1221 : !write(std_out,*)"rprimd",rprimd,"ucvol",ucvol
1222 : write(msg,'(6a,3(a,3es16.6,a))')&
1223 0 : 'Input rprim and acell gives vanishing unit cell volume.',ch10,&
1224 0 : 'This indicates linear dependency between primitive lattice vectors',ch10,&
1225 0 : 'Action: correct either rprim or acell in input file.', ch10, &
1226 0 : 'Rprimd =',rprimd(:,1),ch10,&
1227 0 : ' ',rprimd(:,2),ch10,&
1228 0 : ' ',rprimd(:,3),ch10
1229 0 : ABI_ERROR(msg)
1230 : end if
1231 1915833 : if (ucvol<zero)then
1232 : write(msg,'(2a,3(a,3es16.6,a),7a)')&
1233 0 : 'Current rprimd gives negative (R1 x R2) . R3 . ',ch10,&
1234 0 : 'Rprimd =',rprimd(:,1),ch10,&
1235 0 : ' ',rprimd(:,2),ch10,&
1236 0 : ' ',rprimd(:,3),ch10,&
1237 0 : 'Action: if the cell size and shape are fixed (optcell==0),',ch10,&
1238 0 : ' exchange two of the input rprim vectors;',ch10,&
1239 0 : ' if you are optimizing the cell size and shape (optcell/=0),',ch10,&
1240 0 : ' maybe the move was too large, and you might try to decrease strprecon.'
1241 0 : ABI_ERROR(msg)
1242 : end if
1243 :
1244 : ! Generate gprimd
1245 1915833 : call matr3inv(rprimd, gprimd)
1246 :
1247 : ! Write out rprimd, gprimd and ucvol
1248 1915833 : if (iout>=0) then
1249 7853 : write(msg,'(2a)')' Real(R)+Recip(G) ','space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):'
1250 7853 : call wrtout(iout,msg)
1251 31412 : do nu=1,3
1252 : write(msg, '(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)' ) &
1253 94236 : 'R(',nu,')=',rprimd(:,nu)+tol10,&
1254 117795 : 'G(',nu,')=',gprimd(:,nu)+tol10
1255 31412 : call wrtout(iout,msg)
1256 : end do
1257 7853 : write(msg,'(a,1p,e15.7,a)') ' Unit cell volume ucvol=',ucvol+tol10,' bohr^3'
1258 7853 : call wrtout(iout,msg)
1259 7853 : call wrtout(std_out,msg)
1260 : end if
1261 :
1262 : ! Compute real space metric.
1263 76633320 : rmet = MATMUL(TRANSPOSE(rprimd),rprimd)
1264 :
1265 : ! Compute reciprocal space metric.
1266 76633320 : gmet = MATMUL(TRANSPOSE(gprimd),gprimd)
1267 :
1268 : ! Write out the angles
1269 1915833 : if (iout>=0) then
1270 7853 : angle(1)=acos(rmet(2,3)/sqrt(rmet(2,2)*rmet(3,3)))/two_pi*360.0d0
1271 7853 : angle(2)=acos(rmet(1,3)/sqrt(rmet(1,1)*rmet(3,3)))/two_pi*360.0d0
1272 7853 : angle(3)=acos(rmet(1,2)/sqrt(rmet(1,1)*rmet(2,2)))/two_pi*360.0d0
1273 7853 : write(msg, '(a,3es16.8,a)' )' Angles (23,13,12)=',angle(1:3),' degrees'
1274 7853 : call wrtout(iout,msg)
1275 7853 : call wrtout(std_out,msg)
1276 : end if
1277 :
1278 1915833 : end subroutine metric
1279 : !!***
1280 :
1281 : !!****f* m_geometry/mkradim
1282 : !! NAME
1283 : !! mkradim
1284 : !!
1285 : !! FUNCTION
1286 : !! Not so trivial subroutine to make dimensionless real space
1287 : !! primitive translations rprim(3,3) from dimensional rprimd(3).
1288 : !! also make acell(3).
1289 : !!
1290 : !! INPUTS
1291 : !! rprimd(3,3)=dimensional real space primitive translations (bohr)
1292 : !! where: rprimd(i,j)=rprim(i,j)*acell(j)
1293 : !!
1294 : !! OUTPUT
1295 : !! acell(3)=unit cell length scales (bohr)
1296 : !! rprim(3,3)=dimensionless real space primitive translations
1297 : !!
1298 : !! SOURCE
1299 :
1300 513 : subroutine mkradim(acell,rprim,rprimd)
1301 :
1302 : !Arguments ------------------------------------
1303 : !arrays
1304 : real(dp),intent(out) :: acell(3),rprim(3,3)
1305 : real(dp),intent(in) :: rprimd(3,3)
1306 :
1307 : !Local variables-------------------------------
1308 : !scalars
1309 : integer :: ii,jj
1310 : real(dp) :: rprim_maxabs
1311 : ! *************************************************************************
1312 :
1313 : !Use a representation based on normalised rprim vectors
1314 2052 : do ii=1,3
1315 6156 : acell(ii)=NORM2(rprimd(:,ii))
1316 6669 : rprim(:,ii)=rprimd(:,ii)/acell(ii)
1317 : end do
1318 :
1319 : !Suppress meaningless values
1320 6669 : rprim_maxabs=maxval(abs(rprim))
1321 2052 : do ii=1,3
1322 6669 : do jj=1,3
1323 6156 : if(abs(rprim(ii,jj))<tol12*rprim_maxabs)rprim(ii,jj)=zero
1324 : enddo
1325 : enddo
1326 :
1327 513 : end subroutine mkradim
1328 : !!***
1329 :
1330 : !!****f* m_geometry/chkrprimd
1331 : !!
1332 : !! NAME
1333 : !! chkrprimd
1334 : !!
1335 : !! FUNCTION
1336 : !! Test if {rprim,acell,rprimd} are consistent
1337 : !! It means that rprimd can be reconstructed from the rprim and acell
1338 : !! Output a message if is not the case
1339 : !!
1340 : !! INPUTS
1341 : !!
1342 : !! OUTPUT
1343 : !! (only writing)
1344 : !!
1345 : !! SOURCE
1346 :
1347 0 : subroutine chkrprimd(acell,rprim,rprimd,iout)
1348 :
1349 : !Arguments ------------------------------------
1350 : !scalars
1351 : integer,intent(in) :: iout
1352 : !arrays
1353 : real(dp),intent(in) :: rprim(3,3)
1354 : real(dp),intent(in) :: rprimd(3,3)
1355 : real(dp),intent(in) :: acell(3)
1356 :
1357 : !Local variables-------------------------------
1358 : !scalars
1359 : integer :: ii,jj
1360 : !arrays
1361 : real(dp) :: rprimd_test(3,3)
1362 : logical :: equal
1363 :
1364 : ! ***********************************************************
1365 :
1366 : !###########################################################
1367 : !### 1. Compute rprimd from rprim and acell
1368 0 : do ii=1,3
1369 0 : rprimd_test(ii,1:3)=rprim(ii,1:3)*acell(1:3)
1370 : end do
1371 :
1372 :
1373 : !###########################################################
1374 : !### 2. Compare rprimd and rprimd_test
1375 :
1376 : equal=.TRUE.
1377 0 : do ii=1,3
1378 0 : do jj=1,3
1379 0 : if (abs(rprimd_test(ii,jj)-rprimd(ii,jj))>1.E-12) then
1380 0 : equal=.FALSE.
1381 : end if
1382 : end do
1383 : end do
1384 :
1385 0 : if (equal)then
1386 0 : write(iout,*) 'chkrprimd: rprimd is consistent'
1387 : else
1388 0 : write(iout,*) 'chkrprimd: rprimd is NOT consistent ERROR'
1389 : end if
1390 :
1391 0 : end subroutine chkrprimd
1392 : !!***
1393 :
1394 : !!****f* m_geometry/chkdilatmx
1395 : !! NAME
1396 : !! chkdilatmx
1397 : !!
1398 : !! FUNCTION
1399 : !! Check whether the new rprimd does not give a too large number
1400 : !! of plane waves, compared to the one booked for rprimd, taking
1401 : !! into account the maximal dilatation dilatmx. Actually check whether
1402 : !! the new Fermi sphere is inside the old one, dilated.
1403 : !!
1404 : !! INPUTS
1405 : !! chkdilatmx_ = if 1, will prevent to have any vector outside the Fermi sphere, possibly
1406 : !! by rescaling (three times at most), and then stopping the execution
1407 : !! if 0, simply send a warning, but continues execution
1408 : !! dilatmx = maximal dilatation factor (usually the input variable)
1409 : !! rprimd = new primitive vectors
1410 : !! rprimd_orig = original primitive vectors (usually the input variable)
1411 : !!
1412 : !! OUTPUT
1413 : !! dilatmx_errmsg=Empty string if calculation can continue.
1414 : !! If the calculation cannot continue, dilatmx_errmsg will contain
1415 : !! the message that should be reported in the output file.
1416 : !!
1417 : !! Client code should handle a possible problem with the following test:
1418 : !!
1419 : !! if (LEN_TRIM(dilatmx_errmsg) then
1420 : !! dump dilatmx_errmsg to the main output file.
1421 : !! handle_error
1422 : !! end if
1423 : !!
1424 : !! SOURCE
1425 :
1426 11540 : subroutine chkdilatmx(chkdilatmx_,dilatmx,rprimd,rprimd_orig,dilatmx_errmsg)
1427 :
1428 : !Arguments ------------------------------------
1429 : !scalars
1430 : integer,intent(in) :: chkdilatmx_
1431 : real(dp),intent(in) :: dilatmx
1432 : character(len=500),intent(out) :: dilatmx_errmsg
1433 : !arrays
1434 : real(dp),intent(inout) :: rprimd(3,3)
1435 : real(dp),intent(in) :: rprimd_orig(3,3)
1436 :
1437 : !Local variables-------------------------------
1438 : !scalars
1439 : real(dp) :: alpha,dilatmx_new
1440 : !arrays
1441 : real(dp) :: eigval(3),gprimd_orig(3,3),met(3,3),old_to_new(3,3)
1442 : character(len=500) :: msg
1443 : ! *************************************************************************
1444 :
1445 : !Generates gprimd
1446 11540 : call matr3inv(rprimd_orig,gprimd_orig)
1447 :
1448 : !Find the matrix that transform an original xcart to xred, then to the new xcart
1449 461600 : old_to_new(:,:) = MATMUL(rprimd, TRANSPOSE(gprimd_orig))
1450 :
1451 : !The largest increase in length will be obtained thanks
1452 : !to the diagonalization of the corresponding metric matrix :
1453 : !it is the square root of its largest eigenvalue.
1454 461600 : met(:,:) = MATMUL(TRANSPOSE(old_to_new),old_to_new)
1455 :
1456 11540 : call matr3eigval(eigval,met)
1457 :
1458 57700 : dilatmx_new=sqrt(maxval(eigval(:)))
1459 :
1460 11540 : dilatmx_errmsg = ""
1461 11540 : if(dilatmx_new>dilatmx+tol6)then
1462 :
1463 : ! MJV 2014 07 22: correct rprim to maximum jump allowed by dilatmx
1464 : ! XG 20171011 : eigenvalues of "old_to_old" tensor are of course the unity !
1465 :
1466 31 : if(chkdilatmx_/=0)then
1467 17 : alpha = (dilatmx - one) / (dilatmx_new - one)
1468 : ! for safety, only 90 percent of max jump
1469 17 : alpha = 0.9_dp * alpha
1470 :
1471 221 : rprimd = alpha * rprimd + (one - alpha) * rprimd_orig
1472 :
1473 : write(dilatmx_errmsg,'(3a,es16.6,4a,es16.6,2a,es16.6,a)')&
1474 17 : 'The new primitive vectors rprimd (an evolving quantity)',ch10,&
1475 17 : 'are too large with respect to the old rprimd and the accompanying dilatmx: ',dilatmx,ch10,&
1476 17 : 'This large change of unit cell parameters is not allowed by the present value of dilatmx.',ch10,&
1477 17 : 'An adequate value would have been dilatmx_new= ',dilatmx_new,ch10,&
1478 34 : 'Calculation continues with limited jump, by rescaling the projected move by the factor: ',alpha,'.'
1479 : else
1480 : write(msg, '(3a,es16.6,2a,es16.6,2a)' )&
1481 14 : 'The new primitive vectors rprimd (an evolving quantity)',ch10,&
1482 14 : 'are too large, given the initial rprimd and the accompanying dilatmx: ',dilatmx,ch10,&
1483 14 : 'An adequate value would have been dilatmx_new= ',dilatmx_new,ch10,&
1484 28 : 'As chkdilatmx=0, assume experienced user. Execution will continue.'
1485 14 : ABI_WARNING(msg)
1486 : end if
1487 :
1488 : end if
1489 :
1490 11540 : end subroutine chkdilatmx
1491 : !!***
1492 :
1493 : !!****f* m_geometry/mkrdim
1494 : !! NAME
1495 : !! mkrdim
1496 : !!
1497 : !! FUNCTION
1498 : !! Trivial subroutine to make dimensional real space
1499 : !! primitive translations from length scales acell(3)
1500 : !! and dimensionless translations rprim(3,3).
1501 : !!
1502 : !! INPUTS
1503 : !! acell(3)=unit cell length scales (bohr)
1504 : !! rprim(3,3)=dimensionless real space primitive translations
1505 : !!
1506 : !! OUTPUT
1507 : !! rprimd(3,3)=dimensional real space primitive translations (bohr)
1508 : !! where: rprimd(i,j)=rprim(i,j)*acell(j)
1509 : !!
1510 : !! SOURCE
1511 :
1512 90539 : subroutine mkrdim(acell,rprim,rprimd)
1513 :
1514 : !Arguments ------------------------------------
1515 : !arrays
1516 : real(dp),intent(in) :: acell(3),rprim(3,3)
1517 : real(dp),intent(out) :: rprimd(3,3)
1518 :
1519 : !Local variables-------------------------------
1520 : integer :: ii,jj
1521 : ! *************************************************************************
1522 :
1523 362156 : do ii=1,3
1524 1177007 : do jj=1,3
1525 1086468 : rprimd(ii,jj)=rprim(ii,jj)*acell(jj)
1526 : end do
1527 : end do
1528 :
1529 90539 : end subroutine mkrdim
1530 : !!***
1531 :
1532 : !!****f* m_geometry/xcart2xred
1533 : !! NAME
1534 : !! xcart2xred
1535 : !!
1536 : !! FUNCTION
1537 : !! Convert from cartesian coordinates xcart(3,natom) in bohr to
1538 : !! dimensionless reduced coordinates xred(3,natom) by using
1539 : !! xred(mu,ia)=gprimd(1,mu)*xcart(1,ia)
1540 : !! +gprimd(2,mu)*xcart(2,ia)
1541 : !! +gprimd(3,mu)*xcart(3,ia)
1542 : !! where gprimd is the inverse of rprimd
1543 : !! Note that the reverse operation is done by xred2xcart
1544 : !!
1545 : !! INPUTS
1546 : !! natom=number of atoms in unit cell
1547 : !! rprimd(3,3)=dimensional real space primitive translations (bohr)
1548 : !! xcart(3,natom)=cartesian coordinates of atoms (bohr)
1549 : !!
1550 : !! OUTPUT
1551 : !! xred(3,natom)=dimensionless reduced coordinates of atoms
1552 : !!
1553 : !! SOURCE
1554 :
1555 24383 : subroutine xcart2xred(natom,rprimd,xcart,xred)
1556 :
1557 : !Arguments ------------------------------------
1558 : !scalars
1559 : integer,intent(in) :: natom
1560 : !arrays
1561 : real(dp),intent(in) :: rprimd(3,3),xcart(3,natom)
1562 : real(dp),intent(out) :: xred(3,natom)
1563 :
1564 : !Local variables-------------------------------
1565 : !scalars
1566 : integer :: iatom,mu
1567 : !arrays
1568 : real(dp) :: gprimd(3,3)
1569 : ! *************************************************************************
1570 :
1571 24383 : call matr3inv(rprimd,gprimd)
1572 9288385 : do iatom=1,natom
1573 37080391 : do mu=1,3
1574 37056008 : xred(mu,iatom)= gprimd(1,mu)*xcart(1,iatom)+gprimd(2,mu)*xcart(2,iatom)+gprimd(3,mu)*xcart(3,iatom)
1575 : end do
1576 : end do
1577 :
1578 24383 : end subroutine xcart2xred
1579 : !!***
1580 :
1581 : !!****f* m_geometry/xred2xcart
1582 : !! NAME
1583 : !! xred2xcart
1584 : !!
1585 : !! FUNCTION
1586 : !! Convert from dimensionless reduced coordinates xred(3,natom)
1587 : !! to cartesian coordinates xcart(3,natom) in bohr by using
1588 : !! xcart(mu,ia)=rprimd(mu,1)*xred(1,ia)
1589 : !! +rprimd(mu,2)*xred(2,ia)
1590 : !! +rprimd(mu,3)*xred(3,ia)
1591 : !! Note that the reverse operation is done by xcart2xred.F90
1592 : !!
1593 : !! INPUTS
1594 : !! natom=number of atoms in unit cell
1595 : !! rprimd(3,3)=dimensional real space primitive translations (bohr)
1596 : !! xred(3,natom)=dimensionless reduced coordinates of atoms
1597 : !!
1598 : !! OUTPUT
1599 : !! xcart(3,natom)=cartesian coordinates of atoms (bohr)
1600 : !!
1601 : !! SOURCE
1602 :
1603 132608 : subroutine xred2xcart(natom, rprimd, xcart, xred)
1604 :
1605 : !Arguments ------------------------------------
1606 : !scalars
1607 : integer,intent(in) :: natom
1608 : !arrays
1609 : real(dp),intent(in) :: rprimd(3,3),xred(3,natom)
1610 : real(dp),intent(out) :: xcart(3,natom)
1611 :
1612 : !Local variables-------------------------------
1613 : integer :: iatom,mu
1614 : ! *************************************************************************
1615 :
1616 28103778 : do iatom=1,natom
1617 112017288 : do mu=1,3
1618 111884680 : xcart(mu,iatom)=rprimd(mu,1)*xred(1,iatom)+rprimd(mu,2)*xred(2,iatom)+rprimd(mu,3)*xred(3,iatom)
1619 : end do
1620 : end do
1621 :
1622 132608 : end subroutine xred2xcart
1623 : !!***
1624 :
1625 : !!****f* m_geometry/gred2fcart
1626 : !! NAME
1627 : !! gred2fcart
1628 : !!
1629 : !! FUNCTION
1630 : !! Convert reduced forces into cartesian forces
1631 : !!
1632 : !! INPUTS
1633 : !! gred(3,natom)=symmetrized grtn = d(etotal)/d(xred)
1634 : !! natom=Number of atoms in the unitary cell
1635 : !! Favgz_null=TRUE if the average cartesian force has to be set to zero
1636 : !! FALSE if it is set to zero only in x,y directions (not z)
1637 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space(bohr^-1)
1638 : !!
1639 : !! OUTPUT
1640 : !! fcart(3,natom)=forces in cartesian coordinates (Ha/Bohr)
1641 : !!
1642 : !! NOTES
1643 : !! Unlike gred, fcart has been corrected by enforcing
1644 : !! the translational symmetry, namely that the sum of force
1645 : !! on all atoms is zero (except is a slab is used)
1646 : !!
1647 : !! SOURCE
1648 :
1649 23761 : subroutine gred2fcart(favg,Favgz_null,fcart,gred,gprimd,natom)
1650 :
1651 : !Arguments ------------------------------------
1652 : !scalars
1653 : integer,intent(in) :: natom
1654 : logical :: Favgz_null
1655 : !arrays
1656 : real(dp),intent(out) :: fcart(3,natom)
1657 : real(dp),intent(in) :: gred(3,natom)
1658 : real(dp),intent(in) :: gprimd(3,3)
1659 : real(dp),intent(out) :: favg(3)
1660 :
1661 : !Local variables-------------------------------
1662 : integer :: iatom,mu
1663 : ! *************************************************************************
1664 :
1665 : !Note conversion to cartesian coordinates (bohr) AND
1666 : !negation to make a force out of a gradient
1667 23761 : favg(:)=zero
1668 89386 : do iatom=1,natom
1669 286261 : do mu=1,3
1670 : fcart(mu,iatom)= - (gprimd(mu,1)*gred(1,iatom)+&
1671 : & gprimd(mu,2)*gred(2,iatom)+&
1672 196875 : & gprimd(mu,3)*gred(3,iatom))
1673 262500 : favg(mu)=favg(mu)+fcart(mu,iatom)
1674 : end do
1675 : end do
1676 :
1677 : !Subtract off average force from each force component
1678 : !to avoid spurious drifting of atoms across cell.
1679 95044 : favg(:)=favg(:)/dble(natom)
1680 23761 : if(.not.Favgz_null) favg(3)=zero
1681 89386 : do iatom=1,natom
1682 286261 : fcart(:,iatom)=fcart(:,iatom)-favg(:)
1683 : end do
1684 :
1685 23761 : end subroutine gred2fcart
1686 : !!***
1687 :
1688 : !!****f* m_geometry/fcart2gred
1689 : !!
1690 : !! NAME
1691 : !! fcart2gred
1692 : !!
1693 : !! FUNCTION
1694 : !! Convert cartesian forces into reduced forces
1695 : !!
1696 : !! INPUTS
1697 : !! fcart(3,natom)=forces in cartesian coordinates (Ha/Bohr)
1698 : !! natom=Number of atoms in the unitary cell
1699 : !! rprimd(3,3)=dimensional primitive
1700 : !!
1701 : !! OUTPUT
1702 : !! gred(3,natom)=symmetrized grtn = d(etotal)/d(xred)
1703 : !!
1704 : !! NOTES
1705 : !! Unlike gred, fcart has been corrected by enforcing
1706 : !! the translational symmetry, namely that the sum of force
1707 : !! on all atoms is zero.
1708 : !!
1709 : !! SOURCE
1710 :
1711 33159 : subroutine fcart2gred(fcart,gred,rprimd,natom)
1712 :
1713 : !Arguments ------------------------------------
1714 : !scalars
1715 : integer,intent(in) :: natom
1716 : !arrays
1717 : real(dp),intent(in) :: fcart(3,natom)
1718 : real(dp),intent(out) :: gred(3,natom)
1719 : real(dp),intent(in) :: rprimd(3,3)
1720 :
1721 : !Local variables-------------------------------
1722 : integer :: iatom,mu
1723 : ! *************************************************************************
1724 :
1725 : !MT, april 2012: the coding was not consistent with gred2fcart
1726 18244530 : do iatom=1,natom
1727 72878643 : do mu=1,3
1728 : gred(mu,iatom)= - (rprimd(1,mu)*fcart(1,iatom)+&
1729 : & rprimd(2,mu)*fcart(2,iatom)+&
1730 72845484 : & rprimd(3,mu)*fcart(3,iatom))
1731 : end do
1732 : end do
1733 :
1734 : !Previous version
1735 : !do iatom=1,natom
1736 : !do mu=1,3
1737 : !gred(mu,iatom)= - (rprimd(mu,1)*fcart(1,iatom)+&
1738 : !& rprimd(mu,2)*fcart(2,iatom)+&
1739 : !& rprimd(mu,3)*fcart(3,iatom))
1740 : !end do
1741 : !end do
1742 :
1743 33159 : end subroutine fcart2gred
1744 : !!***
1745 :
1746 : !!****f* m_geometry/bonds_lgth_angles
1747 : !! NAME
1748 : !! bonds_lgth_angles
1749 : !!
1750 : !! FUNCTION
1751 : !! From list of coordinates and primitive translations, output
1752 : !! a list of bonds lengths and bond angles.
1753 : !!
1754 : !! INPUTS
1755 : !! coordn = maximum coordination number to be taken into account
1756 : !! fnameabo_app_geo=name of file for _GEO data
1757 : !! natom = number of atoms in unit cell
1758 : !! ntypat = number of types of atoms in unit cell.
1759 : !! rprimd(3,3) = real space dimensional primitive translations (bohr)
1760 : !! typat(natom) = type integer for each atom in cell
1761 : !! znucl(ntypat)= real(dp), atomic number of atom type
1762 : !! xred(3,natom)= reduced coordinates of atoms
1763 : !!
1764 : !! OUTPUT
1765 : !! data written in file fnameabo_app_geo
1766 : !!
1767 : !! NOTES
1768 : !! The tolerance tol8 aims at giving a machine-independent ordering.
1769 : !! (this trick is used in bonds.f, listkk.f, prtrhomxmn.f and rsiaf9.f)
1770 : !!
1771 : !! SOURCE
1772 :
1773 45 : subroutine bonds_lgth_angles(coordn,fnameabo_app_geo,natom,ntypat,rprimd,typat,xred,znucl)
1774 :
1775 : !Arguments ------------------------------------
1776 : !scalars
1777 : integer,intent(in) :: coordn,natom,ntypat
1778 : character(len=*),intent(in) :: fnameabo_app_geo
1779 : !arrays
1780 : integer,intent(in) :: typat(natom)
1781 : real(dp),intent(in) :: rprimd(3,3),znucl(ntypat)
1782 : real(dp),intent(inout) :: xred(3,natom)
1783 :
1784 : !Local variables-------------------------------
1785 : !scalars
1786 : integer :: done,ia,ib,ic,ii,ineighb,jneighb,mneighb,mu,ndig,nu,t1,t2,t3,tmax,temp_unit
1787 : real(dp) :: adotb,asq,bsq,co,length,sq,thdeg
1788 : !real(dp)u1,u2,u3,v1,v2,v3
1789 : character(len=500) :: msg
1790 : type(atomdata_t) :: atom
1791 : !arrays
1792 45 : integer,allocatable :: list_neighb(:,:,:)
1793 : real(dp) :: bab(3),bac(3),dif(3),rmet(3,3)
1794 45 : real(dp),allocatable :: sqrlength(:),xcart(:,:)
1795 45 : character(len=8),allocatable :: iden(:)
1796 : ! *************************************************************************
1797 :
1798 : !Initialize the file
1799 45 : write(msg, '(3a)' )' bonds_lgth_angles : about to open file ',trim(fnameabo_app_geo),ch10
1800 45 : call wrtout(std_out,msg); call wrtout(ab_out,msg)
1801 :
1802 45 : if (open_file(fnameabo_app_geo,msg,newunit=temp_unit,status='unknown',form='formatted') /= 0) then
1803 0 : ABI_ERROR(msg)
1804 : end if
1805 45 : rewind(temp_unit)
1806 :
1807 45 : write(msg, '(a,a)' ) ch10,' ABINIT package : GEO file '
1808 45 : call wrtout(temp_unit,msg)
1809 :
1810 : !Compute maximum number of neighbors is the neighbor list,
1811 : !from the indicative coordination number
1812 : !Note : the following formula includes next nearest neighbors, but not others
1813 45 : mneighb=1+coordn+coordn*(coordn-1)
1814 :
1815 45 : write(msg, '(a,a,i2,a,a,i4,a,a,a,i4,a)' ) ch10,&
1816 45 : & ' Maximal coordination number, as estimated by the user : ',coordn,ch10,&
1817 45 : & ' giving a maximum of ',coordn*coordn,&
1818 45 : & ' nearest neighbors and next nearest neighbors, ',ch10,&
1819 45 : & ' and ',(coordn*(coordn-1))/2,&
1820 90 : & ' distinct angles between nearest neighbors'
1821 45 : call wrtout(temp_unit,msg)
1822 :
1823 : !Compute metric tensor in real space rmet
1824 180 : do nu=1,3
1825 585 : do mu=1,3
1826 : rmet(mu,nu)=rprimd(1,mu)*rprimd(1,nu)+&
1827 : & rprimd(2,mu)*rprimd(2,nu)+&
1828 540 : & rprimd(3,mu)*rprimd(3,nu)
1829 : end do
1830 : end do
1831 :
1832 45 : write(msg, '(a,a)' )ch10,' Primitive vectors of the periodic cell (bohr)'
1833 45 : call wrtout(temp_unit,msg)
1834 180 : do nu=1,3
1835 135 : write(msg, '(1x,a,i1,a,3f10.5)' ) ' R(',nu,')=',rprimd(:,nu)
1836 180 : call wrtout(temp_unit,msg)
1837 : end do
1838 :
1839 45 : write(msg, '(a,a)' ) ch10,&
1840 90 : & ' Atom list Reduced coordinates Cartesian coordinates (bohr)'
1841 45 : call wrtout(temp_unit,msg)
1842 :
1843 : !Set up a list of character identifiers for all atoms : iden(ia)
1844 135 : ABI_MALLOC(iden,(natom))
1845 271 : iden(:)=' '
1846 271 : do ia=1,natom
1847 226 : ndig=int(log10(dble(ia)+0.5d0))+1
1848 226 : call atomdata_from_znucl(atom,znucl(typat(ia)))
1849 226 : if(ndig==1) write(iden(ia), '(a,a,i1,a)' ) atom%symbol,'(',ia,') '
1850 226 : if(ndig==2) write(iden(ia), '(a,a,i2,a)' ) atom%symbol,'(',ia,') '
1851 226 : if(ndig==3) write(iden(ia), '(a,a,i3,a)' ) atom%symbol,'(',ia,') '
1852 226 : if(ndig==4) write(iden(ia), '(a,a,i4,a)' ) atom%symbol,'(',ia,')'
1853 497 : if(ndig>4)then
1854 0 : close(temp_unit)
1855 : write(msg, '(a,i8,a,a)' )&
1856 0 : 'bonds_lgth_angles cannot handle more than 9999 atoms, while natom=',natom,ch10,&
1857 0 : 'Action: decrease natom, or contact ABINIT group.'
1858 0 : ABI_BUG(msg)
1859 : end if
1860 : end do
1861 :
1862 : !Compute cartesian coordinates, and print reduced and cartesian coordinates
1863 : !then print coordinates in angstrom, with the format needed for xmol
1864 135 : ABI_MALLOC(xcart,(3,natom))
1865 45 : call xred2xcart(natom,rprimd,xcart,xred)
1866 :
1867 271 : do ia=1,natom
1868 : write(msg, '(a,a,3f10.5,a,3f10.5)' ) &
1869 1130 : ' ',iden(ia),(xred(ii,ia)+tol10,ii=1,3),&
1870 2034 : ' ',(xcart(ii,ia)+tol10,ii=1,3)
1871 271 : call wrtout(temp_unit,msg)
1872 : end do
1873 :
1874 45 : write(msg, '(a,a,a,a,i4,a)' )ch10,&
1875 90 : ' XMOL data : natom, followed by cartesian coordinates in Angstrom',ch10,ch10,natom,ch10
1876 45 : call wrtout(temp_unit,msg)
1877 :
1878 271 : do ia=1,natom
1879 226 : call atomdata_from_znucl(atom,znucl(typat(ia)))
1880 904 : write(msg, '(a,a,3f10.5)' )' ',atom%symbol,xcart(1:3,ia)*Bohr_Ang
1881 497 : call wrtout(temp_unit,msg)
1882 : end do
1883 :
1884 45 : ABI_FREE(xcart)
1885 :
1886 225 : ABI_MALLOC(list_neighb,(0:mneighb+1,4,2))
1887 135 : ABI_MALLOC(sqrlength,(0:mneighb+1))
1888 :
1889 : !Compute list of neighbors
1890 271 : do ia=1,natom
1891 :
1892 226 : write(msg, '(a,a,a,a,a,a,a,a,a)' ) ch10,'===========',&
1893 226 : & '=====================================================================',&
1894 452 : & ch10,' ',iden(ia),ch10,ch10,' Bond lengths '
1895 226 : call wrtout(temp_unit,msg)
1896 :
1897 : ! Search other atoms for bonds, but must proceed
1898 : ! in such a way to consider a search box sufficiently large,
1899 : ! so increase the size of the search box until the
1900 : ! final bond length list do not change
1901 648 : do tmax=0,5
1902 :
1903 : ! Set initial list of neighbors to zero,
1904 : ! and initial square of bond lengths to a very large number.
1905 : ! Note that the dimension is larger than neighb to ease
1906 : ! the later sorting : neighbors 0 and neighb+1 are non-existent, while
1907 : ! neighbor 1 will be the atom itself ...
1908 43848 : list_neighb(0:mneighb+1,1:4,1)=0
1909 10152 : sqrlength(1:mneighb+1)=huge(zero)
1910 648 : sqrlength(0)=-1.0d0
1911 :
1912 : ! Here search on all atoms inside the box defined by tmax
1913 10728 : do ib=1,natom
1914 40848 : do t3=-tmax,tmax
1915 157000 : do t2=-tmax,tmax
1916 656560 : do t1=-tmax,tmax
1917 509640 : dif(1)=xred(1,ia)-(xred(1,ib)+dble(t1))
1918 509640 : dif(2)=xred(2,ia)-(xred(2,ib)+dble(t2))
1919 509640 : dif(3)=xred(3,ia)-(xred(3,ib)+dble(t3))
1920 509640 : sq=rsdot(dif(1),dif(2),dif(3),dif(1),dif(2),dif(3),rmet)
1921 :
1922 : ! Insert the atom at the proper place in the neighbor list.
1923 958450 : do ineighb=mneighb,0,-1
1924 : ! Note the tolerance
1925 841650 : if(sq+tol8>sqrlength(ineighb))then
1926 509640 : sqrlength(ineighb+1)=sq
1927 509640 : list_neighb(ineighb+1,1,1)=ib
1928 509640 : list_neighb(ineighb+1,2,1)=t1
1929 509640 : list_neighb(ineighb+1,3,1)=t2
1930 509640 : list_neighb(ineighb+1,4,1)=t3
1931 : ! DEBUG
1932 : ! if(ineighb/=mneighb)then
1933 : ! write(std_out,*)' '
1934 : ! do ii=1,mneighb
1935 : ! write(std_out,*)ii,sqrlength(ii)
1936 : ! end do
1937 : ! end if
1938 : ! ENDDEBUG
1939 509640 : exit
1940 : else
1941 332010 : sqrlength(ineighb+1)=sqrlength(ineighb)
1942 1660050 : list_neighb(ineighb+1,1:4,1)=list_neighb(ineighb,1:4,1)
1943 : end if
1944 : end do
1945 :
1946 : end do
1947 : end do
1948 : end do
1949 : ! end ib loop:
1950 : end do
1951 :
1952 : ! Now, check that the box defined by tmax was large enough :
1953 : ! require the present and old lists to be the same
1954 648 : done=0
1955 :
1956 648 : if(tmax>0)then
1957 : done=1
1958 6306 : do ineighb=1,mneighb
1959 : ! DEBUG
1960 : ! write(std_out,'(5i5,f12.5)' )ineighb,list_neighb(ineighb,1:4,1),&
1961 : ! & sqrlength(ineighb)
1962 : ! write(std_out,'(5i5)' )ineighb,list_neighb(ineighb,1:4,2)
1963 : ! ENDDEBUG
1964 : if( list_neighb(ineighb,1,1)/=list_neighb(ineighb,1,2) .or. &
1965 : & list_neighb(ineighb,2,1)/=list_neighb(ineighb,2,2) .or. &
1966 5884 : & list_neighb(ineighb,3,1)/=list_neighb(ineighb,3,2) .or. &
1967 422 : & list_neighb(ineighb,4,1)/=list_neighb(ineighb,4,2) )then
1968 2531 : done=0
1969 : end if
1970 : end do
1971 : end if
1972 :
1973 : ! If done==1, then one can exit the loop : the correct list of
1974 : ! neighbors is contained in list_neighb(1:neighb,1:4,1),
1975 : ! with the first neighbor being the atom itself
1976 422 : if(done==1)exit
1977 :
1978 : ! If the work is not done, while tmax==5, then there is a problem .
1979 422 : if(tmax==5)then
1980 0 : close(temp_unit)
1981 : write(msg, '(2a)' )&
1982 0 : & 'Did not succeed to generate a reliable list of bonds ',&
1983 0 : & 'since tmax is exceeded.'
1984 0 : ABI_BUG(msg)
1985 : end if
1986 :
1987 : ! Copy the new list into the old list.
1988 25872 : list_neighb(1:mneighb,1:4,2)=list_neighb(1:mneighb,1:4,1)
1989 :
1990 : ! Loop on tmax (note that there are exit instruction inside the loop)
1991 : end do
1992 :
1993 :
1994 :
1995 : ! Output the bond list
1996 2972 : do ineighb=2,mneighb
1997 2746 : ib=list_neighb(ineighb,1,1)
1998 2746 : length=sqrt(sqrlength(ineighb))
1999 : write(msg, '(a,a,a,a,3i2,t27,a,f10.5,a,f9.5,a)' )&
2000 2746 : & ' ',trim(iden(ia)),' - ',trim(iden(ib)),&
2001 2746 : & list_neighb(ineighb,2:4,1),'bond length is ',&
2002 5492 : & length,' bohr ( or ',Bohr_Ang*length,' Angst.)'
2003 2972 : call wrtout(temp_unit,msg)
2004 : end do
2005 :
2006 : ! Output the angle list
2007 271 : if(coordn>1)then
2008 :
2009 168 : write(msg, '(a,a)' ) ch10,' Bond angles '
2010 168 : call wrtout(temp_unit,msg)
2011 :
2012 672 : do ineighb=2,coordn
2013 1680 : do jneighb=ineighb+1,coordn+1
2014 :
2015 1008 : ib=list_neighb(ineighb,1,1)
2016 1008 : ic=list_neighb(jneighb,1,1)
2017 4032 : do mu=1,3
2018 3024 : bab(mu)=xred(mu,ib)+dble(list_neighb(ineighb,1+mu,1))-xred(mu,ia)
2019 4032 : bac(mu)=xred(mu,ic)+dble(list_neighb(jneighb,1+mu,1))-xred(mu,ia)
2020 : end do
2021 1008 : asq=rsdot(bab(1),bab(2),bab(3),bab(1),bab(2),bab(3),rmet)
2022 1008 : bsq=rsdot(bac(1),bac(2),bac(3),bac(1),bac(2),bac(3),rmet)
2023 1008 : adotb=rsdot(bab(1),bab(2),bab(3),bac(1),bac(2),bac(3),rmet)
2024 1008 : co=adotb/sqrt(asq*bsq)
2025 1008 : if( abs(co)-1.0d0 >= 0.0d0 )then
2026 0 : if( abs(co)-1.0d0 <= 1.0d-12 )then
2027 : ! Allows for a small numerical inaccuracy
2028 0 : thdeg=0.0d0
2029 0 : if(co < 0.0d0) thdeg=180.0d0
2030 : else
2031 0 : ABI_BUG('the evaluation of the angle is wrong.')
2032 : end if
2033 : else
2034 1008 : thdeg=acos(co)*180.d0*piinv
2035 : end if
2036 :
2037 : write(msg, '(a,a,3i2,a,a,a,a,3i2,t44,a,f13.5,a)' )&
2038 1008 : & ' ',trim(iden(ib)),list_neighb(ineighb,2:4,1),' - ',&
2039 1008 : & trim(iden(ia)),' - ',trim(iden(ic)),&
2040 2016 : & list_neighb(jneighb,2:4,1),'bond angle is ',thdeg,' degrees '
2041 1512 : call wrtout(temp_unit,msg)
2042 : end do
2043 : end do
2044 :
2045 : end if
2046 : end do ! End big ia loop:
2047 :
2048 45 : ABI_FREE(iden)
2049 45 : ABI_FREE(list_neighb)
2050 45 : ABI_FREE(sqrlength)
2051 :
2052 45 : close(temp_unit)
2053 :
2054 : contains
2055 :
2056 512664 : function rsdot(u1,u2,u3,v1,v2,v3,rmet)
2057 :
2058 : real(dp) :: rsdot
2059 : real(dp),intent(in) :: u1,u2,u3,v1,v2,v3
2060 : real(dp),intent(in) :: rmet(3,3)
2061 : rsdot=rmet(1,1)*u1*v1+rmet(2,1)*u2*v1+&
2062 : & rmet(3,1)*u3*v1+rmet(1,2)*u1*v2+rmet(2,2)*u2*v2+&
2063 512664 : & rmet(3,2)*u3*v2+rmet(1,3)*u1*v3+rmet(2,3)*u2*v3+rmet(3,3)*u3*v3
2064 512664 : end function rsdot
2065 :
2066 : end subroutine bonds_lgth_angles
2067 : !!***
2068 :
2069 : !!****f* m_geometry/randomcellpos
2070 : !! NAME
2071 : !! randomcellpos
2072 : !!
2073 : !! FUNCTION
2074 : !! This subroutine creates a unit cell with random atomic positions. It is
2075 : !! assumed that the cell parameters are given and fixed. Several methods are
2076 : !! used to generate the cell.
2077 : !!
2078 : !! INPUTS
2079 : !! natom=number of atoms
2080 : !! npsp=number of pseudopotentials (needed for the dimension of znucl)
2081 : !! ntypat=number of type of atoms
2082 : !! random_atpos=input variable
2083 : !! 0 no generation of random atomic potision
2084 : !! 1 completely random atomic potisions
2085 : !! 2 random atomic positions, avoiding too close atoms
2086 : !! (prevent coming closer than a fraction of the sum of covalent radii)
2087 : !! 3 same than 2 but also generates the rprim and acell randomly
2088 : !! within some given ranges (angles between 50 and 130)
2089 : !! ratsph(1:ntypat)=radius of the atomic sphere
2090 : !! rprimd(3,3)=dimensional primitive translations in real space (bohr)
2091 : !! typat(1:natom)= input variable giving the type of each atom
2092 : !! znucl(1:npsp)=nuclear number of atom as specified in psp file
2093 : !!
2094 : !! OUTPUT
2095 : !! xred(3,natom)=reduced dimensionless atomic coordinates
2096 : !!
2097 : !! SIDE EFFECTS
2098 : !!
2099 : !! NOTES
2100 : !!
2101 : !! SOURCE
2102 :
2103 7233 : subroutine randomcellpos(natom,npsp,ntypat,random_atpos,ratsph,rprim,rprimd,typat,xred,znucl,acell)
2104 :
2105 : !Arguments ------------------------------------
2106 : !scalars
2107 : integer,intent(in) :: natom,npsp,ntypat,random_atpos
2108 : !arrays
2109 : integer, intent(in) :: typat(natom)
2110 : real(dp),intent(in) :: ratsph(ntypat)
2111 : real(dp), intent(inout) :: rprim(3,3)
2112 : real(dp), intent(inout) :: rprimd(3,3)
2113 : real(dp), intent(inout) :: xred(3,natom)
2114 : real(dp), intent(in) :: znucl(npsp)
2115 : real(dp), intent(inout) :: acell(3)
2116 :
2117 : !Local variables-------------------------------
2118 : integer :: iatom=0,ii,idum=-20
2119 : real(dp) :: rij(3), rijd(3), radiuscovi, radiuscovj, dist, rati, ratj, angdeg(3)
2120 : real(dp) :: cosang,aa,cc,a2
2121 : character(len=500) :: msg
2122 : type(atomdata_t) :: atom
2123 : ! *************************************************************************
2124 :
2125 : !DEBUG
2126 : !For the time being, print rprimd to keep it as an argument, in spite of abirule checking.
2127 : !write (std_out,*) ' randomcellpos : enter'
2128 : !write(std_out,*)' rprimd=',rprimd
2129 : !write(std_out,*)' znucl=',znucl
2130 : !write(std_out,*)' typat=',typat
2131 : !write(std_out,*)' random_atpos=',random_atpos
2132 : !ENDDEBUG
2133 :
2134 7233 : if(random_atpos==2 .and. npsp/=ntypat)then
2135 : write(msg, '(a,i5,2a,i5,a,i5,4a)' )&
2136 0 : & 'Input variable random_atpos= ',random_atpos,ch10,&
2137 0 : & 'However, the number of pseudopotentials ',npsp,', is not equal to the number of type of atoms ',ntypat,ch10,&
2138 0 : & 'The use of alchemical mixing cannot be combined with the constraint based on the mixing of covalent radii.',ch10,&
2139 0 : & 'Action: switch to another value of random_atpos.'
2140 0 : ABI_ERROR(msg)
2141 : end if
2142 :
2143 : !random_atpos = 0 Default value, no random initialisation
2144 : !random_atpos = 1 Fully random (Is it really useful ???)
2145 : !random_atpos = 2 Random, but the sum of the two covalent radii is
2146 : !less than the interatomic distance
2147 : !random_atpos = 3 Random, but the sum of the two (other type of)
2148 : !radii is less than the interatomic distance
2149 : !random_atpos = 4 Random, but the sum of the two pseudopotential
2150 : !radii is less than the interatomic distance
2151 : !random_atpos = 5 Random, but the interatomic distance must be bigger
2152 : !than the sum of
2153 : !some input variable (well, instead of defining a new variable, why
2154 : !not use ratsph ?)
2155 : !Right now we are not using a factor for the tested distance.. something to be done, after a new variable has been defined
2156 :
2157 7233 : if (random_atpos /= 0) then
2158 : select case (random_atpos)
2159 : case (1)
2160 0 : do ii=1,natom
2161 0 : xred(1,ii)=uniformrandom(idum)
2162 0 : xred(2,ii)=uniformrandom(idum)
2163 0 : xred(3,ii)=uniformrandom(idum)
2164 : end do
2165 : case (2)
2166 10 : iatom=0
2167 82 : do
2168 82 : iatom=iatom+1
2169 82 : xred(1,iatom)=uniformrandom(idum)
2170 82 : xred(2,iatom)=uniformrandom(idum)
2171 82 : xred(3,iatom)=uniformrandom(idum)
2172 82 : call atomdata_from_znucl(atom,znucl(typat(iatom)))
2173 82 : radiuscovi = atom%rcov
2174 366 : do ii=1,iatom-1
2175 1144 : rij=xred(:,iatom)-xred(:,ii)
2176 : ! periodic boundary conditions
2177 1144 : rij = rij - 0.5
2178 1144 : rij = rij - anint (rij)
2179 : ! coming back to cube between (0,1)
2180 1144 : rij = rij + 0.5
2181 : ! convert reduced coordinates to cartesian coordinates
2182 286 : call xred2xcart(1,rprimd,rijd,rij)
2183 1144 : dist=dot_product(rijd,rijd)
2184 286 : call atomdata_from_znucl(atom,znucl(typat(ii)))
2185 286 : radiuscovj = atom%rcov
2186 366 : if (dist<(radiuscovj+radiuscovi)) then
2187 2 : iatom = iatom -1
2188 2 : EXIT
2189 : end if
2190 : end do
2191 82 : if (iatom>=natom) EXIT
2192 : end do
2193 : case(3)
2194 0 : iatom=0
2195 0 : do
2196 0 : iatom=iatom+1
2197 0 : xred(1,iatom)=uniformrandom(idum)
2198 0 : xred(2,iatom)=uniformrandom(idum)
2199 0 : xred(3,iatom)=uniformrandom(idum)
2200 0 : call atomdata_from_znucl(atom,znucl(typat(iatom)))
2201 0 : radiuscovi = atom%rcov
2202 0 : do ii=1,iatom-1
2203 0 : rij=xred(:,iatom)-xred(:,ii)
2204 : ! periodic boundary conditions
2205 0 : rij = rij - 0.5
2206 0 : rij = rij - anint (rij)
2207 : ! coming back to cube between (0,1)
2208 0 : rij = rij + 0.5
2209 : ! convert reduced coordinates to cartesian coordinates
2210 0 : call xred2xcart(1,rprimd,rijd,rij)
2211 0 : dist=dot_product(rijd,rijd)
2212 0 : call atomdata_from_znucl(atom,znucl(typat(ii)))
2213 0 : radiuscovj = atom%rcov
2214 0 : if (dist<(radiuscovj+radiuscovi)) then
2215 0 : iatom = iatom -1
2216 0 : EXIT
2217 : end if
2218 : end do
2219 0 : if (iatom>=natom) EXIT
2220 : end do
2221 0 : do ii=1,3
2222 : ! generates cells with angles between 60 and 120 degrees
2223 0 : angdeg(ii)=60_dp+uniformrandom(idum)*60.0_dp
2224 : end do
2225 0 : if (angdeg(1)+angdeg(2)+angdeg(3)>360._dp) then
2226 0 : angdeg(3)=360._dp-angdeg(1)-angdeg(2)
2227 : end if
2228 : ! check if angles are between the limits and create rprim
2229 : if( abs(angdeg(1)-angdeg(2))<tol12 .and. &
2230 0 : & abs(angdeg(2)-angdeg(3))<tol12 .and. &
2231 : & abs(angdeg(1)-90._dp)+abs(angdeg(2)-90._dp)+abs(angdeg(3)-90._dp)>tol12 )then
2232 : ! Treat the case of equal angles (except all right angles) :
2233 : ! generates trigonal symmetry wrt third axis
2234 0 : cosang=cos(pi*angdeg(1)/180.0_dp)
2235 0 : a2=2.0_dp/3.0_dp*(1.0_dp-cosang)
2236 0 : aa=sqrt(a2)
2237 0 : cc=sqrt(1.0_dp-a2)
2238 0 : rprim(1,1)=aa ; rprim(2,1)=0.0_dp ; rprim(3,1)=cc
2239 0 : rprim(1,2)=-0.5_dp*aa ; rprim(2,2)= sqrt(3.0_dp)*0.5_dp*aa ; rprim(3,2)=cc
2240 0 : rprim(1,3)=-0.5_dp*aa ; rprim(2,3)=-sqrt(3.0_dp)*0.5_dp*aa ; rprim(3,3)=cc
2241 : ! DEBUG
2242 : ! write(std_out,*)' ingeo : angdeg=',angdeg(1:3)
2243 : ! write(std_out,*)' ingeo : aa,cc=',aa,cc
2244 : ! ENDDEBUG
2245 : else
2246 : ! Treat all the other cases
2247 0 : rprim(:,:)=0.0_dp
2248 0 : rprim(1,1)=1.0_dp
2249 0 : rprim(1,2)=cos(pi*angdeg(3)/180.0_dp)
2250 0 : rprim(2,2)=sin(pi*angdeg(3)/180.0_dp)
2251 0 : rprim(1,3)=cos(pi*angdeg(2)/180.0_dp)
2252 0 : rprim(2,3)=(cos(pi*angdeg(1)/180.0_dp)-rprim(1,2)*rprim(1,3))/rprim(2,2)
2253 0 : rprim(3,3)=sqrt(1.0_dp-rprim(1,3)**2-rprim(2,3)**2)
2254 : end if
2255 : ! generate acell
2256 0 : aa=zero
2257 0 : do ii=1,npsp
2258 0 : aa=znucl(ii)
2259 : end do
2260 0 : do ii=1,3
2261 0 : acell(ii)=aa+uniformrandom(idum)*4.0
2262 : end do
2263 0 : call mkrdim(acell,rprim,rprimd)
2264 : case(4)
2265 0 : write(std_out,*) 'Not implemented yet'
2266 : case(5)
2267 0 : iatom=0
2268 10 : do
2269 0 : iatom=iatom+1
2270 0 : xred(1,iatom)=uniformrandom(idum)
2271 0 : xred(2,iatom)=uniformrandom(idum)
2272 0 : xred(3,iatom)=uniformrandom(idum)
2273 0 : rati=ratsph(typat(iatom))
2274 0 : do ii=1,iatom-1
2275 0 : ratj=ratsph(typat(ii))
2276 : ! apply periodic boundary conditions
2277 0 : rij=(xred(:,iatom)-xred(:,ii))-0.5
2278 0 : rij = rij - ANINT ( rij )
2279 0 : rij = rij + 0.5
2280 0 : call xred2xcart(natom,rprimd,rijd,rij)
2281 0 : dist=dot_product(rijd,rijd)
2282 0 : if (dist<(rati+ratj)) EXIT
2283 : end do
2284 0 : if (iatom==natom) EXIT
2285 0 : if (ii<(iatom-1)) iatom=iatom-1
2286 : end do
2287 : end select
2288 : end if
2289 :
2290 7233 : end subroutine randomcellpos
2291 : !!***
2292 :
2293 : !!****f* m_geometry/shellstruct
2294 : !! NAME
2295 : !! shellstruct
2296 : !!
2297 : !! FUNCTION
2298 : !! Calculates shell structure (multiplicities, radii) of an atomic configuration
2299 : !!
2300 : !! INPUTS
2301 : !! natom=number of atoms in unit cell
2302 : !! xred=reduced coordinates of atoms
2303 : !! rprimd=unit cell vectors
2304 : !! magv = magnetic ordering of atoms given as 1 and -1, if not given fm is assumed
2305 : !! atp = atom on which the perturbation was done
2306 : !!
2307 : !! OUTPUT
2308 : !! sdisv(nat)= distance of each shell to central atom (only the first nsh entries are relevant)
2309 : !! nsh= number of shells
2310 : !! mult(nat) = number of atoms on shell (only the first nsh entries are relevant)
2311 : !!
2312 : !! SOURCE
2313 :
2314 55 : subroutine shellstruct(xred,rprimd,natom,magv,distv,smult,sdisv,nsh,atp,prtvol)
2315 :
2316 : !Arguments ------------------------------------
2317 : !scalars
2318 : integer,intent(in) :: natom
2319 : integer,intent(in),optional :: atp
2320 : integer,intent(in),optional :: prtvol
2321 : integer,intent(out) :: nsh
2322 : !arrays
2323 : real(dp),intent(in) :: rprimd(3,3)
2324 : real(dp),intent(in) :: xred(3,natom)
2325 : integer,intent(out) :: smult(natom)
2326 : integer,intent(in),optional :: magv(natom)
2327 : real(dp),intent(out) :: sdisv(natom)
2328 : real(dp),intent(out) :: distv(natom)
2329 :
2330 : !Local variables-------------------------------
2331 : !scalars
2332 : integer :: iatom,atpp,ish,prtvoll
2333 : character(len=500) :: msg
2334 : real(dp),parameter :: rndfact=10000_dp
2335 : !arrays
2336 110 : integer :: iperm(natom),jperm(natom)
2337 110 : real(dp) :: distvh(natom,natom)
2338 110 : real(dp) :: magvv(natom)
2339 : ! *************************************************************************
2340 :
2341 55 : if (present(magv)) then
2342 4510 : magvv=magv
2343 : else
2344 0 : magvv=(/ (1, iatom=1,natom) /)
2345 : end if
2346 :
2347 55 : if (present(atp)) then
2348 55 : atpp=atp
2349 : else
2350 0 : atpp=1
2351 : end if
2352 :
2353 55 : if (present(prtvol)) then
2354 55 : prtvoll=prtvol
2355 : else
2356 : prtvoll=1
2357 : end if
2358 :
2359 : !DEBUB
2360 55 : write(std_out,*)'shellstruct start'
2361 : !END DEBUG
2362 :
2363 : !Calculate ionic distances
2364 4510 : call ioniondist(natom,rprimd,xred,distvh,1,magv=int(magvv),atp=atpp)
2365 4510 : distv=distvh(1,:)
2366 :
2367 55 : if (prtvol>2) then
2368 0 : write(std_out,'(a)')' shellstruct ionic distances in cell (distv) : '
2369 0 : call prmat(distv(1:natom),1,natom,1,std_out)
2370 : end if
2371 :
2372 8965 : iperm=(/ (iatom, iatom=1,natom ) /)
2373 4510 : jperm=iperm
2374 4510 : distv=anint(distv*rndfact)/rndfact
2375 : !Sort distances
2376 55 : call sort_dp(natom,distv,iperm,10d-5)
2377 55 : call sort_int(natom,iperm,jperm)
2378 :
2379 4510 : smult=0
2380 5005 : sdisv=dot_product(rprimd(1,:),rprimd(1,:))+dot_product(rprimd(2,:),rprimd(2,:))+dot_product(rprimd(3,:),rprimd(3,:))
2381 :
2382 55 : nsh=1
2383 55 : smult(1)=1
2384 55 : sdisv(1)=distv(1)
2385 :
2386 4455 : do iatom=2,natom
2387 37025 : do ish=1,natom
2388 36970 : if (distv(iatom)>sdisv(ish)) then
2389 : cycle
2390 4400 : else if (distv(iatom)==sdisv(ish)) then
2391 3920 : smult(ish)=smult(ish)+1
2392 3920 : exit
2393 480 : else if (distv(iatom)<sdisv(ish)) then
2394 65760 : smult(ish+1:natom)=smult(ish:natom-1)
2395 65760 : sdisv(ish+1:natom)=sdisv(ish:natom-1)
2396 480 : smult(ish)=1
2397 480 : sdisv(ish)=distv(iatom)
2398 480 : nsh=nsh+1
2399 480 : exit
2400 : end if
2401 : end do
2402 : end do
2403 :
2404 8965 : distv=(/ ( distv(jperm(iatom)),iatom=1,natom ) /)
2405 :
2406 55 : if (prtvoll>2) then
2407 0 : write(msg,'(a,i4,a)')' shellstruct found ',nsh,' shells at distances (sdisv) '
2408 0 : call wrtout(std_out,msg)
2409 0 : call prmat(sdisv(1:nsh),1,nsh,1,std_out)
2410 0 : write(msg,fmt='(a,150i4)')' and multiplicities (smult) ', smult(1:nsh)
2411 0 : call wrtout(std_out,msg)
2412 : end if
2413 :
2414 : !DEBUB
2415 55 : write(std_out,*)'shellstruct leave'
2416 : !END DEBUG
2417 :
2418 55 : end subroutine shellstruct
2419 : !!***
2420 :
2421 : !!****f* m_geometry/ioniondist
2422 : !! NAME
2423 : !! ioniondist
2424 : !!
2425 : !! FUNCTION
2426 : !! Compute ion-ion distances
2427 : !!
2428 : !! INPUTS
2429 : !! natom= number of atoms in unit cell
2430 : !! rprimd(3,3)=dimensional real space primitive translations (bohr)
2431 : !! xred(3,natom)=dimensionless reduced coordinates of atoms
2432 : !! inm(natom,natom)=index (m,n) of the atom
2433 : !! option= 1 output ion-ion distances / 2 output ordering of ion-ion
2434 : !! distances / 3 output variables in varlist
2435 : !! according to ion-ion distances * magnetic ordering
2436 : !! magv magnetic ordering of atoms given also 1 and -1, if not
2437 : !! given fm is assumed
2438 : !! varlist=List of variables
2439 : !! magv(natom)= magnetic ordering of atoms
2440 : !! atp=atom on which the perturbation was done
2441 : !!
2442 : !! OUTPUT
2443 : !!
2444 : !! SOURCE
2445 :
2446 165 : subroutine ioniondist(natom,rprimd,xred,inm,option,varlist,magv,atp,prtvol)
2447 :
2448 : !Arguments ------------------------------------
2449 : !scalars
2450 : integer,intent(in) :: natom,option
2451 : integer,intent(in),optional :: atp !atom on which the perturbation was done
2452 : !arrays
2453 : real(dp),intent(in) :: rprimd(3,3)
2454 : real(dp),intent(in) :: xred(3,natom)
2455 : real(dp),intent(out) :: inm(natom,natom)
2456 : integer,intent(in),optional :: magv(natom)
2457 : real(dp),intent(in),optional :: varlist(natom)
2458 : integer,intent(in),optional :: prtvol
2459 :
2460 : !Local variables-------------------------------
2461 : !scalars
2462 : integer :: iatom,jatom,katom,kdum,atpp,prtvoll
2463 : !character(len=500) :: msg
2464 : !arrays
2465 330 : integer :: interq(natom)
2466 330 : real(dp) :: hxcart(3,natom),distm(natom,natom)
2467 165 : real(dp) :: magvv(natom)
2468 : ! *************************************************************************
2469 :
2470 227370 : hxcart=matmul(rprimd,xred)
2471 26895 : interq=(/(iatom,iatom=1,natom)/)
2472 2251995 : inm=0
2473 :
2474 165 : if (present(magv)) then
2475 13530 : magvv=magv
2476 : else
2477 0 : magvv=(/ (1, iatom=1,natom) /)
2478 : end if
2479 :
2480 165 : if (present(atp)) then
2481 165 : atpp=atp
2482 : else
2483 : atpp=1
2484 : end if
2485 :
2486 165 : if (present(prtvol)) then
2487 110 : prtvoll=prtvol
2488 : else
2489 : prtvoll=1
2490 : end if
2491 :
2492 165 : if (option==3.and.(.not.present(varlist))) then
2493 0 : call wrtout(std_out,'ioniondist error: option=3 but no variable list provided for symmetrization')
2494 : return
2495 : end if
2496 :
2497 : !call wrtout(std_out,' ioniondist start ')
2498 :
2499 2251995 : distm=0
2500 165 : katom=atpp-1
2501 13530 : do iatom=1,natom
2502 13365 : katom=katom+1
2503 13365 : if (katom > natom) katom=1
2504 13365 : distm(iatom,iatom)=0
2505 1139445 : do jatom=iatom,natom
2506 1125915 : distm(iatom,jatom)=dist2(xred(:,katom),xred(:,jatom),rprimd,1)*magvv(katom)*magvv(jatom)
2507 1139280 : distm(jatom,iatom)=distm(iatom,jatom)
2508 : end do
2509 : end do
2510 :
2511 165 : if (prtvoll>=3) then
2512 0 : call wrtout(std_out,'ioniondist: ionic distances:')
2513 0 : call prmat(distm,natom,natom,natom,std_out)
2514 : end if
2515 :
2516 2251995 : distm=anint(distm*10000_dp)/10000_dp ! rounding needed else distm(iatom,jatom)/= distm(1,kdum) sometimes fails
2517 :
2518 13530 : do iatom=1,natom
2519 13530 : if (option==1) then
2520 750610 : inm(iatom,:)=distm(iatom,:)
2521 : else
2522 759520 : do jatom=iatom,natom
2523 : kdum=1
2524 21266760 : do while ( (kdum <= natom) .and. (distm(iatom,jatom)/= distm(1,kdum)) )
2525 21266760 : kdum=kdum+1
2526 : end do
2527 750610 : if (option==2) then
2528 0 : inm(iatom,jatom)=interq(kdum)
2529 750610 : else if (option==3) then
2530 750610 : inm(iatom,jatom)=varlist(kdum)
2531 : end if
2532 759520 : inm(jatom,iatom)=inm(iatom,jatom)
2533 : end do
2534 : end if
2535 : end do
2536 :
2537 165 : if (prtvoll==2) then
2538 0 : call wrtout(std_out,'ioniondist: symmetrized matrix:')
2539 0 : call prmat(distm,1,natom,natom,std_out)
2540 165 : else if (prtvoll>=3) then
2541 0 : call wrtout(std_out,'ioniondist: symmetrized matrix:')
2542 0 : call prmat(distm,natom,natom,natom,std_out)
2543 : end if
2544 :
2545 165 : end subroutine ioniondist
2546 : !!***
2547 :
2548 : !!****f* m_geometry/dist2
2549 : !! NAME
2550 : !! dist2
2551 : !!
2552 : !! FUNCTION
2553 : !! Calculates the distance of v1 and v2 in a crystal by repeating the unit cell
2554 : !!
2555 : !! INPUTS
2556 : !! v1,v2
2557 : !! rprimd: dimensions of the unit cell. if not given 1,0,0/0,1,0/0,0,1 is assumed
2558 : !! option: 0 v1, v2 given in cartesian coordinates (default)
2559 : !! 1 v1,v2 given in reduced coordinates
2560 : !! -1 v1 and v2 are supposed equal, and the routine returns the length of the smallest Bravais lattice vector
2561 : !!
2562 : !! OUTPUT
2563 : !! dist2
2564 : !!
2565 : !! SOURCE
2566 :
2567 1127887 : function dist2(v1,v2,rprimd,option)
2568 :
2569 : !Arguments ------------------------------------
2570 : !scalars
2571 : integer,intent(in),optional :: option
2572 : real(dp) :: dist2
2573 : !arrays
2574 : real(dp),intent(in),optional :: rprimd(3,3)
2575 : real(dp),intent(in) :: v1(3),v2(3)
2576 :
2577 : !Local variables-------------------------------
2578 : !scalars
2579 : integer :: i1,i2,i3,opt,s1,s2,s3
2580 : real(dp):: min2,norm2,ucvol
2581 : !arrays
2582 : integer :: limits(3)
2583 : real(dp) :: corner(3),dred(3),dtot(3),dv(3),dwrap(3),sh(3)
2584 : real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3)
2585 : real(dp) :: vprimd(3,3)
2586 : ! *************************************************************************
2587 :
2588 1127887 : if (.not.PRESENT(rprimd)) then
2589 0 : vprimd=reshape((/1,0,0, 0,1,0, 0,0,1/),(/3,3/))
2590 : else
2591 1127887 : vprimd=rprimd
2592 : end if
2593 :
2594 1127887 : call metric(gmet,gprimd,-1,rmet,vprimd,ucvol)
2595 :
2596 4511548 : dv(:)=v2(:)-v1(:)
2597 :
2598 : !If in cartesian coordinates, need to be transformed to reduced coordinates.
2599 1127887 : opt=0
2600 1127887 : if(present(option))then
2601 1127887 : opt=option
2602 : end if
2603 1127887 : if(opt==0)then
2604 0 : dred(:)=gprimd(1,:)*dv(1)+gprimd(2,:)*dv(2)+gprimd(3,:)*dv(3)
2605 1127887 : else if(opt==1)then
2606 1127833 : dred(:)=dv(:)
2607 54 : else if(opt==-1)then
2608 54 : dred(:)=zero
2609 : end if
2610 :
2611 : !Wrap in the ]-1/2,1/2] interval
2612 1127887 : call wrap2_pmhalf(dred(1),dwrap(1),sh(1))
2613 1127887 : call wrap2_pmhalf(dred(2),dwrap(2),sh(2))
2614 1127887 : call wrap2_pmhalf(dred(3),dwrap(3),sh(3))
2615 :
2616 : !Compute the limits of the parallelipipedic box that contains the Wigner-Seitz cell
2617 : !The reduced coordinates of the corners of the Wigner-Seitz cell are computed (multiplied by two)
2618 : !Then, the maximal values of these reduced coordinates are stored.
2619 1127887 : limits(:)=0
2620 3383661 : do s1=-1,1,2
2621 7895209 : do s2=-1,1,2
2622 6767322 : do s3=-1,1,2
2623 36092384 : corner(:)=gmet(:,1)*s1*rmet(1,1)+gmet(:,2)*s2*rmet(2,2)+gmet(:,3)*s3*rmet(3,3)
2624 9023096 : limits(1)=max(limits(1),ceiling(abs(corner(1))+tol14))
2625 9023096 : limits(2)=max(limits(2),ceiling(abs(corner(2))+tol14))
2626 9023096 : limits(3)=max(limits(3),ceiling(abs(corner(3))+tol14))
2627 : end do
2628 : end do
2629 : end do
2630 :
2631 : !Use all relevant primitive real space lattice vectors to find the minimal difference vector
2632 1127887 : min2=huge(zero)
2633 12852786 : do i1=-limits(1),limits(1)
2634 11724899 : dtot(1)=dwrap(1)+i1
2635 174928345 : do i2=-limits(2),limits(2)
2636 162075559 : dtot(2)=dwrap(2)+i2
2637 2742768725 : do i3=-limits(3),limits(3)
2638 2731043826 : if(opt/=-1.or.i1/=0.or.i2/=0.or.i3/=0)then
2639 2568968213 : dtot(3)=dwrap(3)+i3
2640 : norm2=dtot(1)*rmet(1,1)*dtot(1)+dtot(2)*rmet(2,2)*dtot(2)+dtot(3)*rmet(3,3)*dtot(3)+&
2641 2568968213 : & 2*(dtot(1)*rmet(1,2)*dtot(2)+dtot(2)*rmet(2,3)*dtot(3)+dtot(3)*rmet(3,1)*dtot(1))
2642 2568968213 : min2=min(norm2,min2)
2643 : endif
2644 : end do
2645 : end do
2646 : end do
2647 1127887 : dist2=sqrt(min2)
2648 :
2649 1127887 : end function dist2
2650 : !!***
2651 :
2652 : !!****f* m_geometry/remove_inversion
2653 : !! NAME
2654 : !! remove_inversion
2655 : !!
2656 : !! FUNCTION
2657 : !! Remove the inversion symmetry from a symmetry set as well
2658 : !! all the improper rotations (if present)
2659 : !!
2660 : !! INPUTS
2661 : !! nsym=initial number of symmetries
2662 : !! symrel(3,3,nsym)=Initial set of symmetry operarations in real space
2663 : !! tnons(3,nsym)=Initial fractional translations
2664 : !!
2665 : !! OUTPUT
2666 : !! nsym_out=Number of symmetries in the set without improper rotation
2667 : !! symrel_out(:,:) [pointer] = output symmetries without improper rotations
2668 : !! tnons_out(:) [pointer] = fractional translations associated to symrel_out
2669 : !! pinv=-1 if the inversion has been removed, 1 otherwise
2670 : !!
2671 : !! NOTES
2672 : !! Note the use of pointers, memory is allocated inside the procedure and passed back
2673 : !! to the caller. Thus memory deallocation is relegated to the caller. To be on the safe side
2674 : !! the pointers should be nullified before entering.
2675 : !!
2676 : !! SOURCE
2677 :
2678 17 : subroutine remove_inversion(nsym,symrel,tnons,nsym_out,symrel_out,tnons_out,pinv)
2679 :
2680 : !Arguments ------------------------------------
2681 : !scalars
2682 : integer,intent(in) :: nsym
2683 : integer,intent(out) :: nsym_out,pinv
2684 : !arrays
2685 : integer,intent(in) :: symrel(3,3,nsym)
2686 : integer,pointer :: symrel_out(:,:,:)
2687 : real(dp),intent(in) :: tnons(3,nsym)
2688 : real(dp),pointer :: tnons_out(:,:)
2689 :
2690 : !Local variables-------------------------------
2691 : !scalars
2692 : integer :: is,is2,is_discarded,is_inv,is_retained,nsym2
2693 : logical :: found
2694 : character(len=500) :: msg
2695 : !arrays
2696 34 : integer :: determinant(nsym),inversion(3,3),symrel2(3,3,nsym)
2697 34 : real(dp) :: dtnons(3),tnons2(3,nsym)
2698 : ! *********************************************************************
2699 :
2700 17 : ABI_WARNING('Removing inversion related symmetrie from initial set')
2701 :
2702 : ! Find the occurrence of the inversion symmetry.
2703 238 : call set2unit(inversion) ; inversion=-inversion
2704 :
2705 17 : is_inv=0; found=.FALSE.
2706 381 : do while (is_inv<nsym .and. .not.found)
2707 593 : is_inv=is_inv+1; found=ALL(symrel(:,:,is_inv)==inversion)
2708 : end do
2709 17 : if (found) then
2710 0 : write(msg,'(a,i3)')' The inversion is symmetry operation no. ',is_inv
2711 : else
2712 17 : write(msg,'(a)')' The inversion was not found in the symmetries list.'
2713 : end if
2714 17 : call wrtout(std_out,msg)
2715 :
2716 : ! Find the symmetries that are related through the inversion symmetry
2717 17 : call symdet(determinant,nsym,symrel)
2718 17 : nsym2=0
2719 364 : do is=1,nsym-1
2720 4506 : do is2=is+1,nsym
2721 :
2722 16568 : dtnons(:)=tnons(:,is2)-tnons(:,is)-tnons(:,is_inv)
2723 7077 : found=ALL(symrel(:,:,is)==-symrel(:,:,is2)).and.isinteger(dtnons,tol8)
2724 :
2725 347 : if (found) then
2726 0 : nsym2=nsym2+1
2727 : ! Retain symmetries with positive determinant
2728 0 : if (ALL(tnons(:,is2)<tol8).and.ALL(tnons(:,is)<tol8)) then
2729 0 : is_retained=is2 ; is_discarded=is
2730 0 : if (determinant(is)==1) then
2731 0 : is_retained=is ; is_discarded=is2
2732 : end if
2733 0 : else if (ALL(tnons(:,is2)<tol8)) then
2734 0 : is_retained=is2 ; is_discarded=is
2735 : else
2736 0 : is_retained=is ; is_discarded=is2
2737 : end if
2738 :
2739 0 : symrel2(:,:,nsym2)=symrel(:,:,is_retained)
2740 0 : tnons2 (:,nsym2)=tnons (:,is_retained)
2741 : write(msg,'(a,i3,a,i3,3a,i3,a)')&
2742 0 : & ' Symmetry operations no. ',is,' and no. ',is2,&
2743 0 : & ' are related through the inversion.',ch10,&
2744 0 : & ' Symmetry operation no. ',is_discarded,' will be suppressed.'
2745 0 : call wrtout(std_out,msg)
2746 : end if ! found
2747 :
2748 : end do !is2
2749 : end do !is
2750 :
2751 17 : if (nsym2/=(nsym/2).or.nsym==1) then
2752 17 : call wrtout(std_out, ' Program uses the original set of symmetries ')
2753 17 : nsym_out=nsym
2754 51 : ABI_MALLOC(symrel_out,(3,3,nsym))
2755 51 : ABI_MALLOC(tnons_out,(3,nsym))
2756 4749 : symrel_out(:,:,:)=symrel(:,:,1:nsym)
2757 1473 : tnons_out(:,:)=tnons(:,1:nsym)
2758 17 : pinv=1
2759 : else
2760 0 : write(msg,'(a)')' Inversion related operations have been suppressed from symmetries list.'
2761 0 : call wrtout(std_out,msg)
2762 0 : nsym_out=nsym2
2763 0 : ABI_MALLOC(symrel_out,(3,3,nsym2))
2764 0 : ABI_MALLOC(tnons_out,(3,nsym2))
2765 0 : symrel_out(:,:,:)=symrel2(:,:,1:nsym2)
2766 0 : tnons_out(:,:)=tnons(:,1:nsym2)
2767 0 : pinv=-1
2768 : end if
2769 :
2770 17 : end subroutine remove_inversion
2771 : !!***
2772 :
2773 : !!****f* m_geometry/reduce2primitive
2774 : !! NAME
2775 : !! reduce2primitive
2776 : !!
2777 : !! FUNCTION
2778 : !! Find real space primitive vectors from non-primitive ones and the set of non-integer translations
2779 : !! that leave the system invariant
2780 : !!
2781 : !! INPUTS
2782 : !! ntranslat=number of translations
2783 : !! rprimd(3,3)=dimensional non-primitive vectors in real space (bohr)
2784 : !! tolsym=tolerance for the symmetry operations
2785 : !! translations(3,ntranslat)=translation vectors, in reduced coordinates
2786 : !!
2787 : !! OUTPUT
2788 : !! rprimd_primitive(3,3)=dimensional primitive vectors in real space (bohr)
2789 : !!
2790 : !! SOURCE
2791 :
2792 117 : subroutine reduce2primitive(ntranslat, rprimd, rprimd_primitive, tolsym, translations)
2793 :
2794 : !Arguments ------------------------------------
2795 : !scalars
2796 : integer,intent(in) :: ntranslat
2797 : real(dp),intent(in) :: tolsym
2798 : !arrays
2799 : real(dp),intent(in) :: rprimd(3,3),translations(3,ntranslat)
2800 : real(dp),intent(out) :: rprimd_primitive(3,3)
2801 :
2802 : !Local variables-------------------------------
2803 : !scalars
2804 : integer :: idir,itentative,itrans,replace
2805 : character(len=500) :: msg
2806 : !arrays
2807 234 : real(dp) :: trans_cart(3,ntranslat),trans_red(3,ntranslat)
2808 : !**************************************************************************
2809 :
2810 : !These translations should form the primitive lattice when combined with the non-primitive vectors.
2811 : !Each translation, in reduced coordinates, should be constituted of rational numbers.
2812 : !They should pave the non-primitive cell homogeneously. The issue is to replace
2813 : !at least one (or more) of the non-primitive vectors by one (or more) selected translation vectors among the list.
2814 : !All translation vectors should be an integer linear combination of the vectors of the new basis.
2815 :
2816 117 : rprimd_primitive(:,:)=rprimd(:,:)
2817 :
2818 : !First, the reduced coordinates of translation vectors are transferred to the [0,1[ interval
2819 1773 : trans_red(:,1:ntranslat)=translations(:,1:ntranslat)-nint(translations(:,1:ntranslat)-tolsym)
2820 :
2821 : !Then, one of the translation vectors with the smallest non-zero first coordinate will replace the first vector, if any.
2822 : !Similarly for the three directions.
2823 468 : do idir=1,3
2824 : replace=0
2825 1593 : do itrans=1,ntranslat
2826 1593 : if(trans_red(idir,itrans)>tolsym)then
2827 377 : if(replace==0)then
2828 : replace=1 ; itentative=itrans
2829 : else
2830 175 : if(trans_red(idir,itentative)>trans_red(idir,itrans)+tolsym)then
2831 202 : itentative=itrans
2832 : endif
2833 : endif
2834 : endif
2835 : enddo
2836 468 : if(replace==1)then
2837 : ! Change the trans vectors to cartesian coordinates, using "old" rprimd
2838 202 : call xred2xcart(ntranslat,rprimd_primitive,trans_cart,trans_red)
2839 : ! Replace rprimd vector with index idir by the selected trans_cart vector
2840 808 : rprimd_primitive(:,idir)=trans_cart(:,itentative)
2841 : ! Change the translation vectors to new reduced coordinates using updated rprimd_primitive
2842 202 : call xcart2xred(ntranslat,rprimd_primitive,trans_cart,trans_red)
2843 : !Transfer to the [0,1[ interval
2844 3234 : trans_red(:,1:ntranslat)=trans_red(:,1:ntranslat)-nint(trans_red(:,1:ntranslat)-tolsym)
2845 : endif
2846 : enddo ! idir
2847 :
2848 : !Now, check that all translation vectors have zero reduced coordinates.
2849 531 : do itrans=1,ntranslat
2850 1773 : do idir=1,3
2851 1656 : if (abs(trans_red(idir,itrans))>tolsym) then
2852 : write(msg,'(5a)')&
2853 0 : 'Did not succeed to find primitive cell from non-primitive one.',ch10,&
2854 0 : 'Indeed, there remains a non-vanishing pure translation after reduction.',ch10,&
2855 0 : 'Action: this is a bug, contact ABINIT group. Then, use a primitive cell in your input file.'
2856 0 : ABI_ERROR(msg)
2857 : end if
2858 : enddo
2859 : enddo
2860 :
2861 117 : end subroutine reduce2primitive
2862 : !!***
2863 :
2864 : !!****f* m_geometry/symredcart
2865 : !! NAME
2866 : !! symredcart
2867 : !!
2868 : !! FUNCTION
2869 : !! Convert a symmetry operation from reduced coordinates (integers)
2870 : !! to cartesian coordinates (reals). Can operate in real or reciprocal space
2871 : !!
2872 : !! INPUTS
2873 : !! symred(3,3)=symmetry matrice in reduced coordinates (integers) (real or reciprocal space)
2874 : !! aprim(3,3)=real or reciprocal space dimensional primitive translations (see below)
2875 : !! bprim(3,3)=real or reciprocal space dimensional primitive translations (see below)
2876 : !!
2877 : !! OUTPUT
2878 : !! symcart(3,3)=symmetry matrice in cartesian coordinates (reals)
2879 : !!
2880 : !! NOTES
2881 : !! When aprim=rprimd and bprim=gprimd, the routine operates in real space (on a real space symmetry)
2882 : !! When aprim=gprimd and bprim=rprimd, the routine operates in reciprocal space (on a real space symmetry)
2883 : !!
2884 : !! SOURCE
2885 :
2886 789281 : subroutine symredcart(aprim,bprim,symcart,symred)
2887 :
2888 : !Arguments ------------------------------------
2889 : !arrays
2890 : integer,intent(in) :: symred(3,3)
2891 : real(dp),intent(in) :: aprim(3,3),bprim(3,3)
2892 : real(dp),intent(out) :: symcart(3,3)
2893 :
2894 : !Local variables-------------------------------
2895 : !scalars
2896 : integer :: ii,jj,kk
2897 : real(dp) :: symtmp
2898 : !arrays
2899 : real(dp) :: work(3,3)
2900 : ! *************************************************************************
2901 :
2902 789281 : work=zero
2903 3157124 : do kk=1,3
2904 10260653 : do jj=1,3
2905 7103529 : symtmp=dble(symred(jj,kk))
2906 30781959 : do ii=1,3
2907 28414116 : work(ii,jj)=work(ii,jj)+bprim(ii,kk)*symtmp
2908 : end do
2909 : end do
2910 : end do
2911 :
2912 : ! work = bprim * symred^T
2913 :
2914 789281 : symcart=zero
2915 3157124 : do kk=1,3
2916 10260653 : do jj=1,3
2917 7103529 : symtmp=work(jj,kk)
2918 30781959 : do ii=1,3
2919 : ! symcart = aprim * work^T = aprim * symred * bprim^T
2920 28414116 : symcart(ii,jj)=symcart(ii,jj)+aprim(ii,kk)*symtmp
2921 : end do
2922 : end do
2923 : end do
2924 :
2925 789281 : end subroutine symredcart
2926 : !!***
2927 :
2928 : !!****f* m_geometry/strainsym
2929 : !! NAME
2930 : !! strainsym
2931 : !!
2932 : !! FUNCTION
2933 : !! For given order of point group, symmetrizes the strain tensor,
2934 : !! then produce primitive vectors based on the symmetrized strain.
2935 : !!
2936 : !! INPUTS
2937 : !! nsym=order of group.
2938 : !! rprimd(3,3)= primitive vectors, to be symmetrized
2939 : !! rprimd0(3,3)= reference primitive vectors, already symmetrized
2940 : !! symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations
2941 : !!
2942 : !! OUTPUT
2943 : !! rprimd_symm(3,3)= symmetrized primitive vectors
2944 : !!
2945 : !! SOURCE
2946 :
2947 478 : subroutine strainsym(nsym,rprimd0,rprimd,rprimd_symm,symrel)
2948 :
2949 : use m_linalg_interfaces
2950 :
2951 : !Arguments ------------------------------------
2952 : !scalars
2953 : integer,intent(in) :: nsym
2954 : !arrays
2955 : integer,intent(in) :: symrel(3,3,nsym)
2956 : real(dp),intent(in) :: rprimd(3,3),rprimd0(3,3)
2957 : real(dp),intent(out) :: rprimd_symm(3,3)
2958 :
2959 : !Local variables-------------------------------
2960 : !scalars
2961 : integer :: isym
2962 : !arrays
2963 : integer :: symrel_it(3,3)
2964 : real(dp) :: rprimd0_inv(3,3),strain(3,3),strain_symm(3,3),tmp_mat(3,3),symrel_db(3,3)
2965 : !**************************************************************************
2966 :
2967 : !copy initial rprimd input and construct inverse
2968 478 : rprimd0_inv = rprimd0
2969 478 : call matrginv(rprimd0_inv,3,3)
2970 :
2971 : !define strain as rprimd = strain * rprimd0 (in cartesian frame)
2972 : !so strain = rprimd * rprimd0^{-1}
2973 : !transform to triclinic frame with rprimd0^{-1} * strain * rprimd0
2974 : !giving strain as rprimd0^{-1} * rprimd
2975 478 : call dgemm('N','N',3,3,3,one,rprimd0_inv,3,rprimd,3,zero,strain,3)
2976 :
2977 : !loop over symmetry elements to obtain symmetrized strain matrix
2978 478 : strain_symm = zero
2979 8236 : do isym = 1, nsym
2980 : ! this loop accumulates symrel^{-1}*strain*symrel into strain_symm
2981 : ! mati3inv gives the inverse transpose of symrel
2982 7758 : call mati3inv(symrel(:,:,isym),symrel_it)
2983 100854 : symrel_db = dble(symrel(:,:,isym))
2984 7758 : call dgemm('N','N',3,3,3,one,strain,3,symrel_db,3,zero,tmp_mat,3)
2985 100854 : symrel_db = dble(symrel_it)
2986 8236 : call dgemm('T','N',3,3,3,one,symrel_db,3,tmp_mat,3,one,strain_symm,3)
2987 : end do
2988 :
2989 : !normalize by number of symmetry operations
2990 6214 : strain_symm = strain_symm/dble(nsym)
2991 :
2992 : !this step is equivalent to r_new = r_old * strain * r_old^{-1} * r_old,
2993 : !that is, convert strain back to cartesian frame and then multiply by r_old,
2994 : !to get the r_new primitive vectors
2995 :
2996 478 : call dgemm('N','N',3,3,3,one,rprimd0,3,strain_symm,3,zero,rprimd_symm,3)
2997 :
2998 478 : end subroutine strainsym
2999 : !!***
3000 :
3001 : !!****f* m_geometry/stresssym
3002 : !! NAME
3003 : !! stresssym
3004 : !!
3005 : !! FUNCTION
3006 : !! For given order of point group, symmetrizes the stress tensor,
3007 : !! in symmetrized storage mode and cartesian coordinates, using input
3008 : !! 3x3 symmetry operators in reduced coordinates.
3009 : !! symmetrized tensor replaces input tensor.
3010 : !!
3011 : !! INPUTS
3012 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space (bohr**-1)
3013 : !! nsym=order of group.
3014 : !! sym(3,3,nsym)=symmetry operators (usually symrec=expressed in terms
3015 : !! of action on reciprocal lattice primitive translations); integers.
3016 : !!
3017 : !! SIDE EFFECTS
3018 : !! stress(6)=stress tensor, in cartesian coordinates, in symmetric storage mode
3019 : !!
3020 : !! SOURCE
3021 :
3022 19939 : subroutine stresssym(gprimd,nsym,stress,sym)
3023 :
3024 : !Arguments ------------------------------------
3025 : !scalars
3026 : integer,intent(in) :: nsym
3027 : !arrays
3028 : integer,intent(in) :: sym(3,3,nsym)
3029 : real(dp),intent(in) :: gprimd(3,3)
3030 : real(dp),intent(inout) :: stress(6)
3031 :
3032 : !Local variables-------------------------------
3033 : !scalars
3034 : integer :: ii,isym,mu,nu
3035 : real(dp) :: summ,tmp
3036 : !arrays
3037 : real(dp) :: rprimd(3,3),rprimdt(3,3),strfrac(6),tensor(3,3),tt(3,3)
3038 : !*************************************************************************
3039 :
3040 : !Obtain matrix of real space dimensional primitive translations
3041 : !(inverse transpose of gprimd), and its transpose
3042 19939 : call matr3inv(gprimd,rprimd)
3043 259207 : rprimdt=transpose(rprimd)
3044 :
3045 : !Compute stress tensor in reduced coordinates
3046 : ! strfrac = rprimd^T * stress * rprimd
3047 19939 : call strconv(stress,rprimdt,strfrac)
3048 :
3049 : !Switch to full storage mode
3050 19939 : tensor(1,1)=strfrac(1)
3051 19939 : tensor(2,2)=strfrac(2)
3052 19939 : tensor(3,3)=strfrac(3)
3053 19939 : tensor(3,2)=strfrac(4)
3054 19939 : tensor(3,1)=strfrac(5)
3055 19939 : tensor(2,1)=strfrac(6)
3056 19939 : tensor(2,3)=tensor(3,2)
3057 19939 : tensor(1,3)=tensor(3,1)
3058 19939 : tensor(1,2)=tensor(2,1)
3059 :
3060 : ! these loops are useless - trivial action:
3061 : ! tt = tensor / dble(nsym)
3062 : ! tensor = zero
3063 79756 : do nu=1,3
3064 259207 : do mu=1,3
3065 179451 : tt(mu,nu)=tensor(mu,nu)/dble(nsym)
3066 239268 : tensor(mu,nu)=0.0_dp
3067 : end do
3068 : end do
3069 :
3070 : !loop over all symmetry operations:
3071 : ! tensor = symrec * tt * symrec^T = symrec * rprimd^T * input * rprimd symrec^T
3072 : ! TODO: this should be replaced by a little BLAS call or two
3073 348786 : do isym=1,nsym
3074 1335327 : do mu=1,3
3075 4275011 : do nu=1,3
3076 : summ=0._dp
3077 11838492 : do ii=1,3
3078 : tmp=tt(ii,1)*sym(nu,1,isym)+tt(ii,2)*sym(nu,2,isym)+&
3079 8878869 : & tt(ii,3)*sym(nu,3,isym)
3080 11838492 : summ=summ+sym(mu,ii,isym)*tmp
3081 : end do
3082 3946164 : tensor(mu,nu)=tensor(mu,nu)+summ
3083 : end do
3084 : end do
3085 : end do
3086 :
3087 : !Switch back to symmetric storage mode
3088 19939 : strfrac(1)=tensor(1,1)
3089 19939 : strfrac(2)=tensor(2,2)
3090 19939 : strfrac(3)=tensor(3,3)
3091 19939 : strfrac(4)=tensor(3,2)
3092 19939 : strfrac(5)=tensor(3,1)
3093 19939 : strfrac(6)=tensor(2,1)
3094 :
3095 : !Convert back stress tensor (symmetrized) in cartesian coordinates
3096 : ! stress = gprimd * symrec * rprimd^T * input * rprimd symrec^T * gprimd^T
3097 : ! symrec_cart = gprimd * symrec * rprimd^T
3098 : ! sym_cart = symrec_cart^-1 ^T = rprimd * sym * gprimd^T
3099 19939 : call strconv(strfrac,gprimd,stress)
3100 :
3101 19939 : end subroutine stresssym
3102 : !!***
3103 :
3104 : !!****f* m_geometry/stress_voigt_to_mat
3105 : !! NAME
3106 : !! stress_voigt_to_mat
3107 : !!
3108 : !! FUNCTION
3109 : !! Build 3x3 symmetric stress tensor from stress vector in Voigt notation.
3110 : !!
3111 : !! INPUTS
3112 : !!
3113 : !! OUTPUT
3114 : !!
3115 : !! SOURCE
3116 :
3117 5474 : subroutine stress_voigt_to_mat(stress6, stress_mat)
3118 :
3119 : real(dp),intent(in) :: stress6(6)
3120 : real(dp),intent(out) :: stress_mat(3,3)
3121 :
3122 5474 : stress_mat(1,1) = stress6(1)
3123 5474 : stress_mat(2,2) = stress6(2)
3124 5474 : stress_mat(3,3) = stress6(3)
3125 5474 : stress_mat(2,3) = stress6(4)
3126 5474 : stress_mat(3,2) = stress6(4)
3127 5474 : stress_mat(1,3) = stress6(5)
3128 5474 : stress_mat(3,1) = stress6(5)
3129 5474 : stress_mat(1,2) = stress6(6)
3130 5474 : stress_mat(2,1) = stress6(6)
3131 :
3132 5474 : end subroutine stress_voigt_to_mat
3133 : !!***
3134 :
3135 : !!****f* m_geometry/strconv
3136 : !! NAME
3137 : !! strconv
3138 : !!
3139 : !! FUNCTION
3140 : !! If original gprimd is input, convert from symmetric storage mode
3141 : !! 3x3 tensor in reduced coordinates "frac" to symmetric storage mode
3142 : !! symmetric tensor in cartesian coordinates "cart".
3143 : !!
3144 : !! INPUTS
3145 : !! frac(6)=3x3 tensor in symmetric storage mode, reduced coordinates
3146 : !! gprimd(3,3)=reciprocal space dimensional primitive translations (bohr^-1)
3147 : !!
3148 : !! OUTPUT
3149 : !! cart(6)=symmetric storage mode for symmetric 3x3 tensor in cartesian coords.
3150 : !!
3151 : !! NOTES
3152 : !! $cart(i,j)=G(i,a) G(j,b) frac(a,b)$
3153 : !! "Symmetric" storage mode for 3x3 tensor is 6 element array with
3154 : !! elements 11, 22, 33, 32, 31, and 21.
3155 : !! "cart" may be same array as "frac".
3156 : !! If rprimd transpose is input instead of gprimd, then convert tensor
3157 : !! in cartesian coordinates to reduced coordinates
3158 : !!
3159 : !! SOURCE
3160 :
3161 931827 : subroutine strconv(frac,gprimd,cart)
3162 :
3163 : !Arguments ------------------------------------
3164 : !arrays
3165 : real(dp),intent(in) :: frac(6),gprimd(3,3)
3166 : real(dp),intent(inout) :: cart(6) ! alias of frac !vz_i
3167 :
3168 : !Local variables-------------------------------
3169 : !scalars
3170 : integer :: ii,jj
3171 : !arrays
3172 : real(dp) :: work1(3,3),work2(3,3)
3173 : ! *************************************************************************
3174 :
3175 931827 : work1(1,1)=frac(1)
3176 931827 : work1(2,2)=frac(2)
3177 931827 : work1(3,3)=frac(3)
3178 931827 : work1(3,2)=frac(4) ; work1(2,3)=frac(4)
3179 931827 : work1(3,1)=frac(5) ; work1(1,3)=frac(5)
3180 931827 : work1(2,1)=frac(6) ; work1(1,2)=frac(6)
3181 :
3182 : ! TODO: these are matmuls, replace or get BLAS
3183 : ! work2 = work1 * gprimd^T
3184 3727308 : do ii=1,3
3185 11181924 : work2(:,ii)=zero
3186 12113751 : do jj=1,3
3187 36341253 : work2(:,ii)=work2(:,ii)+gprimd(ii,jj)*work1(:,jj)
3188 : end do
3189 : end do
3190 :
3191 : ! work1 = gprimd * work2 = gprimd * input * gprimd^T
3192 3727308 : do ii=1,3
3193 11181924 : work1(ii,:)=zero
3194 12113751 : do jj=1,3
3195 36341253 : work1(ii,:)=work1(ii,:)+gprimd(ii,jj)*work2(jj,:)
3196 : end do
3197 : end do
3198 :
3199 931827 : cart(1)=work1(1,1)
3200 931827 : cart(2)=work1(2,2)
3201 931827 : cart(3)=work1(3,3)
3202 931827 : cart(4)=work1(2,3)
3203 931827 : cart(5)=work1(1,3)
3204 931827 : cart(6)=work1(1,2)
3205 :
3206 931827 : end subroutine strconv
3207 : !!***
3208 :
3209 : !!****f* m_geometry/littlegroup_pert
3210 : !!
3211 : !! NAME
3212 : !! littlegroup_pert
3213 : !!
3214 : !! FUNCTION
3215 : !! If syuse==0 and abs(rfmeth)==2, determines the set of symmetries that leaves a perturbation invariant.
3216 : !! (Actually, all symmetries that leaves a q-wavevector invariant should be used to reduce the number
3217 : !! of k-points for all perturbations. Unfortunately, one has to take into account the sign reversal of the
3218 : !! perturbation under the symmetry operations, which makes GS routines not usable for the respfn code.
3219 : !! The intermediate choice was to select only those that keep also the perturbation invariant.
3220 : !! Note that the wavevector of the perturbation must also be invariant,
3221 : !! a translation vector in real space is NOT allowed ).
3222 : !!
3223 : !! INPUTS
3224 : !! gprimd(3,3)=dimensional primitive translations for reciprocal space (bohr**-1)
3225 : !! idir=direction of the perturbation
3226 : !! indsym(4,nsym,natom)=indirect indexing of atom labels--see subroutine symatm for definition (if nsym>1)
3227 : !! iout=if non-zero, output on unit iout
3228 : !! ipert=characteristics of the perturbation
3229 : !! natom= number of atoms
3230 : !! nsym=number of space group symmetries
3231 : !! rfmeth =
3232 : !! 1 or -1 if non-stationary block
3233 : !! 2 or -2 if stationary block
3234 : !! 3 or -3 if third order derivatives
3235 : !! positive if symmetries are used to set elements to zero whenever possible, negative to prevent this to happen.
3236 : !! symq(4,2,nsym)= Table computed by littlegroup_q.
3237 : !! three first numbers define the G vector;
3238 : !! fourth number is zero if the q-vector is not preserved, is 1 otherwise
3239 : !! second index is one without time-reversal symmetry, two with time-reversal symmetry
3240 : !! symafm(nsym)=(anti)ferromagnetic part of the symmetry operations
3241 : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
3242 : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
3243 : !! syuse= flag to use the symmetries or not. If 0 usei it, if 1 do not use it.
3244 : !! tnons(3,nsym)=nonsymmorphic translations of space group in terms
3245 : !! of real space primitive translations (may be 0)
3246 : !! [unit]=By default the routine writes to std_out and this is very annoying if we are inside a big loop.
3247 : !! Use unit=dev_null or a negative integer to disable writing.
3248 : !!
3249 : !! OUTPUT
3250 : !! nsym1 =number of space group symmetries that leaves the perturbation invariant
3251 : !! symaf1(nsym1)=(anti)ferromagnetic part of the corresponding symmetry operations
3252 : !! symrl1(3,3,nsym1)=corresponding 3x3 matrices of the group symmetries (real space)
3253 : !! tnons1(3,nsym1)=corresponding nonsymmorphic translations of space group in terms
3254 : !! of real space primitive translations (may be 0)!!
3255 : !!
3256 : !! SOURCE
3257 :
3258 4115 : subroutine littlegroup_pert(gprimd,idir,indsym,iout,ipert,natom,nsym,nsym1, &
3259 4115 : & rfmeth,symafm,symaf1,symq,symrec,symrel,symrl1,syuse,tnons,tnons1, &
3260 : & unit) ! Optional
3261 :
3262 : !Arguments -------------------------------
3263 : !scalars
3264 : integer,intent(in) :: idir,iout,ipert,natom,nsym,rfmeth,syuse
3265 : integer,intent(in),optional :: unit
3266 : integer,intent(out) :: nsym1
3267 : !arrays
3268 : integer,intent(in) :: indsym(4,nsym,natom),symafm(nsym),symq(4,2,nsym)
3269 : integer,intent(in) :: symrec(3,3,nsym),symrel(3,3,nsym)
3270 : integer,intent(out) :: symaf1(nsym),symrl1(3,3,nsym)
3271 : real(dp),intent(in) :: gprimd(3,3),tnons(3,nsym)
3272 : real(dp),intent(out) :: tnons1(3,nsym)
3273 :
3274 : !Local variables -------------------------
3275 : !scalars
3276 : integer :: idir1,ii,istr,isym,jj,nsym_test,tok,ount
3277 : character(len=500) :: msg
3278 : !arrays
3279 : integer :: sym_test(3,3,2)
3280 : real(dp) :: str_test(6)
3281 : ! *********************************************************************
3282 :
3283 4115 : ount = std_out; if (present(unit)) ount = unit
3284 :
3285 4115 : nsym1=0
3286 4115 : if((ipert==natom+3 .or. ipert==natom+4) .and. syuse==0 .and. abs(rfmeth)==2) then
3287 : ! Strain perturbation section
3288 : ! Use ground state routine which symmetrizes cartesian stress as a quick
3289 : ! and dirty test for the invariance of the strain (ipert,idir) under
3290 : ! each candidate symmetry
3291 : ! I am presently assuming that translations are acceptable because I dont
3292 : ! see why not.
3293 :
3294 156 : istr=3*(ipert-natom-3)+idir
3295 156 : nsym_test=2
3296 : ! Store identity as first element for test
3297 2028 : sym_test(:,:,1)=0
3298 156 : sym_test(1,1,1)=1; sym_test(2,2,1)=1; sym_test(3,3,1)=1
3299 3686 : do isym=1,nsym
3300 45890 : sym_test(:,:,2)=symrec(:,:,isym)
3301 3530 : str_test(:)=0.0_dp
3302 3530 : str_test(istr)=1.0_dp
3303 3530 : call stresssym(gprimd,nsym_test,str_test,sym_test)
3304 3686 : if(abs(str_test(istr)-1.0_dp)<tol8)then
3305 : ! The test has been successful !
3306 1004 : nsym1=nsym1+1
3307 1004 : symaf1(nsym1)=symafm(isym)
3308 4016 : do ii=1,3
3309 3012 : tnons1(ii,nsym1)=tnons(ii,isym)
3310 13052 : do jj=1,3
3311 12048 : symrl1(ii,jj,nsym1)=symrel(ii,jj,isym)
3312 : end do
3313 : end do
3314 : end if
3315 : end do
3316 :
3317 3959 : else if(ipert>natom .or. syuse/=0 .or. abs(rfmeth)/=2)then
3318 :
3319 : ! Not yet coded for d/dk or electric field perturbations
3320 704 : nsym1=1
3321 2816 : do ii=1,3
3322 2112 : tnons1(ii,1)=0._dp
3323 2112 : symaf1(1)=1
3324 9152 : do jj=1,3
3325 6336 : symrl1(ii,jj,1)=0
3326 8448 : if(ii==jj)symrl1(ii,jj,1)=1
3327 : end do
3328 : end do
3329 :
3330 : else
3331 :
3332 116592 : do isym=1,nsym
3333 : ! Check that the symmetry operation preserves the wavevector
3334 : ! (a translation is NOT allowed)
3335 : if(symq(4,1,isym)==1 .and.&
3336 : & symq(1,1,isym)==0 .and.&
3337 113337 : & symq(2,1,isym)==0 .and.&
3338 3255 : & symq(3,1,isym)==0 )then
3339 : ! Check that the symmetry operation preserves the atom
3340 29823 : if(ipert==indsym(4,isym,ipert))then
3341 : ! Check if the direction is preserved
3342 : tok=1
3343 111644 : do idir1=1,3
3344 83733 : if((idir1==idir.and.symrec(idir,idir1,isym)/=1) .or.&
3345 27911 : & (idir1/=idir.and.symrec(idir,idir1,isym)/=0))then
3346 83733 : tok=0
3347 : end if
3348 : end do
3349 27911 : if(tok==1)then
3350 : ! All the tests have been successful !
3351 5645 : nsym1=nsym1+1
3352 5645 : symaf1(nsym1)=symafm(isym)
3353 22580 : do ii=1,3
3354 16935 : tnons1(ii,nsym1)=tnons(ii,isym)
3355 73385 : do jj=1,3
3356 67740 : symrl1(ii,jj,nsym1)=symrel(ii,jj,isym)
3357 : end do
3358 : end do
3359 : end if
3360 :
3361 : end if
3362 : end if
3363 : end do
3364 : end if
3365 :
3366 4115 : if (nsym1<1) then
3367 0 : write(msg,'(a,i0,a)')' The number of selected symmetries should be > 0, while it is nsym= ',nsym1,'.'
3368 0 : ABI_BUG(msg)
3369 : end if
3370 :
3371 4115 : if (nsym1 /= 1) then
3372 1584 : if (iout /= ount .and. iout > 0) then
3373 702 : write(msg,'(a,i5,a)')' Found ',nsym1,' symmetries that leave the perturbation invariant.'
3374 702 : call wrtout(iout,msg)
3375 : end if
3376 1584 : write(msg,'(a,i5,a)')' littlegroup_pert: found ',nsym1,' symmetries that leave the perturbation invariant: '
3377 1584 : call wrtout(ount,msg)
3378 : else
3379 2531 : if (iout /= ount .and. iout > 0) then
3380 1565 : write(msg,'(a,a)')' The set of symmetries contains',' only one element for this perturbation.'
3381 1565 : call wrtout(iout,msg)
3382 : end if
3383 2531 : write(msg,'(a)')' littlegroup_pert: only one element in the set of symmetries for this perturbation:'
3384 2531 : call wrtout(ount,msg)
3385 : end if
3386 :
3387 4115 : if (ount > 0) then
3388 6782 : do isym=1,nsym1
3389 4385 : write(msg, '(9i4)' )((symrl1(ii,jj,isym),ii=1,3),jj=1,3)
3390 6782 : call wrtout(ount,msg)
3391 : end do
3392 : end if
3393 :
3394 4115 : end subroutine littlegroup_pert
3395 : !!***
3396 :
3397 : !!****f* ABINIT/irreducible_set_pert
3398 : !! NAME
3399 : !! irreducible_set_pert
3400 : !!
3401 : !! FUNCTION
3402 : !! Determines a set of perturbations that form a basis
3403 : !! in that, using symmetry, they can be used to generate
3404 : !! all other perturbations that are asked to be calculated (target).
3405 : !!
3406 : !! INPUTS
3407 : !! indsym(4,nsym,natom)=indirect indexing array described above: for each
3408 : !! isym,iatom, fourth element is label of atom into which iatom is sent by
3409 : !! INVERSE of symmetry operation isym; first three elements are the primitive
3410 : !! translations which must be subtracted after the transformation to get back
3411 : !! to the original unit cell.
3412 : !! mpert =maximum number of iper
3413 : !! natom= number of atoms
3414 : !! nsym=number of space group symmetries
3415 : !! rfdir(3)=direction for the perturbations
3416 : !! rfpert(mpert)=information on the perturbations
3417 : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
3418 : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
3419 : !! symq(4,2,nsym)= (integer) three first numbers define the G vector;
3420 : !! fourth number is 0 if the q-vector is not preserved, is 1 otherwise
3421 : !! second index is one without time-reversal symmetry, two with time-reversal symmetry
3422 : !!
3423 : !! OUTPUT
3424 : !! pertsy(3,mpert)= the target perturbation is described by the two last indices (idir, and ipert),
3425 : !! the value is 0, 1 or -1, see notes.
3426 : !!
3427 : !! NOTES
3428 : !! Output will be in the pertsy array,
3429 : !! 0 for non-target perturbations
3430 : !! 1 for basis perturbations
3431 : !! -1 for perturbations that can be found from basis perturbations
3432 : !!
3433 : !! SOURCE
3434 :
3435 1518 : subroutine irreducible_set_pert(indsym,mpert,natom,nsym,pertsy,rfdir,rfpert,symq,symrec,symrel)
3436 :
3437 : !Arguments -------------------------------
3438 : !scalars
3439 : integer,intent(in) :: mpert,natom,nsym
3440 : !arrays
3441 : integer,intent(in) :: indsym(4,nsym,natom),rfdir(3),rfpert(mpert)
3442 : integer,intent(in) :: symq(4,2,nsym),symrec(3,3,nsym),symrel(3,3,nsym)
3443 : integer,intent(out) :: pertsy(3,mpert)
3444 :
3445 : !Local variables -------------------------
3446 : !scalars
3447 : integer :: found,idir1,idisy1,ii,ipert1,ipesy1,isign,isym,itirev,jj
3448 : !arrays
3449 : integer :: sym1(3,3)
3450 : ! *********************************************************************
3451 :
3452 : !Zero pertsy
3453 53722 : pertsy(:,:)=0
3454 :
3455 14569 : do ipert1=1,mpert
3456 53722 : do idir1=1,3
3457 52204 : if(rfpert(ipert1)==1.and.rfdir(idir1)==1)then
3458 : ! write(std_out,*)' for candidate idir =',idir1,' ipert = ',ipert1
3459 :
3460 : ! Loop on all symmetries, including time-reversal
3461 255019 : do isym=1,nsym
3462 672538 : do itirev=1,2
3463 457742 : isign=3-2*itirev
3464 :
3465 664974 : if(symq(4,itirev,isym)/=0)then
3466 :
3467 181554 : found=1
3468 :
3469 : ! Here select the symmetric of ipert1
3470 181554 : if(ipert1<=natom)then
3471 137465 : ipesy1=indsym(4,isym,ipert1)
3472 549860 : do ii=1,3
3473 1787045 : do jj=1,3
3474 1649580 : sym1(ii,jj)=symrec(ii,jj,isym)
3475 : end do
3476 : end do
3477 44089 : else if(ipert1==(natom+2))then
3478 50136 : ipesy1=ipert1
3479 50136 : do ii=1,3
3480 162942 : do jj=1,3
3481 150408 : sym1(ii,jj)=symrel(ii,jj,isym)
3482 : end do
3483 : end do
3484 : else
3485 : found=0
3486 : end if
3487 :
3488 : ! Now that a symmetric perturbation has been obtained,
3489 : ! including the expression of the symmetry matrix, see
3490 : ! if the symmetric perturbations are available
3491 : if( found==1 ) then
3492 :
3493 384588 : do idisy1=1,3
3494 384588 : if(sym1(idir1,idisy1)/=0)then
3495 185707 : if(pertsy(idisy1,ipesy1)==0)then
3496 : found=0
3497 : exit
3498 : end if
3499 : end if
3500 : end do
3501 : end if
3502 :
3503 : ! Now, if still found, then it is a symmetric
3504 : ! of some linear combination of existing perturbations
3505 181554 : if(found==1)then
3506 :
3507 : ! DEBUG
3508 : ! write(std_out,*)' all found ! isym, isign= ',isym,isign
3509 : ! write(std_out,1010)((sym1(ii,jj),ii=1,3),jj=1,3)
3510 : ! write(std_out,1010)((sym2(ii,jj),ii=1,3),jj=1,3)
3511 : ! write(std_out,*)sumr,sumi
3512 : ! 1010 format(9i4)
3513 : ! ENDDEBUG
3514 :
3515 40223 : pertsy(idir1,ipert1)=-1
3516 40223 : exit ! Exit loop on symmetry operations
3517 :
3518 : end if
3519 :
3520 : end if ! End loop on all symmetries + time-reversal
3521 : end do
3522 : end do
3523 :
3524 : ! Now that all symmetries have been examined,
3525 : ! if still not symmetric of a linear combination
3526 : ! of basis perturbations, then it is a basis perturbation
3527 7564 : if(pertsy(idir1,ipert1)/=-1) pertsy(idir1,ipert1)=1
3528 : ! write(std_out,'(a,3i5)' ) ' irreducible_set_pert :',idir1,ipert1,pertsy(idir1,ipert1)
3529 :
3530 : end if ! End big loop on all elements
3531 : end do
3532 : end do
3533 :
3534 1518 : end subroutine irreducible_set_pert
3535 : !!***
3536 :
3537 : !!****f* m_dynmat/d3lwsym
3538 : !! NAME
3539 : !! d3lwsym
3540 : !!
3541 : !! FUNCTION
3542 : !! Given a set of calculated elements of the 3DTE matrix,
3543 : !! build (nearly) all the other matrix elements that can be build using symmetries.
3544 : !!
3545 : !! INPUTS
3546 : !! has_strain = if .true. i2pert includes strain perturbation
3547 : !! indsym(4,nsym,natom)=indirect indexing array : for each
3548 : !! isym,iatom, fourth element is label of atom into which iatom is sent by
3549 : !! INVERSE of symmetry operation isym; first three elements are the primitive
3550 : !! translations which must be subtracted after the transformation to get back
3551 : !! to the original unit cell.
3552 : !! mpert =maximum number of ipert
3553 : !! natom= number of atoms
3554 : !! nsym=number of space group symmetries
3555 : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal reduced space)
3556 : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real reduced space)
3557 : !! symrel_cart(3,3,nsym)=3x3 matrices of the group symmetries (real cartesian space)
3558 : !!
3559 : !! SIDE EFFECTS
3560 : !! Input/Output
3561 : !! blkflg(3,mpert,3,mpert,3,mpert)= matrix that indicates if an
3562 : !! element of d3 is available (1 if available, 0 otherwise)
3563 : !! d3(2,3,mpert,3,mpert,3,mpert)= matrix of the 3DTE
3564 : !!
3565 : !! SOURCE
3566 :
3567 : !subroutine d3lwsym(blkflg,d3,has_strain,indsym,mpert,natom,nsym,symrec,symrel,symrel_cart)
3568 17 : subroutine d3lwsym(blkflg,d3,indsym,mpert,natom,nsym,symrec,symrel)
3569 :
3570 : !Arguments -------------------------------
3571 : !scalars
3572 : integer,intent(in) :: mpert,natom,nsym
3573 : ! logical,intent(in) :: has_strain
3574 : !arrays
3575 : integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
3576 : integer,intent(inout) :: blkflg(3,mpert,3,mpert,3,mpert)
3577 : real(dp),intent(inout) :: d3(2,3,mpert,3,mpert,3,mpert)
3578 : ! real(dp),intent(in) :: symrel_cart(3,3,nsym)
3579 :
3580 : !Local variables -------------------------
3581 : !scalars
3582 : integer :: found,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert,idisy1,idisy2,idisy3
3583 : integer :: ipesy1,ipesy2,ipesy3,isym,ithree
3584 : !integer :: istr,i2dir_a,i2dir_b,disy2_a,idisy2_b
3585 : real(dp) :: sumi,sumr
3586 : logical :: is_strain
3587 : !arrays
3588 : ! integer,save :: idx(18)=(/1,1,2,2,3,3,3,2,3,1,2,1,2,3,1,3,1,2/)
3589 : integer :: sym1(3,3),sym2(3,3),sym3(3,3)
3590 : ! integer :: strflg(3,mpert,3,3,3,mpert),strflg_car(3,mpert,3,3,3,mpert)
3591 : ! real(dp) :: d3str(2,3,mpert,3,3,3,mpert)
3592 : ! *********************************************************************
3593 :
3594 : !First, take into account the permutations symmetry of
3595 : !(i1pert,i1dir) and (i2pert,i2dir)
3596 259 : do i1pert = 1, mpert
3597 4183 : do i2pert = 1, mpert
3598 75694 : do i3pert = 1, mpert
3599 :
3600 290036 : do i1dir = 1, 3
3601 929864 : do i2dir = 1, 3
3602 2789592 : do i3dir = 1, 3
3603 :
3604 1931256 : if ((blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1).and. &
3605 643752 : (blkflg(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert)/=1)) then
3606 :
3607 : d3(1,i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = &
3608 842 : d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
3609 : d3(2,i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = &
3610 842 : -d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
3611 :
3612 842 : blkflg(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = 1
3613 :
3614 : end if
3615 :
3616 : end do
3617 : end do
3618 : end do
3619 :
3620 : end do
3621 : end do
3622 : end do
3623 :
3624 : !For strain perturbation we need an array with the two strain indexes
3625 : ! if (has_strain) then
3626 : ! strflg=0
3627 : ! d3str=zero
3628 : ! do i3pert=1, mpert
3629 : ! do i3dir=1,3
3630 : ! do i2pert=natom+3,natom+4
3631 : ! do i2dir=1,3
3632 : ! if (i2pert==natom+3) istr=i2dir
3633 : ! if (i2pert==natom+4) istr=3+i2dir
3634 : ! i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
3635 : ! do i1pert=1,mpert
3636 : ! do i1dir=1,3
3637 : ! if (blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1) then
3638 : ! strflg(i1dir,i1pert,i2dir_a,i2dir_b,i3dir,i3pert)=1
3639 : ! d3str(:,i1dir,i1pert,i2dir_a,i2dir_b,i3dir,i3pert)= &
3640 : ! & d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
3641 : ! if (i2pert==natom+4) then
3642 : ! strflg(i1dir,i1pert,i2dir_b,i2dir_a,i3dir,i3pert)=1
3643 : ! d3str(:,i1dir,i1pert,i2dir_b,i2dir_a,i3dir,i3pert)= &
3644 : ! & d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
3645 : ! end if
3646 : ! end if
3647 : ! end do
3648 : ! end do
3649 : ! end do
3650 : ! end do
3651 : ! end do
3652 : ! end do
3653 : ! end if
3654 :
3655 : !Big Big Loop : symmetrize three times, because
3656 : !of some cases in which one element is not yet available
3657 : !at the first pass, and even at the second one !
3658 :
3659 68 : do ithree=1,3
3660 :
3661 : ! Loop over perturbations
3662 794 : do i1pert = 1, mpert
3663 12549 : do i2pert = 1, mpert
3664 : is_strain=.false.
3665 227082 : do i3pert = 1, mpert
3666 :
3667 870108 : do i1dir = 1, 3
3668 2789592 : do i2dir = 1, 3
3669 8368776 : do i3dir = 1, 3
3670 :
3671 : ! Will get element (idir1,ipert1,idir2,ipert2)
3672 : ! so this element should not yet be present ...
3673 7725024 : if(blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)/=1)then
3674 :
3675 17360586 : d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 0_dp
3676 :
3677 36156726 : do isym = 1, nsym
3678 :
3679 30369864 : found = 1
3680 :
3681 30369864 : if (i1pert <= natom) then
3682 7337334 : ipesy1 = indsym(4,isym,i1pert)
3683 95385342 : sym1(:,:) = symrec(:,:,isym)
3684 23032530 : else if (i1pert == natom + 2) then
3685 2634504 : ipesy1 = i1pert
3686 34248552 : sym1(:,:) = symrel(:,:,isym)
3687 : else
3688 : found = 0
3689 : end if
3690 :
3691 30369864 : if (i2pert <= natom) then
3692 7337334 : ipesy2 = indsym(4,isym,i2pert)
3693 95385342 : sym2(:,:) = symrec(:,:,isym)
3694 23032530 : else if (i2pert == natom + 2) then
3695 2634504 : ipesy2 = i2pert
3696 34248552 : sym2(:,:) = symrel(:,:,isym)
3697 20398026 : else if (i2pert == natom + 3.or. i2pert == natom + 4) then
3698 : !TODO: Symmetries on strain perturbation do not work yet.
3699 : found = 0
3700 : is_strain=.true.
3701 :
3702 : ! ipesy2 = i2pert
3703 : ! sym2(:,:) = NINT(symrel_cart(:,:,isym))
3704 : ! if (i2pert==natom+3) istr=i2dir
3705 : ! if (i2pert==natom+4) istr=3+i2dir
3706 : ! i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
3707 : else
3708 15071142 : found = 0
3709 : end if
3710 :
3711 30369864 : if (i3pert <= natom) then
3712 7457832 : ipesy3 = indsym(4,isym,i3pert)
3713 96951816 : sym3(:,:) = symrec(:,:,isym)
3714 22912032 : else if (i3pert == natom + 2.or.i3pert == natom + 8) then
3715 5142504 : ipesy3 = i3pert
3716 66852552 : sym3(:,:) = symrel(:,:,isym)
3717 : else
3718 : found = 0
3719 : end if
3720 :
3721 30369864 : sumr = 0_dp ; sumi = 0_dp;
3722 30369864 : if (.not.is_strain) then
3723 100171920 : do idisy1 = 1, 3
3724 325558740 : do idisy2 = 1, 3
3725 976676220 : do idisy3 = 1, 3
3726 :
3727 : if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir,idisy2) /=0) &
3728 901547280 : & .and.(sym3(i3dir,idisy3) /=0)) then
3729 :
3730 81492718 : if (blkflg(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 1) then
3731 :
3732 : sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
3733 2909318 : & sym3(i3dir,idisy3)*d3(1,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
3734 : sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
3735 2909318 : & sym3(i3dir,idisy3)*d3(2,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
3736 :
3737 : else
3738 :
3739 : found = 0
3740 :
3741 : end if
3742 :
3743 : end if
3744 :
3745 : end do
3746 : end do
3747 : end do
3748 : else
3749 : ! do idisy1 = 1, 3
3750 : ! !do idisy2_a = 1, 3
3751 : ! ! do idisy2_b = 1, 3
3752 : ! do idisy2 = 1, 3
3753 : ! if (ipesy2==natom+3) istr=idisy2
3754 : ! if (ipesy2==natom+4) istr=3+idisy2
3755 : ! idisy2_a=idx(2*istr-1); idisy2_b=idx(2*istr)
3756 : ! do idisy3 = 1, 3
3757 : !
3758 : ! if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir_a,idisy2_a) /=0) &
3759 : !& .and.(sym2(i2dir_b,idisy2_b) /=0).and.(sym3(i3dir,idisy3) /=0)) then
3760 : !
3761 : ! if (strflg(idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3) == 1) then
3762 : !
3763 : ! sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir_a,idisy2_a)* &
3764 : !& sym2(i2dir_b,idisy2_b)*sym3(i3dir,idisy3)*&
3765 : !& d3str(1,idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3)
3766 : ! sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir_a,idisy2_b)*&
3767 : !& sym2(i2dir_b,idisy2_b)*sym3(i3dir,idisy3)*&
3768 : !& d3str(2,idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3)
3769 : !
3770 : ! else
3771 : !
3772 : ! found = 0
3773 : !
3774 : ! end if
3775 : !
3776 : ! end if
3777 : !
3778 : ! end do
3779 : ! !end do
3780 : ! end do
3781 : ! end do
3782 : end if
3783 :
3784 36156726 : if (found == 1) then
3785 14544 : d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumr
3786 14544 : d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumi
3787 14544 : blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
3788 : end if
3789 :
3790 : end do ! isym
3791 :
3792 : end if ! blkflg
3793 :
3794 : ! Close loop over perturbations
3795 : end do
3796 : end do
3797 : end do
3798 : end do
3799 : end do
3800 : end do
3801 :
3802 : end do ! close loop over ithree
3803 :
3804 17 : end subroutine d3lwsym
3805 : !!***
3806 :
3807 : !!****f* m_dynmat/sylwtens
3808 : !!
3809 : !! NAME
3810 : !! sylwtens
3811 : !!
3812 : !! FUNCTION
3813 : !! Determines the set of irreductible elements of the non-linear
3814 : !! optical susceptibility and Raman tensors
3815 : !!
3816 : !! INPUTS
3817 : !! has_strain = if .true. i2pert includes strain perturbation
3818 : !! indsym(4,nsym,natom)=indirect indexing array described above: for each
3819 : !! isym,iatom, fourth element is label of atom into which iatom is sent by
3820 : !! INVERSE of symmetry operation isym; first three elements are the primitive
3821 : !! translations which must be subtracted after the transformation to get back
3822 : !! to the original unit cell.
3823 : !! mpert =maximum number of ipert
3824 : !! natom= number of atoms
3825 : !! nsym=number of space group symmetries
3826 : !! symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal reduced space)
3827 : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real reduced space)
3828 : !! symrel_cart(3,3,nsym)=3x3 matrices of the group symmetries (real cartesian space)
3829 : !!
3830 : !! OUTPUT
3831 : !! (see side effects)
3832 : !!
3833 : !! SIDE EFFECTS
3834 : !! rfpert(3,mpert,3,mpert,3,mpert) = array defining the type of perturbations
3835 : !! that have to be computed
3836 : !! At the input :
3837 : !! 1 -> element has to be computed explicitly
3838 : !! At the output :
3839 : !! 1 -> element has to be computed explicitly
3840 : !! -1 -> use symmetry operations to obtain the corresponding element
3841 : !! -2 -> element is zero by symmetry
3842 : !!
3843 : !! SOURCE
3844 :
3845 33 : subroutine sylwtens(indsym,mpert,natom,nsym,rfpert,symrec,symrel)
3846 :
3847 : !Arguments -------------------------------
3848 : !scalars
3849 : integer,intent(in) :: mpert,natom,nsym
3850 : !arrays
3851 : integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
3852 : integer,intent(inout) :: rfpert(3,mpert,3,mpert,3,mpert)
3853 : ! real(dp),intent(in) :: symrel_cart(3,3,nsym)
3854 :
3855 : !Local variables -------------------------
3856 : !scalars
3857 : integer :: flag,found,i1dir,i1dir_,i1pert,i1pert_,i2dir,i2dir_,i2pert,i2pert_
3858 : ! integer :: i2dir_a,i2dir_b
3859 : integer :: i3dir,i3dir_,i3pert,i3pert_,idisy1,idisy2,idisy3,ipesy1,ipesy2
3860 : integer :: ipesy3,isym
3861 : ! integer :: istr,idisy2_a,idisy2_b
3862 : logical :: is_strain, is_timdisp
3863 : ! real(dp) :: flag_dp
3864 : !arrays
3865 : ! integer,save :: idx(18)=(/1,1,2,2,3,3,3,2,3,1,2,1,2,3,1,3,1,2/)
3866 : integer :: sym1(3,3),sym2(3,3),sym3(3,3)
3867 33 : integer,allocatable :: pertsy(:,:,:,:,:,:)
3868 : !***********************************************************************
3869 :
3870 231 : ABI_MALLOC(pertsy,(3,mpert,3,mpert,3,mpert))
3871 3406033 : pertsy(:,:,:,:,:,:) = 0
3872 :
3873 : !Loop over perturbations
3874 :
3875 445 : do i1pert_ = 1, mpert
3876 6227 : do i2pert_ = 1, mpert
3877 : is_strain=.false.
3878 98832 : do i3pert_ = 1, mpert
3879 : is_timdisp=.false.
3880 :
3881 376334 : do i1dir_ = 1, 3
3882 1204294 : do i2dir_ = 1, 3
3883 3612882 : do i3dir_ = 1, 3
3884 :
3885 2501226 : i1pert = (mpert - i1pert_ + 1)
3886 2501226 : if (i1pert <= natom) i1pert = natom + 1 - i1pert
3887 2501226 : i2pert = (mpert - i2pert_ + 1)
3888 2501226 : if (i2pert <= natom) i2pert = natom + 1 - i2pert
3889 2501226 : i3pert = (mpert - i3pert_ + 1)
3890 2501226 : if (i3pert <= natom) i3pert = natom + 1 - i3pert
3891 :
3892 2501226 : if (i1pert <= natom) then
3893 : i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
3894 1775250 : else if (i2pert <= natom) then
3895 : i1dir = i2dir_ ; i2dir = i1dir_ ; i3dir = i3dir_
3896 1284606 : else if (i3pert <= natom) then
3897 : i1dir = i3dir_ ; i2dir = i2dir_ ; i3dir = i1dir_
3898 : else
3899 1669194 : i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
3900 : end if
3901 :
3902 3334968 : if (rfpert(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) /= 0) then
3903 :
3904 : ! Loop over all symmetries
3905 :
3906 : flag = 0
3907 131904 : do isym = 1, nsym
3908 :
3909 129012 : found = 1
3910 :
3911 : ! Select the symmetric element of i1pert,i2pert,i3pert
3912 :
3913 129012 : if (i1pert <= natom) then
3914 62218 : ipesy1 = indsym(4,isym,i1pert)
3915 808834 : sym1(:,:) = symrec(:,:,isym)
3916 66794 : else if (i1pert == natom + 2) then
3917 51230 : ipesy1 = i1pert
3918 665990 : sym1(:,:) = symrel(:,:,isym)
3919 : else
3920 : found = 0
3921 : end if
3922 :
3923 129012 : if (i2pert <= natom) then
3924 74302 : ipesy2 = indsym(4,isym,i2pert)
3925 965926 : sym2(:,:) = symrec(:,:,isym)
3926 54710 : else if (i2pert == natom + 2) then
3927 266 : ipesy2 = i2pert
3928 3458 : sym2(:,:) = symrel(:,:,isym)
3929 54444 : else if (i2pert == natom + 3.or. i2pert == natom + 4) then
3930 : ! !TODO: Symmetries on strain perturbation do not work yet.
3931 : found = 0
3932 : is_strain=.true.
3933 : !
3934 : ! ipesy2 = i2pert
3935 : ! sym2(:,:) = NINT(symrel_cart(:,:,isym))
3936 : ! if (i2pert==natom+3) istr=i2dir
3937 : ! if (i2pert==natom+4) istr=3+i2dir
3938 : ! i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
3939 : else
3940 12 : found = 0
3941 : end if
3942 :
3943 129012 : if (i3pert == natom + 8) then
3944 128984 : ipesy3 = i3pert
3945 1676792 : sym3(:,:) = symrel(:,:,isym)
3946 28 : else if (i3pert == natom + 9) then
3947 : is_timdisp=.true.
3948 : found = 0
3949 : else
3950 : found = 0
3951 : end if
3952 :
3953 :
3954 : ! See if the symmetric element is available and check if some
3955 : ! of the elements may be zero. In the latter case, they do not need
3956 : ! to be computed.
3957 :
3958 128984 : if (.not.is_timdisp.and..not.is_strain) then
3959 : if ((flag /= -1).and.&
3960 74552 : & (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
3961 37368 : flag = sym1(i1dir,i1dir)*sym2(i2dir,i2dir)*sym3(i3dir,i3dir)
3962 : end if
3963 :
3964 298208 : do idisy1 = 1, 3
3965 969176 : do idisy2 = 1, 3
3966 2907528 : do idisy3 = 1, 3
3967 :
3968 2012904 : if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir,idisy2) /= 0).and.&
3969 : & (sym3(i3dir,idisy3) /= 0)) then
3970 262548 : if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
3971 2012904 : found = 0
3972 : ! exit ! exit loop over symmetries
3973 : end if
3974 : end if
3975 :
3976 :
3977 2012904 : if ((flag == -1).and.&
3978 670968 : & ((idisy1/=i1dir).or.(idisy2/=i2dir).or.(idisy3/=i3dir))) then
3979 42972 : if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir,idisy2)/=0).and.&
3980 : & (sym3(i3dir,idisy3)/=0)) then
3981 2012904 : flag = 0
3982 : end if
3983 : end if
3984 :
3985 : end do
3986 : end do
3987 : end do
3988 : ! else
3989 : ! if ((flag_dp /= -1).and.&
3990 : !& (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
3991 : ! flag = sym1(i1dir,i1dir)*sym2(i2dir_a,i2dir_a)* &
3992 : ! & sym2(i2dir_b,i2dir_b)*sym3(i3dir,i3dir)
3993 : ! end if
3994 : !
3995 : ! do idisy1 = 1, 3
3996 : ! do idisy2 = 1, 3
3997 : ! if (ipesy2==natom+3) istr=idisy2
3998 : ! if (ipesy2==natom+4) istr=3+idisy2
3999 : ! idisy2_a=idx(2*istr-1); idisy2_b=idx(2*istr)
4000 : ! do idisy3 = 1, 3
4001 : !
4002 : ! if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir_a,idisy2_a) /= 0).and.&
4003 : !& (sym2(i2dir_b,idisy2_b) /= 0).and.(sym3(i3dir,idisy3) /= 0)) then
4004 : ! if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
4005 : ! found = 0
4006 : !! exit ! exit loop over symmetries
4007 : ! end if
4008 : ! end if
4009 : !
4010 : !
4011 : ! if ((flag == -1).and.&
4012 : !& ((idisy1/=i1dir).or.(idisy2_a/=i2dir_a).or.(idisy2_b/=i2dir_b).or.(idisy3/=i3dir))) then
4013 : ! if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir_a,idisy2_a)/=0).and.&
4014 : !& (sym2(i2dir_b,idisy2_b)/=0).and.(sym3(i3dir,idisy3)/=0)) then
4015 : ! flag = 0
4016 : ! end if
4017 : ! end if
4018 : !
4019 : ! end do
4020 : ! end do
4021 : ! end do
4022 : end if
4023 :
4024 129012 : if (found == 1) then
4025 28177 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -1
4026 : end if
4027 :
4028 : ! In case a symmetry operation only changes the sign of an
4029 : ! element, this element has to be equal to zero
4030 :
4031 131904 : if (flag == -1) then
4032 646 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -2
4033 646 : exit
4034 : end if
4035 :
4036 : end do ! close loop on symmetries
4037 :
4038 : ! If the element i1pert,i2pert,i3pert is not symmetric
4039 : ! to a basis element, it is a basis element
4040 :
4041 3538 : if (pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) > -1) then
4042 1551 : pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4043 : end if
4044 :
4045 : end if ! rfpert /= 0
4046 :
4047 : end do ! close loop over perturbations
4048 : end do
4049 : end do
4050 : end do
4051 : end do
4052 : end do
4053 :
4054 : !Now, take into account the permutation of (i1pert,i1dir)
4055 : !and (i2pert,i2dir)
4056 :
4057 :
4058 445 : do i1pert = 1, mpert
4059 6227 : do i2pert = 1, mpert
4060 98832 : do i3pert = 1, mpert
4061 :
4062 376334 : do i1dir = 1, 3
4063 1204294 : do i2dir = 1, 3
4064 3612882 : do i3dir = 1, 3
4065 :
4066 3334968 : if ((i1pert /= i2pert).or.(i1dir /= i2dir)) then
4067 :
4068 2449188 : if ((pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) == 1).and.&
4069 : (pertsy(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) == 1)) then
4070 10 : pertsy(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = -1
4071 : end if
4072 :
4073 : end if
4074 :
4075 : end do
4076 : end do
4077 : end do
4078 :
4079 : end do
4080 : end do
4081 : end do
4082 :
4083 3406033 : rfpert(:,:,:,:,:,:) = pertsy(:,:,:,:,:,:)
4084 :
4085 33 : ABI_FREE(pertsy)
4086 :
4087 33 : end subroutine sylwtens
4088 : !!***
4089 : !!****f* m_geometry/vcart2ylm
4090 : !! NAME
4091 : !! vcart2ylm
4092 : !!
4093 : !! FUNCTION
4094 : !! Convert a 3D Cartesian vector into spherical coordinates (r, theta, phi)
4095 : !! suitable for spherical harmonics calculations (Y_lm).
4096 : !! Angles are returned in degrees.
4097 : !!
4098 : !! INPUTS
4099 : !! vector(3) = Cartesian vector (x, y, z)
4100 : !!
4101 : !! OUTPUTS
4102 : !! length = radial distance r = sqrt(x^2+y^2+z^2)
4103 : !! theta = polar angle (from +z axis), in degrees
4104 : !! phi = azimuthal angle (from +x axis in xy-plane), in degrees
4105 : !!
4106 : !! NOTES
4107 : !! - If the vector magnitude is very small (<1e-9), theta and phi are set to 0.
4108 : !! - Uses the physics/Y_lm convention: theta = polar, phi = azimuth.
4109 : !! - phi is computed using atan2 to account for the correct quadrant.
4110 : !! - This routine assumes input vector is real(8).
4111 : !! - Can be easily extended to arrays of vectors.
4112 :
4113 8928 : subroutine vcart2ylm(vector, length, theta, phi)
4114 :
4115 : !Arguments ---------------------------------------------
4116 : !arrays
4117 : real(8),intent(in) :: vector(3)
4118 : !scalars
4119 : real(8),intent(out) :: length, theta, phi
4120 :
4121 : ! Local
4122 : real(8):: pi
4123 :
4124 8928 : pi=4.0d0*datan(1.0d0)
4125 : ! Compute spherical coordinates
4126 8928 : length = sqrt(vector(1)**2+vector(2)**2+vector(3)**2)
4127 :
4128 8928 : if (length > tol6) then
4129 8374 : theta = acos(vector(3) / length) * 180.d0 / pi
4130 8374 : if (abs(vector(1)) > tol6 .or. abs(vector(2)) > tol6) then
4131 7481 : phi = atan2(vector(2), vector(1)) * 180.d0 / pi
4132 7481 : if (phi<-179) phi=180
4133 : else
4134 893 : phi = 0.d0
4135 : end if
4136 : else
4137 554 : theta = 0.d0
4138 554 : phi = 0.d0
4139 : end if
4140 :
4141 8928 : end subroutine vcart2ylm
4142 : !!***
4143 :
4144 : !!****f* m_geometry/cart2spinaxis
4145 : !! NAME
4146 : !! cart2spinaxis
4147 : !!
4148 : !! FUNCTION
4149 : !! Compute the rotation matrix R = Rz(alpha)*Ry(beta) and rotate a vector in
4150 : !! cartesian coordinate to spinaxis coordinates
4151 : !!
4152 : !! INPUTS
4153 : !! alpha=Euler angle for rotation around z-axis
4154 : !! beta=Euler angle for rotation around y-axis
4155 : !! vin(3)=vector in the cartesian coordinate
4156 : !!
4157 : !! OUTPUT
4158 : !! R(3,3)=rotation matrix from cartesian to spinaxis coordinates
4159 : !! vout(3)=vector in spinaxis coordinate
4160 : !!
4161 : !! SOURCE
4162 :
4163 2 : subroutine cart2spinaxis(alpha, beta, R, vin, vout)
4164 :
4165 : !Arguments -------------------------------
4166 : !scalars
4167 : real(dp),intent(in) :: alpha, beta
4168 : !arrays
4169 : real(dp),intent(out) :: R(3,3)
4170 : real(dp),optional,intent(in) :: vin(3)
4171 : real(dp),optional,intent(out) :: vout(3)
4172 :
4173 : !Local variables -------------------------
4174 : !scalars
4175 : real(dp) :: sb, cb, sa, ca
4176 : !***********************************************************************
4177 :
4178 2 : sb = sin(beta); cb = cos(beta)
4179 2 : sa = sin(alpha); ca = cos(alpha)
4180 :
4181 2 : R(1,1) = cb*ca; R(2,1) = -sa; R(3,1) = sb*ca
4182 2 : R(1,2) = cb*sa; R(2,2) = ca; R(3,2) = sb*sa
4183 2 : R(1,3) = -sb; R(2,3) = zero; R(3,3) = cb
4184 :
4185 2 : if (present(vin) .and. present(vout)) then
4186 0 : vout(:) = matmul(R, vin)
4187 : end if
4188 :
4189 2 : end subroutine cart2spinaxis
4190 : !!***
4191 :
4192 903 : end module m_geometry
4193 : !!***
|