LCOV - code coverage report
Current view: top level - src/77_ddb - m_ddb_piezo.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.1 % 360 310
Test Date: 2026-09-20 15:27:41 Functions: 100.0 % 1 1

            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              : !!***
        

Generated by: LCOV version 2.3-1