Line data Source code
1 : !!****m* ABINIT/m_strain
2 : !!
3 : !! NAME
4 : !! m_strain
5 : !!
6 : !! FUNCTION
7 : !! Module for get the strain
8 : !! Container type is defined
9 : !!
10 : !! COPYRIGHT
11 : !! Copyright (C) 2010-2026 ABINIT group (AM)
12 : !! This file is distributed under the terms of the
13 : !! GNU General Public Licence, see ~abinit/COPYING
14 : !! or http://www.gnu.org/copyleft/gpl.txt .
15 : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
16 : !!
17 : !! SOURCE
18 :
19 : #if defined HAVE_CONFIG_H
20 : #include "config.h"
21 : #endif
22 :
23 : #include "abi_common.h"
24 :
25 : module m_strain
26 :
27 : use defs_basis
28 : use m_errors
29 : use m_abicore
30 : use m_xmpi
31 :
32 : use m_matrix, only : matr3inv
33 :
34 : implicit none
35 :
36 : private :: strain_def2strain
37 : private :: strain_strain2def
38 : public :: strain_print
39 : public :: strain_get
40 : public :: strain_init
41 : public :: strain_apply
42 : !!***
43 :
44 : !!****t* m_strain/strain_type
45 : !! NAME
46 : !! strain_type
47 : !!
48 : !! FUNCTION
49 : !! structure for a effective potential constructed.
50 : !!
51 : !! SOURCE
52 :
53 : type, public :: strain_type
54 : character(len=fnlen) :: name
55 : ! name of the strain (iso,uniaxial,shear...)
56 :
57 : real(dp) :: delta
58 : ! Value of the strain
59 :
60 : integer :: direction
61 : ! Direction of the strain (-1 if isostatic)
62 :
63 : real(dp) :: strain(3,3)
64 : ! Matrix representing the strain
65 :
66 : end type strain_type
67 : !!***
68 :
69 : CONTAINS !===========================================================================================
70 :
71 : !****f* m_strain/strain_init
72 : !!
73 : !! NAME
74 : !! strain_init
75 : !!
76 : !! FUNCTION
77 : !! routine to initialize strain structure
78 : !!
79 : !!
80 : !! INPUTS
81 : !! name = name of the perturbation
82 : !! direction = direction of the perturbation
83 : !! delta = delta to apply in the strain (in percent)
84 : !!
85 : !! OUTPUT
86 : !! strain = structure with all information of strain
87 : !!
88 : !! SOURCE
89 :
90 0 : subroutine strain_init(strain,delta,direction,name)
91 :
92 : !Arguments ------------------------------------
93 : !scalars
94 : character(len=fnlen),optional,intent(in) :: name
95 : real(dp),optional,intent(in) :: delta
96 : integer,optional,intent(in) :: direction
97 : !array
98 : type(strain_type),intent(out) :: strain
99 : !Local variables-------------------------------
100 : !scalar
101 : !arrays
102 : ! *************************************************************************
103 0 : if (present(name)) then
104 0 : strain%name = name
105 : else
106 0 : strain%name = ''
107 : end if
108 :
109 0 : if (present(delta)) then
110 0 : strain%delta = delta
111 : else
112 0 : strain%delta = zero
113 : end if
114 :
115 0 : if (present(direction)) then
116 0 : strain%direction = direction
117 : else
118 0 : strain%direction = 0
119 : end if
120 :
121 0 : call strain_strain2def(strain%strain,strain)
122 :
123 0 : end subroutine strain_init
124 : !!***
125 :
126 : !****f* m_strain/strain_free
127 : !!
128 : !! NAME
129 : !! strain_free
130 : !!
131 : !! FUNCTION
132 : !! routine to free strain structure
133 : !!
134 : !!
135 : !! INPUTS
136 : !! strain = structure with all information of strain
137 : !!
138 : !! OUTPUT
139 : !!
140 : !! SOURCE
141 :
142 0 : subroutine strain_free(strain)
143 :
144 : !Arguments ------------------------------------
145 : !scalars
146 : !array
147 : type(strain_type),intent(inout) :: strain
148 :
149 : !Local variables-------------------------------
150 : !scalar
151 : !arrays
152 : ! *************************************************************************
153 :
154 0 : strain%name = ''
155 0 : strain%delta = zero
156 0 : strain%direction = 0
157 0 : strain%strain = zero
158 :
159 0 : end subroutine strain_free
160 : !!***
161 :
162 :
163 : !****f* m_strain/strain_get
164 : !!
165 : !! NAME
166 : !! strain_get
167 : !!
168 : !! FUNCTION
169 : !! Get the strain for structure, compare to reference
170 : !! structure and fill strain type
171 : !!
172 : !!
173 : !! INPUTS
174 : !! symmetrized = (optional) symmetrize the output
175 : !!
176 : !! OUTPUT
177 : !! strain = structure with all information of strain
178 : !!
179 : !! SOURCE
180 :
181 27999 : subroutine strain_get(strain,rprim,rprim_def,mat_delta,symmetrized)
182 :
183 : !Arguments ------------------------------------
184 : !scalars
185 : !array
186 : type(strain_type),intent(inout) :: strain
187 : real(dp),optional,intent(in) :: rprim(3,3),rprim_def(3,3), mat_delta(3,3)
188 : logical,optional,intent(in) :: symmetrized
189 : !Local variables-------------------------------
190 : !scalar
191 : integer :: i,j
192 : logical :: symmetrized_in
193 : character(len=500) :: message
194 : !arrays
195 : real(dp) :: mat_delta_tmp(3,3),rprim_inv(3,3)
196 : real(dp) :: identity(3,3)
197 : ! *************************************************************************
198 :
199 : !check inputs
200 27999 : symmetrized_in = .FALSE.
201 27999 : if(present(symmetrized)) then
202 13519 : symmetrized_in = symmetrized
203 : end if
204 :
205 27999 : if((present(rprim_def).and..not.present(rprim)).or.&
206 27999 : & (present(rprim).and..not.present(rprim_def))) then
207 : write(message, '(a)' )&
208 0 : & ' strain_get: should give rprim_def and rprim as input of the routines'
209 0 : ABI_BUG(message)
210 : end if
211 :
212 27999 : if(present(rprim_def).and.present(rprim))then
213 : mat_delta_tmp = zero
214 : ! Fill the identity matrix
215 27038 : identity = zero
216 108152 : forall(i=1:3)identity(i,i)=1
217 :
218 27038 : call matr3inv(rprim,rprim_inv)
219 1433014 : mat_delta_tmp = matmul(rprim_def,transpose(rprim_inv))-identity
220 27038 : identity = zero
221 108152 : do i=1,3
222 351494 : do j=1,3
223 324456 : if (abs(mat_delta_tmp(i,j))>tol10) then
224 76532 : identity(i,j) = mat_delta_tmp(i,j)
225 : end if
226 : end do
227 : end do
228 :
229 27038 : mat_delta_tmp = identity
230 :
231 961 : else if (present(mat_delta)) then
232 961 : mat_delta_tmp = mat_delta
233 :
234 : else
235 : write(message, '(a)' )&
236 0 : & ' strain_get: should give rprim_def or mat_delta as input of the routines'
237 0 : ABI_BUG(message)
238 : end if
239 :
240 27999 : if(symmetrized_in)then
241 0 : mat_delta_tmp(2,3) = (mat_delta_tmp(2,3) + mat_delta_tmp(3,2)) / 2
242 0 : mat_delta_tmp(3,1) = (mat_delta_tmp(3,1) + mat_delta_tmp(1,3)) / 2
243 0 : mat_delta_tmp(2,1) = (mat_delta_tmp(2,1) + mat_delta_tmp(1,2)) / 2
244 :
245 0 : mat_delta_tmp(3,2) = mat_delta_tmp(2,3)
246 0 : mat_delta_tmp(1,3) = mat_delta_tmp(3,1)
247 0 : mat_delta_tmp(1,2) = mat_delta_tmp(2,1)
248 :
249 : end if
250 :
251 27999 : call strain_def2strain(mat_delta_tmp,strain)
252 :
253 27999 : end subroutine strain_get
254 : !!***
255 :
256 : !****f* m_strain/strain_apply
257 : !!
258 : !! NAME
259 : !! strain_get
260 : !!
261 : !! FUNCTION
262 : !! Get the strain for structure, compare to reference
263 : !! structure and fill strain type
264 : !!
265 : !!
266 : !! INPUTS
267 : !!
268 : !! OUTPUT
269 : !! strain = structure with all information of strain
270 : !!
271 : !! SOURCE
272 :
273 0 : subroutine strain_apply(rprim,rprim_def,strain)
274 :
275 : !Arguments ------------------------------------
276 : !scalars
277 : !array
278 : real(dp),intent(in) :: rprim(3,3)
279 : real(dp),intent(out) :: rprim_def(3,3)
280 : type(strain_type),intent(in) :: strain
281 : !Local variables-------------------------------
282 : !scalar
283 : !integer :: i
284 : !arrays
285 : ! *************************************************************************
286 :
287 0 : rprim_def(:,:) = zero
288 : ! Fill the identity matrix
289 0 : rprim_def(:,:) = matmul(strain%strain(:,:),transpose(rprim(:,:)))
290 :
291 0 : end subroutine strain_apply
292 : !!***
293 :
294 : !****f* m_strain/strain_def2strain
295 : !!
296 : !! NAME
297 : !! strain_matdef2strain
298 : !!
299 : !! FUNCTION
300 : !! transfer deformation matrix in structure strain
301 : !!
302 : !! INPUTS
303 : !! rprim = contains
304 : !!
305 : !! OUTPUT
306 : !!
307 : !!
308 : !! SOURCE
309 :
310 27999 : subroutine strain_def2strain(mat_strain,strain)
311 :
312 : !Arguments ------------------------------------
313 : !scalars
314 : !array
315 : real(dp),intent(in) :: mat_strain(3,3)
316 : type(strain_type),intent(inout) :: strain
317 : !Local variables-------------------------------
318 : !scalar
319 : !arrays
320 : ! *************************************************************************
321 27999 : strain%name = ""
322 27999 : strain%delta = zero
323 27999 : strain%direction = 0
324 363987 : strain%strain = mat_strain
325 :
326 241167 : if (all(abs(mat_strain)<tol10)) then
327 17764 : strain%name = "reference"
328 : strain%delta = zero
329 : strain%direction = 0
330 230932 : strain%strain = zero
331 : else
332 : if(abs(mat_strain(1,1))>tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))<tol10.and.&
333 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))>tol10.and.abs(mat_strain(2,3))<tol10.and.&
334 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))>tol10) then
335 1321 : if((mat_strain(1,1)-mat_strain(2,2))< tol10.and.&
336 : & (mat_strain(1,1)-mat_strain(3,3))< tol10) then
337 1321 : strain%name = "isostatic"
338 1321 : strain%delta = mat_strain(1,1)
339 1321 : strain%direction = -1
340 17173 : strain%strain = mat_strain
341 : end if
342 : end if
343 : if(abs(mat_strain(1,1))>tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))<tol10.and.&
344 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))<tol10.and.abs(mat_strain(2,3))<tol10.and.&
345 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))<tol10) then
346 0 : strain%name = "uniaxial"
347 0 : strain%delta = mat_strain(1,1)
348 0 : strain%direction = 1
349 0 : strain%strain = mat_strain
350 : end if
351 : if(abs(mat_strain(1,1))<tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))<tol10.and.&
352 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))>tol10.and.abs(mat_strain(2,3))<tol10.and.&
353 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))<tol10) then
354 0 : strain%name = "uniaxial"
355 0 : strain%delta = mat_strain(2,2)
356 0 : strain%direction = 2
357 0 : strain%strain = mat_strain
358 : end if
359 : if(abs(mat_strain(1,1))<tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))<tol10.and.&
360 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))<tol10.and.abs(mat_strain(2,3))<tol10.and.&
361 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))>tol10) then
362 0 : strain%name = "uniaxial"
363 0 : strain%delta = mat_strain(3,3)
364 0 : strain%direction = 3
365 0 : strain%strain = mat_strain
366 : end if
367 : if(abs(mat_strain(1,1))<tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))<tol10.and.&
368 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))<tol10.and.abs(mat_strain(2,3))>tol10.and.&
369 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))>tol10.and.abs(mat_strain(3,3))<tol10) then
370 0 : if (abs(mat_strain(3,2)-mat_strain(3,2))<tol10) then
371 0 : strain%name = "shear"
372 0 : strain%delta = mat_strain(3,2) * 2
373 0 : strain%direction = 4
374 0 : strain%strain = mat_strain
375 : end if
376 : end if
377 : if(abs(mat_strain(1,1))<tol10.and.abs(mat_strain(1,2))<tol10.and.abs(mat_strain(1,3))>tol10.and.&
378 : & abs(mat_strain(2,1))<tol10.and.abs(mat_strain(2,2))<tol10.and.abs(mat_strain(2,3))<tol10.and.&
379 10235 : & abs(mat_strain(3,1))>tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))<tol10) then
380 0 : if (abs(mat_strain(3,1)-mat_strain(1,3))<tol10) then
381 0 : strain%name = "shear"
382 0 : strain%delta = mat_strain(3,1) * 2
383 0 : strain%direction = 5
384 0 : strain%strain = mat_strain
385 : end if
386 : end if
387 : if(abs(mat_strain(1,1))<tol10.and.abs(mat_strain(1,2))>tol10.and.abs(mat_strain(1,3))<tol10.and.&
388 : & abs(mat_strain(2,1))>tol10.and.abs(mat_strain(2,2))<tol10.and.abs(mat_strain(2,3))<tol10.and.&
389 10235 : & abs(mat_strain(3,1))<tol10.and.abs(mat_strain(3,2))<tol10.and.abs(mat_strain(3,3))<tol10) then
390 0 : if (abs(mat_strain(1,2)-mat_strain(2,1))<tol10) then
391 0 : strain%name = "shear"
392 0 : strain%delta = mat_strain(2,1) * 2
393 0 : strain%direction = 6
394 0 : strain%strain = mat_strain
395 : end if
396 : end if
397 : end if
398 :
399 27999 : end subroutine strain_def2strain
400 : !!***
401 :
402 : !****f* m_strain/strain_strain2def
403 : !!
404 : !! NAME
405 : !! strain_matdef2strain
406 : !!
407 : !! FUNCTION
408 : !! transfer deformation matrix in structure strain
409 : !!
410 : !! INPUTS
411 : !! rprim = contains
412 : !!
413 : !! OUTPUT
414 : !!
415 : !!
416 : !! SOURCE
417 :
418 0 : subroutine strain_strain2def(mat_strain,strain)
419 :
420 : !Arguments ------------------------------------
421 : !scalars
422 : !array
423 : real(dp),intent(out) :: mat_strain(3,3)
424 : type(strain_type),intent(in) :: strain
425 : !Local variables-------------------------------
426 : !scalar
427 : integer :: i
428 : !arrays
429 : ! *************************************************************************
430 :
431 0 : mat_strain(:,:) = zero
432 0 : forall(i=1:3)mat_strain(i,i)=1
433 :
434 0 : select case(strain%direction)
435 : case(1)
436 0 : mat_strain(1,1) = mat_strain(1,1) + strain%delta
437 : case(2)
438 0 : mat_strain(2,2) = mat_strain(2,2) + strain%delta
439 : case(3)
440 0 : mat_strain(3,3) = mat_strain(3,3) + strain%delta
441 : case(4)
442 0 : mat_strain(3,2) = strain%delta / 2
443 0 : mat_strain(2,3) = strain%delta / 2
444 : case(5)
445 0 : mat_strain(3,1) = strain%delta / 2
446 0 : mat_strain(1,3) = strain%delta / 2
447 : case(6)
448 0 : mat_strain(2,1) = strain%delta / 2
449 0 : mat_strain(1,2) = strain%delta / 2
450 : end select
451 :
452 0 : end subroutine strain_strain2def
453 : !!***
454 :
455 : !****f* m_strain/strain_print
456 : !!
457 : !! NAME
458 : !! strain_print
459 : !!
460 : !! FUNCTION
461 : !! print the structure strain
462 : !!
463 : !! INPUTS
464 : !!
465 : !! OUTPUT
466 : !! eff_pot = supercell structure with data to be output
467 : !!
468 : !! SOURCE
469 :
470 2056 : subroutine strain_print(strain)
471 :
472 : !Arguments ------------------------------------
473 : !scalars
474 : !array
475 : type(strain_type),intent(in) :: strain
476 : !Local variables-------------------------------
477 : !scalar
478 : integer :: ii
479 : character(len=500) :: message
480 : !arrays
481 : ! *************************************************************************
482 :
483 2056 : if(strain%name == "reference") then
484 1081 : write(message,'(4a)') ch10,' no strain found:',&
485 2162 : & ' This structure is equivalent to the reference structure',ch10
486 1081 : call wrtout(std_out,message,'COLL')
487 : else
488 975 : if(strain%name /= "") then
489 : write(message,'(3a,I2,a,(ES10.2),a)') &
490 20 : & ' The strain is ',trim(strain%name),' type in the direction ',&
491 40 : & strain%direction,' with delta of ',strain%delta, ':'
492 20 : call wrtout(std_out,message,'COLL')
493 20 : call wrtout(ab_out,message,'COLL')
494 80 : do ii = 1,3
495 60 : write(message,'(3es17.8)') strain%strain(ii,1),strain%strain(ii,2),strain%strain(ii,3)
496 80 : call wrtout(std_out,message,'COLL')
497 : end do
498 : else
499 955 : write(message,'(a)') ' Strain does not correspond to standard strain:'
500 955 : call wrtout(std_out,message,'COLL')
501 3820 : do ii = 1,3
502 2865 : write(message,'(3es17.8)') strain%strain(ii,1),strain%strain(ii,2),strain%strain(ii,3)
503 3820 : call wrtout(std_out,message,'COLL')
504 : end do
505 : end if
506 : end if
507 2056 : end subroutine strain_print
508 : !!***
509 :
510 0 : end module m_strain
511 :
|