TABLE OF CONTENTS


ABINIT/m_phonons [ Modules ]

[ Top ] [ Modules ]

NAME

 m_phonons

FUNCTION

 Module for the phonon density of states.
 Container type is defined, and destruction, print subroutines
 as well as the central phdos_init

COPYRIGHT

 Copyright (C) 1999-2024 ABINIT group (XG, MG, MJV, GMR)
 This file is distributed under the terms of the
 GNU General Public Licence, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .
 For the initials of contributors, see ~abinit/doc/developers/contributors.txt .

SOURCE

19 #if defined HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include "abi_common.h"
24 
25 module m_phonons
26 
27  use defs_basis
28  use m_errors
29  use m_xmpi
30  use m_abicore
31  use m_htetra
32  use m_numeric_tools
33  use m_cgtools
34  use m_crystal
35  use m_nctk
36  use, intrinsic :: iso_c_binding
37  use m_atprj
38  use m_sortph
39  use m_ddb
40  use netcdf
41  use m_supercell
42  use m_dtset
43  use m_krank
44 
45  use m_fstrings,        only : itoa, ftoa, sjoin, ltoa, ktoa, strcat, basename, replace
46  use m_symtk,           only : matr3inv
47  use m_time,            only : cwtime, cwtime_report
48  use m_io_tools,        only : open_file
49  use m_geometry,        only : mkrdim, symredcart, normv, phdispl_cart2red
50  use m_dynmat,          only : gtdyn9, dfpt_phfrq, dfpt_prtph, &
51                                pheigvec_normalize, massmult_and_breaksym, &
52                                phdispl_from_eigvec, phangmom_from_eigvec
53  use m_bz_mesh,         only : isamek, make_path, kpath_t, kpath_new
54  use m_ifc,             only : ifc_type
55  use m_anaddb_dataset,  only : anaddb_dataset_type
56  use m_kpts,            only : kpts_ibz_from_kptrlatt, get_full_kgrid, kpts_map, kpts_timrev_from_kptopt
57  use m_special_funcs,   only : bose_einstein
58  use m_sort,            only : sort_dp
59  use m_symfind,         only : symanal
60 
61  implicit none
62 
63  private
64 
65  public :: mkphbs                        ! Compute phonon band structure
66  public :: phonons_write_xmgrace         ! Write phonons bands in Xmgrace format.
67  public :: phonons_write_gnuplot         ! Write phonons bands in gnuplot format.
68  public :: ifc_mkphbs                    ! Compute the phonon band structure from the IFC and write data to file(s)
69  public :: dfpt_symph                    ! Determine the symmetry character of the different phonon modes at Gamma
70 
71  public :: zacharias_supercell_make
72  public :: zacharias_supercell_print
73  public :: thermal_supercell_make
74  public :: thermal_supercell_free
75  public :: thermal_supercell_print

m_phonons/dfpt_symph [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 dfpt_symph

FUNCTION

 Determine the symmetry character of the different phonon modes.

INPUTS

 acell(3)=length scales of primitive translations (bohr)
 eigvec(2*3*natom*3*natom)=eigenvectors of the dynamical matrix
 indsym(4,nsym,natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
 iout=unit number to which output is written
 natom=number of atoms in unit cell
 nsym=number of space group symmetries
 phfrq(3*natom)=phonon frequencies (Hartree units)
 rprim(3,3)=dimensionless primitive translations in real space
 symrel(3,3,nsym)=matrices of the group symmetries (real space)

OUTPUT

SOURCE

2963 subroutine dfpt_symph(iout,acell,eigvec,indsym,natom,nsym,phfrq,rprim,symrel)
2964 
2965 !Arguments ------------------------------------
2966 !scalars
2967  integer,intent(in) :: iout,natom,nsym
2968 !arrays
2969  integer,intent(in) :: indsym(4,nsym,natom),symrel(3,3,nsym)
2970  real(dp),intent(in) :: acell(3),eigvec(2*3*natom*3*natom),phfrq(3*natom)
2971  real(dp),intent(in) :: rprim(3,3)
2972 
2973 !Local variables -------------------------
2974 !scalars
2975  integer :: iad1,iad2,iad3,iatom,idir,ii1,ii2,ii3,imode,isym,itol,jad,jatom,jj
2976  integer :: jmode,kk,ntol
2977  character(len=500) :: message
2978 !arrays
2979  integer,allocatable :: degeneracy(:),integer_characters(:),symind(:,:)
2980  real(dp) :: gprimd(3,3),rprimd(3,3)
2981  real(dp),allocatable :: eigvtr(:),redvec(:),redvtr(:),symph(:,:)
2982 
2983 !******************************************************************
2984 
2985  ! Compute dimensional primitive translations rprimd and its inverse gprimd
2986  call mkrdim(acell,rprim,rprimd)
2987  call matr3inv(rprimd,gprimd)
2988 
2989  ! Build the symmetry index (inverse of indsym(4,:,:))
2990  ABI_MALLOC(symind, (nsym,natom))
2991  do isym=1,nsym
2992    do iatom=1,natom
2993      symind(isym,indsym(4,isym,iatom))=iatom
2994    end do
2995  end do
2996 
2997  ABI_MALLOC(symph,(nsym,3*natom))
2998  ABI_MALLOC(redvec,(2*3*natom))
2999  ABI_MALLOC(redvtr,(2*3*natom))
3000  ABI_MALLOC(eigvtr,(2*3*natom))
3001 
3002  ! Loop over the vibration modes
3003  do imode=1,3*natom
3004 
3005    ! Compute eigvec for this mode in reduced coordinates redvec
3006    do iatom=1,natom
3007      iad1=3*(iatom-1)+1
3008      ii1=2*3*natom*(imode-1)+2*(iad1-1)+1
3009      iad2=3*(iatom-1)+2
3010      ii2=2*3*natom*(imode-1)+2*(iad2-1)+1
3011      iad3=3*(iatom-1)+3
3012      ii3=2*3*natom*(imode-1)+2*(iad3-1)+1
3013      do idir=1,3
3014        jad=3*(iatom-1)+idir
3015        jj=2*(jad-1)+1
3016        redvec(jj)=gprimd(1,idir)*eigvec(ii1)+&
3017                   gprimd(2,idir)*eigvec(ii2)+&
3018                   gprimd(3,idir)*eigvec(ii3)
3019        redvec(jj+1)=gprimd(1,idir)*eigvec(ii1+1)+&
3020                     gprimd(2,idir)*eigvec(ii2+1)+&
3021                     gprimd(3,idir)*eigvec(ii3+1)
3022      end do !idir
3023    end do !iatom
3024 
3025 !  Apply each transformation to redvec and store at the correct location in redvtr (iatom -> jatom)
3026    do isym=1,nsym
3027      do iatom=1,natom
3028        jatom=symind(isym,iatom)
3029        iad1=3*(iatom-1)+1
3030        ii1=2*(iad1-1)+1
3031        iad2=3*(iatom-1)+2
3032        ii2=2*(iad2-1)+1
3033        iad3=3*(iatom-1)+3
3034        ii3=2*(iad3-1)+1
3035        do idir=1,3
3036          jad=3*(jatom-1)+idir
3037          jj=2*(jad-1)+1
3038          redvtr(jj)=dble(symrel(idir,1,isym))*redvec(ii1)+&
3039                     dble(symrel(idir,2,isym))*redvec(ii2)+&
3040                     dble(symrel(idir,3,isym))*redvec(ii3)
3041          redvtr(jj+1)=dble(symrel(idir,1,isym))*redvec(ii1+1)+&
3042                       dble(symrel(idir,2,isym))*redvec(ii2+1)+&
3043                       dble(symrel(idir,3,isym))*redvec(ii3+1)
3044        end do !idir
3045      end do !iatom
3046 
3047 !    Compute redvtr in cartesian coordinates eigvtr
3048      do iatom=1,natom
3049        iad1=3*(iatom-1)+1
3050        ii1=2*(iad1-1)+1
3051        iad2=3*(iatom-1)+2
3052        ii2=2*(iad2-1)+1
3053        iad3=3*(iatom-1)+3
3054        ii3=2*(iad3-1)+1
3055        do idir=1,3
3056          jad=3*(iatom-1)+idir
3057          jj=2*(jad-1)+1
3058          eigvtr(jj)=rprimd(idir,1)*redvtr(ii1)+&
3059                     rprimd(idir,2)*redvtr(ii2)+&
3060                     rprimd(idir,3)*redvtr(ii3)
3061          eigvtr(jj+1)=rprimd(idir,1)*redvtr(ii1+1)+&
3062                       rprimd(idir,2)*redvtr(ii2+1)+&
3063                       rprimd(idir,3)*redvtr(ii3+1)
3064        end do !idir
3065      end do !iatom
3066 
3067 !    Compute scalar product...
3068      symph(isym,imode)=0.0_dp
3069      do jad=1,3*natom
3070        jj=2*(jad-1)+1
3071        kk=2*3*natom*(imode-1)+2*(jad-1)+1
3072        symph(isym,imode)=symph(isym,imode)+eigvtr(jj)*eigvec(kk)+eigvtr(jj+1)*eigvec(kk+1)
3073      end do
3074 
3075    end do !isym
3076  end do !imode
3077 
3078 !Treat degeneracies (different tolerances will be tried)
3079 !Compute the order of the degeneracy, and
3080 !attribute it to the lowest of the degenerate modes
3081 !Also attribute the characters to the lowest mode
3082 !When all the characters are integers, consider that the
3083 !mode is non-degenerate. The maximum difference in frequency
3084 !that is tolerated is on the order of 4cm-1 (which is large...)
3085  ABI_MALLOC(degeneracy, (3*natom))
3086  ABI_MALLOC(integer_characters, (3*natom))
3087  degeneracy(:)=1
3088  integer_characters(:)=0
3089  do itol=1,20
3090    ntol=itol
3091    do imode=3*natom,2,-1
3092      if(integer_characters(imode)==0)then
3093        do jmode=imode-1,1,-1
3094          if(integer_characters(jmode)==0)then
3095            if(abs(phfrq(imode)-phfrq(jmode))<itol*tol6)then
3096              degeneracy(jmode)=degeneracy(jmode)+degeneracy(imode)
3097              degeneracy(imode)=0
3098              symph(:,jmode)=symph(:,jmode)+symph(:,imode)
3099              symph(:,imode)=0.0_dp
3100            end if
3101          end if !integer_characters(jmode)==0
3102        end do !jmode
3103      end if !integer_characters(imode)==0
3104    end do !imode
3105    do imode=1,3*natom
3106      if(maxval(abs( symph(:,imode)-nint(symph(:,imode)) ))<0.05_dp)then
3107        integer_characters(imode)=1
3108      end if
3109    end do
3110    if(sum(integer_characters(:))==3*natom)exit
3111  end do !itol
3112 
3113 !write(std_out,*)' dfpt_symph : degeneracy=',degeneracy(:)
3114 
3115  write(message,'(a,a,es8.2,5a)')ch10,' Analysis of degeneracies and characters (maximum tolerance=',ntol*tol6,' a.u.)',ch10,&
3116   ' For each vibration mode, or group of modes if degenerate,',ch10,&
3117   ' the characters are given for each symmetry operation (see the list in the log file).'
3118  call wrtout([std_out, iout], message)
3119 
3120  do imode=1,3*natom
3121    if(degeneracy(imode)/=0)then
3122      write(message,'(a,i4)') ' Symmetry characters of vibration mode #',imode
3123      call wrtout([std_out, iout], message)
3124      if(degeneracy(imode)>=2)then
3125        if(degeneracy(imode)==2) write(message,'(a,i4)') '        degenerate with vibration mode #',imode+1
3126        if(degeneracy(imode)>=3) write(message,'(a,i4,a,i4)') &
3127          '       degenerate with vibration modes #',imode+1,' to ',imode+degeneracy(imode)-1
3128        call wrtout([std_out, iout], message)
3129      end if
3130      do jj=1,(nsym-1)/16+1
3131        write(message,'(16f5.1)') (symph(isym,imode),isym=(jj-1)*16+1,min(nsym,jj*16))
3132        call wrtout([std_out, iout], message)
3133      end do
3134    end if
3135  end do !imode
3136 
3137  ABI_FREE(degeneracy)
3138  ABI_FREE(integer_characters)
3139  ABI_FREE(eigvtr)
3140  ABI_FREE(redvtr)
3141  ABI_FREE(redvec)
3142  ABI_FREE(symph)
3143  ABI_FREE(symind)
3144 
3145 end subroutine dfpt_symph

m_phonons/freeze_displ_allmodes [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 freeze_displ_allmodes

FUNCTION

  From a given set of phonon modes, generate and output supercells and
  displaced configurations of atoms.
  Typically useful to follow soft modes and see distorsions of crystal structures

INPUTS

 amu(ntypat) = mass of the atoms (atomic mass unit)
 displ(2,3*natom,3*natom) = phonon mode displacements (complex)
 freeze_displ = amplitude of the displacement to freeze into the supercell
 natom = number of atoms in the unit cell
 ntypat = number of atom types
 phfrq(3*natom) = phonon frequencies
 qphnrm = norm of phonon q vector (should be 1 or 0)
 qphon = phonon wavevector
 rprimd(3,3) = dimensionfull primitive translations in real space
 typat(natom) = integer label of each type of atom (1,2,...)
 xcart(3,natom) = cartesian coords of atoms in unit cell (bohr)

OUTPUT

 for the moment only prints to file, but could also return pointer to supercell object, with
 rprimd and atomic positions, for further use

NOTES

 freeze_displ could be determined automatically from a temperature and the phonon frequency,
 as the average displacement of the mode with a Bose distribution.

SOURCE

3182 subroutine freeze_displ_allmodes(displ, freeze_displ, natom, outfile_radix, phfreq,  &
3183                                  qphon, rprimd, typat, xcart, znucl)
3184 
3185 !Arguments ------------------------------------
3186 !scalars
3187  integer,intent(in) :: natom
3188  character(len=*),intent(in) :: outfile_radix
3189  real(dp), intent(in) :: freeze_displ
3190 !arrays
3191  integer,intent(in) :: typat(natom)
3192  real(dp),intent(in) :: displ(2,3*natom,3*natom)
3193  real(dp),intent(in) :: rprimd(3,3)
3194  real(dp),intent(in) :: phfreq(3*natom)
3195  real(dp),intent(in) :: qphon(3)
3196  real(dp),intent(in) :: xcart(3,natom)
3197  real(dp),intent(in) :: znucl(:)
3198 
3199 ! local vars
3200  integer :: jmode
3201  type(supercell_type) :: scell
3202 
3203 ! *************************************************************************
3204 
3205  !determine supercell needed to freeze phonon
3206  call init_supercell_for_qpt(natom, qphon, rprimd, typat, xcart, znucl, scell)
3207 
3208  do jmode = 1, 3*natom
3209    ! reset positions
3210    scell%xcart = scell%xcart_ref
3211 
3212    ! displace atoms according to phonon jmode
3213    call freeze_displ_supercell(displ(:,:,jmode), freeze_displ, scell)
3214 
3215    ! print out everything for this wavevector and mode
3216    call prt_supercell_for_qpt (phfreq(jmode), jmode, outfile_radix, scell)
3217  end do
3218 
3219  call destroy_supercell(scell)
3220 
3221 end subroutine freeze_displ_allmodes

m_phonons/ifc_mkphbs [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 ifc_mkphbs

FUNCTION

 Compute the phonon band structure from the IFC and write data to file(s)

INPUTS

 ifc<ifc_type>=Interatomic force constants
 cryst<crystal_t> = Info on the crystalline structure.
 dtset=<datasets_type>: input: all input variables initialized from the input file.
 prefix=Prefix for output files.
 comm=MPI communicator

OUTPUT

  Only writing.

SOURCE

2812 subroutine ifc_mkphbs(ifc, cryst, dtset, prefix, comm)
2813 
2814 !Arguments -------------------------------
2815 !scalars
2816  integer,intent(in) :: comm
2817  character(len=*),intent(in) :: prefix
2818  type(ifc_type),intent(in) :: ifc
2819  type(crystal_t),intent(in) :: cryst
2820  type(dataset_type),intent(in) :: dtset
2821 
2822 !Local variables -------------------------
2823 !scalars
2824  integer,parameter :: master = 0
2825  integer :: iqpt, nqpts, natom, ncid, nprocs, my_rank, ierr, nph2l, ncerr
2826  type(kpath_t) :: qpath
2827 !arrays
2828  real(dp),allocatable :: qph2l(:,:), qnrml2(:), eigvec(:,:,:,:,:),phfrqs(:,:),phdispl_cart(:,:,:,:),phangmom(:,:,:),weights(:)
2829 
2830 ! *********************************************************************
2831 
2832  if (dtset%prtphbands == 0) return
2833 
2834  if (dtset%ph_nqpath <= 0 .or. dtset%ph_ndivsm <= 0) then
2835    ABI_COMMENT("ph_nqpath <= 0 or ph_ndivsm <= 0. Phonon bands won't be produced. Returning")
2836    return
2837  end if
2838 
2839  call wrtout(std_out, " Writing phonon bands, use prtphbands 0 to disable this part")
2840 
2841  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
2842  natom = cryst%natom
2843 
2844  qpath = kpath_new(dtset%ph_qpath(:,1:dtset%ph_nqpath), cryst%gprimd, dtset%ph_ndivsm)
2845  nqpts = qpath%npts
2846 
2847  ABI_CALLOC(phfrqs, (3*natom,nqpts))
2848  ABI_CALLOC(phdispl_cart, (2,3*natom,3*natom,nqpts))
2849  ABI_CALLOC(phangmom, (3,3*natom,nqpts))
2850  ABI_CALLOC(eigvec, (2,3,natom,3,natom))
2851 
2852  do iqpt=1,nqpts
2853    if (mod(iqpt, nprocs) /= my_rank) cycle ! MPI-parallelism
2854    ! Get phonon frequencies and displacements in cartesian coordinates for this q-point
2855    call ifc%fourq(cryst, qpath%points(:,iqpt), phfrqs(:,iqpt), phdispl_cart(:,:,:,iqpt), out_eigvec=eigvec)
2856    call phangmom_from_eigvec(natom, eigvec, phangmom(:,:,iqpt))
2857  end do
2858 
2859  call xmpi_sum_master(phfrqs, master, comm, ierr)
2860  call xmpi_sum_master(phdispl_cart, master, comm, ierr)
2861  call xmpi_sum_master(phangmom, master, comm, ierr)
2862 
2863  if (my_rank == master) then
2864    ABI_MALLOC(weights, (nqpts))
2865    weights = one
2866 
2867    ! Compute directions for non-analytical behaviour.
2868    ! TODO: The same approach should be used in anaddb at the level of the parser.
2869    ABI_MALLOC(qph2l, (3, 2*dtset%ph_nqpath))
2870    ABI_MALLOC(qnrml2, (2*dtset%ph_nqpath))
2871 
2872    nph2l = 0
2873    if (any(ifc%zeff /= zero)) then
2874      do iqpt=1,dtset%ph_nqpath
2875        if (sum(dtset%ph_qpath(:, iqpt)**2) < tol14) then
2876          nph2l = nph2l + 1
2877          if (iqpt == 1) then
2878            qph2l(:, nph2l) = dtset%ph_qpath(:, 2) - dtset%ph_qpath(:, 1)
2879          else if (iqpt == dtset%ph_nqpath) then
2880            qph2l(:, nph2l) = dtset%ph_qpath(:, dtset%ph_nqpath - 1) - dtset%ph_qpath(:, dtset%ph_nqpath)
2881          else
2882            qph2l(:, nph2l) = dtset%ph_qpath(:, iqpt - 1) - dtset%ph_qpath(:, iqpt)
2883            nph2l = nph2l + 1
2884            qph2l(:, nph2l) = dtset%ph_qpath(:, iqpt + 1) - dtset%ph_qpath(:, iqpt)
2885          end if
2886        end if
2887      end do
2888 
2889      ! Convert to Cartesian coordinates.
2890      do iqpt=1,nph2l
2891        qph2l(:, iqpt) = matmul(cryst%gprimd, qph2l(:, iqpt))
2892      end do
2893      qnrml2 = zero
2894    end if
2895 
2896    ! TODO: A similar piece of code is used in anaddb (mkpbs + ifc_calcnwrite_nana_terms).
2897    ! Should centralize everything in a single routine
2898    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHBST.nc"), xmpi_comm_self), "Creating PHBST")
2899    NCF_CHECK(cryst%ncwrite(ncid))
2900    call phonons_ncwrite(ncid, natom, nqpts, qpath%points, weights, phfrqs, phdispl_cart, phangmom)
2901    ! This flag tells AbiPy that all the non-analytic directions have been computed.
2902    NCF_CHECK(nctk_defnwrite_ivars(ncid, ["has_abipy_non_anal_ph"], [1]))
2903    ncerr = nctk_def_arrays(ncid, [nctkarr_t("atomic_mass_units", "dp", "number_of_atom_species")], defmode=.True.)
2904    NCF_CHECK(ncerr)
2905    NCF_CHECK(nctk_set_datamode(ncid))
2906    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "atomic_mass_units"), ifc%amu))
2907    if (nph2l /= 0) call ifc%calcnwrite_nana_terms(cryst, nph2l, qph2l, qnrml2, ncid=ncid)
2908    NCF_CHECK(nf90_close(ncid))
2909 
2910    ABI_FREE(qph2l)
2911    ABI_FREE(qnrml2)
2912 
2913    select case (dtset%prtphbands)
2914    case (1)
2915      call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nqpts, qpath%points, phfrqs, qptbounds=qpath%bounds)
2916    case (2)
2917      call phonons_write_gnuplot(prefix, natom, nqpts, qpath%points, phfrqs, qptbounds=qpath%bounds)
2918    case (3)
2919      call phonons_write_phfrq(prefix, natom, nqpts, qpath%points, weights, phfrqs, phdispl_cart, phangmom)
2920    case default
2921      ABI_WARNING(sjoin("Unsupported value for prtphbands:", itoa(dtset%prtphbands)))
2922    end select
2923 
2924    ABI_FREE(weights)
2925  end if ! master
2926 
2927  ABI_FREE(phfrqs)
2928  ABI_FREE(phdispl_cart)
2929  ABI_FREE(phangmom)
2930  ABI_FREE(eigvec)
2931 
2932  call qpath%free()
2933 
2934 end subroutine ifc_mkphbs

