LCOV - code coverage report
Current view: top level - src/77_ddb - m_gruneisen.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 96.1 % 279 268
Test Date: 2026-09-21 13:49:52 Functions: 75.0 % 8 6

            Line data    Source code
       1              : !!****m* ABINIT/m_gruneisen
       2              : !! NAME
       3              : !!  m_gruneisen
       4              : !!
       5              : !! FUNCTION
       6              : !!  Objects and methods to compute Gruneisen parameters with central finite differences
       7              : !!  of dynamical matrices obtained with different unit cell volumes.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2011-2026 ABINIT group (MG)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public License, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! SOURCE
      16              : 
      17              : #if defined HAVE_CONFIG_H
      18              : #include "config.h"
      19              : #endif
      20              : 
      21              : #include "abi_common.h"
      22              : 
      23              : MODULE m_gruneisen
      24              : 
      25              :  use defs_basis
      26              :  use m_errors
      27              :  use m_abicore
      28              :  use m_xmpi
      29              :  use m_crystal
      30              :  use m_htetra
      31              :  use m_ddb
      32              :  use m_ddb_hdr
      33              :  use m_ifc
      34              :  use m_cgtools
      35              :  use m_nctk
      36              :  use netcdf
      37              : 
      38              :  use m_io_tools,            only : get_unit, open_file
      39              :  use m_time,                only : cwtime, cwtime_report
      40              :  use m_fstrings,            only : sjoin, itoa, ltoa, ftoa, strcat
      41              :  use m_numeric_tools,       only : central_finite_diff, arth
      42              :  use m_kpts,                only : kpts_ibz_from_kptrlatt, tetra_from_kptrlatt
      43              :  use m_bz_mesh,             only : kpath_t
      44              :  use m_anaddb_dataset,      only : anaddb_dataset_type
      45              :  use m_dynmat,              only : massmult_and_breaksym, dfpt_phfrq, gtdyn9
      46              : 
      47              :  implicit none
      48              : 
      49              :  private
      50              : !!***
      51              : 
      52              : !!****t* m_gruneisen/gruns_t
      53              : !! NAME
      54              : !! gruns_t
      55              : !!
      56              : !! FUNCTION
      57              : !!  Contains the interatomic force constants for different volumes.
      58              : !!  Provides methods to compute phonon bandstructures and gruneisen parameters.
      59              : !!
      60              : !! SOURCE
      61              : 
      62              :  type,public :: gruns_t
      63              : 
      64              :    integer :: natom3
      65              :     ! 3 * natom
      66              : 
      67              :    integer :: nvols
      68              :     ! Number of volumes.
      69              : 
      70              :    integer :: iv0
      71              :     ! Index of the DDB file corresponding to the equilibrium volume V0.
      72              : 
      73              :    real(dp) :: v0
      74              :     ! Equilibrium volume.
      75              : 
      76              :    real(dp) :: delta_vol
      77              :     ! Uniform grid spacing for finite difference.
      78              : 
      79              :    type(crystal_t),allocatable :: cryst_vol(:)
      80              :     ! cryst_vol(nvols)
      81              :     ! crystalline structure for the different volumes.
      82              : 
      83              :    type(ddb_type),allocatable :: ddb_vol(:)
      84              :     ! dbb_vol(nvols)
      85              :     ! DDB objects for the different volumes.
      86              : 
      87              :    type(ifc_type),allocatable :: ifc_vol(:)
      88              :     ! ifc_vol(nvols)
      89              :     ! interatomic force constants for the different volumes.
      90              : 
      91              :  end type gruns_t
      92              : 
      93              :  public :: gruns_new        ! Constructor.
      94              :  public :: gruns_qpath      ! Compute Gruneisen parameters on a q-path.
      95              :  public :: gruns_qmesh      ! Compute Gruneisen parameters on a q-mesh.
      96              :  public :: gruns_free       ! Release memory.
      97              :  public :: gruns_anaddb     ! Driver routine called in anaddb.
      98              : !!***
      99              : 
     100              : contains  !===========================================================
     101              : !!***
     102              : 
     103              : !----------------------------------------------------------------------
     104              : 
     105              : !!****f* m_gruneisen/gruns_new
     106              : !! NAME
     107              : !!  gruns_new
     108              : !!
     109              : !! FUNCTION
     110              : !!  Construct new object from a list of DDB files.
     111              : !!
     112              : !! INPUTS
     113              : !!  ddb_filepaths(:)=Paths of the DDB files (must be ordered by volume)
     114              : !!  inp<anaddb_dataset_type>=Anaddb dataset with input variables
     115              : !!  comm=MPI communicator
     116              : !!
     117              : !! SOURCE
     118              : 
     119            1 : type(gruns_t) function gruns_new(ddb_filepaths, inp, comm) result(new)
     120              : 
     121              : !Arguments ------------------------------------
     122              :  integer,intent(in) :: comm
     123              :  type(anaddb_dataset_type),intent(in) :: inp
     124              : !arrays
     125              :  character(len=*),intent(in) :: ddb_filepaths(:)
     126              : 
     127              : !Local variables-------------------------------
     128              :  integer,parameter :: master=0
     129              :  integer :: ivol,iblock,natom,ddbun, nprocs,my_rank,ierr
     130              :  character(len=500) :: msg
     131           52 :  type(ddb_hdr_type) :: ddb_hdr
     132              : !arrays
     133              :  real(dp) :: dielt(3,3)
     134            1 :  real(dp),allocatable :: zeff(:,:,:), qdrp_cart(:,:,:,:)
     135              : 
     136              : ! ************************************************************************
     137              : 
     138            1 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     139              : 
     140            1 :  new%nvols = size(ddb_filepaths)
     141           57 :  ABI_MALLOC(new%cryst_vol, (new%nvols))
     142            6 :  ABI_MALLOC(new%ddb_vol, (new%nvols))
     143           11 :  ABI_MALLOC(new%ifc_vol, (new%nvols))
     144              : 
     145            1 :  call wrtout(ab_out, "Computation of Gruneisen parameter with central finite difference:")
     146              : 
     147            1 :  ddbun = get_unit()
     148            4 :  do ivol=1,new%nvols
     149            3 :    call wrtout(ab_out, sjoin(" Reading DDB file:", ddb_filepaths(ivol)))
     150              : 
     151            3 :    call new%ddb_vol(ivol)%from_file(ddb_filepaths(ivol), ddb_hdr, new%cryst_vol(ivol), comm)
     152            3 :    call new%ddb_vol(ivol)%set_brav(inp%brav)
     153            3 :    natom = ddb_hdr%natom
     154            3 :    call ddb_hdr%free()
     155              : 
     156            3 :    if (my_rank == master) then
     157            3 :      call new%cryst_vol(ivol)%print(header=sjoin("Structure for ivol:", itoa(ivol)), unit=ab_out, prtvol=-1)
     158              :    end if
     159              : 
     160              :    ! Get Dielectric Tensor and Effective Charges
     161              :    ! (initialized to one_3D and zero if the derivatives are not available in the DDB file)
     162            9 :    ABI_MALLOC(zeff, (3,3,natom))
     163          369 :    ABI_CALLOC(qdrp_cart, (3,3,3,natom))
     164            3 :    iblock = new%ddb_vol(ivol)%get_dielt_zeff(new%cryst_vol(ivol), inp%rfmeth, inp%chneut, inp%selectz, dielt, zeff)
     165            3 :    if (iblock == 0) then
     166            0 :      call wrtout(ab_out, sjoin("- Cannot find dielectric tensor and Born effective charges in DDB file:", ddb_filepaths(ivol)))
     167            0 :      call wrtout(ab_out, "Values initialized with zeros")
     168              :    else
     169            3 :      call wrtout(ab_out, sjoin("- Found dielectric tensor and Born effective charges in DDB file:", ddb_filepaths(ivol)))
     170              :    end if
     171              : 
     172              :    call new%ifc_vol(ivol)%init(new%cryst_vol(ivol), new%ddb_vol(ivol),&
     173              :      inp%brav,inp%asr,inp%symdynmat,inp%dipdip,inp%rfmeth,inp%ngqpt(1:3),inp%nqshft,inp%q1shft,dielt,zeff,&
     174            3 :      qdrp_cart,inp%nsphere,inp%rifcsph,inp%prtsrlr,inp%enunit,inp%sys_dim,comm)
     175            3 :    ABI_FREE(zeff)
     176            4 :    ABI_FREE(qdrp_cart)
     177              :  end do
     178              : 
     179              :  ! Consistency check
     180              :  ! TODO: Add more tests.
     181            1 :  ABI_CHECK(any(new%nvols == [3, 5, 7, 9]), "Central finite difference requires [3,5,7,9] DDB files")
     182              : 
     183            1 :  new%natom3 = 3 * new%cryst_vol(1)%natom
     184            1 :  new%iv0 = 1 + new%nvols / 2
     185            1 :  new%v0 = new%cryst_vol(new%iv0)%ucvol
     186            1 :  new%delta_vol = new%cryst_vol(new%iv0+1)%ucvol - new%cryst_vol(new%iv0)%ucvol
     187              : 
     188            1 :  ierr = 0
     189            4 :  do ivol=1,new%nvols
     190            4 :    if (abs(new%cryst_vol(1)%ucvol + new%delta_vol * (ivol-1) - new%cryst_vol(ivol)%ucvol) > tol4) then
     191            0 :       write(std_out,*)"ucvol, delta_vol, diff_vol", new%cryst_vol(ivol)%ucvol, new%delta_vol, &
     192            0 :         abs(new%cryst_vol(1)%ucvol + new%delta_vol * (ivol-1) - new%cryst_vol(ivol)%ucvol)
     193            0 :       ierr = ierr + 1
     194              :    end if
     195              :  end do
     196            1 :  if (ierr /= 0) then
     197            0 :    msg = ltoa([(new%cryst_vol(ivol)%ucvol, ivol=1,new%nvols)])
     198            0 :    ABI_ERROR(sjoin("Gruneisen calculations requires linear mesh of volumes but received:", msg))
     199              :  end if
     200              : 
     201            2 : end function gruns_new
     202              : !!***
     203              : 
     204              : !----------------------------------------------------------------------
     205              : 
     206              : !!****f* m_gruneisen/gruns_fourq
     207              : !! NAME
     208              : !!  gruns_fourq
     209              : !!
     210              : !! FUNCTION
     211              : !!  Compute gruneisen parameters at an arbitrary q-point.
     212              : !!
     213              : !! INPUTS
     214              : !!  qpt(3)=q-point in reduced coordinates.
     215              : !!
     216              : !! OUTPUT
     217              : !!  wvols(3*natom, nvols) = Phonon frequencies for the different volumen.
     218              : !!  gvals(3*natom)=Gruneisen parameters evaluated at V0.
     219              : !!  dwdq(3,3*natom)=Group velocities at V0 in Cartesian coordinates.
     220              : !!  phdispl_cart(2, natom3, natom3, nvols)=Phonon displacement in Cartesian coordinates for the different volumes
     221              : !!
     222              : !! NOTES
     223              : !!
     224              : !!  The Gruneisen parameter is given by:
     225              : !!
     226              : !!     gamma(q,nu) = - (V / w(q,nu)) dw(q,nu)/dV
     227              : !!
     228              : !!  Using w*2 = <u|D|u> and the Hellmann-Feynmann theorem, one obtains:
     229              : !!
     230              : !!     gamma(q,nu) = - (V / 2 w(q,nu)**2) <u(q,nu)|dD(q)/dV|u(q,nu)>
     231              : !!
     232              : !!  The derivative dD/dV is computed via central finite difference.
     233              : !!
     234              : !! SOURCE
     235              : 
     236          228 : subroutine gruns_fourq(gruns, qpt, wvols, gvals, dwdq, phdispl_cart)
     237              : 
     238              : !Arguments ------------------------------------
     239              : !scalars
     240              :  class(gruns_t),intent(in) :: gruns
     241              : !arrays
     242              :  real(dp),intent(in) :: qpt(3)
     243              :  real(dp),intent(out) :: wvols(gruns%natom3,gruns%nvols),gvals(gruns%natom3),dwdq(3,gruns%natom3)
     244              :  real(dp),intent(out) :: phdispl_cart(2, gruns%natom3, gruns%natom3, gruns%nvols)
     245              : 
     246              : !Local variables-------------------------------
     247              : !scalars
     248              :  integer :: ivol,natom3,nu
     249              :  real(dp) :: fact
     250              : !arrays
     251              :  real(dp) :: dot(2)
     252          456 :  real(dp) :: eigvec(2,gruns%natom3,gruns%natom3,gruns%nvols),d2cart(2,gruns%natom3,gruns%natom3,gruns%nvols)
     253          456 :  real(dp) :: dddv(2,gruns%natom3,gruns%natom3)
     254          456 :  real(dp) :: omat(2,gruns%natom3, gruns%natom3)
     255              : 
     256              : ! ************************************************************************
     257              : 
     258          228 :  natom3 = gruns%natom3
     259          912 :  do ivol=1,gruns%nvols
     260          684 :    if (ivol == gruns%iv0) then
     261              :      ! Compute group velocities for V=V0
     262              :      call gruns%ifc_vol(ivol)%fourq(gruns%cryst_vol(ivol), qpt, wvols(:,ivol), phdispl_cart(:,:,:,ivol), &
     263          228 :                     out_d2cart=d2cart(:,:,:,ivol), out_eigvec=eigvec(:,:,:,ivol), dwdq=dwdq)
     264              :    else
     265              :      call gruns%ifc_vol(ivol)%fourq(gruns%cryst_vol(ivol), qpt, wvols(:,ivol), phdispl_cart(:,:,:,ivol), &
     266          456 :                     out_d2cart=d2cart(:,:,:,ivol), out_eigvec=eigvec(:,:,:,ivol))
     267              :    end if
     268              : 
     269              :    call massmult_and_breaksym(gruns%cryst_vol(ivol)%natom, gruns%cryst_vol(ivol)%ntypat, &
     270          912 :      gruns%cryst_vol(ivol)%typat, gruns%ifc_vol(ivol)%amu, d2cart(:,:,:,ivol))
     271              : 
     272              :    !call zgemm('N','N',natom3,natom3,natom3,cone,d2cart(:,:,:,ivol),natom3,eigvec(:,:,:,ivol),natom3,czero,omat,natom3)
     273              :    !do nu=1,natom3
     274              :    !  write(std_out,*)"H|psi> - w**2 |psi>",maxval(abs(omat(:,:,nu) - wvols(nu,ivol) ** 2 * eigvec(:,:,nu,ivol)))
     275              :    !end do
     276              :  end do
     277              : 
     278              :  ! Compute dD(q)/dV with central finite difference.
     279        57684 :  dddv = zero
     280          912 :  do ivol=1,gruns%nvols
     281          684 :    fact = central_finite_diff(1, ivol, gruns%nvols)
     282       115824 :    if (fact /= zero) dddv = dddv + fact * d2cart(:,:,:,ivol)
     283              :  end do
     284        57684 :  dddv = dddv / gruns%delta_vol
     285              : 
     286              :  ! Compute -V0/(2w(q)**2) <u(q)|dD(q)/dq|u(q)>
     287          228 :  call zgemm('N','N',natom3,natom3,natom3,cone,dddv,natom3,eigvec(:,:,:,gruns%iv0),natom3,czero,omat,natom3)
     288         2280 :  do nu=1,natom3
     289         2280 :    if (abs(wvols(nu, gruns%iv0)) > tol12) then
     290         2043 :      dot = cg_zdotc(natom3, eigvec(1,1,nu, gruns%iv0), omat(1,1,nu))
     291              :      ! Must change sign if we have a purely imaginary solution i.e. z = iw
     292         2043 :      gvals(nu) = -sign(one, wvols(nu, gruns%iv0)) * gruns%v0 * dot(1) / (two * wvols(nu, gruns%iv0)**2)
     293              :    else
     294            9 :      gvals(nu) = zero
     295              :    end if
     296              :  end do
     297              : 
     298          228 : end subroutine gruns_fourq
     299              : !!***
     300              : 
     301              : !----------------------------------------------------------------------
     302              : 
     303              : !!****f* m_gruneisen/gruns_qpath
     304              : !! NAME
     305              : !!  gruns_qpath
     306              : !!
     307              : !! FUNCTION
     308              : !!  Compute gruneisen parameters and group velocities on a q-path
     309              : !!  Write results to file.
     310              : !!
     311              : !! INPUTS
     312              : !!  prefix=Prefix for output files.
     313              : !!  qpath<kpath_t>=Object describing the q-path.
     314              : !!  ncid=netcdf file id.
     315              : !!  comm=MPI communicator.
     316              : !!
     317              : !! OUTPUT
     318              : !!  Only writing
     319              : !!
     320              : !! SOURCE
     321              : 
     322            1 : subroutine gruns_qpath(gruns, prefix, qpath, ncid, comm)
     323              : 
     324              : !Arguments ------------------------------------
     325              : !scalars
     326              :  class(gruns_t),intent(in) :: gruns
     327              :  integer,intent(in) :: ncid,comm
     328              :  type(kpath_t),intent(in) :: qpath
     329              :  character(len=*),intent(in) :: prefix
     330              : 
     331              : !Local variables-------------------------------
     332              : !scalars
     333              :  integer,parameter :: master=0
     334              :  integer :: nprocs,my_rank,iqpt,ierr,ncerr,unt,iv0,nu,ii
     335              :  character(len=500) :: msg
     336              : !arrays
     337            1 :  real(dp),allocatable :: gvals_qpath(:,:),wvols_qpath(:,:,:),dwdq_qpath(:,:,:)
     338            1 :  real(dp),allocatable :: phdispl_cart_qpath(:,:,:,:,:)
     339              : 
     340              : ! ************************************************************************
     341              : 
     342            1 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     343              : 
     344           81 :  write(msg,'(a,(80a),4a)')ch10,('=',ii=1,80),ch10,ch10,' Calculation of Gruneisen parameters along q-path ',ch10
     345            1 :  call wrtout(std_out, msg)
     346              :  !call wrtout(ab_out, msg)
     347              : 
     348            1 :  iv0 = gruns%iv0
     349         2578 :  ABI_CALLOC(wvols_qpath, (gruns%natom3, gruns%nvols, qpath%npts))
     350          834 :  ABI_CALLOC(gvals_qpath, (gruns%natom3, qpath%npts))
     351         3075 :  ABI_CALLOC(dwdq_qpath, (3, gruns%natom3, qpath%npts))
     352        63086 :  ABI_CALLOC(phdispl_cart_qpath, (2, gruns%natom3, gruns%natom3, gruns%nvols, qpath%npts))
     353              : 
     354           84 :  do iqpt=1,qpath%npts
     355           83 :    if (mod(iqpt, nprocs) /= my_rank) cycle ! mpi-parallelism
     356              :    call gruns_fourq(gruns, qpath%points(:,iqpt), wvols_qpath(:,:,iqpt), gvals_qpath(:,iqpt), &
     357           84 :                     dwdq_qpath(:,:,iqpt), phdispl_cart_qpath(:,:,:,:,iqpt))
     358              :  end do
     359              : 
     360            1 :  call xmpi_sum(wvols_qpath, comm, ierr)
     361            1 :  call xmpi_sum(gvals_qpath, comm, ierr)
     362            1 :  call xmpi_sum(dwdq_qpath, comm, ierr)
     363            1 :  call xmpi_sum(phdispl_cart_qpath, comm, ierr)
     364              : 
     365              :  ! Write text files with phonon frequencies and gruneisen on the path.
     366            1 :  if (my_rank == master) then
     367            1 :    if (open_file(strcat(prefix, "_GRUNS_QPATH"), msg, newunit=unt, form="formatted", action="write") /= 0) then
     368            1 :      ABI_ERROR(msg)
     369              :    end if
     370            1 :    write(unt,'(a)')'# Phonon band structure, Gruneisen parameters and group velocity'
     371            1 :    write(unt,'(a)')"# Energy in Hartree, DOS in states/Hartree"
     372            2 :    call qpath%print([unt], pre="#")
     373              :    write(unt,'(5a)')&
     374            1 :      "# phfreq(mode=1) gruneisen(mode=1) velocity(mode=1)    phfreq(mode=2) gruneisen(mode=2) velocity(mode=2)   ..."
     375           84 :    do iqpt=1,qpath%npts
     376          830 :      do nu=1,gruns%natom3
     377              :        write(unt, "(3es17.8)", advance="no") &
     378         3071 :          wvols_qpath(nu, iv0, iqpt), gvals_qpath(nu, iqpt), sum(dwdq_qpath(1:3, nu, iqpt) ** 2)
     379              :      end do
     380           84 :      write(unt, "(a)")" "
     381              :    end do
     382            1 :    close(unt)
     383              :  end if
     384              : 
     385            1 :  if (my_rank == master .and. ncid /= nctk_noid) then
     386            2 :    ncerr = nctk_def_dims(ncid, [nctkdim_t("gruns_nqpath", qpath%npts)], defmode=.True.)
     387            1 :    NCF_CHECK(ncerr)
     388              : 
     389              :    ncerr = nctk_def_arrays(ncid, [ &
     390              :      ! q-points of the path
     391              :      nctkarr_t("gruns_qpath", "dp", "three, gruns_nqpath"), &
     392              :      ! gruneisen parameters on the path
     393              :      nctkarr_t("gruns_gvals_qpath", "dp", "number_of_phonon_modes, gruns_nqpath"), &
     394              :      ! phonon frequencies at the different volumes
     395              :      nctkarr_t("gruns_wvols_qpath", "dp", "number_of_phonon_modes, gruns_nvols, gruns_nqpath"), &
     396              :      ! group velocities at V0 in Cartesian coordinates.
     397              :      nctkarr_t("gruns_dwdq_qpath", "dp", "three, number_of_phonon_modes, gruns_nqpath"), &
     398              :      ! displacements for the different volumes.
     399              :      nctkarr_t("gruns_phdispl_cart_qpath", "dp", &
     400              :          "two, number_of_phonon_modes, number_of_phonon_modes, gruns_nvols, gruns_nqpath") &
     401            6 :    ])
     402            1 :    NCF_CHECK(ncerr)
     403              : 
     404              :    ! Write data.
     405            1 :    NCF_CHECK(nctk_set_datamode(ncid))
     406            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qpath"), qpath%points))
     407            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gvals_qpath"), gvals_qpath))
     408            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wvols_qpath"), wvols_qpath))
     409            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_dwdq_qpath"), dwdq_qpath))
     410            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_phdispl_cart_qpath"), phdispl_cart_qpath))
     411              :  end if
     412              : 
     413            1 :  ABI_FREE(wvols_qpath)
     414            1 :  ABI_FREE(gvals_qpath)
     415            1 :  ABI_FREE(dwdq_qpath)
     416            1 :  ABI_FREE(phdispl_cart_qpath)
     417              : 
     418            1 : end subroutine gruns_qpath
     419              : !!***
     420              : 
     421              : !----------------------------------------------------------------------
     422              : 
     423              : !!****f* m_gruneisen/gruns_qmesh
     424              : !! NAME
     425              : !!  gruns_qmesh
     426              : !!
     427              : !! FUNCTION
     428              : !!  Compute gruneisen parameters and group velocities on a q-mesh.
     429              : !!  Save results to file.
     430              : !!
     431              : !! INPUTS
     432              : !!  prefix=Prefix for output files.
     433              : !!  dosdeltae=Step for the frequency mesh.
     434              : !!  ngqpt(3)=q-mesh divisions
     435              : !!  nshiftq=Number of shifts used to generated the ab-initio q-mesh.
     436              : !!  shiftq(3,nshiftq)=The shifts of the ab-initio q-mesh.
     437              : !!  ncid=netcdf file id.
     438              : !!  comm=MPI communicator
     439              : !!
     440              : !! OUTPUT
     441              : !!
     442              : !! SOURCE
     443              : 
     444            1 : subroutine gruns_qmesh(gruns, prefix, dosdeltae, ngqpt, nshiftq, shiftq, ncid, comm)
     445              : 
     446              : !Arguments ------------------------------------
     447              : !scalars
     448              :  class(gruns_t),intent(in) :: gruns
     449              :  integer,intent(in) :: nshiftq,ncid,comm
     450              :  real(dp),intent(in) :: dosdeltae !,dossmear
     451              :  character(len=*),intent(in) :: prefix
     452              : !arrays
     453              :  integer,intent(in) :: ngqpt(3)
     454              :  real(dp),intent(in) :: shiftq(3,nshiftq)
     455              : 
     456              : !Local variables-------------------------------
     457              : !scalars
     458              :  integer,parameter :: master=0,qptopt1=1,bcorr0=0
     459              :  integer :: nprocs,my_rank,iqibz,nqbz,nqibz,ierr,ii,nu,ncerr,nomega,cnt,unt,io
     460              :  real(dp) :: gavg,omega_min,omega_max,v2
     461            1 :  type(htetra_t) :: tetra
     462              :  character(len=500) :: msg
     463              : !arrays
     464              :  integer :: qptrlatt(3,3)
     465            1 :  real(dp),allocatable :: gvals_qibz(:,:),wvols_qibz(:,:,:),dwdq_qibz(:,:,:)
     466            1 :  real(dp),allocatable :: qibz(:,:),qbz(:,:),wtq(:)
     467            1 :  real(dp),allocatable :: wdt(:,:),wdos(:,:),grdos(:,:),gr2dos(:,:),wibz(:),omega_mesh(:)
     468            1 :  real(dp),allocatable :: vdos(:,:),v2dos(:,:)
     469            1 :  real(dp),allocatable :: phdispl_cart_qibz(:,:,:,:,:)
     470              : 
     471              : ! ************************************************************************
     472              : 
     473            1 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     474              : 
     475           81 :  write(msg,'(a,(80a),4a)')ch10,('=',ii=1,80),ch10,ch10,' Calculation of Gruneisen DOSes ',ch10
     476            1 :  call wrtout(std_out, msg)
     477              : 
     478              :  ! Generate the q-mesh by finding the IBZ and the corresponding weights.
     479            4 :  ABI_CHECK(all(ngqpt > 0), sjoin("invalid ngqpt:", ltoa(ngqpt)))
     480            1 :  qptrlatt = 0
     481            4 :  do ii=1,3
     482            4 :    qptrlatt(ii,ii) = ngqpt(ii)
     483              :  end do
     484              : 
     485              :  ! Get IBZ and BZ.
     486              :  call kpts_ibz_from_kptrlatt(gruns%cryst_vol(gruns%iv0), qptrlatt, qptopt1, nshiftq, shiftq, &
     487            1 :    nqibz, qibz, wtq, nqbz, qbz)
     488              : 
     489              :  ! Build tetrahedra
     490            1 :  tetra = tetra_from_kptrlatt(gruns%cryst_vol(gruns%iv0), qptopt1, qptrlatt, nshiftq, shiftq, nqibz, qibz, comm, msg, ierr)
     491            1 :  if (ierr /= 0) ABI_ERROR(msg)
     492              : 
     493         4500 :  ABI_CALLOC(wvols_qibz, (gruns%natom3, gruns%nvols, nqibz))
     494         1454 :  ABI_CALLOC(gvals_qibz, (gruns%natom3, nqibz))
     495         5369 :  ABI_CALLOC(dwdq_qibz, (3, gruns%natom3, nqibz))
     496       110206 :  ABI_CALLOC(phdispl_cart_qibz, (2, gruns%natom3, gruns%natom3, gruns%nvols, nqibz))
     497              : 
     498            1 :  gavg = zero
     499          146 :  do iqibz=1,nqibz
     500          145 :    if (mod(iqibz, nprocs) /= my_rank) cycle ! mpi-parallelism
     501              :    call gruns_fourq(gruns, qibz(:,iqibz), wvols_qibz(:,:,iqibz), gvals_qibz(:,iqibz), &
     502          145 :                     dwdq_qibz(:,:,iqibz), phdispl_cart_qibz(:,:,:,:,iqibz))
     503         1451 :    gavg = gavg + wtq(iqibz) * sum(gvals_qibz(:,iqibz))
     504              :  end do
     505            1 :  gavg = gavg / gruns%natom3
     506              : 
     507            1 :  call xmpi_sum(gavg, comm, ierr)
     508            1 :  call xmpi_sum(wvols_qibz, comm, ierr)
     509            1 :  call xmpi_sum(gvals_qibz, comm, ierr)
     510            1 :  call xmpi_sum(dwdq_qibz, comm, ierr)
     511            1 :  call xmpi_sum(phdispl_cart_qibz, comm, ierr)
     512              : 
     513            1 :  omega_min = gruns%ifc_vol(gruns%iv0)%omega_minmax(1)
     514            1 :  omega_max = gruns%ifc_vol(gruns%iv0)%omega_minmax(2)
     515            1 :  nomega = nint((omega_max - omega_min) / dosdeltae) + 1
     516            1 :  nomega = max(6, nomega) ! Ensure Simpson integration will be ok
     517              : 
     518            3 :  ABI_MALLOC(omega_mesh, (nomega))
     519            1 :  omega_mesh = arth(omega_min, dosdeltae, nomega)
     520            1 :  omega_max = omega_mesh(nomega)
     521              :  !write(std_out,*)"hello",omega_min,omega_max,dosdeltae,(omega_max-omega_min) / (nomega-1)
     522            3 :  ABI_MALLOC(wibz, (nqibz))
     523            3 :  ABI_MALLOC(wdt, (nomega, 2))
     524         3990 :  ABI_CALLOC(wdos, (nomega, 2))
     525         3990 :  ABI_CALLOC(grdos, (nomega, 2))
     526         3990 :  ABI_CALLOC(gr2dos, (nomega, 2))
     527         3990 :  ABI_CALLOC(vdos, (nomega, 2))
     528         3990 :  ABI_CALLOC(v2dos, (nomega, 2))
     529              : 
     530              :  ! Compute DOSes.
     531            1 :  cnt = 0
     532          146 :  do iqibz=1,nqibz
     533         1451 :    do nu=1,gruns%natom3
     534         1305 :      cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! mpi-parallelism
     535       191835 :      wibz = wvols_qibz(nu, gruns%iv0, :)
     536         1305 :      call tetra%get_onewk(iqibz,bcorr0,nomega,nqibz,wibz,omega_min,omega_max,one,wdt)
     537      5205645 :      wdt = wdt*wtq(iqibz)
     538      5206950 :      wdos = wdos + wdt
     539      5206950 :      grdos = grdos + wdt * gvals_qibz(nu,iqibz)
     540      5206950 :      gr2dos = gr2dos + wdt * gvals_qibz(nu,iqibz) ** 2
     541         5220 :      v2 = sum(dwdq_qibz(1:3,nu,iqibz) ** 2)
     542      5206950 :      vdos = vdos + wdt * sqrt(v2)
     543      5207095 :      v2dos = v2dos + wdt * v2
     544              :    end do
     545              :  end do
     546              : 
     547            1 :  call xmpi_sum(wdos, comm, ierr)
     548            1 :  call xmpi_sum(grdos, comm, ierr)
     549            1 :  call xmpi_sum(gr2dos, comm, ierr)
     550            1 :  call xmpi_sum(vdos, comm, ierr)
     551            1 :  call xmpi_sum(v2dos, comm, ierr)
     552              : 
     553            1 :  if (my_rank == master) then
     554            1 :    call wrtout(ab_out, sjoin(" Average Gruneisen parameter:", ftoa(gavg, fmt="f8.5")))
     555              : 
     556              :    ! Write text files with Gruneisen and DOSes.
     557            1 :    if (open_file(strcat(prefix, "_GRUNS_DOS"), msg, newunit=unt, form="formatted", action="write") /= 0) then
     558            1 :      ABI_ERROR(msg)
     559              :    end if
     560            1 :    write(unt,'(a)')'# Phonon density of states, Gruneisen DOS and phonon group velocity DOS'
     561            1 :    write(unt,'(a)')"# Energy in Hartree, DOS in states/Hartree"
     562            1 :    write(unt,'(a,i0)')'# Tetrahedron method with nqibz= ',nqibz
     563            1 :    write(unt,"(a,f8.5)")"# Average Gruneisen parameter:", gavg
     564              :    write(unt,'(5a)') &
     565            1 :      "# omega PH_DOS Gruns_DOS Gruns**2_DOS Vel_DOS  Vel**2_DOS  PH_IDOS Gruns_IDOS Gruns**2_IDOS Vel_IDOS Vel**2_IDOS"
     566         1994 :    do io=1,nomega
     567         1993 :      write(unt, "(11es17.8)")omega_mesh(io), &
     568         1993 :        wdos(io,1), grdos(io,1), gr2dos(io,1), vdos(io,1), v2dos(io,1), &
     569         3987 :        wdos(io,2), grdos(io,2), gr2dos(io,2), vdos(io,2), v2dos(io,2)
     570              :    end do
     571            1 :    close(unt)
     572              :  end if
     573              : 
     574              :  ! Write netcdf files.
     575            1 :  if (my_rank == master .and. ncid /= nctk_noid) then
     576              :    ncerr = nctk_def_dims(ncid, [ &
     577              :      nctkdim_t("gruns_nqibz", nqibz), nctkdim_t('gruns_nshiftq', nshiftq), &
     578            4 :      nctkdim_t('gruns_nomega', nomega)], defmode=.True.)
     579            1 :    NCF_CHECK(ncerr)
     580              : 
     581              :    ncerr = nctk_def_arrays(ncid, [ &
     582              :     ! q-point sampling in IBZ,
     583              :     nctkarr_t("gruns_qptrlatt", "int", "three, three"), &
     584              :     nctkarr_t("gruns_shiftq", "dp", "three, gruns_nshiftq"), &
     585              :     nctkarr_t("gruns_qibz", "dp", "three, gruns_nqibz"), &
     586              :     nctkarr_t("gruns_wtq", "dp", "gruns_nqibz"), &
     587              :     ! gruneisen parameters in IBZ
     588              :     ! phonon frequencies at the different volumes,
     589              :     ! group velocities at V0 in Cartesian coordinates.
     590              :     nctkarr_t("gruns_gvals_qibz", "dp", "number_of_phonon_modes, gruns_nqibz"), &
     591              :     nctkarr_t("gruns_wvols_qibz", "dp", "number_of_phonon_modes, gruns_nvols, gruns_nqibz"), &
     592              :     nctkarr_t("gruns_dwdq_qibz", "dp", "three, number_of_phonon_modes, gruns_nqibz"), &
     593              :     ! displacements for the different volumes.
     594              :     nctkarr_t("gruns_phdispl_cart_qibz", "dp", &
     595              :         "two, number_of_phonon_modes, number_of_phonon_modes, gruns_nvols, gruns_nqibz"), &
     596              :     ! DOSes and IDOSes
     597              :     nctkarr_t("gruns_omega_mesh", "dp", "gruns_nomega"), &
     598              :     nctkarr_t("gruns_wdos", "dp", "gruns_nomega, two"), &
     599              :     nctkarr_t("gruns_grdos", "dp", "gruns_nomega, two"), &
     600              :     nctkarr_t("gruns_gr2dos", "dp", "gruns_nomega, two"), &
     601              :     nctkarr_t("gruns_v2dos", "dp", "gruns_nomega, two"), &
     602              :     nctkarr_t("gruns_vdos", "dp", "gruns_nomega, two") &
     603           15 :    ])
     604            1 :    NCF_CHECK(ncerr)
     605              : 
     606              :    ! Write data.
     607            1 :    NCF_CHECK(nctk_set_datamode(ncid))
     608            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qptrlatt"), qptrlatt))
     609            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_shiftq"), shiftq))
     610            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qibz"), qibz))
     611            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wtq"), wtq))
     612            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gvals_qibz"), gvals_qibz))
     613            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wvols_qibz"), wvols_qibz))
     614            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_dwdq_qibz"), dwdq_qibz))
     615            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_phdispl_cart_qibz"), phdispl_cart_qibz))
     616            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_omega_mesh"), omega_mesh))
     617            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wdos"), wdos))
     618            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_grdos"), grdos))
     619            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gr2dos"), gr2dos))
     620            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_v2dos"), v2dos))
     621            1 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_vdos"), vdos))
     622              :  end if
     623              : 
     624            1 :  ABI_FREE(qibz)
     625            1 :  ABI_FREE(wtq)
     626            1 :  ABI_FREE(qbz)
     627            1 :  ABI_FREE(wvols_qibz)
     628            1 :  ABI_FREE(gvals_qibz)
     629            1 :  ABI_FREE(dwdq_qibz)
     630            1 :  ABI_FREE(phdispl_cart_qibz)
     631            1 :  ABI_FREE(omega_mesh)
     632            1 :  ABI_FREE(wibz)
     633            1 :  ABI_FREE(wdt)
     634            1 :  ABI_FREE(wdos)
     635            1 :  ABI_FREE(grdos)
     636            1 :  ABI_FREE(gr2dos)
     637            1 :  ABI_FREE(v2dos)
     638            1 :  ABI_FREE(vdos)
     639              : 
     640            1 :  call tetra%free()
     641              : 
     642            3 : end subroutine gruns_qmesh
     643              : !!***
     644              : 
     645              : !----------------------------------------------------------------------
     646              : 
     647              : !!****f* m_gruneisen/gruns_free
     648              : !! NAME
     649              : !!  gruns_free
     650              : !!
     651              : !! FUNCTION
     652              : !!  Free dynamic memory.
     653              : !!
     654              : !! SOURCE
     655              : 
     656            1 : subroutine gruns_free(gruns)
     657              : 
     658              : !Arguments ------------------------------------
     659              :  class(gruns_t),intent(inout) :: gruns
     660              : 
     661              : !Local variables-------------------------------
     662              :  integer :: ii
     663              : ! ************************************************************************
     664              : 
     665            1 :  if (allocated(gruns%ifc_vol)) then
     666            4 :    do ii=1,size(gruns%cryst_vol)
     667            4 :      call gruns%cryst_vol(ii)%free()
     668              :    end do
     669            4 :    ABI_FREE(gruns%cryst_vol)
     670              :  end if
     671              : 
     672            1 :  if (allocated(gruns%ddb_vol)) then
     673            4 :    do ii=1,size(gruns%ddb_vol)
     674            4 :      call gruns%ddb_vol(ii)%free()
     675              :    end do
     676            4 :    ABI_FREE(gruns%ddb_vol)
     677              :  end if
     678              : 
     679            1 :  if (allocated(gruns%ifc_vol)) then
     680            4 :    do ii=1,size(gruns%ifc_vol)
     681            4 :      call gruns%ifc_vol(ii)%free()
     682              :    end do
     683            4 :    ABI_FREE(gruns%ifc_vol)
     684              :  end if
     685              : 
     686            1 : end subroutine gruns_free
     687              : !!***
     688              : 
     689              : !----------------------------------------------------------------------
     690              : 
     691              : !!****f* m_gruneisen/gruns_anaddb
     692              : !! NAME
     693              : !!  gruns_anaddb
     694              : !!
     695              : !! FUNCTION
     696              : !!  Driver routine called in anaddb to compute Gruneisen parameters.
     697              : !!
     698              : !! INPUTS
     699              : !!  inp<anaddb_dataset_type: :: anaddb input variables.
     700              : !!  prefix=Prefix for output files
     701              : !!  comm=MPI communicator
     702              : !!
     703              : !! OUTPUT
     704              : !!  Only writing.
     705              : !!
     706              : !! SOURCE
     707              : 
     708            1 : subroutine gruns_anaddb(inp, comm)
     709              : 
     710              : !Arguments ------------------------------------
     711              :  integer,intent(in) :: comm
     712              :  type(anaddb_dataset_type),intent(inout) :: inp
     713              : 
     714              : !Local variables-------------------------------
     715              : !scalars
     716              :  integer,parameter :: master=0
     717              :  integer :: ii,nprocs,my_rank,ncid,iv0, ncerr
     718              :  real(dp) :: cpu,wall,gflops
     719              :  type(gruns_t),target :: gruns
     720            1 :  type(kpath_t) :: qpath
     721              : ! ************************************************************************
     722              : 
     723            1 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     724              : 
     725            1 :  ABI_CHECK(inp%ifcflag == 1, "Gruneisen requires ifcflag == 1")
     726              : 
     727            1 :  call cwtime(cpu, wall, gflops, "start")
     728              : 
     729            1 :  gruns = gruns_new(inp%gruns_ddbs, inp, comm)
     730            1 :  iv0 = gruns%iv0
     731              : 
     732            1 :  ncid = nctk_noid
     733            1 :  if (my_rank == master) then
     734            1 :    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(inp%filename_output, "_GRUNS.nc"), xmpi_comm_self), "Creating _GRUNS.nc")
     735              : 
     736              :    ! Write structure corresponding to iv0
     737            1 :    NCF_CHECK(gruns%cryst_vol(iv0)%ncwrite(ncid))
     738              : 
     739              :    ! Add important dimensions and additional metadata.
     740              :    ncerr = nctk_def_dims(ncid, [ &
     741              :      nctkdim_t("gruns_nvols", gruns%nvols), &
     742            3 :      nctkdim_t('number_of_phonon_modes', gruns%natom3)], defmode=.True.)
     743            1 :    NCF_CHECK(ncerr)
     744            2 :    ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: "gruns_iv0"])
     745            1 :    NCF_CHECK(ncerr)
     746              : 
     747              :    ! Add lattice parameters and positions of the `gruns_nvols` structures so
     748              :    ! that we can easily reconstruct structure objects in AbiPy.
     749              :    ncerr = nctk_def_arrays(ncid, [ &
     750              :      nctkarr_t("gruns_rprimd", "dp", "three, three, gruns_nvols"), &
     751              :      nctkarr_t("gruns_xred", "dp", "three, number_of_atoms, gruns_nvols") &
     752            3 :    ])
     753            1 :    NCF_CHECK(ncerr)
     754              : 
     755            3 :    ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: "gruns_iv0"], [iv0], datamode=.True.)
     756            1 :    NCF_CHECK(ncerr)
     757              : 
     758            4 :    do ii=1,gruns%nvols
     759           12 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_rprimd"), gruns%cryst_vol(ii)%rprimd, start=[1,1,ii]))
     760           13 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_xred"), gruns%cryst_vol(ii)%xred, start=[1,1,ii]))
     761              :    end do
     762              : 
     763              :    !call phonons_ncwrite(ncid,natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart)
     764              :    !NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'atomic_mass_units'), ddb%amu))
     765              :  end if
     766              : 
     767              :  ! Compute gruneisen parameters on the q-mesh.
     768            4 :  if (all(inp%ng2qpt /= 0)) then
     769            1 :    call gruns_qmesh(gruns, inp%filename_output, inp%dosdeltae, inp%ng2qpt, 1, inp%q2shft, ncid, comm)
     770              :  else
     771            0 :    ABI_WARNING("Cannot compute Gruneisen parameters on q-mesh because ng2qpt == 0")
     772              :  end if
     773              : 
     774              :  ! Compute gruneisen on the q-path.
     775            1 :  if (inp%nqpath /= 0) then
     776            1 :    call qpath%init(inp%qpath, gruns%cryst_vol(iv0)%gprimd, inp%ndivsm)
     777            1 :    call gruns_qpath(gruns, inp%filename_output, qpath, ncid, comm)
     778            1 :    call qpath%free()
     779              :  else
     780            0 :    ABI_WARNING("Cannot compute Gruneisen parameters on q-path because nqpath == 0")
     781              :  end if
     782              : 
     783              :  ! Compute speed of sound for V0.
     784            1 :  if (inp%vs_qrad_tolkms(1) > zero) then
     785            1 :    call gruns%ifc_vol(iv0)%speedofsound(gruns%cryst_vol(iv0), inp%vs_qrad_tolkms, ncid, comm)
     786              :  end if
     787              : 
     788              :  ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
     789            1 :  if (my_rank == master .and. inp%nph2l /= 0 .and. inp%ifcflag == 1) then
     790            0 :    call gruns%ifc_vol(iv0)%calcnwrite_nana_terms(gruns%cryst_vol(iv0), inp%nph2l, inp%qph2l, inp%qnrml2, ncid)
     791              :  end if
     792              : 
     793              :  if (my_rank == master) then
     794            1 :    NCF_CHECK(nf90_close(ncid))
     795              :  end if
     796              : 
     797            1 :  call gruns_free(gruns)
     798            1 :  call cwtime_report("gruns_anaddb", cpu, wall, gflops)
     799              : 
     800            1 : end subroutine gruns_anaddb
     801              : !!***
     802              : 
     803              : !----------------------------------------------------------------------
     804              : 
     805            0 : end module m_gruneisen
        

Generated by: LCOV version 2.3-1