LCOV - code coverage report
Current view: top level - src/77_ddb - m_phonons.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.0 % 1339 1138
Test Date: 2026-11-09 12:18:26 Functions: 84.8 % 33 28
Branches: 56.5 % 3209 1812

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_phonons
       2                 :             : !! NAME
       3                 :             : !! m_phonons
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! Module for the phonon density of states.
       7                 :             : !! Container type is defined, and destruction, print subroutines
       8                 :             : !! as well as the central phdos_init
       9                 :             : !!
      10                 :             : !! COPYRIGHT
      11                 :             : !! Copyright (C) 1999-2026 ABINIT group (XG, MG, MJV, GMR)
      12                 :             : !! This file is distributed under the terms of the
      13                 :             : !! GNU General Public Licence, see ~abinit/COPYING
      14                 :             : !! or http://www.gnu.org/copyleft/gpl.txt .
      15                 :             : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      16                 :             : !!
      17                 :             : !! SOURCE
      18                 :             : 
      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, intrinsic :: iso_c_binding
      28                 :             :  use defs_basis
      29                 :             :  use m_errors
      30                 :             :  use m_xmpi
      31                 :             :  use m_abicore
      32                 :             :  use m_htetra
      33                 :             :  use m_numeric_tools
      34                 :             :  use m_cgtools
      35                 :             :  use m_crystal
      36                 :             :  use m_nctk
      37                 :             :  use m_sortph
      38                 :             :  use m_ddb
      39                 :             :  use netcdf
      40                 :             :  use m_supercell
      41                 :             : 
      42                 :             : 
      43                 :             :  use m_fstrings,        only : itoa, ftoa, sjoin, ltoa, ktoa, strcat, basename, replace
      44                 :             :  use m_matrix,          only : matr3inv
      45                 :             :  use m_symtk,           only : sg_multable
      46                 :             :  use m_krank,           only : krank_t
      47                 :             :  use m_dtset,           only : dataset_type
      48                 :             :  use m_time,            only : cwtime, cwtime_report
      49                 :             :  use m_io_tools,        only : open_file
      50                 :             :  use m_geometry,        only : mkrdim, symredcart, normv, phdispl_cart2red
      51                 :             :  use m_dynmat,          only : gtdyn9, dfpt_phfrq, dfpt_prtph, &
      52                 :             :                                pheigvec_normalize, massmult_and_breaksym, phdispl_from_eigvec, phangmom_from_eigvec
      53                 :             :  use m_atprj,           only : atprj_type
      54                 :             :  use m_bz_mesh,         only : isamek, make_path, kpath_t
      55                 :             :  use m_ifc,             only : ifc_type
      56                 :             :  use m_anaddb_dataset,  only : anaddb_dataset_type
      57                 :             :  use m_kpts,            only : kpts_ibz_from_kptrlatt, get_full_kgrid, kpts_map, kpts_timrev_from_kptopt
      58                 :             :  use m_special_funcs,   only : bose_einstein
      59                 :             :  use m_sort,            only : sort_dp
      60                 :             :  use m_symfind,         only : symanal
      61                 :             : 
      62                 :             :  implicit none
      63                 :             : 
      64                 :             :  private
      65                 :             : 
      66                 :             :  public :: mkphbs                        ! Compute phonon band structure
      67                 :             :  public :: phonons_write_xmgrace         ! Write phonons bands in Xmgrace format.
      68                 :             :  public :: phonons_write_gnuplot         ! Write phonons bands in gnuplot format.
      69                 :             :  public :: ifc_mkphbs                    ! Compute the phonon band structure from the IFC and write data to file(s)
      70                 :             :  public :: dfpt_symph                    ! Determine the symmetry character of the different phonon modes at Gamma
      71                 :             : 
      72                 :             :  public :: zacharias_supercell_make
      73                 :             :  public :: zacharias_supercell_print
      74                 :             :  public :: thermal_supercell_make
      75                 :             :  public :: thermal_supercell_free
      76                 :             :  public :: thermal_supercell_print
      77                 :             : !!***
      78                 :             : 
      79                 :             : !!****t* m_phonons/phdos_t
      80                 :             : !! NAME
      81                 :             : !! phdos_t
      82                 :             : !!
      83                 :             : !! FUNCTION
      84                 :             : !! Container for phonon DOS and atom projected contributions
      85                 :             : !!
      86                 :             : !! SOURCE
      87                 :             : 
      88                 :             :  type,public :: phdos_t
      89                 :             : 
      90                 :             :   integer :: ntypat
      91                 :             :   ! Number of type of atoms.
      92                 :             : 
      93                 :             :   integer :: natom
      94                 :             :   ! Number of atoms is the unit cell.
      95                 :             : 
      96                 :             :   integer :: nomega
      97                 :             :   ! Number of frequency points in DOS mesh.
      98                 :             : 
      99                 :             :   integer :: nqibz
     100                 :             :   ! Number of q-points in the IBZ.
     101                 :             : 
     102                 :             :   integer :: n_normal_vec_dmm
     103                 :             :   ! Number of directions to project the thermal current in the diffuse mismatch model
     104                 :             : 
     105                 :             :   integer :: prtdos
     106                 :             :   ! Option of DOS calculation (1 for Gaussian, 2 for tetrahedrons).
     107                 :             : 
     108                 :             :   real(dp) :: omega_min
     109                 :             :   ! Min frequency for DOS calculation.
     110                 :             : 
     111                 :             :   real(dp) :: omega_max
     112                 :             :   ! Max frequency for DOS calculation.
     113                 :             : 
     114                 :             :   real(dp) :: omega_step
     115                 :             :   ! Frequency step.
     116                 :             : 
     117                 :             :   real(dp) :: dossmear
     118                 :             :   ! Gaussian broadening.
     119                 :             : 
     120                 :             :   integer :: qptrlatt(3,3) = 0
     121                 :             :   ! q-mesh as computed in getkgrid_low
     122                 :             : 
     123                 :             :   real(dp) :: shiftq(3)
     124                 :             :   ! Shigt of Q-mesh computed by getkgrid_low (1 shift is enough)
     125                 :             : 
     126                 :             :   real(dp),allocatable :: atom_mass(:)
     127                 :             :    ! atom_mass(natom)
     128                 :             : 
     129                 :             :   real(dp),allocatable :: normal_vec_dmm(:,:)
     130                 :             :   ! normal_vec_dmm(3,n_normal_vec_dmm)
     131                 :             :   ! Cartesian directions to project the thermal current in the diffuse mismatch model
     132                 :             : 
     133                 :             :   real(dp),allocatable :: omega(:)
     134                 :             :    ! omega(nomega)
     135                 :             :    ! Frequency grid.
     136                 :             : 
     137                 :             :   real(dp),allocatable :: phdos(:)
     138                 :             :    ! phdos(nomega)
     139                 :             :    ! phonon DOS.
     140                 :             : 
     141                 :             :   real(dp),allocatable :: phdos_int(:)
     142                 :             :    ! phdos_int(nomega)
     143                 :             :    ! integrated phonon DOS
     144                 :             : 
     145                 :             :   real(dp),allocatable :: phdos_dmm(:,:)
     146                 :             :    ! phdos_dmm(nomega,n_normal_vec_dmm)
     147                 :             :    ! phonon DOS including projection of velocity onto a given direction n normal to an interface
     148                 :             :    ! in the diffuse mismatch model
     149                 :             : 
     150                 :             :   real(dp),allocatable :: pjdos(:,:,:)
     151                 :             :    ! pjdos(nomega,3,natom)
     152                 :             :    ! projected DOS (over atoms and cartesian directions)
     153                 :             : 
     154                 :             :   real(dp),allocatable :: pjdos_int(:,:,:)
     155                 :             :    ! pjdos_int(nomega,3,natom)
     156                 :             :    ! Integrated atomic PJDOS along the three cartesian directions.
     157                 :             : 
     158                 :             :   real(dp),allocatable :: pjdos_type(:,:)
     159                 :             :    ! pjdos_type(nomega,ntypat)
     160                 :             :    ! phonon DOS contribution arising from a particular atom-type.
     161                 :             : 
     162                 :             :   real(dp),allocatable :: pjdos_type_int(:,:)
     163                 :             :    ! pjdos_type_int(nomega,ntypat)
     164                 :             :    ! Integrate phonon DOS contribution arising from a particular atom-type.
     165                 :             : 
     166                 :             :   real(dp),allocatable :: pjdos_rc_type(:,:,:)
     167                 :             :    ! phdos(nomega,3,ntypat)
     168                 :             :    ! phonon DOS contribution arising from a particular atom-type
     169                 :             :    ! decomposed along the three cartesian directions.
     170                 :             : 
     171                 :             :   real(dp),allocatable :: msqd_dos_atom(:,:,:,:)
     172                 :             :    ! msqd_dos_atom(nomega,3,3,natom)
     173                 :             :    ! mean square displacement matrix, frequency dependent like a DOS, tensor in cartesian coords.
     174                 :             :    ! allows one to calculate Debye Waller factors by integration with 1/omega
     175                 :             :    ! and the Bose Einstein factor
     176                 :             : 
     177                 :             :  contains
     178                 :             : 
     179                 :             :    procedure :: print => phdos_print
     180                 :             :    procedure :: print_debye => phdos_print_debye
     181                 :             :    procedure :: print_msqd => phdos_print_msqd
     182                 :             :    procedure :: print_thermo => phdos_print_thermo
     183                 :             :    procedure :: free => phdos_free
     184                 :             :    procedure :: ncwrite => phdos_ncwrite
     185                 :             :    procedure :: init => phdos_init  ! Constructor
     186                 :             :  end type phdos_t
     187                 :             : !!***
     188                 :             : 
     189                 :             : !!****t* m_phonons/phstore_t
     190                 :             : !! NAME
     191                 :             : !! phstore_t
     192                 :             : !!
     193                 :             : !! FUNCTION
     194                 :             : !!  This object stores ph eigenvalues and eigenvectors in the IBZ and provides methods
     195                 :             : !!  to compute the corresponding quantities in the full BZ using symmetries.
     196                 :             : !!  Useful for very intensive loops of q-points in the BZ in which the call to ifc_fourq
     197                 :             : !!  may become a significant bottleneck.
     198                 :             : !!  Note that IBZ quantities are memory-distributed inside the MPI communicator comm.
     199                 :             : !!  and the symmetrization is performed in a non-blocking fashion so that it's possible to overlap
     200                 :             : !!  the symmetrization with computations. See sigmaph for usage.
     201                 :             : !!
     202                 :             : !! SOURCE
     203                 :             : 
     204                 :             :  type,public :: phstore_t
     205                 :             : 
     206                 :             :    integer :: nqibz
     207                 :             :    ! Number of q-points in the IBZ
     208                 :             : 
     209                 :             :    integer :: comm
     210                 :             :    ! MPI communicator used to distribute memory.
     211                 :             : 
     212                 :             :    integer :: nprocs
     213                 :             :    ! Number of MPI procs in comm.
     214                 :             : 
     215                 :             :    integer :: my_rank
     216                 :             :    ! Rank of this MPI proc inside comm
     217                 :             : 
     218                 :             :    integer :: natom, natom3
     219                 :             : 
     220                 :             :    logical :: use_ifc_fourq = .False.
     221                 :             :    ! Debugging flag. If True, replace symmetrization with call to ifc_fourq.
     222                 :             : 
     223                 :             :    integer :: requests(2)
     224                 :             :    ! MPI requests
     225                 :             : 
     226                 :             :    integer,allocatable :: qibz_start(:), qibz_stop(:)
     227                 :             :    ! (0:%nprocs-1))
     228                 :             :    ! Initial and final index of the IBZ qpoint treated by this MPI proc inside comm.
     229                 :             : 
     230                 :             :    real(dp), contiguous, pointer :: qibz(:,:)
     231                 :             :    ! q-points in the IBZ.
     232                 :             : 
     233                 :             :    real(dp),allocatable :: phfreqs_qibz(:,:)
     234                 :             :    ! (natom3, %nqibz))
     235                 :             :    ! Ph frequencies in the IBZ
     236                 :             : 
     237                 :             :    real(dp),allocatable :: pheigvec_qibz(:,:,:,:)
     238                 :             :    ! (2, natom3, natom3, %nqibz))
     239                 :             :    ! Ph eigenvectors in the IBZ
     240                 :             : 
     241                 :             :    real(dp),allocatable :: phfrq(:)
     242                 :             :    ! (natom3)
     243                 :             :    ! Ph frequencies for q in the full BZ
     244                 :             : 
     245                 :             :    real(dp),allocatable :: displ_cart(:,:,:,:)
     246                 :             :    ! displ_cart(2, 3, natom, %natom3)
     247                 :             :    ! Ph displacement for q in the full BZ
     248                 :             : 
     249                 :             :   contains
     250                 :             : 
     251                 :             :     procedure :: init => phstore_init                    ! Creation method (allocates memory, initialize data from input vars).
     252                 :             :     procedure :: async_rotate => phstore_async_rotate    ! Begin non-blocking collective MPI communication to symmetrize stuff
     253                 :             :     procedure :: wait => phstore_wait                    ! Wait from non-blocking MPI BCAST started in phstore_async_rotate,
     254                 :             :                                                          ! return ph frequencies and displacements.
     255                 :             :     procedure :: free => phstore_free                    ! Free dynamic memory
     256                 :             :  end type phstore_t
     257                 :             : !!***
     258                 :             : 
     259                 :             :  public :: pheigvec_rotate      ! Obtain phonon eigenvectors for q in the BZ from the symmetrical image in the IBZ.
     260                 :             :  public :: test_phrotation      ! Validate pheigvec_rotate routine.
     261                 :             : 
     262                 :             : contains  !=====================================================
     263                 :             : !!***
     264                 :             : 
     265                 :             : !!****f* m_phonons/phdos_print
     266                 :             : !! NAME
     267                 :             : !! phdos_print
     268                 :             : !!
     269                 :             : !! FUNCTION
     270                 :             : !! Print out phonon DOS (and partial DOS etc) in meV units
     271                 :             : !!
     272                 :             : !! INPUTS
     273                 :             : !! PHdos= container object for phonon DOS
     274                 :             : !! fname=File name for output
     275                 :             : !!
     276                 :             : !! OUTPUT
     277                 :             : !!  Only writing.
     278                 :             : !!
     279                 :             : !! SOURCE
     280                 :             : 
     281                 :          79 : subroutine phdos_print(PHdos, fname)
     282                 :             : 
     283                 :             : !Arguments ------------------------------------
     284                 :             :  class(phdos_t),intent(in) :: PHdos
     285                 :             :  character(len=*),intent(in) :: fname
     286                 :             : 
     287                 :             : !Local variables-------------------------------
     288                 :             :  integer :: io,itype,unt,unt_by_atom,unt_msqd,iatom
     289                 :             :  real(dp) :: tens(3,3)
     290                 :             :  character(len=500) :: msg, msg_method
     291                 :             :  character(len=fnlen) :: fname_by_atom, fname_msqd
     292                 :             :  character(len=3) :: unitname
     293                 :             : ! *************************************************************************
     294                 :             : 
     295                 :             : ! Use Ha units everywhere
     296                 :          79 :  unitname='Ha'
     297                 :             : 
     298                 :         133 :  select case (PHdos%prtdos)
     299                 :             :  case (1)
     300                 :             :    write(msg_method,'(a,es16.8,2a,i0)')&
     301                 :          54 :     '# Gaussian method with smearing = ',PHdos%dossmear,unitname,', nqibz =',PHdos%nqibz
     302                 :             :  case (2)
     303                 :          25 :    write(msg_method,'(a,i0)')'# Tetrahedron method, nqibz= ',PHdos%nqibz
     304                 :             :  case default
     305      [ +  +  - ]:          79 :    ABI_ERROR(sjoin(" Wrong prtdos: ",itoa(PHdos%prtdos)))
     306                 :             :  end select
     307                 :             : 
     308                 :             :  ! Open external file and write results
     309         [ -  + ]:          79 :  if (open_file(fname,msg,newunit=unt,form="formatted",action="write") /= 0) then
     310                 :           0 :    ABI_ERROR(msg)
     311                 :             :  end if
     312                 :          79 :  write(msg,'(3a)')'# ',ch10,'# Phonon density of states and atom type projected DOS'
     313                 :          79 :  call wrtout(unt,msg)
     314                 :          79 :  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
     315                 :          79 :  call wrtout(unt,msg)
     316                 :          79 :  call wrtout(unt,msg_method)
     317                 :          79 :  write(msg,'(5a)')'# ',ch10,'# omega     PHDOS    INT_PHDOS   PJDOS[atom_type=1]  INT_PJDOS[atom_type=1] ...  ',ch10,'# '
     318                 :          79 :  call wrtout(unt,msg)
     319         [ +  + ]:      149297 :  do io=1,PHdos%nomega
     320                 :      149218 :    write(unt,'(3es17.8)',advance='NO')PHdos%omega(io),PHdos%phdos(io),PHdos%phdos_int(io)
     321         [ +  + ]:      354297 :    do itype=1,PHdos%ntypat
     322                 :      354297 :      write(unt,'(2es17.8,2x)',advance='NO')PHdos%pjdos_type(io,itype),PHdos%pjdos_type_int(io,itype)
     323                 :             :    end do
     324                 :      149297 :    write(unt,*)
     325                 :             :  end do
     326                 :          79 :  close(unt)
     327                 :             : 
     328         [ +  - ]:          79 :  fname_by_atom = trim(fname) // "_by_atom"
     329         [ -  + ]:          79 :  if (open_file(fname_by_atom,msg,newunit=unt_by_atom,form="formatted",action="write") /= 0) then
     330                 :           0 :    ABI_ERROR(msg)
     331                 :             :  end if
     332                 :          79 :  write(msg,'(3a)')'# ',ch10,'# Phonon density of states and atom projected DOS'
     333                 :          79 :  call wrtout(unt_by_atom,msg)
     334                 :          79 :  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
     335                 :          79 :  call wrtout(unt_by_atom,msg)
     336                 :          79 :  call wrtout(unt_by_atom,msg_method)
     337                 :          79 :  write(msg,'(5a)')'# ',ch10,'# omega     PHDOS    PJDOS[atom=1]  PJDOS[atom=2] ...  ',ch10,'# '
     338                 :          79 :  call wrtout(unt_by_atom,msg)
     339         [ +  + ]:      149297 :  do io=1,PHdos%nomega
     340                 :      149218 :    write(unt_by_atom,'(2es17.8)',advance='NO')PHdos%omega(io),PHdos%phdos(io)
     341         [ +  + ]:      511704 :    do iatom=1,PHdos%natom
     342         [ +  + ]:     1599162 :      write(unt_by_atom,'(1es17.8,2x)',advance='NO') sum(PHdos%pjdos(io,1:3,iatom))
     343                 :             :    end do
     344                 :      149297 :    write(unt_by_atom,*)
     345                 :             :  end do
     346                 :          79 :  close(unt_by_atom)
     347                 :             : 
     348         [ +  - ]:          79 :  fname_msqd = trim(fname) // "_msqd"
     349         [ -  + ]:          79 :  if (open_file(fname_msqd,msg,newunit=unt_msqd,form="formatted",action="write") /= 0) then
     350                 :           0 :    ABI_ERROR(msg)
     351                 :             :  end if
     352                 :          79 :  write(msg,'(3a)')'# ',ch10,'# Phonon density of states weighted msq displacement matrix (set to zero below 1e-12)'
     353                 :          79 :  call wrtout(unt_msqd,msg)
     354                 :          79 :  write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in bohr^2 states/',unitname
     355                 :          79 :  call wrtout(unt_msqd,msg)
     356                 :          79 :  call wrtout(unt_msqd,msg_method)
     357                 :          79 :  write(msg,'(5a)')'# ',ch10,'# omega     MSQDisp[atom=1, xx, yy, zz, yz, xz, xy]  MSQDisp[atom=2, xx, yy,...] ...  ',ch10,'# '
     358                 :          79 :  call wrtout(unt_msqd,msg)
     359         [ +  + ]:      149297 :  do io=1,PHdos%nomega
     360                 :      149218 :    write(unt_msqd,'(2es17.8)',advance='NO')PHdos%omega(io)
     361         [ +  + ]:      511704 :    do iatom=1,PHdos%natom
     362   [ +  +  +  + ]:     4712318 :      tens = PHdos%msqd_dos_atom(io,:,:,iatom)
     363   [ +  +  +  +  :     4712318 :      where (abs(tens) < tol12)
                   +  + ]
     364                 :             :         tens = zero
     365                 :             :      end where
     366                 :             :      write(unt_msqd,'(6es17.8,2x)',advance='NO') &
     367                 :      362486 :         tens(1,1), tens(2,2), tens(3,3), &
     368                 :      874190 :         tens(2,3), tens(1,3), tens(1,2)
     369                 :             :    end do
     370                 :      149297 :    write(unt_msqd,*)
     371                 :             :  end do
     372                 :          79 :  close(unt_msqd)
     373                 :             : 
     374                 :          79 : end subroutine phdos_print
     375                 :             : !!***
     376                 :             : 
     377                 :             : !----------------------------------------------------------------------
     378                 :             : 
     379                 :             : !****f* m_phonons/phdos_print_debye
     380                 :             : !!
     381                 :             : !! NAME
     382                 :             : !! phdos_print_debye
     383                 :             : !!
     384                 :             : !! FUNCTION
     385                 :             : !! Print out global Debye temperature, force constant, etc... from phonon DOS
     386                 :             : !!
     387                 :             : !! INPUTS
     388                 :             : !! phonon_dos= container object for phonon DOS
     389                 :             : !! ucvol = unit cell volume
     390                 :             : !!
     391                 :             : !! OUTPUT
     392                 :             : !!  Only writing.
     393                 :             : !!
     394                 :             : !! SOURCE
     395                 :             : 
     396                 :          11 : subroutine phdos_print_debye(PHdos, ucvol)
     397                 :             : 
     398                 :             : !Arguments ------------------------------------
     399                 :             :  class(phdos_t),intent(in) :: PHdos
     400                 :             :  real(dp), intent(in) :: ucvol
     401                 :             : 
     402                 :             : !Local variables-------------------------------
     403                 :             :  integer :: io, iomax, iomin
     404                 :             :  real(dp) :: avgom2dos, avgspeedofsound, debyefreq, meanfreq, meanfreq2
     405                 :             :  character(len=500) :: msg
     406                 :             : !arrays
     407                 :             :  integer :: units(2)
     408                 :          11 :  real(dp), allocatable :: om2dos(:), om1dos(:), intdos(:)
     409                 :             : ! *************************************************************************
     410                 :             : 
     411         [ +  + ]:          33 :  units = [std_out, ab_out]
     412                 :             : 
     413                 :             :  ! average speed of sound: coefficient of omega^2 in the DOS is = Volume / 2 pi^2 hbar^3 v_s^3
     414                 :             :  ! first find how far out we can fit with a parabola
     415   [ -  +  +  -  :       40817 :  ABI_CALLOC(om2dos, (PHdos%nomega))
          +  -  +  -  -  
             +  -  +  +  
                      + ]
     416   [ -  +  +  -  :       40806 :  ABI_CALLOC(om1dos, (PHdos%nomega))
          -  +  -  +  +  
                      + ]
     417   [ -  +  +  -  :       40806 :  ABI_CALLOC(intdos, (PHdos%nomega))
          -  +  -  +  +  
                      + ]
     418                 :       40795 :  avgom2dos = zero
     419         [ +  + ]:       40795 :  do io=1,PHdos%nomega
     420         [ +  + ]:       40795 :    if (abs(PHdos%omega(io)) > 1.e-8) then
     421                 :       40780 :      om1dos(io) = PHdos%phdos(io) / PHdos%omega(io)
     422                 :       40780 :      om2dos(io) = PHdos%phdos(io) / PHdos%omega(io)**2
     423                 :             :    end if
     424                 :             :  end do
     425                 :             : 
     426                 :             :  ! integrate dos / omega
     427                 :          11 :  call simpson_int(PHdos%nomega,PHdos%omega_step,om1dos,intdos)
     428                 :          11 :  meanfreq = intdos(PHdos%nomega)
     429                 :             : 
     430                 :             :  ! integrate dos / omega^2
     431         [ +  + ]:       40795 :  intdos = zero
     432                 :          11 :  call simpson_int(PHdos%nomega,PHdos%omega_step,om2dos,intdos)
     433                 :          11 :  meanfreq2 = intdos(PHdos%nomega)
     434                 :             : 
     435                 :          11 :  iomin = 1; iomax = PHdos%nomega
     436         [ +  - ]:       10345 :  do io = 1, PHdos%nomega
     437                 :             :    ! skip eventual negative frequency modes
     438         [ +  + ]:       10345 :    if (PHdos%omega(io) <= tol10) then
     439                 :             :      iomin = io
     440                 :             :      cycle
     441                 :             :    end if
     442                 :             : 
     443                 :             :    ! accumulate dos * om^2 to make an average
     444                 :          11 :    avgom2dos = avgom2dos + om2dos(io)
     445                 :             :    ! first deviation from initial value of more than 10 percent
     446         [ -  + ]:          11 :    if (abs(one-om2dos(iomin)/om2dos(io)) > 0.1_dp) then
     447                 :             :      iomax = io; exit
     448                 :             :    end if
     449                 :             :  end do
     450                 :             : 
     451                 :          11 :  avgom2dos = avgom2dos / (iomax-iomin+1)
     452                 :             :  ! this value is also useful for partial atomic DOS, related to kinetic energy and Force constant in Moessbauer
     453                 :             : 
     454                 :          11 :  avgspeedofsound = (ucvol / 2 / pi**2 / avgom2dos)**third
     455                 :          11 :  write (msg,'(a,E20.10,3a,F16.4,2a)') ' Average speed of sound: ', avgspeedofsound, ' (at units) ',ch10,&
     456                 :          22 :               '-                      = ', avgspeedofsound * Bohr_Ang * 1.d-13 / Time_Sec, ' [km/s]',ch10
     457                 :          11 :  call wrtout(units, msg)
     458                 :             : 
     459                 :             :  ! Debye frequency = vs * (6 pi^2 natom / ucvol)**1/3
     460                 :          11 :  debyefreq = avgspeedofsound * (six*pi**2/ucvol)**(1./3.)
     461                 :          11 :  write (msg,'(a,E20.10,3a,E20.10,a)') ' Debye frequency from DOS: ', debyefreq, ' (Ha) ',ch10,&
     462                 :          22 :                                     '-                        = ', debyefreq*Ha_THz, ' (THz)'
     463                 :          11 :  call wrtout(units, msg)
     464                 :             : 
     465                 :             :  ! Debye temperature = hbar * Debye frequency / kb
     466                 :          11 :  write (msg,'(a,E20.10,2a)') '-Debye temperature from DOS: ', debyefreq*Ha_K, ' (K)', ch10
     467                 :          11 :  call wrtout(units, msg)
     468                 :             : 
     469         [ -  + ]:          11 :  ABI_FREE(om2dos)
     470         [ -  + ]:          11 :  ABI_FREE(om1dos)
     471                 :          11 :  ABI_FREE(intdos)
     472                 :             : 
     473                 :          11 : end subroutine phdos_print_debye
     474                 :             : !!***
     475                 :             : 
     476                 :             : !----------------------------------------------------------------------
     477                 :             : 
     478                 :             : !****f* m_phonons/phdos_print_thermo
     479                 :             : !! NAME
     480                 :             : !! phdos_print_thermo
     481                 :             : !!
     482                 :             : !! FUNCTION
     483                 :             : !! Print out global thermodynamic quantities based on DOS
     484                 :             : !! Only master node should call this routine.
     485                 :             : !!
     486                 :             : !! INPUTS
     487                 :             : !! phonon_dos= container object for phonon DOS
     488                 :             : !! ucvol = unit cell volume
     489                 :             : !!
     490                 :             : !! OUTPUT
     491                 :             : !!  Only writing.
     492                 :             : !!
     493                 :             : !! SOURCE
     494                 :             : 
     495                 :          11 : subroutine phdos_print_thermo(PHdos, fname, ntemper, tempermin, temperinc)
     496                 :             : 
     497                 :             : !Arguments ------------------------------------
     498                 :             :  class(phdos_t),intent(in) :: PHdos
     499                 :             :  integer, intent(in) :: ntemper
     500                 :             :  real(dp), intent(in) :: tempermin, temperinc
     501                 :             :  character(len=*),intent(in) :: fname
     502                 :             : 
     503                 :             : !Local variables-------------------------------
     504                 :             :  integer :: iomega, itemper, tunt
     505                 :             :  character(len=500) :: msg
     506                 :             :  real(dp) :: wover2t, ln2shx, cothx, invsinh2
     507                 :             :  real(dp) :: tmp, domega
     508                 :             : !arrays
     509                 :          11 :  real(dp), allocatable :: free(:), energy(:), entropy(:), spheat(:),wme(:)
     510                 :             : 
     511                 :             : ! *********************************************************************
     512                 :             : 
     513                 :             :  ! Allocate and put zeroes for F, E, S, Cv
     514   [ -  +  +  -  :         143 :  ABI_CALLOC(free,    (ntemper))
          +  -  +  -  -  
             +  -  +  +  
                      + ]
     515   [ -  +  +  -  :         132 :  ABI_CALLOC(energy,  (ntemper))
          -  +  -  +  +  
                      + ]
     516   [ -  +  +  -  :         132 :  ABI_CALLOC(entropy, (ntemper))
          -  +  -  +  +  
                      + ]
     517   [ -  +  +  -  :         132 :  ABI_CALLOC(spheat,  (ntemper))
          -  +  -  +  +  
                      + ]
     518   [ -  +  +  -  :         132 :  ABI_CALLOC(wme,     (ntemper))
          -  +  -  +  +  
                      + ]
     519                 :             : 
     520                 :             :  ! open THERMO file
     521         [ -  + ]:          11 :  if (open_file(fname, msg, newunit=tunt, form="formatted", action="write") /= 0) then
     522                 :           0 :    ABI_ERROR(msg)
     523                 :             :  end if
     524                 :             : 
     525                 :             :  write(msg, '(3a)' )&
     526                 :          11 :   ' phdos_print_thermo: thermodynamic functions calculated from prtdos DOS (not histogram)',ch10,&
     527                 :          22 :   '     see THERMO output file ...'
     528                 :          11 :  call wrtout(std_out,msg)
     529                 :             : 
     530                 :             :  ! print header
     531                 :          11 :  write(tunt,'(a,a)') ch10,&
     532                 :          22 :   ' # At  T     F(J/mol-c)     E(J/mol-c)     S(J/(mol-c.K)) C(J/(mol-c.K)) Omega_mean(cm-1) from prtdos DOS'
     533                 :          11 :  write(tunt, "(a)")' # (A mol-c is the abbreviation of a mole-cell, that is, the'
     534                 :          11 :  write(tunt, "(a)")' #  number of Avogadro times the atoms in a unit cell)'
     535                 :             : 
     536                 :          11 :  domega = phdos%omega_step
     537                 :             : 
     538         [ +  + ]:         121 :  do itemper=1,ntemper
     539                 :             :    ! The temperature (tmp) is given in Ha
     540                 :         110 :    tmp=(tempermin+temperinc*dble(itemper-1))*kb_HaK
     541                 :             : 
     542         [ +  + ]:      407950 :    do iomega=1,PHdos%nomega
     543         [ +  + ]:      407840 :      if (abs(PHdos%phdos(iomega)) < 1.e-200_dp) cycle
     544                 :             : 
     545                 :             :      ! wover2t= hbar*w / 2kT dimensionless
     546         [ +  - ]:      375470 :      wover2t = zero;     if(tmp > tol14) wover2t=PHdos%omega(iomega)*half/tmp
     547                 :             :      ! should not be much of a problem for the log, but still put a check.
     548   [ +  +  +  - ]:      375470 :      ln2shx=zero;        if (wover2t > tol16 .and. wover2t < 100.0_dp) ln2shx=log(two * sinh(wover2t))
     549         [ +  - ]:      281080 :      cothx=zero;         if (wover2t > tol16) cothx=one/tanh(wover2t)
     550         [ +  - ]:      281080 :      invsinh2=zero;      if (wover2t > tol16 .and. wover2t < 100.0_dp) invsinh2=one/sinh(wover2t)**2
     551                 :             : 
     552                 :             :      ! This matches the equations published in Lee & Gonze, PRB 51, 8610 (1995) [[cite:Lee1995]]
     553                 :      375470 :      free(itemper)   = free(itemper)    + PHdos%phdos(iomega)*tmp*ln2shx
     554                 :      375470 :      energy(itemper) = energy(itemper)  + PHdos%phdos(iomega)*half*PHdos%omega(iomega)*cothx
     555                 :      375470 :      spheat(itemper) = spheat(itemper)  + PHdos%phdos(iomega)*wover2t**2 * invsinh2
     556                 :      375470 :      entropy(itemper)= entropy(itemper) + PHdos%phdos(iomega)*(wover2t*cothx - ln2shx)
     557                 :      407950 :      wme(itemper)    = wme(itemper)     + PHdos%phdos(iomega)*PHdos%omega(iomega)*wover2t**2 * invsinh2
     558                 :             :    end do ! iomega
     559                 :             : 
     560                 :             :    ! suppose homogeneous omega grid and multiply by domega
     561                 :         110 :    free(itemper)   = free(itemper)    * domega
     562                 :         110 :    energy(itemper) = energy(itemper)  * domega
     563                 :         110 :    entropy(itemper)= entropy(itemper) * domega
     564                 :         110 :    spheat(itemper) = spheat(itemper)  * domega
     565                 :         110 :    wme(itemper)    = wme(itemper)     * domega
     566                 :             : 
     567         [ +  - ]:         110 :    if (abs(spheat(itemper))>tol8) wme(itemper)=wme(itemper)/spheat(itemper)
     568                 :             : 
     569                 :             :    ! do the printing to file
     570                 :         110 :    write(tunt,'(es11.3,5es15.7)') tmp/kb_HaK,&
     571                 :         110 :     Ha_J*Avogadro*free(itemper),&
     572                 :         110 :     Ha_J*Avogadro*energy(itemper),&
     573                 :         110 :     Ha_J*Avogadro*kb_HaK*entropy(itemper),&
     574                 :         110 :     Ha_J*Avogadro*kb_HaK*spheat(itemper),&
     575                 :         231 :     wme(itemper)*Ha_cmm1
     576                 :             :  end do ! itemper
     577                 :             : 
     578                 :          11 :  close(tunt)
     579                 :             : 
     580         [ -  + ]:          11 :  ABI_FREE(free)
     581         [ -  + ]:          11 :  ABI_FREE(energy)
     582         [ -  + ]:          11 :  ABI_FREE(entropy)
     583         [ -  + ]:          11 :  ABI_FREE(spheat)
     584         [ -  + ]:          11 :  ABI_FREE(wme)
     585                 :             : 
     586                 :          11 : end subroutine phdos_print_thermo
     587                 :             : !!***
     588                 :             : !----------------------------------------------------------------------
     589                 :             : 
     590                 :             : !!****f* m_phonons/phdos_free
     591                 :             : !! NAME
     592                 :             : !! phdos_free
     593                 :             : !!
     594                 :             : !! FUNCTION
     595                 :             : !! Free memory
     596                 :             : !!
     597                 :             : !! SOURCE
     598                 :             : 
     599                 :         177 : subroutine phdos_free(PHdos)
     600                 :             : 
     601                 :             : !Arguments -------------------------------
     602                 :             :  class(phdos_t),intent(inout) ::PHdos
     603                 :             : ! *************************************************************************
     604                 :             : 
     605         [ +  - ]:         177 :  ABI_SFREE(PHdos%atom_mass)
     606         [ +  - ]:         177 :  ABI_SFREE(PHdos%normal_vec_dmm)
     607         [ +  - ]:         177 :  ABI_SFREE(PHdos%omega)
     608         [ +  - ]:         177 :  ABI_SFREE(PHdos%phdos)
     609         [ +  - ]:         177 :  ABI_SFREE(PHdos%phdos_int)
     610         [ +  - ]:         177 :  ABI_SFREE(PHdos%phdos_dmm)
     611         [ +  - ]:         177 :  ABI_SFREE(PHdos%pjdos)
     612         [ +  - ]:         177 :  ABI_SFREE(PHdos%pjdos_int)
     613         [ +  - ]:         177 :  ABI_SFREE(PHdos%pjdos_type)
     614         [ +  - ]:         177 :  ABI_SFREE(PHdos%pjdos_type_int)
     615         [ +  - ]:         177 :  ABI_SFREE(PHdos%pjdos_rc_type)
     616         [ +  - ]:         177 :  ABI_SFREE(PHdos%msqd_dos_atom)
     617                 :             : 
     618                 :         177 : end subroutine phdos_free
     619                 :             : !!***
     620                 :             : 
     621                 :             : !--------------------------------------------------------------------------
     622                 :             : 
     623                 :             : !!****f* m_phonons/phdos_malloc
     624                 :             : !! NAME
     625                 :             : !! phdos_malloc
     626                 :             : !!
     627                 :             : !! FUNCTION
     628                 :             : !! Allocate memory
     629                 :             : !!
     630                 :             : !! INPUTS
     631                 :             : !!
     632                 :             : !! OUTPUT
     633                 :             : !!
     634                 :             : !! SOURCE
     635                 :             : 
     636         [ +  - ]:         177 : subroutine phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos, n_normal_vec_dmm)
     637                 :             : 
     638                 :             : ! Arguments ------------------------------------------------------
     639                 :             :  class(phdos_t),intent(out) :: phdos
     640                 :             :  type(crystal_t),intent(in) :: crystal
     641                 :             :  type(ifc_type),intent(in) :: ifc
     642                 :             :  integer,intent(in) :: prtdos
     643                 :             :  integer,intent(in),optional :: n_normal_vec_dmm
     644                 :             :  real(dp),intent(in) :: dosdeltae,dossmear
     645                 :             :  real(dp),intent(in) :: wminmax(2)
     646                 :             : 
     647                 :             : !Local variables -------------------------
     648                 :             :  integer :: io
     649                 :             : ! *********************************************************************
     650                 :             : 
     651                 :         177 :  phdos%ntypat     = crystal%ntypat
     652                 :         177 :  phdos%natom      = crystal%natom
     653                 :         177 :  phdos%prtdos     = prtdos
     654                 :         177 :  phdos%dossmear   = dossmear
     655                 :         177 :  phdos%omega_step = dosdeltae
     656                 :         177 :  phdos%n_normal_vec_dmm = 7
     657         [ -  + ]:         177 :  if (present(n_normal_vec_dmm)) then
     658                 :           0 :    phdos%n_normal_vec_dmm = n_normal_vec_dmm
     659                 :             :  end if
     660                 :             :  ! Use values stored in ifc (obtained with ab-initio q-mesh + pad)
     661         [ +  + ]:         177 :  if (wminmax(2) > wminmax(1)) then
     662                 :          68 :    phdos%omega_min = wminmax(1)
     663                 :          68 :    phdos%omega_max = wminmax(2)
     664                 :             :  else
     665                 :         109 :    phdos%omega_min = ifc%omega_minmax(1)
     666                 :         109 :    phdos%omega_max = ifc%omega_minmax(2)
     667                 :             :  end if
     668                 :             :  ! Must be consistent with mesh computed in tetra routines!
     669                 :         177 :  phdos%nomega = nint((phdos%omega_max - phdos%omega_min) / phdos%omega_step) + 1
     670                 :             :  ! Ensure Simpson integration will be ok
     671                 :         177 :  phdos%nomega = max(6, phdos%nomega)
     672                 :             : 
     673                 :             :  ! Build frequency mesh.
     674   [ -  +  +  -  :         531 :  ABI_MALLOC(phdos%omega, (phdos%nomega))
          +  -  -  +  -  
                +  -  + ]
     675         [ +  + ]:      200199 :  do io=1,phdos%nomega
     676                 :      200199 :    phdos%omega(io) = phdos%omega_min + phdos%omega_step * (io - 1)
     677                 :             :  end do
     678                 :         177 :  phdos%omega_min = phdos%omega(1)
     679                 :         177 :  phdos%omega_max = phdos%omega(phdos%nomega)
     680                 :             : 
     681                 :             :  ! Allocate arrays that depend on nomega and set them to zero.
     682   [ -  +  +  -  :        5487 :  ABI_CALLOC(phdos%normal_vec_dmm, (3, phdos%n_normal_vec_dmm))
          +  -  +  -  -  
          +  -  +  -  +  
             +  +  +  + ]
     683   [ -  +  +  -  :      200376 :  ABI_CALLOC(phdos%phdos, (phdos%nomega))
          -  +  -  +  -  
                +  +  + ]
     684   [ -  +  +  -  :      200376 :  ABI_CALLOC(phdos%phdos_int, (phdos%nomega))
          -  +  -  +  -  
                +  +  + ]
     685   [ -  +  +  -  :     1402101 :  ABI_CALLOC(phdos%phdos_dmm, (phdos%nomega,phdos%n_normal_vec_dmm))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  -  +  +  
                +  +  + ]
     686   [ -  +  +  -  :     1398168 :  ABI_CALLOC(phdos%pjdos, (phdos%nomega, 3, crystal%natom))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  -  +  +  
             +  +  +  +  
                      + ]
     687   [ -  +  +  -  :     1397991 :  ABI_CALLOC(phdos%pjdos_int, (phdos%nomega, 3, crystal%natom))
          -  +  +  -  -  
          +  -  +  -  +  
          +  +  +  +  +  
                      + ]
     688   [ -  +  +  -  :     4193643 :  ABI_CALLOC(phdos%msqd_dos_atom, (phdos%nomega, 3, 3, crystal%natom))
          +  -  -  +  +  
          -  +  -  +  -  
          -  +  -  +  -  
          +  +  +  +  +  
             +  +  +  + ]
     689   [ -  +  +  -  :         531 :  ABI_MALLOC(phdos%atom_mass, (crystal%natom))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     690   [ +  -  +  +  :        1110 :  phdos%atom_mass = crystal%amu(crystal%typat(:)) * amu_emass
          +  -  -  +  -  
                -  +  + ]
     691                 :             : 
     692                 :         177 : end subroutine phdos_malloc
     693                 :             : !!***
     694                 :             : 
     695                 :             : !---------------------------------------------------------------
     696                 :             : 
     697                 :             : !!****f* m_phonons/phdos_init
     698                 :             : !! NAME
     699                 :             : !! phdos_init
     700                 :             : !!
     701                 :             : !! FUNCTION
     702                 :             : !! Calculate the phonon density of states as well as
     703                 :             : !! the contributions associated to the different types of atoms in the unit cell.
     704                 :             : !! Two methods are implemented: gaussian method and linear interpolation based on tetrahedra.
     705                 :             : !!
     706                 :             : !! INPUTS
     707                 :             : !! ifc<ifc_type>=Interatomic force constants
     708                 :             : !! crystal<crystal_t>=Info on the crystalline structure.
     709                 :             : !! prtdos=1 for gaussian method, 2 for tetrahedra.
     710                 :             : !! dosdeltae=Step of frequency mesh.
     711                 :             : !! dossmear=Gaussian broadening, used if prtdos==1.
     712                 :             : !! dos_ngqpt(3)=Divisions of the q-mesh used for computing the DOS
     713                 :             : !! nqshift=Number of shifts in Q-mesh
     714                 :             : !! dos_qshift(3, nqshift)=Shift of the q-mesh.
     715                 :             : !! prefix=Prefix for PHBIZ output file. Empty string to deactivate output.
     716                 :             : !! comm=MPI communicator.
     717                 :             : !! prtout=write info to the output and log files.
     718                 :             : !!
     719                 :             : !! OUTPUT
     720                 :             : !! phdos<phdos_t>=Container with phonon DOS, IDOS and atom-projected DOS.
     721                 :             : !! count_wminmax(2)=Number of (interpolated) phonon frequencies that are outside
     722                 :             : !!   input range (see wminmax). Client code can use count_wminmax and wminmax to
     723                 :             : !!   enlarge the mesh and call the routine again to recompute the DOS
     724                 :             : !!   if all frequencies should be included.
     725                 :             : !!
     726                 :             : !! SIDE EFFECTS
     727                 :             : !! wminmax(2)=
     728                 :             : !!   In input: min and max value of frequency mesh. Used only if minmax(2) > minmax(1)
     729                 :             : !!    else values are taken from ifc%omega_minmax (computed from ab-initio mesh + pad)
     730                 :             : !!   In output: min and max frequency obtained after interpolating the IFCs on the dense q-mesh dos_ngqpt
     731                 :             : !!
     732                 :             : !! SOURCE
     733                 :             : 
     734                 :         177 : subroutine phdos_init(phdos, crystal, ifc, prtdos, dosdeltae_in, dossmear, dos_ngqpt, nqshft, dos_qshift, prefix, &
     735                 :             :                       wminmax, count_wminmax, comm, dos_maxmode, prtout)
     736                 :             : 
     737                 :             : !Arguments -------------------------------
     738                 :             : !scalars
     739                 :             :  class(phdos_t),intent(out) :: phdos
     740                 :             :  integer,intent(in) :: prtdos,nqshft,comm
     741                 :             :  real(dp),intent(in) :: dosdeltae_in,dossmear
     742                 :             :  character(len=*),intent(in) ::  prefix
     743                 :             :  type(crystal_t),intent(in) :: crystal
     744                 :             :  type(ifc_type),intent(in) :: ifc
     745                 :             :  integer, optional, intent(in) :: dos_maxmode
     746                 :             :  logical, optional, intent(in) :: prtout
     747                 :             : !arrays
     748                 :             :  integer,intent(in) :: dos_ngqpt(3)
     749                 :             :  integer,intent(out) :: count_wminmax(2)
     750                 :             :  real(dp),intent(in) :: dos_qshift(3,nqshft)
     751                 :             :  real(dp),intent(inout) :: wminmax(2)
     752                 :             : 
     753                 :             : !Local variables -------------------------
     754                 :             : !scalars
     755                 :             :  integer,parameter :: bcorr0 = 0, master = 0
     756                 :             :  integer :: iat,jat,idir,imode,io,iq_ibz,itype, my_qptopt, my_nsym
     757                 :             :  integer :: nqbz,ierr,natom,nomega,jdir, isym, nprocs, my_rank, ncid, icart
     758                 :             :  logical :: refine_dosdeltae
     759                 :             :  real(dp),parameter :: max_occ1=one, gaussmaxarg = sqrt(-log(1.d-90)), max_smallq = 0.0625_dp
     760                 :             :  real(dp) :: nsmallq,gaussfactor,gaussprefactor,normq,debyefreq,rtmp
     761                 :             :  real(dp) :: cpu, wall, gflops, cpu_all, wall_all, gflops_all
     762                 :             :  real(dp) :: dosdeltae, phdos_int, projfact
     763                 :             :  character(len=500) :: msg
     764                 :             :  character(len=80) :: errstr
     765                 :         177 :  type(htetra_t) :: htetra_q
     766                 :             : !arrays
     767                 :             :  integer :: in_qptrlatt(3,3),new_qptrlatt(3,3), units(2)
     768                 :             :  integer :: dos_maxmode_
     769                 :             :  logical :: prtout_
     770                 :         177 :  integer,allocatable :: bz2ibz_smap(:,:), bz2ibz(:)
     771                 :             :  real(dp) :: veloc(3), speedofsound(3),speedofsound_(3)
     772                 :         354 :  real(dp) :: displ(2*3*Crystal%natom*3*Crystal%natom)
     773                 :         531 :  real(dp) :: eigvec(2,3,Crystal%natom,3*Crystal%natom),phfrq(3*Crystal%natom),phangmom(3,3*Crystal%natom)
     774                 :         354 :  real(dp) :: veloc_1q(3,3*Crystal%natom)
     775                 :             :  real(dp) :: qlatt(3,3),rlatt(3,3), msqd_atom_tmp(3,3),temp_33(3,3)
     776                 :         354 :  real(dp) :: symcart(3,3,crystal%nsym), syme2_xyza(3, crystal%natom)
     777                 :         177 :  real(dp),allocatable :: full_eigvec(:,:,:,:,:),full_phfrq(:,:),full_phangmom(:,:,:),new_shiftq(:,:), full_veloc(:,:,:)
     778                 :         177 :  real(dp),allocatable :: qbz(:,:),qibz(:,:),tmp_phfrq(:) !, work_msqd(:,:,:,:)
     779         [ +  - ]:         177 :  real(dp),allocatable :: wtq_ibz(:),xvals(:), gvals_wtq(:), wdt(:,:), energies(:)
     780                 :             : ! *********************************************************************
     781                 :             : 
     782                 :             :  DBG_ENTER("COLL")
     783                 :             : 
     784                 :         177 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     785         [ +  + ]:         531 :  units = [std_out, ab_out]
     786                 :         177 :  prtout_ = .true.
     787         [ +  + ]:         177 :  if (present(prtout)) then
     788                 :          92 :     prtout_ = prtout
     789                 :             :  end if
     790                 :             : 
     791                 :             :  ! Consistency check.
     792         [ -  + ]:         177 :  if (all(prtdos /= [1, 2])) then
     793                 :           0 :    ABI_BUG(sjoin('prtdos should be 1 or 2, but received', itoa(prtdos)))
     794                 :             :  end if
     795                 :         177 :  dosdeltae = dosdeltae_in; refine_dosdeltae = .false.
     796         [ -  + ]:         177 :  if (dosdeltae <= zero) then
     797                 :           0 :    dosdeltae = -dosdeltae; refine_dosdeltae = .true.
     798         [ #  # ]:           0 :    ABI_CHECK(nprocs == 1, "refine_dosdeltae cannot be used with nprocs > 1")
     799                 :             :  end if
     800   [ +  +  -  + ]:         177 :  if (prtdos == 1 .and. dossmear <= zero) then
     801                 :           0 :    ABI_BUG(sjoin('dossmear should be positive but received', ftoa(dossmear)))
     802                 :             :  end if
     803                 :             : 
     804                 :         177 :  call cwtime(cpu_all, wall_all, gflops_all, "start")
     805                 :             : 
     806                 :             :  ! Get symmetries in cartesian coordinates
     807         [ +  + ]:        7315 :  do isym=1,crystal%nsym
     808                 :        7315 :    call symredcart(crystal%rprimd,crystal%gprimd,symcart(:,:,isym),crystal%symrel(:,:,isym))
     809                 :             :  end do
     810                 :             : 
     811                 :         177 :  natom = crystal%natom
     812                 :         177 :  call phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos)
     813                 :         177 :  nomega = phdos%nomega
     814                 :             : 
     815   [ +  +  +  + ]:        4713 :  veloc_1q = zero
     816                 :             :  ! TODO: add input variable and adapt these directions to be read in from input file
     817         [ +  - ]:         177 :  if (phdos%n_normal_vec_dmm >= 7) then
     818         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,1) = [one, zero, zero]
     819         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,2) = [zero, one, zero]
     820         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,3) = [zero, zero, one]
     821         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,4) = [one, one, zero]
     822         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,5) = [one, zero, one]
     823         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,6) = [zero, one, one]
     824         [ +  + ]:         708 :    phdos%normal_vec_dmm(:,7) = [one, one, one]
     825                 :             :  end if
     826   [ -  +  +  -  :         531 :  ABI_MALLOC(gvals_wtq, (nomega))
          +  -  +  -  -  
                +  -  + ]
     827   [ -  +  +  -  :         354 :  ABI_MALLOC(xvals, (nomega))
             -  +  -  + ]
     828                 :             : 
     829                 :             :  ! Parameters defining the gaussian approximant.
     830         [ +  + ]:         177 :  if (prtdos == 1) then
     831                 :             :    ! TODO: use gaussian and update reference files.
     832                 :         101 :    gaussprefactor = one / (dossmear * sqrt(two_pi))
     833                 :         101 :    gaussfactor = one / (sqrt2 * dossmear)
     834                 :         101 :    write(msg, '(4a,f8.5,2a,f8.5,a,i0)') ch10, &
     835                 :         101 :     ' phdos_init: calculating phonon DOS using gaussian method:', ch10, &
     836                 :         101 :     '    gaussian smearing [meV] = ', dossmear * Ha_meV, ch10, &
     837                 :         202 :     '    frequency step    [meV] = ', phdos%omega_step * Ha_meV, ", nomega = ",phdos%nomega
     838         [ -  + ]:          76 :  else if (prtdos == 2) then
     839                 :          76 :    write(msg, '(4a,f8.5,a,i0)') ch10, &
     840                 :          76 :     ' phdos_init: calculating phonon DOS using tetrahedron method:', ch10, &
     841                 :         152 :     '    frequency step    [meV] = ',phdos%omega_step * Ha_meV, ", nomega = ",phdos%nomega
     842                 :             :  end if
     843         [ +  + ]:         177 :  if (prtout_) call wrtout(std_out, msg)
     844                 :             : 
     845                 :             :  ! This call will set %nqibz and IBZ and BZ arrays
     846                 :         177 :  in_qptrlatt = 0; in_qptrlatt(1, 1) = dos_ngqpt(1); in_qptrlatt(2, 2) = dos_ngqpt(2); in_qptrlatt(3, 3) = dos_ngqpt(3)
     847                 :             : 
     848                 :         177 :  my_qptopt = 1
     849                 :             :  !my_qptopt = 3 ! This to deactivate the use of symmetries for debugging purposes.
     850                 :             :  call kpts_ibz_from_kptrlatt(crystal, in_qptrlatt, my_qptopt, nqshft, dos_qshift, &
     851                 :         177 :    phdos%nqibz, qibz, wtq_ibz, nqbz, qbz, new_kptrlatt=new_qptrlatt, new_shiftk=new_shiftq, bz2ibz=bz2ibz_smap)
     852                 :             : 
     853                 :             :  my_nsym = crystal%nsym; if (my_qptopt == 3) my_nsym = 1
     854                 :             : 
     855   [ +  +  +  + ]:        2301 :  phdos%qptrlatt = new_qptrlatt
     856         [ +  + ]:         708 :  phdos%shiftq(:) = new_shiftq(:, 1) ! only one shift in output
     857                 :             : 
     858         [ +  - ]:         177 :  if (my_rank == master) then
     859         [ +  - ]:         177 :    write(msg, "(3a, i0)")" DOS ngqpt: ", trim(ltoa(dos_ngqpt)), ", qptopt: ", my_qptopt
     860         [ +  + ]:         177 :    if (prtout_) call wrtout(std_out, msg)
     861                 :         177 :    write(msg, "(2(a, i0))")" Number of q-points in the IBZ: ", phdos%nqibz, ", number of MPI processes: ", nprocs
     862         [ +  + ]:         177 :    if (prtout_) call wrtout(std_out, msg)
     863                 :             :  end if
     864                 :             :  !call cwtime_report(" kpts_ibz_from_kptrlatt", cpu, wall, gflops)
     865                 :             : 
     866         [ +  + ]:         177 :  if (prtdos == 2) then
     867                 :             :    ! Prepare tetrahedron method including workspace arrays.
     868                 :             :    ! Convert kptrlatt to double and invert, qlatt here refer to the shortest qpt vectors
     869   [ +  +  +  + ]:         988 :    rlatt = new_qptrlatt; call matr3inv(rlatt, qlatt)
     870                 :             : 
     871   [ -  +  +  -  :         228 :    ABI_MALLOC(bz2ibz, (nqbz))
          +  -  +  -  -  
                +  -  + ]
     872   [ +  -  -  +  :      472734 :    bz2ibz = bz2ibz_smap(1,:)
             -  -  +  + ]
     873                 :             : 
     874                 :          76 :    call htetra_q%init(bz2ibz, crystal%gprimd, qlatt, qbz, nqbz, qibz, phdos%nqibz, ierr, errstr, comm)
     875                 :             :    !call cwtime_report(" init_tetra", cpu, wall, gflops)
     876         [ -  + ]:          76 :    ABI_CHECK(ierr == 0, errstr)
     877         [ -  + ]:          76 :    ABI_FREE(bz2ibz)
     878                 :             : 
     879                 :             :    ! Allocate arrays used to store the entire spectrum, Required to calculate tetra weights.
     880                 :             :    ! this may change in the future if Matteo refactorizes the tetra weights as sums over k instead of sums over bands
     881   [ +  -  -  +  :      104400 :    ABI_CALLOC(full_phfrq, (3*natom, phdos%nqibz))
          +  -  -  +  +  
          -  +  -  +  -  
          -  +  -  +  +  
                +  +  + ]
     882   [ -  +  +  -  :      369509 :    ABI_CALLOC(full_veloc, (3,3*natom, phdos%nqibz))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  +  +  +  
                +  +  + ]
     883   [ -  +  +  -  :         228 :    ABI_MALLOC(full_phangmom, (3, 3*natom, phdos%nqibz))
          -  +  +  -  -  
                +  -  + ]
     884   [ -  +  +  -  :         380 :    ABI_MALLOC_OR_DIE(full_eigvec, (2, 3, natom, 3*natom, phdos%nqibz), ierr)
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  +  -  -  
                +  -  + ]
     885   [ +  +  +  +  :     1885406 :    full_eigvec = zero
          +  +  +  +  +  
                      + ]
     886                 :             :  end if ! tetra
     887                 :             : 
     888         [ -  + ]:         177 :  ABI_FREE(bz2ibz_smap)
     889         [ -  + ]:         177 :  ABI_FREE(new_shiftq)
     890                 :             : 
     891                 :             :  ! MPI Sum over irreducible q-points then sync the following integrals:
     892                 :             :  !   speedofsound, nsmallq
     893                 :             :  !   wminmax and count_wminmax
     894                 :             :  !   if gauss: %phdos, %msqd_dos_atom
     895                 :             :  !   if tetra: full_phfrq, full_eigvec, full_phangmom, %phdos_int
     896                 :             : 
     897                 :         177 :  nsmallq = zero; speedofsound = zero
     898                 :         177 :  wminmax = [huge(one), -huge(one)]; count_wminmax = 0
     899                 :             : 
     900         [ +  + ]:      155684 :  do iq_ibz=1,phdos%nqibz
     901         [ +  - ]:      155507 :    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
     902                 :             : 
     903                 :             :    ! Fourier interpolation (keep track of min/max to decide if initial mesh was large enough)
     904                 :             :    ! get velocities from this call as well for iq_ibz
     905                 :             :    ! the if clause saves a bit of time if we do not need to project anything later
     906         [ +  - ]:      155507 :    if (phdos%n_normal_vec_dmm > 0) then
     907                 :      155507 :      call ifc%fourq(crystal, qibz(:,iq_ibz), phfrq, displ, out_eigvec=eigvec, dwdq=veloc_1q)
     908                 :             :    else
     909                 :           0 :      call ifc%fourq(crystal, qibz(:,iq_ibz), phfrq, displ, out_eigvec=eigvec)
     910                 :             :    end if
     911                 :             : 
     912   [ +  -  -  +  :     1067041 :    wminmax(1) = min(wminmax(1), minval(phfrq))
             -  -  +  + ]
     913         [ +  + ]:      155507 :    if (wminmax(1) < phdos%omega(1)) count_wminmax(1) = count_wminmax(1) + 1
     914   [ +  -  -  +  :     1067041 :    wminmax(2) = max(wminmax(2), maxval(phfrq))
             -  -  +  + ]
     915         [ +  + ]:      155507 :    if (wminmax(2) > phdos%omega(nomega)) count_wminmax(2) = count_wminmax(2) + 1
     916                 :             : 
     917         [ +  + ]:      622028 :    normq = sum(qibz(:,iq_ibz) ** 2)
     918   [ +  +  +  + ]:      155507 :    if (normq < max_smallq .and. normq > tol6) then
     919                 :       12131 :      call phdos_calc_vsound(eigvec, crystal%gmet, natom, phfrq, qibz(:,iq_ibz), speedofsound_)
     920         [ +  + ]:       48524 :      speedofsound = speedofsound + speedofsound_ * wtq_ibz(iq_ibz)
     921                 :       12131 :      nsmallq = nsmallq + wtq_ibz(iq_ibz)
     922                 :             :    end if
     923                 :             : 
     924                 :      155507 :    dos_maxmode_ = 3*natom
     925         [ +  + ]:      155507 :    if (present(dos_maxmode)) then
     926         [ -  + ]:        1982 :      if (dos_maxmode > 0 .and. dos_maxmode < 3*natom) then
     927                 :      155507 :        dos_maxmode_ = dos_maxmode
     928                 :             :      end if
     929                 :             :    end if
     930                 :             : 
     931                 :         177 :    select case (prtdos)
     932                 :             :    case (1)
     933         [ +  + ]:      807514 :      do imode=1,dos_maxmode_
     934                 :             :        ! Precompute \delta(w - w_{qnu}) * weight(q)
     935   [ +  -  -  +  :   403576059 :        xvals = (phdos%omega(:) - phfrq(imode)) * gaussfactor
             -  -  +  + ]
     936   [ +  +  +  + ]:   402908427 :        where (abs(xvals) < gaussmaxarg)
     937                 :             :          gvals_wtq = gaussprefactor * exp(-xvals*xvals) * wtq_ibz(iq_ibz)
     938                 :             :        elsewhere
     939                 :             :          gvals_wtq = zero
     940                 :             :        end where
     941                 :             : 
     942                 :             :        ! Accumulate PHDOS
     943         [ +  + ]:   402908427 :        phdos%phdos(:) = phdos%phdos(:) + gvals_wtq(:)
     944                 :             : 
     945                 :             :        ! Rotate e(q) to get e(Sq) to account for symmetrical q-points in BZ.
     946                 :             :        ! eigenvectors indeed are not invariant under rotation. See e.g. Eq 39-40 of PhysRevB.76.165108 [[cite:Giustino2007]].
     947                 :             :        ! In principle there's a phase due to nonsymmorphic translations but we here need |e(Sq)_iatom|**2
     948   [ +  +  +  + ]:     5662896 :        syme2_xyza = zero
     949         [ +  + ]:     1916448 :        do iat=1,natom
     950         [ +  + ]:    22847520 :          do isym=1,my_nsym
     951                 :    20931072 :            jat = crystal%indsym(4,isym,iat)
     952                 :             :            syme2_xyza(:,jat) = syme2_xyza(:,jat) + &
     953                 :             :              matmul(symcart(:,:,isym), eigvec(1,:,iat,imode)) ** 2 + &
     954   [ +  +  +  +  :   587318832 :              matmul(symcart(:,:,isym), eigvec(2,:,iat,imode)) ** 2
          +  +  +  +  +  
                      + ]
     955                 :             :          end do
     956                 :             :        end do
     957   [ +  +  +  + ]:     5662896 :        syme2_xyza = syme2_xyza / my_nsym
     958                 :             : 
     959                 :             :        ! Accumulate PJDOS
     960         [ +  + ]:     1916448 :        do iat=1,natom
     961         [ +  + ]:     5662896 :          do idir=1,3
     962         [ +  + ]:  2230540797 :            phdos%pjdos(:,idir,iat) = phdos%pjdos(:,idir,iat) + syme2_xyza(idir,iat) * gvals_wtq
     963                 :             :          end do
     964                 :             :        end do
     965                 :             : 
     966                 :             :        ! Accumulate outer product of displacement vectors
     967                 :             :        ! NB: only accumulate real part. e(-q) = e(q)* the full sum over the BZ guarantees Im=0
     968                 :             :        ! this sum only does irreducible points: the matrix is symmetrized below
     969                 :             :        ! msqd_atom_tmp has units of bohr^2 / Ha as gaussval ~ 1/smear ~ 1/Ha
     970         [ +  + ]:     1916448 :        do iat=1,natom
     971                 :     1248816 :          msqd_atom_tmp = zero
     972         [ +  + ]:     4995264 :          do idir=1,3
     973         [ +  + ]:    16234608 :            do jdir=1,3
     974                 :             :              msqd_atom_tmp(jdir,idir) = msqd_atom_tmp(jdir,idir) + ( &
     975                 :             :                    eigvec(1,idir,iat,imode) * eigvec(1,jdir,iat,imode) &
     976                 :    14985792 :                 +  eigvec(2,idir,iat,imode) * eigvec(2,jdir,iat,imode) )
     977                 :             :            end do
     978                 :             :          end do
     979                 :             : 
     980                 :             :          ! Symmetrize matrices to get full sum of tensor over all BZ, not just IBZ.
     981                 :             :          ! the atom is not necessarily invariant under symops, so these contributions should be added to each iat separately
     982                 :             :          ! normalization by nsym is done at the end outside the iqpt loop and after the tetrahedron clause
     983                 :             :          ! NB: looks consistent with the sym in harmonic thermo, just used in opposite
     984                 :             :          ! direction for symops: symrel here instead of symrec and the inverse of indsym in harmonic_thermo
     985         [ +  + ]:    22847520 :          do isym=1, my_nsym
     986                 :             :            !temp_33 = matmul( (symcart(:,:,isym)), matmul(msqd_atom_tmp, transpose(symcart(:,:,isym))) )
     987                 :             :            ! MG Version
     988   [ +  +  +  +  :  1904727552 :            temp_33 = matmul( (transpose(symcart(:,:,isym))), matmul(msqd_atom_tmp, symcart(:,:,isym)) )
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
     989   [ +  +  +  + ]:   272103936 :            temp_33 = temp_33 / my_nsym
     990                 :    20931072 :            jat = crystal%indsym(4,isym,iat)
     991         [ +  + ]:    84973104 :            do idir=1,3
     992         [ +  + ]:   272103936 :              do jdir=1,3
     993                 :             :                phdos%msqd_dos_atom(:,idir,jdir,jat) = phdos%msqd_dos_atom(:,idir,jdir,jat) + &
     994         [ +  + ]: >14319*10^7 :                  temp_33(idir, jdir) * gvals_wtq
     995                 :             :              end do
     996                 :             :            end do
     997                 :             :          end do
     998                 :             : 
     999                 :             :        end do ! iat msqd loop
    1000                 :             : 
    1001                 :             :        ! DOS including velocity projected onto interface normal vector
    1002         [ +  + ]:     2670528 :        veloc = veloc_1q(:,imode)
    1003         [ +  + ]:     5480938 :        do icart = 1, phdos%n_normal_vec_dmm
    1004                 :             :          ! projection of the velocity onto chosen normal vector for the interface in DMM.
    1005                 :             :          ! NB: The sign can change, but norm of scalar product is the correct recipe.
    1006                 :             :          projfact = zero
    1007                 :             :          ! as we are summing only over irred q-points, need to add all contributions
    1008                 :             :          ! from the velocities on the star of q_ibz
    1009         [ +  + ]:   101462928 :          do isym=1,my_nsym
    1010   [ +  +  +  +  :  1553305488 :            projfact = projfact + abs(dot_product(matmul(symcart(:,:,isym),veloc),phdos%normal_vec_dmm(:,icart)))
                   +  + ]
    1011                 :             :          end do
    1012         [ +  + ]:  2821026621 :          phdos%phdos_dmm(:,icart) = phdos%phdos_dmm(:,icart) + projfact * gvals_wtq(:) / my_nsym
    1013                 :             :        end do
    1014                 :             : 
    1015                 :             :      end do ! imode
    1016                 :             : 
    1017                 :             :    case (2)
    1018                 :             :      ! Tetrahedra; Save phonon frequencies, eigenvectors and angular momentum.
    1019                 :             :      ! Sum is done after the loops over the two meshes.
    1020         [ +  + ]:      104020 :      full_phfrq(:,iq_ibz) = phfrq(:)
    1021   [ +  +  +  + ]:      369205 :      full_veloc(:,:,iq_ibz) = veloc_1q(:,:)
    1022   [ +  +  +  +  :     1885330 :      full_eigvec(:,:,:,:,iq_ibz) = eigvec
             +  +  +  + ]
    1023   [ +  +  +  + ]:      369205 :      full_phangmom(:,:,iq_ibz) = phangmom
    1024                 :             : 
    1025                 :             :    case default
    1026      [ +  +  - ]:      155507 :      ABI_ERROR(sjoin("Wrong value for prtdos:", itoa(prtdos)))
    1027                 :             :    end select
    1028                 :             :  end do ! iq_ibz
    1029                 :             : 
    1030         [ -  + ]:         177 :  ABI_FREE(qbz)
    1031         [ -  + ]:         177 :  ABI_FREE(gvals_wtq)
    1032         [ -  + ]:         177 :  ABI_FREE(xvals)
    1033                 :             : 
    1034                 :         177 :  call xmpi_sum_master(nsmallq, master, comm, ierr)
    1035                 :         177 :  call xmpi_sum_master(speedofsound, master, comm, ierr)
    1036                 :             : 
    1037                 :             :  !call cwtime_report(" phdos", cpu, wall, gflops)
    1038                 :             : 
    1039         [ +  - ]:         177 :  if (my_rank == master) then
    1040         [ +  + ]:         177 :    if (nsmallq > tol10) then
    1041                 :             :       ! Write info about speed of sound
    1042         [ +  + ]:         700 :       speedofsound = speedofsound / nsmallq
    1043                 :             :       write (msg,'(a,E20.10,3a,F16.4,2a)') &
    1044         [ +  + ]:         700 :          ' Average speed of sound partial sums: ', third*sum(speedofsound), ' (at units)',ch10, &
    1045         [ +  + ]:         875 :          '-                                   = ', third*sum(speedofsound) * Bohr_Ang * 1.d-13 / Time_Sec, ' [km/s]',ch10
    1046         [ +  + ]:         175 :       if (prtout_) call wrtout(units, msg)
    1047                 :             : 
    1048                 :             :       ! Debye frequency = vs * (6 pi^2 natom / ucvol)**1/3
    1049         [ +  + ]:         700 :       debyefreq = third*sum(speedofsound) * (six*pi**2/crystal%ucvol)**(1./3.)
    1050                 :             :       write (msg,'(a,E20.10,3a,E20.10,a)') &
    1051                 :         175 :          ' Debye frequency from partial sums: ', debyefreq, ' (Ha)',ch10, &
    1052                 :         350 :          '-                                 = ', debyefreq*Ha_THz, ' (THz)'
    1053         [ +  + ]:         175 :       if (prtout_) call wrtout(units, msg)
    1054                 :             : 
    1055                 :             :       ! Debye temperature = hbar * Debye frequency / kb
    1056                 :         175 :       write (msg,'(a,E20.10,2a)') '-Debye temperature from partial sums: ', debyefreq*Ha_K, ' (K)', ch10
    1057         [ +  + ]:         175 :       if (prtout_) call wrtout(units, msg)
    1058                 :             :    end if
    1059                 :             :  end if
    1060                 :             : 
    1061         [ +  + ]:         177 :  if (prtdos == 2) then
    1062                 :          76 :    call cwtime(cpu, wall, gflops, "start")
    1063                 :             :    ! Finalize integration with tetrahedra
    1064                 :             :    ! All the data are contained in full_phfrq, full_eigvec and full_phangmom.
    1065                 :          76 :    call xmpi_sum(full_phfrq, comm, ierr)
    1066                 :          76 :    call xmpi_sum(full_veloc, comm, ierr)
    1067                 :          76 :    call xmpi_sum(full_eigvec, comm, ierr)
    1068                 :          76 :    call xmpi_sum(full_phangmom, comm, ierr)
    1069                 :             : 
    1070   [ -  +  +  -  :         228 :    ABI_MALLOC(tmp_phfrq, (phdos%nqibz))
          +  -  +  -  -  
                +  -  + ]
    1071                 :             : 
    1072                 :           0 :    do
    1073   [ -  +  +  -  :         228 :      ABI_MALLOC(wdt, (phdos%nomega, 2))
          +  -  +  -  -  
                +  -  + ]
    1074   [ -  +  +  -  :         228 :      ABI_MALLOC(energies, (phdos%nomega))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
    1075         [ -  + ]:          76 :      energies = linspace(phdos%omega_min, phdos%omega_max, phdos%nomega)
    1076                 :             : 
    1077         [ +  + ]:       15701 :      do iq_ibz=1,phdos%nqibz
    1078         [ +  - ]:       15625 :        if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
    1079                 :             : 
    1080         [ +  + ]:      104096 :        do imode=1,dos_maxmode_
    1081                 :             :          ! Compute the weights for this q-point using tetrahedron
    1082         [ +  + ]:    20158392 :          tmp_phfrq(:) = full_phfrq(imode,:)
    1083                 :       88395 :          call htetra_q%get_onewk_wvals(iq_ibz,bcorr0,phdos%nomega,energies,max_occ1,phdos%nqibz,tmp_phfrq,wdt)
    1084   [ +  +  +  + ]:   161295981 :          wdt = wdt * wtq_ibz(iq_ibz)
    1085                 :             : 
    1086                 :             :          ! Accumulate DOS/IDOS
    1087         [ +  + ]:    80603793 :          phdos%phdos(:)     = phdos%phdos(:)     + wdt(:, 1)
    1088         [ +  + ]:    80603793 :          phdos%phdos_int(:) = phdos%phdos_int(:) + wdt(:, 2)
    1089                 :             : 
    1090                 :             :          ! Rotate e(q) to get e(Sq) to account for other q-points in BZ. See notes in gaussian branch
    1091   [ +  +  +  + ]:      800919 :          syme2_xyza = zero
    1092         [ +  + ]:      266526 :          do iat=1,natom
    1093         [ +  + ]:     7665588 :            do isym=1,my_nsym
    1094                 :     7399062 :              jat = crystal%indsym(4,isym,iat)
    1095                 :             :              syme2_xyza(:,jat) = syme2_xyza(:,jat) + &
    1096                 :             :                matmul(symcart(:,:,isym), full_eigvec(1,:,iat,imode,iq_ibz)) ** 2 + &
    1097   [ +  +  +  +  :   207351867 :                matmul(symcart(:,:,isym), full_eigvec(2,:,iat,imode,iq_ibz)) ** 2
          +  -  +  +  +  
             +  +  -  +  
                      + ]
    1098                 :             :            end do
    1099                 :             :          end do
    1100   [ +  +  +  + ]:      800919 :          syme2_xyza = syme2_xyza / my_nsym
    1101                 :             : 
    1102         [ +  + ]:      266526 :          do iat=1,natom
    1103         [ +  + ]:      800919 :            do idir=1,3
    1104         [ +  + ]:   597389409 :              phdos%pjdos(:,idir,iat) = phdos%pjdos(:,idir,iat) + syme2_xyza(idir,iat) * wdt(:,1)
    1105         [ +  + ]:   597567540 :              phdos%pjdos_int(:,idir,iat) = phdos%pjdos_int(:,idir,iat) + syme2_xyza(idir,iat) * wdt(:,2)
    1106                 :             :            end do
    1107                 :             :          end do
    1108                 :             : 
    1109         [ +  + ]:      266526 :          do iat=1,natom
    1110                 :             : 
    1111                 :             :            ! Accumulate outer product of displacement vectors
    1112                 :      178131 :            msqd_atom_tmp = zero
    1113         [ +  + ]:      712524 :            do idir=1,3
    1114         [ +  + ]:     2315703 :              do jdir=1,3
    1115                 :             :                msqd_atom_tmp(jdir,idir) = msqd_atom_tmp(jdir,idir) + ( &
    1116                 :             :                      full_eigvec(1,idir,iat,imode,iq_ibz) * full_eigvec(1,jdir,iat,imode,iq_ibz) &
    1117                 :     2137572 :                   +  full_eigvec(2,idir,iat,imode,iq_ibz) * full_eigvec(2,jdir,iat,imode,iq_ibz) )
    1118                 :             :              end do
    1119                 :             :            end do
    1120                 :             : 
    1121                 :             :            ! Symmetrize matrices to get full sum of tensor over all BZ, not just IBZ.
    1122                 :             :            ! the atom is not necessarily invariant under symops, so these contributions should be added to each iat separately
    1123                 :             :            ! normalization by nsym is done at the end outside the iqpt loop and after the tetrahedron clause
    1124                 :             :            ! from loops above only the eigvec are kept and not the displ, so we still have to divide by the masses
    1125                 :             :            ! TODO: need to check the direction of the symcart vs transpose or inverse, given that jat is the pre-image of iat...
    1126         [ +  + ]:     7665588 :            do isym=1,my_nsym
    1127                 :             :              !temp_33 = matmul((symcart(:,:,isym)), matmul(msqd_atom_tmp, transpose(symcart(:,:,isym))))
    1128                 :             :              ! MG Version
    1129   [ +  +  +  +  :   673314642 :              temp_33 = matmul( (transpose(symcart(:,:,isym))), matmul(msqd_atom_tmp, symcart(:,:,isym)) )
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
    1130   [ +  +  +  + ]:    96187806 :              temp_33 = temp_33 / my_nsym
    1131                 :     7399062 :              jat = crystal%indsym(4,isym,iat)
    1132         [ +  + ]:    29774379 :              do idir=1,3
    1133         [ +  + ]:    96187806 :                do jdir=1,3
    1134                 :             :                  phdos%msqd_dos_atom(:,idir,jdir,jat) = phdos%msqd_dos_atom(:,idir,jdir,jat) + &
    1135         [ +  + ]: 61356659490 :                    temp_33(idir, jdir) * wdt(:,1)
    1136                 :             :                end do
    1137                 :             :              end do
    1138                 :             :            end do
    1139                 :             :          end do ! iat msqd accumulation
    1140                 :             : 
    1141                 :             :          ! DOS including velocity projected onto interface normal vector
    1142         [ +  + ]:      353580 :          veloc = full_veloc(:,imode,iq_ibz)
    1143         [ +  + ]:      722785 :          do icart = 1, phdos%n_normal_vec_dmm
    1144                 :             :            ! projection of the velocity onto chosen normal vector for the interface in DMM.
    1145                 :             :            ! NB: The sign can change, but norm of scalar product is the correct recipe.
    1146                 :             :            projfact = zero
    1147                 :             :            ! as we are summing only over irred q-points, need to add all contributions
    1148                 :             :            ! from the velocities on the star of q_ibz
    1149         [ +  + ]:    27404727 :            do isym=1,my_nsym
    1150   [ +  +  +  +  :   429194157 :              projfact = projfact + abs(dot_product(matmul(symcart(:,:,isym),veloc),phdos%normal_vec_dmm(:,icart)))
                   +  + ]
    1151                 :             :            end do
    1152         [ +  + ]:   564314946 :            phdos%phdos_dmm(:,icart) = phdos%phdos_dmm(:,icart) + projfact * wdt(:,1) / my_nsym
    1153                 :             :          end do
    1154                 :             : 
    1155                 :             :        end do ! imode
    1156                 :             :      end do ! iq_ibz
    1157                 :             : 
    1158         [ -  + ]:          76 :      if (refine_dosdeltae) then
    1159                 :             :        ! HM: Check if the integration of the DOS is correct, otherwise half dos%deltae and re-run
    1160                 :             :        ! MG FIXME: This won't work in parallel because we still have to call xmpi_sum
    1161                 :           0 :        call ctrap(phdos%nomega, phdos%phdos, phdos%omega_step, phdos_int)
    1162         [ #  # ]:           0 :        if (abs(phdos_int - crystal%natom*3) > tol2) then
    1163                 :           0 :          write(msg,'(a,f6.2,a,i4,2a,e10.3,a,e10.3)') "The value of the integral is", phdos_int, &
    1164                 :           0 :                       " but it should be", crystal%natom*3, ch10,&
    1165                 :           0 :                       "I will decrease dosdeltae from: ", dosdeltae, " to: ", dosdeltae/two
    1166                 :           0 :          ABI_WARNING(msg)
    1167                 :           0 :          dosdeltae = dosdeltae / two
    1168                 :           0 :          call phdos%free()
    1169                 :           0 :          call phdos_malloc(phdos, crystal, ifc, dosdeltae, dossmear, wminmax, prtdos)
    1170                 :           0 :          nomega = phdos%nomega
    1171         [ #  # ]:           0 :          ABI_FREE(wdt)
    1172         [ #  # ]:           0 :          ABI_FREE(energies)
    1173                 :             :          cycle
    1174                 :             :        endif
    1175                 :             :      endif
    1176                 :             : 
    1177                 :             :      exit
    1178                 :             :    end do
    1179                 :             : 
    1180         [ -  + ]:          76 :    ABI_FREE(energies)
    1181         [ -  + ]:          76 :    ABI_FREE(wdt)
    1182                 :             : 
    1183                 :             :    ! Make eigvec into phonon displacements.
    1184         [ +  + ]:         225 :    do iat = 1, natom
    1185   [ +  +  +  +  :     1811000 :      full_eigvec(:,:,iat,:,:) = full_eigvec(:,:,iat,:,:) / sqrt(phdos%atom_mass(iat))
             +  +  +  + ]
    1186                 :             :    end do
    1187                 :             : 
    1188                 :          76 :    call cwtime_report(" tetra accumulate", cpu, wall, gflops)
    1189                 :             : 
    1190   [ +  -  -  + ]:          76 :    if (my_rank == master .and. len_trim(prefix) > 0) then
    1191         [ #  # ]:           0 :      NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHIBZ.nc"), xmpi_comm_self), "Creating PHIBZ")
    1192         [ #  # ]:           0 :      NCF_CHECK(crystal%ncwrite(ncid))
    1193                 :           0 :      call phonons_ncwrite(ncid, natom, phdos%nqibz, qibz, wtq_ibz, full_phfrq, full_eigvec, full_phangmom)
    1194         [ #  # ]:           0 :      NCF_CHECK(nf90_close(ncid))
    1195                 :             :    end if
    1196                 :             : 
    1197                 :             :    ! Immediately free this - it contains displ and not eigvec at this stage
    1198         [ -  + ]:          76 :    ABI_FREE(full_eigvec)
    1199         [ -  + ]:          76 :    ABI_FREE(full_phfrq)
    1200         [ -  + ]:          76 :    ABI_FREE(full_veloc)
    1201         [ -  + ]:          76 :    ABI_FREE(full_phangmom)
    1202         [ -  + ]:          76 :    ABI_FREE(tmp_phfrq)
    1203                 :         228 :    call htetra_q%free()
    1204                 :             :  else
    1205                 :         101 :    ABI_WARNING('The netcdf PHIBZ file is only output for tetrahedron integration and DOS calculations')
    1206                 :             :  end if ! tetrahedra
    1207                 :             : 
    1208                 :             :  ! Test if the initial mesh was large enough
    1209                 :         177 :  call xmpi_sum(count_wminmax, comm, ierr)
    1210                 :         354 :  call xmpi_min(wminmax(1), rtmp, comm, ierr); wminmax(1) = rtmp
    1211                 :         354 :  call xmpi_max(wminmax(2), rtmp, comm, ierr); wminmax(2) = rtmp
    1212                 :             : 
    1213                 :         177 :  call xmpi_sum(phdos%phdos, comm, ierr)
    1214                 :         177 :  call xmpi_sum(phdos%phdos_dmm, comm, ierr)
    1215                 :         177 :  call xmpi_sum(phdos%msqd_dos_atom, comm, ierr)
    1216                 :         177 :  call xmpi_sum(phdos%pjdos, comm, ierr)
    1217         [ +  + ]:         177 :  if (prtdos == 2) then
    1218                 :             :    ! Reduce integrals if tetra, gauss will compute idos with simpson.
    1219                 :          76 :    call xmpi_sum(phdos%phdos_int, comm, ierr)
    1220                 :          76 :    call xmpi_sum(phdos%pjdos_int, comm, ierr)
    1221                 :             :  end if
    1222                 :             : 
    1223                 :             :  ! for dmm phdos need to normalize by q point integration element
    1224   [ +  +  +  + ]:     1401570 :  phdos%phdos_dmm = phdos%phdos_dmm * two_pi**3 / crystal%ucvol
    1225                 :             : 
    1226                 :             :  ! ===============================
    1227                 :             :  ! === Compute Integrated PDOS ===
    1228                 :             :  ! ===============================
    1229   [ -  +  +  -  :      877560 :  ABI_CALLOC(phdos%pjdos_rc_type, (nomega, 3, crystal%ntypat))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  -  +  +  
             +  +  +  +  
                      + ]
    1230   [ -  +  +  -  :      292910 :  ABI_CALLOC(phdos%pjdos_type, (nomega, crystal%ntypat))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  -  +  +  
                +  +  + ]
    1231   [ -  +  +  -  :      292733 :  ABI_CALLOC(phdos%pjdos_type_int, (nomega, crystal%ntypat))
          -  +  +  -  -  
          +  -  +  -  +  
             +  +  +  + ]
    1232                 :             : 
    1233         [ +  + ]:         555 :  do iat=1,natom
    1234                 :         378 :    itype = crystal%typat(iat)
    1235         [ +  + ]:      465694 :    do io=1,phdos%nomega
    1236         [ +  + ]:     1861264 :      phdos%pjdos_rc_type(io,:,itype) = phdos%pjdos_rc_type(io,:,itype) + phdos%pjdos(io,:,iat)
    1237         [ +  + ]:     1861642 :      phdos%pjdos_type(io,itype) = phdos%pjdos_type(io,itype) + sum(phdos%pjdos(io,:,iat))
    1238                 :             :    end do
    1239         [ +  + ]:         555 :    if (prtdos == 2) then
    1240         [ +  + ]:      199348 :      do io=1,phdos%nomega
    1241         [ +  + ]:      796945 :        phdos%pjdos_type_int(io,itype) = phdos%pjdos_type_int(io,itype) + sum(phdos%pjdos_int(io,:,iat))
    1242                 :             :      end do
    1243                 :             :    end if
    1244                 :             :  end do
    1245                 :             : 
    1246                 :             :  ! Evaluate IDOS using simple simpson integration
    1247                 :             :  ! In principle one could use derf.F90, just to be consistent ...
    1248         [ +  + ]:         177 :  if (prtdos == 1) then
    1249                 :         101 :    call simpson_int(phdos%nomega,phdos%omega_step, phdos%phdos, phdos%phdos_int)
    1250         [ +  + ]:         330 :    do iat=1,natom
    1251         [ +  + ]:        1017 :      do idir=1,3
    1252                 :         916 :        call simpson_int(phdos%nomega, phdos%omega_step, phdos%pjdos(:,idir,iat), phdos%pjdos_int(:,idir,iat))
    1253                 :             :      end do
    1254                 :             :    end do
    1255         [ +  + ]:         224 :    do itype=1,crystal%ntypat
    1256                 :         224 :      call simpson_int(phdos%nomega, phdos%omega_step, phdos%pjdos_type(:,itype), phdos%pjdos_type_int(:,itype))
    1257                 :             :    end do
    1258                 :             :  end if
    1259                 :             : 
    1260         [ -  + ]:         177 :  ABI_FREE(qibz)
    1261         [ -  + ]:         177 :  ABI_FREE(wtq_ibz)
    1262                 :             : 
    1263                 :         177 :  call cwtime_report(" phdos_init", cpu_all, wall_all, gflops_all)
    1264                 :             :  DBG_EXIT("COLL")
    1265                 :             : 
    1266   [ -  +  -  +  :         531 : end subroutine phdos_init
          -  +  -  +  -  
          -  -  -  -  +  
          -  -  -  -  -  
          +  -  +  -  +  
             -  +  -  + ]
    1267                 :             : !!***
    1268                 :             : 
    1269                 :             : !----------------------------------------------------------------------
    1270                 :             : 
    1271                 :             : !!****f* m_phonons/zacharias_supercell_make
    1272                 :             : !! NAME
    1273                 :             : !! zacharias_supercell_make
    1274                 :             : !!
    1275                 :             : !! FUNCTION
    1276                 :             : !!  Construct an optimally thermalized supercell following Zacharias and Giustino
    1277                 :             : !!  See: PRB 94 075125 (2016) [[cite:Zacharias2016]]
    1278                 :             : !!
    1279                 :             : !! INPUTS
    1280                 :             : !!
    1281                 :             : !! OUTPUT
    1282                 :             : !!
    1283                 :             : !! SOURCE
    1284                 :             : 
    1285   [ +  +  -  +  :          21 : subroutine zacharias_supercell_make(Crystal, Ifc, ntemper, rlatt, tempermin, temperinc, thm_scells)
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  +  
                      - ]
    1286                 :             : 
    1287                 :             : !Arguments ------------------------------------
    1288                 :             : !scalars
    1289                 :             :  integer, intent(in) :: ntemper
    1290                 :             :  integer, intent(in) :: rlatt(3,3)
    1291                 :             :  real(dp), intent(in) :: tempermin, temperinc
    1292                 :             :  type(crystal_t),intent(in) :: Crystal
    1293                 :             :  type(ifc_type),intent(in) :: Ifc
    1294                 :             :  type(supercell_type), intent(out) :: thm_scells(ntemper)
    1295                 :             : 
    1296                 :             : !Local variables-------------------------------
    1297                 :             : !scalars
    1298                 :             :  integer :: iq, nqibz, nqbz, qptopt1, imode, itemper, ierr, jmode
    1299                 :             :  real(dp) :: temperature_K, temperature, modesign, sigma, freeze_displ
    1300                 :             : !arrays
    1301                 :           1 :  integer, allocatable :: modeindex(:)
    1302                 :           1 :  real(dp), allocatable :: qshft(:,:) ! dummy with 2 dimensions for call to kpts_ibz_from_kptrlatt
    1303                 :           1 :  real(dp), allocatable :: qbz(:,:), qibz(:,:), wtq_ibz(:)
    1304                 :           1 :  real(dp), allocatable :: phfrq_allq(:), phdispl_allq(:,:,:,:,:)
    1305                 :           1 :  real(dp), allocatable :: phfrq(:), phdispl(:,:,:,:),pheigvec(:,:,:,:)
    1306                 :           1 :  real(dp), allocatable :: phdispl1(:,:,:)
    1307                 :             :  character (len=500) :: msg
    1308                 :             : ! *************************************************************************
    1309                 :             : 
    1310                 :             :  ! check inputs
    1311                 :             :  ! TODO: add check that all rlatt are the same on input
    1312                 :             : 
    1313                 :             :  if (rlatt(1,2)/=0 .or.  rlatt(1,3)/=0 .or.  rlatt(2,3)/=0 .or. &
    1314   [ +  -  +  -  :           1 :      rlatt(2,1)/=0 .or.  rlatt(3,1)/=0 .or.  rlatt(3,2)/=0) then
          +  -  +  -  +  
                -  -  + ]
    1315                 :           0 :    write (msg, '(4a, 9I6, a)') ' for the moment I have not implemented ', &
    1316                 :           0 :      ' non diagonal supercells.',ch10,' rlatt for temp 1 = ', rlatt, ' Returning '
    1317                 :           0 :    ABI_WARNING(msg)
    1318                 :           0 :    return
    1319                 :             :  end if
    1320                 :             : 
    1321                 :             :  ! build qpoint grid used for the Fourier interpolation (use no syms for the moment!)
    1322                 :           1 :  qptopt1 = 3
    1323                 :             : 
    1324                 :             :  ! for the moment do not allow shifted q grids. We are interpolating anyway, so it will always work
    1325         [ -  + ]:           1 :  ABI_MALLOC(qshft,(3,1))
    1326         [ +  + ]:           4 :  qshft(:,1)=zero
    1327                 :             : 
    1328                 :             :  ! This call will set nqibz, IBZ and BZ arrays
    1329                 :             :  call kpts_ibz_from_kptrlatt(crystal, rlatt, qptopt1, 1, qshft, &
    1330                 :           1 :     nqibz, qibz, wtq_ibz, nqbz, qbz) ! new_kptrlatt, new_shiftk)  ! Optional
    1331         [ -  + ]:           1 :  ABI_FREE(qshft)
    1332                 :             : 
    1333                 :             :  ! allocate arrays with all of the q, omega, and displacement vectors
    1334   [ +  -  -  +  :           3 :  ABI_MALLOC_OR_DIE(phfrq_allq, (3*Crystal%natom*nqibz), ierr)
          +  -  +  -  +  
          -  +  -  -  +  
                   -  + ]
    1335   [ -  +  +  -  :           5 :  ABI_MALLOC_OR_DIE(phdispl_allq, (2, 3, Crystal%natom, 3*Crystal%natom, nqibz), ierr)
          +  -  -  +  +  
          -  -  +  +  -  
          +  -  +  -  +  
             -  -  +  -  
                      + ]
    1336                 :             : 
    1337   [ -  +  +  -  :           3 :  ABI_MALLOC(phfrq, (3*Crystal%natom))
          +  -  +  -  -  
                +  -  + ]
    1338   [ -  +  +  -  :           4 :  ABI_MALLOC(phdispl, (2, 3, Crystal%natom, 3*Crystal%natom))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
    1339   [ -  +  +  -  :           3 :  ABI_MALLOC(pheigvec, (2, 3, Crystal%natom, 3*Crystal%natom))
          -  +  +  -  -  
                +  -  + ]
    1340                 :             : 
    1341                 :             :  ! loop over q to get all frequencies and displacement vectors
    1342   [ -  +  +  -  :           3 :  ABI_MALLOC(modeindex, (nqibz*3*Crystal%natom))
          +  -  +  -  -  
                +  -  + ]
    1343                 :           1 :  imode = 0
    1344         [ +  + ]:           9 :  do iq = 1, nqibz
    1345                 :             :    ! Fourier interpolation.
    1346                 :           8 :    call ifc%fourq(Crystal, qibz(:,iq), phfrq, phdispl, out_eigvec=pheigvec)
    1347         [ +  + ]:         152 :    phfrq_allq((iq-1)*3*Crystal%natom+1 : iq*3*Crystal%natom) = phfrq
    1348   [ +  +  +  +  :        8792 :    phdispl_allq(1:2, 1:3, 1:Crystal%natom, 1:3*Crystal%natom, iq) = phdispl
             +  +  +  + ]
    1349         [ +  + ]:         153 :    do jmode = 1, 3*Crystal%natom
    1350                 :         144 :      imode = imode + 1
    1351                 :         152 :      modeindex(imode) = imode
    1352                 :             :    end do
    1353                 :             :  end do
    1354         [ -  + ]:           1 :  ABI_FREE(phfrq)
    1355         [ -  + ]:           1 :  ABI_FREE(pheigvec)
    1356         [ -  + ]:           1 :  ABI_FREE(phdispl)
    1357                 :             : 
    1358                 :             :  ! sort modes in whole list: get indirect indexing for qbz and displ
    1359                 :           1 :  call sort_dp(nqibz*3*Crystal%natom, phfrq_allq, modeindex, tol10)
    1360                 :             :  ! NB: phfrq is sorted now, but displ and qibz will have to be indexed indirectly with modeindex
    1361                 :             : 
    1362                 :             :  ! only diagonal supercell case for the moment
    1363         [ +  + ]:          11 :  do itemper = 1, ntemper
    1364                 :          11 :    call thm_scells(itemper)%init(Crystal%natom, rlatt, Crystal%rprimd, Crystal%typat, Crystal%xcart, Crystal%znucl)
    1365                 :             :  end do
    1366                 :             : 
    1367                 :             :  ! precalculate phase factors???
    1368   [ -  +  +  -  :           3 :  ABI_MALLOC(phdispl1, (2, 3, Crystal%natom))
          +  -  +  -  -  
                +  -  + ]
    1369                 :             :  ! for all modes at all q in whole list, sorted
    1370                 :         145 :  modesign=one
    1371                 :             : 
    1372         [ +  + ]:         145 :  do imode = 1, 3*Crystal%natom*nqibz
    1373                 :             :    ! skip modes with too low or negative frequency -> Bose factor explodes (eg acoustic at Gamma)
    1374         [ +  + ]:         144 :    if (phfrq_allq(imode) < tol10) cycle
    1375                 :             : 
    1376         [ +  + ]:         141 :    iq = ceiling(dble(modeindex(imode))/dble(3*Crystal%natom))
    1377                 :         141 :    jmode = modeindex(imode) - (iq-1)*3*Crystal%natom
    1378   [ -  +  +  +  :        8742 :    phdispl1 = phdispl_allq(:,:,:,jmode,iq)
             +  +  +  + ]
    1379                 :             : 
    1380                 :             :    ! loop over temperatures
    1381         [ +  + ]:        1551 :    do itemper = 1, ntemper
    1382                 :        1410 :      temperature_K = tempermin + dble(itemper-1)*temperinc  ! this is in Kelvin
    1383                 :        1410 :      temperature = temperature_K / Ha_K
    1384                 :             : 
    1385                 :             :      ! trick supercell object into using present q point
    1386         [ +  + ]:        5640 :      thm_scells(itemper)%qphon(:) = qibz(:,iq)
    1387                 :             : 
    1388                 :             :      ! find thermal displacement amplitude eq 4 of Zacharias
    1389                 :             :      ! combined with l_nu,q expression in paragraph before
    1390                 :        1410 :      sigma = sqrt((bose_einstein(phfrq_allq(imode), temperature) + half)/phfrq_allq(imode))
    1391                 :             : 
    1392                 :             :      ! add displacement for this mode to supercell positions eq 5 of Zacharias
    1393                 :        1410 :      freeze_displ = modesign * sigma
    1394                 :        1551 :      call thm_scells(itemper)%freeze_displ(phdispl1(:,:,:), freeze_displ)
    1395                 :             :    end do !itemper
    1396                 :             : 
    1397                 :             :    ! this is the prescription: flip sign for each successive mode in full
    1398                 :             :    ! spectrum, to cancel electron phonon coupling to 1st order
    1399                 :             :    ! (hopefully 3rd order as well)
    1400                 :         145 :    modesign = -modesign
    1401                 :             :  end do !imode
    1402                 :             : 
    1403         [ -  + ]:           1 :  ABI_FREE(modeindex)
    1404         [ -  + ]:           1 :  ABI_FREE(phfrq_allq)
    1405         [ -  + ]:           1 :  ABI_FREE(phdispl_allq)
    1406         [ -  + ]:           1 :  ABI_FREE(phdispl1)
    1407         [ -  + ]:           1 :  ABI_FREE(qibz)
    1408         [ -  + ]:           1 :  ABI_FREE(qbz)
    1409         [ -  + ]:           1 :  ABI_FREE(wtq_ibz)
    1410                 :             : 
    1411   [ -  +  -  +  :           1 : end subroutine zacharias_supercell_make
                   -  + ]
    1412                 :             : !!***
    1413                 :             : 
    1414                 :             : !----------------------------------------------------------------------
    1415                 :             : 
    1416                 :             : !!****f* m_phonons/thermal_supercell_make
    1417                 :             : !! NAME
    1418                 :             : !! thermal_supercell_make
    1419                 :             : !!
    1420                 :             : !! FUNCTION
    1421                 :             : !!  Construct a random thermalized supercell configuration, as in TDEP
    1422                 :             : !!  main function is for training set generation in multibinit
    1423                 :             : !!
    1424                 :             : !! INPUTS
    1425                 :             : !!   Crystal = crystal object with rprim etc...
    1426                 :             : !!   Ifc = interatomic force constants object from anaddb
    1427                 :             : !!   option = option to deal with negative frequency -> Bose factor explodes (eg acoustic at Gamma)
    1428                 :             : !!      several philosophies to be implemented for the unstable modes:
    1429                 :             : !!      option == 1 =>  ignore
    1430                 :             : !!      option == 2 =>  populate them according to a default amplitude
    1431                 :             : !!      option == 3 =>  populate according to their modulus squared
    1432                 :             : !!      option == 4 =>  USER defined value(s), require namplitude and amplitude
    1433                 :             : !!   nconfig = number of requested configurations
    1434                 :             : !!   rlatt = matrix of conversion for supercell (3 0 0   0 3 0   0 0 3 for example)
    1435                 :             : !!   temperature_K =  temperature in Kelvin
    1436                 :             : !!   nqpt = number of q-point
    1437                 :             : !!   namplitude = number of amplitude provided by the user
    1438                 :             : !!   amplitudes(namplitude) = list of the amplitudes of the unstable phonons
    1439                 :             : !!                            amplitudes(1:3,iamplitude) = qpt
    1440                 :             : !!                            amplitudes(4,iamplitude)   = mode
    1441                 :             : !!                            amplitudes(5,iamplitude)   = amplitude
    1442                 :             : !!
    1443                 :             : !! OUTPUT
    1444                 :             : !!   thm_scells = array of configurations with thermalized supercells
    1445                 :             : !!
    1446                 :             : !! SOURCE
    1447                 :             : 
    1448   [ #  #  #  #  :           0 : subroutine thermal_supercell_make(amplitudes,Crystal, Ifc,namplitude, nconfig,option,&
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    1449                 :           0 :                                   rlatt, temperature_K, thm_scells)
    1450                 :             : 
    1451                 :             : !Arguments ------------------------------------
    1452                 :             : !scalars
    1453                 :             :  integer, intent(in) :: option,nconfig
    1454                 :             :  integer, intent(in) :: rlatt(3,3)
    1455                 :             :  real(dp), intent(in) :: temperature_K
    1456                 :             :  type(crystal_t),intent(in) :: Crystal
    1457                 :             :  type(ifc_type),intent(in) :: Ifc
    1458                 :             :  type(supercell_type), intent(out) :: thm_scells(nconfig)
    1459                 :             :  integer,intent(in) :: namplitude
    1460                 :             : !Local variables-------------------------------
    1461                 :             : !scalars
    1462                 :             :  integer :: iq, nqibz, nqbz, qptopt1, iampl ,imode, ierr, iconfig
    1463                 :             :  real(dp) :: temperature, sigma, freeze_displ
    1464                 :             :  real(dp) :: rand !, rand1, rand2
    1465                 :             :  real(dp),intent(in):: amplitudes(5,namplitude)
    1466                 :             :  !arrays
    1467                 :           0 :  real(dp), allocatable :: qshft(:,:) ! dummy with 2 dimensions for call to kpts_ibz_from_kptrlatt
    1468                 :           0 :  real(dp), allocatable :: qbz(:,:), qibz(:,:), wtqibz(:)
    1469                 :           0 :  real(dp), allocatable :: phfrq_allq(:,:), phdispl_allq(:,:,:,:,:)
    1470                 :           0 :  real(dp), allocatable :: phfrq(:), phdispl(:,:,:,:),pheigvec(:,:,:,:)
    1471                 :           0 :  real(dp), allocatable :: phdispl1(:,:,:)
    1472                 :             :  character (len=500) :: msg
    1473                 :             : ! *************************************************************************
    1474                 :             : 
    1475                 :             : ! check inputs
    1476                 :             : ! TODO: add check that all rlatt are the same on input
    1477                 :             :  if (rlatt(1,2)/=0 .or.  rlatt(1,3)/=0 .or.  rlatt(2,3)/=0 .or. &
    1478   [ #  #  #  #  :           0 :      rlatt(2,1)/=0 .or.  rlatt(3,1)/=0 .or.  rlatt(3,2)/=0) then
          #  #  #  #  #  
                #  #  # ]
    1479                 :           0 :    write (msg, '(4a, 9I6, a)') ' for the moment I have not implemented ', &
    1480                 :           0 :      ' non diagonal supercells.',ch10,' rlatt for temp 1 = ', rlatt, ' Returning '
    1481                 :           0 :    ABI_WARNING(msg)
    1482                 :           0 :    return
    1483                 :             :  end if
    1484                 :             : 
    1485                 :           0 :  temperature = temperature_K /  Ha_K
    1486                 :             : 
    1487                 :             :  ! build qpoint grid used for the Fourier interpolation.
    1488                 :             :  !(use no syms for the moment!)
    1489                 :           0 :  qptopt1 = 3
    1490                 :             : 
    1491                 :             :  ! for the moment do not allow shifted q grids.
    1492                 :             :  ! We are interpolating anyway, so it will always work
    1493         [ #  # ]:           0 :  ABI_MALLOC(qshft,(3,1))
    1494         [ #  # ]:           0 :  qshft(:,1)=zero
    1495                 :             : 
    1496                 :             :  ! This call will set nqibz, IBZ and BZ arrays
    1497                 :             :  call kpts_ibz_from_kptrlatt(crystal, rlatt, qptopt1, 1, qshft, &
    1498                 :           0 :                               nqibz, qibz, wtqibz, nqbz, qbz) ! new_kptrlatt, new_shiftk)  ! Optional
    1499         [ #  # ]:           0 :  ABI_FREE(qshft)
    1500                 :             : 
    1501                 :             :  ! allocate arrays wzith all of the q, omega, and displacement vectors
    1502   [ #  #  #  #  :           0 :  ABI_MALLOC_OR_DIE(phfrq_allq, (3*Crystal%natom, nqibz), ierr)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    1503   [ #  #  #  #  :           0 :  ABI_MALLOC_OR_DIE(phdispl_allq, (2, 3, Crystal%natom, 3*Crystal%natom, nqibz), ierr)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1504                 :             : 
    1505   [ #  #  #  #  :           0 :  ABI_MALLOC(phfrq, (3*Crystal%natom))
          #  #  #  #  #  
                #  #  # ]
    1506   [ #  #  #  #  :           0 :  ABI_MALLOC(phdispl, (2, 3, Crystal%natom, 3*Crystal%natom))
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1507   [ #  #  #  #  :           0 :  ABI_MALLOC(pheigvec, (2, 3, Crystal%natom, 3*Crystal%natom))
          #  #  #  #  #  
                #  #  # ]
    1508                 :             : 
    1509                 :             :  ! loop over q to get all frequencies and displacement vectors
    1510                 :           0 :  imode = 0
    1511         [ #  # ]:           0 :  do iq = 1, nqibz
    1512                 :             :    ! Fourier interpolation.
    1513                 :           0 :    call ifc%fourq(Crystal, qibz(:,iq), phfrq, phdispl, out_eigvec=pheigvec)
    1514         [ #  # ]:           0 :    phfrq_allq(1:3*Crystal%natom, iq) = phfrq
    1515   [ #  #  #  #  :           0 :    phdispl_allq(1:2, 1:3, 1:Crystal%natom, 1:3*Crystal%natom, iq) = phdispl
             #  #  #  # ]
    1516                 :             :  end do
    1517         [ #  # ]:           0 :  ABI_FREE(phfrq)
    1518         [ #  # ]:           0 :  ABI_FREE(pheigvec)
    1519         [ #  # ]:           0 :  ABI_FREE(phdispl)
    1520                 :             : 
    1521                 :             :  ! only diagonal supercell case for the moment
    1522         [ #  # ]:           0 :  do iconfig = 1, nconfig
    1523                 :           0 :    call thm_scells(iconfig)%init(Crystal%natom, rlatt, Crystal%rprimd, Crystal%typat, Crystal%xcart, Crystal%znucl)
    1524                 :             :  end do
    1525                 :             : 
    1526                 :             :  ! precalculate phase factors???
    1527                 :             : 
    1528   [ #  #  #  #  :           0 :  ABI_MALLOC(phdispl1, (2, 3, Crystal%natom))
          #  #  #  #  #  
                #  #  # ]
    1529                 :             : 
    1530                 :             :  ! for all modes at all q in whole list, sorted
    1531         [ #  # ]:           0 :  do iq = 1, nqibz
    1532         [ #  # ]:           0 :    do imode = 1, 3*Crystal%natom
    1533                 :             : 
    1534                 :             :      ! skip modes with too low or negative frequency -> Bose factor explodes (eg acoustic at Gamma)
    1535                 :             :      ! TODO: check the convergence wrt the tolerance
    1536                 :             :      ! several philosophies to be implemented for the unstable modes:
    1537                 :             :      ! 1) ignore
    1538                 :             :      ! 2) populate them according to a default amplitude
    1539                 :             :      ! 3) populate according to their modulus squared
    1540         [ #  # ]:           0 :      if (abs(phfrq_allq(imode, iq))<tol6) cycle
    1541                 :             : 
    1542   [ #  #  #  #  :           0 :      phdispl1 = phdispl_allq(:,:,:,imode,iq)
             #  #  #  # ]
    1543                 :             : 
    1544                 :             :      ! loop over configurations
    1545         [ #  # ]:           0 :      do iconfig = 1, nconfig
    1546                 :             : 
    1547                 :             :        ! trick supercell object into using present q point
    1548         [ #  # ]:           0 :        thm_scells(iconfig)%qphon(:) = qibz(:,iq)
    1549                 :             : 
    1550                 :             :        ! find thermal displacement amplitude eq 4 of Zacharias
    1551                 :             :        !   combined with l_nu,q expression in paragraph before
    1552         [ #  # ]:           0 :        if (phfrq_allq(imode, iq) > tol6) then
    1553                 :           0 :          sigma = sqrt( (bose_einstein(phfrq_allq(imode,iq), temperature) + half)/phfrq_allq(imode,iq))
    1554                 :             :        else
    1555                 :             :          !Treat negative frequencies
    1556                 :           0 :          select case (option)
    1557                 :             :          case (1)
    1558                 :             :            !Do not populate
    1559                 :           0 :            sigma = 0._dp
    1560                 :             :          case (2)
    1561                 :             :            !Default amplitude for all the frequencies
    1562                 :           0 :            sigma = 100._dp
    1563                 :             :          case (3)
    1564                 :             :            !Absolute value of the frequencies
    1565                 :           0 :            sigma=sqrt((bose_einstein(abs(phfrq_allq(imode,iq)),temperature)+half) / abs(phfrq_allq(imode,iq)))
    1566                 :             :          case (4)
    1567                 :             :            sigma = 0._dp
    1568                 :             :            !Search if the amplitude of this unstable phonon is in the input argument amplitudes
    1569         [ #  # ]:           0 :            do iampl=1,namplitude
    1570                 :             :              if(abs(thm_scells(iconfig)%qphon(1) - amplitudes(1,iampl)) < tol8.and.&
    1571                 :             :                 abs(thm_scells(iconfig)%qphon(2) - amplitudes(2,iampl)) < tol8.and.&
    1572   [ #  #  #  #  :           0 :                 abs(thm_scells(iconfig)%qphon(3) - amplitudes(3,iampl)) < tol8.and.&
             #  #  #  # ]
    1573                 :           0 :                 abs(imode - amplitudes(4,iampl)) < tol8) then
    1574                 :           0 :                sigma = amplitudes(5,iampl)
    1575                 :             :              end if
    1576                 :             :            end do
    1577                 :             :            !If not, the amplitude is zero
    1578   [ #  #  #  #  :           0 :            if(abs(sigma) < tol8)then
                #  #  # ]
    1579                 :           0 :              write (msg, '(a,I0,a,3es12.5,2a,I0)') ' The amplitude of the unstable mode ',&
    1580         [ #  # ]:           0 :                 int(imode),' of the qpt ',thm_scells(iconfig)%qphon(:), ch10,&
    1581                 :           0 :                 'is set to zero for the configuration ',iconfig
    1582                 :           0 :              ABI_WARNING(msg)
    1583                 :             :            end if
    1584                 :             :          end select
    1585                 :             :        end if
    1586                 :             : 
    1587                 :             :        ! add displacement for this mode to supercell positions eq 5 of Zacharias
    1588                 :           0 :        call RANDOM_NUMBER(rand)
    1589                 :           0 :        rand = two * rand - one
    1590                 :             : 
    1591                 :             :        ! from TDEP documentation for gaussian distribution of displacements
    1592                 :             :        !call RANDOM_NUMBER(rand1)
    1593                 :             :        !call RANDOM_NUMBER(rand2)
    1594                 :             :        ! rand = sqrt(-two*rand1) * sin(twopi*rand2)
    1595                 :             : 
    1596                 :             :        ! if (rand > half) then
    1597                 :             :        !   rand = one
    1598                 :             :        ! else
    1599                 :             :        !   rand = -one
    1600                 :             :        ! end if
    1601                 :             : 
    1602                 :           0 :        freeze_displ =  rand * sigma
    1603                 :             : 
    1604                 :           0 :        call thm_scells(iconfig)%freeze_displ(phdispl1(:,:,:), freeze_displ)
    1605                 :             :      end do !iconfig
    1606                 :             :    end do !imode
    1607                 :             :  end do !iq
    1608                 :             : 
    1609         [ #  # ]:           0 :  ABI_FREE(phfrq_allq)
    1610         [ #  # ]:           0 :  ABI_FREE(phdispl_allq)
    1611         [ #  # ]:           0 :  ABI_FREE(phdispl1)
    1612         [ #  # ]:           0 :  ABI_FREE(qibz)
    1613         [ #  # ]:           0 :  ABI_FREE(qbz)
    1614         [ #  # ]:           0 :  ABI_FREE(wtqibz)
    1615                 :             : 
    1616   [ #  #  #  #  :           0 : end subroutine thermal_supercell_make
                   #  # ]
    1617                 :             : !!***
    1618                 :             : 
    1619                 :             : !----------------------------------------------------------------------
    1620                 :             : 
    1621                 :             : !!****f* m_phonons/thermal_supercell_free
    1622                 :             : !! NAME
    1623                 :             : !! thermal_supercell_free
    1624                 :             : !!
    1625                 :             : !! FUNCTION
    1626                 :             : !!  deallocate thermal array of supercells
    1627                 :             : !!
    1628                 :             : !! SOURCE
    1629                 :             : 
    1630                 :           1 : subroutine thermal_supercell_free(nscells, thm_scells)
    1631                 :             : 
    1632                 :             : !Arguments ------------------------------------
    1633                 :             : !scalars
    1634                 :             :  integer, intent(in) :: nscells
    1635                 :             :  type(supercell_type), allocatable, intent(inout) :: thm_scells(:)
    1636                 :             : 
    1637                 :             : ! local
    1638                 :             :  integer :: icell
    1639                 :             : 
    1640         [ +  - ]:           1 :  if (allocated(thm_scells)) then
    1641         [ +  + ]:          11 :    do icell = 1, nscells
    1642                 :          11 :      call thm_scells(icell)%free()
    1643                 :             :    end do
    1644                 :             :  end if
    1645                 :             : 
    1646                 :           1 : end subroutine thermal_supercell_free
    1647                 :             : !!***
    1648                 :             : 
    1649                 :             : !----------------------------------------------------------------------
    1650                 :             : 
    1651                 :             : !!****f* m_phonons/zacharias_supercell_print
    1652                 :             : !! NAME
    1653                 :             : !! zacharias_supercell_print
    1654                 :             : !!
    1655                 :             : !! FUNCTION
    1656                 :             : !!  print files with thermal array of supercells
    1657                 :             : !!
    1658                 :             : !! INPUTS
    1659                 :             : !!
    1660                 :             : !! OUTPUT
    1661                 :             : !!
    1662                 :             : !! SOURCE
    1663                 :             : 
    1664                 :           1 : subroutine zacharias_supercell_print(fname, ntemper, tempermin, temperinc, thm_scells)
    1665                 :             : 
    1666                 :             : !Arguments ------------------------------------
    1667                 :             : !scalars
    1668                 :             :  integer, intent(in) :: ntemper
    1669                 :             :  real(dp), intent(in) :: tempermin
    1670                 :             :  real(dp), intent(in) :: temperinc
    1671                 :             :  type(supercell_type), intent(in) :: thm_scells(ntemper)
    1672                 :             :  character(len=fnlen), intent(in) :: fname
    1673                 :             : 
    1674                 :             : ! local
    1675                 :             :  integer :: itemp
    1676                 :             :  character(len=80) :: title1, title2
    1677                 :             :  character(len=fnlen) :: filename
    1678                 :             :  real(dp) :: temper
    1679                 :             :  character(len=10) :: temper_str
    1680                 :             : 
    1681         [ +  + ]:          11 :  do itemp = 1, ntemper
    1682                 :          10 :    temper = dble(itemp-1)*temperinc+tempermin
    1683                 :          10 :    write(temper_str,'(I8)') int(temper)
    1684         [ +  - ]:          10 :    write(filename, '(3a)') trim(fname), "_T_", trim(adjustl(temper_str))
    1685                 :          10 :    write(title1, '(3a)') "#  Zacharias thermalized supercell at temperature T= ", trim(temper_str), " Kelvin"
    1686                 :          10 :    title2 = "#  generated with alternating thermal displacements of all phonons"
    1687                 :          11 :    call thm_scells(itemp)%print_abinit(filename, title1, title2)
    1688                 :             :  end do
    1689                 :             : 
    1690                 :           1 : end subroutine zacharias_supercell_print
    1691                 :             : !!***
    1692                 :             : 
    1693                 :             : !!****f* m_phonons/thermal_supercell_print
    1694                 :             : !! NAME
    1695                 :             : !! thermal_supercell_print
    1696                 :             : !!
    1697                 :             : !! FUNCTION
    1698                 :             : !!  print files with thermalized array of random supercell configurations
    1699                 :             : !!
    1700                 :             : !! INPUTS
    1701                 :             : !!
    1702                 :             : !! OUTPUT
    1703                 :             : !!
    1704                 :             : !! SOURCE
    1705                 :             : 
    1706                 :           0 : subroutine thermal_supercell_print(fname, nconfig, temperature_K, thm_scells)
    1707                 :             : 
    1708                 :             : !Arguments ------------------------------------
    1709                 :             : !scalars
    1710                 :             :  integer, intent(in) :: nconfig
    1711                 :             :  type(supercell_type), intent(in) :: thm_scells(nconfig)
    1712                 :             :  character(len=fnlen), intent(in) :: fname
    1713                 :             :  real(dp), intent(in) :: temperature_K
    1714                 :             : 
    1715                 :             : ! local
    1716                 :             :  integer :: iconfig,itemp
    1717                 :             :  character(len=80) :: title1, title2
    1718                 :             :  character(len=fnlen) :: filename
    1719                 :             :  character(len=10) :: config_str
    1720                 :             : 
    1721         [ #  # ]:           0 :  do iconfig = 1, nconfig
    1722                 :           0 :    write(config_str,'(I8)') iconfig
    1723         [ #  # ]:           0 :    write(filename, '(3a)') trim(fname), "_cf_", trim(adjustl(config_str))
    1724                 :           0 :    write(title1, '(a,I6,a)') "#  thermalized supercell at temperature T= ", temperature_K, " Kelvin"
    1725                 :           0 :    title2 = "#  generated with random thermal displacements of all phonons"
    1726                 :           0 :    call thm_scells(itemp)%print_abinit(filename, title1, title2)
    1727                 :             :  end do
    1728                 :             : 
    1729                 :           0 : end subroutine thermal_supercell_print
    1730                 :             : !!***
    1731                 :             : 
    1732                 :             : !----------------------------------------------------------------------
    1733                 :             : 
    1734                 :             : !!****f* m_phonons/phdos_ncwrite
    1735                 :             : !! NAME
    1736                 :             : !! phdos_ncwrite
    1737                 :             : !!
    1738                 :             : !! FUNCTION
    1739                 :             : !!  Save the content of the object in a netcdf file.
    1740                 :             : !!
    1741                 :             : !! INPUTS
    1742                 :             : !!  ncid=NC file handle (open in the caller)
    1743                 :             : !!  phdos<phdos_t>=Container object
    1744                 :             : !!
    1745                 :             : !! OUTPUT
    1746                 :             : !!  Only writing
    1747                 :             : !!
    1748                 :             : !! NOTES
    1749                 :             : !!  Frequencies are in eV, DOS are in states/eV.
    1750                 :             : !!
    1751                 :             : !! SOURCE
    1752                 :             : 
    1753                 :          63 : subroutine phdos_ncwrite(phdos, ncid)
    1754                 :             : 
    1755                 :             : !Arguments ------------------------------------
    1756                 :             : !scalars
    1757                 :             :  class(phdos_t),intent(in) :: phdos
    1758                 :             :  integer,intent(in) :: ncid
    1759                 :             : 
    1760                 :             : !Local variables-------------------------------
    1761                 :             :  integer :: ncerr
    1762                 :             : ! *************************************************************************
    1763                 :             : 
    1764                 :             : ! Define dimensions
    1765         [ -  + ]:          63 :  NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
    1766                 :             : 
    1767                 :             :  ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_atoms", phdos%natom),&
    1768                 :             :    nctkdim_t("number_of_atom_species", phdos%ntypat), nctkdim_t("number_of_frequencies", phdos%nomega), &
    1769         [ +  + ]:         378 :    nctkdim_t("nqibz", phdos%nqibz), nctkdim_t("number_of_normal_vec_dmm", phdos%n_normal_vec_dmm)])
    1770         [ -  + ]:          63 :  NCF_CHECK(ncerr)
    1771                 :             : 
    1772                 :             : !scalars
    1773   [ +  +  -  +  :         126 :  NCF_CHECK(nctk_def_iscalars(ncid, ["prtdos"]))
                   -  - ]
    1774   [ +  +  -  +  :         126 :  NCF_CHECK(nctk_def_dpscalars(ncid, ["dossmear"]))
                   -  - ]
    1775                 :             : 
    1776                 :             : !arrays
    1777                 :             :  ncerr = nctk_def_arrays(ncid, [&
    1778                 :             :    nctkarr_t('wmesh', "dp", 'number_of_frequencies'),&
    1779                 :             :    nctkarr_t('phdos', "dp", 'number_of_frequencies'),&
    1780                 :             :    nctkarr_t('phdos_dmm', "dp", 'number_of_frequencies, number_of_normal_vec_dmm'),&
    1781                 :             :    nctkarr_t('normal_vec_dmm', "dp", 'three, number_of_normal_vec_dmm'),&
    1782                 :             :    nctkarr_t('pjdos', "dp", 'number_of_frequencies, three, number_of_atoms'),&
    1783                 :             :    nctkarr_t('pjdos_type', "dp", 'number_of_frequencies, number_of_atom_species'),&
    1784                 :             :    nctkarr_t('pjdos_rc_type', "dp", 'number_of_frequencies, three, number_of_atom_species'), &
    1785                 :             :    nctkarr_t('msqd_dos_atom', "dp", 'number_of_frequencies, three, three, number_of_atoms'), &
    1786                 :             :    nctkarr_t('qptrlatt', "int", 'three, three'), &
    1787                 :             :    nctkarr_t('shiftq', "dp", 'three') &
    1788         [ +  + ]:         693 :  ])
    1789         [ -  + ]:          63 :  NCF_CHECK(ncerr)
    1790                 :             : 
    1791                 :             :  ! Write variables. Note unit conversion.
    1792         [ -  + ]:          63 :  NCF_CHECK(nctk_set_datamode(ncid))
    1793         [ -  + ]:          63 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "prtdos"), phdos%prtdos))
    1794         [ -  + ]:          63 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'dossmear'), phdos%dossmear*Ha_eV))
    1795   [ +  -  +  +  :       85905 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'wmesh'), phdos%omega*Ha_eV))
          -  +  -  -  -  
                      - ]
    1796         [ -  + ]:          63 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'normal_vec_dmm'), phdos%normal_vec_dmm))
    1797   [ +  -  +  +  :       85905 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'phdos'), phdos%phdos/Ha_eV))
          -  +  -  -  -  
                      - ]
    1798   [ +  -  +  +  :      601398 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'phdos_dmm'), phdos%phdos_dmm/Ha_eV)) ! TODO: these should also be converted for the velocity
          +  +  -  +  -  
             -  -  -  -  
                      - ]
    1799   [ +  -  +  +  :      592900 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos'), phdos%pjdos/Ha_eV))
          +  +  +  +  -  
          +  -  -  -  -  
             -  -  -  - ]
    1800   [ +  -  +  +  :      122611 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos_type'), phdos%pjdos_type/Ha_eV))
          +  +  -  +  -  
             -  -  -  -  
                      - ]
    1801   [ +  -  +  +  :      367802 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'pjdos_rc_type'), phdos%pjdos_rc_type/Ha_eV))
          +  +  +  +  -  
          +  -  -  -  -  
             -  -  -  - ]
    1802   [ +  -  +  +  :     1778695 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'msqd_dos_atom'), phdos%msqd_dos_atom/Ha_eV))
          +  +  +  +  +  
          +  -  +  -  -  
          -  -  -  -  -  
                -  -  - ]
    1803         [ -  + ]:          63 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'qptrlatt'), phdos%qptrlatt))
    1804         [ -  + ]:          63 :  NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'shiftq'), phdos%shiftq))
    1805                 :             : 
    1806                 :          63 : end subroutine phdos_ncwrite
    1807                 :             : !!***
    1808                 :             : 
    1809                 :             : !----------------------------------------------------------------------
    1810                 :             : 
    1811                 :             : !!****f* m_phonons/mkphbs
    1812                 :             : !! NAME
    1813                 :             : !! mkphbs
    1814                 :             : !!
    1815                 :             : !! FUNCTION
    1816                 :             : !! Function to calculate the phonon band structure, from the IFC
    1817                 :             : !!
    1818                 :             : !! INPUTS
    1819                 :             : !! Ifc<ifc_type>=Interatomic force constants
    1820                 :             : !! crystal<type(crystal_t)> = Info on the crystalline structure.
    1821                 :             : !! inp= (derived datatype) contains all the input variables
    1822                 :             : !! ddb<type(ddb_type)>=Object storing the DDB results.
    1823                 :             : !! asrq0<asrq0_t>=Object for the treatment of the ASR based on the q=0 block found in the DDB file.
    1824                 :             : !! prefix=Prefix for output files.
    1825                 :             : !! dielt(3,3)=dielectric tensor
    1826                 :             : !! comm=MPI communicator
    1827                 :             : !!
    1828                 :             : !! OUTPUT
    1829                 :             : !!  Only writing.
    1830                 :             : !!
    1831                 :             : !! SOURCE
    1832                 :             : 
    1833                 :          65 : subroutine mkphbs(Ifc,Crystal,inp,ddb,asrq0,prefix,comm)
    1834                 :             : 
    1835                 :             : !Arguments -------------------------------
    1836                 :             : !scalars
    1837                 :             :  integer,intent(in) :: comm
    1838                 :             :  character(len=*),intent(in) :: prefix
    1839                 :             :  type(ifc_type),intent(in) :: Ifc
    1840                 :             :  type(crystal_t),intent(in) :: Crystal
    1841                 :             :  type(anaddb_dataset_type),target,intent(in) :: inp
    1842                 :             :  type(ddb_type),intent(in) :: ddb
    1843                 :             :  type(asrq0_t),intent(inout) :: asrq0
    1844                 :             : !Local variables -------------------------
    1845                 :             : !scalars
    1846                 :             :  integer,parameter :: master=0
    1847                 :             :  integer :: unt, iphl1,iblok,rftyp, ii,nfineqpath,nsym,natom,ncid,nprocs,my_rank
    1848                 :             :  integer :: natprj_bs,eivec,enunit,ifcflag,ptgroupma,spgroup
    1849                 :             :  real(dp) :: freeze_displ, cfact, omega, omega_min, gaussmaxarg, gaussfactor, gaussprefactor, xx, eta
    1850                 :             :  character(500) :: msg
    1851                 :             :  character(len=8) :: unitname
    1852                 :             : !arrays
    1853                 :             :  integer :: bravais(11),rfphon(4),rfelfd(4),rfstrs(4), units(2)
    1854                 :             :  integer :: nomega, imode, iomega
    1855                 :          65 :  integer,allocatable :: ndiv(:)
    1856                 :             :  real(dp) :: speedofsound(3),genafm(3)
    1857                 :             :  real(dp) :: qphnrm(3), qphon(3), qphon_padded(3,3),res(3)
    1858                 :         130 :  real(dp) :: d2cart(2,ddb%msize),real_qphon(3)
    1859                 :         130 :  real(dp) :: displ(2*3*Crystal%natom*3*Crystal%natom),eigval(3,Crystal%natom),phangmom(3,3*Crystal%natom)
    1860                 :          65 :  real(dp),allocatable :: phfrq(:),eigvec(:,:,:,:,:)
    1861                 :          65 :  real(dp),allocatable :: save_phfrq(:,:),save_phdispl_cart(:,:,:,:),save_qpoints(:,:),save_phangmom(:,:,:)
    1862                 :          65 :  real(dp),allocatable :: weights(:), dos4bs(:)
    1863                 :          65 :  real(dp),allocatable,target :: alloc_path(:,:)
    1864                 :          65 :  real(dp),pointer :: fineqpath(:,:)
    1865                 :          65 :  type(atprj_type) :: atprj
    1866                 :             : ! *********************************************************************
    1867                 :             : 
    1868                 :             :  ! Only master works for the time being
    1869                 :          65 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    1870         [ -  + ]:          65 :  if (my_rank /= master) return
    1871                 :             : 
    1872         [ +  + ]:         195 :  units = [std_out, ab_out]
    1873                 :          65 :  nsym = Crystal%nsym; natom = Crystal%natom
    1874                 :             : 
    1875                 :             :  ! Copy parameters from inp (then I will try to remove inp from the API so that I can call mkphbs in eph)
    1876                 :          65 :  ifcflag = inp%ifcflag
    1877                 :          65 :  natprj_bs = inp%natprj_bs
    1878                 :          65 :  freeze_displ = inp%freeze_displ
    1879                 :          65 :  eivec = inp%eivec; enunit = inp%enunit
    1880                 :          65 :  rftyp=inp%rfmeth
    1881                 :             : 
    1882                 :          65 :  nullify(fineqpath)
    1883                 :          65 :  nfineqpath = inp%nph1l
    1884                 :          65 :  fineqpath => inp%qph1l
    1885                 :             : 
    1886         [ +  + ]:          65 :  if(inp%nph1l==0) then
    1887         [ -  + ]:           8 :    if (inp%nqpath==0) then
    1888                 :             :      return ! if there is nothing to do, return
    1889                 :             :    else
    1890                 :             :      ! allow override of nph1l with nqpath if the former is not set
    1891                 :             :      ! allocate and compute path here and make fineqpath points to it
    1892   [ +  -  -  +  :          24 :      ABI_MALLOC(ndiv,(inp%nqpath-1))
          +  -  +  -  +  
             -  -  +  -  
                      + ]
    1893                 :           8 :      call make_path(inp%nqpath,inp%qpath,Crystal%gmet,'G',inp%ndivsm,ndiv,nfineqpath,alloc_path,std_out)
    1894         [ -  + ]:           8 :      ABI_FREE(ndiv)
    1895                 :           8 :      fineqpath => alloc_path
    1896                 :             :    end if
    1897                 :             :  end if
    1898                 :             : 
    1899   [ +  -  +  + ]:        5265 :  write(msg, '(a,(80a),a,a,a,a)' ) ch10,('=',ii=1,80),ch10,ch10,' Treat the first list of vectors ',ch10
    1900                 :          65 :  call wrtout(units, msg)
    1901                 :             : 
    1902         [ +  + ]:          65 :  if (natprj_bs > 0) call atprj%init(natom, natprj_bs, inp%iatprj_bs, prefix)
    1903                 :             : 
    1904   [ +  -  -  +  :         260 :  ABI_MALLOC(phfrq, (3*natom))
          +  -  +  -  +  
             -  -  +  -  
                      + ]
    1905   [ -  +  +  -  :         325 :  ABI_MALLOC(eigvec, (2,3,natom,3,natom))
          +  -  -  +  +  
          -  +  -  +  -  
             -  +  -  + ]
    1906   [ -  +  +  -  :         195 :  ABI_MALLOC(save_qpoints, (3,nfineqpath))
          +  -  +  -  -  
                +  -  + ]
    1907   [ -  +  +  -  :         260 :  ABI_MALLOC(save_phfrq, (3*natom,nfineqpath))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
    1908   [ -  +  +  -  :         325 :  ABI_MALLOC(save_phdispl_cart, (2,3*natom,3*natom,nfineqpath))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                      + ]
    1909   [ -  +  +  -  :         260 :  ABI_MALLOC(save_phangmom, (3,3*natom,nfineqpath))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
    1910         [ +  + ]:         260 :  qphnrm = one
    1911                 :             : 
    1912         [ +  + ]:        1309 :  do iphl1=1,nfineqpath
    1913                 :             : 
    1914                 :             :    ! Initialisation of the phonon wavevector
    1915         [ +  + ]:        4976 :    qphon(:)=fineqpath(:,iphl1)
    1916                 :             : 
    1917         [ +  + ]:        1244 :    if (inp%nph1l /= 0) qphnrm(1) = inp%qnrml1(iphl1)
    1918                 :             : 
    1919         [ +  + ]:        4976 :    save_qpoints(:,iphl1) = qphon / qphnrm(1)
    1920                 :             : 
    1921                 :             :    ! Generation of the dynamical matrix in cartesian coordinates
    1922         [ +  + ]:        1244 :    if (ifcflag == 1) then
    1923                 :             : 
    1924                 :             :      ! Get phonon frequencies and displacements in reduced coordinates for this q-point
    1925                 :             :      !call ifc%fourq(cryst, save_qpoints(:,iphl1), phfrq, displ, out_eigvec=eigvec)
    1926                 :             : 
    1927                 :             :      ! Get d2cart using the interatomic forces and the
    1928                 :             :      ! long-range coulomb interaction through Ewald summation
    1929                 :             :      call gtdyn9(Ifc%acell,Ifc%atmfrc,Ifc%dielt,Ifc%dipdip,Ifc%dyewq0,d2cart,Crystal%gmet,Ifc%gprim,Ifc%mpert,natom, &
    1930                 :             :       Ifc%nrpt,qphnrm(1),qphon,Crystal%rmet,Ifc%rprim,Ifc%rpt,Ifc%trans,Crystal%ucvol,Ifc%wghatm,Crystal%xred,ifc%zeff,&
    1931                 :             :       ifc%qdrp_cart,ifc%ewald_option,eta,xmpi_comm_self,Ifc%sys_dim,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad,&
    1932                 :        1202 :       dielt_env=Ifc%dielt_env,dielt_thick=Ifc%dielt_thick)
    1933         [ +  + ]:        1202 :      if (asrq0%asr==6) then
    1934         [ +  + ]:         644 :        qphon_padded = zero; qphon_padded(:,1) = qphon(:)
    1935                 :         161 :        call asrq0%apply(natom, ddb%mpert, ddb%msize, qphon_padded, Crystal, d2cart)
    1936                 :             :      end if
    1937         [ +  - ]:          42 :    else if (ifcflag == 0) then
    1938                 :             : 
    1939                 :             :      !call ddb_diagoq(ddb, crystal, save_qpoints(:,iphl1), asrq0, ifc%symdynmat, rftyp, phfrq, displ, &
    1940                 :             :      !                out_eigvec=eigvec)
    1941                 :             : 
    1942                 :             :      ! Look for the information in the DDB (no interpolation here!)
    1943   [ +  +  +  +  :         294 :      rfphon(1:2)=1; rfelfd(1:2)=0; rfstrs(1:2)=0
                   +  + ]
    1944         [ +  + ]:         168 :      qphon_padded = zero; qphon_padded(:,1) = qphon
    1945                 :             : 
    1946                 :          42 :      call ddb%get_block(iblok,qphon_padded,qphnrm,rfphon,rfelfd,rfstrs,rftyp)
    1947                 :             : 
    1948                 :             :      ! Copy the dynamical matrix in d2cart
    1949   [ +  +  +  + ]:     1159908 :      d2cart(:,1:ddb%msize)=ddb%val(:,:,iblok)
    1950                 :             : 
    1951                 :             :      ! Eventually impose the acoustic sum rule based on previously calculated d2asr
    1952                 :          42 :      call asrq0%apply(natom, ddb%mpert, ddb%msize, qphon_padded, Crystal, d2cart)
    1953                 :             :    end if
    1954                 :             : 
    1955                 :             :    ! Use inp%symdynmat instead of ifc because of ifcflag
    1956                 :             :    ! Calculation of the eigenvectors and eigenvalues of the dynamical matrix
    1957                 :             :    call dfpt_phfrq(ddb%amu,displ,d2cart,eigval,eigvec,Crystal%indsym,&
    1958                 :             :                    ddb%mpert,Crystal%nsym,natom,nsym,Crystal%ntypat,phfrq,qphnrm(1),qphon,&
    1959                 :        1244 :                    crystal%rprimd,inp%symdynmat,Crystal%symrel,Crystal%symafm,Crystal%typat,Crystal%ucvol)
    1960                 :             : 
    1961                 :             :    ! Calculation of the phonon angular momentum
    1962                 :             :    ! maybe add it in dpft_phfrq directly ?
    1963                 :        1244 :    call phangmom_from_eigvec(natom, eigvec, phangmom)
    1964                 :             : 
    1965         [ +  + ]:        1244 :    if (abs(freeze_displ) > tol10) then
    1966                 :           6 :      real_qphon = zero
    1967   [ +  -  +  + ]:          24 :      if (abs(qphnrm(1)) > tol8) real_qphon = qphon / qphnrm(1)
    1968                 :             :      call freeze_displ_allmodes(displ, freeze_displ, natom, prefix, phfrq, &
    1969                 :           6 :                                 real_qphon, crystal%rprimd, Crystal%typat, crystal%xcart, crystal%znucl)
    1970                 :             :    end if
    1971                 :             : 
    1972                 :             :    ! If requested, output projection of each mode on given atoms
    1973         [ +  + ]:        1244 :    if (natprj_bs > 0) call atprj%print(iphl1, phfrq, eigvec)
    1974                 :             : 
    1975                 :             :    ! In case eivec == 4, write output files for band2eps (visualization of phonon band structures)
    1976         [ +  + ]:        1244 :    if (eivec == 4) call sortph(eigvec,displ,strcat(prefix, "_B2EPS"),natom,phfrq)
    1977                 :             : 
    1978                 :             :    ! Write the phonon frequencies
    1979                 :        1244 :    call dfpt_prtph(displ,eivec,enunit,ab_out,natom,phfrq,qphnrm(1),qphon)
    1980                 :             : 
    1981         [ +  + ]:       14621 :    save_phfrq(:,iphl1) = phfrq
    1982         [ +  + ]:        4976 :    save_phdispl_cart(:,:,:,iphl1) = RESHAPE(displ, [2, 3*natom, 3*natom])
    1983         [ +  + ]:        3732 :    save_phangmom(:,:,iphl1) = RESHAPE(phangmom, [3, 3*natom])
    1984                 :             : 
    1985                 :             :    ! Determine the symmetries of the phonon mode at Gamma
    1986                 :             :    ! TODO: generalize for other q-point little groups.
    1987   [ +  +  +  + ]:        4976 :    if (sum(abs(qphon)) < DDB_QTOL) then
    1988                 :             :      call symanal(bravais,0,genafm,nsym,nsym,ptgroupma,Crystal%rprimd,spgroup, &
    1989                 :          72 :                   Crystal%symafm,Crystal%symrel,Crystal%tnons,tol5,verbose=.TRUE.)
    1990                 :          72 :      call dfpt_symph(ab_out,ddb%acell,eigvec,Crystal%indsym,natom,nsym,phfrq,ddb%rprim,Crystal%symrel)
    1991                 :             :    end if
    1992                 :             : 
    1993                 :             :    ! if we have an acoustic mode (small q and acoustic type displacements)
    1994                 :             :    ! extrapolate speed of sound in this direction, and Debye frequency
    1995         [ +  + ]:        4976 :    call wrap2_pmhalf(qphon, real_qphon, res)
    1996         [ +  + ]:         311 :    if (sqrt(real_qphon(1)**2+real_qphon(2)**2+real_qphon(3)**2) < quarter .and. &
    1997         [ +  + ]:        1309 :        sqrt(real_qphon(1)**2+real_qphon(2)**2+real_qphon(3)**2) > tol6) then
    1998                 :         237 :      call phdos_calc_vsound(eigvec, Crystal%gmet, natom, phfrq, real_qphon, speedofsound)
    1999                 :         237 :      if (my_rank == master) call phdos_print_vsound(ab_out, Crystal%ucvol, speedofsound)
    2000                 :             :    end if
    2001                 :             : 
    2002                 :             :  end do ! iphl1
    2003                 :             : 
    2004                 :             :  ! calculate dos for the specific q points along the BS calculated. only Gaussians are possible - no interpolation
    2005   [ +  +  +  +  :       14686 :  omega_min = minval(save_phfrq(:,:))
          +  +  +  -  -  
                +  -  - ]
    2006   [ +  +  +  +  :       14686 :  nomega=NINT( (maxval(save_phfrq(:,:))-omega_min) / inp%dosdeltae ) + 1
          +  +  +  -  -  
                +  -  - ]
    2007                 :          65 :  nomega=MAX(6,nomega) ! Ensure Simpson integration will be ok
    2008                 :             : 
    2009   [ -  +  +  -  :      249018 :  ABI_CALLOC(dos4bs,(nomega))
          +  -  -  +  -  
                +  +  + ]
    2010                 :             : 
    2011                 :          65 :  gaussmaxarg = sqrt(-log(1.d-90))
    2012                 :          65 :  gaussprefactor = one/(inp%dossmear*sqrt(two_pi))
    2013                 :          65 :  gaussfactor    = one/(sqrt2*inp%dossmear)
    2014         [ +  + ]:        1309 :  do iphl1=1,nfineqpath
    2015         [ +  + ]:       14686 :    do imode=1,3*natom
    2016         [ +  + ]:    55778618 :      do iomega=1, nomega
    2017                 :    55763997 :        omega = omega_min + (iomega-1) * inp%dosdeltae
    2018                 :    55763997 :        xx = (omega - save_phfrq(imode,iphl1)) * gaussfactor
    2019         [ +  + ]:    55777374 :        if(abs(xx) < gaussmaxarg) dos4bs(iomega) = dos4bs(iomega) + gaussprefactor*exp(-xx*xx)
    2020                 :             :      end do
    2021                 :             :    end do
    2022                 :             :  end do
    2023                 :             : 
    2024                 :             :  !deallocate sortph array
    2025                 :          65 :  call end_sortph()
    2026                 :             : 
    2027         [ +  + ]:          65 :  if (natprj_bs > 0) call atprj%free()
    2028                 :             : 
    2029                 :             : ! WRITE OUT FILES
    2030                 :             :  if (my_rank == master) then
    2031   [ -  +  +  -  :         195 :    ABI_MALLOC(weights, (nfineqpath))
          +  -  +  -  -  
                +  -  + ]
    2032         [ +  + ]:        1309 :    weights = one
    2033         [ -  + ]:          65 :    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHBST.nc"), xmpi_comm_self), "Creating PHBST")
    2034         [ -  + ]:          65 :    NCF_CHECK(crystal%ncwrite(ncid))
    2035                 :          65 :    call phonons_ncwrite(ncid,natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart,save_phangmom)
    2036                 :             :    ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
    2037   [ +  +  +  + ]:          65 :    if (inp%nph2l /= 0 .and. inp%ifcflag == 1) then
    2038                 :          14 :      call ifc%calcnwrite_nana_terms(crystal, inp%nph2l, inp%qph2l, inp%qnrml2, ncid)
    2039                 :             :    end if
    2040         [ -  + ]:          65 :    NCF_CHECK(nf90_close(ncid))
    2041                 :             : 
    2042                 :          65 :    call phonons_write_phfrq(prefix, natom,nfineqpath,save_qpoints,weights,save_phfrq,save_phdispl_cart, save_phangmom)
    2043                 :             : 
    2044                 :          65 :    select case (inp%prtphbands)
    2045                 :             :    case (0)
    2046                 :          65 :      continue
    2047                 :             : 
    2048                 :             :    case (1)
    2049         [ +  + ]:          65 :      if (inp%nph1l == 0) then
    2050                 :             :        call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nfineqpath, save_qpoints, save_phfrq, &
    2051                 :           8 :           qptbounds=inp%qpath)
    2052                 :             :      else
    2053                 :          57 :        call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nfineqpath, save_qpoints, save_phfrq)
    2054                 :             :      end if
    2055                 :             : 
    2056                 :             :    case (2)
    2057         [ #  # ]:           0 :      if (inp%nph1l == 0) then
    2058                 :           0 :        call phonons_write_gnuplot(prefix, natom, nfineqpath, save_qpoints, save_phfrq, qptbounds=inp%qpath)
    2059                 :             :      else
    2060                 :           0 :        call phonons_write_gnuplot(prefix, natom, nfineqpath, save_qpoints, save_phfrq)
    2061                 :             :      end if
    2062                 :             : 
    2063                 :             :    case default
    2064   [ +  -  -  - ]:          65 :      ABI_WARNING(sjoin("Don't know how to handle prtphbands:", itoa(inp%prtphbands)))
    2065                 :             :    end select
    2066                 :             : 
    2067                 :             :    ! write out DOS file for q along this path
    2068                 :          65 :    cfact=one
    2069                 :          65 :    unitname = 'Ha'
    2070         [ -  + ]:          65 :    if (open_file('PHBST_partial_DOS',msg,newunit=unt,form="formatted",action="write") /= 0) then
    2071                 :           0 :      ABI_ERROR(msg)
    2072                 :             :    end if
    2073                 :          65 :    write(msg,'(3a)')'# ',ch10,'# Partial phonon density of states for q along a band structure path'
    2074                 :          65 :    call wrtout(unt, msg)
    2075                 :          65 :    write(msg,'(6a)')'# ',ch10,'# Energy in ',unitname,', DOS in states/',unitname
    2076                 :          65 :    call wrtout(unt, msg)
    2077                 :          65 :    write(msg,'(a,E20.10,2a,i8)') '# Gaussian method with smearing = ',inp%dossmear*cfact,unitname, ', nq =', nfineqpath
    2078                 :          65 :    call wrtout(unt, msg)
    2079                 :          65 :    write(msg,'(5a)')'# ',ch10,'# omega     PHDOS ',ch10,'# '
    2080                 :          65 :    call wrtout(unt, msg)
    2081         [ +  + ]:      248888 :    do iomega=1,nomega
    2082                 :      248823 :      omega = omega_min + (iomega-1) * inp%dosdeltae
    2083                 :      248823 :      write(unt,'(2es17.8)',advance='NO')omega*cfact,dos4bs(iomega)/cfact
    2084                 :      248888 :      write(unt,*)
    2085                 :             :    end do
    2086                 :          65 :    close(unt)
    2087                 :             : 
    2088         [ -  + ]:          65 :    ABI_FREE(weights)
    2089                 :             :  end if
    2090                 :             : 
    2091         [ -  + ]:          65 :  ABI_FREE(save_qpoints)
    2092         [ -  + ]:          65 :  ABI_FREE(save_phfrq)
    2093         [ -  + ]:          65 :  ABI_FREE(save_phdispl_cart)
    2094         [ -  + ]:          65 :  ABI_FREE(save_phangmom)
    2095         [ -  + ]:          65 :  ABI_FREE(phfrq)
    2096         [ -  + ]:          65 :  ABI_FREE(eigvec)
    2097         [ -  + ]:          65 :  ABI_FREE(dos4bs)
    2098         [ +  + ]:          65 :  ABI_SFREE(alloc_path)
    2099                 :             : 
    2100   [ -  +  -  +  :         130 : end subroutine mkphbs
                   -  + ]
    2101                 :             : !!***
    2102                 :             : 
    2103                 :             : !!****f* m_phonons/phdos_calc_vsound
    2104                 :             : !!
    2105                 :             : !! NAME
    2106                 :             : !! phdos_calc_vsound
    2107                 :             : !!
    2108                 :             : !! FUNCTION
    2109                 :             : !!  From the frequencies for acoustic modes at small q, estimate speed of sound (which also gives Debye temperature)
    2110                 :             : !!
    2111                 :             : !! INPUTS
    2112                 :             : !! eigvec(2,3*natom,3*natom) = phonon eigenvectors at present q-point
    2113                 :             : !! gmet(3,3) = metric tensor in reciprocal space.
    2114                 :             : !! natom = number of atoms in the unit cell
    2115                 :             : !! phfrq(3*natom) = phonon frequencies at present q-point
    2116                 :             : !! qphon(3) = phonon q-point
    2117                 :             : !! ucvol = unit cell volume
    2118                 :             : !!
    2119                 :             : !! OUTPUT
    2120                 :             : !!
    2121                 :             : !! SOURCE
    2122                 :             : 
    2123                 :       12368 : subroutine phdos_calc_vsound(eigvec, gmet, natom, phfrq, qphon, speedofsound)
    2124                 :             : 
    2125                 :             : !Arguments -------------------------------
    2126                 :             : !scalars
    2127                 :             :  integer, intent(in) :: natom
    2128                 :             : !arrays
    2129                 :             :  real(dp), intent(in) :: gmet(3,3),qphon(3),phfrq(3*natom),eigvec(2,3*natom,3*natom)
    2130                 :             :  real(dp), intent(out) :: speedofsound(3)
    2131                 :             : 
    2132                 :             : !Local variables -------------------------
    2133                 :             :  integer :: iatref,imode, iatom, isacoustic, imode_acoustic
    2134                 :             : ! character(len=500) :: msg
    2135                 :             :  real(dp) :: qnormcart
    2136                 :             :  real(dp) :: qtmp(3)
    2137                 :             : ! *********************************************************************
    2138                 :             : 
    2139                 :       12368 :  imode_acoustic = 0
    2140                 :             : 
    2141         [ +  + ]:       73163 :  do imode = 1, 3*natom
    2142                 :             :    ! Check if this mode is acoustic like: scalar product of all displacement vectors are collinear
    2143                 :      178956 :    isacoustic = 1
    2144                 :             :    ! Find reference atom with non-zero displacement
    2145         [ +  + ]:      178956 :    do iatom=1,natom
    2146   [ +  +  +  +  :     1242405 :      if(sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3,imode)**2) >tol16)iatref=iatom
                   +  + ]
    2147                 :             :    enddo
    2148                 :             :    ! Now compute scalar product, and check they are all positive
    2149         [ +  + ]:      178956 :    do iatom = 1, natom
    2150   [ +  +  +  +  :     1181610 :      if (sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3, imode)&
                   +  + ]
    2151                 :       88963 :             *eigvec(:,(iatref-1)*3+1:(iatref-1)*3+3, imode)) < tol16 ) isacoustic = 0
    2152                 :             :    end do
    2153         [ +  + ]:       60795 :    if (isacoustic == 0) cycle
    2154                 :       37081 :    imode_acoustic = min(imode_acoustic + 1, 3)
    2155                 :             : 
    2156                 :             :    ! write (msg, '(a,I6,a,3F12.4)') ' Found acoustic mode ', imode, ' for |q| in red coord < 0.25 ; q = ', qphon
    2157                 :             :    ! call wrtout(std_out, msg)
    2158   [ +  +  +  + ]:      482053 :    qtmp = matmul(gmet, qphon)
    2159         [ +  + ]:      148324 :    qnormcart = two * pi * sqrt(sum(qphon*qtmp))
    2160                 :       73163 :    speedofsound(imode_acoustic) = phfrq(imode) / qnormcart
    2161                 :             :  end do
    2162                 :             : 
    2163                 :       12368 : end subroutine phdos_calc_vsound
    2164                 :             : !!***
    2165                 :             : 
    2166                 :             : !!****f* m_phonons/phdos_print_vsound
    2167                 :             : !!
    2168                 :             : !! NAME
    2169                 :             : !! phdos_print_vsound
    2170                 :             : !!
    2171                 :             : !! FUNCTION
    2172                 :             : !!  Print out estimate speed of sound and Debye temperature at this (small) q
    2173                 :             : !!  should only be called by master proc for the hard unit number
    2174                 :             : !!
    2175                 :             : !! INPUTS
    2176                 :             : !! unit=Fortran unit number
    2177                 :             : !! speedofsound(3)
    2178                 :             : !!
    2179                 :             : !! OUTPUT
    2180                 :             : !!  Only writing
    2181                 :             : !!
    2182                 :             : !! SOURCE
    2183                 :             : 
    2184                 :         237 : subroutine phdos_print_vsound(iunit, ucvol, speedofsound)
    2185                 :             : 
    2186                 :             : !Arguments -------------------------------
    2187                 :             : !scalras
    2188                 :             :  integer, intent(in) :: iunit
    2189                 :             :  real(dp), intent(in) :: ucvol
    2190                 :             : !arrays
    2191                 :             :  real(dp), intent(in) :: speedofsound(3)
    2192                 :             : 
    2193                 :             : !Local variables -------------------------
    2194                 :             :  integer :: imode_acoustic, units(2)
    2195                 :             :  character(len=500) :: msg
    2196                 :             :  real(dp) :: tdebye
    2197                 :             : ! *********************************************************************
    2198                 :             : 
    2199         [ +  + ]:         711 :  units = [std_out, iunit]
    2200                 :             : 
    2201         [ +  + ]:         948 :  do imode_acoustic = 1, 3
    2202                 :             :    ! from phonon frequency, estimate speed of sound by linear interpolation from Gamma
    2203                 :             :    write (msg, '(2a,a,E20.10,a,a,F20.5)') &
    2204                 :         711 :     ' Speed of sound for this q and mode:',ch10,&
    2205                 :         711 :     '   in atomic units: ', speedofsound(imode_acoustic), ch10,&
    2206                 :        1422 :     '   in units km/s: ', speedofsound(imode_acoustic) * Bohr_Ang * 1.d-13 / Time_Sec
    2207                 :         711 :    call wrtout(units, msg)
    2208                 :             : 
    2209                 :             :    ! also estimate partial Debye temperature, = energy if this band went to zone edge
    2210                 :         711 :    tdebye = speedofsound(imode_acoustic) * pi * (six / pi / ucvol)**(third)
    2211                 :             :    write (msg, '(2a,a,E20.10,a,a,F20.5)') &
    2212                 :         711 :     ' Partial Debye temperature for this q and mode:',ch10,&
    2213                 :         711 :     '   in atomic units: ', tdebye, ch10,&
    2214                 :        1422 :     '   in SI units K  : ', tdebye * Ha_K
    2215                 :         711 :    call wrtout(units, msg)
    2216                 :         948 :    call wrtout(units, "")
    2217                 :             :  end do
    2218                 :             : 
    2219                 :         237 : end subroutine phdos_print_vsound
    2220                 :             : !!***
    2221                 :             : 
    2222                 :             : !----------------------------------------------------------------------
    2223                 :             : 
    2224                 :             : !!****f* m_phonons/phdos_print_msqd
    2225                 :             : !!
    2226                 :             : !! NAME
    2227                 :             : !! phdos_print_msqd
    2228                 :             : !!
    2229                 :             : !! FUNCTION
    2230                 :             : !!  Print out mean square displacement and velocity for each atom (trace and full matrix) as a function of T
    2231                 :             : !!  see for example https://atztogo.github.io/phonopy/thermal-displacement.html#thermal-displacement
    2232                 :             : !!  Only master node should call this routine.
    2233                 :             : !!
    2234                 :             : !! INPUTS
    2235                 :             : !!   PHdos structure
    2236                 :             : !!
    2237                 :             : !! OUTPUT
    2238                 :             : !!   to file only
    2239                 :             : !!
    2240                 :             : !! SOURCE
    2241                 :             : 
    2242                 :          11 : subroutine phdos_print_msqd(PHdos, fname, ntemper, tempermin, temperinc)
    2243                 :             : 
    2244                 :             : !Arguments -------------------------------
    2245                 :             : !scalars
    2246                 :             :  class(phdos_t),intent(in) :: PHdos
    2247                 :             :  character(len=*),intent(in) :: fname
    2248                 :             :  integer, intent(in) :: ntemper
    2249                 :             :  real(dp), intent(in) :: tempermin, temperinc
    2250                 :             : 
    2251                 :             : !Local variables -------------------------
    2252                 :             :  integer :: io, iomin, itemp, iunit, junit, iatom
    2253                 :             :  real(dp) :: temper
    2254                 :             :  character(len=500) :: msg
    2255                 :             :  character(len=fnlen) :: fname_msqd, fname_veloc
    2256                 :             : !arrays
    2257                 :          11 :  real(dp), allocatable :: bose_msqd(:,:), tmp_msqd(:,:), integ_msqd(:,:)
    2258                 :          11 :  real(dp), allocatable :: bose_msqv(:,:), tmp_msqv(:,:), integ_msqv(:,:)
    2259                 :             : ! *********************************************************************
    2260                 :             : 
    2261         [ +  - ]:          11 :  fname_msqd = trim(fname) //"_MSQD_T"
    2262         [ -  + ]:          11 :  if (open_file(fname_msqd, msg, newunit=iunit, form="formatted", status="unknown", action="write") /= 0) then
    2263                 :           0 :    ABI_ERROR(msg)
    2264                 :             :  end if
    2265         [ +  - ]:          11 :  fname_veloc = trim(fname) // "_MSQV_T"
    2266         [ -  + ]:          11 :  if (open_file(fname_veloc, msg, newunit=junit, form="formatted", status="unknown", action="write") /= 0) then
    2267                 :           0 :    ABI_ERROR(msg)
    2268                 :             :  end if
    2269                 :             : 
    2270                 :             :  ! write the header
    2271                 :          11 :  write (iunit, '(a)') '# mean square displacement for each atom as a function of T (bohr^2)'
    2272                 :          11 :  write (junit, '(a)') "# mean square velocity for each atom as a function of T (bohr^2/atomic time unit^2)"
    2273                 :             : 
    2274                 :          11 :  write (msg, '(a,F18.10,a,F18.10,a)') '#  T in Kelvin, from ', tempermin, ' to ', tempermin+(ntemper-1)*temperinc
    2275                 :          11 :  write (iunit, '(a)') trim(msg)
    2276                 :          11 :  write (junit, '(a)') trim(msg)
    2277                 :             : 
    2278                 :          11 :  write (msg, '(2a)') '#    T             |u^2|                u_xx                u_yy                u_zz',&
    2279                 :          22 :                      '                u_yz                u_xz                u_xy in bohr^2'
    2280                 :          11 :  write (iunit, '(a)') trim(msg)
    2281                 :          11 :  write (msg, '(3a)') '#    T             |v^2|                v_xx                v_yy                v_zz',&
    2282                 :          11 :                      '                v_yz                v_xz                v_xy',&
    2283                 :          22 :                      ' in bohr^2/atomic time unit^2'
    2284                 :          11 :  write (junit, '(a)') trim(msg)
    2285                 :             : 
    2286   [ -  +  +  -  :          33 :  ABI_MALLOC(tmp_msqd, (PHdos%nomega,9))
          +  -  +  -  -  
                +  -  + ]
    2287   [ -  +  +  -  :          22 :  ABI_MALLOC(tmp_msqv, (PHdos%nomega,9))
             -  +  -  + ]
    2288   [ -  +  +  -  :          33 :  ABI_MALLOC(integ_msqd, (9,ntemper))
          +  -  +  -  -  
                +  -  + ]
    2289   [ -  +  +  -  :          22 :  ABI_MALLOC(integ_msqv, (9,ntemper))
             -  +  -  + ]
    2290   [ -  +  +  -  :          44 :  ABI_MALLOC(bose_msqd, (PHdos%nomega, ntemper))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
    2291   [ -  +  +  -  :          33 :  ABI_MALLOC(bose_msqv, (PHdos%nomega, ntemper))
          -  +  +  -  -  
                +  -  + ]
    2292                 :             : 
    2293         [ -  + ]:       10455 :  do io=1, PHdos%nomega
    2294         [ +  + ]:       10455 :    if ( PHdos%omega(io) >= 2._dp * 4.56d-6 ) exit ! 2 cm-1 TODO: make this an input parameter
    2295                 :             :  end do
    2296                 :             :  iomin = io
    2297                 :             : 
    2298                 :             :  ! calculate bose only once for each atom (instead of for each atom)
    2299   [ +  +  +  + ]:      407961 :  bose_msqd = zero
    2300   [ +  +  +  + ]:      407961 :  bose_msqv = zero
    2301         [ +  + ]:         121 :  do itemp = 1, ntemper
    2302                 :         110 :    temper = tempermin + (itemp-1) * temperinc
    2303         [ +  - ]:         110 :    if (temper < 1.e-3) cycle ! millikelvin at least to avoid exploding Bose factor(TM)
    2304         [ +  + ]:      303521 :    do io = iomin, PHdos%nomega
    2305                 :             :      ! NB: factors follow convention in phonopy documentation
    2306                 :             :      ! the 1/sqrt(omega) factor in phonopy is contained in the displacement vector definition
    2307                 :             :      ! bose() is dimensionless
    2308                 :             :      !bose_msqd(io, itemp) =  (half + one  / ( exp(PHdos%omega(io)/(kb_HaK*temper)) - one )) / PHdos%omega(io)
    2309                 :             :      !bose_msqv(io, itemp) =  (half + one  / ( exp(PHdos%omega(io)/(kb_HaK*temper)) - one )) * PHdos%omega(io)
    2310                 :      303400 :      bose_msqd(io, itemp) =  (half + bose_einstein(PHdos%omega(io),kb_HaK*temper)) / PHdos%omega(io)
    2311                 :      303510 :      bose_msqv(io, itemp) =  (half + bose_einstein(PHdos%omega(io),kb_HaK*temper)) * PHdos%omega(io)
    2312                 :             :    end do
    2313                 :             :  end do
    2314                 :             : 
    2315         [ +  + ]:          36 :  do iatom=1,PHdos%natom
    2316                 :          25 :    write (msg, '(a,I8)') '# atom number ', iatom
    2317                 :          25 :    write (iunit, '(a)') trim(msg)
    2318                 :          25 :    write (junit, '(a)') trim(msg)
    2319                 :             : 
    2320                 :             :    ! for each T and each atom, integrate msqd matrix with Bose Einstein factor and output
    2321   [ +  +  +  + ]:        2525 :    integ_msqd = zero
    2322         [ +  + ]:          75 :    tmp_msqd = reshape(PHdos%msqd_dos_atom(:,:,:,iatom), (/PHdos%nomega, 9/))
    2323                 :             : 
    2324                 :             :    ! perform all integrations as matrix multiplication: integ_msqd (idir, itemp) = [tmp_msqd(io,idir)]^T  * bose_msqd(io,itemp)
    2325                 :          25 :    call DGEMM('T','N', 9, ntemper, PHdos%nomega, one, tmp_msqd,PHdos%nomega, bose_msqd, PHdos%nomega, zero, integ_msqd, 9)
    2326                 :             :    ! NB: this presumes an equidistant omega grid
    2327   [ +  +  +  + ]:        2525 :    integ_msqd = integ_msqd * (PHdos%omega(2)-PHdos%omega(1)) / PHdos%atom_mass(iatom)
    2328                 :             : 
    2329   [ +  +  +  + ]:        2525 :    integ_msqv = zero
    2330         [ +  + ]:          75 :    tmp_msqv = reshape(PHdos%msqd_dos_atom(:,:,:,iatom), (/PHdos%nomega, 9/))
    2331                 :             : 
    2332                 :             :    ! perform all integrations as matrix multiplication: integ_msqv (idir, itemp) = [tmp_msqv(io,idir)]^T  * bose_msqv(io,itemp)
    2333                 :          25 :    call DGEMM('T','N', 9, ntemper, PHdos%nomega, one, tmp_msqv,PHdos%nomega, bose_msqv, PHdos%nomega, zero, integ_msqv, 9)
    2334                 :             :    ! NB: this presumes an equidistant omega grid
    2335   [ +  +  +  + ]:        2525 :    integ_msqv = integ_msqv * (PHdos%omega(2)-PHdos%omega(1)) / PHdos%atom_mass(iatom)
    2336                 :             : 
    2337                 :             :    ! print out stuff
    2338         [ +  + ]:         275 :    do itemp = 1, ntemper
    2339                 :         250 :      temper = tempermin + (itemp-1) * temperinc
    2340                 :             :      write (msg, '(F10.2,4x,E22.10,2x,6E22.10)') &
    2341                 :         250 :        temper, third*(integ_msqd(1,itemp)+integ_msqd(5,itemp)+integ_msqd(9,itemp)), &
    2342                 :         250 :                       integ_msqd(1,itemp),integ_msqd(5,itemp),integ_msqd(9,itemp), &
    2343                 :         500 :                       integ_msqd(6,itemp),integ_msqd(3,itemp),integ_msqd(2,itemp)
    2344                 :         250 :      write (iunit, '(a)') trim(msg)
    2345                 :             :      write (msg, '(F10.2,4x,E22.10,2x,6E22.10)') &
    2346                 :         250 :        temper, third*(integ_msqv(1,itemp)+integ_msqv(5,itemp)+integ_msqv(9,itemp)), &
    2347                 :         250 :                       integ_msqv(1,itemp),integ_msqv(5,itemp),integ_msqv(9,itemp), &
    2348                 :         500 :                       integ_msqv(6,itemp),integ_msqv(3,itemp),integ_msqv(2,itemp)
    2349                 :         275 :      write (junit, '(a)') trim(msg)
    2350                 :             :    end do ! itemp
    2351                 :             : 
    2352                 :          25 :    write (iunit, '(a)') ''
    2353                 :          36 :    write (junit, '(a)') ''
    2354                 :             :  enddo ! iatom
    2355                 :             : 
    2356         [ -  + ]:          11 :  ABI_FREE(tmp_msqd)
    2357         [ -  + ]:          11 :  ABI_FREE(tmp_msqv)
    2358         [ -  + ]:          11 :  ABI_FREE(bose_msqd)
    2359         [ -  + ]:          11 :  ABI_FREE(bose_msqv)
    2360         [ -  + ]:          11 :  ABI_FREE(integ_msqd)
    2361         [ -  + ]:          11 :  ABI_FREE(integ_msqv)
    2362                 :             : 
    2363                 :          11 :  close(iunit)
    2364                 :          11 :  close(junit)
    2365                 :             : 
    2366                 :          11 : end subroutine phdos_print_msqd
    2367                 :             : !!***
    2368                 :             : 
    2369                 :             : !----------------------------------------------------------------------
    2370                 :             : 
    2371                 :             : !!****f* m_phonons/phonons_ncwrite
    2372                 :             : !! NAME
    2373                 :             : !! phonons_ncwrite
    2374                 :             : !!
    2375                 :             : !! FUNCTION
    2376                 :             : !!  Write phonon bandstructure to netcdf file.
    2377                 :             : !!
    2378                 :             : !! INPUTS
    2379                 :             : !!  ncid =NC file handle
    2380                 :             : !!  natom=Number of atoms
    2381                 :             : !!  nqpts=Number of q-points.
    2382                 :             : !!  qpoints=List of q-points in reduced coordinates
    2383                 :             : !!  weights(nqpts)= q-point weights
    2384                 :             : !!  phfreq=Phonon frequencies
    2385                 :             : !!  phdispl_cart=Phonon displacementent in Cartesian coordinates.
    2386                 :             : !!  phangmom= Phonon angular momentum in cartesian coordinates
    2387                 :             : !!
    2388                 :             : !! NOTES
    2389                 :             : !!  Input data is in a.u, whereas the netcdf files saves data in eV for frequencies
    2390                 :             : !!  and Angstrom for the displacements
    2391                 :             : !!  The angular momentum is output in units of hbar
    2392                 :             : !!
    2393                 :             : !! OUTPUT
    2394                 :             : !!  Only writing
    2395                 :             : !!
    2396                 :             : !! SOURCE
    2397                 :             : 
    2398                 :         102 : subroutine phonons_ncwrite(ncid, natom, nqpts, qpoints, weights, phfreq, phdispl_cart, phangmom)
    2399                 :             : 
    2400                 :             : !Arguments ------------------------------------
    2401                 :             : !scalars
    2402                 :             :  integer,intent(in) :: ncid,natom,nqpts
    2403                 :             : !arrays
    2404                 :             :  real(dp),intent(in) :: qpoints(3,nqpts),weights(nqpts)
    2405                 :             :  real(dp),intent(in) :: phfreq(3*natom,nqpts),phdispl_cart(2,3*natom,3*natom,nqpts),phangmom(3,3*natom,nqpts)
    2406                 :             : 
    2407                 :             : !Local variables-------------------------------
    2408                 :             :  integer :: nphmodes,ncerr
    2409                 :             : ! *************************************************************************
    2410                 :             : 
    2411                 :         102 :  nphmodes = 3*natom
    2412                 :             : 
    2413         [ -  + ]:         102 :  NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
    2414                 :             : 
    2415                 :             :  ncerr = nctk_def_dims(ncid, [&
    2416         [ +  + ]:         408 :    nctkdim_t("number_of_qpoints", nqpts), nctkdim_t('number_of_phonon_modes', nphmodes), nctkdim_t('three', 3)])
    2417         [ -  + ]:         102 :  NCF_CHECK(ncerr)
    2418                 :             : 
    2419                 :             :  ! Define arrays
    2420                 :             :  ncerr = nctk_def_arrays(ncid, [&
    2421                 :             :    nctkarr_t('qpoints', "dp" , 'number_of_reduced_dimensions, number_of_qpoints'),&
    2422                 :             :    nctkarr_t('qweights',"dp", 'number_of_qpoints'),&
    2423                 :             :    nctkarr_t('phfreqs',"dp", 'number_of_phonon_modes, number_of_qpoints'),&
    2424                 :             :    nctkarr_t('phdispl_cart',"dp", 'complex, number_of_phonon_modes, number_of_phonon_modes, number_of_qpoints'),&
    2425         [ +  + ]:         612 :    nctkarr_t('phangmom',"dp", 'three, number_of_phonon_modes, number_of_qpoints')])
    2426         [ -  + ]:         102 :  NCF_CHECK(ncerr)
    2427                 :             : 
    2428                 :             :  ! Write variables.
    2429         [ -  + ]:         102 :  NCF_CHECK(nctk_set_datamode(ncid))
    2430         [ -  + ]:         102 :  NCF_CHECK(nf90_put_var(ncid, vid('qpoints'), qpoints))
    2431         [ -  + ]:         102 :  NCF_CHECK(nf90_put_var(ncid, vid('qweights'), weights))
    2432   [ +  +  +  +  :       27523 :  NCF_CHECK(nf90_put_var(ncid, vid('phfreqs'), phfreq*Ha_eV))
          -  +  -  -  -  
                      - ]
    2433   [ +  +  +  +  :      777070 :  NCF_CHECK(nf90_put_var(ncid, vid('phdispl_cart'), phdispl_cart*Bohr_Ang))
          +  +  +  +  -  
          +  -  -  -  -  
             -  -  -  - ]
    2434         [ -  + ]:         102 :  NCF_CHECK(nf90_put_var(ncid, vid('phangmom'), phangmom))
    2435                 :             : 
    2436                 :             : contains
    2437                 :         510 : integer function vid(vname)
    2438                 :             :  character(len=*),intent(in) :: vname
    2439   [ +  -  +  - ]:         510 :  vid = nctk_idname(ncid, vname)
    2440                 :             : end function vid
    2441                 :             : 
    2442                 :             : end subroutine phonons_ncwrite
    2443                 :             : !!***
    2444                 :             : 
    2445                 :             : !----------------------------------------------------------------------
    2446                 :             : 
    2447                 :             : !!****f* m_phonons/phonons_write_phfrq
    2448                 :             : !! NAME
    2449                 :             : !! phonons_write_phfrq
    2450                 :             : !!
    2451                 :             : !! FUNCTION
    2452                 :             : !!  Write phonon bandstructure in a text file. Fixed file name for the moment
    2453                 :             : !!
    2454                 :             : !! INPUTS
    2455                 :             : !!  natom=Number of atoms
    2456                 :             : !!  nqpts=Number of q-points.
    2457                 :             : !!  qpoints=List of q-points in reduced coordinates
    2458                 :             : !!  weights(nqpts)= q-point weights
    2459                 :             : !!  phfreq=Phonon frequencies
    2460                 :             : !!  phdispl_cart=Phonon displacementent in Cartesian coordinates.
    2461                 :             : !!
    2462                 :             : !! NOTES
    2463                 :             : !!  Input data is in a.u, output too
    2464                 :             : !!
    2465                 :             : !! OUTPUT
    2466                 :             : !!  Only writing
    2467                 :             : !!
    2468                 :             : !! SOURCE
    2469                 :             : 
    2470                 :          65 :  subroutine phonons_write_phfrq(path,natom,nqpts,qpoints,weights,phfreq,phdispl_cart,phangmom)
    2471                 :             : 
    2472                 :             : !Arguments ------------------------------------
    2473                 :             : !scalars
    2474                 :             :  integer,intent(in) :: natom,nqpts
    2475                 :             :  character(len=*),intent(in) :: path
    2476                 :             : !arrays
    2477                 :             :  real(dp),intent(in) :: qpoints(3,nqpts),weights(nqpts)
    2478                 :             :  real(dp),intent(in) :: phfreq(3*natom,nqpts)
    2479                 :             :  real(dp),intent(in) :: phdispl_cart(2,3*natom,3*natom,nqpts)
    2480                 :             :  real(dp),intent(in) :: phangmom(3,3*natom,nqpts)
    2481                 :             : 
    2482                 :             : !Local variables-------------------------------
    2483                 :             : !scalars
    2484                 :             :  integer :: nphmodes, iq, iunit, imod, icomp
    2485                 :             :  real(dp) :: dummy
    2486                 :             :  character(len=300) :: fmt
    2487                 :             :  character(len=500) :: msg
    2488                 :             : ! *************************************************************************
    2489                 :             : 
    2490                 :          65 :  nphmodes = 3*natom
    2491                 :             : 
    2492                 :          65 :  dummy = qpoints(1,1); dummy = weights(1)
    2493                 :             : 
    2494                 :             :  ! Write phonon frequencies
    2495         [ -  + ]:          65 :  if (open_file(strcat(path, "_PHFRQ"), msg, newunit=iunit, form="formatted", status="unknown", action="write") /= 0) then
    2496                 :          65 :    ABI_ERROR(msg)
    2497                 :             :  end if
    2498                 :             : 
    2499                 :          65 :  write (iunit, '(a)')  '# ABINIT generated phonon band structure file. All in Ha atomic units'
    2500                 :          65 :  write (iunit, '(a)')  '# '
    2501                 :          65 :  write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
    2502                 :          65 :  write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
    2503                 :          65 :  write (iunit, '(a)')  '# '
    2504                 :             : 
    2505                 :          65 :  write (fmt,'(a,i0,a)') "(I5, ", nphmodes, "E20.10)"
    2506         [ +  + ]:        1309 :  do iq= 1, nqpts
    2507                 :        1309 :    write (iunit, fmt)  iq, phfreq(:,iq)
    2508                 :             :  end do
    2509                 :             : 
    2510                 :          65 :  close(iunit)
    2511                 :             : 
    2512                 :             :  ! Does not Write phonon displacement ?
    2513                 :             :  if (.False.) then
    2514                 :             :    if (open_file(strcat(path, "_PHDISPL"), msg, unit=iunit, form="formatted", status="unknown", action="write") /= 0) then
    2515                 :             :      ABI_ERROR(msg)
    2516                 :             :    end if
    2517                 :             : 
    2518                 :             :    write (iunit, '(a)')     '# ABINIT generated phonon displacements, along points in PHFRQ file. All in Ha atomic units'
    2519                 :             :    write (iunit, '(a)')     '# '
    2520                 :             :    write (iunit, '(a)')     '# displacements in cartesian coordinates, Re and Im parts '
    2521                 :             :    write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
    2522                 :             :    write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
    2523                 :             :    write (iunit, '(a)')     '# '
    2524                 :             : 
    2525                 :             :    !write (fmt,'(a,I3,a)') "( ", nphmodes, "(2E20.10,2x))"
    2526                 :             :    fmt = "(2E20.10,2x)"
    2527                 :             : 
    2528                 :             :    do iq = 1, nqpts
    2529                 :             :      write (iunit, '(a, i0)') '# iq ', iq
    2530                 :             :      do imod = 1, nphmodes
    2531                 :             :        write (iunit, '(a, i0)') '# imode ', imod
    2532                 :             :        do icomp = 1, nphmodes
    2533                 :             :          write (iunit, fmt, ADVANCE='NO') phdispl_cart(:,icomp,imod,iq)
    2534                 :             :        end do
    2535                 :             :        write (iunit, '(a)') ' '
    2536                 :             :      end do
    2537                 :             :    end do
    2538                 :             : 
    2539                 :             :    close(iunit)
    2540                 :             :  end if
    2541                 :             : 
    2542                 :             :  ! Write phonon angular momentum
    2543         [ -  + ]:          65 :  if (open_file(strcat(path, "_PHANGMOM"), msg, unit=iunit, form="formatted", status="unknown", action="write") /= 0) then
    2544                 :          65 :    ABI_ERROR(msg)
    2545                 :             :  end if
    2546                 :             : 
    2547                 :          65 :  write (iunit, '(a)')     '# ABINIT generated phonon angular momentum, along points in PHFRQ file. All in Ha atomic units'
    2548                 :          65 :  write (iunit, '(a)')     '# '
    2549                 :          65 :  write (iunit, '(a)')     '# angular momentum in cartesian coordinates '
    2550                 :          65 :  write (iunit, '(a,i0)')  '# number_of_qpoints ', nqpts
    2551                 :          65 :  write (iunit, '(a,i0)')  '# number_of_phonon_modes ', nphmodes
    2552                 :          65 :  write (iunit, '(a)')     '# '
    2553                 :             : 
    2554                 :          65 :  write (fmt,'(a,i0,a)') "(I5, ", nphmodes, "E20.10)"
    2555         [ +  + ]:         260 :  do icomp = 1, 3
    2556         [ +  + ]:        3927 :    do iq= 1, nqpts
    2557                 :        3927 :      write (iunit, fmt)  iq, phangmom(icomp,:,iq)
    2558                 :             :    end do
    2559         [ +  + ]:         260 :    if (icomp /= 3) then
    2560                 :         130 :      write (iunit, '(a,a)') ''
    2561                 :             :    end if
    2562                 :             :  end do
    2563                 :             : 
    2564                 :          65 :  close(iunit)
    2565                 :             : 
    2566                 :          65 : end subroutine phonons_write_phfrq
    2567                 :             : !!***
    2568                 :             : 
    2569                 :             : !----------------------------------------------------------------------
    2570                 :             : 
    2571                 :             : !!****f* m_phonons/phonons_write_xmgrace
    2572                 :             : !! NAME
    2573                 :             : !! phonons_write_xmgrace
    2574                 :             : !!
    2575                 :             : !! FUNCTION
    2576                 :             : !!  Write phonons bands in Xmgrace format. This routine should be called by a single processor.
    2577                 :             : !!
    2578                 :             : !! INPUTS
    2579                 :             : !!  filename=Filename
    2580                 :             : !!  natom=Number of atoms
    2581                 :             : !!  nqpts=Number of q-points
    2582                 :             : !!  qpts(3,nqpts)=Q-points
    2583                 :             : !!  phfreqs(3*natom,nqpts)=Phonon frequencies.
    2584                 :             : !!  [qptbounds(:,:)]=Optional argument giving the extrema of the q-path.
    2585                 :             : !!
    2586                 :             : !! OUTPUT
    2587                 :             : !!  Only writing
    2588                 :             : !!
    2589                 :             : !! SOURCE
    2590                 :             : 
    2591   [ +  +  +  -  :         101 : subroutine phonons_write_xmgrace(filename, natom, nqpts, qpts, phfreqs, qptbounds)
                   -  + ]
    2592                 :             : 
    2593                 :             : !Arguments ------------------------------------
    2594                 :             : !scalars
    2595                 :             :  integer,intent(in) :: natom,nqpts
    2596                 :             :  real(dp),intent(in) :: qpts(3,nqpts),phfreqs(3*natom,nqpts)
    2597                 :             :  character(len=*),intent(in) :: filename
    2598                 :             : !arrays
    2599                 :             :  real(dp),optional,intent(in) :: qptbounds(:,:)
    2600                 :             : 
    2601                 :             : !Local variables-------------------------------
    2602                 :             : !scalars
    2603                 :             :  integer :: unt,iq,nu,ii,start,nqbounds
    2604                 :             :  character(len=500) :: msg
    2605                 :             : !arrays
    2606                 :             :  integer :: g0(3)
    2607                 :         101 :  integer,allocatable :: bounds2qpt(:)
    2608                 :             : ! *********************************************************************
    2609                 :             : 
    2610                 :         101 :  nqbounds = 0
    2611         [ +  + ]:         101 :  if (present(qptbounds)) then
    2612   [ +  +  +  - ]:         132 :    if (product(shape(qptbounds)) > 0 ) then
    2613                 :             :      ! Find correspondence between qptbounds and k-points in ebands.
    2614                 :          44 :      nqbounds = size(qptbounds, dim=2)
    2615   [ -  +  +  -  :         132 :      ABI_MALLOC(bounds2qpt, (nqbounds))
          +  -  +  -  -  
                +  -  + ]
    2616         [ +  + ]:         211 :      bounds2qpt = 1; start = 1
    2617         [ +  + ]:         211 :      do ii=1,nqbounds
    2618         [ +  - ]:        2570 :         do iq=start,nqpts
    2619   [ -  +  -  -  :        2526 :           if (isamek(qpts(:, iq), qptbounds(:, ii), g0)) then
          -  -  -  +  +  
                      + ]
    2620                 :         167 :             bounds2qpt(ii) = iq; start = iq + 1; exit
    2621                 :             :           end if
    2622                 :             :         end do
    2623                 :             :      end do
    2624                 :             :    end if
    2625                 :             :  end if
    2626                 :             : 
    2627         [ -  + ]:         101 :  if (open_file(filename, msg, newunit=unt, form="formatted", action="write") /= 0) then
    2628                 :           0 :    ABI_ERROR(msg)
    2629                 :             :  end if
    2630                 :             : 
    2631                 :         101 :  write(unt,'(a)') "# Grace project file"
    2632                 :         101 :  write(unt,'(a)') "# Generated by Abinit"
    2633                 :         101 :  write(unt,'(2(a,i0))') "# natom: ",natom,", nqpt: ",nqpts
    2634                 :         101 :  write(unt,'(a)') "# Frequencies are in meV"
    2635                 :         101 :  write(unt,'(a)')"# List of q-points and their index (C notation i.e. count from 0)"
    2636         [ +  + ]:        3238 :  do iq=1,nqpts
    2637                 :        3238 :    write(unt, "(a)")sjoin("#", itoa(iq-1), ktoa(qpts(:,iq)))
    2638                 :             :  end do
    2639                 :             : 
    2640                 :         101 :  write(unt,'(a)') "@page size 792, 612"
    2641                 :         101 :  write(unt,'(a)') "@page scroll 5%"
    2642                 :         101 :  write(unt,'(a)') "@page inout 5%"
    2643                 :         101 :  write(unt,'(a)') "@link page off"
    2644                 :         101 :  write(unt,'(a)') "@with g0"
    2645                 :         101 :  write(unt,'(a)') "@world xmin 0.00"
    2646                 :         101 :  write(unt,'(a,i0)') '@world xmax ',nqpts
    2647   [ +  +  +  +  :       27358 :  write(unt,'(a,e16.8)') '@world ymin ',minval(phfreqs * Ha_meV)
          +  +  +  -  -  
                +  -  - ]
    2648   [ +  +  +  +  :       27358 :  write(unt,'(a,e16.8)') '@world ymax ',maxval(phfreqs * Ha_meV)
          +  +  +  -  -  
                +  -  - ]
    2649                 :         101 :  write(unt,'(a)') '@default linewidth 1.5'
    2650                 :         101 :  write(unt,'(a)') '@xaxis  tick on'
    2651                 :         101 :  write(unt,'(a)') '@xaxis  tick major 1'
    2652                 :         101 :  write(unt,'(a)') '@xaxis  tick major color 1'
    2653                 :         101 :  write(unt,'(a)') '@xaxis  tick major linestyle 3'
    2654                 :         101 :  write(unt,'(a)') '@xaxis  tick major grid on'
    2655                 :         101 :  write(unt,'(a)') '@xaxis  tick spec type both'
    2656                 :         101 :  write(unt,'(a)') '@xaxis  tick major 0, 0'
    2657         [ +  + ]:         101 :  if (nqbounds /= 0) then
    2658                 :          44 :    write(unt,'(a,i0)') '@xaxis  tick spec ',nqbounds
    2659         [ +  + ]:         211 :    do iq=1,nqbounds
    2660                 :             :      !write(unt,'(a,i0,a,a)') '@xaxis  ticklabel ',iq-1,',', "foo"
    2661                 :         211 :      write(unt,'(a,i0,a,i0)') '@xaxis  tick major ',iq-1,' , ',bounds2qpt(iq) - 1
    2662                 :             :    end do
    2663                 :             :  end if
    2664                 :         101 :  write(unt,'(a)') '@xaxis  ticklabel char size 1.500000'
    2665                 :         101 :  write(unt,'(a)') '@yaxis  tick major 10'
    2666                 :         101 :  write(unt,'(a)') '@yaxis  label "Phonon Energy [meV]"'
    2667                 :         101 :  write(unt,'(a)') '@yaxis  label char size 1.500000'
    2668                 :         101 :  write(unt,'(a)') '@yaxis  ticklabel char size 1.500000'
    2669         [ +  + ]:         920 :  do nu=1,3*natom
    2670                 :         920 :    write(unt,'(a,i0,a)') '@    s',nu-1,' line color 1'
    2671                 :             :  end do
    2672         [ +  + ]:         920 :  do nu=1,3*natom
    2673                 :         819 :    write(unt,'(a,i0)') '@target G0.S',nu-1
    2674                 :         819 :    write(unt,'(a)') '@type xy'
    2675         [ +  + ]:       24939 :    do iq=1,nqpts
    2676                 :       24939 :       write(unt,'(i0,1x,e16.8)') iq-1, phfreqs(nu, iq) * Ha_meV
    2677                 :             :    end do
    2678                 :         920 :    write(unt,'(a)') '&'
    2679                 :             :  end do
    2680                 :             : 
    2681                 :         101 :  close(unt)
    2682                 :             : 
    2683         [ +  + ]:         101 :  ABI_SFREE(bounds2qpt)
    2684                 :             : 
    2685                 :         101 : end subroutine phonons_write_xmgrace
    2686                 :             : !!***
    2687                 :             : 
    2688                 :             : !----------------------------------------------------------------------
    2689                 :             : 
    2690                 :             : !!****f* m_phonons/phonons_write_gnuplot
    2691                 :             : !! NAME
    2692                 :             : !! phonons_write_gnuplot
    2693                 :             : !!
    2694                 :             : !! FUNCTION
    2695                 :             : !!  Write phonons bands in gnuplot format. This routine should be called by a single processor.
    2696                 :             : !!
    2697                 :             : !! INPUTS
    2698                 :             : !!  prefix=prefix for files (.data, .gnuplot)
    2699                 :             : !!  natom=Number of atoms
    2700                 :             : !!  nqpts=Number of q-points
    2701                 :             : !!  qpts(3,nqpts)=Q-points
    2702                 :             : !!  phfreqs(3*natom,nqpts)=Phonon frequencies.
    2703                 :             : !!  [qptbounds(:,:)]=Optional argument giving the extrema of the q-path.
    2704                 :             : !!
    2705                 :             : !! OUTPUT
    2706                 :             : !!  Only writing
    2707                 :             : !!
    2708                 :             : !! SOURCE
    2709                 :             : 
    2710   [ +  -  +  -  :           1 : subroutine phonons_write_gnuplot(prefix, natom, nqpts, qpts, phfreqs, qptbounds)
                   -  + ]
    2711                 :             : 
    2712                 :             : !Arguments ------------------------------------
    2713                 :             : !scalars
    2714                 :             :  integer,intent(in) :: natom,nqpts
    2715                 :             :  real(dp),intent(in) :: qpts(3,nqpts),phfreqs(3*natom,nqpts)
    2716                 :             :  character(len=*),intent(in) :: prefix
    2717                 :             : !arrays
    2718                 :             :  real(dp),optional,intent(in) :: qptbounds(:,:)
    2719                 :             : 
    2720                 :             : !Local variables-------------------------------
    2721                 :             : !scalars
    2722                 :             :  integer :: unt,iq,ii,start,nqbounds,gpl_unt
    2723                 :             :  character(len=500) :: msg,fmt
    2724                 :             :  character(len=fnlen) :: datafile,basefile
    2725                 :             : !arrays
    2726                 :             :  integer :: g0(3)
    2727                 :           1 :  integer,allocatable :: bounds2qpt(:)
    2728                 :             : ! *********************************************************************
    2729                 :             : 
    2730                 :           1 :  nqbounds = 0
    2731         [ +  - ]:           1 :  if (present(qptbounds)) then
    2732   [ +  +  +  - ]:           3 :    if (product(shape(qptbounds)) > 0 ) then
    2733                 :             :      ! Find correspondence between qptbounds and k-points in ebands.
    2734                 :           1 :      nqbounds = size(qptbounds, dim=2)
    2735   [ -  +  +  -  :           3 :      ABI_MALLOC(bounds2qpt, (nqbounds))
          +  -  +  -  -  
                +  -  + ]
    2736         [ +  + ]:           4 :      bounds2qpt = 1; start = 1
    2737         [ +  + ]:           4 :      do ii=1,nqbounds
    2738         [ +  - ]:          42 :         do iq=start,nqpts
    2739   [ -  +  -  -  :          41 :           if (isamek(qpts(:, iq), qptbounds(:, ii), g0)) then
          -  -  -  +  +  
                      + ]
    2740                 :           3 :             bounds2qpt(ii) = iq; start = iq + 1; exit
    2741                 :             :           end if
    2742                 :             :         end do
    2743                 :             :      end do
    2744                 :             :    end if
    2745                 :             :  end if
    2746                 :             : 
    2747         [ +  - ]:           1 :  datafile = strcat(prefix, "_PHBANDS.data")
    2748         [ -  + ]:           1 :  if (open_file(datafile, msg, newunit=unt, form="formatted", action="write") /= 0) then
    2749                 :           0 :    ABI_ERROR(msg)
    2750                 :             :  end if
    2751         [ -  + ]:           1 :  if (open_file(strcat(prefix, "_PHBANDS.gnuplot"), msg, newunit=gpl_unt, form="formatted", action="write") /= 0) then
    2752                 :           1 :    ABI_ERROR(msg)
    2753                 :             :  end if
    2754         [ +  - ]:           1 :  basefile = basename(datafile)
    2755                 :             : 
    2756                 :           1 :  write(unt,'(a)') "# Phonon band structure data file"
    2757                 :           1 :  write(unt,'(a)') "# Generated by Abinit"
    2758                 :           1 :  write(unt,'(2(a,i0))') "# natom: ",natom,", nqpt: ",nqpts
    2759                 :           1 :  write(unt,'(a)') "# Frequencies are in meV"
    2760                 :           1 :  write(unt,'(a)')"# List of q-points and their index (C notation i.e. count from 0)"
    2761         [ +  + ]:          42 :  do iq=1,nqpts
    2762                 :          42 :    write(unt, "(a)")sjoin("#", itoa(iq-1), ktoa(qpts(:,iq)))
    2763                 :             :  end do
    2764                 :             : 
    2765         [ +  - ]:           1 :  fmt = sjoin("(i0,1x,", itoa(3*natom), "(es16.8,1x))")
    2766                 :           1 :  write(unt,'(a)')"# [kpt-index, mode_1, mode_2 ...]"
    2767         [ +  + ]:          42 :  do iq=1,nqpts
    2768         [ +  + ]:         165 :    write(unt, fmt) iq-1, phfreqs(:, iq) * Ha_meV
    2769                 :             :  end do
    2770                 :             : 
    2771                 :             :  ! gnuplot script file
    2772                 :           1 :   write(gpl_unt,'(a)') '# File to plot electron bandstructure with gnuplot'
    2773                 :             :   !write(gpl_unt,'(a)') "#set terminal postscript eps enhanced color font 'Times-Roman,26' lw 2"
    2774                 :           1 :   write(gpl_unt,'(a)') '#use the next lines to make a nice figure for a paper'
    2775                 :           1 :   write(gpl_unt,'(a)') '#set term postscript enhanced eps color lw 0.5 dl 0.5'
    2776                 :           1 :   write(gpl_unt,'(a)') '#set pointsize 0.275'
    2777                 :           1 :   write(gpl_unt,'(a)') 'set palette defined ( 0 "blue", 3 "green", 6 "yellow", 10 "red" )'
    2778                 :           1 :   write(gpl_unt,'(a)') 'unset key'
    2779                 :           1 :   write(gpl_unt,'(a)') '# can make pointsize smaller (~0.5). Too small and nothing is printed'
    2780                 :           1 :   write(gpl_unt,'(a)') 'set pointsize 0.8'
    2781                 :           1 :   write(gpl_unt,'(a)') 'set view 0,0'
    2782                 :           1 :   write(gpl_unt,'(a,i0,a)') 'set xrange [0:',nqpts-1,']'
    2783                 :             :   write(gpl_unt,'(2(a,es16.8),a)')&
    2784   [ +  +  +  +  :         329 :     'set yrange [',minval(phfreqs * Ha_meV),':',maxval(phfreqs * Ha_meV),']'
          +  +  +  -  -  
          +  -  -  +  +  
          +  +  +  +  +  
             -  -  +  -  
                      - ]
    2785                 :           1 :   write(gpl_unt,'(a)') 'set xlabel "Momentum"'
    2786                 :           1 :   write(gpl_unt,'(a)') 'set ylabel "Energy [meV]"'
    2787                 :           1 :   write(gpl_unt,'(a)') strcat('set title "', replace(basefile, "_", "\\_"),'"')
    2788         [ -  + ]:           1 :   if (nqbounds == 0) then
    2789                 :           0 :      write(gpl_unt,'(a)') 'set grid xtics'
    2790                 :             :   else
    2791                 :           1 :     write(gpl_unt,"(a)")"# Add vertical lines in correspondence of high-symmetry points."
    2792                 :           1 :     write(gpl_unt,'(a)') 'unset xtics'
    2793         [ +  + ]:           4 :     do ii=1,nqbounds
    2794                 :             :       write(gpl_unt,"(a,2(i0,a))") &
    2795                 :           4 :         "set arrow from ",bounds2qpt(ii)-1,",graph(0,0) to ",bounds2qpt(ii)-1,",graph(1,1) nohead"
    2796                 :             :       !write(gpl_unt,"(a)")sjoin("set xtics add ('kname'", itoa(bounds2kpt(ii)-1), ")")
    2797                 :             :     end do
    2798                 :             :   end if
    2799                 :           1 :   write(gpl_unt,"(a)")sjoin("nbranch =", itoa(3*natom))
    2800                 :           1 :   write(gpl_unt,"(a)")strcat('plot for [i=2:nbranch] "', basefile, '" u 1:i every :1 with lines linetype -1')
    2801                 :           1 :   write(gpl_unt,"(a)")"pause -1"
    2802                 :             : 
    2803                 :           1 :  close(unt)
    2804                 :           1 :  close(gpl_unt)
    2805                 :             : 
    2806         [ +  - ]:           1 :  ABI_SFREE(bounds2qpt)
    2807                 :             : 
    2808                 :           1 : end subroutine phonons_write_gnuplot
    2809                 :             : !!***
    2810                 :             : 
    2811                 :             : !!****f* m_phonons/ifc_mkphbs
    2812                 :             : !! NAME
    2813                 :             : !! ifc_mkphbs
    2814                 :             : !!
    2815                 :             : !! FUNCTION
    2816                 :             : !! Compute the phonon band structure from the IFC and write data to file(s)
    2817                 :             : !!
    2818                 :             : !! INPUTS
    2819                 :             : !! ifc<ifc_type>=Interatomic force constants
    2820                 :             : !! cryst<crystal_t> = Info on the crystalline structure.
    2821                 :             : !! dtset=<datasets_type>: input: all input variables initialized from the input file.
    2822                 :             : !! prefix=Prefix for output files.
    2823                 :             : !! comm=MPI communicator
    2824                 :             : !!
    2825                 :             : !! OUTPUT
    2826                 :             : !!  Only writing.
    2827                 :             : !!
    2828                 :             : !! SOURCE
    2829                 :             : 
    2830                 :          98 : subroutine ifc_mkphbs(ifc, cryst, dtset, prefix, comm)
    2831                 :             : 
    2832                 :             : !Arguments -------------------------------
    2833                 :             : !scalars
    2834                 :             :  class(ifc_type),intent(in) :: ifc
    2835                 :             :  type(crystal_t),intent(in) :: cryst
    2836                 :             :  type(dataset_type),intent(in) :: dtset
    2837                 :             :  character(len=*),intent(in) :: prefix
    2838                 :             :  integer,intent(in) :: comm
    2839                 :             : 
    2840                 :             : !Local variables -------------------------
    2841                 :             : !scalars
    2842                 :             :  integer,parameter :: master = 0
    2843                 :             :  integer :: iqpt, nqpts, natom, ncid, nprocs, my_rank, ierr, ndirs, ncerr
    2844                 :          98 :  type(kpath_t) :: qpath
    2845                 :             : !arrays
    2846                 :          98 :  real(dp),allocatable :: qph2l(:,:), qnrml2(:), eigvec(:,:,:,:,:),phfrqs(:,:),phdispl_cart(:,:,:,:),phangmom(:,:,:),weights(:)
    2847                 :             : ! *********************************************************************
    2848                 :             : 
    2849         [ -  + ]:          98 :  if (dtset%prtphbands == 0) return
    2850                 :             : 
    2851   [ +  +  -  + ]:          98 :  if (dtset%ph_nqpath <= 0 .or. dtset%ph_ndivsm <= 0) then
    2852                 :          61 :    ABI_COMMENT("ph_nqpath <= 0 or ph_ndivsm <= 0. Phonon bands won't be produced. Returning")
    2853                 :          61 :    return
    2854                 :             :  end if
    2855                 :             : 
    2856                 :          37 :  call wrtout(std_out, " Writing phonon bands, use prtphbands 0 to disable this part")
    2857                 :             : 
    2858                 :          37 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2859                 :             : 
    2860                 :          37 :  natom = cryst%natom
    2861                 :          37 :  call qpath%init(dtset%ph_qpath(:,1:dtset%ph_nqpath), cryst%gprimd, dtset%ph_ndivsm)
    2862                 :          37 :  nqpts = qpath%npts
    2863                 :             : 
    2864   [ +  -  -  +  :       12948 :  ABI_CALLOC(phfrqs, (3*natom,nqpts))
          +  -  -  +  +  
          -  +  -  +  -  
          -  +  -  +  +  
                +  +  + ]
    2865   [ -  +  +  -  :      201931 :  ABI_CALLOC(phdispl_cart, (2,3*natom,3*natom,nqpts))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
          +  +  +  +  +  
             +  +  +  + ]
    2866   [ -  +  +  -  :       45546 :  ABI_CALLOC(phangmom, (3,3*natom,nqpts))
          -  +  +  -  +  
          -  +  -  -  +  
          -  +  +  +  +  
                +  +  + ]
    2867   [ -  +  +  -  :        4357 :  ABI_CALLOC(eigvec, (2,3,natom,3,natom))
          +  -  -  +  +  
          -  +  -  +  -  
          -  +  -  +  +  
          +  +  +  +  +  
             +  +  +  + ]
    2868                 :             : 
    2869         [ +  + ]:        1971 :  do iqpt=1,nqpts
    2870         [ -  + ]:        1934 :    if (mod(iqpt, nprocs) /= my_rank) cycle ! MPI-parallelism
    2871                 :             :    ! Get phonon frequencies and displacements in cartesian coordinates for this q-point
    2872                 :        1934 :    call ifc%fourq(cryst, qpath%points(:,iqpt), phfrqs(:,iqpt), phdispl_cart(:,:,:,iqpt), out_eigvec=eigvec)
    2873                 :        1971 :    call phangmom_from_eigvec(natom, eigvec, phangmom(:,:,iqpt))
    2874                 :             :  end do
    2875                 :             : 
    2876                 :          37 :  call xmpi_sum_master(phfrqs, master, comm, ierr)
    2877                 :          37 :  call xmpi_sum_master(phdispl_cart, master, comm, ierr)
    2878                 :          37 :  call xmpi_sum_master(phangmom, master, comm, ierr)
    2879                 :             : 
    2880         [ +  - ]:          37 :  if (my_rank == master) then
    2881   [ -  +  +  -  :         111 :    ABI_MALLOC(weights, (nqpts))
          +  -  +  -  -  
                +  -  + ]
    2882         [ +  + ]:        1971 :    weights = one
    2883                 :             : 
    2884                 :             :    ! Compute directions for non-analytical behaviour.
    2885                 :             :    ! TODO: The same approach should be used in anaddb at the level of the parser.
    2886   [ -  +  +  -  :         111 :    ABI_MALLOC(qph2l, (3, 2*dtset%ph_nqpath))
          +  -  -  +  -  
                      + ]
    2887   [ -  +  +  -  :         111 :    ABI_MALLOC(qnrml2, (2*dtset%ph_nqpath))
          +  -  -  +  -  
                      + ]
    2888                 :             : 
    2889                 :          37 :    ndirs = 0
    2890   [ +  +  +  +  :         531 :    if (any(ifc%zeff /= zero)) then
          +  +  +  +  +  
                      + ]
    2891         [ +  + ]:          73 :      do iqpt=1,dtset%ph_nqpath
    2892   [ +  +  +  + ]:         247 :        if (sum(dtset%ph_qpath(:, iqpt)**2) < tol14) then
    2893                 :          16 :          ndirs = ndirs + 1
    2894         [ +  + ]:          16 :          if (iqpt == 1) then
    2895         [ +  + ]:          60 :            qph2l(:, ndirs) = dtset%ph_qpath(:, 2) - dtset%ph_qpath(:, 1)
    2896         [ -  + ]:           1 :          else if (iqpt == dtset%ph_nqpath) then
    2897         [ #  # ]:           0 :            qph2l(:, ndirs) = dtset%ph_qpath(:, dtset%ph_nqpath - 1) - dtset%ph_qpath(:, dtset%ph_nqpath)
    2898                 :             :          else
    2899         [ +  + ]:           4 :            qph2l(:, ndirs) = dtset%ph_qpath(:, iqpt - 1) - dtset%ph_qpath(:, iqpt)
    2900                 :           1 :            ndirs = ndirs + 1
    2901         [ +  + ]:           4 :            qph2l(:, ndirs) = dtset%ph_qpath(:, iqpt + 1) - dtset%ph_qpath(:, iqpt)
    2902                 :             :          end if
    2903                 :             :        end if
    2904                 :             :      end do
    2905                 :             : 
    2906                 :             :      ! Convert to Cartesian coordinates.
    2907         [ +  + ]:          32 :      do iqpt=1,ndirs
    2908   [ +  +  +  +  :         338 :        qph2l(:, iqpt) = matmul(cryst%gprimd, qph2l(:, iqpt))
          +  +  +  +  +  
                      - ]
    2909                 :             :      end do
    2910         [ +  + ]:         131 :      qnrml2 = zero
    2911                 :             :    end if
    2912                 :             : 
    2913                 :             :    ! TODO: A similar piece of code is used in anaddb (mkpbs + ifc_calcnwrite_nana_terms).
    2914                 :             :    ! Should centralize everything in a single routine
    2915         [ -  + ]:          37 :    NCF_CHECK_MSG(nctk_open_create(ncid, strcat(prefix, "_PHBST.nc"), xmpi_comm_self), "Creating PHBST")
    2916         [ -  + ]:          37 :    NCF_CHECK(cryst%ncwrite(ncid))
    2917                 :          37 :    call phonons_ncwrite(ncid, natom, nqpts, qpath%points, weights, phfrqs, phdispl_cart, phangmom)
    2918                 :             :    ! This flag tells AbiPy that all the non-analytic directions have been computed.
    2919   [ +  +  -  +  :          74 :    NCF_CHECK(nctk_defnwrite_ivars(ncid, ["has_abipy_non_anal_ph"], [1]))
                   -  - ]
    2920         [ +  + ]:          74 :    ncerr = nctk_def_arrays(ncid, [nctkarr_t("atomic_mass_units", "dp", "number_of_atom_species")], defmode=.True.)
    2921         [ -  + ]:          37 :    NCF_CHECK(ncerr)
    2922         [ -  + ]:          37 :    NCF_CHECK(nctk_set_datamode(ncid))
    2923         [ -  + ]:          37 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "atomic_mass_units"), ifc%amu))
    2924         [ +  + ]:          37 :    if (ndirs /= 0) call ifc%calcnwrite_nana_terms(cryst, ndirs, qph2l, qnrml2, ncid=ncid)
    2925         [ -  + ]:          37 :    NCF_CHECK(nf90_close(ncid))
    2926                 :             : 
    2927         [ -  + ]:          37 :    ABI_FREE(qph2l)
    2928         [ -  + ]:          37 :    ABI_FREE(qnrml2)
    2929                 :             : 
    2930                 :          36 :    select case (dtset%prtphbands)
    2931                 :             :    case (1)
    2932                 :          36 :      call phonons_write_xmgrace(strcat(prefix, "_PHBANDS.agr"), natom, nqpts, qpath%points, phfrqs, qptbounds=qpath%bounds)
    2933                 :             :    case (2)
    2934                 :           1 :      call phonons_write_gnuplot(prefix, natom, nqpts, qpath%points, phfrqs, qptbounds=qpath%bounds)
    2935                 :             :    case (3)
    2936                 :           0 :      call phonons_write_phfrq(prefix, natom, nqpts, qpath%points, weights, phfrqs, phdispl_cart, phangmom)
    2937                 :             :    case default
    2938   [ +  +  -  - ]:          37 :      ABI_WARNING(sjoin("Unsupported value for prtphbands:", itoa(dtset%prtphbands)))
    2939                 :             :    end select
    2940                 :             : 
    2941         [ -  + ]:          37 :    ABI_FREE(weights)
    2942                 :             :  end if ! master
    2943                 :             : 
    2944         [ -  + ]:          37 :  ABI_FREE(phfrqs)
    2945         [ -  + ]:          37 :  ABI_FREE(phdispl_cart)
    2946         [ -  + ]:          37 :  ABI_FREE(phangmom)
    2947         [ -  + ]:          37 :  ABI_FREE(eigvec)
    2948                 :             : 
    2949                 :          37 :  call qpath%free()
    2950                 :             : 
    2951   [ -  +  -  +  :          98 : end subroutine ifc_mkphbs
          -  +  -  +  -  
          +  -  +  -  +  
                   -  + ]
    2952                 :             : !!***
    2953                 :             : 
    2954                 :             : !!****f* m_phonons/dfpt_symph
    2955                 :             : !! NAME
    2956                 :             : !! dfpt_symph
    2957                 :             : !!
    2958                 :             : !! FUNCTION
    2959                 :             : !! Determine the symmetry character of the different phonon modes.
    2960                 :             : !!
    2961                 :             : !! INPUTS
    2962                 :             : !! acell(3)=length scales of primitive translations (bohr)
    2963                 :             : !! eigvec(2*3*natom*3*natom)=eigenvectors of the dynamical matrix
    2964                 :             : !! indsym(4,nsym,natom)=indirect indexing array : for each
    2965                 :             : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    2966                 :             : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    2967                 :             : !!   translations which must be subtracted after the transformation to get back
    2968                 :             : !!   to the original unit cell.
    2969                 :             : !! iout=unit number to which output is written
    2970                 :             : !! natom=number of atoms in unit cell
    2971                 :             : !! nsym=number of space group symmetries
    2972                 :             : !! phfrq(3*natom)=phonon frequencies (Hartree units)
    2973                 :             : !! rprim(3,3)=dimensionless primitive translations in real space
    2974                 :             : !! symrel(3,3,nsym)=matrices of the group symmetries (real space)
    2975                 :             : !!
    2976                 :             : !! OUTPUT
    2977                 :             : !!
    2978                 :             : !! SOURCE
    2979                 :             : 
    2980                 :          72 : subroutine dfpt_symph(iout, acell, eigvec, indsym, natom, nsym, phfrq, rprim, symrel)
    2981                 :             : 
    2982                 :             : !Arguments ------------------------------------
    2983                 :             : !scalars
    2984                 :             :  integer,intent(in) :: iout,natom,nsym
    2985                 :             : !arrays
    2986                 :             :  integer,intent(in) :: indsym(4,nsym,natom),symrel(3,3,nsym)
    2987                 :             :  real(dp),intent(in) :: acell(3),eigvec(2*3*natom*3*natom),phfrq(3*natom)
    2988                 :             :  real(dp),intent(in) :: rprim(3,3)
    2989                 :             : 
    2990                 :             : !Local variables -------------------------
    2991                 :             : !scalars
    2992                 :             :  integer :: iad1,iad2,iad3,iatom,idir,ii1,ii2,ii3,imode,isym,itol,jad,jatom,jj, jmode,kk,ntol
    2993                 :             :  character(len=500) :: msg
    2994                 :             : !arrays
    2995                 :             :  integer :: units(2)
    2996                 :          72 :  integer,allocatable :: degeneracy(:),integer_characters(:),symind(:,:)
    2997                 :             :  real(dp) :: gprimd(3,3),rprimd(3,3)
    2998                 :          72 :  real(dp),allocatable :: eigvtr(:),redvec(:),redvtr(:),symph(:,:)
    2999                 :             : !******************************************************************
    3000                 :             : 
    3001         [ +  + ]:         216 :  units = [std_out, iout]
    3002                 :             : 
    3003                 :             :  ! Compute dimensional primitive translations rprimd and its inverse gprimd
    3004                 :          72 :  call mkrdim(acell,rprim,rprimd)
    3005                 :          72 :  call matr3inv(rprimd,gprimd)
    3006                 :             : 
    3007                 :             :  ! Build the symmetry index (inverse of indsym(4,:,:))
    3008   [ -  +  +  -  :         288 :  ABI_MALLOC(symind, (nsym,natom))
          -  +  +  -  +  
          -  +  -  -  +  
                   -  + ]
    3009         [ +  + ]:        2275 :  do isym=1,nsym
    3010         [ +  + ]:        7984 :    do iatom=1,natom
    3011                 :        7912 :      symind(isym,indsym(4,isym,iatom))=iatom
    3012                 :             :    end do
    3013                 :             :  end do
    3014                 :             : 
    3015   [ -  +  +  -  :         360 :  ABI_MALLOC(symph,(nsym,3*natom))
          +  -  -  +  +  
          -  +  -  +  -  
             -  +  -  + ]
    3016   [ +  -  -  +  :         216 :  ABI_MALLOC(redvec,(2*3*natom))
          +  -  +  -  +  
             -  -  +  -  
                      + ]
    3017   [ -  +  +  -  :         144 :  ABI_MALLOC(redvtr,(2*3*natom))
             -  +  -  + ]
    3018   [ -  +  +  -  :         144 :  ABI_MALLOC(eigvtr,(2*3*natom))
             -  +  -  + ]
    3019                 :             : 
    3020                 :             :  ! Loop over the vibration modes
    3021         [ +  + ]:         756 :  do imode=1,3*natom
    3022                 :             : 
    3023                 :             :    ! Compute eigvec for this mode in reduced coordinates redvec
    3024         [ +  + ]:        4320 :    do iatom=1,natom
    3025                 :        3636 :      iad1=3*(iatom-1)+1
    3026                 :        3636 :      ii1=2*3*natom*(imode-1)+2*(iad1-1)+1
    3027                 :        3636 :      iad2=3*(iatom-1)+2
    3028                 :        3636 :      ii2=2*3*natom*(imode-1)+2*(iad2-1)+1
    3029                 :        3636 :      iad3=3*(iatom-1)+3
    3030                 :        3636 :      ii3=2*3*natom*(imode-1)+2*(iad3-1)+1
    3031         [ +  + ]:       15228 :      do idir=1,3
    3032                 :       10908 :        jad=3*(iatom-1)+idir
    3033                 :       10908 :        jj=2*(jad-1)+1
    3034                 :             :        redvec(jj)=gprimd(1,idir)*eigvec(ii1)+&
    3035                 :             :                   gprimd(2,idir)*eigvec(ii2)+&
    3036                 :       10908 :                   gprimd(3,idir)*eigvec(ii3)
    3037                 :             :        redvec(jj+1)=gprimd(1,idir)*eigvec(ii1+1)+&
    3038                 :             :                     gprimd(2,idir)*eigvec(ii2+1)+&
    3039                 :       14544 :                     gprimd(3,idir)*eigvec(ii3+1)
    3040                 :             :      end do !idir
    3041                 :             :    end do !iatom
    3042                 :             : 
    3043                 :             : !  Apply each transformation to redvec and store at the correct location in redvtr (iatom -> jatom)
    3044         [ +  + ]:       17883 :    do isym=1,nsym
    3045         [ +  + ]:       90960 :      do iatom=1,natom
    3046                 :       73833 :        jatom=symind(isym,iatom)
    3047                 :       73833 :        iad1=3*(iatom-1)+1
    3048                 :       73833 :        ii1=2*(iad1-1)+1
    3049                 :       73833 :        iad2=3*(iatom-1)+2
    3050                 :       73833 :        ii2=2*(iad2-1)+1
    3051                 :       73833 :        iad3=3*(iatom-1)+3
    3052                 :       73833 :        ii3=2*(iad3-1)+1
    3053         [ +  + ]:      312459 :        do idir=1,3
    3054                 :      221499 :          jad=3*(jatom-1)+idir
    3055                 :      221499 :          jj=2*(jad-1)+1
    3056                 :             :          redvtr(jj)=dble(symrel(idir,1,isym))*redvec(ii1)+&
    3057                 :             :                     dble(symrel(idir,2,isym))*redvec(ii2)+&
    3058                 :      221499 :                     dble(symrel(idir,3,isym))*redvec(ii3)
    3059                 :             :          redvtr(jj+1)=dble(symrel(idir,1,isym))*redvec(ii1+1)+&
    3060                 :             :                       dble(symrel(idir,2,isym))*redvec(ii2+1)+&
    3061                 :      295332 :                       dble(symrel(idir,3,isym))*redvec(ii3+1)
    3062                 :             :        end do !idir
    3063                 :             :      end do !iatom
    3064                 :             : 
    3065                 :             : !    Compute redvtr in cartesian coordinates eigvtr
    3066         [ +  + ]:       90960 :      do iatom=1,natom
    3067                 :       73833 :        iad1=3*(iatom-1)+1
    3068                 :       73833 :        ii1=2*(iad1-1)+1
    3069                 :       73833 :        iad2=3*(iatom-1)+2
    3070                 :       73833 :        ii2=2*(iad2-1)+1
    3071                 :       73833 :        iad3=3*(iatom-1)+3
    3072                 :       73833 :        ii3=2*(iad3-1)+1
    3073         [ +  + ]:      312459 :        do idir=1,3
    3074                 :      221499 :          jad=3*(iatom-1)+idir
    3075                 :      221499 :          jj=2*(jad-1)+1
    3076                 :             :          eigvtr(jj)=rprimd(idir,1)*redvtr(ii1)+&
    3077                 :             :                     rprimd(idir,2)*redvtr(ii2)+&
    3078                 :      221499 :                     rprimd(idir,3)*redvtr(ii3)
    3079                 :             :          eigvtr(jj+1)=rprimd(idir,1)*redvtr(ii1+1)+&
    3080                 :             :                       rprimd(idir,2)*redvtr(ii2+1)+&
    3081                 :      295332 :                       rprimd(idir,3)*redvtr(ii3+1)
    3082                 :             :        end do !idir
    3083                 :             :      end do !iatom
    3084                 :             : 
    3085                 :             : !    Compute scalar product...
    3086                 :       17127 :      symph(isym,imode)=zero
    3087         [ +  + ]:      239310 :      do jad=1,3*natom
    3088                 :      221499 :        jj=2*(jad-1)+1
    3089                 :      221499 :        kk=2*3*natom*(imode-1)+2*(jad-1)+1
    3090                 :      238626 :        symph(isym,imode)=symph(isym,imode)+eigvtr(jj)*eigvec(kk)+eigvtr(jj+1)*eigvec(kk+1)
    3091                 :             :      end do
    3092                 :             : 
    3093                 :             :    end do !isym
    3094                 :             :  end do !imode
    3095                 :             : 
    3096                 :             : !Treat degeneracies (different tolerances will be tried)
    3097                 :             : !Compute the order of the degeneracy, and
    3098                 :             : !attribute it to the lowest of the degenerate modes
    3099                 :             : !Also attribute the characters to the lowest mode
    3100                 :             : !When all the characters are integers, consider that the
    3101                 :             : !mode is non-degenerate. The maximum difference in frequency
    3102                 :             : !that is tolerated is on the order of 4cm-1 (which is large...)
    3103   [ -  +  +  -  :         216 :  ABI_MALLOC(degeneracy, (3*natom))
          +  -  +  -  -  
                +  -  + ]
    3104   [ -  +  +  -  :         144 :  ABI_MALLOC(integer_characters, (3*natom))
             -  +  -  + ]
    3105         [ +  + ]:         756 :  degeneracy(:)=1
    3106         [ +  + ]:         756 :  integer_characters(:)=0
    3107         [ +  + ]:         121 :  do itol=1,20
    3108                 :         119 :    ntol=itol
    3109         [ +  + ]:        1155 :    do imode=3*natom,2,-1
    3110         [ +  + ]:        1155 :      if(integer_characters(imode)==0)then
    3111         [ +  + ]:        6187 :        do jmode=imode-1,1,-1
    3112         [ +  + ]:        6187 :          if(integer_characters(jmode)==0)then
    3113         [ +  + ]:        5199 :            if(abs(phfrq(imode)-phfrq(jmode))<itol*tol6)then
    3114                 :         523 :              degeneracy(jmode)=degeneracy(jmode)+degeneracy(imode)
    3115                 :         523 :              degeneracy(imode)=0
    3116         [ +  + ]:       16241 :              symph(:,jmode)=symph(:,jmode)+symph(:,imode)
    3117         [ +  + ]:       16241 :              symph(:,imode)=zero
    3118                 :             :            end if
    3119                 :             :          end if !integer_characters(jmode)==0
    3120                 :             :        end do !jmode
    3121                 :             :      end if !integer_characters(imode)==0
    3122                 :             :    end do !imode
    3123         [ +  + ]:        1274 :    do imode=1,3*natom
    3124   [ +  -  -  +  :       22838 :      if(maxval(abs( symph(:,imode)-nint(symph(:,imode)) ))<0.05_dp)then
          -  -  +  +  +  
                      + ]
    3125                 :        1041 :        integer_characters(imode)=1
    3126                 :             :      end if
    3127                 :             :    end do
    3128   [ +  +  +  + ]:        1276 :    if(sum(integer_characters(:))==3*natom)exit
    3129                 :             :  end do !itol
    3130                 :             : 
    3131                 :             :  !write(std_out,*)' dfpt_symph : degeneracy=',degeneracy(:)
    3132                 :             : 
    3133                 :          72 :  write(msg,'(a,a,es8.2,5a)')ch10,' Analysis of degeneracies and characters (maximum tolerance=',ntol*tol6,' a.u.)',ch10,&
    3134                 :          72 :   ' For each vibration mode, or group of modes if degenerate,',ch10,&
    3135                 :         144 :   ' the characters are given for each symmetry operation (see the list in the log file).'
    3136                 :          72 :  call wrtout(units, msg)
    3137                 :             : 
    3138                 :             :  !use m_ptgroups, only : get_classes
    3139                 :             :  !call get_classes(nsym, sym, nclass, nelements, elements_idx)
    3140                 :             : 
    3141         [ +  + ]:         756 :  do imode=1,3*natom
    3142         [ +  + ]:         756 :    if(degeneracy(imode)/=0)then
    3143                 :         334 :      write(msg,'(a,i4)') ' Symmetry characters of vibration mode #',imode
    3144                 :         334 :      call wrtout(units, msg)
    3145         [ +  + ]:         334 :      if (degeneracy(imode)>=2)then
    3146         [ +  + ]:         201 :        if (degeneracy(imode)==2) write(msg,'(a,i4)') '        degenerate with vibration mode #',imode+1
    3147         [ +  + ]:         201 :        if (degeneracy(imode)>=3) write(msg,'(a,i4,a,i4)') &
    3148                 :         137 :          '       degenerate with vibration modes #',imode+1,' to ',imode+degeneracy(imode)-1
    3149                 :         201 :        call wrtout(units, msg)
    3150                 :             :      end if
    3151         [ +  + ]:         880 :      do jj=1,(nsym-1)/16+1
    3152                 :         546 :        write(msg,'(16f5.1)') (symph(isym,imode),isym=(jj-1)*16+1,min(nsym,jj*16))
    3153                 :         880 :        call wrtout(units, msg)
    3154                 :             :      end do
    3155                 :             :    end if
    3156                 :             :  end do !imode
    3157                 :             : 
    3158         [ -  + ]:          72 :  ABI_FREE(degeneracy)
    3159         [ -  + ]:          72 :  ABI_FREE(integer_characters)
    3160         [ -  + ]:          72 :  ABI_FREE(eigvtr)
    3161         [ -  + ]:          72 :  ABI_FREE(redvtr)
    3162         [ -  + ]:          72 :  ABI_FREE(redvec)
    3163         [ -  + ]:          72 :  ABI_FREE(symph)
    3164         [ -  + ]:          72 :  ABI_FREE(symind)
    3165                 :             : 
    3166                 :          72 : end subroutine dfpt_symph
    3167                 :             : !!***
    3168                 :             : 
    3169                 :             : !!****f* m_phonons/freeze_displ_allmodes
    3170                 :             : !!
    3171                 :             : !! NAME
    3172                 :             : !! freeze_displ_allmodes
    3173                 :             : !!
    3174                 :             : !! FUNCTION
    3175                 :             : !!  From a given set of phonon modes, generate and output supercells and
    3176                 :             : !!  displaced configurations of atoms.
    3177                 :             : !!  Typically useful to follow soft modes and see distortions of crystal structures
    3178                 :             : !!
    3179                 :             : !! INPUTS
    3180                 :             : !! amu(ntypat) = mass of the atoms (atomic mass unit)
    3181                 :             : !! displ(2,3*natom,3*natom) = phonon mode displacements (complex)
    3182                 :             : !! freeze_displ = amplitude of the displacement to freeze into the supercell
    3183                 :             : !! natom = number of atoms in the unit cell
    3184                 :             : !! ntypat = number of atom types
    3185                 :             : !! phfrq(3*natom) = phonon frequencies
    3186                 :             : !! qphnrm = norm of phonon q vector (should be 1 or 0)
    3187                 :             : !! qphon = phonon wavevector
    3188                 :             : !! rprimd(3,3) = dimensionfull primitive translations in real space
    3189                 :             : !! typat(natom) = integer label of each type of atom (1,2,...)
    3190                 :             : !! xcart(3,natom) = cartesian coords of atoms in unit cell (bohr)
    3191                 :             : !!
    3192                 :             : !! OUTPUT
    3193                 :             : !! for the moment only prints to file, but could also return pointer to supercell object, with
    3194                 :             : !! rprimd and atomic positions, for further use
    3195                 :             : !!
    3196                 :             : !! NOTES
    3197                 :             : !! freeze_displ could be determined automatically from a temperature and the phonon frequency,
    3198                 :             : !! as the average displacement of the mode with a Bose distribution.
    3199                 :             : !!
    3200                 :             : !! SOURCE
    3201                 :             : !!
    3202                 :             : 
    3203                 :          12 : subroutine freeze_displ_allmodes(displ, freeze_displ, natom, outfile_radix, phfreq,  &
    3204         [ -  + ]:           6 :                                  qphon, rprimd, typat, xcart, znucl)
    3205                 :             : 
    3206                 :             : !Arguments ------------------------------------
    3207                 :             : !scalars
    3208                 :             :  integer,intent(in) :: natom
    3209                 :             :  character(len=*),intent(in) :: outfile_radix
    3210                 :             :  real(dp), intent(in) :: freeze_displ
    3211                 :             : !arrays
    3212                 :             :  integer,intent(in) :: typat(natom)
    3213                 :             :  real(dp),intent(in) :: displ(2,3*natom,3*natom), rprimd(3,3), phfreq(3*natom), qphon(3), xcart(3,natom)
    3214                 :             :  real(dp),intent(in) :: znucl(:)
    3215                 :             : 
    3216                 :             : !Local variables-------------------------------
    3217                 :             :  integer :: jmode
    3218                 :           6 :  type(supercell_type) :: scell
    3219                 :             : ! *************************************************************************
    3220                 :             : 
    3221                 :             :  !determine supercell needed to freeze phonon
    3222                 :           6 :  call scell%init_for_qpt(natom, qphon, rprimd, typat, xcart, znucl)
    3223                 :             : 
    3224         [ +  + ]:          42 :  do jmode = 1, 3*natom
    3225                 :             :    ! reset positions
    3226   [ +  -  +  -  :         504 :    scell%xcart = scell%xcart_ref
          -  +  -  -  -  
          -  -  -  +  +  
                   +  + ]
    3227                 :             : 
    3228                 :             :    ! displace atoms according to phonon jmode
    3229                 :          36 :    call scell%freeze_displ(displ(:,:,jmode), freeze_displ)
    3230                 :             : 
    3231                 :             :    ! print out everything for this wavevector and mode
    3232                 :          42 :    call scell%print_for_qpt(phfreq(jmode), jmode, outfile_radix)
    3233                 :             :  end do
    3234                 :             : 
    3235                 :           6 :  call scell%free()
    3236                 :             : 
    3237   [ -  +  -  +  :           6 : end subroutine freeze_displ_allmodes
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    3238                 :             : !!***
    3239                 :             : 
    3240                 :             : !----------------------------------------------------------------------
    3241                 :             : 
    3242                 :             : !!****f* m_phonons/pheigvec_rotate
    3243                 :             : !! NAME
    3244                 :             : !! pheigvec_rotate
    3245                 :             : !!
    3246                 :             : !! FUNCTION
    3247                 :             : !!  Return phonon eigenvectors for q in the BZ from the symmetrical image in the IBZ.
    3248                 :             : !!  Note that the isym index is supposed to have been computed in kpts_map with the symrec convention.
    3249                 :             : !!
    3250                 :             : !! INPUTS
    3251                 :             : !!  cryst: crystal structure
    3252                 :             : !!  qq_ibz: q-point in the IBZ
    3253                 :             : !!  isym
    3254                 :             : !!  itimrev
    3255                 :             : !!  eigvec_ibz: Input phonon eigenvectors at qq_ibz.
    3256                 :             : !!
    3257                 :             : !! OUTPUT
    3258                 :             : !!  eigvec_bz: phonon eigenvectors at q_bz.
    3259                 :             : !!  displ_cart_qbz: phonon displacement at q_bz in Cartesian coordinates.
    3260                 :             : !!  [displ_red_qbz]: phonon displacement at q_bz in reduced coordinates.
    3261                 :             : 
    3262                 :        4777 : subroutine pheigvec_rotate(cryst, qq_ibz, isym, itimrev, eigvec_ibz, eigvec_qbz, displ_cart_qbz, &
    3263                 :             :                            displ_red_qbz) ! Optional
    3264                 :             : 
    3265                 :             : !Arguments ------------------------------------
    3266                 :             : !scalars
    3267                 :             :  type(crystal_t),intent(in) :: cryst
    3268                 :             :  integer,intent(in) :: isym, itimrev
    3269                 :             :  real(dp),intent(in) :: qq_ibz(3), eigvec_ibz(2,3*cryst%natom,3*cryst%natom)
    3270                 :             :  real(dp),intent(out) :: eigvec_qbz(2,3*cryst%natom,3*cryst%natom)
    3271                 :             :  real(dp),intent(out) :: displ_cart_qbz(2,3*cryst%natom,3*cryst%natom)
    3272                 :             :  real(dp),optional,intent(out) :: displ_red_qbz(2,3*cryst%natom,3*cryst%natom)
    3273                 :             : 
    3274                 :             : !Local variables-------------------------------
    3275                 :             : !scalars
    3276                 :             :  integer :: natom, natom3, idir, iat, jdir, iat_sym !, isym_inv
    3277                 :             :  real(dp) :: arg
    3278                 :             : !arrays
    3279                 :             :  integer :: r0(3)
    3280                 :        9554 :  real(dp) :: gamma_matrix(2,3,cryst%natom,3,cryst%natom)
    3281                 :             :  real(dp) :: symat(3,3), phase(2) !, dum(0, 0), gamma2(2,3,cryst%natom,3,cryst%natom)
    3282                 :             : !************************************************************************
    3283                 :             : 
    3284                 :        4777 :  natom = cryst%natom; natom3 = cryst%natom * 3
    3285   [ +  +  +  + ]:       62101 :  symat = cryst%symrel_cart(:,:,isym)
    3286                 :             : 
    3287                 :             :  ! Build Gamma matrix in Cartesian coordinates.
    3288                 :             :  ! e(S q_ibz) = Gamma({S, v}) e(q_ibz)
    3289   [ +  +  +  +  :      542819 :  gamma_matrix = zero
          +  +  +  +  +  
                      + ]
    3290         [ +  + ]:       13550 :  do iat=1,natom
    3291                 :             :    !do iat_sym=1,natom
    3292                 :             :    ! $ R^{-1} (xred(:,iat)-\tau) = xred(:,iat_sym) + R_0 $
    3293                 :             :    !   indsym(4,  isym,iat) gives iat_sym in the original unit cell.
    3294                 :             :    !   indsym(1:3,isym,iat) gives the lattice vector $R_0$.
    3295                 :        8773 :    iat_sym = cryst%indsym(4, isym, iat)
    3296         [ +  + ]:       35092 :    r0 = cryst%indsym(1:3, isym, iat)
    3297         [ +  + ]:       35092 :    arg = two_pi * dot_product(qq_ibz, real(r0))
    3298         [ +  + ]:       26319 :    phase(:) = [cos(arg), sin(arg)] !; write(std_out, *)" ro: ", r0, "phase: " ,phase, "qq_ibz: ", qq_ibz
    3299         [ +  + ]:       39869 :    do jdir=1,3
    3300         [ +  + ]:      114049 :      do idir=1,3
    3301         [ +  + ]:      263190 :        gamma_matrix(:, idir, iat, jdir, iat_sym) = symat(idir, jdir) * phase(:)
    3302                 :             :      end do
    3303                 :             :    end do
    3304                 :             :  end do
    3305                 :             : 
    3306                 :             :  !write(std_out, "(2a)")" Gamma_matrix for qq_bz:", trim(ktoa(qq_bz))
    3307                 :             :  !call print_arr([std_out], reshape(cmplx(gamma_matrix(1,:,:,:,:), gamma_matrix(2,:,:,:,:)), [natom3, natom3]))
    3308                 :             :  !gamma2 = gamma_matrix
    3309                 :             :  !call cg_zgemm("C", "N", natom3, natom3, natom3, gamma_matrix, gamma2, eigvec_qbz)
    3310                 :             :  !write(std_out, "(a)")" gamma^H gamma:"
    3311                 :             :  !call print_arr([std_out], reshape(cmplx(eigvec_qbz(1,:,:), eigvec_qbz(2,:,:)), [natom3, natom3]))
    3312                 :             :  !call cg_check_unitary(natom3, gamm_matrix)
    3313                 :             : 
    3314                 :        4777 :  call cg_zgemm("N", "N", natom3, natom3, natom3, gamma_matrix, eigvec_ibz, eigvec_qbz)
    3315   [ +  +  +  +  :       15781 :  if (itimrev == 1) eigvec_qbz(2,:,:) = -eigvec_qbz(2,:,:)
                   +  + ]
    3316                 :             : 
    3317                 :             :  ! Fix the phase of the eigenvectors
    3318                 :             :  !call fxphas_seq(eigvec_qbz, dum, 0, 0, 1, 3*natom*3*natom, 0, 3*natom, 3*natom, 0)
    3319                 :             :  ! Normalise the eigenvectors
    3320                 :             :  !call pheigvec_normalize(natom, eigvec_qbz)
    3321                 :             : 
    3322                 :             :  ! Compute phonon displacements in Cartesian coordinates
    3323                 :        4777 :  call phdispl_from_eigvec(cryst%natom, cryst%ntypat, cryst%typat, cryst%amu, eigvec_qbz, displ_cart_qbz)
    3324                 :             : 
    3325                 :             :  ! Compute phonon displacements in reduced coordinates.
    3326         [ +  + ]:        4777 :  if (present(displ_red_qbz)) call phdispl_cart2red(cryst%natom, cryst%gprimd, displ_cart_qbz, displ_red_qbz)
    3327                 :             : 
    3328                 :        4777 : end subroutine pheigvec_rotate
    3329                 :             : !!***
    3330                 :             : 
    3331                 :             : !----------------------------------------------------------------------
    3332                 :             : 
    3333                 :             : !!****f* m_phonons/phstore_init
    3334                 :             : !! NAME
    3335                 :             : !! phstore_init
    3336                 :             : !!
    3337                 :             : !! FUNCTION
    3338                 :             : !!  Create new object with phonon quantities in the IBZ.
    3339                 :             : !!
    3340                 :             : !! INPUTS
    3341                 :             : !!  cryst: Crystal structure
    3342                 :             : !!  ifc: Interatomic force constants.
    3343                 :             : !!  nqibz: Number of q-points in the IBZ.
    3344                 :             : !!  qibz: q-points in the IBZ
    3345                 :             : !!  use_ifc_fourq:  True to replace symmetrization with call to ifc_fourq (debugging option)
    3346                 :             : !!  comm: MPI communicator in which phonon arrays in the IBZ will be MPI distributed.
    3347                 :             : 
    3348         [ +  - ]:          58 : subroutine phstore_init(new, cryst, ifc, nqibz, qibz, use_ifc_fourq, comm)
    3349                 :             : 
    3350                 :             : !Arguments ------------------------------------
    3351                 :             :  class(phstore_t),intent(out) :: new
    3352                 :             :  type(crystal_t),intent(in) :: cryst
    3353                 :             :  type(ifc_type),intent(in) :: ifc
    3354                 :             :  integer,intent(in) :: nqibz, comm
    3355                 :             :  logical,intent(in) :: use_ifc_fourq
    3356                 :             :  real(dp),target,intent(in) :: qibz(3, nqibz)
    3357                 :             : 
    3358                 :             : !Local variables ------------------------------
    3359                 :             : !scalars
    3360                 :             :  integer :: natom3, my_q1, my_q2, iq_ibz
    3361                 :             :  character(len=500) :: msg
    3362                 :             : ! *************************************************************************
    3363                 :             : 
    3364                 :          58 :  new%qibz => qibz
    3365                 :             : 
    3366                 :          58 :  new%natom = cryst%natom; natom3 = cryst%natom * 3; new%natom3 = natom3
    3367                 :          58 :  new%comm = comm; new%nprocs = xmpi_comm_size(comm); new%my_rank = xmpi_comm_rank(comm)
    3368                 :          58 :  new%use_ifc_fourq = use_ifc_fourq
    3369                 :             : 
    3370   [ -  +  +  -  :         232 :  ABI_MALLOC(new%displ_cart, (2, 3, cryst%natom, natom3))
          -  +  +  -  +  
          -  +  -  -  +  
             -  +  -  + ]
    3371   [ +  -  -  +  :         232 :  ABI_MALLOC(new%phfrq, (3*cryst%natom))
          +  -  +  -  +  
          -  -  +  -  +  
                   -  + ]
    3372         [ -  + ]:          58 :  if (new%use_ifc_fourq) return
    3373                 :             : 
    3374                 :             :  ! Split qibz in blocks inside comm
    3375   [ -  +  +  -  :         174 :  ABI_MALLOC(new%qibz_start, (0:new%nprocs-1))
          +  -  +  -  -  
             +  -  +  -  
                      + ]
    3376   [ -  +  +  -  :         116 :  ABI_MALLOC(new%qibz_stop, (0:new%nprocs-1))
          -  +  -  +  -  
                      + ]
    3377                 :          58 :  call xmpi_split_work2_i4b(nqibz, new%nprocs, new%qibz_start, new%qibz_stop)
    3378                 :             : 
    3379                 :          58 :  my_q1 = new%qibz_start(new%my_rank)
    3380                 :          58 :  my_q2 = new%qibz_stop(new%my_rank)
    3381                 :             : 
    3382                 :          58 :  call wrtout(std_out, " Computing all phonon frequencies and eigenvectors in the IBZ.", pre_newlines=1)
    3383                 :          58 :  call wrtout(std_out, sjoin(" Number of IBZ q-points stored by this rank inside pert_comm:", itoa(my_q2 - my_q1 + 1)))
    3384                 :             :  write(msg, "(a,f8.1,a)") &
    3385                 :          58 :    " Memory required by pheigvec_qibz: ", 2 * natom3**2 * (my_q2 - my_q1 + 1) * dp * b2Mb, " [Mb] <<< MEM"
    3386                 :          58 :  call wrtout(std_out, msg)
    3387                 :             : 
    3388   [ -  +  +  -  :         232 :  ABI_MALLOC(new%phfreqs_qibz, (natom3, my_q1:my_q2))
          -  +  +  -  +  
          -  +  -  -  +  
             -  +  -  + ]
    3389   [ -  +  +  -  :         290 :  ABI_MALLOC(new%pheigvec_qibz, (2, natom3, natom3, my_q1:my_q2))
          -  +  +  -  -  
          +  +  -  +  -  
          +  -  -  +  -  
                +  -  + ]
    3390                 :             : 
    3391         [ +  + ]:        4048 :  do iq_ibz=my_q1, my_q2
    3392                 :             :    call ifc%fourq(cryst, qibz(:,iq_ibz), new%phfreqs_qibz(:, iq_ibz), new%displ_cart, &
    3393                 :        4048 :                   out_eigvec=new%pheigvec_qibz(:,:,:,iq_ibz))
    3394                 :             :  end do
    3395                 :             : 
    3396                 :             : end subroutine phstore_init
    3397                 :             : !!***
    3398                 :             : 
    3399                 :             : !----------------------------------------------------------------------
    3400                 :             : 
    3401                 :             : !!****f* m_phonons/phstore_free
    3402                 :             : !! NAME
    3403                 :             : !! phstore_free
    3404                 :             : !!
    3405                 :             : !! FUNCTION
    3406                 :             : !!  Free dynamic memory.
    3407                 :             : !!
    3408                 :             : !! INPUTS
    3409                 :             : 
    3410                 :          58 : subroutine phstore_free(self)
    3411                 :             : 
    3412                 :             : !Arguments ------------------------------------
    3413                 :             :  class(phstore_t),intent(inout) :: self
    3414                 :             : ! *************************************************************************
    3415                 :             : 
    3416         [ +  - ]:          58 :  ABI_SFREE(self%qibz_start)
    3417         [ +  - ]:          58 :  ABI_SFREE(self%qibz_stop)
    3418         [ +  - ]:          58 :  ABI_SFREE(self%phfreqs_qibz)
    3419         [ +  - ]:          58 :  ABI_SFREE(self%pheigvec_qibz)
    3420         [ +  - ]:          58 :  ABI_SFREE(self%displ_cart)
    3421         [ +  - ]:          58 :  ABI_SFREE(self%phfrq)
    3422                 :             : 
    3423                 :          58 :  self%qibz => null()
    3424                 :             : 
    3425                 :          58 : end subroutine phstore_free
    3426                 :             : !!***
    3427                 :             : 
    3428                 :             : !----------------------------------------------------------------------
    3429                 :             : 
    3430                 :             : !!****f* m_phonons/phstore_async_rotate
    3431                 :             : !! NAME
    3432                 :             : !! phstore_async_rotate
    3433                 :             : !!
    3434                 :             : !! FUNCTION
    3435                 :             : !!  Begin non-blocking collective MPI communication inside self%comm to obtain
    3436                 :             : !!  phonon frequencies and eigenvectors in the BZ from data in the IBZ.
    3437                 :             : !!
    3438                 :             : !! INPUTS
    3439                 :             : 
    3440                 :        4852 : subroutine phstore_async_rotate(self, cryst, ifc, iq_ibz, qpt_ibz, qpt_bz, isym_q, trev_q)
    3441                 :             : 
    3442                 :             : !Arguments ------------------------------------
    3443                 :             :  class(phstore_t),intent(inout) :: self
    3444                 :             :  type(crystal_t), intent(in) :: cryst
    3445                 :             :  type(ifc_type),intent(in) :: ifc
    3446                 :             :  integer,intent(in) :: iq_ibz, isym_q, trev_q
    3447                 :             :  real(dp),intent(in) :: qpt_ibz(3), qpt_bz(3)
    3448                 :             : 
    3449                 :             : !Local variables ------------------------------
    3450                 :             : !scalars
    3451                 :             :  integer :: rank, master, ierr
    3452                 :             :  logical :: isirr_q
    3453                 :        4852 :  real(dp) :: eigvec_qpt(2, self%natom3, self%natom3)
    3454                 :             : ! *************************************************************************
    3455                 :             : 
    3456                 :             :  ABI_UNUSED(qpt_ibz(1))
    3457                 :             : 
    3458         [ -  + ]:        4852 :  if (self%use_ifc_fourq) then
    3459                 :             :    ! Debugging section.
    3460                 :           0 :    call ifc%fourq(cryst, qpt_bz, self%phfrq, self%displ_cart); return
    3461                 :             :  end if
    3462                 :             : 
    3463                 :             :  ! Find the MPI rank storing the q-point in the IBZ.
    3464         [ +  - ]:        4852 :  do rank=0,self%nprocs-1
    3465   [ +  -  +  - ]:        4852 :    if (iq_ibz >= self%qibz_start(rank) .and. iq_ibz <= self%qibz_stop(rank)) then
    3466                 :        4852 :      master = rank; exit
    3467                 :             :    end if
    3468                 :             :  end do
    3469         [ -  + ]:        4852 :  ABI_CHECK(rank /= self%nprocs, sjoin("Nobody has iq_ibz: ", itoa(iq_ibz)))
    3470                 :             : 
    3471                 :             :  ! Begin non-blocking communication for phfrq frequencies.
    3472   [ +  -  +  -  :       36260 :  if (self%my_rank == master) self%phfrq = self%phfreqs_qibz(:, iq_ibz)
          -  +  -  -  +  
                      + ]
    3473                 :        4852 :  call xmpi_ibcast(self%phfrq, master, self%comm, self%requests(1), ierr)
    3474                 :             : 
    3475                 :             :  ! Rotate eigvectors at q_ibz to get eigenvector at q_bz
    3476                 :             :  ! Don't test if umklapp == 0 because we use the periodic gauge:
    3477                 :             :  !
    3478                 :             :  !   phfreq(q+G) = phfreq(q) and eigvec(q) = eigvec(q+G)
    3479                 :             :  !
    3480   [ +  +  +  + ]:        4852 :  isirr_q = isym_q == 1 .and. trev_q == 0
    3481                 :             : 
    3482         [ +  - ]:        4852 :  if (self%my_rank == master) then
    3483                 :             :    ! I own the data --> operate on it
    3484         [ +  + ]:        4852 :    if (isirr_q) then
    3485                 :             :      ! q in IBZ --> no rotation is needed.
    3486                 :             :      call phdispl_from_eigvec(cryst%natom, cryst%ntypat, cryst%typat, cryst%amu, &
    3487                 :        2014 :                               self%pheigvec_qibz(:,:,:,iq_ibz), self%displ_cart)
    3488                 :             :    else
    3489                 :             :      ! q in BZ --> rotate phonon eigenvectors.
    3490                 :             :      call pheigvec_rotate(cryst, self%qibz(:, iq_ibz), isym_q, trev_q, self%pheigvec_qibz(:,:,:,iq_ibz), &
    3491                 :        2838 :                           eigvec_qpt, self%displ_cart)
    3492                 :             :    end if
    3493                 :             :  end if
    3494                 :             : 
    3495                 :             :  ! Begin non-blocking bcast for displ_cart. Caller must wait (use phstore_wait)
    3496                 :        4852 :  call xmpi_ibcast(self%displ_cart, master, self%comm, self%requests(2), ierr)
    3497                 :             : 
    3498                 :             : end subroutine phstore_async_rotate
    3499                 :             : !!***
    3500                 :             : 
    3501                 :             : !----------------------------------------------------------------------
    3502                 :             : 
    3503                 :             : !!****f* m_phonons/phstore_wait
    3504                 :             : !! NAME
    3505                 :             : !! phstore_wait
    3506                 :             : !!
    3507                 :             : !! FUNCTION
    3508                 :             : !!  Wait from non-blocking MPI BCAST started in phstore_async_rotate,
    3509                 :             : !!  returns phonon frequencies and displacements in Cartesian and reduced coordinates.
    3510                 :             : !!
    3511                 :             : !! INPUTS
    3512                 :             : 
    3513                 :        4852 : subroutine phstore_wait(self, cryst, phfrq, displ_cart, displ_red)
    3514                 :             : 
    3515                 :             : !Arguments ------------------------------------
    3516                 :             :  class(phstore_t),intent(inout) :: self
    3517                 :             :  type(crystal_t),intent(in) :: cryst
    3518                 :             :  real(dp) ABI_ASYNC, intent(out) :: phfrq(self%natom3)
    3519                 :             :  real(dp) ABI_ASYNC, intent(out) :: displ_cart(2, 3, self%natom, self%natom3)
    3520                 :             :  real(dp),intent(out) :: displ_red(2, 3, self%natom, self%natom3)
    3521                 :             : 
    3522                 :             : !Local variables ------------------------------
    3523                 :             :  integer :: ierr
    3524                 :             : ! *************************************************************************
    3525                 :             : 
    3526         [ +  - ]:        4852 :  if (.not. self%use_ifc_fourq) call xmpi_waitall(self%requests, ierr)
    3527         [ +  + ]:       31408 :  phfrq = self%phfrq
    3528   [ +  +  +  +  :      536968 :  displ_cart = self%displ_cart
             +  +  +  + ]
    3529                 :        4852 :  call phdispl_cart2red(cryst%natom, cryst%gprimd, displ_cart, displ_red)
    3530                 :             : 
    3531                 :        4852 : end subroutine phstore_wait
    3532                 :             : !!***
    3533                 :             : 
    3534                 :             : !----------------------------------------------------------------------
    3535                 :             : 
    3536                 :             : !!****f* m_phonons/test_phrotation
    3537                 :             : !! NAME
    3538                 :             : !! test_phrotation
    3539                 :             : !!
    3540                 :             : !! FUNCTION
    3541                 :             : !!  Test the symmetrization of the phonon eigenvalues and eigenvectors.
    3542                 :             : !!
    3543                 :             : !! INPUT
    3544                 :             : !!  cryst=Crystalline structure
    3545                 :             : !!  ifc<ifc_type>=interatomic force constants and corresponding real space grid info.
    3546                 :             : !!  ngqpt(3)=Divisions of the ab-initio q-mesh.
    3547                 :             : !!  qptopt=option for the generation of q points (defines whether spatial symmetries and/or time-reversal can be used)
    3548                 :             : !!  comm= MPI communicator
    3549                 :             : 
    3550                 :           0 : subroutine test_phrotation(ifc, cryst, qptopt, ngqpt, comm)
    3551                 :             : 
    3552                 :             : !Arguments ------------------------------------
    3553                 :             :  type(ifc_type),intent(in) :: ifc
    3554                 :             :  type(crystal_t),intent(in) :: cryst
    3555                 :             :  integer,intent(in) :: qptopt, comm, ngqpt(3)
    3556                 :             : 
    3557                 :             : !Local variables-------------------------------
    3558                 :             : !scalars
    3559                 :             :  integer,parameter :: nqshft1 = 1, master = 0
    3560                 :             :  integer :: nqibz, iq_bz, iq_ibz, nqbz, ii, natom, natom3, ierr
    3561                 :             :  integer :: isym, itimrev, ierr_freq, ierr_eigvec, prtvol
    3562                 :             :  real(dp), parameter ::  tol_phfreq_meV = tol3, tol_eigvec = tol6
    3563                 :             :  real(dp) :: maxerr_phfreq, err_phfreq, maxerr_eigvec ! err_eigvec
    3564                 :             :  logical :: isirr_q
    3565                 :             :  character(len=500) :: msg, fmt_freqs, fmt_eigvec
    3566                 :           0 :  type(krank_t) :: qrank
    3567                 :             : !arrays
    3568                 :             :  integer :: in_qptrlatt(3,3), new_qptrlatt(3,3), g0(3)
    3569                 :           0 :  integer,allocatable :: bz2ibz(:,:), bz2ibz_listkk(:,:), toinv(:,:)
    3570                 :           0 :  real(dp) :: qshift(3, nqshft1), phfrq(3*cryst%natom), work(3*cryst%natom)
    3571                 :           0 :  real(dp) :: eigvec_out(2,3*cryst%natom,3*cryst%natom) !eigvec_ibz(2,3*cryst%natom,3*cryst%natom),
    3572                 :           0 :  real(dp) :: eigvec_bz(2,3*cryst%natom,3*cryst%natom), displ_cart_qbz(2,3*cryst%natom,3*cryst%natom)
    3573                 :           0 :  real(dp) :: d2cart(2,3*cryst%natom,3*cryst%natom), d2tmp(2,3*cryst%natom,3*cryst%natom)
    3574                 :           0 :  real(dp),allocatable :: wtq_ibz(:), qbz(:,:), qibz(:,:), displ_cart(:,:,:,:),displ_red(:,:,:,:)
    3575                 :           0 :  real(dp),allocatable :: phfreqs_qibz(:,:), displ_cart_ibz(:,:,:,:),eigvec_ibz(:,:,:,:)
    3576                 :             : !************************************************************************
    3577                 :             : 
    3578         [ #  # ]:           0 :  if (xmpi_comm_rank(comm) /= 0) return
    3579                 :             : 
    3580                 :           0 :  call wrtout(std_out, sjoin(" Testing symmetrization of phonon frequencies and eigenvectors with ngqpt:", ltoa(ngqpt)), ch10)
    3581                 :           0 :  prtvol = 1; natom = cryst%natom; natom3 = cryst%natom * 3
    3582                 :             : 
    3583                 :             :  ! Create a regular grid
    3584                 :           0 :  in_qptrlatt = 0; in_qptrlatt(1, 1) = ngqpt(1); in_qptrlatt(2, 2) = ngqpt(2); in_qptrlatt(3, 3) = ngqpt(3)
    3585                 :           0 :  qshift = zero
    3586                 :             : 
    3587                 :             :  call kpts_ibz_from_kptrlatt(cryst, in_qptrlatt, qptopt, nqshft1, qshift, &
    3588                 :           0 :                              nqibz, qibz, wtq_ibz, nqbz, qbz, new_kptrlatt=new_qptrlatt, bz2ibz=bz2ibz)
    3589         [ #  # ]:           0 :  ABI_FREE(bz2ibz)
    3590                 :             : 
    3591                 :             :  !write(std_out, "(2(a, i0))")" nqibz: ", nqibz, ", nqbz:", nqbz
    3592                 :             :  !write(std_out, "(a)") " qibz_list:"
    3593                 :             :  !do iq_ibz=1,nqibz
    3594                 :             :  !  write(std_out, "(a)")trim(ltoa(qibz(:,iq_ibz)))
    3595                 :             :  !end do
    3596                 :             :  !call cryst%print(unit=std_out)
    3597                 :             :  !write(std_out, *)""
    3598                 :             : 
    3599                 :             :  ! Compute BZ --> IBZ mapping.
    3600   [ #  #  #  #  :           0 :  ABI_MALLOC(bz2ibz_listkk, (6, nqbz))
          #  #  #  #  #  
                #  #  # ]
    3601                 :             : 
    3602                 :           0 :  call qrank%from_kptrlatt(nqibz, qibz, in_qptrlatt, compute_invrank=.False.)
    3603                 :             : 
    3604         [ #  # ]:           0 :  if (kpts_map("symrec", qptopt, cryst, qrank, nqbz, qbz, bz2ibz_listkk) /= 0) then
    3605                 :           0 :    write(msg, '(3a)' ) "Error mapping BZ to IBZ",ch10,"The q-point could not be generated from a symmetrical one"
    3606                 :           0 :    ABI_ERROR(msg)
    3607                 :             :  end if
    3608                 :             : 
    3609                 :           0 :  call qrank%free()
    3610                 :             : 
    3611                 :             :  ! Compute ph freqs in the IBZ.
    3612   [ #  #  #  #  :           0 :  ABI_CALLOC(phfreqs_qibz, (natom3, nqibz))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    3613   [ #  #  #  #  :           0 :  ABI_CALLOC(displ_cart_ibz, (2, natom3, natom3, nqibz))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    3614   [ #  #  #  #  :           0 :  ABI_CALLOC(eigvec_ibz, (2, natom3, natom3, nqibz))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    3615                 :             : 
    3616         [ #  # ]:           0 :  do iq_ibz=1,nqibz
    3617                 :             :    call ifc%fourq(cryst, qibz(:,iq_ibz), phfreqs_qibz(:,iq_ibz), displ_cart_ibz(:,:,:,iq_ibz), &
    3618                 :           0 :                   out_eigvec=eigvec_ibz(:,:,:,iq_ibz))
    3619                 :             :  end do
    3620                 :             : 
    3621   [ #  #  #  #  :           0 :  ABI_MALLOC(displ_cart, (2, 3, cryst%natom, natom3))
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    3622   [ #  #  #  #  :           0 :  ABI_MALLOC(displ_red, (2, 3, cryst%natom, natom3))
          #  #  #  #  #  
                #  #  # ]
    3623                 :             : 
    3624   [ #  #  #  #  :           0 :  ABI_MALLOC(toinv, (4, cryst%nsym))
          #  #  #  #  #  
                #  #  # ]
    3625                 :           0 :  call sg_multable(cryst%nsym, cryst%symafm, cryst%symrel, ierr, toinv=toinv, tnons=cryst%tnons, tnons_tol=tol6)
    3626         [ #  # ]:           0 :  ABI_CHECK(ierr == 0, "sg_multable returned ierr != 0")
    3627                 :             : 
    3628                 :             :  ! Precompute ph freqs in the BZ and compare with BZ
    3629                 :           0 :  ierr_freq = 0; ierr_eigvec = 0
    3630         [ #  # ]:           0 :  fmt_freqs = sjoin("(a, ", itoa(natom3), "(f7.3, 1x))")
    3631         [ #  # ]:           0 :  fmt_eigvec = sjoin("(a, i0, 1x, a, ", itoa(natom3), "(f12.9, 1x))")
    3632                 :           0 :  maxerr_phfreq = zero; maxerr_eigvec = zero
    3633                 :             : 
    3634         [ #  # ]:           0 :  do iq_bz=1,nqbz
    3635                 :           0 :    call ifc%fourq(cryst, qbz(:, iq_bz), phfrq, displ_cart, out_eigvec=eigvec_bz, out_d2cart=d2cart)
    3636                 :             : 
    3637                 :           0 :    iq_ibz = bz2ibz_listkk(1, iq_bz); isym = bz2ibz_listkk(2, iq_bz)
    3638                 :           0 :    itimrev = bz2ibz_listkk(6, iq_bz); g0 = bz2ibz_listkk(3:5, iq_bz)
    3639                 :             :    isirr_q = isym == 1 .and. itimrev == 0 .and. all(g0 == 0)
    3640                 :             : 
    3641                 :             :    ! Compare phfreqs within tol in meV.
    3642   [ #  #  #  #  :           0 :    err_phfreq = maxval(abs(phfrq - phfreqs_qibz(:, iq_ibz))) * Ha_meV
             #  #  #  # ]
    3643         [ #  # ]:           0 :    if (err_phfreq > tol_phfreq_meV) then
    3644                 :           0 :      maxerr_phfreq = max(maxerr_phfreq, err_phfreq)
    3645                 :           0 :      write(std_out,*)" " // repeat("=", 92)
    3646   [ #  #  #  # ]:           0 :      write(std_out, "(4a)")" qbz:", trim(ktoa(qbz(:, iq_bz))), " --> qibz:", trim(ktoa(qibz(:, iq_ibz)))
    3647         [ #  # ]:           0 :      write(std_out, fmt_freqs)" w_bz :", phfrq * Ha_meV
    3648         [ #  # ]:           0 :      write(std_out, fmt_freqs)" w_ibz:", phfreqs_qibz(:, iq_ibz) * Ha_meV
    3649                 :           0 :      write(std_out,*)" err_phfreq (meV):", err_phfreq, " > tol: ", tol_phfreq_meV
    3650                 :           0 :      write(std_out,*)" " // repeat("=", 92)
    3651                 :           0 :      ierr_freq = ierr_freq + 1
    3652                 :             :    end if
    3653                 :             : 
    3654                 :             :    ! Rotate and compare eigenvectors
    3655                 :             :    call pheigvec_rotate(cryst, qibz(:, iq_ibz), isym, itimrev, eigvec_ibz(:,:,:,iq_ibz), &
    3656                 :           0 :                         eigvec_out, displ_cart_qbz)
    3657                 :             : 
    3658                 :             :    ! e^H D e = w**2 I
    3659                 :           0 :    call massmult_and_breaksym(natom, cryst%ntypat, cryst%typat, cryst%amu, d2cart)
    3660                 :           0 :    call cg_zgemm("N", "N", natom3, natom3, natom3, d2cart, eigvec_out, d2tmp)
    3661                 :           0 :    call cg_zgemm("C", "N", natom3, natom3, natom3, eigvec_out, d2tmp, d2cart)
    3662         [ #  # ]:           0 :    do ii=1,natom3
    3663                 :           0 :      work(ii) = d2cart(1, ii, ii)
    3664                 :             :    end do
    3665         [ #  # ]:           0 :    work = sqrt(abs(phfrq ** 2 - work)) * Ha_meV
    3666   [ #  #  #  #  :           0 :    if (maxval(work) > tol_phfreq_meV) ierr_eigvec = ierr_eigvec + 1
          #  #  #  #  #  
                      # ]
    3667   [ #  #  #  #  :           0 :    write(std_out, *) "max eig_diff [meV]: ", maxval(work)
             #  #  #  # ]
    3668                 :           0 :    write(std_out, "(a)")" e^H D e (meV**2)"
    3669   [ #  #  #  #  :           0 :    d2cart = d2cart * Ha_meV ** 2
                   #  # ]
    3670   [ #  #  #  #  :           0 :    call print_arr([std_out], reshape(cmplx(d2cart(1,:,:), d2cart(2,:,:), kind=dp), [natom3, natom3]))
          #  #  #  #  #  
                      # ]
    3671                 :             : 
    3672                 :             :    !err_eigvec = maxval(abs(eigvec_out - eigvec_bz))
    3673                 :             :    !if (err_eigvec > tol_eigvec) then
    3674                 :             :    !  maxerr_eigvec = max(maxerr_eigvec, err_eigvec)
    3675                 :             :    !  write(std_out, "(4a)")" qbz:", trim(ktoa(qbz(:, iq_bz))), " --> qibz: ", trim(ktoa(qibz(:, iq_ibz)))
    3676                 :             :    !  write(std_out, "(a,2(i0,1x),a)")" qbz image through isym, itimrev: ", isym, itimrev, trim(ltoa(cryst%tnons(:, isym)))
    3677                 :             :    !  write(std_out, "(a,l1)")" has_r0: ", any(cryst%indsym(1:3, isym, :) /= 0)
    3678                 :             :    !  write(std_out, *) "err_eigvec ", err_eigvec, " > tol:", tol_eigvec
    3679                 :             :    !  do ii=1,natom3
    3680                 :             :    !    if (all(abs(eigvec_out(:,:,ii) - eigvec_bz(:,:,ii)) < tol_eigvec)) cycle
    3681                 :             :    !    if (prtvol > 0) then
    3682                 :             :    !      write(std_out, "(a, 2(f12.9,1x))") " diff (re/im): ", &
    3683                 :             :    !        maxval(abs(eigvec_out(1,:,ii) - eigvec_bz(1,:,ii))), maxval(abs(eigvec_out(2,:,ii) - eigvec_bz(2,:,ii)))
    3684                 :             :    !      write(std_out, fmt_eigvec) " mode: ", ii, "re_sym: ", eigvec_out(1,:,ii)
    3685                 :             :    !      write(std_out, fmt_eigvec) " mode: ", ii, "re_bz : ", eigvec_bz(1,:,ii)
    3686                 :             :    !      write(std_out, fmt_eigvec) " mode: ", ii, "im_sym: ", eigvec_out(2,:,ii)
    3687                 :             :    !      write(std_out, fmt_eigvec) " mode: ", ii, "im_bz : ", eigvec_bz(2,:,ii)
    3688                 :             :    !    end if
    3689                 :             :    !  end do
    3690                 :             :    !  write(std_out,*)" " // repeat("=", 92)
    3691                 :             :    !  ierr_eigvec = ierr_eigvec + 1
    3692                 :             :    !end if
    3693                 :             : 
    3694                 :             :  end do
    3695                 :             : 
    3696                 :           0 :  write(std_out,*)" === Final results ==="
    3697                 :           0 :  write(std_out,*)" maxerr_phfreq (meV): ", maxerr_phfreq
    3698                 :           0 :  write(std_out,*)" percentage of erroneous q-points for phfreq: ", ierr_freq / (one * nqbz) * 100, "%"
    3699                 :           0 :  write(std_out,*)""
    3700                 :             :  !write(std_out,*)" maxerr_eigvec: ", maxerr_eigvec
    3701                 :           0 :  write(std_out,*)" percentage of q-points for eigvec: ", ierr_eigvec / (one * nqbz) * 100, "%"
    3702                 :           0 :  write(std_out,*)""
    3703                 :             : 
    3704         [ #  # ]:           0 :  if (ierr_freq /= 0) then
    3705                 :           0 :    ABI_ERROR("Wrong symmetrization in phonon eigenvalues.")
    3706         [ #  # ]:           0 :  else if (ierr_eigvec /= 0) then
    3707                 :           0 :    ABI_ERROR("Wrong symmetrization in phonon eigenvectors.")
    3708                 :             :  else
    3709                 :           0 :    write(std_out, "(a)")" ALL OK: No error detected!"
    3710                 :             :  end if
    3711                 :             : 
    3712         [ #  # ]:           0 :  ABI_FREE(displ_cart)
    3713         [ #  # ]:           0 :  ABI_FREE(displ_red)
    3714         [ #  # ]:           0 :  ABI_SFREE(bz2ibz_listkk)
    3715         [ #  # ]:           0 :  ABI_SFREE(qbz)
    3716         [ #  # ]:           0 :  ABI_SFREE(qibz)
    3717         [ #  # ]:           0 :  ABI_SFREE(wtq_ibz)
    3718         [ #  # ]:           0 :  ABI_FREE(phfreqs_qibz)
    3719         [ #  # ]:           0 :  ABI_FREE(displ_cart_ibz)
    3720         [ #  # ]:           0 :  ABI_FREE(eigvec_ibz)
    3721         [ #  # ]:           0 :  ABI_FREE(toinv)
    3722                 :             : 
    3723   [ #  #  #  #  :           0 : end subroutine test_phrotation
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    3724                 :             : !!***
    3725                 :             : 
    3726   [ -  +  -  -  :        1253 : end module m_phonons
          +  +  -  +  +  
          -  -  +  -  +  
          +  -  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                   -  + ]
    3727                 :             : !!***
        

Generated by: LCOV version 2.3-1