m_phonons/mkphbs [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 mkphbs

FUNCTION

 Function to calculate the phonon band structure, from the IFC

INPUTS

 Ifc<ifc_type>=Interatomic force constants
 crystal<type(crystal_t)> = Info on the crystalline structure.
 inp= (derived datatype) contains all the input variables
 ddb<type(ddb_type)>=Object storing the DDB results.
 asrq0<asrq0_t>=Object for the treatment of the ASR based on the q=0 block found in the DDB file.
 prefix=Prefix for output files.
 dielt(3,3)=dielectric tensor
 comm=MPI communicator

OUTPUT

  Only writing.

SOURCE

1796 subroutine mkphbs(Ifc,Crystal,inp,ddb,asrq0,prefix,comm)
1797 
1798 !Arguments -------------------------------
1799 !scalars
1800  integer,intent(in) :: comm
1801  character(len=*),intent(in) :: prefix
1802  type(ifc_type),intent(in) :: Ifc
1803  type(crystal_t),intent(in) :: Crystal
1804  type(anaddb_dataset_type),target,intent(in) :: inp
1805  type(ddb_type),intent(in) :: ddb
1806  type(asrq0_t),intent(inout) :: asrq0
1807 
1808 !Local variables -------------------------
1809 !scalars
1810  integer,parameter :: master=0
1811  integer :: unt
1812  integer :: iphl1,iblok,rftyp, ii,nfineqpath,nsym,natom,ncid,nprocs,my_rank
1813  integer :: natprj_bs,eivec,enunit,ifcflag,ptgroupma,spgroup
1814  real(dp) :: freeze_displ
1815  real(dp) :: cfact
1816  character(500) :: msg
1817  character(len=8) :: unitname
1818 !arrays
1819  integer :: bravais(11),rfphon(4),rfelfd(4),rfstrs(4)
1820  integer :: nomega, imode, iomega
1821  integer,allocatable :: ndiv(:)
1822  real(dp) :: omega, omega_min, gaussmaxarg, gaussfactor, gaussprefactor, xx
1823  real(dp) :: speedofsound(3),genafm(3)
1824  real(dp) :: qphnrm(3), qphon(3), qphon_padded(3,3),res(3)
1825  real(dp) :: d2cart(2,ddb%msize),real_qphon(3)
1826  real(dp) :: displ(2*3*Crystal%natom*3*Crystal%natom),eigval(3,Crystal%natom),phangmom(3,3*Crystal%natom)
1827  real(dp),allocatable :: phfrq(:),eigvec(:,:,:,:,:)
1828  real(dp),allocatable :: save_phfrq(:,:),save_phdispl_cart(:,:,:,:),save_qpoints(:,:),save_phangmom(:,:,:)
1829  real(dp),allocatable :: weights(:)
1830  real(dp),allocatable :: dos4bs(:)
1831  real(dp),allocatable,target :: alloc_path(:,:)
1832  real(dp),pointer :: fineqpath(:,:)
1833  type(atprj_type) :: atprj
1834 
1835 ! *********************************************************************
1836 
1837  ! Only master works for the time being
1838  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
1839  if (my_rank /= master) return
1840 
1841  nsym = Crystal%nsym; natom = Crystal%natom
1842 
1843  ! Copy parameters from inp (then I will try to remove inp from the API so that I can call mkphbs in eph)
1844  ifcflag = inp%ifcflag
1845  natprj_bs = inp%natprj_bs
1846  freeze_displ = inp%freeze_displ
1847  eivec = inp%eivec; enunit = inp%enunit
1848  rftyp=inp%rfmeth
1849 
1850  nullify(fineqpath)
1851  nfineqpath = inp%nph1l
1852  fineqpath => inp%qph1l
1853 
1854  if(inp%nph1l==0) then
1855    if (inp%nqpath==0) then
1856      return ! if there is nothing to do, return
1857    else
1858      ! allow override of nph1l with nqpath if the former is not set
1859      ! allocate and compute path here and make fineqpath points to it
1860      ABI_MALLOC(ndiv,(inp%nqpath-1))
1861      call make_path(inp%nqpath,inp%qpath,Crystal%gmet,'G',inp%ndivsm,ndiv,nfineqpath,alloc_path,std_out)
1862      ABI_FREE(ndiv)
1863      fineqpath => alloc_path
1864    end if
1865  end if
1866 
1867  write(msg, '(a,(80a),a,a,a,a)' ) ch10,('=',ii=1,80),ch10,ch10,' Treat the first list of vectors ',ch10
1868  call wrtout([std_out, ab_out], msg)
1869 
1870  if (natprj_bs > 0) call atprj_init(atprj, natom, natprj_bs, inp%iatprj_bs, prefix)
1871 
1872  ABI_MALLOC(phfrq, (3*natom))
1873  ABI_MALLOC(eigvec, (2,3,natom,3,natom))
1874  ABI_MALLOC(save_qpoints, (3,nfineqpath))
1875  ABI_MALLOC(save_phfrq, (3*natom,nfineqpath))
1876  ABI_MALLOC(save_phdispl_cart, (2,3*natom,3*natom,nfineqpath))
1877  ABI_MALLOC(save_phangmom, (3,3*natom,nfineqpath))
1878  qphnrm = one
1879 
1880  do iphl1=1,nfineqpath
1881 
1882    ! Initialisation of the phonon wavevector
1883    qphon(:)=fineqpath(:,iphl1)
1884 
1885    if (inp%nph1l /= 0) qphnrm(1) = inp%qnrml1(iphl1)
1886 
1887    save_qpoints(:,iphl1) = qphon / qphnrm(1)
1888 
1889    ! Generation of the dynamical matrix in cartesian coordinates
1890    if (ifcflag == 1) then
1891 
1892      ! Get phonon frequencies and displacements in reduced coordinates for this q-point
1893      !call ifc%fourq(cryst, save_qpoints(:,iphl1), phfrq, displ, out_eigvec=eigvec)
1894 
1895      ! Get d2cart using the interatomic forces and the
1896      ! long-range coulomb interaction through Ewald summation
1897      call gtdyn9(ddb%acell,Ifc%atmfrc,Ifc%dielt,Ifc%dipdip,Ifc%dyewq0,d2cart,Crystal%gmet,ddb%gprim,ddb%mpert,natom, &
1898       Ifc%nrpt,qphnrm(1),qphon,Crystal%rmet,ddb%rprim,Ifc%rpt,Ifc%trans,Crystal%ucvol,Ifc%wghatm,Crystal%xred,ifc%zeff,&
1899       ifc%qdrp_cart,ifc%ewald_option,xmpi_comm_self,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
1900 
1901    else if (ifcflag == 0) then
1902 
1903      !call ddb_diagoq(ddb, crystal, save_qpoints(:,iphl1), asrq0, ifc%symdynmat, rftyp, phfrq, displ, &
1904      !                out_eigvec=eigvec)
1905 
1906      ! Look for the information in the DDB (no interpolation here!)
1907      rfphon(1:2)=1; rfelfd(1:2)=0; rfstrs(1:2)=0
1908      qphon_padded = zero; qphon_padded(:,1) = qphon
1909 
1910      call ddb%get_block(iblok,qphon_padded,qphnrm,rfphon,rfelfd,rfstrs,rftyp)
1911 
1912      ! Copy the dynamical matrix in d2cart
1913      d2cart(:,1:ddb%msize)=ddb%val(:,:,iblok)
1914 
1915      ! Eventually impose the acoustic sum rule based on previously calculated d2asr
1916      call asrq0%apply(natom, ddb%mpert, ddb%msize, crystal%xcart, d2cart)
1917    end if
1918 
1919    ! Use inp%symdynmat instead of ifc because of ifcflag
1920    ! Calculation of the eigenvectors and eigenvalues of the dynamical matrix
1921    call dfpt_phfrq(ddb%amu,displ,d2cart,eigval,eigvec,Crystal%indsym,&
1922                    ddb%mpert,Crystal%nsym,natom,nsym,Crystal%ntypat,phfrq,qphnrm(1),qphon,&
1923                    crystal%rprimd,inp%symdynmat,Crystal%symrel,Crystal%symafm,Crystal%typat,Crystal%ucvol)
1924    ! Calculation of the phonon angular momentum
1925    ! maybe add it in dpft_phfrq directly ?
1926    call phangmom_from_eigvec(natom, eigvec, phangmom)
1927 
1928    if (abs(freeze_displ) > tol10) then
1929      real_qphon = zero
1930      if (abs(qphnrm(1)) > tol8) real_qphon = qphon / qphnrm(1)
1931      call freeze_displ_allmodes(displ, freeze_displ, natom, prefix, phfrq, &
1932                                 real_qphon, crystal%rprimd, Crystal%typat, crystal%xcart, crystal%znucl)
1933    end if
1934 
1935    ! If requested, output projection of each mode on given atoms
1936    if (natprj_bs > 0) call atprj_print(atprj, iphl1, phfrq, eigvec)
1937 
1938    ! In case eivec == 4, write output files for band2eps (visualization of phonon band structures)
1939    if (eivec == 4) then
1940      call sortph(eigvec,displ,strcat(prefix, "_B2EPS"),natom,phfrq)
1941    end if
1942 
1943    ! Write the phonon frequencies
1944    call dfpt_prtph(displ,eivec,enunit,ab_out,natom,phfrq,qphnrm(1),qphon)
1945 
1946    save_phfrq(:,iphl1) = phfrq
1947    save_phdispl_cart(:,:,:,iphl1) = RESHAPE(displ, [2, 3*natom, 3*natom])
1948    save_phangmom(:,:,iphl1) = RESHAPE(phangmom, [3, 3*natom])
1949 
1950    ! Determine the symmetries of the phonon mode at Gamma
1951    ! TODO: generalize for other q-point little groups.
1952    if (sum(abs(qphon)) < DDB_QTOL) then
1953      call symanal(bravais,0,genafm,nsym,nsym,ptgroupma,Crystal%rprimd,spgroup, &
1954                   Crystal%symafm,Crystal%symrel,Crystal%tnons,tol5,verbose=.TRUE.)
1955      call dfpt_symph(ab_out,ddb%acell,eigvec,Crystal%indsym,natom,nsym,phfrq,ddb%rprim,Crystal%symrel)
1956    end if
1957 
1958    ! if we have an acoustic mode (small q and acoustic type displacements)
1959    ! extrapolate speed of sound in this direction, and Debye frequency
1960    call wrap2_pmhalf(qphon, real_qphon, res)
1961    if (sqrt(real_qphon(1)**2+real_qphon(2)**2+real_qphon(3)**2) < quarter .and. &
1962        sqrt(real_qphon(1)**2+real_qphon(2)**2+real_qphon(3)**2) > tol6) then
1963      call phdos_calc_vsound(eigvec, Crystal%gmet, natom, phfrq, real_qphon, speedofsound)
1964      if (my_rank == master) call phdos_print_vsound(ab_out, Crystal%ucvol, speedofsound)
1965    end if
1966 
1967  end do ! iphl1
1968 
1969  ! calculate dos for the specific q points along the BS calculated
1970  ! only Gaussians are possible - no interpolation
1971  omega_min = minval(save_phfrq(:,:))
1972  nomega=NINT( (maxval(save_phfrq(:,:))-omega_min) / inp%dosdeltae ) + 1
1973  nomega=MAX(6,nomega) ! Ensure Simpson integration will be ok
1974 
1975  ABI_MALLOC(dos4bs,(nomega))
1976  dos4bs = zero
1977  gaussmaxarg = sqrt(-log(1.d-90))
1978  gaussprefactor = one/(inp%dossmear*sqrt(two_pi))
1979  gaussfactor    = one/(sqrt2*inp%dossmear)
1980  do iphl1=1,nfineqpath
1981    do imode=1,3*natom
1982      do iomega=1, nomega
1983        omega = omega_min + (iomega-1) * inp%dosdeltae
1984        xx = (omega - save_phfrq(imode,iphl1)) * gaussfactor
1985        if(abs(xx) < gaussmaxarg) then
1986          dos4bs(iomega) = dos4bs(iomega) + gaussprefactor*exp(-xx*xx)
1987        end if
1988      end do
1989    end do
1990  end do
1991 
1992 
1993  !deallocate sortph array
1994  call end_sortph()
1995 
1996  if (natprj_bs > 0) call atprj_destroy(atprj)
1997 
1998 ! WRITE OUT FILES
1999  if (my_rank == master) then
2000    ABI_MALLOC(weights, (nfineqpath))
2001    weights = one
2002 
2003    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHBST.nc"), xmpi_comm_self), "Creating PHBST")
2004    NCF_CHECK(crystal%ncwrite(ncid))
2005    call phonons_ncwrite(ncid,natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart,save_phangmom)
2006 
2007    ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
2008    if (inp%nph2l /= 0 .and. inp%ifcflag == 1) then
2009      call ifc%calcnwrite_nana_terms(crystal, inp%nph2l, inp%qph2l, inp%qnrml2, ncid)
2010    end if
2011    NCF_CHECK(nf90_close(ncid))
2012 
2013    call phonons_write_phfrq(prefix, natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart, save_phangmom)
2014 
2015    select case (inp%prtphbands)
2016    case (0)
2017      continue
2018 
2019    case (1)
2020      if (inp%nph1l == 0) then
2021        call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nfineqpath, save_qpoints, save_phfrq, &
2022           qptbounds=inp%qpath)
2023      else
2024        call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nfineqpath, save_qpoints, save_phfrq)
2025      end if
2026 
2027    case (2)
2028      if (inp%nph1l == 0) then
2029        call phonons_write_gnuplot(prefix, natom, nfineqpath, save_qpoints, save_phfrq, qptbounds=inp%qpath)
2030      else
2031        call phonons_write_gnuplot(prefix, natom, nfineqpath, save_qpoints, save_phfrq)
2032      end if
2033 
2034    case default
2035      ABI_WARNING(sjoin("Don't know how to handle prtphbands:", itoa(inp%prtphbands)))
2036    end select
2037 
2038    ! write out DOS file for q along this path
2039    cfact=one
2040    unitname = 'Ha'
2041    if (open_file('PHBST_partial_DOS',msg,newunit=unt,form="formatted",action="write") /= 0) then
2042      ABI_ERROR(msg)
2043    end if
2044    write(msg,'(3a)')'# ',ch10,'# Partial phonon density of states for q along a band structure path'
2045    call wrtout(unt, msg)
2046    write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
2047    call wrtout(unt, msg)
2048    write(msg,'(a,E20.10,2a,i8)') '# Gaussian method with smearing = ',inp%dossmear*cfact,unitname, ', nq =', nfineqpath
2049    call wrtout(unt, msg)
2050    write(msg,'(5a)')'# ',ch10,'# omega     PHDOS ',ch10,'# '
2051    call wrtout(unt, msg)
2052    do iomega=1,nomega
2053      omega = omega_min + (iomega-1) * inp%dosdeltae
2054      write(unt,'(2es17.8)',advance='NO')omega*cfact,dos4bs(iomega)/cfact
2055      write(unt,*)
2056    end do
2057    close(unt)
2058 
2059    ABI_FREE(weights)
2060  end if
2061 
2062  ABI_FREE(save_qpoints)
2063  ABI_FREE(save_phfrq)
2064  ABI_FREE(save_phdispl_cart)
2065  ABI_FREE(save_phangmom)
2066  ABI_FREE(phfrq)
2067  ABI_FREE(eigvec)
2068  ABI_FREE(dos4bs)
2069  ABI_SFREE(alloc_path)
2070 
2071 end subroutine mkphbs

