TABLE OF CONTENTS


ABINIT/m_gruneisen [ Modules ]

[ Top ] [ Modules ]

NAME

  m_gruneisen

FUNCTION

  Objects and methods to compute Gruneisen parameters with central finite differences
  of dynamical matrices obtained with different unit cell volumes.

COPYRIGHT

 Copyright (C) 2011-2024 ABINIT group (MG)
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .

SOURCE

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 #ifdef HAVE_NETCDF
37  use netcdf
38 #endif
39 
40  use m_io_tools,            only : get_unit, open_file
41  use m_time,                only : cwtime, cwtime_report
42  use m_fstrings,            only : sjoin, itoa, ltoa, ftoa, strcat
43  use m_numeric_tools,       only : central_finite_diff, arth
44  use m_kpts,                only : kpts_ibz_from_kptrlatt, tetra_from_kptrlatt
45  use m_bz_mesh,             only : kpath_t, kpath_new
46  use m_anaddb_dataset,      only : anaddb_dataset_type
47  use m_dynmat,              only : massmult_and_breaksym, dfpt_phfrq, gtdyn9
48 
49  implicit none
50 
51  private

m_gruneisen/gruns_anaddb [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_anaddb

FUNCTION

  Driver routine called in anaddb to compute Gruneisen parameters.

INPUTS

  inp<anaddb_dataset_type: :: anaddb input variables.
  prefix=Prefix for output files
  comm=MPI communicator

OUTPUT

  Only writing.

SOURCE

717 subroutine gruns_anaddb(inp, prefix, comm)
718 
719 !Arguments ------------------------------------
720  integer,intent(in) :: comm
721  character(len=*),intent(in) :: prefix
722  type(anaddb_dataset_type) :: inp
723 
724 !Local variables-------------------------------
725 !scalars
726  integer,parameter :: master=0
727  integer :: ii,nprocs,my_rank,ncid,iv0
728 #ifdef HAVE_NETCDF
729  integer :: ncerr
730 #endif
731  real(dp) :: cpu,wall,gflops
732  type(gruns_t),target :: gruns
733  type(kpath_t) :: qpath
734 
735 ! ************************************************************************
736 
737  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
738 
739  ABI_CHECK(inp%ifcflag == 1, "Gruneisen requires ifcflag == 1")
740 
741  call cwtime(cpu, wall, gflops, "start")
742 
743  gruns = gruns_new(inp%gruns_ddbs, inp, comm)
744  iv0 = gruns%iv0
745 
746  ncid = nctk_noid
747 #ifdef HAVE_NETCDF
748  if (my_rank == master) then
749    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_GRUNS.nc"), xmpi_comm_self), "Creating _GRUNS.nc")
750 
751    ! Write structure corresponding to iv0
752    NCF_CHECK(gruns%cryst_vol(iv0)%ncwrite(ncid))
753 
754    ! Add important dimensions and additional metadata.
755    ncerr = nctk_def_dims(ncid, [ &
756      nctkdim_t("gruns_nvols", gruns%nvols), &
757      nctkdim_t('number_of_phonon_modes', gruns%natom3)], defmode=.True.)
758    NCF_CHECK(ncerr)
759    ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: "gruns_iv0"])
760    NCF_CHECK(ncerr)
761 
762    ! Add lattice parameters and positions of the `gruns_nvols` structures so
763    ! that we can easily reconstruct structure objects in AbiPy.
764    ncerr = nctk_def_arrays(ncid, [ &
765      nctkarr_t("gruns_rprimd", "dp", "three, three, gruns_nvols"), &
766      nctkarr_t("gruns_xred", "dp", "three, number_of_atoms, gruns_nvols") &
767    ])
768    NCF_CHECK(ncerr)
769 
770    ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: "gruns_iv0"], [iv0], datamode=.True.)
771    NCF_CHECK(ncerr)
772 
773    do ii=1,gruns%nvols
774      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_rprimd"), gruns%cryst_vol(ii)%rprimd, start=[1,1,ii]))
775      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_xred"), gruns%cryst_vol(ii)%xred, start=[1,1,ii]))
776    end do
777 
778    !call phonons_ncwrite(ncid,natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart)
779    !NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'atomic_mass_units'), ddb%amu))
780  end if
781 #endif
782 
783  ! Compute gruneisen parameters on the q-mesh.
784  if (all(inp%ng2qpt /= 0)) then
785    call gruns_qmesh(gruns, prefix, inp%dosdeltae, inp%ng2qpt, 1, inp%q2shft, ncid, comm)
786  else
787    ABI_WARNING("Cannot compute Gruneisen parameters on q-mesh because ng2qpt == 0")
788  end if
789 
790  ! Compute gruneisen on the q-path.
791  if (inp%nqpath /= 0) then
792    qpath = kpath_new(inp%qpath, gruns%cryst_vol(iv0)%gprimd, inp%ndivsm)
793    call gruns_qpath(gruns, prefix, qpath, ncid, comm)
794    call qpath%free()
795  else
796    ABI_WARNING("Cannot compute Gruneisen parameters on q-path because nqpath == 0")
797  end if
798 
799  ! Compute speed of sound for V0.
800  if (inp%vs_qrad_tolkms(1) > zero) then
801    call gruns%ifc_vol(iv0)%speedofsound(gruns%cryst_vol(iv0), inp%vs_qrad_tolkms, ncid, comm)
802  end if
803 
804  ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
805  if (my_rank == master .and. inp%nph2l /= 0 .and. inp%ifcflag == 1) then
806    call gruns%ifc_vol(iv0)%calcnwrite_nana_terms(gruns%cryst_vol(iv0), inp%nph2l, inp%qph2l, inp%qnrml2, ncid)
807  end if
808 
809 #ifdef HAVE_NETCDF
810  if (my_rank == master) then
811    NCF_CHECK(nf90_close(ncid))
812  end if
813 #endif
814 
815  call gruns_free(gruns)
816  call cwtime_report("gruns_anaddb", cpu, wall, gflops)
817 
818 end subroutine gruns_anaddb

