Line data Source code
1 : !!****m* ABINIT/m_ddb_piezo
2 : !! NAME
3 : !! m_ddb_piezo
4 : !!
5 : !! FUNCTION
6 : !!
7 : !! COPYRIGHT
8 : !! Copyright (C) 1999-2026 ABINIT group (XW)
9 : !! This file is distributed under the terms of the
10 : !! GNU General Public License, see ~abinit/COPYING
11 : !! or http://www.gnu.org/copyleft/gpl.txt .
12 : !!
13 : !! SOURCE
14 :
15 : #if defined HAVE_CONFIG_H
16 : #include "config.h"
17 : #endif
18 :
19 : #include "abi_common.h"
20 :
21 : module m_ddb_piezo
22 :
23 : use defs_basis
24 : use m_abicore
25 : use m_errors
26 : use m_nctk
27 : use netcdf
28 :
29 : use m_fstrings, only : sjoin, itoa
30 : use m_hide_lapack, only : matrginv
31 : use m_anaddb_dataset, only : anaddb_dataset_type
32 :
33 : implicit none
34 :
35 : private
36 : !!***
37 :
38 : public :: ddb_piezo
39 : !!***
40 :
41 : contains
42 : !!***
43 :
44 : !!****f* ABINIT/ddb_piezo
45 : !!
46 : !! NAME
47 : !! ddb_piezo
48 : !!
49 : !! FUNCTION
50 : !! Get the piezoelectric tensor (e-tensor), both clamped ion and relaxed ion;
51 : !! Compute physical(relaxed ion) piezoeletric (d, g, h) tensors;
52 : !! Compute relaxed ion and free stress dielectric tensor;
53 : !! Compute relaxed ion elastic and compliance tensors under fixed
54 : !! displacement field boundary conditions.
55 : !!
56 : !! INPUTS
57 : !! inp= (derived datatype) contains all the input variables
58 : !! blkval(2,3,mpert,3,mpert,nblok)=
59 : !! second derivatives of total energy with respect to electric fields
60 : !! atom displacements,strain,...... all in cartesian coordinates
61 : !! dielt_rlx=relaxed ion dielectric tensor
62 : !! iblok= bolk number in DDB file contains 2 derivative of energy
63 : !! instrain=force response internal strain tensor
64 : !! iout=out file number
65 : !! mpert=maximum number of ipert
66 : !! natom=number of atoms in unit cell
67 : !! nblok=number of total bloks in DDB file
68 : !! ucvol=unit cell volume
69 : !! ncid=the id of the open NetCDF file. Set to nctk_noid if netcdf output is not wanted.
70 : !!
71 : !! OUTPUT
72 : !! piezo = piezoelectric tensor
73 : !!
74 : !! NOTES
75 : !! The elastic (compliance) tensors calculated here are under fixed D-field boundary
76 : !! condition, which include piezoelectric corrections to the elastic (compliance)
77 : !! tensors calculated in ddb_elast.F90 whose boundary condition is fixed E-field.
78 : !!
79 : !! SOURCE
80 :
81 5 : subroutine ddb_piezo(inp,blkval,dielt_rlx,elast,iblok,instrain,iout,mpert,natom,nblok,piezo,ucvol,ncid)
82 :
83 : !Arguments-------------------------------------------
84 : !scalars
85 : integer,intent(in) :: iblok,iout,mpert,natom,nblok,ncid
86 : real(dp),intent(in) :: ucvol
87 : type(anaddb_dataset_type),intent(in) :: inp
88 : !arrays
89 : real(dp),intent(in) :: blkval(2,3,mpert,3,mpert,nblok),dielt_rlx(3,3)
90 : real(dp),intent(in) :: elast(6,6),instrain(3*natom,6)
91 : real(dp),intent(out) :: piezo(6,3)
92 :
93 : !Local variables---------------------------------------
94 : !scalars
95 : integer :: idir1,idir2,ier,ii1,ii2,ipert1,ipert2,ivarA,ivarB,ncerr
96 : character(len=500) :: message
97 : logical :: iwrite
98 : !arrays
99 10 : real(dp) :: Amatr(3*natom-3,3*natom-3),Apmatr(3*natom,3*natom)
100 10 : real(dp) :: Bmatr(2,((3*natom-3)*(3*natom-2))/2)
101 10 : real(dp) :: Bpmatr(2,(3*natom*(3*natom+1))/2),Cmatr(3*natom-3,3*natom-3)
102 10 : real(dp) :: Cpmatr(3*natom,3*natom),Nmatr(3*natom,3*natom),beta_tensor(3,3)
103 : real(dp) :: compliance(6,6),compliance_dis(6,6)
104 10 : real(dp) :: d2cart_relaxed(2,3,mpert,3,mpert,nblok),d_tensor(6,3)
105 10 : real(dp) :: dielt_stress(3,3),eigval(3*natom-3),eigvalp(3*natom)
106 10 : real(dp) :: eigvec(2,3*natom-3,3*natom-3),eigvecp(2,3*natom,3*natom)
107 : real(dp) :: elast_dis(6,6),g_tensor(3,6),h_tensor(3,6)
108 10 : real(dp) :: kmatrix(3*natom,3*natom),new1(6,3*natom),piezo_clamped(6,3)
109 10 : real(dp) :: piezo_correction(6,3),piezo_relaxed(6,3),zhpev1(2,2*3*natom-4)
110 10 : real(dp) :: zhpev1p(2,2*3*natom-1),zhpev2(3*3*natom-5),zhpev2p(3*3*natom-2)
111 10 : real(dp) :: zstar1(3,3*natom),zstar2(3*natom,3)
112 :
113 : !****************************************************************
114 :
115 : !extraction of the clamped ion piezoelectric constants from blkvals
116 5 : iwrite = iout > 0
117 :
118 : !the six strain perturbations
119 35 : do ivarA=1,6
120 : ! the three E-field perturbations
121 125 : do ivarB=1,3
122 : ! judge if the ivarA>3 or not
123 90 : if(ivarA>3) then
124 45 : idir1=ivarA-3
125 45 : ipert1=natom+4
126 : ! for the shear part of the strain
127 : else if(ivarA<=3) then
128 45 : idir1=ivarA
129 45 : ipert1=natom+3
130 : ! for the diagonal part of strain
131 : end if
132 90 : idir2=ivarB
133 90 : ipert2=natom+2 !for the E-field perturbation only
134 120 : piezo(ivarA,ivarB)=blkval(1,idir2,ipert2,idir1,ipert1,iblok)
135 : end do
136 : end do
137 :
138 : !consider the volume and the -Qe before the piezo
139 : !according to the (30) in notes, the units are tranformed from atomic units to the SI units
140 35 : do ivarA=1,6
141 125 : do ivarB=1,3
142 120 : piezo(ivarA,ivarB)=piezo(ivarA,ivarB)*AmuBohr2_Cm2
143 : ! now it is in the SI unit
144 : end do
145 : end do
146 :
147 : !give the values of d2cart_relaxed as the same as blkval
148 : !and also give the initial values of piezo_clamped and piezo_relaxed
149 25911 : d2cart_relaxed(:,:,:,:,:,:)=blkval(:,:,:,:,:,:)
150 5 : piezo_clamped(:,:)=piezo(:,:)
151 :
152 : !********************************************************************
153 : !print the main results of the piezoelectric constants
154 5 : if(inp%piezoflag==1.or.inp%piezoflag==3 .or. inp%piezoflag==7)then
155 5 : write(message,'(3a)')ch10,' Proper piezoelectric constants (clamped ion) (unit:c/m^2)',ch10
156 5 : call wrtout(std_out,message,'COLL')
157 :
158 35 : do ivarA=1,6
159 35 : write(std_out,'(3f16.8)')piezo_clamped(ivarA,1),piezo_clamped(ivarA,2),piezo_clamped(ivarA,3)
160 : end do
161 :
162 5 : call wrtout(iout,message,'COLL')
163 5 : if (iwrite) then
164 35 : do ivarA=1,6
165 35 : write(iout,'(3f16.8)')piezo_clamped(ivarA,1),piezo_clamped(ivarA,2),piezo_clamped(ivarA,3)
166 : end do
167 : end if
168 : end if
169 :
170 : !the next is the calculation of the relaxed ion piezoelectric constants
171 : !first extract the K(force constant) matrix
172 :
173 : !if (piezoflag==2 .or. inp%piezoflag==3)then
174 : !extracting force matrix at gamma
175 19 : do ipert1=1,natom
176 61 : do ii1=1,3
177 42 : ivarA=ii1+3*(ipert1-1)
178 188 : do ipert2=1,natom
179 570 : do ii2=1,3
180 396 : ivarB=ii2+3*(ipert2-1)
181 528 : kmatrix(ivarA,ivarB)=blkval(1,ii1,ipert1,ii2,ipert2,iblok)
182 : end do
183 : end do
184 : end do
185 : end do
186 :
187 443 : Apmatr(:,:)=kmatrix(:,:)
188 :
189 : !DEBUG
190 : !kmatrix values
191 : !write(std_out,'(/,a,/)')'the force constant matrix'
192 : !do ivarA=1,3*natom
193 : !write(std_out,'(/)')
194 : !do ivarB=1,3*natom
195 : !write(std_out,'(es16.6)')kmatrix(ivarB,ivarA)
196 : !end do
197 : !end do
198 : !ENDDEBUG
199 :
200 443 : Nmatr(:,:)=zero
201 :
202 47 : do ivarA=1,3*natom
203 443 : do ivarB=1,3*natom
204 396 : if (mod(ivarA,3)==0 .and. mod(ivarB,3)==0) Nmatr(ivarA,ivarB)=one
205 396 : if (mod(ivarA,3)==1 .and. mod(ivarB,3)==1) Nmatr(ivarA,ivarB)=one
206 438 : if (mod(ivarA,3)==2 .and. mod(ivarB,3)==2) Nmatr(ivarA,ivarB)=one
207 : end do
208 : end do
209 :
210 : !DEBUG
211 : !do ivarA=1,3*natom
212 : !write(std_out,'(/)')
213 : !do ivarB=1,3*natom
214 : !write(std_out,'(es16.6)')Nmatr(ivarB,ivarA)
215 : !end do
216 : !end do
217 : !ENDDEBUG
218 :
219 : !starting the pseudoinversing processes
220 : !then get the eigenvectors of the big matrix,give values to matrixBp
221 : ii1=1
222 47 : do ivarA=1,3*natom
223 266 : do ivarB=1,ivarA
224 219 : Bpmatr(1,ii1)=Nmatr(ivarB,ivarA)
225 261 : ii1=ii1+1
226 : end do
227 : end do
228 :
229 : !the imaginary part of the force matrix
230 224 : Bpmatr(2,:)=zero
231 : !then call the subroutines CHPEV and ZHPEV to get the eigenvectors
232 5 : call ZHPEV ('V','U',3*natom,Bpmatr,eigvalp,eigvecp,3*natom,zhpev1p,zhpev2p,ier)
233 5 : ABI_CHECK(ier == 0, sjoin("ZHPEV returned:", itoa(ier)))
234 :
235 : !DEBUG
236 : !the eigenval and eigenvec
237 : !write(std_out,'(/,a,/)')'the eigenvalues and eigenvectors'
238 : !do ivarA=1,3*natom
239 : !write(std_out,'(/)')
240 : !write(std_out,'(es16.6)')eigvalp(ivarA)
241 : !end do
242 : !do ivarA=1,3*natom
243 : !write(std_out,'(/)')
244 : !do ivarB=1,3*natom
245 : !write(std_out,'(es16.6)')eigvecp(1,ivarB,ivarA)
246 : !end do
247 : !end do
248 : !ENDDEBUG
249 :
250 : !then do the muplication to get the reduced matrix,in two steps
251 : !After this the force constant matrix is decouple in two bloks,
252 : !accoustic and optical ones
253 443 : Cpmatr(:,:)=zero
254 47 : do ivarA=1,3*natom
255 443 : do ivarB=1,3*natom
256 4542 : do ii1=1,3*natom
257 : Cpmatr(ivarA,ivarB)=Cpmatr(ivarA,ivarB)+eigvecp(1,ii1,ivarA)*&
258 4500 : & Apmatr(ii1,ivarB)
259 : end do
260 : end do
261 : end do
262 :
263 443 : Apmatr(:,:)=zero
264 47 : do ivarA=1,3*natom
265 443 : do ivarB=1,3*natom
266 4542 : do ii1=1,3*natom
267 : Apmatr(ivarA,ivarB)=Apmatr(ivarA,ivarB)+Cpmatr(ivarA,ii1)*&
268 4500 : & eigvecp(1,ii1,ivarB)
269 : end do
270 : end do
271 : end do
272 :
273 : !DEBUG
274 : !the blok diago
275 : !write(std_out,'(/,a,/)')'Apmatr'
276 : !do ivarA=1,3*natom
277 : !write(std_out,'(/)')
278 : !do ivarB=1,3*natom
279 : !write(std_out,'(es16.6)')Apmatr(ivarA,ivarB)
280 : !end do
281 : !end do
282 : !ENDDEBUG
283 :
284 : !check the last three eigenvalues whether too large or not
285 : ivarB=0
286 20 : do ivarA=3*natom-2,3*natom
287 20 : if (ABS(Apmatr(ivarA,ivarA))>tol6) ivarB=1
288 : end do
289 5 : if(ivarB==1)then
290 4 : write(message,'(a,a,a,a,a,a,a,a,a,a,3es16.6)')ch10,&
291 4 : & ' ddb_piezo : WARNING -',ch10,&
292 4 : & ' Acoustic sum rule violation met : the eigenvalues of accoustic mode',ch10,&
293 4 : & ' are too large at Gamma point',ch10,&
294 4 : & ' Increase cutoff energy or k-points sampling.',ch10,&
295 8 : & ' The three eigenvalues are:',Apmatr(3*natom-2,3*natom-2),Apmatr(3*natom-1,natom-1),Apmatr(3*natom,3*natom)
296 4 : call wrtout(std_out, message, 'COLL')
297 4 : call wrtout(iout,message,'COLL')
298 : end if
299 :
300 : !give the value of reduced matrix form Apmatr to Amatr
301 32 : do ivarA=1,3*natom-3
302 221 : do ivarB=1,3*natom-3
303 216 : Amatr(ivarA,ivarB)=Apmatr(ivarA,ivarB)
304 : end do
305 : end do
306 : !now the reduced matrix is in the matrixA, the convert it
307 : !first give the give the value of matixB from matrixA
308 : ii1=1
309 32 : do ivarA=1,3*natom-3
310 140 : do ivarB=1,ivarA
311 108 : Bmatr(1,ii1)=Amatr(ivarB,ivarA)
312 135 : ii1=ii1+1
313 : end do
314 : end do
315 113 : Bmatr(2,:)=zero
316 :
317 : !call the subroutines CHPEV and ZHPEV to get the eigenvectors and the eigenvalues
318 5 : call ZHPEV ('V','U',3*natom-3,Bmatr,eigval,eigvec,3*natom-3,zhpev1,zhpev2,ier)
319 5 : ABI_CHECK(ier == 0, sjoin("ZHPEV returned:", itoa(ier)))
320 :
321 : !check the unstable phonon modes, if the first is negative then print warning message
322 5 : if(eigval(1)<-1.0*tol8)then
323 0 : write(message,'(a,a,a,a,a,a)') ch10,&
324 0 : & ' ddb_piezo : WARNING -',ch10,&
325 0 : & ' Unstable eigenvalue detected in force constant matrix at Gamma point',ch10,&
326 0 : & ' The system under calculation is physically unstable.'
327 0 : call wrtout(std_out, message, 'COLL')
328 0 : call wrtout(iout,message,'COLL')
329 : end if
330 :
331 : !do the matrix multiplication to get pseudoinverse inverse matrix
332 221 : Cmatr(:,:)=zero
333 221 : Amatr(:,:)=zero
334 32 : do ivarA=1,3*natom-3
335 32 : Cmatr(ivarA,ivarA)=one/eigval(ivarA)
336 : end do
337 :
338 32 : do ivarA=1,3*natom-3
339 221 : do ivarB=1,3*natom-3
340 1755 : do ii1=1,3*natom-3
341 : Amatr(ivarA,ivarB)=Amatr(ivarA,ivarB)+eigvec(1,ivarA,ii1)*&
342 1728 : & Cmatr(ii1,ivarB)
343 : end do
344 : end do
345 : end do
346 :
347 : !the second mulplication
348 221 : Cmatr(:,:)=zero
349 32 : do ivarA=1,3*natom-3
350 221 : do ivarB=1,3*natom-3
351 1755 : do ii1=1,3*natom-3
352 : Cmatr(ivarA,ivarB)=Cmatr(ivarA,ivarB)+&
353 1728 : & Amatr(ivarA,ii1)*eigvec(1,ivarB,ii1)
354 : end do
355 : end do
356 : end do
357 :
358 : !DEBUG
359 : !write(std_out,'(/,a,/)')'the pseudo inverse of the force matrix'
360 : !do ivarA=1,3*natom
361 : !write(std_out,'(/)')
362 : !do ivarB=1,3*natom
363 : !write(std_out,'(es16.6)')Cmatr(ivarA,ivarB)
364 : !end do
365 : !end do
366 : !ENDDEBUG
367 :
368 : !so now the inverse of the reduced matrix is in the matrixC
369 : !now do another mulplication to get the pseudoinverse of the original
370 443 : Cpmatr(:,:)=zero
371 443 : Apmatr(:,:)=zero
372 32 : do ivarA=1,3*natom-3
373 221 : do ivarB=1,3*natom-3
374 216 : Cpmatr(ivarA,ivarB)=Cmatr(ivarA,ivarB)
375 : end do
376 : end do
377 :
378 : !now times the eigvecp
379 47 : do ivarA=1,3*natom
380 443 : do ivarB=1,3*natom
381 4542 : do ii1=1,3*natom
382 4500 : Apmatr(ivarA,ivarB)=Apmatr(ivarA,ivarB)+eigvecp(1,ivarA,ii1)*Cpmatr(ii1,ivarB)
383 : end do
384 : end do
385 : end do
386 :
387 443 : Cpmatr(:,:)=zero
388 47 : do ivarA=1,3*natom
389 443 : do ivarB=1,3*natom
390 4542 : do ii1=1,3*natom
391 : Cpmatr(ivarA,ivarB)=Cpmatr(ivarA,ivarB)+&
392 4500 : & Apmatr(ivarA,ii1)*eigvecp(1,ivarB,ii1)
393 : end do
394 : end do
395 : end do
396 :
397 : !now the inverse in in Cpmatr
398 443 : kmatrix(:,:)=Cpmatr(:,:)
399 : !transfer the inverse of k-matrix back to the k matrix
400 : !so now the inverse of k matrix is in the kmatrix
401 : !ending the part for pseudoinversing the K matrix
402 :
403 : !we still need the z-star matrix
404 20 : do idir1=1,3
405 : d2cart_relaxed(1,idir1,natom+2,idir1,natom+2,iblok)=&
406 20 : & d2cart_relaxed(1,idir1,natom+2,idir1,natom+2,iblok)-1.0_dp
407 : end do
408 :
409 20 : do idir1=1,3
410 65 : do idir2=1,3
411 150 : do ii1=1,2
412 : d2cart_relaxed(ii1,idir1,natom+2,idir2,natom+2,iblok)=&
413 135 : & d2cart_relaxed(ii1,idir1,natom+2,idir2,natom+2,iblok)/four_pi
414 : end do
415 : end do
416 : end do
417 :
418 20 : do ivarA=1,3
419 15 : idir1=ivarA
420 15 : ipert1=natom+2
421 62 : do ipert2=1,natom
422 183 : do idir2=1,3
423 126 : ivarB=idir2+3*(ipert2-1)
424 168 : zstar1(ivarA,ivarB)=d2cart_relaxed(1,idir1,ipert1,idir2,ipert2,iblok)
425 : end do
426 : end do
427 : end do
428 :
429 : !then get the inverse of the zstar1 for zstar2(3*natom,3)
430 47 : do ivarA=1,3*natom
431 173 : do ivarB=1,3
432 168 : zstar2(ivarA,ivarB)=zstar1(ivarB,ivarA)
433 : end do
434 : end do
435 : !the the matrix I need for the multiplication is in kmatrix and zstar2
436 :
437 : !the first matrix mulplication
438 299 : new1(:,:)=zero
439 35 : do ii1=1,6
440 287 : do ii2=1,3*natom
441 2658 : do ivarA=1,3*natom
442 : new1(ii1,ii2)=new1(ii1,ii2)+instrain(ivarA,ii1)*&
443 2628 : & kmatrix(ivarA,ii2)
444 : end do
445 : end do
446 : end do
447 :
448 : !do the second matrix mulplication
449 5 : piezo_correction(:,:)=zero
450 35 : do ii1=1,6
451 125 : do ii2=1,3
452 876 : do ivarA=1,3*natom
453 : piezo_correction(ii1,ii2)=piezo_correction(ii1,ii2)+&
454 846 : & new1(ii1,ivarA)* zstar2(ivarA,ii2)
455 : end do
456 : end do
457 : end do
458 :
459 : !then consider the volume and the change the unit form atomic to SI
460 35 : do ii1=1,6
461 125 : do ii2=1,3
462 90 : piezo_correction(ii1,ii2)= (piezo_correction(ii1,ii2) / ucvol)*AmuBohr2_Cm2
463 120 : piezo_relaxed(ii1,ii2)=piezo_clamped(ii1,ii2)+ piezo_correction(ii1,ii2)
464 : end do
465 : end do
466 : !end the calculation of piezoelectric constants
467 :
468 : !then print out the relaxed ion piezoelectric constants
469 :
470 5 : if(inp%piezoflag==2.or.inp%piezoflag==3 .or. inp%piezoflag==7)then
471 5 : if(inp%instrflag==0)then
472 0 : write(message,'(a,a,a,a,a,a,a,a)' )ch10,&
473 0 : & ' WARNING: in order to get the piezoelectric tensor (relaxed ion), ',ch10,&
474 0 : & ' one needs information about internal strain ',ch10,&
475 0 : & ' one should set instrflag==1;',ch10,&
476 0 : & ' otherwise the program will continue but will give wrong values.'
477 0 : call wrtout(std_out,message,'COLL')
478 0 : call wrtout(iout,message,'COLL')
479 : end if
480 5 : write(message,'(3a)')ch10,' Proper piezoelectric constants (relaxed ion) (unit:c/m^2)',ch10
481 5 : call wrtout(std_out,message,'COLL')
482 35 : do ivarA=1,6
483 35 : write(std_out,'(3f16.8)')piezo_relaxed(ivarA,1),piezo_relaxed(ivarA,2),piezo_relaxed(ivarA,3)
484 : end do
485 :
486 5 : call wrtout(iout,message,'COLL')
487 5 : if (iwrite) then
488 35 : do ivarA=1,6
489 35 : write(iout,'(3f16.8)')piezo_relaxed(ivarA,1),piezo_relaxed(ivarA,2),piezo_relaxed(ivarA,3)
490 : end do
491 : end if
492 : end if
493 :
494 : !DEBUG
495 : !check the values of the relaxed ion dielectric tensor
496 : !write(message,'(a,a,a,a)')ch10,'debug the dielt tensor values ',&
497 : !& '(unit:c/m^2)',ch10
498 : !call wrtout(std_out,message,'COLL')
499 : !do ivarA=1,3
500 : !write(std_out,'(3f16.8)')dielt_rlx(ivarA,1),dielt_rlx(ivarA,2),dielt_rlx(ivarA,3)
501 : !end do
502 : !END DEBUG
503 :
504 : !DEBUG
505 : !print the relaxed ion elast tensor
506 : !write(message,'(a,a,a,a)')ch10,' debugElastic Tensor(relaxed ion)',&
507 : !& '(unit:10^2GP,VOIGT notation):',ch10
508 : !call wrtout(std_out,message,'COLL')
509 : !do ivarA=1,6
510 : !write(std_out,'(6f12.7)')elast(ivarA,1)/100.00_dp,elast(ivarA,2)/100.00_dp,&
511 : !& elast(ivarA,3)/100.00_dp,elast(ivarA,4)/100.00_dp,&
512 : !& elast(ivarA,5)/100.00_dp,elast(ivarA,6)/100.00_dp
513 : !end do
514 : !ENDDEBUG
515 :
516 : !Start to compute the piezoelectric d tensors
517 : !first initialize the d_tensor values
518 : !first make sure the elastic tensor is not zero
519 5 : d_tensor(:,:)=zero
520 5 : if(inp%elaflag>1)then
521 : ! then get the relaxed ion compliance tensor
522 5 : compliance(:,:)=elast(:,:)
523 5 : call matrginv(compliance,6,6)
524 35 : do ivarA=1,6
525 125 : do ivarB=1,3
526 660 : do ii1=1,6
527 : d_tensor(ivarA,ivarB)=d_tensor(ivarA,ivarB)+compliance(ivarA,ii1)*&
528 630 : & piezo_relaxed(ii1,ivarB)
529 : end do
530 : end do
531 : end do
532 : ! then convert in to the right unit pc/N
533 35 : do ivarA=1,6
534 125 : do ivarB=1,3
535 120 : d_tensor(ivarA,ivarB)=1000*d_tensor(ivarA,ivarB)
536 : end do
537 : end do
538 : end if
539 :
540 : !then print out the results of d tensor in log and output files
541 5 : if(inp%piezoflag==4 .or. inp%piezoflag==7)then
542 2 : if(inp%instrflag==0 .or. inp%elaflag==0 .or. inp%elaflag==1)then
543 0 : write(message,'(12a)' )ch10,&
544 0 : & ' WARNING:in order to get the piezoelectric d tensor(relaxed ion),', ch10,&
545 0 : & ' one needs the elastic tensor(relaxed ion) and piezoelectric e tensor',ch10,&
546 0 : & ' the latter needs the information of internal strain;',ch10,&
547 0 : & ' please check that both instrflag and elaflag are set to correct numbers',ch10,&
548 0 : & ' (elaflag= 2,3,4, or 5; instrflag=1)',ch10,&
549 0 : & ' otherwise the program will continue but give wrong values.'
550 0 : call wrtout(std_out,message,'COLL')
551 0 : call wrtout(iout,message,'COLL')
552 : end if
553 2 : write(message,'(3a)')ch10,' Piezoelectric d tensor (relaxed ion) (unit:pc/N)',ch10
554 2 : call wrtout(std_out,message,'COLL')
555 14 : do ivarA=1,6
556 14 : write(std_out,'(3f16.8)')d_tensor(ivarA,1),d_tensor(ivarA,2),d_tensor(ivarA,3)
557 : end do
558 2 : call wrtout(iout,message,'COLL')
559 2 : if (iwrite) then
560 14 : do ivarA=1,6
561 14 : write(iout,'(3f16.8)')d_tensor(ivarA,1),d_tensor(ivarA,2),d_tensor(ivarA,3)
562 : end do
563 : end if
564 : end if
565 : !end the part of piezoelectric d tensor (relaxed ion only).
566 :
567 : !then start to compute the piezoelectric g tensor
568 : !according to the equation, we first need to know the information
569 : !of the free-stress dielectric tensor
570 : !first make sure dielt_rlx exits, so we do not invert zero matrix
571 5 : dielt_stress(:,:)=zero
572 5 : g_tensor(:,:)=zero
573 5 : if(inp%dieflag>0)then
574 12 : do ivarA=1,3
575 39 : do ivarB=1,3
576 27 : dielt_stress(ivarA,ivarB)=zero
577 198 : do ii1=1,6
578 : dielt_stress(ivarA,ivarB)=dielt_stress(ivarA,ivarB)+&
579 189 : & piezo_relaxed(ii1,ivarA)*d_tensor(ii1,ivarB)
580 : end do
581 : end do
582 : end do
583 :
584 : ! then combine the relaxed ion(fixed strain) dielectric
585 : ! tensor and also restore the unit
586 12 : do ivarA=1,3
587 39 : do ivarB=1,3
588 : dielt_stress(ivarA,ivarB)=dielt_rlx(ivarA,ivarB)+&
589 36 : & dielt_stress(ivarA,ivarB)/(eps0*1.0e12)
590 : end do
591 : end do
592 :
593 : ! DEBUG
594 : ! write(message,'(a,a,a,a)')ch10,'debug the free stress dielectric tensor ',&
595 : ! & '(unit:pc/N)',ch10
596 : ! call wrtout(std_out,message,'COLL')
597 : ! do ivarA=1,3
598 : ! write(std_out,'(3f16.8)')dielt_stress(ivarA,1),dielt_stress(ivarA,2),&
599 : ! & dielt_stress(ivarA,3)
600 : ! end do
601 : ! ENDDEBUG
602 :
603 : ! then get the g tensor
604 : beta_tensor(:,:)=0
605 3 : beta_tensor(:,:)=dielt_stress(:,:)
606 :
607 3 : call matrginv(beta_tensor,3,3)
608 12 : do ivarA=1,3
609 66 : do ivarB=1,6
610 54 : g_tensor(ivarA,ivarB)=zero
611 225 : do ii1=1,3
612 : g_tensor(ivarA,ivarB)=g_tensor(ivarA,ivarB)+beta_tensor(ivarA,ii1)*&
613 216 : & d_tensor(ivarB,ii1)
614 : end do
615 : end do
616 : end do
617 : ! then restore the unit to be m^2/C
618 12 : do ivarA=1,3
619 66 : do ivarB=1,6
620 63 : g_tensor(ivarA,ivarB)=g_tensor(ivarA,ivarB)/(eps0*1.0e12)
621 : end do
622 : end do
623 : end if
624 : !then print out the final results of the g tensors(relaxed ion)
625 5 : if(inp%piezoflag==5 .or. inp%piezoflag==7)then
626 : if(inp%instrflag==0 .or. inp%elaflag==0&
627 : & .or. inp%elaflag==1 .or. inp%elaflag==0&
628 2 : & .or. inp%dieflag==2 .or. inp%dieflag==1)then
629 0 : write(message,'(a,a,a,a,a,a,a,a)' )ch10,&
630 0 : & ' WARNING:in order to get the piezoelectric g tensor(relaxed ion),',ch10,&
631 0 : & ' need internal strain, dielectric(relaxed-ion) and elastic(realxed ion)',ch10,&
632 0 : & ' please set instrflag==1, elaflag==2,3,4 or 5, dieflag==3 or 4',ch10,&
633 0 : & ' otherwise the program will still continue but give wrong values.'
634 0 : call wrtout(std_out,message,'COLL')
635 0 : call wrtout(iout,message,'COLL')
636 : end if
637 :
638 2 : write(message,'(3a)')ch10,' Piezoelectric g tensor (relaxed ion) (unit:m^2/c)',ch10
639 2 : call wrtout(std_out,message,'COLL')
640 14 : do ivarA=1,6
641 14 : write(std_out,'(3f16.8)')g_tensor(1,ivarA),g_tensor(2,ivarA),g_tensor(3,ivarA)
642 : end do
643 2 : call wrtout(iout,message,'COLL')
644 2 : if (iwrite) then
645 14 : do ivarA=1,6
646 14 : write(iout,'(3f16.8)')g_tensor(1,ivarA),g_tensor(2,ivarA),g_tensor(3,ivarA)
647 : end do
648 : end if
649 : end if
650 : !end the part of piezoelectric g tensor (relaxed ion only).
651 :
652 : !then start the part for computation of h tensor
653 5 : h_tensor(:,:)=zero
654 : !first make sure the dielt_rlx is not zero in the memory
655 5 : if(inp%dieflag>0)then
656 : beta_tensor(:,:)=0
657 3 : beta_tensor(:,:)=dielt_rlx(:,:)
658 : ! write(std_out,*)' call matrginv 3, dielt_rlx(:,:)= ',dielt_rlx(:,:)
659 :
660 3 : call matrginv(beta_tensor,3,3)
661 12 : do ivarA=1,3
662 66 : do ivarB=1,6
663 54 : h_tensor(ivarA,ivarB)=zero
664 225 : do ii1=1,3
665 : h_tensor(ivarA,ivarB)=h_tensor(ivarA,ivarB)+beta_tensor(ivarA,ii1)*&
666 216 : & piezo_relaxed(ivarB,ii1)
667 : end do
668 : end do
669 : end do
670 : ! then restore the unit to be N/c
671 12 : do ivarA=1,3
672 66 : do ivarB=1,6
673 63 : h_tensor(ivarA,ivarB)=1000.0*(h_tensor(ivarA,ivarB)/(eps0*1.0e12))
674 : end do
675 : end do
676 : end if
677 : !then print out the final results of h tensors
678 5 : if(inp%piezoflag==6 .or. inp%piezoflag==7)then
679 2 : if(inp%instrflag==0 .or. inp%dieflag==1 .or. &
680 : & inp%dieflag==2)then
681 0 : write(message,'(a,a,a,a,a,a,a,a)' )ch10,&
682 0 : & ' WARNING: in order to get the h tensor, ',ch10,&
683 0 : & ' one needs information about internal strain and dielectric(relaxed ion)',ch10,&
684 0 : & ' one should set dieflag==3 or 4 and instrflag==1;',ch10,&
685 0 : & ' otherwise the program will continue but give wrong values.'
686 0 : call wrtout(std_out,message,'COLL')
687 0 : call wrtout(iout,message,'COLL')
688 : end if
689 2 : write(message,'(3a)')ch10,' Piezoelectric h tensor (relaxed ion) (unit:GN/c)',ch10
690 2 : call wrtout(std_out,message,'COLL')
691 14 : do ivarA=1,6
692 14 : write(std_out,'(3f16.8)')h_tensor(1,ivarA),h_tensor(2,ivarA),h_tensor(3,ivarA)
693 : end do
694 2 : call wrtout(iout,message,'COLL')
695 2 : if (iwrite) then
696 14 : do ivarA=1,6
697 14 : write(iout,'(3f16.8)')h_tensor(1,ivarA),h_tensor(2,ivarA),h_tensor(3,ivarA)
698 : end do
699 : end if
700 : end if
701 : !end the part of piezoelectric h tensor (relaxed ion only).
702 :
703 : !print the free stress dielectric tensor
704 5 : if(inp%dieflag==4)then
705 2 : write(message, '(a,a)')ch10,'************************************************'
706 2 : call wrtout(std_out,message,'COLL')
707 2 : call wrtout(iout,message,'COLL')
708 2 : if(inp%instrflag==0 .or. inp%elaflag==0 .or. inp%elaflag==1)then
709 0 : write(message,'(a,a,a,a,a,a,a,a)' )ch10,&
710 0 : & ' WARNING: in order to get the free stress dielectric tensor,',ch10,&
711 0 : & ' one needs internal strain and elastic (relaxed ion)', ch10,&
712 0 : & ' we need set elaflag==2,3,4 or 5 and instrflag==1.',ch10,&
713 0 : & ' otherwise the program may continue but give wrong and nonsense values.'
714 0 : call wrtout(std_out,message,'COLL')
715 0 : call wrtout(iout,message,'COLL')
716 : end if
717 2 : write(message,'(a,a,a)')ch10,' Free stress dielectric tensor (dimensionless)',ch10
718 2 : call wrtout(std_out,message,'COLL')
719 8 : do ivarA=1,3
720 8 : write(std_out,'(3f16.8)')dielt_stress(ivarA,1),dielt_stress(ivarA,2),dielt_stress(ivarA,3)
721 : end do
722 2 : call wrtout(iout,message,'COLL')
723 2 : if (iwrite) then
724 8 : do ivarA=1,3
725 8 : write(iout,'(3f16.8)')dielt_stress(ivarA,1),dielt_stress(ivarA,2),dielt_stress(ivarA,3)
726 : end do
727 : end if
728 : end if
729 : !end the part of printing out the free stress dielectric tensor
730 :
731 : !then print out the fixed displacement elastic tensor
732 5 : elast_dis = zero; compliance_dis = zero
733 :
734 5 : if(inp%elaflag==4 .and. inp%dieflag>0)then
735 : if(inp%instrflag==0 .or. inp%dieflag==1 .or. &
736 2 : & inp%dieflag==2 .or. inp%dieflag==0)then
737 0 : write(message,'(a,a,a,a,a,a,a,a)' )ch10,&
738 0 : & ' WARNING: in order to get the elatic(fixed D field) tensor, ',ch10,&
739 0 : & ' one needs information about internal strain and dielectric(relaxed ion)',ch10,&
740 0 : & ' one should set dieflag==3 or 4 and instrflag==1;',ch10,&
741 0 : & ' otherwise the program will continue but give wrong values.'
742 0 : call wrtout(std_out,message,'COLL')
743 0 : call wrtout(iout,message,'COLL')
744 : end if
745 :
746 : !Then begin the computation of the fixed displacement elastic and compliance tensor(relaxed ion)
747 14 : do ivarA=1,6
748 86 : do ivarB=1,6
749 72 : elast_dis(ivarA,ivarB)=zero
750 300 : do ii1=1,3
751 : elast_dis(ivarA,ivarB)=elast_dis(ivarA,ivarB)+&
752 288 : & h_tensor(ii1,ivarA)*piezo_relaxed(ivarB,ii1)
753 : end do
754 : end do
755 : end do
756 : !Then should add the relaxed ion fixed E-field values
757 14 : do ivarA=1,6
758 86 : do ivarB=1,6
759 84 : elast_dis(ivarA,ivarB)=elast_dis(ivarA,ivarB)+elast(ivarA,ivarB)
760 : end do
761 : end do
762 :
763 2 : write(message, '(a,a)')ch10,'************************************************'
764 2 : call wrtout(std_out,message,'COLL')
765 2 : call wrtout(iout,message,'COLL')
766 2 : write(message,'(5a)')ch10,&
767 2 : & ' Elastic Tensor (relaxed ion) (unit:10^2GP)',ch10,&
768 4 : & ' (at fixed displacement field boundary condition)',ch10
769 2 : call wrtout(std_out,message,'COLL')
770 14 : do ivarA=1,6
771 12 : write(std_out,'(6f12.7)')elast_dis(ivarA,1)/100.00_dp,elast_dis(ivarA,2)/100.00_dp,&
772 12 : & elast_dis(ivarA,3)/100.00_dp,elast_dis(ivarA,4)/100.00_dp,&
773 26 : & elast_dis(ivarA,5)/100.00_dp,elast_dis(ivarA,6)/100.00_dp
774 : end do
775 2 : call wrtout(iout,message,'COLL')
776 2 : if (iwrite) then
777 14 : do ivarA=1,6
778 12 : write(iout,'(6f12.7)')elast_dis(ivarA,1)/100.00_dp,elast_dis(ivarA,2)/100.00_dp,&
779 12 : & elast_dis(ivarA,3)/100.00_dp,elast_dis(ivarA,4)/100.00_dp,&
780 26 : & elast_dis(ivarA,5)/100.00_dp,elast_dis(ivarA,6)/100.00_dp
781 : end do
782 : end if
783 : ! then invert the above to get the corresponding compliance tensor
784 : compliance_dis(:,:)=0
785 2 : compliance_dis(:,:)=elast_dis(:,:)
786 :
787 2 : call matrginv(compliance_dis,6,6)
788 : ! then print out the compliance tensor at fixed displacement field
789 2 : write(message,'(5a)')ch10,&
790 2 : & ' Compliance Tensor (relaxed ion) (unit: 10^-2(GP)^-1)',ch10,&
791 4 : & ' (at fixed displacement field boundary condition)',ch10
792 2 : call wrtout(std_out,message,'COLL')
793 14 : do ivarB=1,6
794 12 : write(std_out,'(6f12.7)')compliance_dis(ivarB,1)*100.00_dp,&
795 12 : & compliance_dis(ivarB,2)*100.00_dp,&
796 12 : & compliance_dis(ivarB,3)*100.00_dp,compliance_dis(ivarB,4)*100.00_dp,&
797 12 : & compliance_dis(ivarB,5)*100.00_dp,&
798 26 : & compliance_dis(ivarB,6)*100.00_dp
799 : end do
800 2 : call wrtout(iout,message,'COLL')
801 :
802 2 : if (iwrite) then
803 14 : do ivarB=1,6
804 12 : write(iout,'(6f12.7)')compliance_dis(ivarB,1)*100.00,&
805 12 : & compliance_dis(ivarB,2)*100.00_dp,&
806 12 : & compliance_dis(ivarB,3)*100.00_dp,compliance_dis(ivarB,4)*100.00_dp,&
807 12 : & compliance_dis(ivarB,5)*100.00_dp,&
808 26 : & compliance_dis(ivarB,6)*100.00_dp
809 : end do
810 : end if
811 : end if
812 : !end if the elaflag==4 for the fixed didplacement field elastic tensor
813 : !end the part for computation of elastic at fixed displacement field
814 :
815 : ! write tensors to netcdf file.
816 5 : if (ncid /= nctk_noid) then
817 : ncerr = nctk_def_arrays(ncid, [ &
818 : nctkarr_t("piezo_clamped_ion", "dp", "six, three"), &
819 : nctkarr_t("piezo_relaxed_ion", "dp", "six, three"), &
820 : nctkarr_t("d_tensor_relaxed_ion", "dp", "six, three"), &
821 : nctkarr_t("g_tensor_relaxed_ion", "dp", "three, six"), &
822 : nctkarr_t("h_tensor_relaxed_ion", "dp", "three, six"), &
823 : nctkarr_t("free_stress_dielectric_tensor", "dp", "three, three"), &
824 : nctkarr_t("elastic_tensor_relaxed_ion_fixed_D", "dp", "six, six"), &
825 : nctkarr_t("compliance_tensor_relaxed_ion_fixed_D", "dp", "six, six")], &
826 45 : defmode=.True.)
827 5 : NCF_CHECK(ncerr)
828 : ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
829 25 : "elaflag", "piezoflag", "instrflag", "dieflag"])
830 5 : NCF_CHECK(ncerr)
831 :
832 5 : NCF_CHECK(nctk_set_datamode(ncid))
833 : ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
834 : "elaflag", "piezoflag", "instrflag", "dieflag"], &
835 45 : [inp%elaflag, inp%piezoflag, inp%instrflag, inp%dieflag])
836 5 : NCF_CHECK(ncerr)
837 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "piezo_clamped_ion"), piezo_clamped))
838 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "piezo_relaxed_ion"), piezo_relaxed))
839 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "d_tensor_relaxed_ion"), d_tensor))
840 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "g_tensor_relaxed_ion"), g_tensor))
841 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "h_tensor_relaxed_ion"), h_tensor))
842 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "free_stress_dielectric_tensor"), dielt_stress))
843 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "elastic_tensor_relaxed_ion_fixed_D"), elast_dis))
844 5 : NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "compliance_tensor_relaxed_ion_fixed_D"), compliance_dis))
845 : end if
846 :
847 5 : end subroutine ddb_piezo
848 : !!***
849 :
850 : end module m_ddb_piezo
851 : !!***
|