m_phonons/phdos_calc_vsound [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_calc_vsound

FUNCTION

  From the frequencies for acoustic modes at small q, estimate speed of sound (which also gives Debye temperature)

INPUTS

 eigvec(2,3*natom,3*natom) = phonon eigenvectors at present q-point
 gmet(3,3) = metric tensor in reciprocal space.
 natom = number of atoms in the unit cell
 phfrq(3*natom) = phonon frequencies at present q-point
 qphon(3) = phonon q-point
 ucvol = unit cell volume

OUTPUT

SOURCE

2094 subroutine phdos_calc_vsound(eigvec,gmet,natom,phfrq,qphon,speedofsound)
2095 
2096 !Arguments -------------------------------
2097 !scalras
2098  integer, intent(in) :: natom
2099 !arrays
2100  real(dp), intent(in) :: gmet(3,3),qphon(3)
2101  real(dp), intent(in) :: phfrq(3*natom),eigvec(2,3*natom,3*natom)
2102  real(dp), intent(out) :: speedofsound(3)
2103 
2104 !Local variables -------------------------
2105  integer :: iatref,imode, iatom, isacoustic, imode_acoustic
2106 ! character(len=500) :: msg
2107  real(dp) :: qnormcart
2108  real(dp) :: qtmp(3)
2109 
2110 ! *********************************************************************
2111 
2112  imode_acoustic = 0
2113  do imode = 1, 3*natom
2114 
2115    ! Check if this mode is acoustic like: scalar product of all displacement vectors are collinear
2116    isacoustic = 1
2117    ! Find reference atom with non-zero displacement
2118    do iatom=1,natom
2119      if(sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3,imode)**2) >tol16)iatref=iatom
2120    enddo
2121    ! Now compute scalar product, and check they are all positive
2122    do iatom = 1, natom
2123      if (sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3, imode)&
2124             *eigvec(:,(iatref-1)*3+1:(iatref-1)*3+3, imode)) < tol16 ) isacoustic = 0
2125    end do
2126    if (isacoustic == 0) cycle
2127    imode_acoustic = min(imode_acoustic + 1, 3)
2128 
2129    ! write (msg, '(a,I6,a,3F12.4)') ' Found acoustic mode ', imode, ' for |q| in red coord < 0.25 ; q = ', qphon
2130    ! call wrtout(std_out, msg)
2131    qtmp = matmul(gmet, qphon)
2132    qnormcart = two * pi * sqrt(sum(qphon*qtmp))
2133    speedofsound(imode_acoustic) = phfrq(imode) / qnormcart
2134  end do
2135 
2136 end subroutine phdos_calc_vsound