m_gruneisen/gruns_fourq [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_fourq

FUNCTION

  Compute gruneisen parameters at an arbitrary q-point.

INPUTS

  qpt(3)=q-point in reduced coordinates.

OUTPUT

  wvols(3*natom, nvols) = Phonon frequencies for the different volumen.
  gvals(3*natom)=Gruneisen parameters evaluated at V0.
  dwdq(3,3*natom)=Group velocities at V0 in Cartesian coordinates.
  phdispl_cart(2, natom3, natom3, nvols)=Phonon displacement in Cartesian coordinates for the different volumes

NOTES

  The Gruneisen parameter is given by:

     gamma(q,nu) = - (V / w(q,nu)) dw(q,nu)/dV

  Using w*2 = <u|D|u> and the Hellmann-Feynmann theorem, one obtains:

     gamma(q,nu) = - (V / 2 w(q,nu)**2) <u(q,nu)|dD(q)/dV|u(q,nu)>

  The derivative dD/dV is computed via central finite difference.

SOURCE

238 subroutine gruns_fourq(gruns, qpt, wvols, gvals, dwdq, phdispl_cart)
239 
240 !Arguments ------------------------------------
241 !scalars
242  type(gruns_t),intent(in) :: gruns
243 !arrays
244  real(dp),intent(in) :: qpt(3)
245  real(dp),intent(out) :: wvols(gruns%natom3,gruns%nvols),gvals(gruns%natom3),dwdq(3,gruns%natom3)
246  real(dp),intent(out) :: phdispl_cart(2, gruns%natom3, gruns%natom3, gruns%nvols)
247 
248 !Local variables-------------------------------
249 !scalars
250  integer :: ivol,natom3,nu
251  real(dp) :: fact
252 !arrays
253  real(dp) :: dot(2)
254  real(dp) :: eigvec(2,gruns%natom3,gruns%natom3,gruns%nvols),d2cart(2,gruns%natom3,gruns%natom3,gruns%nvols)
255  real(dp) :: dddv(2,gruns%natom3,gruns%natom3)
256  real(dp) :: omat(2,gruns%natom3, gruns%natom3)
257 
258 ! ************************************************************************
259 
260  natom3 = gruns%natom3
261  do ivol=1,gruns%nvols
262    if (ivol == gruns%iv0) then
263      ! Compute group velocities for V=V0
264      call gruns%ifc_vol(ivol)%fourq(gruns%cryst_vol(ivol), qpt, wvols(:,ivol), phdispl_cart(:,:,:,ivol), &
265                     out_d2cart=d2cart(:,:,:,ivol), out_eigvec=eigvec(:,:,:,ivol), dwdq=dwdq)
266    else
267      call gruns%ifc_vol(ivol)%fourq(gruns%cryst_vol(ivol), qpt, wvols(:,ivol), phdispl_cart(:,:,:,ivol), &
268                     out_d2cart=d2cart(:,:,:,ivol), out_eigvec=eigvec(:,:,:,ivol))
269    end if
270 
271    call massmult_and_breaksym(gruns%cryst_vol(ivol)%natom, gruns%cryst_vol(ivol)%ntypat, &
272      gruns%cryst_vol(ivol)%typat, gruns%ifc_vol(ivol)%amu, d2cart(:,:,:,ivol))
273 
274    !call zgemm('N','N',natom3,natom3,natom3,cone,d2cart(:,:,:,ivol),natom3,eigvec(:,:,:,ivol),natom3,czero,omat,natom3)
275    !do nu=1,natom3
276    !  write(std_out,*)"H|psi> - w**2 |psi>",maxval(abs(omat(:,:,nu) - wvols(nu,ivol) ** 2 * eigvec(:,:,nu,ivol)))
277    !end do
278  end do
279 
280  ! Compute dD(q)/dV with central finite difference.
281  dddv = zero
282  do ivol=1,gruns%nvols
283    fact = central_finite_diff(1, ivol, gruns%nvols)
284    if (fact /= zero) dddv = dddv + fact * d2cart(:,:,:,ivol)
285  end do
286  dddv = dddv / gruns%delta_vol
287 
288  ! Compute -V0/(2w(q)**2) <u(q)|dD(q)/dq|u(q)>
289  call zgemm('N','N',natom3,natom3,natom3,cone,dddv,natom3,eigvec(:,:,:,gruns%iv0),natom3,czero,omat,natom3)
290  do nu=1,natom3
291    if (abs(wvols(nu, gruns%iv0)) > tol12) then
292      dot = cg_zdotc(natom3, eigvec(1,1,nu, gruns%iv0), omat(1,1,nu))
293      ! Must change sign if we have a purely imaginary solution i.e. z = iw
294      gvals(nu) = -sign(one, wvols(nu, gruns%iv0)) * gruns%v0 * dot(1) / (two * wvols(nu, gruns%iv0)**2)
295    else
296      gvals(nu) = zero
297    end if
298  end do
299 
300 end subroutine gruns_fourq

m_gruneisen/gruns_free [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_free

FUNCTION

  Free dynamic memory.

SOURCE

662 subroutine gruns_free(gruns)
663 
664 !Arguments ------------------------------------
665 !array
666  type(gruns_t),intent(inout) :: gruns
667 
668 !Local variables-------------------------------
669 !scalars
670  integer :: ii
671 
672 ! ************************************************************************
673 
674  if (allocated(gruns%ifc_vol)) then
675    do ii=1,size(gruns%cryst_vol)
676      call gruns%cryst_vol(ii)%free()
677    end do
678    ABI_FREE(gruns%cryst_vol)
679  end if
680 
681  if (allocated(gruns%ddb_vol)) then
682    do ii=1,size(gruns%ddb_vol)
683      call gruns%ddb_vol(ii)%free()
684    end do
685    ABI_FREE(gruns%ddb_vol)
686  end if
687 
688  if (allocated(gruns%ifc_vol)) then
689    do ii=1,size(gruns%ifc_vol)
690      call gruns%ifc_vol(ii)%free()
691    end do
692    ABI_FREE(gruns%ifc_vol)
693  end if
694 
695 end subroutine gruns_free

m_gruneisen/gruns_new [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_new

FUNCTION

  Construct new object from a list of DDB files.

INPUTS

  ddb_filepaths(:)=Paths of the DDB files (must be ordered by volume)
  inp<anaddb_dataset_type>=Anaddb dataset with input variables
  comm=MPI communicator

SOURCE

121 type(gruns_t) function gruns_new(ddb_filepaths, inp, comm) result(new)
122 
123 !Arguments ------------------------------------
124  integer,intent(in) :: comm
125  type(anaddb_dataset_type),intent(in) :: inp
126 !arrays
127  character(len=*),intent(in) :: ddb_filepaths(:)
128 
129 !Local variables-------------------------------
130  integer,parameter :: master=0
131  integer :: ivol,iblock,natom,ddbun, nprocs,my_rank,ierr
132  character(len=500) :: msg
133  type(ddb_hdr_type) :: ddb_hdr
134 !arrays
135  real(dp) :: dielt(3,3)
136  real(dp),allocatable :: zeff(:,:,:), qdrp_cart(:,:,:,:)
137 
138 ! ************************************************************************
139 
140  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
141 
142  new%nvols = size(ddb_filepaths)
143  ABI_MALLOC(new%cryst_vol, (new%nvols))
144  ABI_MALLOC(new%ddb_vol, (new%nvols))
145  ABI_MALLOC(new%ifc_vol, (new%nvols))
146 
147  call wrtout(ab_out, "Computation of Gruneisen parameter with central finite difference:")
148 
149  ddbun = get_unit()
150  do ivol=1,new%nvols
151    call wrtout(ab_out, sjoin(" Reading DDB file:", ddb_filepaths(ivol)))
152 
153    call new%ddb_vol(ivol)%from_file(ddb_filepaths(ivol), ddb_hdr, new%cryst_vol(ivol), comm)
154    call new%ddb_vol(ivol)%set_brav(inp%brav)
155    natom = ddb_hdr%natom
156    call ddb_hdr%free()
157 
158    if (my_rank == master) then
159      call new%cryst_vol(ivol)%print(header=sjoin("Structure for ivol:", itoa(ivol)), unit=ab_out, prtvol=-1)
160    end if
161 
162    ! Get Dielectric Tensor and Effective Charges
163    ! (initialized to one_3D and zero if the derivatives are not available in the DDB file)
164    ABI_MALLOC(zeff, (3,3,natom))
165    ABI_CALLOC(qdrp_cart, (3,3,3,natom))
166    iblock = new%ddb_vol(ivol)%get_dielt_zeff(new%cryst_vol(ivol), inp%rfmeth, inp%chneut, inp%selectz, dielt, zeff)
167    if (iblock == 0) then
168      call wrtout(ab_out, sjoin("- Cannot find dielectric tensor and Born effective charges in DDB file:", ddb_filepaths(ivol)))
169      call wrtout(ab_out, "Values initialized with zeros")
170    else
171      call wrtout(ab_out, sjoin("- Found dielectric tensor and Born effective charges in DDB file:", ddb_filepaths(ivol)))
172    end if
173 
174    call new%ifc_vol(ivol)%init(new%cryst_vol(ivol), new%ddb_vol(ivol),&
175      inp%brav,inp%asr,inp%symdynmat,inp%dipdip,inp%rfmeth,inp%ngqpt(1:3),inp%nqshft,inp%q1shft,dielt,zeff,&
176      qdrp_cart,inp%nsphere,inp%rifcsph,inp%prtsrlr,inp%enunit,comm)
177    ABI_FREE(zeff)
178    ABI_FREE(qdrp_cart)
179  end do
180 
181  ! Consistency check
182  ! TODO: Add more tests.
183  ABI_CHECK(any(new%nvols == [3, 5, 7, 9]), "Central finite difference requires [3,5,7,9] DDB files")
184 
185  new%natom3 = 3 * new%cryst_vol(1)%natom
186  new%iv0 = 1 + new%nvols / 2
187  new%v0 = new%cryst_vol(new%iv0)%ucvol
188  new%delta_vol = new%cryst_vol(new%iv0+1)%ucvol - new%cryst_vol(new%iv0)%ucvol
189 
190  ierr = 0
191  do ivol=1,new%nvols
192    if (abs(new%cryst_vol(1)%ucvol + new%delta_vol * (ivol-1) - new%cryst_vol(ivol)%ucvol) > tol4) then
193       write(std_out,*)"ucvol, delta_vol, diff_vol", new%cryst_vol(ivol)%ucvol, new%delta_vol, &
194         abs(new%cryst_vol(1)%ucvol + new%delta_vol * (ivol-1) - new%cryst_vol(ivol)%ucvol)
195       ierr = ierr + 1
196    end if
197  end do
198  if (ierr /= 0) then
199    msg = ltoa([(new%cryst_vol(ivol)%ucvol, ivol=1,new%nvols)])
200    ABI_ERROR(sjoin("Gruneisen calculations requires linear mesh of volumes but received:", msg))
201  end if
202 
203 end function gruns_new

m_gruneisen/gruns_qmesh [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_qmesh

FUNCTION

  Compute gruneisen parameters and group velocities on a q-mesh.
  Save results to file.

INPUTS

  prefix=Prefix for output files.
  dosdeltae=Step for the frequency mesh.
  ngqpt(3)=q-mesh divisions
  nshiftq=Number of shifts used to generated the ab-initio q-mesh.
  shiftq(3,nshiftq)=The shifts of the ab-initio q-mesh.
  ncid=netcdf file id.
  comm=MPI communicator

OUTPUT

SOURCE

448 subroutine gruns_qmesh(gruns, prefix, dosdeltae, ngqpt, nshiftq, shiftq, ncid, comm)
449 
450 !Arguments ------------------------------------
451 !scalars
452  integer,intent(in) :: nshiftq,ncid,comm
453  real(dp),intent(in) :: dosdeltae !,dossmear
454  type(gruns_t),intent(in) :: gruns
455  character(len=*),intent(in) :: prefix
456 !arrays
457  integer,intent(in) :: ngqpt(3)
458  real(dp),intent(in) :: shiftq(3,nshiftq)
459 
460 !Local variables-------------------------------
461 !scalars
462  integer,parameter :: master=0,qptopt1=1,bcorr0=0
463  integer :: nprocs,my_rank,iqibz,nqbz,nqibz,ierr,ii,nu,ncerr,nomega,cnt,unt,io
464  real(dp) :: gavg,omega_min,omega_max,v2
465  type(htetra_t) :: tetra
466  character(len=500) :: msg
467 !arrays
468  integer :: qptrlatt(3,3)
469  real(dp),allocatable :: gvals_qibz(:,:),wvols_qibz(:,:,:),dwdq_qibz(:,:,:)
470  real(dp),allocatable :: qibz(:,:),qbz(:,:),wtq(:)
471  real(dp),allocatable :: wdt(:,:),wdos(:,:),grdos(:,:),gr2dos(:,:),wibz(:),omega_mesh(:)
472  real(dp),allocatable :: vdos(:,:),v2dos(:,:)
473  real(dp),allocatable :: phdispl_cart_qibz(:,:,:,:,:)
474 
475 ! ************************************************************************
476 
477  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
478 
479  write(msg,'(a,(80a),4a)')ch10,('=',ii=1,80),ch10,ch10,' Calculation of Gruneisen DOSes ',ch10
480  call wrtout(std_out, msg)
481 
482  ! Generate the q-mesh by finding the IBZ and the corresponding weights.
483  ABI_CHECK(all(ngqpt > 0), sjoin("invalid ngqpt:", ltoa(ngqpt)))
484  qptrlatt = 0
485  do ii=1,3
486    qptrlatt(ii,ii) = ngqpt(ii)
487  end do
488 
489  ! Get IBZ and BZ.
490  call kpts_ibz_from_kptrlatt(gruns%cryst_vol(gruns%iv0), qptrlatt, qptopt1, nshiftq, shiftq, &
491    nqibz, qibz, wtq, nqbz, qbz)
492 
493  ! Build tetrahedra
494  tetra = tetra_from_kptrlatt(gruns%cryst_vol(gruns%iv0), qptopt1, qptrlatt, nshiftq, shiftq, nqibz, qibz, comm, msg, ierr)
495  if (ierr /= 0) ABI_ERROR(msg)
496 
497  ABI_CALLOC(wvols_qibz, (gruns%natom3, gruns%nvols, nqibz))
498  ABI_CALLOC(gvals_qibz, (gruns%natom3, nqibz))
499  ABI_CALLOC(dwdq_qibz, (3, gruns%natom3, nqibz))
500  ABI_CALLOC(phdispl_cart_qibz, (2, gruns%natom3, gruns%natom3, gruns%nvols, nqibz))
501 
502  gavg = zero
503  do iqibz=1,nqibz
504    if (mod(iqibz, nprocs) /= my_rank) cycle ! mpi-parallelism
505    call gruns_fourq(gruns, qibz(:,iqibz), wvols_qibz(:,:,iqibz), gvals_qibz(:,iqibz), &
506                     dwdq_qibz(:,:,iqibz), phdispl_cart_qibz(:,:,:,:,iqibz))
507    gavg = gavg + wtq(iqibz) * sum(gvals_qibz(:,iqibz))
508  end do
509  gavg = gavg / gruns%natom3
510 
511  call xmpi_sum(gavg, comm, ierr)
512  call xmpi_sum(wvols_qibz, comm, ierr)
513  call xmpi_sum(gvals_qibz, comm, ierr)
514  call xmpi_sum(dwdq_qibz, comm, ierr)
515  call xmpi_sum(phdispl_cart_qibz, comm, ierr)
516 
517  omega_min = gruns%ifc_vol(gruns%iv0)%omega_minmax(1)
518  omega_max = gruns%ifc_vol(gruns%iv0)%omega_minmax(2)
519  nomega = nint((omega_max - omega_min) / dosdeltae) + 1
520  nomega = max(6, nomega) ! Ensure Simpson integration will be ok
521 
522  ABI_MALLOC(omega_mesh, (nomega))
523  omega_mesh = arth(omega_min, dosdeltae, nomega)
524  omega_max = omega_mesh(nomega)
525  !write(std_out,*)"hello",omega_min,omega_max,dosdeltae,(omega_max-omega_min) / (nomega-1)
526  ABI_MALLOC(wibz, (nqibz))
527  ABI_MALLOC(wdt, (nomega, 2))
528  ABI_CALLOC(wdos, (nomega, 2))
529  ABI_CALLOC(grdos, (nomega, 2))
530  ABI_CALLOC(gr2dos, (nomega, 2))
531  ABI_CALLOC(vdos, (nomega, 2))
532  ABI_CALLOC(v2dos, (nomega, 2))
533 
534  ! Compute DOSes.
535  cnt = 0
536  do iqibz=1,nqibz
537    do nu=1,gruns%natom3
538      cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! mpi-parallelism
539      wibz = wvols_qibz(nu, gruns%iv0, :)
540      call tetra%get_onewk(iqibz,bcorr0,nomega,nqibz,wibz,omega_min,omega_max,one,wdt)
541      wdt = wdt*wtq(iqibz)
542      wdos = wdos + wdt
543      grdos = grdos + wdt * gvals_qibz(nu,iqibz)
544      gr2dos = gr2dos + wdt * gvals_qibz(nu,iqibz) ** 2
545      v2 = sum(dwdq_qibz(1:3,nu,iqibz) ** 2)
546      vdos = vdos + wdt * sqrt(v2)
547      v2dos = v2dos + wdt * v2
548    end do
549  end do
550 
551  call xmpi_sum(wdos, comm, ierr)
552  call xmpi_sum(grdos, comm, ierr)
553  call xmpi_sum(gr2dos, comm, ierr)
554  call xmpi_sum(vdos, comm, ierr)
555  call xmpi_sum(v2dos, comm, ierr)
556 
557  if (my_rank == master) then
558    call wrtout(ab_out, sjoin(" Average Gruneisen parameter:", ftoa(gavg, fmt="f8.5")))
559 
560    ! Write text files with Gruneisen and DOSes.
561    if (open_file(strcat(prefix, "_GRUNS_DOS"), msg, newunit=unt, form="formatted", action="write") /= 0) then
562      ABI_ERROR(msg)
563    end if
564    write(unt,'(a)')'# Phonon density of states, Gruneisen DOS and phonon group velocity DOS'
565    write(unt,'(a)')"# Energy in Hartree, DOS in states/Hartree"
566    write(unt,'(a,i0)')'# Tetrahedron method with nqibz= ',nqibz
567    write(unt,"(a,f8.5)")"# Average Gruneisen parameter:", gavg
568    write(unt,'(5a)') &
569      "# 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"
570    do io=1,nomega
571      write(unt, "(11es17.8)")omega_mesh(io), &
572        wdos(io,1), grdos(io,1), gr2dos(io,1), vdos(io,1), v2dos(io,1), &
573        wdos(io,2), grdos(io,2), gr2dos(io,2), vdos(io,2), v2dos(io,2)
574    end do
575    close(unt)
576  end if
577 
578 #ifdef HAVE_NETCDF
579  ! Write netcdf files.
580  if (my_rank == master .and. ncid /= nctk_noid) then
581    ncerr = nctk_def_dims(ncid, [ &
582      nctkdim_t("gruns_nqibz", nqibz), nctkdim_t('gruns_nshiftq', nshiftq), &
583      nctkdim_t('gruns_nomega', nomega)], defmode=.True.)
584    NCF_CHECK(ncerr)
585 
586    ncerr = nctk_def_arrays(ncid, [ &
587     ! q-point sampling in IBZ,
588     nctkarr_t("gruns_qptrlatt", "int", "three, three"), &
589     nctkarr_t("gruns_shiftq", "dp", "three, gruns_nshiftq"), &
590     nctkarr_t("gruns_qibz", "dp", "three, gruns_nqibz"), &
591     nctkarr_t("gruns_wtq", "dp", "gruns_nqibz"), &
592     ! gruneisen parameters in IBZ
593     ! phonon frequencies at the different volumes,
594     ! group velocities at V0 in Cartesian coordinates.
595     nctkarr_t("gruns_gvals_qibz", "dp", "number_of_phonon_modes, gruns_nqibz"), &
596     nctkarr_t("gruns_wvols_qibz", "dp", "number_of_phonon_modes, gruns_nvols, gruns_nqibz"), &
597     nctkarr_t("gruns_dwdq_qibz", "dp", "three, number_of_phonon_modes, gruns_nqibz"), &
598     ! displacements for the different volumes.
599     nctkarr_t("gruns_phdispl_cart_qibz", "dp", &
600         "two, number_of_phonon_modes, number_of_phonon_modes, gruns_nvols, gruns_nqibz"), &
601     ! DOSes and IDOSes
602     nctkarr_t("gruns_omega_mesh", "dp", "gruns_nomega"), &
603     nctkarr_t("gruns_wdos", "dp", "gruns_nomega, two"), &
604     nctkarr_t("gruns_grdos", "dp", "gruns_nomega, two"), &
605     nctkarr_t("gruns_gr2dos", "dp", "gruns_nomega, two"), &
606     nctkarr_t("gruns_v2dos", "dp", "gruns_nomega, two"), &
607     nctkarr_t("gruns_vdos", "dp", "gruns_nomega, two") &
608    ])
609    NCF_CHECK(ncerr)
610 
611    ! Write data.
612    NCF_CHECK(nctk_set_datamode(ncid))
613    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qptrlatt"), qptrlatt))
614    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_shiftq"), shiftq))
615    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qibz"), qibz))
616    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wtq"), wtq))
617    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gvals_qibz"), gvals_qibz))
618    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wvols_qibz"), wvols_qibz))
619    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_dwdq_qibz"), dwdq_qibz))
620    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_phdispl_cart_qibz"), phdispl_cart_qibz))
621    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_omega_mesh"), omega_mesh))
622    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wdos"), wdos))
623    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_grdos"), grdos))
624    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gr2dos"), gr2dos))
625    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_v2dos"), v2dos))
626    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_vdos"), vdos))
627  end if
628 #endif
629 
630  ABI_FREE(qibz)
631  ABI_FREE(wtq)
632  ABI_FREE(qbz)
633  ABI_FREE(wvols_qibz)
634  ABI_FREE(gvals_qibz)
635  ABI_FREE(dwdq_qibz)
636  ABI_FREE(phdispl_cart_qibz)
637  ABI_FREE(omega_mesh)
638  ABI_FREE(wibz)
639  ABI_FREE(wdt)
640  ABI_FREE(wdos)
641  ABI_FREE(grdos)
642  ABI_FREE(gr2dos)
643  ABI_FREE(v2dos)
644  ABI_FREE(vdos)
645 
646  call tetra%free()
647 
648 end subroutine gruns_qmesh

m_gruneisen/gruns_qpath [ Functions ]

[ Top ] [ m_gruneisen ] [ Functions ]

NAME

  gruns_qpath

FUNCTION

  Compute gruneisen parameters and group velocities on a q-path
  Write results to file.

INPUTS

  prefix=Prefix for output files.
  qpath<kpath_t>=Object describing the q-path.
  ncid=netcdf file id.
  comm=MPI communicator.

OUTPUT

  Only writing

SOURCE

324 subroutine gruns_qpath(gruns, prefix, qpath, ncid, comm)
325 
326 !Arguments ------------------------------------
327 !scalars
328  integer,intent(in) :: ncid,comm
329  type(gruns_t),intent(in) :: gruns
330  type(kpath_t),intent(in) :: qpath
331  character(len=*),intent(in) :: prefix
332 
333 !Local variables-------------------------------
334 !scalars
335  integer,parameter :: master=0
336  integer :: nprocs,my_rank,iqpt,ierr,ncerr,unt,iv0,nu,ii
337  character(len=500) :: msg
338 !arrays
339  real(dp),allocatable :: gvals_qpath(:,:),wvols_qpath(:,:,:),dwdq_qpath(:,:,:)
340  real(dp),allocatable :: phdispl_cart_qpath(:,:,:,:,:)
341 
342 ! ************************************************************************
343 
344  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
345 
346  write(msg,'(a,(80a),4a)')ch10,('=',ii=1,80),ch10,ch10,' Calculation of Gruneisen parameters along q-path ',ch10
347  call wrtout(std_out, msg)
348  !call wrtout(ab_out, msg)
349 
350  iv0 = gruns%iv0
351  ABI_CALLOC(wvols_qpath, (gruns%natom3, gruns%nvols, qpath%npts))
352  ABI_CALLOC(gvals_qpath, (gruns%natom3, qpath%npts))
353  ABI_CALLOC(dwdq_qpath, (3, gruns%natom3, qpath%npts))
354  ABI_CALLOC(phdispl_cart_qpath, (2, gruns%natom3, gruns%natom3, gruns%nvols, qpath%npts))
355 
356  do iqpt=1,qpath%npts
357    if (mod(iqpt, nprocs) /= my_rank) cycle ! mpi-parallelism
358    call gruns_fourq(gruns, qpath%points(:,iqpt), wvols_qpath(:,:,iqpt), gvals_qpath(:,iqpt), &
359                     dwdq_qpath(:,:,iqpt), phdispl_cart_qpath(:,:,:,:,iqpt))
360  end do
361 
362  call xmpi_sum(wvols_qpath, comm, ierr)
363  call xmpi_sum(gvals_qpath, comm, ierr)
364  call xmpi_sum(dwdq_qpath, comm, ierr)
365  call xmpi_sum(phdispl_cart_qpath, comm, ierr)
366 
367  ! Write text files with phonon frequencies and gruneisen on the path.
368  if (my_rank == master) then
369    if (open_file(strcat(prefix, "_GRUNS_QPATH"), msg, newunit=unt, form="formatted", action="write") /= 0) then
370      ABI_ERROR(msg)
371    end if
372    write(unt,'(a)')'# Phonon band structure, Gruneisen parameters and group velocity'
373    write(unt,'(a)')"# Energy in Hartree, DOS in states/Hartree"
374    call qpath%print(unit=unt, pre="#")
375    write(unt,'(5a)')&
376      "# phfreq(mode=1) gruneisen(mode=1) velocity(mode=1)    phfreq(mode=2) gruneisen(mode=2) velocity(mode=2)   ..."
377    do iqpt=1,qpath%npts
378      do nu=1,gruns%natom3
379        write(unt, "(3es17.8)", advance="no") &
380          wvols_qpath(nu, iv0, iqpt), gvals_qpath(nu, iqpt), sum(dwdq_qpath(1:3, nu, iqpt) ** 2)
381      end do
382      write(unt, "(a)")" "
383    end do
384    close(unt)
385  end if
386 
387 #ifdef HAVE_NETCDF
388  if (my_rank == master .and. ncid /= nctk_noid) then
389    ncerr = nctk_def_dims(ncid, [nctkdim_t("gruns_nqpath", qpath%npts)], defmode=.True.)
390    NCF_CHECK(ncerr)
391 
392    ncerr = nctk_def_arrays(ncid, [ &
393      ! q-points of the path
394      nctkarr_t("gruns_qpath", "dp", "three, gruns_nqpath"), &
395      ! gruneisen parameters on the path
396      nctkarr_t("gruns_gvals_qpath", "dp", "number_of_phonon_modes, gruns_nqpath"), &
397      ! phonon frequencies at the different volumes
398      nctkarr_t("gruns_wvols_qpath", "dp", "number_of_phonon_modes, gruns_nvols, gruns_nqpath"), &
399      ! group velocities at V0 in Cartesian coordinates.
400      nctkarr_t("gruns_dwdq_qpath", "dp", "three, number_of_phonon_modes, gruns_nqpath"), &
401      ! displacements for the different volumes.
402      nctkarr_t("gruns_phdispl_cart_qpath", "dp", &
403          "two, number_of_phonon_modes, number_of_phonon_modes, gruns_nvols, gruns_nqpath") &
404    ])
405    NCF_CHECK(ncerr)
406 
407    ! Write data.
408    NCF_CHECK(nctk_set_datamode(ncid))
409    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_qpath"), qpath%points))
410    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_gvals_qpath"), gvals_qpath))
411    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_wvols_qpath"), wvols_qpath))
412    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_dwdq_qpath"), dwdq_qpath))
413    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "gruns_phdispl_cart_qpath"), phdispl_cart_qpath))
414  end if
415 #endif
416 
417  ABI_FREE(wvols_qpath)
418  ABI_FREE(gvals_qpath)
419  ABI_FREE(dwdq_qpath)
420  ABI_FREE(phdispl_cart_qpath)
421 
422 end subroutine gruns_qpath

m_gruneisen/gruns_t [ Types ]

[ Top ] [ m_gruneisen ] [ Types ]

NAME

 gruns_t

FUNCTION

  Contains the interatomic force constants for different volumes.
  Provides methods to compute phonon bandstructures and gruneisen parameters.

SOURCE

64  type,public :: gruns_t
65 
66    integer :: natom3
67     ! 3 * natom
68 
69    integer :: nvols
70     ! Number of volumes.
71 
72    integer :: iv0
73     ! Index of the DDB file corresponding to the equilibrium volume V0.
74 
75    real(dp) :: v0
76     ! Equilibrium volume.
77 
78    real(dp) :: delta_vol
79     ! Uniform grid spacing for finite difference.
80 
81    type(crystal_t),allocatable :: cryst_vol(:)
82     ! cryst_vol(nvols)
83     ! crystalline structure for the different volumes.
84 
85    type(ddb_type),allocatable :: ddb_vol(:)
86     ! dbb_vol(nvols)
87     ! DDB objects for the different volumes.
88 
89    type(ifc_type),allocatable :: ifc_vol(:)
90     ! ifc_vol(nvols)
91     ! interatomic force constants for the different volumes.
92 
93  end type gruns_t
94 
95  public :: gruns_new        ! Constructor.
96  public :: gruns_qpath      ! Compute Gruneisen parameters on a q-path.
97  public :: gruns_qmesh      ! Compute Gruneisen parameters on a q-mesh.
98  public :: gruns_free       ! Release memory.
99  public :: gruns_anaddb     ! Driver routine called in anaddb.