m_phonons/phdos_free [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_free

FUNCTION

 destructor function for phonon DOS object

INPUTS

 PHdos= container object for phonon DOS

SOURCE

595 subroutine phdos_free(PHdos)
596 
597 !Arguments -------------------------------
598  class(phdos_t),intent(inout) ::PHdos
599 
600 ! *************************************************************************
601 
602  !@phdos_t
603  ABI_SFREE(PHdos%atom_mass)
604  ABI_SFREE(PHdos%omega)
605  ABI_SFREE(PHdos%phdos)
606  ABI_SFREE(PHdos%phdos_int)
607  ABI_SFREE(PHdos%pjdos)
608  ABI_SFREE(PHdos%pjdos_int)
609  ABI_SFREE(PHdos%pjdos_type)
610  ABI_SFREE(PHdos%pjdos_type_int)
611  ABI_SFREE(PHdos%pjdos_rc_type)
612  ABI_SFREE(PHdos%msqd_dos_atom)
613 
614 end subroutine phdos_free

m_phonons/phdos_init [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_init

FUNCTION

 Calculate the phonon density of states as well as
 the contributions associated to the different types of atoms in the unit cell.
 Two methods are implemented: gaussian method and linear interpolation based on tetrahedra.

INPUTS

 ifc<ifc_type>=Interatomic force constants
 crystal<crystal_t>=Info on the crystalline structure.
 prtdos=1 for gaussian method, 2 for tetrahedra.
 dosdeltae=Step of frequency mesh.
 dossmear=Gaussian broadening, used if prtdos==1.
 dos_ngqpt(3)=Divisions of the q-mesh used for computing the DOS
 nqshift=Number of shifts in Q-mesh
 dos_qshift(3, nqshift)=Shift of the q-mesh.
 prefix=Prefix for PHBIZ output file. Empty string to deactivate output.
 comm=MPI communicator.

OUTPUT

 phdos<phdos_t>=Container with phonon DOS, IDOS and atom-projected DOS.
 count_wminmax(2)=Number of (interpolated) phonon frequencies that are outside
   input range (see wminmax). Client code can use count_wminmax and wminmax to
   enlarge the mesh and call the routine again to recompute the DOS
   if all frequencies should be included.

SIDE EFFECTS

 wminmax(2)=
   In input: min and max value of frequency mesh. Used only if minmax(2) > minmax(1)
    else values are taken from ifc%omega_minmax (computed from ab-initio mesh + pad)
   In output: min and max frequency obtained after interpolating the IFCs on the dense q-mesh dos_ngqpt

SOURCE

 721 subroutine phdos_init(phdos, crystal, ifc, prtdos, dosdeltae_in, dossmear, dos_ngqpt, nqshft, dos_qshift, prefix, &
 722                       wminmax, count_wminmax, comm, dos_maxmode)
 723 
 724 !Arguments -------------------------------
 725 !scalars
 726  class(phdos_t),intent(out) :: phdos
 727  integer,intent(in) :: prtdos,nqshft,comm
 728  real(dp),intent(in) :: dosdeltae_in,dossmear
 729  character(len=*),intent(in) ::  prefix
 730  type(crystal_t),intent(in) :: crystal
 731  type(ifc_type),intent(in) :: ifc
 732  integer, optional, intent(in) :: dos_maxmode
 733 !arrays
 734  integer,intent(in) :: dos_ngqpt(3)
 735  integer,intent(out) :: count_wminmax(2)
 736  real(dp),intent(in) :: dos_qshift(3,nqshft)
 737  real(dp),intent(inout) :: wminmax(2)
 738 
 739 !Local variables -------------------------
 740 !scalars
 741  integer,parameter :: bcorr0 = 0, master = 0
 742  integer :: iat,jat,idir,imode,io,iq_ibz,itype, my_qptopt, my_nsym
 743  integer :: nqbz,ierr,natom,nomega,jdir, isym, nprocs, my_rank, ncid
 744  logical :: refine_dosdeltae
 745  real(dp),parameter :: max_occ1=one, gaussmaxarg = sqrt(-log(1.d-90)), max_smallq = 0.0625_dp
 746  real(dp) :: nsmallq,gaussfactor,gaussprefactor,normq,debyefreq,rtmp
 747  real(dp) :: cpu, wall, gflops, cpu_all, wall_all, gflops_all
 748  real(dp) :: dosdeltae, phdos_int
 749  character(len=500) :: msg
 750  character(len=80) :: errstr
 751  type(htetra_t) :: htetraq
 752 !arrays
 753  integer :: in_qptrlatt(3,3),new_qptrlatt(3,3)
 754  integer :: dos_maxmode_
 755  integer,allocatable :: bz2ibz_smap(:,:), bz2ibz(:)
 756  real(dp) :: speedofsound(3),speedofsound_(3)
 757  real(dp) :: displ(2*3*Crystal%natom*3*Crystal%natom)
 758  real(dp) :: eigvec(2,3,Crystal%natom,3*Crystal%natom),phfrq(3*Crystal%natom),phangmom(3,3*Crystal%natom)
 759  real(dp) :: qlatt(3,3),rlatt(3,3), msqd_atom_tmp(3,3),temp_33(3,3)
 760  real(dp) :: symcart(3,3,crystal%nsym), syme2_xyza(3, crystal%natom)
 761  real(dp),allocatable :: full_eigvec(:,:,:,:,:),full_phfrq(:,:),full_phangmom(:,:,:),new_shiftq(:,:)
 762  real(dp),allocatable :: qbz(:,:),qibz(:,:),tmp_phfrq(:) !, work_msqd(:,:,:,:)
 763  real(dp),allocatable :: wtq_ibz(:),xvals(:), gvals_wtq(:), wdt(:,:), energies(:)
 764 
 765 ! *********************************************************************
 766 
 767  DBG_ENTER("COLL")
 768 
 769  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
 770 
 771  ! Consistency check.
 772  if (all(prtdos /= [1, 2])) then
 773    ABI_BUG(sjoin('prtdos should be 1 or 2, but received', itoa(prtdos)))
 774  end if
 775  dosdeltae = dosdeltae_in; refine_dosdeltae = .false.
 776  if (dosdeltae <= zero) then
 777    dosdeltae = -dosdeltae; refine_dosdeltae = .true.
 778    ABI_CHECK(nprocs == 1, "refine_dosdeltae cannot be used with nprocs > 1")
 779  end if
 780  if (prtdos == 1 .and. dossmear <= zero) then
 781    ABI_BUG(sjoin('dossmear should be positive but received', ftoa(dossmear)))
 782  end if
 783 
 784  call cwtime(cpu_all, wall_all, gflops_all, "start")
 785 
 786  ! Get symmetries in cartesian coordinates
 787  do isym=1,crystal%nsym
 788    call symredcart(crystal%rprimd,crystal%gprimd,symcart(:,:,isym),crystal%symrel(:,:,isym))
 789  end do
 790 
 791  natom = crystal%natom
 792  call phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos)
 793  nomega = phdos%nomega
 794 
 795  ABI_MALLOC(gvals_wtq, (nomega))
 796  ABI_MALLOC(xvals, (nomega))
 797 
 798  ! Parameters defining the gaussian approximant.
 799  if (prtdos == 1) then
 800    ! TODO: use gaussian and update reference files.
 801    gaussprefactor = one / (dossmear * sqrt(two_pi))
 802    gaussfactor = one / (sqrt2 * dossmear)
 803    write(msg, '(4a,f8.5,2a,f8.5,a,i0)') ch10, &
 804     ' phdos_init: calculating phonon DOS using gaussian method:', ch10, &
 805     '    gaussian smearing [meV] = ', dossmear * Ha_meV, ch10, &
 806     '    frequency step    [meV] = ', phdos%omega_step * Ha_meV, ", nomega = ",phdos%nomega
 807  else if (prtdos == 2) then
 808    write(msg, '(4a,f8.5,a,i0)') ch10, &
 809     ' phdos_init: calculating phonon DOS using tetrahedron method:', ch10, &
 810     '    frequency step    [meV] = ',phdos%omega_step * Ha_meV, ", nomega = ",phdos%nomega
 811  end if
 812  call wrtout(std_out, msg)
 813 
 814  ! This call will set %nqibz and IBZ and BZ arrays
 815  in_qptrlatt = 0; in_qptrlatt(1, 1) = dos_ngqpt(1); in_qptrlatt(2, 2) = dos_ngqpt(2); in_qptrlatt(3, 3) = dos_ngqpt(3)
 816 
 817  my_qptopt = 1
 818  !my_qptopt = 3 ! This to deactivate the use of symmetries for debugging purposes.
 819  call kpts_ibz_from_kptrlatt(crystal, in_qptrlatt, my_qptopt, nqshft, dos_qshift, &
 820    phdos%nqibz, qibz, wtq_ibz, nqbz, qbz, new_kptrlatt=new_qptrlatt, new_shiftk=new_shiftq, bz2ibz=bz2ibz_smap)
 821 
 822  phdos%qptrlatt = new_qptrlatt
 823  phdos%shiftq(:) = new_shiftq(:, 1) ! only one shift in output
 824 
 825  if (my_rank == master) then
 826    write(msg, "(3a, i0)")" DOS ngqpt: ", trim(ltoa(dos_ngqpt)), ", qptopt: ", my_qptopt
 827    call wrtout(std_out, msg)
 828    write(msg, "(2(a, i0))")" Number of q-points in the IBZ: ", phdos%nqibz, ", number of MPI processes: ", nprocs
 829    call wrtout(std_out, msg)
 830  end if
 831  !call cwtime_report(" kpts_ibz_from_kptrlatt", cpu, wall, gflops)
 832 
 833  if (prtdos == 2) then
 834    ! Prepare tetrahedron method including workspace arrays.
 835    ! Convert kptrlatt to double and invert, qlatt here refer to the shortest qpt vectors
 836    rlatt = new_qptrlatt; call matr3inv(rlatt, qlatt)
 837 
 838    ABI_MALLOC(bz2ibz, (nqbz))
 839    bz2ibz = bz2ibz_smap(1,:)
 840 
 841    call htetra_init(htetraq, bz2ibz, crystal%gprimd, qlatt, qbz, nqbz, qibz, phdos%nqibz, ierr, errstr, comm)
 842    !call cwtime_report(" init_tetra", cpu, wall, gflops)
 843    ABI_CHECK(ierr == 0, errstr)
 844    ABI_FREE(bz2ibz)
 845 
 846    ! Allocate arrays used to store the entire spectrum, Required to calculate tetra weights.
 847    ! this may change in the future if Matteo refactorizes the tetra weights as sums over k instead of sums over bands
 848    ABI_CALLOC(full_phfrq, (3*natom, phdos%nqibz))
 849    ABI_MALLOC(full_phangmom, (3, 3*natom, phdos%nqibz))
 850    ABI_MALLOC_OR_DIE(full_eigvec, (2, 3, natom, 3*natom, phdos%nqibz), ierr)
 851    full_eigvec = zero
 852  end if ! tetra
 853 
 854  ABI_SFREE(bz2ibz_smap)
 855  ABI_FREE(new_shiftq)
 856 
 857  ! MPI Sum over irreducible q-points then sync the following integrals:
 858  !   speedofsound, nsmallq
 859  !   wminmax and count_wminmax
 860  !   if gauss: %phdos, %msqd_dos_atom
 861  !   if tetra: full_phfrq, full_eigvec, full_phangmom, %phdos_int
 862 
 863  nsmallq = zero; speedofsound = zero
 864  wminmax = [huge(one), -huge(one)]; count_wminmax = 0
 865 
 866  do iq_ibz=1,phdos%nqibz
 867    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
 868 
 869    ! Fourier interpolation (keep track of min/max to decide if initial mesh was large enough)
 870    call ifc%fourq(crystal, qibz(:,iq_ibz), phfrq, displ, out_eigvec=eigvec)
 871    wminmax(1) = min(wminmax(1), minval(phfrq))
 872    if (wminmax(1) < phdos%omega(1)) count_wminmax(1) = count_wminmax(1) + 1
 873    wminmax(2) = max(wminmax(2), maxval(phfrq))
 874    if (wminmax(2) > phdos%omega(nomega)) count_wminmax(2) = count_wminmax(2) + 1
 875 
 876    normq = sum(qibz(:,iq_ibz) ** 2)
 877    if (normq < max_smallq .and. normq > tol6) then
 878      call phdos_calc_vsound(eigvec, crystal%gmet, natom, phfrq, qibz(:,iq_ibz), speedofsound_)
 879      speedofsound = speedofsound + speedofsound_ * wtq_ibz(iq_ibz)
 880      nsmallq = nsmallq + wtq_ibz(iq_ibz)
 881    end if
 882 
 883    dos_maxmode_ = 3*natom
 884    if (present(dos_maxmode)) then
 885      if (dos_maxmode > 0 .and. dos_maxmode < 3*natom) then
 886        dos_maxmode_ = dos_maxmode
 887      end if
 888    end if
 889 
 890    select case (prtdos)
 891    case (1)
 892      do imode=1,dos_maxmode_
 893        ! Precompute \delta(w - w_{qnu}) * weight(q)
 894        xvals = (phdos%omega(:) - phfrq(imode)) * gaussfactor
 895        where (abs(xvals) < gaussmaxarg)
 896          gvals_wtq = gaussprefactor * exp(-xvals*xvals) * wtq_ibz(iq_ibz)
 897        elsewhere
 898          gvals_wtq = zero
 899        end where
 900 
 901        ! Accumulate PHDOS
 902        phdos%phdos(:) = phdos%phdos(:) + gvals_wtq
 903 
 904        ! Rotate e(q) to get e(Sq) to account for symmetrical q-points in BZ.
 905        ! eigenvectors indeed are not invariant under rotation. See e.g. Eq 39-40 of PhysRevB.76.165108 [[cite:Giustino2007]].
 906        ! In principle there's a phase due to nonsymmorphic translations but we here need |e(Sq)_iatom|**2
 907        syme2_xyza = zero
 908        my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
 909        do iat=1,natom
 910          do isym=1,my_nsym
 911            jat = crystal%indsym(4,isym,iat)
 912            syme2_xyza(:,jat) = syme2_xyza(:,jat) + &
 913              matmul(symcart(:,:,isym), eigvec(1,:,iat,imode)) ** 2 + &
 914              matmul(symcart(:,:,isym), eigvec(2,:,iat,imode)) ** 2
 915          end do
 916        end do
 917        syme2_xyza = syme2_xyza / my_nsym
 918 
 919        ! Accumulate PJDOS
 920        do iat=1,natom
 921          do idir=1,3
 922            phdos%pjdos(:,idir,iat) = phdos%pjdos(:,idir,iat) + syme2_xyza(idir,iat) * gvals_wtq
 923          end do
 924        end do
 925 
 926        ! Accumulate outer product of displacement vectors
 927        ! NB: only accumulate real part. e(-q) = e(q)* the full sum over the BZ guarantees Im=0
 928        ! this sum only does irreducible points: the matrix is symmetrized below
 929        ! msqd_atom_tmp has units of bohr^2 / Ha as gaussval ~ 1/smear ~ 1/Ha
 930        do iat=1,natom
 931          msqd_atom_tmp = zero
 932          do idir=1,3
 933            do jdir=1,3
 934              msqd_atom_tmp(jdir,idir) = msqd_atom_tmp(jdir,idir) + ( &
 935                    eigvec(1,idir,iat,imode) * eigvec(1,jdir,iat,imode) &
 936                 +  eigvec(2,idir,iat,imode) * eigvec(2,jdir,iat,imode) )
 937            end do
 938          end do
 939 
 940          ! Symmetrize matrices to get full sum of tensor over all BZ, not just IBZ.
 941          ! the atom is not necessarily invariant under symops, so these contributions should be added to each iat separately
 942          ! normalization by nsym is done at the end outside the iqpt loop and after the tetrahedron clause
 943          ! NB: looks consistent with the sym in harmonic thermo, just used in opposite
 944          ! direction for symops: symrel here instead of symrec and the inverse of indsym in harmonic_thermo
 945          my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
 946          do isym=1, my_nsym
 947            !temp_33 = matmul( (symcart(:,:,isym)), matmul(msqd_atom_tmp, transpose(symcart(:,:,isym))) )
 948            ! MG Version
 949            temp_33 = matmul( (transpose(symcart(:,:,isym))), matmul(msqd_atom_tmp, symcart(:,:,isym)) )
 950            temp_33 = temp_33 / my_nsym
 951            jat = crystal%indsym(4,isym,iat)
 952            do idir=1,3
 953              do jdir=1,3
 954                phdos%msqd_dos_atom(:,idir,jdir,jat) = phdos%msqd_dos_atom(:,idir,jdir,jat) + &
 955                  temp_33(idir, jdir) * gvals_wtq
 956              end do
 957            end do
 958          end do
 959 
 960        end do ! iat
 961      end do ! imode
 962 
 963    case (2)
 964      ! Tetrahedra; Save phonon frequencies, eigenvectors and angular momentum.
 965      ! Sum is done after the loops over the two meshes.
 966      full_phfrq(:,iq_ibz) = phfrq(:)
 967      full_eigvec(:,:,:,:,iq_ibz) = eigvec
 968      full_phangmom(:,:,iq_ibz) = phangmom
 969 
 970    case default
 971      ABI_ERROR(sjoin("Wrong value for prtdos:", itoa(prtdos)))
 972    end select
 973  end do ! iq_ibz
 974 
 975  ABI_FREE(qbz)
 976  ABI_FREE(gvals_wtq)
 977  ABI_FREE(xvals)
 978 
 979  call xmpi_sum_master(nsmallq, master, comm, ierr)
 980  call xmpi_sum_master(speedofsound, master, comm, ierr)
 981 
 982  !call cwtime_report(" phdos", cpu, wall, gflops)
 983 
 984  if (my_rank == master .and. nsmallq > tol10) then
 985    ! Write info about speed of sound
 986    speedofsound = speedofsound / nsmallq
 987    write (msg,'(a,E20.10,3a,F16.4,2a)') &
 988        ' Average speed of sound partial sums: ', third*sum(speedofsound), ' (at units)',ch10, &
 989        '-                                   = ', third*sum(speedofsound) * Bohr_Ang * 1.d-13 / Time_Sec, ' [km/s]',ch10
 990    call wrtout([std_out, ab_out], msg)
 991 
 992    ! Debye frequency = vs * (6 pi^2 natom / ucvol)**1/3
 993    debyefreq = third*sum(speedofsound) * (six*pi**2/crystal%ucvol)**(1./3.)
 994    write (msg,'(a,E20.10,3a,E20.10,a)') &
 995       ' Debye frequency from partial sums: ', debyefreq, ' (Ha)',ch10, &
 996       '-                                 = ', debyefreq*Ha_THz, ' (THz)'
 997    call wrtout([std_out, ab_out], msg)
 998 
 999    ! Debye temperature = hbar * Debye frequency / kb
1000    write (msg,'(a,E20.10,2a)') '-Debye temperature from partial sums: ', debyefreq*Ha_K, ' (K)', ch10
1001    call wrtout([std_out, ab_out], msg)
1002  end if
1003 
1004  if (prtdos == 2) then
1005    call cwtime(cpu, wall, gflops, "start")
1006    ! Finalize integration with tetrahedra
1007    ! All the data are contained in full_phfrq, full_eigvec and full_phangmom.
1008    call xmpi_sum(full_phfrq, comm, ierr)
1009    call xmpi_sum(full_eigvec, comm, ierr)
1010    call xmpi_sum(full_phangmom, comm, ierr)
1011 
1012    ABI_MALLOC(tmp_phfrq, (phdos%nqibz))
1013 
1014    do
1015      ABI_MALLOC(wdt, (phdos%nomega, 2))
1016      ABI_MALLOC(energies, (phdos%nomega))
1017      energies = linspace(phdos%omega_min, phdos%omega_max, phdos%nomega)
1018 
1019      do iq_ibz=1,phdos%nqibz
1020        if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
1021 
1022        do imode=1,dos_maxmode_
1023          ! Compute the weights for this q-point using tetrahedron
1024          tmp_phfrq(:) = full_phfrq(imode,:)
1025          call htetraq%get_onewk_wvals(iq_ibz,bcorr0,phdos%nomega,energies,max_occ1,phdos%nqibz,tmp_phfrq,wdt)
1026          wdt = wdt * wtq_ibz(iq_ibz)
1027 
1028          ! Accumulate DOS/IDOS
1029          phdos%phdos(:)     = phdos%phdos(:)     + wdt(:, 1)
1030          phdos%phdos_int(:) = phdos%phdos_int(:) + wdt(:, 2)
1031 
1032          ! Rotate e(q) to get e(Sq) to account for other q-points in BZ. See notes in gaussian branch
1033          syme2_xyza = zero
1034          my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
1035          do iat=1,natom
1036            do isym=1,my_nsym
1037              jat = crystal%indsym(4,isym,iat)
1038              syme2_xyza(:,jat) = syme2_xyza(:,jat) + &
1039                matmul(symcart(:,:,isym), full_eigvec(1,:,iat,imode,iq_ibz)) ** 2 + &
1040                matmul(symcart(:,:,isym), full_eigvec(2,:,iat,imode,iq_ibz)) ** 2
1041            end do
1042          end do
1043          syme2_xyza = syme2_xyza / my_nsym
1044 
1045          do iat=1,natom
1046            do idir=1,3
1047              phdos%pjdos(:,idir,iat) = phdos%pjdos(:,idir,iat) + syme2_xyza(idir,iat) * wdt(:,1)
1048              phdos%pjdos_int(:,idir,iat) = phdos%pjdos_int(:,idir,iat) + syme2_xyza(idir,iat) * wdt(:,2)
1049            end do
1050          end do
1051 
1052          do iat=1,natom
1053 
1054            ! Accumulate outer product of displacement vectors
1055            msqd_atom_tmp = zero
1056            do idir=1,3
1057              do jdir=1,3
1058                msqd_atom_tmp(jdir,idir) = msqd_atom_tmp(jdir,idir) + ( &
1059                      full_eigvec(1,idir,iat,imode,iq_ibz) * full_eigvec(1,jdir,iat,imode,iq_ibz) &
1060                   +  full_eigvec(2,idir,iat,imode,iq_ibz) * full_eigvec(2,jdir,iat,imode,iq_ibz) )
1061              end do
1062            end do
1063 
1064            ! Symmetrize matrices to get full sum of tensor over all BZ, not just IBZ.
1065            ! the atom is not necessarily invariant under symops, so these contributions should be added to each iat separately
1066            ! normalization by nsym is done at the end outside the iqpt loop and after the tetrahedron clause
1067            ! from loops above only the eigvec are kept and not the displ, so we still have to divide by the masses
1068            ! TODO: need to check the direction of the symcart vs transpose or inverse, given that jat is the pre-image of iat...
1069            my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
1070            !my_nsym = 1
1071            do isym=1,my_nsym
1072              !temp_33 = matmul((symcart(:,:,isym)), matmul(msqd_atom_tmp, transpose(symcart(:,:,isym))))
1073              ! MG Version
1074              temp_33 = matmul( (transpose(symcart(:,:,isym))), matmul(msqd_atom_tmp, symcart(:,:,isym)) )
1075              temp_33 = temp_33 / my_nsym
1076              jat = crystal%indsym(4,isym,iat)
1077              do idir=1,3
1078                do jdir=1,3
1079                  phdos%msqd_dos_atom(:,idir,jdir,jat) = phdos%msqd_dos_atom(:,idir,jdir,jat) + &
1080                    temp_33(idir, jdir) * wdt(:,1)
1081                end do
1082              end do
1083            end do
1084          end do ! iat
1085 
1086        end do ! imode
1087      end do ! iq_ibz
1088 
1089      if (refine_dosdeltae) then
1090        ! HM: Check if the integration of the DOS is correct, otherwise half dos%deltae and re-run
1091        ! MG FIXME: This won't work in parallel because we still have to call xmpi_sum
1092        call ctrap(phdos%nomega, phdos%phdos, phdos%omega_step, phdos_int)
1093        if (abs(phdos_int - crystal%natom*3) > tol2) then
1094          write(msg,'(a,f6.2,a,i4,2a,e10.3,a,e10.3)') "The value of the integral is", phdos_int, &
1095                       " but it should be", crystal%natom*3, ch10,&
1096                       "I will decrease dosdeltae from: ", dosdeltae, " to: ", dosdeltae/two
1097          ABI_WARNING(msg)
1098          dosdeltae = dosdeltae / two
1099          call phdos%free()
1100          call phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos)
1101          nomega = phdos%nomega
1102          ABI_FREE(wdt)
1103          ABI_FREE(energies)
1104          cycle
1105        endif
1106      endif
1107 
1108      exit
1109    end do
1110 
1111    ABI_FREE(energies)
1112    ABI_FREE(wdt)
1113 
1114    ! Make eigvec into phonon displacements.
1115    do iat = 1, natom
1116      full_eigvec(:,:,iat,:,:) = full_eigvec(:,:,iat,:,:) / sqrt(phdos%atom_mass(iat))
1117    end do
1118 
1119    call cwtime_report(" tetra accumulate", cpu, wall, gflops)
1120 
1121    if (my_rank == master .and. len_trim(prefix) > 0) then
1122      NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHIBZ.nc"), xmpi_comm_self), "Creating PHIBZ")
1123      NCF_CHECK(crystal%ncwrite(ncid))
1124      call phonons_ncwrite(ncid, natom, phdos%nqibz, qibz, wtq_ibz, full_phfrq, full_eigvec, full_phangmom)
1125      NCF_CHECK(nf90_close(ncid))
1126    end if
1127 
1128    ! Immediately free this - it contains displ and not eigvec at this stage
1129    ABI_FREE(full_eigvec)
1130    ABI_FREE(full_phfrq)
1131    ABI_FREE(full_phangmom)
1132    ABI_FREE(tmp_phfrq)
1133    call htetraq%free()
1134  else
1135    ABI_WARNING('The netcdf PHIBZ file is only output for tetrahedron integration and DOS calculations')
1136  end if ! tetrahedra
1137 
1138  ! Test if the initial mesh was large enough
1139  call xmpi_sum(count_wminmax, comm, ierr)
1140  call xmpi_min(wminmax(1), rtmp, comm, ierr); wminmax(1) = rtmp
1141  call xmpi_max(wminmax(2), rtmp, comm, ierr); wminmax(2) = rtmp
1142 
1143  call xmpi_sum(phdos%phdos, comm, ierr)
1144  call xmpi_sum(phdos%msqd_dos_atom, comm, ierr)
1145  call xmpi_sum(phdos%pjdos, comm, ierr)
1146  if (prtdos == 2) then
1147    ! Reduce integrals if tetra, gauss will compute idos with simpson.
1148    call xmpi_sum(phdos%phdos_int, comm, ierr)
1149    call xmpi_sum(phdos%pjdos_int, comm, ierr)
1150  end if
1151 
1152 #if 0
1153  !my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
1154  !ABI_MALLOC(work_msqd, (phdos%nomega, 3, 3, crystal%natom))
1155  !work_msqd = phdos%msqd_dos_atom
1156  !phdos%msqd_dos_atom = zero
1157  !do iat=1,natom
1158  !  do isym=1,my_nsym
1159  !    jat = crystal%indsym(4,isym,iat)
1160  !    do io=1,phdos%nomega
1161  !        phdos%msqd_dos_atom(io,:,:,jat) = phdos%msqd_dos_atom(io,:,:,jat) + &
1162  !          matmul(transpose(symcart(:,:,isym)), matmul(work_msqd(io,:,:,iat), symcart(:,:,isym)))
1163  !    end do
1164  !  end do
1165  !end do
1166  !ABI_FREE(work_msqd)
1167  !phdos%msqd_dos_atom = phdos%msqd_dos_atom / my_nsym
1168 #endif
1169 
1170  ! normalize by mass and factor of 2, now added in the printout to agree with harmonic_thermo
1171  ! do iat=1, natom
1172  !   phdos%msqd_dos_atom(:,:,:,iat) = phdos%msqd_dos_atom(:,:,:,iat) * invmass(iat) * half
1173  ! end do ! iat
1174 
1175  ! ===============================
1176  ! === Compute Integrated PDOS ===
1177  ! ===============================
1178  ABI_CALLOC(phdos%pjdos_rc_type, (nomega, 3, crystal%ntypat))
1179  ABI_CALLOC(phdos%pjdos_type, (nomega, crystal%ntypat))
1180  ABI_CALLOC(phdos%pjdos_type_int, (nomega, crystal%ntypat))
1181 
1182  do iat=1,natom
1183    itype = crystal%typat(iat)
1184    do io=1,phdos%nomega
1185      phdos%pjdos_rc_type(io,:,itype) = phdos%pjdos_rc_type(io,:,itype) + phdos%pjdos(io,:,iat)
1186      phdos%pjdos_type(io,itype) = phdos%pjdos_type(io,itype) + sum(phdos%pjdos(io,:,iat))
1187    end do
1188    if (prtdos == 2) then
1189      do io=1,phdos%nomega
1190        phdos%pjdos_type_int(io,itype) = phdos%pjdos_type_int(io,itype) + sum(phdos%pjdos_int(io,:,iat))
1191      end do
1192    end if
1193  end do
1194 
1195  ! Evaluate IDOS using simple simpson integration
1196  ! In principle one could use derf.F90, just to be consistent ...
1197  if (prtdos == 1) then
1198    call simpson_int(phdos%nomega,phdos%omega_step, phdos%phdos, phdos%phdos_int)
1199    do iat=1,natom
1200      do idir=1,3
1201        call simpson_int(phdos%nomega, phdos%omega_step, phdos%pjdos(:,idir,iat), phdos%pjdos_int(:,idir,iat))
1202      end do
1203    end do
1204    do itype=1,crystal%ntypat
1205      call simpson_int(phdos%nomega, phdos%omega_step, phdos%pjdos_type(:,itype), phdos%pjdos_type_int(:,itype))
1206    end do
1207  end if
1208 
1209  ABI_FREE(qibz)
1210  ABI_FREE(wtq_ibz)
1211 
1212  call cwtime_report(" phdos_init", cpu_all, wall_all, gflops_all)
1213  DBG_EXIT("COLL")
1214 
1215 end subroutine phdos_init

m_phonons/phdos_malloc [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_malloc

FUNCTION

INPUTS

OUTPUT

SOURCE

631 subroutine phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos)
632 
633 ! Arguments ------------------------------------------------------
634  class(phdos_t),intent(out) :: phdos
635  type(crystal_t),intent(in) :: crystal
636  type(ifc_type),intent(in) :: ifc
637  integer,intent(in) :: prtdos
638  real(dp),intent(in) :: dosdeltae,dossmear
639  real(dp),intent(in) :: wminmax(2)
640 
641 !Local variables -------------------------
642  integer :: io
643 ! *********************************************************************
644 
645  phdos%ntypat     = crystal%ntypat
646  phdos%natom      = crystal%natom
647  phdos%prtdos     = prtdos
648  phdos%dossmear   = dossmear
649  phdos%omega_step = dosdeltae
650  ! Use values stored in ifc (obtained with ab-initio q-mesh + pad)
651  if (wminmax(2) > wminmax(1)) then
652    phdos%omega_min = wminmax(1)
653    phdos%omega_max = wminmax(2)
654  else
655    phdos%omega_min = ifc%omega_minmax(1)
656    phdos%omega_max = ifc%omega_minmax(2)
657  end if
658  ! Must be consistent with mesh computed in tetra routines!
659  phdos%nomega = nint((phdos%omega_max - phdos%omega_min) / phdos%omega_step) + 1
660  ! Ensure Simpson integration will be ok
661  phdos%nomega = max(6, phdos%nomega)
662 
663  ! Build frequency mesh.
664  ABI_MALLOC(phdos%omega, (phdos%nomega))
665  do io=1,phdos%nomega
666    phdos%omega(io) = phdos%omega_min + phdos%omega_step * (io - 1)
667  end do
668  phdos%omega_min = phdos%omega(1)
669  phdos%omega_max = phdos%omega(phdos%nomega)
670 
671  ! Allocate arrays that depend on nomega and set them to zero.
672  ABI_CALLOC(phdos%phdos, (phdos%nomega))
673  ABI_CALLOC(phdos%phdos_int, (phdos%nomega))
674  ABI_CALLOC(phdos%pjdos, (phdos%nomega, 3, crystal%natom))
675  ABI_CALLOC(phdos%pjdos_int, (phdos%nomega, 3, crystal%natom))
676  ABI_CALLOC(phdos%msqd_dos_atom, (phdos%nomega, 3, 3, crystal%natom))
677  ABI_MALLOC(phdos%atom_mass, (crystal%natom))
678  phdos%atom_mass = crystal%amu(crystal%typat(:)) * amu_emass
679 
680 end subroutine phdos_malloc

m_phonons/phdos_ncwrite [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_ncwrite

FUNCTION

  Save the content of the object in a netcdf file.

INPUTS

  ncid=NC file handle (open in the caller)
  phdos<phdos_t>=Container object

OUTPUT

  Only writing

NOTES

  Frequencies are in eV, DOS are in states/eV.

SOURCE

1718 subroutine phdos_ncwrite(phdos, ncid)
1719 
1720 !Arguments ------------------------------------
1721 !scalars
1722  class(phdos_t),intent(in) :: phdos
1723  integer,intent(in) :: ncid
1724 
1725 !Local variables-------------------------------
1726 !scalars
1727  integer :: ncerr
1728 
1729 ! *************************************************************************
1730 
1731 ! Define dimensions
1732  NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
1733 
1734  ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_atoms", phdos%natom),&
1735    nctkdim_t("number_of_atom_species", phdos%ntypat), nctkdim_t("number_of_frequencies", phdos%nomega), &
1736    nctkdim_t("nqibz", phdos%nqibz)])
1737  NCF_CHECK(ncerr)
1738 
1739 !scalars
1740  NCF_CHECK(nctk_def_iscalars(ncid, ["prtdos"]))
1741  NCF_CHECK(nctk_def_dpscalars(ncid, ["dossmear"]))
1742 
1743 !arrays
1744  ncerr = nctk_def_arrays(ncid, [&
1745    nctkarr_t('wmesh', "dp", 'number_of_frequencies'),&
1746    nctkarr_t('phdos', "dp", 'number_of_frequencies'),&
1747    nctkarr_t('pjdos', "dp", 'number_of_frequencies, three, number_of_atoms'),&
1748    nctkarr_t('pjdos_type', "dp", 'number_of_frequencies, number_of_atom_species'),&
1749    nctkarr_t('pjdos_rc_type', "dp", 'number_of_frequencies, three, number_of_atom_species'), &
1750    nctkarr_t('msqd_dos_atom', "dp", 'number_of_frequencies, three, three, number_of_atoms'), &
1751    nctkarr_t('qptrlatt', "int", 'three, three'), &
1752    nctkarr_t('shiftq', "dp", 'three') &
1753  ])
1754  NCF_CHECK(ncerr)
1755 
1756  ! Write variables. Note unit conversion.
1757  NCF_CHECK(nctk_set_datamode(ncid))
1758  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "prtdos"), phdos%prtdos))
1759  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'dossmear'), phdos%dossmear*Ha_eV))
1760  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'wmesh'), phdos%omega*Ha_eV))
1761  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'phdos'), phdos%phdos/Ha_eV))
1762  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos'), phdos%pjdos/Ha_eV))
1763  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos_type'), phdos%pjdos_type/Ha_eV))
1764  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos_rc_type'), phdos%pjdos_rc_type/Ha_eV))
1765  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'msqd_dos_atom'), phdos%msqd_dos_atom/Ha_eV))
1766  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'qptrlatt'), phdos%qptrlatt))
1767  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'shiftq'), phdos%shiftq))
1768 
1769 end subroutine phdos_ncwrite

m_phonons/phdos_print [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_print

FUNCTION

 Print out phonon DOS (and partial DOS etc) in meV units

INPUTS

 PHdos= container object for phonon DOS
 fname=File name for output

OUTPUT

  Only writing.

SOURCE

271 subroutine phdos_print(PHdos, fname)
272 
273 !Arguments ------------------------------------
274  class(phdos_t),intent(in) :: PHdos
275  character(len=*),intent(in) :: fname
276 
277 !Local variables-------------------------------
278  integer :: io,itype,unt,unt_by_atom,unt_msqd,iatom
279  real(dp) :: tens(3,3)
280  character(len=500) :: msg, msg_method
281  character(len=fnlen) :: fname_by_atom, fname_msqd
282  character(len=3) :: unitname
283 
284 ! *************************************************************************
285 
286 ! Use Ha units everywhere
287  unitname='Ha'
288 
289  select case (PHdos%prtdos)
290  case (1)
291    write(msg_method,'(a,es16.8,2a,i0)')&
292     '# Gaussian method with smearing = ',PHdos%dossmear,unitname,', nqibz =',PHdos%nqibz
293  case (2)
294    write(msg_method,'(a,i0)')'# Tetrahedron method, nqibz= ',PHdos%nqibz
295  case default
296    ABI_ERROR(sjoin(" Wrong prtdos: ",itoa(PHdos%prtdos)))
297  end select
298 
299  ! Open external file and write results
300  if (open_file(fname,msg,newunit=unt,form="formatted",action="write") /= 0) then
301    ABI_ERROR(msg)
302  end if
303  write(msg,'(3a)')'# ',ch10,'# Phonon density of states and atom type projected DOS'
304  call wrtout(unt,msg)
305  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
306  call wrtout(unt,msg)
307  call wrtout(unt,msg_method,'COLL')
308  write(msg,'(5a)')'# ',ch10,'# omega     PHDOS    INT_PHDOS   PJDOS[atom_type=1]  INT_PJDOS[atom_type=1] ...  ',ch10,'# '
309  call wrtout(unt,msg)
310  do io=1,PHdos%nomega
311    write(unt,'(3es17.8)',advance='NO')PHdos%omega(io),PHdos%phdos(io),PHdos%phdos_int(io)
312    do itype=1,PHdos%ntypat
313      write(unt,'(2es17.8,2x)',advance='NO')PHdos%pjdos_type(io,itype),PHdos%pjdos_type_int(io,itype)
314    end do
315    write(unt,*)
316  end do
317  close(unt)
318 
319  fname_by_atom = trim(fname) // "_by_atom"
320  if (open_file(fname_by_atom,msg,newunit=unt_by_atom,form="formatted",action="write") /= 0) then
321    ABI_ERROR(msg)
322  end if
323  write(msg,'(3a)')'# ',ch10,'# Phonon density of states and atom projected DOS'
324  call wrtout(unt_by_atom,msg)
325  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
326  call wrtout(unt_by_atom,msg)
327  call wrtout(unt_by_atom,msg_method)
328  write(msg,'(5a)')'# ',ch10,'# omega     PHDOS    PJDOS[atom=1]  PJDOS[atom=2] ...  ',ch10,'# '
329  call wrtout(unt_by_atom,msg)
330  do io=1,PHdos%nomega
331    write(unt_by_atom,'(2es17.8)',advance='NO')PHdos%omega(io),PHdos%phdos(io)
332    do iatom=1,PHdos%natom
333      write(unt_by_atom,'(1es17.8,2x)',advance='NO') sum(PHdos%pjdos(io,1:3,iatom))
334    end do
335    write(unt_by_atom,*)
336  end do
337  close(unt_by_atom)
338 
339  fname_msqd = trim(fname) // "_msqd"
340  if (open_file(fname_msqd,msg,newunit=unt_msqd,form="formatted",action="write") /= 0) then
341    ABI_ERROR(msg)
342  end if
343  write(msg,'(3a)')'# ',ch10,'# Phonon density of states weighted msq displacement matrix (set to zero below 1e-12)'
344  call wrtout(unt_msqd,msg)
345  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in bohr^2 states/',unitname
346  call wrtout(unt_msqd,msg)
347  call wrtout(unt_msqd,msg_method)
348  write(msg,'(5a)')'# ',ch10,'# omega     MSQDisp[atom=1, xx, yy, zz, yz, xz, xy]  MSQDisp[atom=2, xx, yy,...] ...  ',ch10,'# '
349  call wrtout(unt_msqd,msg)
350  do io=1,PHdos%nomega
351    write(unt_msqd,'(2es17.8)',advance='NO')PHdos%omega(io)
352    do iatom=1,PHdos%natom
353      tens = PHdos%msqd_dos_atom(io,:,:,iatom)
354      where (abs(tens) < tol12)
355         tens = zero
356      end where
357      write(unt_msqd,'(6es17.8,2x)',advance='NO') &
358         tens(1,1), &
359         tens(2,2), &
360         tens(3,3), &
361         tens(2,3), &
362         tens(1,3), &
363         tens(1,2)
364    end do
365    write(unt_msqd,*)
366  end do
367  close(unt_msqd)
368 
369 end subroutine phdos_print

m_phonons/phdos_print_msqd [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_print_msqd

FUNCTION

  Print out mean square displacement and velocity for each atom (trace and full matrix) as a function of T
  see for example https://atztogo.github.io/phonopy/thermal-displacement.html#thermal-displacement
  Only master node should call this routine.

INPUTS

   PHdos structure

OUTPUT

   to file only

SOURCE

2216 subroutine phdos_print_msqd(PHdos, fname, ntemper, tempermin, temperinc)
2217 
2218 !Arguments -------------------------------
2219 !scalars
2220  integer, intent(in) :: ntemper
2221  class(phdos_t),intent(in) :: PHdos
2222  character(len=*),intent(in) :: fname
2223  real(dp), intent(in) :: tempermin, temperinc
2224 
2225 !Local variables -------------------------
2226  integer :: io, iomin, itemp, iunit, junit, iatom
2227  real(dp) :: temper
2228  character(len=500) :: msg
2229  character(len=fnlen) :: fname_msqd
2230  character(len=fnlen) :: fname_veloc
2231 !arrays
2232  real(dp), allocatable :: bose_msqd(:,:), tmp_msqd(:,:), integ_msqd(:,:)
2233  real(dp), allocatable :: bose_msqv(:,:), tmp_msqv(:,:), integ_msqv(:,:)
2234 
2235 ! *********************************************************************
2236 
2237  fname_msqd = trim(fname) //"_MSQD_T"
2238  if (open_file(fname_msqd, msg, newunit=iunit, form="formatted", status="unknown", action="write") /= 0) then
2239    ABI_ERROR(msg)
2240  end if
2241  fname_veloc = trim(fname) // "_MSQV_T"
2242  if (open_file(fname_veloc, msg, newunit=junit, form="formatted", status="unknown", action="write") /= 0) then
2243    ABI_ERROR(msg)
2244  end if
2245 
2246  ! write the header
2247  write (iunit, '(a)') '# mean square displacement for each atom as a function of T (bohr^2)'
2248  write (junit, '(a)') "# mean square velocity for each atom as a function of T (bohr^2/atomic time unit^2)"
2249 
2250  write (msg, '(a,F18.10,a,F18.10,a)') '#  T in Kelvin, from ', tempermin, ' to ', tempermin+(ntemper-1)*temperinc
2251  write (iunit, '(a)') trim(msg)
2252  write (junit, '(a)') trim(msg)
2253 
2254  write (msg, '(2a)') '#    T             |u^2|                u_xx                u_yy                u_zz',&
2255                      '                u_yz                u_xz                u_xy in bohr^2'
2256  write (iunit, '(a)') trim(msg)
2257  write (msg, '(3a)') '#    T             |v^2|                v_xx                v_yy                v_zz',&
2258                      '                v_yz                v_xz                v_xy',&
2259                      ' in bohr^2/atomic time unit^2'
2260  write (junit, '(a)') trim(msg)
2261 
2262  ABI_MALLOC(tmp_msqd, (PHdos%nomega,9))
2263  ABI_MALLOC(tmp_msqv, (PHdos%nomega,9))
2264  ABI_MALLOC(integ_msqd, (9,ntemper))
2265  ABI_MALLOC(integ_msqv, (9,ntemper))
2266  ABI_MALLOC(bose_msqd, (PHdos%nomega, ntemper))
2267  ABI_MALLOC(bose_msqv, (PHdos%nomega, ntemper))
2268 
2269  do io=1, PHdos%nomega
2270    if ( PHdos%omega(io) >= 2._dp * 4.56d-6 ) exit ! 2 cm-1 TODO: make this an input parameter
2271  end do
2272  iomin = io
2273 
2274  ! calculate bose only once for each atom (instead of for each atom)
2275  bose_msqd = zero
2276  bose_msqv = zero
2277  do itemp = 1, ntemper
2278    temper = tempermin + (itemp-1) * temperinc
2279    if (temper < 1.e-3) cycle ! millikelvin at least to avoid exploding Bose factor(TM)
2280    do io = iomin, PHdos%nomega
2281      ! NB: factors follow convention in phonopy documentation
2282      ! the 1/sqrt(omega) factor in phonopy is contained in the displacement vector definition
2283      ! bose() is dimensionless
2284      !bose_msqd(io, itemp) =  (half + one  / ( exp(PHdos%omega(io)/(kb_HaK*temper)) - one )) / PHdos%omega(io)
2285      !bose_msqv(io, itemp) =  (half + one  / ( exp(PHdos%omega(io)/(kb_HaK*temper)) - one )) * PHdos%omega(io)
2286      bose_msqd(io, itemp) =  (half + bose_einstein(PHdos%omega(io),kb_HaK*temper)) / PHdos%omega(io)
2287      bose_msqv(io, itemp) =  (half + bose_einstein(PHdos%omega(io),kb_HaK*temper)) * PHdos%omega(io)
2288    end do
2289  end do
2290 
2291  do iatom=1,PHdos%natom
2292    write (msg, '(a,I8)') '# atom number ', iatom
2293    write (iunit, '(a)') trim(msg)
2294    write (junit, '(a)') trim(msg)
2295 
2296    ! for each T and each atom, integrate msqd matrix with Bose Einstein factor and output
2297    integ_msqd = zero
2298    tmp_msqd = reshape(PHdos%msqd_dos_atom(:,:,:,iatom), (/PHdos%nomega, 9/))
2299 
2300    ! perform all integrations as matrix multiplication: integ_msqd (idir, itemp) = [tmp_msqd(io,idir)]^T  * bose_msqd(io,itemp)
2301    call DGEMM('T','N', 9, ntemper, PHdos%nomega, one, tmp_msqd,PHdos%nomega, bose_msqd, PHdos%nomega, zero, integ_msqd, 9)
2302    ! NB: this presumes an equidistant omega grid
2303    integ_msqd = integ_msqd * (PHdos%omega(2)-PHdos%omega(1)) / PHdos%atom_mass(iatom)
2304 
2305    integ_msqv = zero
2306    tmp_msqv = reshape(PHdos%msqd_dos_atom(:,:,:,iatom), (/PHdos%nomega, 9/))
2307 
2308    ! perform all integrations as matrix multiplication: integ_msqv (idir, itemp) = [tmp_msqv(io,idir)]^T  * bose_msqv(io,itemp)
2309    call DGEMM('T','N', 9, ntemper, PHdos%nomega, one, tmp_msqv,PHdos%nomega, bose_msqv, PHdos%nomega, zero, integ_msqv, 9)
2310    ! NB: this presumes an equidistant omega grid
2311    integ_msqv = integ_msqv * (PHdos%omega(2)-PHdos%omega(1)) / PHdos%atom_mass(iatom)
2312 
2313    ! print out stuff
2314    do itemp = 1, ntemper
2315      temper = tempermin + (itemp-1) * temperinc
2316      write (msg, '(F10.2,4x,E22.10,2x,6E22.10)') &
2317        temper, third*(integ_msqd(1,itemp)+integ_msqd(5,itemp)+integ_msqd(9,itemp)), &
2318                       integ_msqd(1,itemp),integ_msqd(5,itemp),integ_msqd(9,itemp), &
2319                       integ_msqd(6,itemp),integ_msqd(3,itemp),integ_msqd(2,itemp)
2320      write (iunit, '(a)') trim(msg)
2321      write (msg, '(F10.2,4x,E22.10,2x,6E22.10)') &
2322        temper, third*(integ_msqv(1,itemp)+integ_msqv(5,itemp)+integ_msqv(9,itemp)), &
2323                       integ_msqv(1,itemp),integ_msqv(5,itemp),integ_msqv(9,itemp), &
2324                       integ_msqv(6,itemp),integ_msqv(3,itemp),integ_msqv(2,itemp)
2325      write (junit, '(a)') trim(msg)
2326    end do ! itemp
2327 
2328    write (iunit, '(a)') ''
2329    write (junit, '(a)') ''
2330  enddo ! iatom
2331 
2332  ABI_FREE(tmp_msqd)
2333  ABI_FREE(tmp_msqv)
2334  ABI_FREE(bose_msqd)
2335  ABI_FREE(bose_msqv)
2336  ABI_FREE(integ_msqd)
2337  ABI_FREE(integ_msqv)
2338 
2339  close(iunit)
2340  close(junit)
2341 
2342 end subroutine phdos_print_msqd

m_phonons/phdos_print_vsound [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phdos_print_vsound

FUNCTION

  Print out estimate speed of sound and Debye temperature at this (small) q
  should only be called by master proc for the hard unit number

INPUTS

 unit=Fortran unit number
 speedofsound(3)

OUTPUT

SOURCE

2156 subroutine phdos_print_vsound(iunit,ucvol,speedofsound)
2157 
2158 !Arguments -------------------------------
2159 !scalras
2160  integer, intent(in) :: iunit
2161  real(dp), intent(in) :: ucvol
2162 !arrays
2163  real(dp), intent(in) :: speedofsound(3)
2164 
2165 !Local variables -------------------------
2166  integer :: imode_acoustic
2167  character(len=500) :: msg
2168  real(dp) :: tdebye
2169 
2170 ! *********************************************************************
2171 
2172  do imode_acoustic = 1, 3
2173    ! from phonon frequency, estimate speed of sound by linear interpolation from Gamma
2174    write (msg, '(2a,a,E20.10,a,a,F20.5)') &
2175     ' Speed of sound for this q and mode:',ch10,&
2176     '   in atomic units: ', speedofsound(imode_acoustic), ch10,&
2177     '   in units km/s: ', speedofsound(imode_acoustic) * Bohr_Ang * 1.d-13 / Time_Sec
2178    call wrtout(iunit, msg)
2179    call wrtout(std_out, msg)
2180 
2181    ! also estimate partial Debye temperature, = energy if this band went to zone edge
2182    tdebye = speedofsound(imode_acoustic) * pi * (six / pi / ucvol)**(third)
2183    write (msg, '(2a,a,E20.10,a,a,F20.5)') &
2184     ' Partial Debye temperature for this q and mode:',ch10,&
2185     '   in atomic units: ', tdebye, ch10,&
2186     '   in SI units K  : ', tdebye * Ha_K
2187    call wrtout(iunit,msg)
2188    call wrtout(iunit,"")
2189    call wrtout(std_out,msg)
2190    call wrtout(std_out,"")
2191  end do
2192 
2193 end subroutine phdos_print_vsound

m_phonons/phdos_t [ Types ]

[ Top ] [ m_phonons ] [ Types ]

NAME

 phdos_t

FUNCTION

 Container for phonon DOS and atom projected contributions

SOURCE

 87  type,public :: phdos_t
 88 
 89   integer :: ntypat
 90   ! Number of type of atoms.
 91 
 92   integer :: natom
 93   ! Number of atoms is the unit cell.
 94 
 95   integer :: prtdos
 96   ! Option of DOS calculation (1 for Gaussian, 2 for tetrahedrons).
 97 
 98   integer :: nomega
 99   ! Number of frequency points in DOS mesh.
100 
101   integer :: nqibz
102   ! Number of q-points in the IBZ.
103 
104   real(dp) :: omega_min
105   ! Min frequency for DOS calculation.
106 
107   real(dp) :: omega_max
108   ! Max frequency for DOS calculation.
109 
110   real(dp) :: omega_step
111   ! Frequency step.
112 
113   real(dp) :: dossmear
114   ! Gaussian broadening.
115 
116   integer :: qptrlatt(3,3) = 0
117   ! q-mesh as computed in getkgrid_low
118 
119   real(dp) :: shiftq(3)
120   ! Shigt of Q-mesh computed by getkgrid_low (1 shift is enough)
121 
122   real(dp),allocatable :: atom_mass(:)
123    ! atom_mass(natom)
124 
125   real(dp),allocatable :: omega(:)
126    ! omega(nomega)
127    ! Frequency grid.
128 
129   real(dp),allocatable :: phdos(:)
130    ! phdos(nomega)
131    ! phonon DOS.
132 
133   real(dp),allocatable :: phdos_int(:)
134    ! phdos_int(nomega)
135    ! integrated phonon DOS
136 
137   real(dp),allocatable :: pjdos(:,:,:)
138    ! pjdos(nomega,3,natom)
139    ! projected DOS (over atoms and cartesian directions)
140 
141   real(dp),allocatable :: pjdos_int(:,:,:)
142    ! pjdos_int(nomega,3,natom)
143    ! Integrated atomic PJDOS along the three cartesian directions.
144 
145   real(dp),allocatable :: pjdos_type(:,:)
146    ! pjdos_type(nomega,ntypat)
147    ! phonon DOS contribution arising from a particular atom-type.
148 
149   real(dp),allocatable :: pjdos_type_int(:,:)
150    ! pjdos_type_int(nomega,ntypat)
151    ! Integrate phonon DOS contribution arising from a particular atom-type.
152 
153   real(dp),allocatable :: pjdos_rc_type(:,:,:)
154    ! phdos(nomega,3,ntypat)
155    ! phonon DOS contribution arising from a particular atom-type
156    ! decomposed along the three cartesian directions.
157 
158   real(dp),allocatable :: msqd_dos_atom(:,:,:,:)
159    ! msqd_dos_atom(nomega,3,3,natom)
160    ! mean square displacement matrix, frequency dependent like a DOS, tensor in cartesian coords.
161    ! allows one to calculate Debye Waller factors by integration with 1/omega
162    ! and the Bose Einstein factor
163 
164  contains
165 
166    procedure :: print => phdos_print
167    procedure :: print_debye => phdos_print_debye
168    procedure :: print_msqd => phdos_print_msqd
169    procedure :: print_thermo => phdos_print_thermo
170    procedure :: free => phdos_free
171    procedure :: ncwrite => phdos_ncwrite
172    procedure :: init => phdos_init  ! Constructor
173  end type phdos_t

m_phonons/pheigvec_rotate [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 pheigvec_rotate

FUNCTION

  Return phonon eigenvectors for q in the BZ from the symmetrical image in the IBZ.

INPUTS

  cryst: crystal structure
  qq_ibz: q-point in the IBZ
  isym
  itimrev
  eigvec_ibz: Input phonon eigenvectors at qq_ibz.

OUTPUT

  eigvec_bz: phonon eigenvectors at q_bz.
  displ_cart_qbz: phonon displacement at q_bz in Cartesian coordinates.
  [displ_red_qbz]: phonon displacement at q_bz in reduced coordinates.


m_phonons/phonons_ncwrite [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phonons_ncwrite

FUNCTION

  Write phonon bandstructure in a netcdf file.

INPUTS

  ncid =NC file handle
  natom=Number of atoms
  nqpts=Number of q-points.
  qpoints=List of q-points in reduced coordinates
  weights(nqpts)= q-point weights
  phfreq=Phonon frequencies
  phdispl_cart=Phonon displacementent in Cartesian coordinates.
  phangmom= Phonon angular momentum in cartesian coordinates

NOTES

  Input data is in a.u, whereas the netcdf files saves data in eV for frequencies
  and Angstrom for the displacements
  The angular momentum is output in units of hbar

OUTPUT

  Only writing

SOURCE

2374 subroutine phonons_ncwrite(ncid,natom,nqpts,qpoints,weights,phfreq,phdispl_cart,phangmom)
2375 
2376 !Arguments ------------------------------------
2377 !scalars
2378  integer,intent(in) :: ncid,natom,nqpts
2379 !arrays
2380  real(dp),intent(in) :: qpoints(3,nqpts),weights(nqpts)
2381  real(dp),intent(in) :: phfreq(3*natom,nqpts),phdispl_cart(2,3*natom,3*natom,nqpts),phangmom(3,3*natom,nqpts)
2382 
2383 !Local variables-------------------------------
2384 !scalars
2385  integer :: nphmodes,ncerr
2386 
2387 ! *************************************************************************
2388 
2389  nphmodes = 3*natom
2390 
2391  NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
2392 
2393  ncerr = nctk_def_dims(ncid, [&
2394    nctkdim_t("number_of_qpoints", nqpts), nctkdim_t('number_of_phonon_modes', nphmodes), nctkdim_t('three', 3)])
2395  NCF_CHECK(ncerr)
2396 
2397  ! Define arrays
2398  ncerr = nctk_def_arrays(ncid, [&
2399    nctkarr_t('qpoints', "dp" , 'number_of_reduced_dimensions, number_of_qpoints'),&
2400    nctkarr_t('qweights',"dp", 'number_of_qpoints'),&
2401    nctkarr_t('phfreqs',"dp", 'number_of_phonon_modes, number_of_qpoints'),&
2402    nctkarr_t('phdispl_cart',"dp", 'complex, number_of_phonon_modes, number_of_phonon_modes, number_of_qpoints'),&
2403    nctkarr_t('phangmom',"dp", 'three, number_of_phonon_modes, number_of_qpoints')])
2404  NCF_CHECK(ncerr)
2405 
2406  ! Write variables.
2407  NCF_CHECK(nctk_set_datamode(ncid))
2408  NCF_CHECK(nf90_put_var(ncid, vid('qpoints'), qpoints))
2409  NCF_CHECK(nf90_put_var(ncid, vid('qweights'), weights))
2410  NCF_CHECK(nf90_put_var(ncid, vid('phfreqs'), phfreq*Ha_eV))
2411  NCF_CHECK(nf90_put_var(ncid, vid('phdispl_cart'), phdispl_cart*Bohr_Ang))
2412  NCF_CHECK(nf90_put_var(ncid, vid('phangmom'), phangmom))
2413 
2414 
2415 contains
2416 integer function vid(vname)
2417  character(len=*),intent(in) :: vname
2418  vid = nctk_idname(ncid, vname)
2419 end function vid
2420 
2421 end subroutine phonons_ncwrite

m_phonons/phonons_write_gnuplot [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phonons_write_gnuplot

FUNCTION

  Write phonons bands in gnuplot format. This routine should be called by a single processor.

INPUTS

  prefix=prefix for files (.data, .gnuplot)
  natom=Number of atoms
  nqpts=Number of q-points
  qpts(3,nqpts)=Q-points
  phfreqs(3*natom,nqpts)=Phonon frequencies.
  [qptbounds(:,:)]=Optional argument giving the extrema of the q-path.

OUTPUT

  Only writing

SOURCE

2691 subroutine phonons_write_gnuplot(prefix, natom, nqpts, qpts, phfreqs, qptbounds)
2692 
2693 !Arguments ------------------------------------
2694 !scalars
2695  integer,intent(in) :: natom,nqpts
2696  real(dp),intent(in) :: qpts(3,nqpts),phfreqs(3*natom,nqpts)
2697  character(len=*),intent(in) :: prefix
2698 !arrays
2699  real(dp),optional,intent(in) :: qptbounds(:,:)
2700 
2701 !Local variables-------------------------------
2702 !scalars
2703  integer :: unt,iq,ii,start,nqbounds,gpl_unt
2704  character(len=500) :: msg,fmt
2705  character(len=fnlen) :: datafile,basefile
2706 !arrays
2707  integer :: g0(3)
2708  integer,allocatable :: bounds2qpt(:)
2709 
2710 ! *********************************************************************
2711 
2712  nqbounds = 0
2713  if (present(qptbounds)) then
2714    if (product(shape(qptbounds)) > 0 ) then
2715      ! Find correspondence between qptbounds and k-points in ebands.
2716      nqbounds = size(qptbounds, dim=2)
2717      ABI_MALLOC(bounds2qpt, (nqbounds))
2718      bounds2qpt = 1; start = 1
2719      do ii=1,nqbounds
2720         do iq=start,nqpts
2721           if (isamek(qpts(:, iq), qptbounds(:, ii), g0)) then
2722             bounds2qpt(ii) = iq; start = iq + 1; exit
2723           end if
2724         end do
2725      end do
2726    end if
2727  end if
2728 
2729  datafile = strcat(prefix, "_PHBANDS.data")
2730  if (open_file(datafile, msg, newunit=unt, form="formatted", action="write") /= 0) then
2731    ABI_ERROR(msg)
2732  end if
2733  if (open_file(strcat(prefix, "_PHBANDS.gnuplot"), msg, newunit=gpl_unt, form="formatted", action="write") /= 0) then
2734    ABI_ERROR(msg)
2735  end if
2736  basefile = basename(datafile)
2737 
2738  write(unt,'(a)') "# Phonon band structure data file"
2739  write(unt,'(a)') "# Generated by Abinit"
2740  write(unt,'(2(a,i0))') "# natom: ",natom,", nqpt: ",nqpts
2741  write(unt,'(a)') "# Frequencies are in meV"
2742  write(unt,'(a)')"# List of q-points and their index (C notation i.e. count from 0)"
2743  do iq=1,nqpts
2744    write(unt, "(a)")sjoin("#", itoa(iq-1), ktoa(qpts(:,iq)))
2745  end do
2746 
2747  fmt = sjoin("(i0,1x,", itoa(3*natom), "(es16.8,1x))")
2748  write(unt,'(a)')"# [kpt-index, mode_1, mode_2 ...]"
2749  do iq=1,nqpts
2750    write(unt, fmt) iq-1, phfreqs(:, iq) * Ha_meV
2751  end do
2752 
2753  ! gnuplot script file
2754   write(gpl_unt,'(a)') '# File to plot electron bandstructure with gnuplot'
2755   !write(gpl_unt,'(a)') "#set terminal postscript eps enhanced color font 'Times-Roman,26' lw 2"
2756   write(gpl_unt,'(a)') '#use the next lines to make a nice figure for a paper'
2757   write(gpl_unt,'(a)') '#set term postscript enhanced eps color lw 0.5 dl 0.5'
2758   write(gpl_unt,'(a)') '#set pointsize 0.275'
2759   write(gpl_unt,'(a)') 'set palette defined ( 0 "blue", 3 "green", 6 "yellow", 10 "red" )'
2760   write(gpl_unt,'(a)') 'unset key'
2761   write(gpl_unt,'(a)') '# can make pointsize smaller (~0.5). Too small and nothing is printed'
2762   write(gpl_unt,'(a)') 'set pointsize 0.8'
2763   write(gpl_unt,'(a)') 'set view 0,0'
2764   write(gpl_unt,'(a,i0,a)') 'set xrange [0:',nqpts-1,']'
2765   write(gpl_unt,'(2(a,es16.8),a)')&
2766     'set yrange [',minval(phfreqs * Ha_meV),':',maxval(phfreqs * Ha_meV),']'
2767   write(gpl_unt,'(a)') 'set xlabel "Momentum"'
2768   write(gpl_unt,'(a)') 'set ylabel "Energy [meV]"'
2769   write(gpl_unt,'(a)') strcat('set title "', replace(basefile, "_", "\\_"),'"')
2770   if (nqbounds == 0) then
2771      write(gpl_unt,'(a)') 'set grid xtics'
2772   else
2773     write(gpl_unt,"(a)")"# Add vertical lines in correspondence of high-symmetry points."
2774     write(gpl_unt,'(a)') 'unset xtics'
2775     do ii=1,nqbounds
2776       write(gpl_unt,"(a,2(i0,a))") &
2777         "set arrow from ",bounds2qpt(ii)-1,",graph(0,0) to ",bounds2qpt(ii)-1,",graph(1,1) nohead"
2778       !write(gpl_unt,"(a)")sjoin("set xtics add ('kname'", itoa(bounds2kpt(ii)-1), ")")
2779     end do
2780   end if
2781   write(gpl_unt,"(a)")sjoin("nbranch =", itoa(3*natom))
2782   write(gpl_unt,"(a)")strcat('plot for [i=2:nbranch] "', basefile, '" u 1:i every :1 with lines linetype -1')
2783   write(gpl_unt,"(a)")"pause -1"
2784 
2785  close(unt)
2786  close(gpl_unt)
2787 
2788  ABI_SFREE(bounds2qpt)
2789 
2790 end subroutine phonons_write_gnuplot

m_phonons/phonons_write_phfrq [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phonons_write_phfrq

FUNCTION

  Write phonon bandstructure in a text file. Fixed file name for the moment

INPUTS

  natom=Number of atoms
  nqpts=Number of q-points.
  qpoints=List of q-points in reduced coordinates
  weights(nqpts)= q-point weights
  phfreq=Phonon frequencies
  phdispl_cart=Phonon displacementent in Cartesian coordinates.

NOTES

  Input data is in a.u, output too

OUTPUT

  Only writing

SOURCE

2449  subroutine phonons_write_phfrq(path,natom,nqpts,qpoints,weights,phfreq,phdispl_cart,phangmom)
2450 
2451 !Arguments ------------------------------------
2452 !scalars
2453  integer,intent(in) :: natom,nqpts
2454  character(len=*),intent(in) :: path
2455 !arrays
2456  real(dp),intent(in) :: qpoints(3,nqpts),weights(nqpts)
2457  real(dp),intent(in) :: phfreq(3*natom,nqpts)
2458  real(dp),intent(in) :: phdispl_cart(2,3*natom,3*natom,nqpts)
2459  real(dp),intent(in) :: phangmom(3,3*natom,nqpts)
2460 
2461 !Local variables-------------------------------
2462 !scalars
2463  integer :: nphmodes, iq, iunit, imod, icomp
2464  real(dp) :: dummy
2465  character(len=300) :: formt
2466  character(len=500) :: msg
2467 
2468 ! *************************************************************************
2469 
2470  nphmodes = 3*natom
2471 
2472  dummy = qpoints(1,1); dummy = weights(1)
2473 
2474  ! Write phonon frequencies
2475  if (open_file(strcat(path, "_PHFRQ"), msg, newunit=iunit, form="formatted", status="unknown", action="write") /= 0) then
2476    ABI_ERROR(msg)
2477  end if
2478 
2479  write (iunit, '(a)')  '# ABINIT generated phonon band structure file. All in Ha atomic units'
2480  write (iunit, '(a)')  '# '
2481  write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
2482  write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
2483  write (iunit, '(a)')  '# '
2484 
2485  write (formt,'(a,i0,a)') "(I5, ", nphmodes, "E20.10)"
2486  do iq= 1, nqpts
2487    write (iunit, formt)  iq, phfreq(:,iq)
2488  end do
2489 
2490  close(iunit)
2491 
2492  ! Does not Write phonon displacement ?
2493  if (.False.) then
2494    if (open_file(strcat(path, "_PHDISPL"), msg, unit=iunit, form="formatted", status="unknown", action="write") /= 0) then
2495      ABI_ERROR(msg)
2496    end if
2497 
2498    write (iunit, '(a)')     '# ABINIT generated phonon displacements, along points in PHFRQ file. All in Ha atomic units'
2499    write (iunit, '(a)')     '# '
2500    write (iunit, '(a)')     '# displacements in cartesian coordinates, Re and Im parts '
2501    write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
2502    write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
2503    write (iunit, '(a)')     '# '
2504 
2505    !write (formt,'(a,I3,a)') "( ", nphmodes, "(2E20.10,2x))"
2506    formt = "(2E20.10,2x)"
2507 
2508    do iq = 1, nqpts
2509      write (iunit, '(a, i0)') '# iq ', iq
2510      do imod = 1, nphmodes
2511        write (iunit, '(a, i0)') '# imode ', imod
2512        do icomp = 1, nphmodes
2513          write (iunit, formt, ADVANCE='NO') phdispl_cart(:,icomp,imod,iq)
2514        end do
2515        write (iunit, '(a)') ' '
2516      end do
2517    end do
2518 
2519    close(iunit)
2520  end if
2521 
2522  ! Write phonon angular momentum
2523  if (open_file(strcat(path, "_PHANGMOM"), msg, unit=iunit, form="formatted", status="unknown", action="write") /= 0) then
2524    ABI_ERROR(msg)
2525  end if
2526 
2527  write (iunit, '(a)')     '# ABINIT generated phonon angular momentum, along points in PHFRQ file. All in Ha atomic units'
2528  write (iunit, '(a)')     '# '
2529  write (iunit, '(a)')     '# angular momentum in cartesian coordinates '
2530  write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
2531  write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
2532  write (iunit, '(a)')     '# '
2533 
2534  write (formt,'(a,i0,a)') "(I5, ", nphmodes, "E20.10)"
2535  do icomp = 1, 3
2536    do iq= 1, nqpts
2537      write (iunit, formt)  iq, phangmom(icomp,:,iq)
2538    end do
2539    if (icomp /= 3) then
2540      write (iunit, '(a,a)') ''
2541    end if
2542  end do
2543 
2544  close(iunit)
2545 
2546 end subroutine phonons_write_phfrq

m_phonons/phonons_write_xmgrace [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phonons_write_xmgrace

FUNCTION

  Write phonons bands in Xmgrace format. This routine should be called by a single processor.

INPUTS

  filename=Filename
  natom=Number of atoms
  nqpts=Number of q-points
  qpts(3,nqpts)=Q-points
  phfreqs(3*natom,nqpts)=Phonon frequencies.
  [qptbounds(:,:)]=Optional argument giving the extrema of the q-path.

OUTPUT

  Only writing

SOURCE

2571 subroutine phonons_write_xmgrace(filename, natom, nqpts, qpts, phfreqs, qptbounds)
2572 
2573 !Arguments ------------------------------------
2574 !scalars
2575  integer,intent(in) :: natom,nqpts
2576  real(dp),intent(in) :: qpts(3,nqpts),phfreqs(3*natom,nqpts)
2577  character(len=*),intent(in) :: filename
2578 !arrays
2579  real(dp),optional,intent(in) :: qptbounds(:,:)
2580 
2581 !Local variables-------------------------------
2582 !scalars
2583  integer :: unt,iq,nu,ii,start,nqbounds
2584  character(len=500) :: msg
2585 !arrays
2586  integer :: g0(3)
2587  integer,allocatable :: bounds2qpt(:)
2588 
2589 ! *********************************************************************
2590 
2591  nqbounds = 0
2592  if (present(qptbounds)) then
2593    if (product(shape(qptbounds)) > 0 ) then
2594      ! Find correspondence between qptbounds and k-points in ebands.
2595      nqbounds = size(qptbounds, dim=2)
2596      ABI_MALLOC(bounds2qpt, (nqbounds))
2597      bounds2qpt = 1; start = 1
2598      do ii=1,nqbounds
2599         do iq=start,nqpts
2600           if (isamek(qpts(:, iq), qptbounds(:, ii), g0)) then
2601             bounds2qpt(ii) = iq; start = iq + 1; exit
2602           end if
2603         end do
2604      end do
2605    end if
2606  end if
2607 
2608  if (open_file(filename, msg, newunit=unt, form="formatted", action="write") /= 0) then
2609    ABI_ERROR(msg)
2610  end if
2611 
2612  write(unt,'(a)') "# Grace project file"
2613  write(unt,'(a)') "# Generated by Abinit"
2614  write(unt,'(2(a,i0))') "# natom: ",natom,", nqpt: ",nqpts
2615  write(unt,'(a)') "# Frequencies are in meV"
2616  write(unt,'(a)')"# List of q-points and their index (C notation i.e. count from 0)"
2617  do iq=1,nqpts
2618    write(unt, "(a)")sjoin("#", itoa(iq-1), ktoa(qpts(:,iq)))
2619  end do
2620 
2621  write(unt,'(a)') "@page size 792, 612"
2622  write(unt,'(a)') "@page scroll 5%"
2623  write(unt,'(a)') "@page inout 5%"
2624  write(unt,'(a)') "@link page off"
2625  write(unt,'(a)') "@with g0"
2626  write(unt,'(a)') "@world xmin 0.00"
2627  write(unt,'(a,i0)') '@world xmax ',nqpts
2628  write(unt,'(a,e16.8)') '@world ymin ',minval(phfreqs * Ha_meV)
2629  write(unt,'(a,e16.8)') '@world ymax ',maxval(phfreqs * Ha_meV)
2630  write(unt,'(a)') '@default linewidth 1.5'
2631  write(unt,'(a)') '@xaxis  tick on'
2632  write(unt,'(a)') '@xaxis  tick major 1'
2633  write(unt,'(a)') '@xaxis  tick major color 1'
2634  write(unt,'(a)') '@xaxis  tick major linestyle 3'
2635  write(unt,'(a)') '@xaxis  tick major grid on'
2636  write(unt,'(a)') '@xaxis  tick spec type both'
2637  write(unt,'(a)') '@xaxis  tick major 0, 0'
2638  if (nqbounds /= 0) then
2639    write(unt,'(a,i0)') '@xaxis  tick spec ',nqbounds
2640    do iq=1,nqbounds
2641      !write(unt,'(a,i0,a,a)') '@xaxis  ticklabel ',iq-1,',', "foo"
2642      write(unt,'(a,i0,a,i0)') '@xaxis  tick major ',iq-1,' , ',bounds2qpt(iq) - 1
2643    end do
2644  end if
2645  write(unt,'(a)') '@xaxis  ticklabel char size 1.500000'
2646  write(unt,'(a)') '@yaxis  tick major 10'
2647  write(unt,'(a)') '@yaxis  label "Phonon Energy [meV]"'
2648  write(unt,'(a)') '@yaxis  label char size 1.500000'
2649  write(unt,'(a)') '@yaxis  ticklabel char size 1.500000'
2650  do nu=1,3*natom
2651    write(unt,'(a,i0,a)') '@    s',nu-1,' line color 1'
2652  end do
2653  do nu=1,3*natom
2654    write(unt,'(a,i0)') '@target G0.S',nu-1
2655    write(unt,'(a)') '@type xy'
2656    do iq=1,nqpts
2657       write(unt,'(i0,1x,e16.8)') iq-1, phfreqs(nu, iq) * Ha_meV
2658    end do
2659    write(unt,'(a)') '&'
2660  end do
2661 
2662  close(unt)
2663 
2664  ABI_SFREE(bounds2qpt)
2665 
2666 end subroutine phonons_write_xmgrace

m_phonons/phstore_async_rotate [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phstore_async_rotate

FUNCTION

  Begin non-blocking collective MPI communication inside self%comm to obtain
  phonon frequencies and eigenvectors in the BZ from data in the IBZ.

INPUTS


m_phonons/phstore_free [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phstore_free

FUNCTION

  Free dynamic memory.

INPUTS


m_phonons/phstore_new [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phstore_new

FUNCTION

  Create new object with phonon quantities in the IBZ.

INPUTS

  cryst: Crystal structure
  ifc: Interatomic force constants.
  nqibz: Number of q-points in the IBZ.
  qibz: q-points in the IBZ
  use_ifc_fourq:  True to replace symmetrization with call to ifc_fourq (debugging option)
  comm: MPI communicator in which phonon arrays in the IBZ will be MPI distributed.

m_phonons/phstore_t [ Types ]

[ Top ] [ m_phonons ] [ Types ]

NAME

 phstore_t

FUNCTION

  This object stores ph eigenvalues and eigenvectors in the IBZ and provides methods
  to compute the corresponding quantites in the full BZ using symmetries.
  Useful for very intensive loops of q-points in the BZ in which the call to ifc_fourq
  may become a significant bottleneck.
  Note that IBZ quantities are memory-distributed inside the MPI communicator comm.
  and the symmetrization is performed in a non-blocking fashion so that it's possible to overlap
  the symmetrization with computations. See sigmaph for usage.

SOURCE

192  type,public :: phstore_t
193 
194    integer :: nqibz
195    ! Number of q-points in the IBZ
196 
197    integer :: comm
198    ! MPI communicator used to distribute memory.
199 
200    integer :: nprocs
201    ! Number of MPI procs in comm.
202 
203    integer :: my_rank
204    ! Rank of this MPI proc inside comm
205 
206    integer :: natom, natom3
207 
208    logical :: use_ifc_fourq = .False.
209    ! Debuggin flag. If True, replace symmetrization with call to ifc_fourq.
210 
211    integer :: requests(2)
212    ! MPI requests
213 
214    integer,allocatable :: qibz_start(:), qibz_stop(:)
215    ! (0:%nprocs-1))
216    ! Initial and final index of the IBZ qpoint treated by this MPI proc inside comm.
217 
218    real(dp), ABI_CONTIGUOUS pointer :: qibz(:,:)
219    ! q-points in the IBZ.
220 
221    real(dp),allocatable :: phfreqs_qibz(:,:)
222    ! (natom3, %nqibz))
223    ! Ph frequencies in the IBZ
224 
225    real(dp),allocatable :: pheigvec_qibz(:,:,:,:)
226    ! (2, natom3, natom3, %nqibz))
227    ! Ph eigenvectors in the IBZ
228 
229    real(dp),allocatable :: phfrq(:)
230    ! (natom3)
231    ! Ph frequencies for q in the full BZ
232 
233    real(dp),allocatable :: displ_cart(:,:,:,:)
234    ! displ_cart(2, 3, natom, %natom3)
235    ! Ph displacement for q in the full BZ
236 
237   contains
238 
239     procedure :: async_rotate => phstore_async_rotate    ! Begin non-blocking collective MPI communication to symmetrize stuff
240     procedure :: wait => phstore_wait                    ! Wait from non-blocking MPI BCAST started in phstore_async_rotate,
241                                                          ! return ph frequencies and displacements.
242     procedure :: free => phstore_free                    ! Free dynamic memory
243 
244  end type phstore_t

m_phonons/phstore_wait [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 phstore_wait

FUNCTION

  Wait from non-blocking MPI BCAST started in phstore_async_rotate,
  returns phonon frequencies and displacements in Cartesian and reduced coordinates.

INPUTS


m_phonons/test_phrotation [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 test_phrotation

FUNCTION

  Test the symmetrization of the phonon eigenvalues and eigenvectors.

 INPUT
  cryst=Crystalline structure
  ifc<ifc_type>=interatomic force constants and corresponding real space grid info.
  ngqpt(3)=Divisions of the ab-initio q-mesh.
  qptopt=option for the generation of q points (defines whether spatial symmetries and/or time-reversal can be used)
  comm= MPI communicator


m_phonons/thermal_supercell_free [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 thermal_supercell_free

FUNCTION

  deallocate thermal array of supercells

INPUTS

OUTPUT

NOTES

SOURCE

1593 subroutine thermal_supercell_free(nscells, thm_scells)
1594 
1595 !Arguments ------------------------------------
1596 !scalars
1597  integer, intent(in) :: nscells
1598  type(supercell_type), allocatable, intent(inout) :: thm_scells(:)
1599 
1600 ! local
1601  integer :: icell
1602 
1603  if (allocated(thm_scells)) then
1604    do icell = 1, nscells
1605      call destroy_supercell(thm_scells(icell))
1606    end do
1607  end if
1608 
1609 end subroutine thermal_supercell_free

m_phonons/thermal_supercell_make [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 thermal_supercell_make

FUNCTION

  Construct an random thermalized supercell configuration, as in TDEP
  main function is for training set generation in multibinit

INPUTS

   Crystal = crystal object with rprim etc...
   Ifc = interatomic force constants object from anaddb
   option = option to deal with negative frequency -> Bose factor explodes (eg acoustic at Gamma)
      several philosophies to be implemented for the unstable modes:
      option == 1 =>  ignore
      option == 2 =>  populate them according to a default amplitude
      option == 3 =>  populate according to their modulus squared
      option == 4 =>  USER defined value(s), require namplitude and amplitude
   nconfig = numer of requested configurations
   rlatt = matrix of conversion for supercell (3 0 0   0 3 0   0 0 3 for example)
   temperature_K =  temperature in Kelvin
   nqpt = number of q-point
   namplitude = number of amplitude provided by the user
   amplitudes(namplitude) = list of the amplitudes of the unstable phonons
                            amplitudes(1:3,iamplitude) = qpt
                            amplitudes(4,iamplitude)   = mode
                            amplitudes(5,iamplitude)   = amplitude

OUTPUT

   thm_scells = array of configurations with thermalized supercells

NOTES

SOURCE

1404 subroutine thermal_supercell_make(amplitudes,Crystal, Ifc,namplitude, nconfig,option,&
1405 &                                 rlatt, temperature_K, thm_scells)
1406 
1407 !Arguments ------------------------------------
1408 !scalars
1409  integer, intent(in) :: option,nconfig
1410  integer, intent(in) :: rlatt(3,3)
1411  real(dp), intent(in) :: temperature_K
1412  type(crystal_t),intent(in) :: Crystal
1413  type(ifc_type),intent(in) :: Ifc
1414  type(supercell_type), intent(out) :: thm_scells(nconfig)
1415  integer,intent(in) :: namplitude
1416 !Local variables-------------------------------
1417 !scalars
1418  integer :: iq, nqibz, nqbz, qptopt1, iampl ,imode, ierr, iconfig
1419  real(dp) :: temperature, sigma, freeze_displ
1420  real(dp) :: rand !, rand1, rand2
1421  real(dp),intent(in):: amplitudes(5,namplitude)
1422  !arrays
1423  real(dp), allocatable :: qshft(:,:) ! dummy with 2 dimensions for call to kpts_ibz_from_kptrlatt
1424  real(dp), allocatable :: qbz(:,:), qibz(:,:), wtqibz(:)
1425  real(dp), allocatable :: phfrq_allq(:,:), phdispl_allq(:,:,:,:,:)
1426  real(dp), allocatable :: phfrq(:), phdispl(:,:,:,:),pheigvec(:,:,:,:)
1427  real(dp), allocatable :: phdispl1(:,:,:)
1428  character (len=500) :: msg
1429 
1430 ! *************************************************************************
1431 ! check inputs
1432 ! TODO: add check that all rlatt are the same on input
1433  if (rlatt(1,2)/=0 .or.  rlatt(1,3)/=0 .or.  rlatt(2,3)/=0 .or. &
1434 &    rlatt(2,1)/=0 .or.  rlatt(3,1)/=0 .or.  rlatt(3,2)/=0) then
1435    write (msg, '(4a, 9I6, a)') ' for the moment I have not implemented ', &
1436 &    ' non diagonal supercells.',ch10,' rlatt for temp 1 = ', rlatt, ' Returning '
1437    ABI_WARNING(msg)
1438    return
1439  end if
1440 
1441  temperature = temperature_K /  Ha_K
1442 
1443  ! build qpoint grid used for the Fourier interpolation.
1444  !(use no syms for the moment!)
1445  qptopt1 = 3
1446 
1447  ! for the moment do not allow shifted q grids.
1448  ! We are interpolating anyway, so it will always work
1449  ABI_MALLOC(qshft,(3,1))
1450  qshft(:,1)=zero
1451 
1452  ! This call will set nqibz, IBZ and BZ arrays
1453  call kpts_ibz_from_kptrlatt(crystal, rlatt, qptopt1, 1, qshft, &
1454                               nqibz, qibz, wtqibz, nqbz, qbz) ! new_kptrlatt, new_shiftk)  ! Optional
1455  ABI_FREE(qshft)
1456 
1457  ! allocate arrays wzith all of the q, omega, and displacement vectors
1458  ABI_MALLOC_OR_DIE(phfrq_allq, (3*Crystal%natom, nqibz), ierr)
1459  ABI_MALLOC_OR_DIE(phdispl_allq, (2, 3, Crystal%natom, 3*Crystal%natom, nqibz), ierr)
1460 
1461  ABI_MALLOC(phfrq, (3*Crystal%natom))
1462  ABI_MALLOC(phdispl, (2, 3, Crystal%natom, 3*Crystal%natom))
1463  ABI_MALLOC(pheigvec, (2, 3, Crystal%natom, 3*Crystal%natom))
1464 
1465  ! loop over q to get all frequencies and displacement vectors
1466  imode = 0
1467  do iq = 1, nqibz
1468    ! Fourier interpolation.
1469    call ifc%fourq(Crystal, qibz(:,iq), phfrq, phdispl, out_eigvec=pheigvec)
1470    phfrq_allq(1:3*Crystal%natom, iq) = phfrq
1471    phdispl_allq(1:2, 1:3, 1:Crystal%natom, 1:3*Crystal%natom, iq) = phdispl
1472  end do
1473  ABI_FREE(phfrq)
1474  ABI_FREE(pheigvec)
1475  ABI_FREE(phdispl)
1476 
1477  ! only diagonal supercell case for the moment
1478  do iconfig = 1, nconfig
1479    call init_supercell(Crystal%natom, rlatt, Crystal%rprimd, Crystal%typat, Crystal%xcart, Crystal%znucl, thm_scells(iconfig))
1480  end do
1481 
1482  ! precalculate phase factors???
1483 
1484  ABI_MALLOC(phdispl1, (2, 3, Crystal%natom))
1485 
1486  ! for all modes at all q in whole list, sorted
1487  do iq = 1, nqibz
1488    do imode = 1, 3*Crystal%natom
1489 
1490      ! skip modes with too low or negative frequency -> Bose factor explodes (eg acoustic at Gamma)
1491      ! TODO: check the convergence wrt the tolerance
1492      ! several philosophies to be implemented for the unstable modes:
1493      ! 1) ignore
1494      ! 2) populate them according to a default amplitude
1495      ! 3) populate according to their modulus squared
1496      if (abs(phfrq_allq(imode, iq))<tol6) cycle
1497 
1498      phdispl1 = phdispl_allq(:,:,:,imode,iq)
1499 
1500      ! loop over configurations
1501      do iconfig = 1, nconfig
1502 
1503        ! trick supercell object into using present q point
1504        thm_scells(iconfig)%qphon(:) = qibz(:,iq)
1505 
1506        ! find thermal displacement amplitude eq 4 of Zacharias
1507        !   combined with l_nu,q expression in paragraph before
1508        if (phfrq_allq(imode, iq) > tol6) then
1509          sigma = sqrt( (bose_einstein(phfrq_allq(imode,iq), temperature) + half)/phfrq_allq(imode,iq))
1510        else
1511          !Treat negative frequencies
1512          select case (option)
1513          case(1)
1514            !Do not populate
1515            sigma = 0._dp
1516          case(2)
1517            !Default amplitude for all the frequencies
1518            sigma = 100._dp
1519          case(3)
1520            !Absolute value of the frequencies
1521            sigma=sqrt((bose_einstein(abs(phfrq_allq(imode,iq)),temperature)+half)/&
1522 &                abs(phfrq_allq(imode,iq)))
1523          case(4)
1524            sigma = 0._dp
1525            !Search if the amplitude of this unstable phonon is in the input argument amplitudes
1526            do iampl=1,namplitude
1527              if(abs(thm_scells(iconfig)%qphon(1) - amplitudes(1,iampl)) < tol8.and.&
1528 &               abs(thm_scells(iconfig)%qphon(2) - amplitudes(2,iampl)) < tol8.and.&
1529 &               abs(thm_scells(iconfig)%qphon(3) - amplitudes(3,iampl)) < tol8.and.&
1530 &               abs(imode - amplitudes(4,iampl)) < tol8) then
1531                sigma = amplitudes(5,iampl)
1532              end if
1533            end do
1534            !If not, the amplitude is zero
1535            if(abs(sigma) < tol8)then
1536              write (msg, '(a,I0,a,3es12.5,2a,I0)') ' The amplitude of the unstable mode ',&
1537 &                int(imode),' of the qpt ',thm_scells(iconfig)%qphon(:), ch10,&
1538 &                'is set to zero for the configuration ',iconfig
1539              ABI_WARNING(msg)
1540            end if
1541          end select
1542        end if
1543 
1544        ! add displacement for this mode to supercell positions eq 5 of Zacharias
1545        call RANDOM_NUMBER(rand)
1546        rand = two * rand - one
1547 
1548        ! from TDEP documentation for gaussian distribution of displacements
1549        !call RANDOM_NUMBER(rand1)
1550        !call RANDOM_NUMBER(rand2)
1551        ! rand = sqrt(-two*rand1) * sin(twopi*rand2)
1552 
1553        ! if (rand > half) then
1554        !   rand = one
1555        ! else
1556        !   rand = -one
1557        ! end if
1558 
1559        freeze_displ =  rand * sigma
1560 
1561        call freeze_displ_supercell (phdispl1(:,:,:), freeze_displ, thm_scells(iconfig))
1562      end do !iconfig
1563    end do !imode
1564  end do !iq
1565 
1566  ABI_FREE(phfrq_allq)
1567  ABI_FREE(phdispl_allq)
1568  ABI_FREE(phdispl1)
1569  ABI_FREE(qibz)
1570  ABI_FREE(qbz)
1571  ABI_FREE(wtqibz)
1572 
1573 end subroutine thermal_supercell_make

m_phonons/thermal_supercell_print [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 thermal_supercell_print

FUNCTION

  print files with thermalized array of random supercell configurations

INPUTS

OUTPUT

NOTES

SOURCE

1671 subroutine thermal_supercell_print(fname, nconfig, temperature_K, thm_scells)
1672 
1673 !Arguments ------------------------------------
1674 !scalars
1675  integer, intent(in) :: nconfig
1676  type(supercell_type), intent(in) :: thm_scells(nconfig)
1677  character(len=fnlen), intent(in) :: fname
1678  real(dp), intent(in) :: temperature_K
1679 
1680 ! local
1681  integer :: iconfig,itemp
1682  character(len=80) :: title1, title2
1683  character(len=fnlen) :: filename
1684  character(len=10) :: config_str
1685 
1686  do iconfig = 1, nconfig
1687    write (config_str,'(I8)') iconfig
1688    write (filename, '(3a)') trim(fname), "_cf_", trim(adjustl(config_str))
1689    write (title1, '(a,I6,a)') "#  thermalized supercell at temperature T= ", temperature_K, " Kelvin"
1690    title2 = "#  generated with random thermal displacements of all phonons"
1691    call prt_supercell (filename, thm_scells(itemp), title1, title2)
1692  end do
1693 
1694 end subroutine thermal_supercell_print

m_phonons/zacharias_supercell_make [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 zacharias_supercell_make

FUNCTION

  Construct an optimally thermalized supercell following Zacharias and Giustino
  PRB 94 075125 (2016) [[cite:Zacharias2016]]

INPUTS

OUTPUT

SOURCE

1234 subroutine zacharias_supercell_make(Crystal, Ifc, ntemper, rlatt, tempermin, temperinc, thm_scells)
1235 
1236 !Arguments ------------------------------------
1237 !scalars
1238  integer, intent(in) :: ntemper
1239  integer, intent(in) :: rlatt(3,3)
1240  real(dp), intent(in) :: tempermin, temperinc
1241  type(crystal_t),intent(in) :: Crystal
1242  type(ifc_type),intent(in) :: Ifc
1243  type(supercell_type), intent(out) :: thm_scells(ntemper)
1244 
1245 !Local variables-------------------------------
1246 !scalars
1247  integer :: iq, nqibz, nqbz, qptopt1, imode, itemper, ierr, jmode
1248  real(dp) :: temperature_K, temperature, modesign, sigma, freeze_displ
1249 !arrays
1250  integer, allocatable :: modeindex(:)
1251  real(dp), allocatable :: qshft(:,:) ! dummy with 2 dimensions for call to kpts_ibz_from_kptrlatt
1252  real(dp), allocatable :: qbz(:,:), qibz(:,:), wtq_ibz(:)
1253  real(dp), allocatable :: phfrq_allq(:), phdispl_allq(:,:,:,:,:)
1254  real(dp), allocatable :: phfrq(:), phdispl(:,:,:,:),pheigvec(:,:,:,:)
1255  real(dp), allocatable :: phdispl1(:,:,:)
1256  character (len=500) :: msg
1257 
1258 ! *************************************************************************
1259 
1260  ! check inputs
1261  ! TODO: add check that all rlatt are the same on input
1262 
1263  if (rlatt(1,2)/=0 .or.  rlatt(1,3)/=0 .or.  rlatt(2,3)/=0 .or. &
1264      rlatt(2,1)/=0 .or.  rlatt(3,1)/=0 .or.  rlatt(3,2)/=0) then
1265    write (msg, '(4a, 9I6, a)') ' for the moment I have not implemented ', &
1266      ' non diagonal supercells.',ch10,' rlatt for temp 1 = ', rlatt, ' Returning '
1267    ABI_WARNING(msg)
1268    return
1269  end if
1270 
1271  ! build qpoint grid used for the Fourier interpolation.
1272  !(use no syms for the moment!)
1273  qptopt1 = 3
1274 
1275  ! for the moment do not allow shifted q grids.
1276  ! We are interpolating anyway, so it will always work
1277  ABI_MALLOC(qshft,(3,1))
1278  qshft(:,1)=zero
1279 
1280  ! This call will set nqibz, IBZ and BZ arrays
1281  call kpts_ibz_from_kptrlatt(crystal, rlatt, qptopt1, 1, qshft, &
1282     nqibz, qibz, wtq_ibz, nqbz, qbz) ! new_kptrlatt, new_shiftk)  ! Optional
1283  ABI_FREE(qshft)
1284 
1285  ! allocate arrays with all of the q, omega, and displacement vectors
1286  ABI_MALLOC_OR_DIE(phfrq_allq, (3*Crystal%natom*nqibz), ierr)
1287  ABI_MALLOC_OR_DIE(phdispl_allq, (2, 3, Crystal%natom, 3*Crystal%natom, nqibz), ierr)
1288 
1289  ABI_MALLOC(phfrq, (3*Crystal%natom))
1290  ABI_MALLOC(phdispl, (2, 3, Crystal%natom, 3*Crystal%natom))
1291  ABI_MALLOC(pheigvec, (2, 3, Crystal%natom, 3*Crystal%natom))
1292 
1293  ! loop over q to get all frequencies and displacement vectors
1294  ABI_MALLOC(modeindex, (nqibz*3*Crystal%natom))
1295  imode = 0
1296  do iq = 1, nqibz
1297    ! Fourier interpolation.
1298    call ifc%fourq(Crystal, qibz(:,iq), phfrq, phdispl, out_eigvec=pheigvec)
1299    phfrq_allq((iq-1)*3*Crystal%natom+1 : iq*3*Crystal%natom) = phfrq
1300    phdispl_allq(1:2, 1:3, 1:Crystal%natom, 1:3*Crystal%natom, iq) = phdispl
1301    do jmode = 1, 3*Crystal%natom
1302      imode = imode + 1
1303      modeindex(imode) = imode
1304    end do
1305  end do
1306  ABI_FREE(phfrq)
1307  ABI_FREE(pheigvec)
1308  ABI_FREE(phdispl)
1309 
1310  ! sort modes in whole list: get indirect indexing for qbz and displ
1311  call sort_dp(nqibz*3*Crystal%natom, phfrq_allq, modeindex, tol10)
1312  ! NB: phfrq is sorted now, but displ and qibz will have to be indexed indirectly with modeindex
1313 
1314  ! only diagonal supercell case for the moment
1315  do itemper = 1, ntemper
1316    call init_supercell(Crystal%natom, rlatt, Crystal%rprimd, Crystal%typat, Crystal%xcart, Crystal%znucl, thm_scells(itemper))
1317  end do
1318 
1319  ! precalculate phase factors???
1320 
1321  ABI_MALLOC(phdispl1, (2, 3, Crystal%natom))
1322  ! for all modes at all q in whole list, sorted
1323  modesign=one
1324  do imode = 1, 3*Crystal%natom*nqibz
1325    ! skip modes with too low or negative frequency -> Bose factor explodes (eg acoustic at Gamma)
1326    if (phfrq_allq(imode) < tol10) cycle
1327 
1328    iq = ceiling(dble(modeindex(imode))/dble(3*Crystal%natom))
1329    jmode = modeindex(imode) - (iq-1)*3*Crystal%natom
1330    phdispl1 = phdispl_allq(:,:,:,jmode,iq)
1331 
1332    ! loop over temperatures
1333    do itemper = 1, ntemper
1334      temperature_K = tempermin + dble(itemper-1)*temperinc  ! this is in Kelvin
1335      temperature = temperature_K / Ha_K !=315774.65_dp
1336 
1337      ! trick supercell object into using present q point
1338      thm_scells(itemper)%qphon(:) = qibz(:,iq)
1339 
1340      ! find thermal displacement amplitude eq 4 of Zacharias
1341      !   combined with l_nu,q expression in paragraph before
1342      sigma = sqrt( (bose_einstein(phfrq_allq(imode), temperature) + half)/phfrq_allq(imode) )
1343 
1344      ! add displacement for this mode to supercell positions eq 5 of Zacharias
1345        freeze_displ = modesign * sigma
1346        call freeze_displ_supercell (phdispl1(:,:,:), freeze_displ, thm_scells(itemper))
1347 
1348    end do !itemper
1349 
1350    ! this is the prescription: flip sign for each successive mode in full
1351    ! spectrum, to cancel electron phonon coupling to 1st order
1352    ! (hopeflly 3rd order as well)
1353    modesign=-modesign
1354 
1355  end do !imode
1356 
1357  ABI_FREE(modeindex)
1358  ABI_FREE(phfrq_allq)
1359  ABI_FREE(phdispl_allq)
1360  ABI_FREE(phdispl1)
1361  ABI_FREE(qibz)
1362  ABI_FREE(qbz)
1363  ABI_FREE(wtq_ibz)
1364 
1365 end subroutine zacharias_supercell_make

m_phonons/zacharias_supercell_print [ Functions ]

[ Top ] [ m_phonons ] [ Functions ]

NAME

 zacharias_supercell_print

FUNCTION

  print files with thermal array of supercells

INPUTS

OUTPUT

SOURCE

1627 subroutine zacharias_supercell_print(fname, ntemper, tempermin, temperinc, thm_scells)
1628 
1629 !Arguments ------------------------------------
1630 !scalars
1631  integer, intent(in) :: ntemper
1632  real(dp), intent(in) :: tempermin
1633  real(dp), intent(in) :: temperinc
1634  type(supercell_type), intent(in) :: thm_scells(ntemper)
1635  character(len=fnlen), intent(in) :: fname
1636 
1637 ! local
1638  integer :: itemp
1639  character(len=80) :: title1, title2
1640  character(len=fnlen) :: filename
1641  real(dp) :: temper
1642  character(len=10) :: temper_str
1643 
1644  do itemp = 1, ntemper
1645    temper = dble(itemp-1)*temperinc+tempermin
1646    write (temper_str,'(I8)') int(temper)
1647    write (filename, '(3a)') trim(fname), "_T_", trim(adjustl(temper_str))
1648    write (title1, '(3a)') "#  Zacharias thermalized supercell at temperature T= ", trim(temper_str), " Kelvin"
1649    title2 = "#  generated with alternating thermal displacements of all phonons"
1650    call prt_supercell (filename, thm_scells(itemp), title1, title2)
1651  end do
1652 
1653 end subroutine zacharias_supercell_print