LCOV - code coverage report
Current view: top level - src/77_ddb - m_ifc.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.2 % 1141 984
Test Date: 2026-09-19 17:42:43 Functions: 77.3 % 22 17

            Line data    Source code
       1              : !!****m* ABINIT/m_ifc
       2              : !! NAME
       3              : !!  m_ifc
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module contains the declaration of data types and methods
       7              : !!  used to handle interatomic force constants.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2011-2026 ABINIT group (XG,MJV,EB,MG,GA)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public License, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! SOURCE
      16              : 
      17              : #if defined HAVE_CONFIG_H
      18              : #include "config.h"
      19              : #endif
      20              : 
      21              : #include "abi_common.h"
      22              : 
      23              : MODULE m_ifc
      24              : 
      25              :  use defs_basis
      26              :  use m_errors
      27              :  use m_abicore
      28              :  use m_xmpi
      29              :  use m_sort
      30              :  use m_cgtools
      31              :  use m_ddb
      32              :  use m_ddb_hdr
      33              :  use m_symkpt
      34              :  use netcdf
      35              :  use m_nctk
      36              : 
      37              :  use m_io_tools,      only : open_file
      38              :  use m_numeric_tools, only : arth
      39              :  use m_fstrings,      only : ktoa, int2char4, sjoin, itoa, ltoa, ftoa
      40              :  use m_matrix,        only : matr3inv
      41              :  use m_special_funcs, only : abi_derfc
      42              :  use m_time,          only : cwtime, cwtime_report, timab
      43              :  use m_copy,          only : alloc_copy
      44              :  use m_pptools,       only : printbxsf
      45              :  use m_lebedev,       only : lebedev_t, lebedev_ngrids
      46              :  use m_ewald,         only : ewald9, ewald9_2D
      47              :  use m_crystal,       only : crystal_t
      48              :  use m_geometry,      only : phdispl_cart2red, normv, mkrdim
      49              :  use m_kpts,          only : kpts_ibz_from_kptrlatt, smpbz
      50              :  use m_bz_mesh,       only : kpath_t
      51              :  use m_dynmat,        only : canct9, dist9 , ifclo9, axial9, q0dy3_apply, q0dy3_calc, asrif9, dynmat_dq, &
      52              :                              make_bigbox, canat9, chkrp9, ftifc_q2r, wght9, nanal9, gtdyn9, dymfz9, &
      53              :                              massmult_and_breaksym, dfpt_phfrq, dfpt_prtph, d2cart_to_red, ftifc_r2q
      54              : 
      55              :  implicit none
      56              : 
      57              :  private
      58              : 
      59              :  public :: defwrite_nonana_terms
      60              :  ! Write to ncfile the phonon frequencies and displacements for q --> 0
      61              :  ! in the presence of non-analytical behaviour.
      62              : !!***
      63              : 
      64              : !!****t* m_ifc/ifc_type
      65              : !! NAME
      66              : !! ifc_type
      67              : !!
      68              : !! FUNCTION
      69              : !!  Contains the necessary data to interpolate the
      70              : !!  phonon bandstructure and eigenvectors in reciprocal space (ie.
      71              : !!  interatomic force constants and corresponding real space grid info).
      72              : !!
      73              : !! SOURCE
      74              : 
      75              :  type,public :: ifc_type
      76              : 
      77              :    integer :: natom = -1
      78              :      ! Number of atoms in the unit cell.
      79              : 
      80              :    integer :: mpert = -1
      81              :      ! Maximum number of ipert.
      82              : 
      83              :    integer :: asr = -1
      84              :      ! Option for the treatment of the Acoustic Sum Rule.
      85              : 
      86              :    integer :: brav = -1
      87              :      ! Option for the sampling of the BZ (anaddb input variable)
      88              : 
      89              :    real(dp) :: dielt_env = one
      90              :      ! Dielectric constant of environment for 2D materials electrostatics
      91              : 
      92              :    real(dp) :: dielt_thick(2) = zero
      93              :      ! Dielectric thickness of the 2D materials for electrostatics
      94              : 
      95              :    integer :: sys_dim = 1
      96              :      ! System dimmensionality for electrostatic treatment + rotational invariance
      97              : 
      98              :    integer :: dipdip = -1
      99              :      ! dipole dipole interaction flag.
     100              : 
     101              :    integer :: dipquad = -1
     102              :      ! dipole quadrupole interaction flag.
     103              : 
     104              :    integer :: quadquad = -1
     105              :      ! dipole quadrupole interaction flag.
     106              : 
     107              :    integer :: symdynmat = -1
     108              :      ! If equal to 1, the dynamical matrix is symmetrized in dfpt_phfrq before the diagonalization.
     109              : 
     110              :    integer :: nqshft = -1
     111              :      ! Number of shifts in the q-mesh (usually 1 since the mesh is gamma-centered!)
     112              : 
     113              :    integer :: nqibz = -1
     114              :      ! Number of points in the IBZ
     115              : 
     116              :    integer :: nqbz = -1
     117              :      ! Number of points in the full BZ
     118              : 
     119              :    integer :: nrpt = -1
     120              :      ! Number of real space points used to integrate IFC (for interpolation of dynamical matrices)
     121              : 
     122              :    integer :: ngqpt(3) = -1
     123              :     ! Number of division in the Q mesh.
     124              : 
     125              :    integer :: ewald_option = -1
     126              :     ! Option for the ewald sum
     127              : 
     128              :    real(dp) :: eta = -one
     129              :     ! eta: parameter used to split R and G-space summation. See ewald9.
     130              : 
     131              :    real(dp) :: rprim(3,3),gprim(3,3),acell(3)
     132              :      ! These values are used to call anaddb routines that don't use rprimd, gprimd
     133              : 
     134              :    real(dp) :: dielt(3,3)
     135              :      ! Dielectric tensor (Cartesian coordinates)
     136              : 
     137              :    real(dp) :: omega_minmax(2)
     138              :      ! Min and max frequency obtained on the initial ab-initio q-mesh (-+ 30 cmm1)
     139              :      ! Used to generate frequency meshes for DOSes.
     140              : 
     141              :    real(dp) :: r_inscribed_sphere
     142              :      ! radius of biggest sphere inscribed in the WS supercell
     143              : 
     144              :    real(dp),allocatable :: amu(:)
     145              :      ! amu(ntypat)
     146              :      ! mass of the atoms (atomic mass unit)
     147              : 
     148              :    real(dp),allocatable :: atmfrc(:,:,:,:,:)
     149              :      ! atmfrc(3,natom,3,natom,nrpt)
     150              :      ! Inter atomic forces in real space
     151              : 
     152              :    integer,allocatable :: cell(:,:)
     153              :      ! cell(nrpt,3)
     154              :      ! Give the index of the cell and irpt
     155              : 
     156              :    real(dp),allocatable :: ewald_atmfrc(:,:,:,:,:)
     157              :      ! Ewald_atmfrc(3,natom,3,natom,nrpt)
     158              :      ! Ewald Inter atomic forces in real space
     159              : 
     160              :    real(dp),allocatable :: short_atmfrc(:,:,:,:,:)
     161              :      ! short_atmfrc(3,natom,3,natom,nrpt)
     162              :      ! Short range part of Inter atomic forces in real space
     163              : 
     164              :    real(dp),allocatable :: qshft(:,:)
     165              :     ! qshft(3,nqshft)
     166              :     ! The shifts of the q-mesh
     167              : 
     168              :    real(dp), allocatable :: rpt(:,:)
     169              :      ! rpt(3,nrpt)
     170              :      ! Real space points in canonical type coordinates.
     171              : 
     172              :    real(dp),allocatable :: wghatm(:,:,:)
     173              :      ! wghatm(natom,natom,nrpt)
     174              :      ! Weights for each point and atom in the Wigner Seitz supercell in real space.
     175              : 
     176              :    real(dp),allocatable :: rcan(:,:)
     177              :      ! rcan(3,natom)
     178              :      ! Atomic position in canonical coordinates.
     179              : 
     180              :    real(dp),allocatable :: trans(:,:)
     181              :      ! trans(3,natom)
     182              :      ! Atomic translations: xred = rcan + trans
     183              : 
     184              :    real(dp),allocatable :: dyewq0(:,:,:)
     185              :      ! dyewq0(3,3,natom)
     186              :      ! Atomic electrostatic self-interaction correction to the dynamical matrix (only when dipdip = 1).
     187              : 
     188              :    real(dp),allocatable :: zeff(:,:,:)
     189              :      ! zeff(3,3,natom)
     190              :      ! Born effective charge on each atom, versus electric field and atomic displacement.
     191              :      ! Cartesian coordinates
     192              : 
     193              :    real(dp),allocatable :: qdrp_cart(:,:,:,:)
     194              :      ! qdrp_cart(3,3,3,natom)
     195              :      ! Quadrupole tensor on each atom
     196              :      ! Cartesian coordinates
     197              : 
     198              :    real(dp),allocatable :: qibz(:,:)
     199              :      ! qibz(3,nqibz))
     200              :      ! List of q-points in the IBZ
     201              : 
     202              :    real(dp),allocatable :: wtq(:)
     203              :      ! wtq(nqibz))
     204              :      ! q-point Weights.
     205              : 
     206              :    real(dp),allocatable :: qbz(:,:)
     207              :      ! qbz(3,nqbz))
     208              :      ! List of q-points in the full BZ
     209              : 
     210              :    real(dp),allocatable :: dynmat(:,:,:,:,:,:)
     211              :      ! dynmat(2,3,natom,3,natom,nqbz))
     212              :      ! dynamical matrices relative to the q points of the BZ. sampling
     213              :      ! Note that the long-range dip-dip part has been removed if dipdip = 1
     214              :      ! Moreover the array is multiplied by a phase shift in mkifc9.
     215              : 
     216              :  contains
     217              : 
     218              :     procedure :: free => ifc_free
     219              :     ! Release memory.
     220              : 
     221              :     procedure :: print => ifc_print
     222              :      ! Print info on the object.
     223              : 
     224              :     procedure :: fourq => ifc_fourq
     225              :      ! Use Fourier interpolation to compute interpolated frequencies w(q) and eigenvectors e(q).
     226              : 
     227              :       procedure :: get_dcdq => ifc_get_dcdq
     228              :     !  Compute first derivative of reciprocal-space IFCs based on IFCs.
     229              : 
     230              :     procedure :: get_dwdq => ifc_get_dwdq
     231              :     !  Compute phonon group velocities at an arbitrary q-point.
     232              : 
     233              :     procedure :: get_phmesh => ifc_get_phmesh
     234              :      ! Build linear mesh for phonons.
     235              : 
     236              :     procedure :: speedofsound => ifc_speedofsound
     237              :      ! Compute the speed of sound by averaging phonon group velocities.
     238              : 
     239              :     procedure :: write => ifc_write
     240              :      ! Print the ifc (output, netcdf and text file).
     241              : 
     242              :     procedure :: outphbtrap => ifc_outphbtrap
     243              :      ! Print out phonon frequencies on regular grid for BoltzTrap code.
     244              : 
     245              :     procedure :: printbxsf => ifc_printbxsf
     246              :      ! Output phonon isosurface in Xcrysden format.
     247              : 
     248              :     procedure :: calcnwrite_nana_terms => ifc_calcnwrite_nana_terms
     249              :      ! Compute phonons for q--> 0 with LO-TO.
     250              : 
     251              :     procedure :: calcnwrite_nana_terms_qpath => ifc_calcnwrite_nana_terms_qpath
     252              :      ! Compute phonons for q--> 0 with LO-TO from qpath_t and write results to netcdf file.
     253              : 
     254              :     procedure :: init => ifc_init
     255              :      ! Constructor from DDB datatype.
     256              : 
     257              :     procedure :: from_file => ifc_from_file
     258              :      ! Constructor from filename.
     259              : 
     260              :     procedure :: to_ddb => ifc_to_ddb
     261              :      ! Construct a DDB object.
     262              : 
     263              :  end type ifc_type
     264              : !!***
     265              : 
     266              : !----------------------------------------------------------------------
     267              : 
     268              : contains  !===========================================================
     269              : !!***
     270              : 
     271              : !----------------------------------------------------------------------
     272              : 
     273              : !!****f* m_ifc/ifc_free
     274              : !! NAME
     275              : !! ifc_free
     276              : !!
     277              : !! FUNCTION
     278              : !!  Deallocate memory for the ifc_type structure
     279              : !!
     280              : !! SOURCE
     281              : 
     282         1536 : subroutine ifc_free(ifc)
     283              : 
     284              : !Arguments ------------------------------------
     285              :  class(ifc_type),intent(inout) :: ifc
     286              : ! ************************************************************************
     287              : 
     288         1536 :  ABI_SFREE(ifc%amu)
     289         1536 :  ABI_SFREE(ifc%atmfrc)
     290         1536 :  ABI_SFREE(ifc%cell)
     291         1536 :  ABI_SFREE(ifc%ewald_atmfrc)
     292         1536 :  ABI_SFREE(ifc%short_atmfrc)
     293         1536 :  ABI_SFREE(ifc%qshft)
     294         1536 :  ABI_SFREE(ifc%rpt)
     295         1536 :  ABI_SFREE(ifc%wghatm)
     296         1536 :  ABI_SFREE(ifc%rcan)
     297         1536 :  ABI_SFREE(ifc%trans)
     298         1536 :  ABI_SFREE(ifc%dyewq0)
     299         1536 :  ABI_SFREE(ifc%qibz)
     300         1536 :  ABI_SFREE(ifc%wtq)
     301         1536 :  ABI_SFREE(ifc%qbz)
     302         1536 :  ABI_SFREE(ifc%zeff)
     303         1536 :  ABI_SFREE(ifc%qdrp_cart)
     304         1536 :  ABI_SFREE(ifc%dynmat)
     305              : 
     306         1536 : end subroutine ifc_free
     307              : !!***
     308              : 
     309              : !----------------------------------------------------------------------
     310              : 
     311              : !!****f* m_ifc/ifc_init
     312              : !! NAME
     313              : !!  ifc_init
     314              : !!
     315              : !! FUNCTION
     316              : !!  Initialize the dynamical matrix as well as the IFCs.
     317              : !!  taking into account the dipole-dipole, dipole-quadrupole and quadrupole-quadrupole interaction.
     318              : !!
     319              : !! INPUTS
     320              : !! crystal<type(crystal_t)> = Information on the crystalline structure.
     321              : !! ddb<type(ddb_type)> = Database with derivatives.
     322              : !! brav=bravais lattice (1 or -1=simple lattice, 2=face centered lattice, 3=centered lattice, 4=hexagonal lattice)
     323              : !! asr= Option for the imposition of the ASR
     324              : !!   0 => no ASR,
     325              : !!   1 => modify "asymmetrically" the diagonal element
     326              : !!   2 => modify "symmetrically" the diagonal element
     327              : !! symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
     328              : !! dipdip=
     329              : !!   if 0, no dipole-dipole interaction was subtracted in atmfrc
     330              : !!   if 1, atmfrc has been build without dipole-dipole part
     331              : !! rfmeth =
     332              : !!   1 if non-stationary block
     333              : !!   2 if stationary block
     334              : !!   3 if third order derivatives
     335              : !! dielt(3,3)=dielectric tensor.
     336              : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
     337              : !! prtsrlr: TODO: TO BE REMOVED
     338              : !! enunit: TODO: TO BE REMOVED
     339              : !! dielt(3,3)=dielectric tensor
     340              : !! ngqpt_in = input values of ngqpt
     341              : !! nqshft=Number of shifths in q-grid.
     342              : !! q1shft(3,nqshft)=Shifts for q-grid
     343              : !! nsphere=number of atoms to be included in the cut-off sphere for interatomic force constant.
     344              : !!    0: maximum extent allowed by the grid.
     345              : !!  > 0: Apply cutoff
     346              : !!   -1: Analyze the effect of different nsphere values on the phonon spectrum, in particular the
     347              : !!       frequencies around gamma.
     348              : !! rifcsph=radius for cutoff of IFC.
     349              : !! comm=MPI communicator.
     350              : !! [Ifc_coarse]=Optional.
     351              : !! [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
     352              : !! [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part
     353              : !! prtout=write info to the output and log files.
     354              : !!
     355              : !! OUTPUT
     356              : !! Ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
     357              : !!
     358              : !! SOURCE
     359              : 
     360          242 : subroutine ifc_init(Ifc,crystal,ddb,brav,asr,symdynmat,dipdip,&
     361          242 :                     rfmeth,ngqpt_in,nqshft,q1shft,dielt,zeff,qdrp_cart,nsphere,rifcsph,&
     362              :                     prtsrlr,enunit,& ! TODO: TO BE REMOVED
     363              :                     sys_dim,comm, &
     364              :                     Ifc_coarse,dipquad,quadquad,dielt_env,dielt_thick,prtout) ! Optional
     365              : 
     366              : !Arguments ------------------------------------
     367              :  class(ifc_type),intent(inout) :: Ifc
     368              :  integer,intent(in) :: asr,dipdip,symdynmat,nqshft,rfmeth,nsphere,comm,sys_dim
     369              :  real(dp),intent(in) :: rifcsph
     370              :  type(crystal_t),intent(in) :: Crystal
     371              :  type(ddb_type),intent(in) :: ddb
     372              :  type(ifc_type),optional,intent(in) :: Ifc_coarse
     373              :  integer,optional,intent(in) :: dipquad, quadquad
     374              :  logical, optional, intent(in) :: prtout
     375              :  real(dp), optional, intent(in) :: dielt_env,dielt_thick(2)
     376              : 
     377              : !arrays
     378              :  integer,intent(in) :: ngqpt_in(3)
     379              :  real(dp),intent(in) :: q1shft(3,nqshft)
     380              :  real(dp),intent(in) :: dielt(3,3),zeff(3,3,Crystal%natom)
     381              :  real(dp),intent(in) :: qdrp_cart(3,3,3,Crystal%natom)
     382              : !anaddb variables (TO BE REMOVED)
     383              :  integer,intent(in) :: prtsrlr,enunit,brav
     384              : 
     385              : !Local variables -------------------------
     386              : !scalars
     387              :  integer,parameter :: timrev1=1,iout0=0,chksymbreak0=0
     388              :  integer :: mpert,iout,iqpt,mqpt,nsym,ntypat,iq_ibz,iq_bz,ii,natom
     389              :  integer :: nqbz,option,plus,sumg0,irpt,irpt_new, nprocs,my_rank,my_ierr,ierr
     390              :  logical :: prtout_
     391              :  real(dp),parameter :: qphnrm=one
     392              :  real(dp) :: cpu,wall,gflops,xval,rcut_min,r_inscribed_sphere,toldist
     393              :  character(len=500*4) :: msg
     394         1452 :  type(ifc_type) :: ifc_tmp
     395              : !arrays
     396              :  integer :: ngqpt(9),qptrlatt(3,3)
     397          484 :  integer,allocatable :: qmissing(:),ibz2bz(:),bz2ibz_smap(:,:)
     398              :  real(dp) :: gprim(3,3),rprim(3,3),qpt(3),rprimd(3,3), gprim_tmp(3,3), rprim_tmp(3,3)
     399          968 :  real(dp):: rcan(3,Crystal%natom),trans(3,Crystal%natom),dyewq0(3,3,Crystal%natom)
     400          484 :  real(dp) :: displ_cart(2*3*Crystal%natom*3*Crystal%natom)
     401          484 :  real(dp) :: phfrq(3*Crystal%natom)
     402          484 :  real(dp) :: eigvec(2,3,Crystal%natom,3,Crystal%natom)
     403          484 :  real(dp),allocatable :: dyew(:,:,:,:,:),out_d2cart(:,:,:,:,:)
     404          242 :  real(dp),allocatable :: dynmatfull(:,:,:,:,:,:),dynmat_sr(:,:,:,:,:,:),dynmat_lr(:,:,:,:,:,:) ! for OmegaSRLR
     405          242 :  real(dp),allocatable :: wtq(:),wtq_folded(:),qbz(:,:)
     406              : !******************************************************************
     407              :  ! TODO
     408              :  ! - Remove brav
     409              :  ! - Separate into ifc_init and ifc_from_ddb
     410              : 
     411          242 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     412          242 :  call cwtime(cpu, wall, gflops, "start")
     413              : 
     414          242 :  mpert = ddb%mpert
     415          242 :  iout = ab_out
     416          242 :  prtout_ = .true.
     417          242 :  if (present(prtout)) prtout_ = prtout
     418              : 
     419          242 :  nsym = Crystal%nsym
     420          242 :  natom = Crystal%natom
     421          242 :  ntypat = Crystal%ntypat
     422         3146 :  rprimd = Crystal%rprimd
     423              : 
     424          968 :  ngqpt=0; ngqpt(1:3)=ngqpt_in(1:3)
     425              : 
     426              :  ! Copy important parameters in Ifc
     427          242 :  Ifc%natom = natom
     428          242 :  Ifc%mpert = mpert
     429          242 :  Ifc%asr = asr
     430          242 :  Ifc%brav = brav
     431          242 :  Ifc%dielt_env=0; if (present(dielt_env)) Ifc%dielt_env = dielt_env
     432          836 :  Ifc%dielt_thick(:)=0; if (present(dielt_thick)) Ifc%dielt_thick = dielt_thick(1:2)
     433          242 :  Ifc%sys_dim = sys_dim
     434          242 :  Ifc%dipdip = abs(dipdip)
     435          242 :  Ifc%dipquad=0; if (present(dipquad)) Ifc%dipquad = dipquad
     436          242 :  Ifc%quadquad=0; if (present(quadquad)) Ifc%quadquad = quadquad
     437          242 :  Ifc%symdynmat = symdynmat
     438          968 :  Ifc%ngqpt = ngqpt_in(1:3)
     439          242 :  Ifc%nqshft = nqshft
     440          242 :  call alloc_copy(q1shft(:,1:Ifc%nqshft),Ifc%qshft)
     441          242 :  Ifc%ewald_option = 0; if (dipdip < 0) Ifc%ewald_option = 1 !HM TODO: expose this in the init?
     442              : 
     443              : 
     444              :  ! These two ways of defining rprim, gprim, acell should be equivalent.
     445              :  ! Note that the crystal object does not know about acell.
     446         3146 :  Ifc%rprim = ddb%rprim
     447         3146 :  Ifc%gprim = ddb%gprim
     448          968 :  Ifc%acell = ddb%acell
     449              :  !Ifc%rprim = crystal%rprimd
     450              :  !Ifc%gprim = crystal%gprimd
     451              :  !Ifc%acell = one
     452              :  !
     453              :  !! When brav/=1, we need specific values of rprim.
     454              :  !if (abs(brav)/=1) then
     455              :  !  if (brav==2) then
     456              :  !    !  Face Centered Lattice
     457              :  !    fac = half_sqrt2
     458              :  !  else if (brav==3) then
     459              :  !    !  Body Centered Cubic Lattice
     460              :  !    fac = half_sqrt3
     461              :  !  else if (brav==4) then
     462              :  !    !  Hexagonal Lattice
     463              :  !    fac = one
     464              :  !  end if
     465              :  !  Ifc%acell(1) = sqrt(rprimd(1,1)**2 + rprimd(2,1)**2 + rprimd(3,1)**2) / fac
     466              :  !  Ifc%acell(2) = sqrt(rprimd(1,2)**2 + rprimd(2,2)**2 + rprimd(3,2)**2) / fac
     467              :  !  Ifc%acell(3) = sqrt(rprimd(1,3)**2 + rprimd(2,3)**2 + rprimd(3,3)**2) / fac
     468              :  !  do ii=1,3
     469              :  !    Ifc%rprim(ii, 1) = rprimd(ii, 1) / Ifc%acell(1)
     470              :  !    Ifc%rprim(ii, 2) = rprimd(ii, 2) / Ifc%acell(2)
     471              :  !    Ifc%rprim(ii, 3) = rprimd(ii, 3) / Ifc%acell(3)
     472              :  !    Ifc%gprim(ii, 1) = crystal%gprimd(ii, 1) * Ifc%acell(1)
     473              :  !    Ifc%gprim(ii, 2) = crystal%gprimd(ii, 2) * Ifc%acell(2)
     474              :  !    Ifc%gprim(ii, 3) = crystal%gprimd(ii, 3) * Ifc%acell(3)
     475              :  !  end do
     476              :  !
     477              :  !end if
     478              : 
     479              :  ! Check if the rprim are coherent with the choice used in the interatomic forces generation
     480          242 :  call chkrp9(Ifc%brav,Ifc%rprim)
     481              : 
     482         6050 :  rprim = Ifc%rprim; gprim = Ifc%gprim
     483              : 
     484              :  ! -------------------------------------------------------------------------- !
     485              :  ! Compute dyewq0, the correction to be applied to the Ewald, see Eq.(71) of PRB55, 10355 (1997).
     486         8549 :  dyewq0 = zero
     487          242 :  if ((Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1).and. (Ifc%asr==1.or.Ifc%asr==2.or.Ifc%asr==6)) then
     488              :    ! Calculation of the non-analytical part for q=0
     489          158 :    sumg0=0
     490          158 :    qpt(:)=zero
     491          790 :    ABI_MALLOC(dyew,(2,3,natom,3,natom))
     492          158 :    if (sys_dim==1) then
     493          156 :      if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
     494              :        call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
     495            3 :                    Crystal%xred,zeff,qdrp_cart,ifc%eta,option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
     496              :      else
     497              :        call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
     498          153 :                   Crystal%xred,zeff,qdrp_cart,ifc%eta, option=ifc%ewald_option)
     499              :      end if
     500              :    else
     501              :      ! 2D materials are embedded in a dielectric environment (typically vacuum in DFT calculations)
     502              :      ! which leads to a different long-range electrostatics than in 2D. The next routine allows
     503              :      ! to estimate it.
     504            2 :      call ewald9_2D(natom,ddb%acell,Crystal%xred,rprim,dielt,dyew,qpt,zeff,qdrp_cart,dielt_env,dielt_thick,sys_dim)
     505              :    end if
     506          158 :    call q0dy3_calc(natom,dyewq0,dyew,Ifc%asr)
     507          158 :    ABI_FREE(dyew)
     508              :  end if
     509              : 
     510              :  ! -------------------------------------------------------------------------- !
     511              :  ! Setup q-points
     512              : 
     513              :  ! Sample the Brillouin zone
     514          242 :  option=1
     515          242 :  qptrlatt = 0; qptrlatt(1,1)=ngqpt(1); qptrlatt(2,2)=ngqpt(2); qptrlatt(3,3)=ngqpt(3)
     516          242 :  mqpt=ngqpt(1)*ngqpt(2)*ngqpt(3)*nqshft
     517          242 :  if (Ifc%brav==2) mqpt=mqpt/2
     518          242 :  if (Ifc%brav==3) mqpt=mqpt/4
     519              : 
     520          726 :  ABI_MALLOC(qbz,(3,mqpt))
     521          242 :  call smpbz(Ifc%brav,ab_out,qptrlatt,mqpt,nqbz,nqshft,option,q1shft,qbz,prtout=prtout_)
     522              : 
     523              :  ! Find the irreducible zone (qibz)
     524          726 :  ABI_MALLOC(ibz2bz, (nqbz))
     525          726 :  ABI_MALLOC(wtq_folded, (nqbz))
     526          484 :  ABI_MALLOC(wtq, (nqbz))
     527        26542 :  wtq = one / nqbz ! Weights sum up to one
     528          726 :  ABI_MALLOC(bz2ibz_smap, (6, nqbz))
     529              : 
     530              :  ! FIXME: timrev1 should be set to 0 if TR cannot be used
     531              :  call symkpt(chksymbreak0,crystal%gmet,ibz2bz,iout0,qbz,nqbz,ifc%nqibz,crystal%nsym,&
     532          242 :    crystal%symrec,timrev1,wtq,wtq_folded, bz2ibz_smap, xmpi_comm_self)
     533              : 
     534          242 :  ABI_FREE(bz2ibz_smap)
     535              : 
     536          726 :  ABI_MALLOC(ifc%qibz, (3,ifc%nqibz))
     537          726 :  ABI_MALLOC(ifc%wtq, (ifc%nqibz))
     538         3394 :  do iq_ibz=1,ifc%nqibz
     539        12608 :    ifc%qibz(:,iq_ibz) = qbz(:, ibz2bz(iq_ibz))
     540         3394 :    ifc%wtq(iq_ibz) = wtq_folded(ibz2bz(iq_ibz))
     541              :  end do
     542          242 :  ABI_FREE(ibz2bz)
     543          242 :  ABI_FREE(wtq_folded)
     544          242 :  ABI_FREE(wtq)
     545              : 
     546              :  ! -------------------------------------------------------------------------- !
     547              :  ! Setup dynamical matrix and IFC matrix
     548              : 
     549         1452 :  ABI_MALLOC(Ifc%dynmat,(2,3,natom,3,natom,nqbz))
     550              : 
     551              :  ! This is needed to preserve the behavior of the old implementation with canonical coordinate.
     552          242 :  if (Ifc%brav == 1) then
     553         2548 :    gprim_tmp = Crystal%gprimd
     554          196 :    rprim_tmp = rprimd
     555              :  else
     556           46 :    gprim_tmp = gprim
     557           46 :    rprim_tmp = rprim
     558              :  endif
     559              : 
     560              :  ! Find symmetrical dynamical matrices
     561          242 :  if (.not.present(Ifc_coarse)) then
     562              :    ! Each q-point in the BZ mush be the symmetrical of one of the qpts in the ddb file.
     563              :    ! SP - gprimd and rprimd is required instead of gprim and rprim for non-diagonal supercells.
     564              :    call symdm9(ddb, &
     565              :      Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
     566          241 :      Crystal%symrec, Crystal%symrel, comm)
     567              : 
     568              :  else
     569              :    ! Symmetrize the qpts in the BZ using the q-points in the ddb.
     570              :    ! Then use Ifc_coarse to fill the missing entries with Fourier interpolated matrices.
     571              :    !
     572              :    ! TODO: The previous version of refineblk was hacking the DDB database to add the q-points in the **IBZ**
     573              :    ! Then D(q) was symmetrized in symdm9. This version avoids the symmetrization: the q-points
     574              :    ! in the BZ that are not in the coarse q-mesh are obtained by an explicit FT.
     575              :    ! This means that the final D(q) may break some symmetry in q-space if the FT does not preserve it.
     576              :    ! The most elegant approach would be to get D(q_ibz) via FT if q_ibz is not in the coarse mesh and then
     577              :    ! call symdm9 to get D(q) for each q point in the star of q_ibz.
     578            1 :    call wrtout(std_out,"Will fill missing qpoints in the full BZ using the coarse q-mesh")
     579              : 
     580              :    call symdm9(ddb, &
     581              :      Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
     582            1 :      Crystal%symrec,Crystal%symrel,comm, qmissing=qmissing)
     583              : 
     584              :    ! Compute dynamical matrix with Fourier interpolation on the coarse q-mesh.
     585            1 :    write(msg,"(a,i0,a)")"Will use Fourier interpolation to construct D(q) for ",size(qmissing)," q-points"
     586            1 :    call wrtout(std_out,msg)
     587              : 
     588            4 :    ABI_MALLOC(out_d2cart, (2,3,natom,3,natom))
     589           97 :    do ii=1,size(qmissing)
     590           96 :      iq_bz = qmissing(ii)
     591          384 :      qpt = qbz(:,iq_bz)
     592              :      ! TODO: check dipdip option and phase, but I think this is correct!
     593           96 :      call Ifc_coarse%fourq(Crystal,qpt,phfrq,displ_cart,out_d2cart=out_d2cart)
     594         3361 :      Ifc%dynmat(:,:,:,:,:,iq_bz) = out_d2cart
     595              :    end do
     596              : 
     597            1 :    ABI_FREE(qmissing)
     598            1 :    ABI_FREE(out_d2cart)
     599              :  end if
     600              : 
     601              :  ! OmegaSRLR: Store full dynamical matrix for decomposition into short- and long-range parts
     602          968 :  ABI_MALLOC(dynmatfull,(2,3,natom,3,natom,nqbz))
     603     12537758 :  dynmatfull=Ifc%dynmat
     604              : 
     605          242 :  if (Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1) then
     606              :    ! Take off the dipole-dipole part of the dynamical matrix
     607          158 :    if (prtout_) call wrtout(std_out, " Will extract the dipole-dipole part for every wavevector")
     608          632 :    ABI_MALLOC(dyew,(2,3,natom,3,natom))
     609              : 
     610        11530 :    do iqpt=1,nqbz
     611        11372 :      if (mod(iqpt, nprocs) /= my_rank) then ! mpi-parallelism
     612         1988 :        ifc%dynmat(:,:,:,:,:,iqpt) = zero; cycle
     613              :      end if
     614        45472 :      qpt(:)=qbz(:,iqpt)
     615        11368 :      sumg0=0
     616        11368 :      if (sys_dim==1) then
     617              :              ! 3D case
     618        11031 :        if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
     619              :          call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
     620              :                      Crystal%xred,zeff,qdrp_cart, ifc%eta, &
     621           48 :                      option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
     622              :        else
     623              :          call ewald9(Ifc%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
     624              :                      Crystal%xred,zeff,qdrp_cart, ifc%eta, &
     625        10983 :                      option=ifc%ewald_option)
     626              :        end if
     627              :      else
     628              :        ! 2D case
     629          337 :        call ewald9_2D(natom,ddb%acell,Crystal%xred,rprim,dielt,dyew,qpt,zeff,qdrp_cart,one,dielt_thick,sys_dim)
     630              :      end if
     631        11368 :      call q0dy3_apply(natom,dyewq0,dyew)
     632        11368 :      plus=0
     633              :      ! Implement Eq.(76) of Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], possibly generalized for quadrupoles
     634        11526 :      call nanal9(dyew,Ifc%dynmat,iqpt,natom,nqbz,plus)
     635              :    end do
     636              : 
     637          158 :    call xmpi_sum(ifc%dynmat, comm, ierr)
     638          158 :    ABI_FREE(dyew)
     639              :    !if (prtout_) call wrtout(std_out, " Done")
     640              :  end if
     641              : 
     642              :  ! OmegaSRLR: Store the short-range dynmat and compute long-range as difference
     643         1452 :  ABI_MALLOC(dynmat_sr,(2,3,natom,3,natom,nqbz))
     644          968 :  ABI_MALLOC(dynmat_lr,(2,3,natom,3,natom,nqbz))
     645     12537758 :  dynmat_sr=Ifc%dynmat
     646     12537758 :  dynmat_lr=dynmatfull-dynmat_sr
     647              : 
     648              :  ! Now, take care of the remaining part of the dynamical matrix
     649              :  ! Move to canonical normalized coordinates
     650          242 :  call canat9(Ifc%brav,natom,rcan,rprim,trans,Crystal%xred)
     651              : 
     652              :  ! Multiply the dynamical matrix by a phase shift
     653              :  option=1
     654          242 :  call dymfz9(Ifc%dynmat,natom,nqbz,gprim,option,qbz,trans)
     655              : 
     656              :  ! -------------------------------------------------------------------------- !
     657              :  ! Compute interatomic forces in real space
     658              : 
     659              :  ! Create the Big Box of R vectors in real space and compute the number of points (cells) in real space
     660          242 :  call make_bigbox(Ifc%brav,ifc_tmp%cell,ngqpt,nqshft,rprim,ifc_tmp%nrpt,ifc_tmp%rpt)
     661              : 
     662              :  ! Weights associated to these R points and to atomic pairs
     663         1210 :  ABI_MALLOC(ifc_tmp%wghatm, (natom, natom, ifc_tmp%nrpt))
     664              : 
     665              :  ! HM: this tolerance is highly dependent on the compilation/architecture
     666              :  !     numeric errors in the DDB text file. Try a few tolerances and check whether all the weights are found.
     667          242 :  toldist = tol8
     668          243 :  do while (toldist <= tol6)
     669              :    ! Note ngqpt(9) with intent(inout)!
     670              :    call wght9(Ifc%brav,gprim,natom,ngqpt,nqbz,nqshft,ifc_tmp%nrpt,q1shft,rcan,&
     671          243 :               ifc_tmp%rpt,rprimd,toldist,r_inscribed_sphere,ifc_tmp%wghatm,my_ierr)
     672          243 :    call xmpi_max(my_ierr, ierr, comm, ii)
     673          243 :    if (ierr > 0) toldist = toldist * 10
     674          243 :    if (ierr == 0) exit
     675              :  end do
     676              : 
     677          242 :  if (ierr > 0) then
     678              :    write(msg, '(3a,es14.4,2a,i0, 14a)' ) &
     679            0 :     'The sum of the weight is not equal to nqpt.',ch10,&
     680            0 :     'The sum of the weights is: ',sum(ifc_tmp%wghatm),ch10,&
     681            0 :     'The number of q-points is: ',nqbz, ch10, &
     682            0 :     'This might have several sources.',ch10,&
     683            0 :     'If toldist is larger than 1.0e-8, the atom positions might be loose.',ch10,&
     684            0 :     'and the q point weights not computed properly.',ch10,&
     685            0 :     'Action: make input atomic positions more symmetric.',ch10,&
     686            0 :     'Otherwise, you might increase "buffer" in m_dynmat.F90 see bigbx9 subroutine and recompile.',ch10,&
     687            0 :     'Actually, this can also happen when ngqpt is 0 0 0,',ch10,&
     688            0 :     'if abs(brav) /= 1, in this case you should change brav to 1. If brav is already set to 1 (default) try -1.'
     689            0 :    ABI_ERROR(msg)
     690              :  end if
     691              : 
     692              :  ! Fourier transform of the dynamical matrices (q-->R)
     693         1452 :  ABI_MALLOC(ifc_tmp%atmfrc, (3,natom,3,natom,ifc_tmp%nrpt))
     694          242 :  call ftifc_q2r(ifc_tmp%atmfrc,Ifc%dynmat,gprim,natom,nqbz,ifc_tmp%nrpt,ifc_tmp%rpt,qbz, comm)
     695              : 
     696              :  ! Eventually impose Acoustic Sum Rule on the interatomic forces
     697          242 :  if (Ifc%asr > 0) call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
     698              : 
     699              :  ! The interatomic forces have been calculated
     700          242 :  write(msg, '(2a)')ch10,' The interatomic forces have been obtained '
     701          634 :  if (prtout_) call wrtout([std_out, ab_out], msg)
     702          242 :  call cwtime_report(" ifc_init1", cpu, wall, gflops)
     703              : 
     704              :  ! Apply cutoff on ifc if needed
     705          242 :  if (nsphere > 0 .or. abs(rifcsph) > tol10) then
     706            3 :    call wrtout(std_out, ' Apply cutoff on IFCs.')
     707            3 :    call wrtout(std_out, sjoin(" nsphere:", itoa(nsphere), ", rifcsph:", ftoa(rifcsph)))
     708            3 :    call wrtout(std_out, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(r_inscribed_sphere)))
     709            3 :    call corsifc9(Ifc%acell,gprim,natom,ifc_tmp%nrpt,nsphere,rifcsph,rcan,rprim,ifc_tmp%rpt,rcut_min,ifc_tmp%wghatm)
     710            3 :    if (Ifc%asr > 0) then
     711            3 :      call wrtout(std_out, ' Enforcing ASR on cutoffed IFCs.')
     712            3 :      call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
     713              :    end if
     714              :  end if
     715              : 
     716              :  ! Only conserve the necessary points in rpt: in the FT algorithm the order of the points is unimportant
     717              :  ! In the case of effective potential, we need to keep all the points
     718          242 :  Ifc%nrpt = 0
     719       552916 :  do irpt=1,ifc_tmp%nrpt
     720     11065688 :    if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) Ifc%nrpt = Ifc%nrpt + 1
     721              :  end do
     722              : 
     723      8689738 :  ABI_CALLOC(Ifc%atmfrc,(3,natom,3,natom,Ifc%nrpt))
     724       169430 :  ABI_CALLOC(Ifc%rpt,(3,Ifc%nrpt))
     725       169430 :  ABI_CALLOC(Ifc%cell,(3,Ifc%nrpt))
     726       851252 :  ABI_CALLOC(Ifc%wghatm,(natom,natom,Ifc%nrpt))
     727      8689738 :  ABI_CALLOC(Ifc%short_atmfrc,(3,natom,3,natom,Ifc%nrpt))
     728      8689496 :  ABI_CALLOC(Ifc%ewald_atmfrc,(3,natom,3,natom,Ifc%nrpt))
     729              : 
     730              :  irpt_new = 1
     731       552916 :  do irpt = 1, ifc_tmp%nrpt
     732     11065688 :    if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) then
     733      8688528 :      Ifc%atmfrc(:,:,:,:,irpt_new) = ifc_tmp%atmfrc(:,:,:,:,irpt)
     734       168704 :      Ifc%rpt(:,irpt_new) = ifc_tmp%rpt(:,irpt)
     735       850042 :      Ifc%wghatm(:,:,irpt_new) = ifc_tmp%wghatm(:,:,irpt)
     736       168704 :      Ifc%cell(:,irpt_new) = ifc_tmp%cell(:,irpt)
     737        42176 :      Ifc%r_inscribed_sphere = r_inscribed_sphere
     738        42176 :      irpt_new = irpt_new + 1
     739              :    end if
     740              :  end do
     741              : 
     742              :  !write(std_out,*)"nrpt before filter:", ifc_tmp%nrpt, ", after: ", ifc%nrpt
     743              :  !do irpt=1,ifc%nrpt
     744              :  !  write(std_out,*)ifc%rpt(:,irpt), (ifc%wghatm(ii,ii,irpt), ii=1,natom)
     745              :  !end do
     746              : 
     747          242 :  call ifc_tmp%free()
     748              : 
     749              :  ! -------------------------------------------------------------------------- !
     750              : 
     751              :  ! Copy other useful arrays.
     752         3146 :  Ifc%dielt = dielt
     753          242 :  Ifc%nqbz = nqbz
     754              : 
     755          242 :  call alloc_copy(rcan, Ifc%rcan)
     756          242 :  call alloc_copy(trans, Ifc%trans)
     757          242 :  call alloc_copy(dyewq0, Ifc%dyewq0)
     758          242 :  call alloc_copy(qbz(:,1:nqbz), Ifc%qbz)
     759          242 :  call alloc_copy(zeff, Ifc%zeff)
     760          242 :  call alloc_copy(qdrp_cart, Ifc%qdrp_cart)
     761          242 :  call alloc_copy(crystal%amu, Ifc%amu)
     762              : 
     763              :  ! Compute min/max ph frequency with ab-initio q-mesh.
     764          242 :  ifc%omega_minmax(1) = huge(one); ifc%omega_minmax(2) = -huge(one)
     765         3394 :  do iq_ibz=1,ifc%nqibz
     766         3152 :    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
     767         3144 :    call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), phfrq, displ_cart)
     768        38088 :    ifc%omega_minmax(1) = min(ifc%omega_minmax(1), minval(phfrq))
     769        38338 :    ifc%omega_minmax(2) = max(ifc%omega_minmax(2), maxval(phfrq))
     770              :  end do
     771          242 :  xval = ifc%omega_minmax(1); call xmpi_min(xval, ifc%omega_minmax(1), comm, ierr)
     772          242 :  xval = ifc%omega_minmax(2); call xmpi_max(xval, ifc%omega_minmax(2), comm, ierr)
     773              :  ! Enlarge boundaries by 30 cm-1
     774          242 :  ifc%omega_minmax(1) = ifc%omega_minmax(1) - 30.0_dp/Ha_cmm1
     775          242 :  ifc%omega_minmax(2) = ifc%omega_minmax(2) + 30.0_dp/Ha_cmm1
     776              : 
     777              :  ! TODO (This is to be suppressed in a future version)
     778          242 :  if (prtsrlr == 1) then
     779              :    ! Check that the starting values are well reproduced.
     780            0 :    write(msg, '(2a)' )' mkifc9 : now check that the starting values ',&
     781            0 :      ' are reproduced after the use of interatomic forces '
     782            0 :    if (prtout_) call wrtout(std_out, msg)
     783            0 :    do iqpt=1,nqbz
     784            0 :      qpt(:)=Ifc%qbz(:,iqpt)
     785            0 :      call ifc%fourq(Crystal,qpt,phfrq,displ_cart,out_eigvec=eigvec)
     786              : 
     787              :      ! OmegaSRLR: Perform decomposition of dynamical matrix
     788              :      ! MG: FIXME I don't think the implementation is correct when q !=0
     789              :      if (prtsrlr==1) then
     790            0 :        call omega_decomp(Ifc%amu,natom,ntypat,Crystal%typat,dynmatfull,dynmat_sr,dynmat_lr,iqpt,nqbz,eigvec)
     791              :      end if
     792              :      ! Write the phonon frequencies (this is for checking purposes).
     793              :      ! Note: these phonon frequencies are not written on unit iout, only on unit std_out.
     794            0 :      call dfpt_prtph(displ_cart,0,enunit,-1,natom,phfrq,qphnrm,qpt)
     795              :    end do
     796              :  end if
     797              : 
     798              :  ! OmegaSRLR: deallocate memory used by dynmat decomposition
     799          242 :  ABI_FREE(dynmatfull)
     800          242 :  ABI_FREE(dynmat_sr)
     801          242 :  ABI_FREE(dynmat_lr)
     802          242 :  ABI_FREE(qbz)
     803              : 
     804          242 :  if (nsphere == -1) call ifc_autocutoff(ifc, crystal, comm)
     805              : 
     806          242 :  call cwtime_report(" ifc_init2", cpu, wall, gflops)
     807              : 
     808         1210 : end subroutine ifc_init
     809              : !!***
     810              : 
     811              : !----------------------------------------------------------------------
     812              : 
     813              : !!****f* m_ifc/ifc_from_file
     814              : !! NAME
     815              : !!  ifc_from_file
     816              : !!
     817              : !! FUNCTION
     818              : !!  Initialize instance from file.
     819              : !!
     820              : !! INPUTS
     821              : !!
     822              : !! OUTPUT
     823              : !!
     824              : !! SOURCE
     825              : 
     826            0 : subroutine ifc_from_file(ifc, dielt, filename,natom,ngqpt,nqshift,qshift,ucell_ddb,zeff,qdrp_cart,comm)
     827              : 
     828              : !Arguments ------------------------------------
     829              : !scalars
     830              :  class(ifc_type),intent(out) :: Ifc
     831              :  integer,intent(in) :: nqshift,comm
     832              :  integer,intent(inout) :: natom
     833              : !arrays
     834              :  integer,intent(in) :: ngqpt(3)
     835              :  real(dp),intent(in) :: qshift(3,nqshift)
     836              :  character(len=*),intent(in) :: filename
     837              :  real(dp),intent(inout) :: dielt(3,3)
     838              :  real(dp),allocatable,intent(inout) :: zeff(:,:,:)
     839              :  real(dp),allocatable,intent(inout) :: qdrp_cart(:,:,:,:)
     840              :  type(crystal_t),intent(out) :: ucell_ddb
     841              : 
     842              : !Local variables -------------------------
     843              : !scalars
     844              :  integer :: dipdip,i,iblok,iblok_tmp
     845              :  logical :: file_exists
     846              :  character(len=500) :: msg
     847            0 :  type(ddb_type) :: ddb
     848            0 :  type(ddb_hdr_type) :: ddb_hdr
     849              : !******************************************************************
     850              : 
     851              :  !check if ddb file exists
     852            0 :  inquire(file=filename, exist=file_exists)
     853              : 
     854            0 :  if (file_exists .eqv. .true.)then
     855              :    !Reading the ddb
     856            0 :    call ddb%from_file(filename, ddb_hdr, ucell_ddb, comm)
     857            0 :    call ddb_hdr%free()
     858            0 :    natom = ddb%natom
     859              :  else
     860            0 :    ABI_ERROR(sjoin("File:", filename, "is not present in the directory"))
     861              :  end if
     862              : 
     863              :  ! Get Dielectric Tensor and Effective Charges
     864              :  ! (initialized to one_3D and zero if the derivatives are not available in the DDB file)
     865            0 :  ABI_MALLOC(zeff,(3,3,natom))
     866            0 :  iblok = ddb%get_dielt_zeff(ucell_ddb,1,1,0,dielt,zeff)
     867              : 
     868              :  ! Try to get dielt, in case just the DDE are present
     869            0 :  if (iblok == 0) then
     870            0 :    iblok_tmp = ddb%get_dielt(1,dielt)
     871              :  end if
     872              : 
     873            0 :  ABI_MALLOC(qdrp_cart,(3,3,3,natom))
     874            0 :  iblok = ddb%get_quadrupoles(ddb_hdr%ddb_version,1,BLKTYP_d3E_xx,qdrp_cart)
     875              : 
     876              :  ! ifc to be calculated for interpolation
     877            0 :  write(msg, '(a,a,(80a),a,a,a,a)' ) ch10,('=',i=1,80),ch10,ch10,' Calculation of the interatomic forces ',ch10
     878            0 :  call wrtout([std_out, ab_out], msg)
     879            0 :  if ((maxval(abs(zeff)) .lt. tol10) .OR. (maxval(dielt) .gt. 100000.0)) then
     880            0 :    dipdip=0
     881              :  else
     882            0 :    dipdip=1
     883              :  end if
     884            0 :  call ifc%init(ucell_ddb,ddb,1,1,1,dipdip,1,ngqpt,nqshift,qshift,dielt,zeff,qdrp_cart,0,0.0_dp,0,1,1,comm)
     885              : 
     886              :  ! Free them all
     887            0 :  call ddb%free()
     888              : 
     889            0 : end subroutine ifc_from_file
     890              : !!***
     891              : 
     892              : !----------------------------------------------------------------------
     893              : 
     894              : !!****f* m_ifc/ifc_print
     895              : !! NAME
     896              : !!  ifc_print
     897              : !!
     898              : !! FUNCTION
     899              : !!  Print info on the object
     900              : !!
     901              : !! INPUTS
     902              : !!  units=Unit numbers for output
     903              : !!  [header]=String to be printed as header for additional info.
     904              : !!  [prtvol]=Verbosity level.
     905              : !!
     906              : !! SOURCE
     907              : 
     908          326 : subroutine ifc_print(ifc, units, header, prtvol)
     909              : 
     910              : !Arguments ------------------------------------
     911              : !scalars
     912              :  class(ifc_type),intent(in) :: ifc
     913              :  integer,intent(in) :: units(:)
     914              :  integer,optional,intent(in) :: prtvol
     915              :  character(len=*),optional,intent(in) :: header
     916              : 
     917              : !Local variables-------------------------------
     918              :  integer :: my_prtvol,iatom,ii,idir
     919              :  character(len=500) :: msg
     920              : ! *********************************************************************
     921              : 
     922          163 :  my_prtvol = 0; if (present(prtvol)) my_prtvol = prtvol
     923              : 
     924          163 :  msg = ' ==== Info on the interatomic force constants ==== '
     925          163 :  if (present(header)) msg = ' ==== '//trim(adjustl(header))//' ==== '
     926          163 :  call wrtout(units, msg)
     927              : 
     928          163 :  call wrtout(units,' Real(R)+Recip(G) space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):')
     929          652 :  do ii=1,3
     930              :    write(msg,'(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)')&
     931          489 :     'R(',ii,')=',ifc%rprim(:,ii),'G(',ii,')=',ifc%gprim(:,ii)
     932          652 :    call wrtout(units,msg)
     933              :  end do
     934          163 :  call wrtout(units, sjoin(" acell:", ltoa(ifc%acell)))
     935          163 :  call wrtout(units, sjoin(" Acoustic Sum Rule option (asr):", itoa(ifc%asr)))
     936          163 :  call wrtout(units, sjoin(" Option for the sampling of the BZ (brav):", itoa(ifc%brav)))
     937          163 :  call wrtout(units, sjoin(" Symmetrization flag (symdynmat):", itoa(ifc%symdynmat)))
     938          163 :  call wrtout(units, sjoin(" Dipole-dipole interaction flag (dipdip):", itoa(ifc%dipdip)))
     939          163 :  call wrtout(units, sjoin(" Dipole-quadrupole interaction flag (dipquad):", itoa(ifc%dipquad)))
     940          163 :  call wrtout(units, sjoin(" quadrupole-quadrupole interaction flag (quadquad):", itoa(ifc%quadquad)))
     941          163 :  call wrtout(units, sjoin(" Ewald option:", itoa(ifc%ewald_option)))
     942          163 :  call wrtout(units, sjoin(" Dielectric tensor: ", ch10, ltoa(reshape(ifc%dielt, [9]), fmt="f10.2")))
     943          163 :  call wrtout(units, " Effective charges:")
     944          532 :  do iatom=1,ifc%natom
     945          532 :    call wrtout(units, ltoa(reshape(ifc%zeff(:,:,iatom), [3*3]), fmt="f10.2"))
     946              :  end do
     947          163 :  call wrtout(units, " Quadrupolar terms:")
     948          532 :  do iatom=1,ifc%natom
     949         1639 :    do idir=1,3
     950         1476 :      call wrtout(units, ltoa(reshape(ifc%qdrp_cart(:,:,idir,iatom), [3*3]), fmt="f10.2"))
     951              :    end do
     952              :  end do
     953              : 
     954          163 :  call wrtout(units, sjoin(" Mass of the atoms (atomic mass unit): ", ltoa(ifc%amu)))
     955          163 :  call wrtout(units, sjoin(" Number of real-space points for IFC(R): ", itoa(ifc%nrpt)))
     956          163 :  call wrtout(units, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(ifc%r_inscribed_sphere)))
     957          163 :  call wrtout(units, " ")
     958          163 :  call wrtout(units, " Q-mesh:")
     959          163 :  call wrtout(units, sjoin(" ngqpt:", ltoa(ifc%ngqpt),", nqshft:", itoa(ifc%nqshft)))
     960          337 :  do ii=1,ifc%nqshft
     961          337 :    call wrtout(units, sjoin("  ", ktoa(ifc%qshft(:,ii))))
     962              :  end do
     963              : 
     964          163 : end subroutine ifc_print
     965              : !!***
     966              : 
     967              : !----------------------------------------------------------------------
     968              : 
     969              : !!****f* m_ifc/ifc_fourq
     970              : !! NAME
     971              : !!  ifc_fourq
     972              : !!
     973              : !! FUNCTION
     974              : !!  Compute the phonon frequencies and the group velocities at the specified q-point by performing
     975              : !!  a Fourier transform on the IFCs matrix in real space.
     976              : !!
     977              : !! INPUTS
     978              : !!  Crystal<type(crystal_t)> = Information on the crystalline structure.
     979              : !!  qpt(3)=q-point in reduced coordinates (unless nanaqdir is specified)
     980              : !!  [nanaqdir]=If present, the qpt will be treated as a vector specifying the
     981              : !!    direction in q-space along which the non-analytic behaviour of the dynamical
     982              : !!    matrix will be treated. Possible values:
     983              : !!       "cart" if qpt defines a direction in Cartesian coordinates
     984              : !!       "reduced" if qpt defines a direction in reduced coordinates
     985              : !!  [comm]: MPI communicator
     986              : !!
     987              : !! OUTPUT
     988              : !!  phfrq(3*natom) = Phonon frequencies in Hartree
     989              : !!  displ_cart(2,3,natom,3*natom) = Phonon displacement in Cartesian coordinates
     990              : !!  [out_d2cart(2,3,3*natom,3,3*natom)] = The (interpolated) dynamical matrix for this q-point
     991              : !!  [out_eigvec(2*3*natom*3*natom) = The (interpolated) eigenvectors of the dynamical matrix in Cartesian coords.
     992              : !!  [out_displ_red(2*3*natom*3*natom) = The (interpolated) displacement in reduced coordinates.
     993              : !!  [dwdq(3,3*natom)] = Group velocities i.e. d(omega(q))/dq in Cartesian coordinates.
     994              : !!
     995              : !! SOURCE
     996              : 
     997       310925 : subroutine ifc_fourq(ifc, crystal, qpt, phfrq, displ_cart, &
     998              :                      nanaqdir, comm, &                              ! Optional [in]
     999       303185 :                      out_d2cart, out_eigvec, out_displ_red, dwdq)   ! Optional [out]
    1000              : 
    1001              : !Arguments ------------------------------------
    1002              : !scalars
    1003              :  class(ifc_type),intent(in) :: Ifc
    1004              :  character(len=*),optional,intent(in) :: nanaqdir
    1005              :  type(crystal_t),intent(in) :: Crystal
    1006              :  integer,optional,intent(in) :: comm
    1007              : !arrays
    1008              :  real(dp),intent(in) :: qpt(3)
    1009              :  real(dp),intent(out) :: displ_cart(2,3,Crystal%natom,3*Crystal%natom)
    1010              :  real(dp),intent(out) :: phfrq(3*Crystal%natom)
    1011              :  real(dp),optional,intent(out) :: out_d2cart(2,3,Crystal%natom,3,Crystal%natom)
    1012              :  real(dp),optional,intent(out) :: out_eigvec(2,3,Crystal%natom,3*Crystal%natom)
    1013              :  real(dp),optional,intent(out) :: out_displ_red(2,3,Crystal%natom,3*Crystal%natom)
    1014              :  real(dp),optional,intent(out) :: dwdq(3,3*crystal%natom)
    1015              : 
    1016              : !Local variables-------------------------------
    1017              : !scalars
    1018              :  integer :: natom, comm_
    1019              :  real(dp) :: qphnrm, eta
    1020              : !arrays
    1021       621850 :  real(dp) :: my_qpt(3),eigvec(2,3,Crystal%natom,3*Crystal%natom),eigval(3*Crystal%natom)
    1022       621850 :  real(dp) :: d2cart(2,3,Ifc%mpert,3,Ifc%mpert),tsec(2)
    1023              : ! ************************************************************************
    1024              : 
    1025              :  ! Keep track of total time spent.
    1026       310925 :  call timab(1748, 1, tsec)
    1027              : 
    1028       310925 :  natom = Crystal%natom
    1029              :  ! TODO: Rewrite and Parallelize ewald9 in gtdyn9
    1030       310925 :  comm_ = xmpi_comm_self; if (present(comm)) comm_ = comm
    1031              : 
    1032              :  ! Use my_qpt because dfpt_phfrq can change the q-point (very bad design)
    1033       310925 :  qphnrm = one; my_qpt = qpt
    1034              : 
    1035       310925 :  if (present(nanaqdir)) then
    1036              :    ! This will break backward compatibility because qpt is **always** in reduced coordinates.
    1037              :    ! while dfpt_phfrq assume cartesian coordinates !!!!!!!!!!!
    1038              :    ! It does not make sense to change API just to treat this particular case
    1039              :    ! We should **alwayse use q-points in reduced coordinates.
    1040        18434 :    qphnrm = zero
    1041            2 :    select case (nanaqdir)
    1042              :    case ("reduced")
    1043              :      ! Convert to Cartesian.
    1044           26 :      my_qpt = matmul(Crystal%gprimd, qpt)
    1045              :    case ("cart")
    1046            0 :      continue
    1047              :    case default
    1048        18434 :      ABI_ERROR(sjoin("Wrong value for nanaqdir:", nanaqdir))
    1049              :    end select
    1050              :  end if
    1051              : 
    1052              :  ! The dynamical matrix d2cart is calculated here:
    1053              :  call gtdyn9(Ifc%acell,Ifc%atmfrc,Ifc%dielt,Ifc%dipdip,Ifc%dyewq0,d2cart,Crystal%gmet,Ifc%gprim,Ifc%mpert,natom,&
    1054              :    Ifc%nrpt,qphnrm,my_qpt,Crystal%rmet,Ifc%rprim,Ifc%rpt,Ifc%trans,Crystal%ucvol,Ifc%wghatm,Crystal%xred,Ifc%zeff,&
    1055              :    Ifc%qdrp_cart,Ifc%ewald_option,eta,comm_, Ifc%sys_dim,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad,&
    1056       310925 :    dielt_env=Ifc%dielt_env,dielt_thick=Ifc%dielt_thick)
    1057              : 
    1058              :  ! Calculate the eigenvectors and eigenvalues of the dynamical matrix
    1059              :  call dfpt_phfrq(Ifc%amu,displ_cart,d2cart,eigval,eigvec,Crystal%indsym,&
    1060              :    Ifc%mpert,Crystal%nsym,natom,Crystal%nsym,Crystal%ntypat,phfrq,qphnrm,my_qpt,&
    1061       310925 :    Crystal%rprimd,Ifc%symdynmat,Crystal%symrel,Crystal%symafm,Crystal%typat,Crystal%ucvol)
    1062              : 
    1063              :  ! OmegaSRLR: Perform decomposition of dynamical matrix
    1064              :  !if (srlr==1) call omega_decomp(amu,natom,ntypat,typat,dynmatfull,dynmatsr,dynmatlr,iqpt,nqpt,eigvec)
    1065              : 
    1066              :  ! Return the interpolated dynamical matrix and the eigenvector for this q-point
    1067     10338725 :  if (present(out_d2cart)) out_d2cart = d2cart(:,:,:natom,:,:natom)
    1068     59527619 :  if (present(out_eigvec)) out_eigvec = eigvec
    1069              : 
    1070              :  ! Return phonon displacement in reduced coordinates.
    1071       310925 :  if (present(out_displ_red)) call phdispl_cart2red(natom, crystal%gprimd, displ_cart, out_displ_red)
    1072              : 
    1073              :  ! Option to get vectors in reduced coordinates?
    1074              :  !call phdispl_cart2red(natom, crystal%gprimd, out_eigvec, out_eigvec_red)
    1075              : 
    1076              :  ! Compute group velocities.
    1077       310925 :  if (present(dwdq)) call ifc%get_dwdq(crystal, my_qpt, phfrq, eigvec, dwdq, comm_)
    1078              : 
    1079       310925 :  call timab(1748, 2, tsec)
    1080              : 
    1081       341520 : end subroutine ifc_fourq
    1082              : !!***
    1083              : 
    1084              : !!****f* m_ifc/ifc_get_dcdq
    1085              : !! NAME
    1086              : !!  ifc_get_dcdq
    1087              : !!
    1088              : !! FUNCTION
    1089              : !!  Compute the first-derivative of reciprocal space IFCs based on real-space IFCs.
    1090              : !!
    1091              : !! INPUTS
    1092              : !!  ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
    1093              : !!  crystal<crystal_t> = Information on the crystalline structure.
    1094              : !!  comm: MPI communicator
    1095              : !!
    1096              : !! OUTPUT
    1097              : !!  dcdq(2,3,natom,3,natom,3) = first derivatives of reciprocal-space IFCs in cartesian coordinates.
    1098              : !!
    1099              : !! NOTES
    1100              : !!  Using:
    1101              : !!
    1102              : !!    dC/dq = \sum_b C(kappa alpha, kappa' beta) (0,b) (R_kappa'beta (b) - R_kappa alpha)
    1103              : !!
    1104              : !!
    1105              : !! SOURCE
    1106              : 
    1107            0 : subroutine ifc_get_dcdq(ifc, cryst, dcdq, dcdqdq, comm)
    1108              : 
    1109              : !Arguments ------------------------------------
    1110              : !scalars
    1111              :  class(ifc_type),intent(in) :: ifc
    1112              :  type(crystal_t),intent(in) :: cryst
    1113              :  integer,intent(in) :: comm!, dipdip
    1114              : !arrays
    1115              :  real(dp), intent(inout) :: dcdq(3,cryst%natom,3,cryst%natom,3)
    1116              :  real(dp), intent(out) :: dcdqdq(3,cryst%natom,3,3,3)
    1117              :  !real(dp), intent(in) :: dyewq0(cryst%natom,3,cryst%natom,3)
    1118              : 
    1119              : !Local variables-------------------------------
    1120              : !scalars
    1121              :  integer :: ii,jj, mu, kk
    1122              :  real(dp) :: qpt(3)
    1123              : !arrays
    1124            0 :  real(dp) :: dyntmp(2,3,cryst%natom,3,cryst%natom)
    1125            0 :  real(dp) :: dcdqcan(2,3,cryst%natom,3,cryst%natom,3)
    1126            0 :  real(dp) :: dcdqred(2,3,cryst%natom,3,cryst%natom,3)
    1127              : ! ************************************************************************
    1128              : 
    1129              :  ABI_UNUSED((/comm/))
    1130            0 :  qpt=zero ; dyntmp = zero
    1131            0 :  dcdq=zero ; dcdqcan= zero ; dcdqred = zero
    1132            0 :  dcdqdq=zero
    1133              :  ! Compute the derivative based on the canonical coordinates
    1134            0 :  call dynmat_dq(qpt, cryst%natom, ifc%gprim, ifc%nrpt, ifc%rpt, ifc%atmfrc, ifc%wghatm, dcdqcan)
    1135              :  ! We have also to consider the phase factor introduced by the canonical coordinates (shift on
    1136              :  ! atoms coordinates in other unit cells)
    1137              :  ! Only a phase shift, but since we look at the derivative, this also have a contribution here
    1138            0 :  call ftifc_r2q(ifc%atmfrc,dyntmp, ifc%gprim, cryst%natom, 1, ifc%nrpt, ifc%rpt, qpt, ifc%wghatm, comm)
    1139              :  ! Move to reduced coordinates
    1140            0 :  do ii= 1,3
    1141            0 :    do jj=1,3
    1142            0 :      dcdqred(:,:,:,:,:,ii) = dcdqred(:,:,:,:,:,ii)+ifc%gprim(jj,ii)*dcdqcan(:,:,:,:,:,jj)
    1143              :    end do
    1144              :  end do
    1145            0 :  do ii=1,3
    1146            0 :    do mu =1,cryst%natom
    1147            0 :      do jj=1,3
    1148            0 :        do kk=1,3
    1149            0 :          dcdqred(2,ii,mu,jj,:,kk) = dcdqred(2,ii,mu,jj,:,kk)-dyntmp(1,ii,mu,jj,:)*(ifc%trans(kk,:)-ifc%trans(kk,mu))
    1150            0 :          dcdqred(2,ii,mu,jj,:,kk) = dcdqred(2,ii,mu,jj,:,kk)+dyntmp(1,ii,mu,jj,:)*(cryst%xred(kk,:)-cryst%xred(kk,mu))
    1151              :        end do
    1152              :      end do
    1153              :    end do
    1154              :  end do
    1155            0 :  if (ifc%dipdip==1) ABI_WARNING("2D electrostatics + IFCs derivatives from real-space IFCs not fully tested")
    1156              :  ! If long-range electrostatics are treated separately, we need to add here the contribution to the torque
    1157              :  ! Note that there is only a contribution coming from the zone-center IFCs here
    1158              :  ! In 3D the derivative diverges; in 2D it does not, so we can add it with finite difference
    1159              :  !if (dipdip==1 .and. (ifc%sys_dim==2 .or. ifc%sys_dim==3 .or. ifc%sys_dim==4)) then
    1160              :     !do kk=1,3
    1161              :       !if (kk /= ifc%sys_dim-1) then
    1162              :         !do jj=-1,1,2
    1163              :           !qtmp(:) = zero
    1164              :           !qtmp(kk)=jj*0.01_dp
    1165              :           !call ewald9_2D(cryst%natom,ifc%acell,cryst%xred,ifc%rprim,ifc%dielt,dyew_tmp,&
    1166              :           !        qtmp,ifc%zeff,ifc%qdrp_cart,ifc%dielt_env,ifc%dielt_thick,ifc%sys_dim)
    1167              :           !dcdqred(2,:,:,:,:,kk) = dcdqred(2,:,:,:,:,kk)+half*dyew_tmp(2,:,:,:,:)/qtmp(kk)
    1168              :  !       end do
    1169              :  !     end if
    1170              :  !   end do
    1171              :  !end if
    1172              :  ! Move to cartesian coordinates
    1173            0 :  do ii=1,3
    1174            0 :    do jj=1,3
    1175            0 :      dcdq(:,:,:,:,ii)=dcdq(:,:,:,:,ii)+dcdqred(2,:,:,:,:,jj)*cryst%rprimd(ii,jj)
    1176              :    end do
    1177              :  end do
    1178              : 
    1179            0 :  end subroutine ifc_get_dcdq
    1180              : !!***
    1181              : 
    1182              : !!****f* m_ifc/ifc_get_dwdq
    1183              : !! NAME
    1184              : !!  ifc_get_dwdq
    1185              : !!
    1186              : !! FUNCTION
    1187              : !!  Compute phonon group velocities at an arbitrary q-point.
    1188              : !!
    1189              : !! INPUTS
    1190              : !!  crystal<crystal_t> = Information on the crystalline structure.
    1191              : !!  qpt(3)=q-point in reduced coordinates.
    1192              : !!  eigvec(2*3*natom*3*natom) = The eigenvectors of the dynamical matrix.
    1193              : !!  comm: MPI communicator
    1194              : !!
    1195              : !! OUTPUT
    1196              : !!  dwdq(3,3*natom) = Group velocities e.g. d(omega(q))/dq in Cartesian coordinates.
    1197              : !!
    1198              : !! NOTES
    1199              : !!  Using:
    1200              : !!
    1201              : !!    D(q) u(q,nu) = w(q, nu)**2 and <u(q,nu) | u(q,nu')> = \delta_{nu, nu'}
    1202              : !!
    1203              : !!  one can show, using the Hellman-Feynman theorem, that:
    1204              : !!
    1205              : !!    \nabla_q w(q, nu) = 1/(2 w(q, nu))  <u(q, nu)| \nabla_q D(q) | u(q, nu)>
    1206              : !!
    1207              : !! SOURCE
    1208              : 
    1209       227649 : subroutine ifc_get_dwdq(ifc, cryst, qpt, phfrq, eigvec, dwdq, comm)
    1210              : 
    1211              : !Arguments ------------------------------------
    1212              : !scalars
    1213              :  class(ifc_type),intent(in) :: ifc
    1214              :  type(crystal_t),intent(in) :: cryst
    1215              :  integer,intent(in) :: comm
    1216              : !arrays
    1217              :  real(dp),intent(in) :: qpt(3)
    1218              :  real(dp),intent(in) :: phfrq(3*cryst%natom)
    1219              :  real(dp),intent(in) :: eigvec(2,3*cryst%natom,3*cryst%natom)
    1220              :  real(dp),intent(out) :: dwdq(3,3*cryst%natom)
    1221              : 
    1222              : !Local variables-------------------------------
    1223              : !scalars
    1224              :  !integer,save :: enough=0
    1225              :  integer,parameter :: nqpt1=1,option2=2,sumg0=0
    1226              :  integer :: ii,nu,natom3,jj
    1227              :  real(dp) :: hh, eta
    1228              : !arrays
    1229       455298 :  real(dp) :: dddq(2,3*cryst%natom,3*cryst%natom,3),dot(2),qfd(3)
    1230       455298 :  real(dp) :: omat(2,3*cryst%natom,3*cryst%natom)
    1231       455298 :  real(dp) :: dyew(2,3*cryst%natom,3*cryst%natom)
    1232              : ! ************************************************************************
    1233              : 
    1234              :  ABI_UNUSED((/comm/))
    1235       227649 :  natom3 = cryst%natom * 3
    1236              : 
    1237              :  ! Generate the analytical part from the interatomic forces
    1238       227649 :  call dynmat_dq(qpt, cryst%natom, ifc%gprim, ifc%nrpt, ifc%rpt, ifc%atmfrc, ifc%wghatm, dddq)
    1239              : 
    1240              :  ! The analytical dynamical matrix dq has been generated
    1241              :  ! in the normalized canonical coordinate system. Now, the
    1242              :  ! phase is modified, in order to recover the usual (xred) coordinate of atoms.
    1243       910596 :  do ii=1,3
    1244       682947 :    call dymfz9(dddq(:,:,:,ii), cryst%natom, nqpt1, ifc%gprim, option2, qpt, ifc%trans)
    1245    124232646 :    dddq(:,:,:,ii) = dddq(:,:,:,ii) * ifc%acell(ii)
    1246              :  end do
    1247              : 
    1248       227649 :  if (ifc%dipdip == 1.or.ifc%dipquad == 1.or.ifc%quadquad == 1) then
    1249              :    ! Add the gradient of the non-analytical part.
    1250              :    ! Note that dddq is in cartesian coordinates.
    1251              :    ! For the time being, the gradient is computed with finite difference and step hh.
    1252              :    ! TODO: should generalize ewald9 to compute dq.
    1253              :    !enough = enough + 1
    1254              :    !if (enough <= 5)  ABI_WARNING("phonon velocities with dipdip==1 not yet tested.")
    1255              :    hh = 0.01_dp
    1256        69388 :    do ii=1,3
    1257       331731 :      do jj=-1,1,2
    1258              :        ! qcart --> qred
    1259       104082 :        qfd = zero; qfd(ii) = jj
    1260      1665312 :        qfd = matmul(cryst%rprimd, qfd); qfd = qfd / normv(qfd, cryst%gmet, "G")
    1261              :        !write(std_out,*)"normv:",normv(qfd, cryst%gmet, "G")
    1262       416328 :        qfd = qpt + hh * qfd
    1263              : 
    1264              :        call ewald9(ifc%acell,ifc%dielt,dyew,cryst%gmet,ifc%gprim,cryst%natom,qfd,&
    1265              :           cryst%rmet,ifc%rprim,sumg0,cryst%ucvol,cryst%xred,ifc%zeff,ifc%qdrp_cart, eta, &
    1266       104082 :           ifc%ewald_option,dipquad=ifc%dipquad,quadquad=ifc%quadquad)
    1267       104082 :        call q0dy3_apply(cryst%natom,ifc%dyewq0,dyew)
    1268     11943351 :        dddq(:,:,:,ii) = dddq(:,:,:,ii) + (jj * half / hh) * dyew
    1269              :      end do
    1270              :    end do
    1271              :  end if
    1272              : 
    1273       910596 :  do ii=1,3
    1274       910596 :    call massmult_and_breaksym(cryst%natom, cryst%ntypat, cryst%typat, ifc%amu, dddq(:,:,:,ii))
    1275              :  end do
    1276              : 
    1277              :  ! Compute 1/(2w(q)) <u(q)|dD(q)/dq|u(q)>
    1278       910596 :  do ii=1,3
    1279       682947 :    call zgemm('N','N',natom3,natom3,natom3,cone,dddq(:,:,:,ii),natom3,eigvec,natom3,czero,omat,natom3)
    1280      5145393 :    do nu=1,natom3
    1281      4917744 :      if (abs(phfrq(nu)) > tol12) then
    1282      4234005 :        dot = cg_zdotc(natom3, eigvec(1,1,nu), omat(1,1,nu))
    1283              :        ! abs(w) is needed to get the correct derivative if we have a purely imaginary solution.
    1284      4234005 :        dwdq(ii, nu) = dot(1) / (two * abs(phfrq(nu)))
    1285              :      else
    1286          792 :        dwdq(ii, nu) = zero
    1287              :      end if
    1288              :    end do
    1289              :  end do
    1290              : 
    1291       227649 : end subroutine ifc_get_dwdq
    1292              : !!***
    1293              : 
    1294              : !----------------------------------------------------------------------
    1295              : 
    1296              : !!****f* m_ifc/ifc_get_phmesh
    1297              : !! NAME
    1298              : !!  ifc_get_phmesh
    1299              : !!
    1300              : !! FUNCTION
    1301              : !!  Build linear mesh for phonons.
    1302              : !!
    1303              : !! INPUTS
    1304              : !!
    1305              : !! OUTPUT
    1306              : !!
    1307              : !! SOURCE
    1308              : 
    1309           65 : subroutine ifc_get_phmesh(ifc, ph_wstep, phmesh_size, phmesh)
    1310              : 
    1311              : !Arguments ------------------------------------
    1312              : !scalars
    1313              :  class(ifc_type),intent(in) :: ifc
    1314              :  real(dp),intent(in) :: ph_wstep
    1315              :  integer,intent(out) :: phmesh_size
    1316              : !arrays
    1317              :  real(dp),allocatable,intent(out) :: phmesh(:)
    1318              : !******************************************************************
    1319              : 
    1320           65 :  phmesh_size = nint((ifc%omega_minmax(2) - ifc%omega_minmax(1) ) / ph_wstep) + 1
    1321          195 :  ABI_MALLOC(phmesh, (phmesh_size))
    1322           65 :  phmesh = arth(ifc%omega_minmax(1), ph_wstep, phmesh_size)
    1323              : 
    1324           65 : end subroutine ifc_get_phmesh
    1325              : !!***
    1326              : 
    1327              : !----------------------------------------------------------------------
    1328              : 
    1329              : !!****f* m_ifc/ifc_speedofsound
    1330              : !!
    1331              : !! NAME
    1332              : !! ifc_speedofsound
    1333              : !!
    1334              : !! FUNCTION
    1335              : !!  Calculate the speed of sound by averaging the phonon group velocities of the
    1336              : !!  three acoustic modes on a small sphere of radius qrad centered around Gamma.
    1337              : !!  Perform spherical integration with Lebedev-Laikov grids
    1338              : !!
    1339              : !! INPUTS
    1340              : !! crystal<crystal_t> = Information on the crystalline structure.
    1341              : !! qrad_tolkms(2):
    1342              : !!   qrad=Radius of the sphere in reciprocal space
    1343              : !!   atols_kms=Absolute tolerance in kilometer/second. The code generates spherical meshes
    1344              : !!     until the results are converged twice within atols_kms.
    1345              : !! ncid=the id of the open NetCDF file. Use nctk_noid to disable netcdf output.
    1346              : !! comm=MPI communicator.
    1347              : !!
    1348              : !! OUTPUT
    1349              : !!
    1350              : !! SOURCE
    1351              : 
    1352            1 : subroutine ifc_speedofsound(ifc, crystal, qrad_tolkms, ncid, comm)
    1353              : 
    1354              : !Arguments -------------------------------
    1355              : !scalars
    1356              :  class(ifc_type),intent(in) :: ifc
    1357              :  integer,intent(in) :: comm,ncid
    1358              :  type(crystal_t),intent(in) :: crystal
    1359              : !arrays
    1360              :  real(dp),intent(in) :: qrad_tolkms(2)
    1361              : 
    1362              : !Local variables -------------------------
    1363              : !scalars
    1364              :  integer,parameter :: master=0
    1365              :  integer :: ii,nu,igrid,my_rank,nprocs,ierr,converged,npts,num_negw,vs_ierr,ncerr
    1366              :  integer :: iatom,iatref,num_acoustic,isacoustic
    1367              :  real(dp) :: min_negw,cpu,wall,gflops, qrad,tolkms,diff
    1368              :  character(len=500) :: msg
    1369            1 :  type(lebedev_t) :: lgrid
    1370              : !arrays
    1371              :  integer :: asnu(3)
    1372              :  real(dp) :: qred(3),qvers_cart(3),qvers_red(3),quad(3),prev_quad(3),vs(7,3)
    1373            3 :  real(dp) :: phfrqs(3*crystal%natom),dwdq(3,3*crystal%natom)
    1374            2 :  real(dp) :: displ_cart(2,3*crystal%natom,3*crystal%natom),eigvec(2,3*crystal%natom,3*crystal%natom)
    1375              : ! *********************************************************************
    1376              : 
    1377            1 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
    1378              : 
    1379            1 :  if (ifc%asr == 0) ABI_WARNING("Computing speed of sound with asr == 0! Use asr > 0")
    1380            1 :  qrad = qrad_tolkms(1); tolkms = qrad_tolkms(2)
    1381            1 :  ABI_CHECK(qrad > zero, "vs_qrad <= 0")
    1382            1 :  ABI_CHECK(tolkms > zero, "vs_tolkms <= 0")
    1383              : 
    1384            1 :  call cwtime(cpu, wall, gflops, "start")
    1385              : 
    1386              :  ! Find the index of the first acoustic modes (needed to handle systems with unstable branches at Gamma
    1387              :  ! In this case, indeed, we end up computing derivatives for the wrong branches, the integration becomes
    1388              :  ! unstable and difficult to converge.
    1389            1 :  qred = zero
    1390            1 :  call ifc%fourq(crystal, qred, phfrqs, displ_cart,out_eigvec=eigvec)
    1391              :  !write(std_out,*)"omega(q==Gamma): ",phfrqs
    1392              : 
    1393            1 :  num_acoustic = 0
    1394            3 :  do nu = 1, 3*crystal%natom
    1395              :    ! Check if this mode is acoustic like: scalar product of all displacement vectors are collinear
    1396           12 :    isacoustic = 1
    1397              :    ! Find reference atom with non-zero displacement
    1398           12 :    do iatom=1,crystal%natom
    1399           93 :      if(sum(displ_cart(:,(iatom-1)*3+1:(iatom-1)*3+3,nu)**2) >tol16)iatref=iatom
    1400              :    end do
    1401              :    ! Now compute scalar product, and check they are all positive
    1402           12 :    do iatom = 1, crystal%natom
    1403           93 :      if (sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3, nu)*eigvec(:,(iatref-1)*3+1:(iatref-1)*3+3, nu)) < tol16 ) isacoustic = 0
    1404              :    end do
    1405            4 :    if (isacoustic == 1) then
    1406            3 :      num_acoustic=num_acoustic+1
    1407            3 :      asnu(num_acoustic)=nu
    1408            3 :      if (num_acoustic==3) exit
    1409              :    end if
    1410              :  end do
    1411              : 
    1412            1 :  ABI_CHECK(num_acoustic == 3, sjoin("Wrong number of acoustic modes:", itoa(num_acoustic)))
    1413              : 
    1414            1 :  write(std_out,"(a,3i2,a)") "The bands with indices ",asnu(:)," will be used to calculate the sound velocities"
    1415              : 
    1416              :  ! Speed of sound along reduced directions.
    1417            7 :  do ii=1,6
    1418            6 :    qred = zero; qred(MOD(ii-1,3)+1) = one
    1419           42 :    if (ii >= 4 .and. ii <= 6) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
    1420              :    !if (ii >= 7 .and. ii <= 9) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
    1421           24 :    qvers_red = (qred / normv(qred, crystal%gmet, "G"))
    1422           24 :    qred = qrad * qvers_red
    1423              :    !write(std_out,*)"dir",normv(qred, crystal%gmet, "G"), qrad
    1424            6 :    call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
    1425              : 
    1426           24 :    do nu=1,3
    1427           78 :      vs(ii, nu) = sqrt(sum(dwdq(1:3,asnu(nu)) ** 2)) * Bohr_meter * 0.001_dp / Time_Sec
    1428              :    end do
    1429            6 :    write(std_out,"(a,3es12.4,a)")" ||vs(nu)||:",vs(ii,:), " [km/s]"
    1430              : 
    1431           96 :    qvers_cart = matmul(crystal%gprimd, qvers_red) * two_pi
    1432           24 :    do nu=1,3
    1433           78 :      vs(ii, nu) = dot_product(dwdq(1:3,asnu(nu)), qvers_cart) * Bohr_meter * 0.001_dp / Time_Sec
    1434              :    end do
    1435            7 :    write(std_out,"(a,3es12.4,a)")" <q|vs(nu)>:",vs(ii,:), " [km/s]"
    1436              : 
    1437              :    !do nu=1,3
    1438              :    !  write(std_out,"(a,3es12.4,a)")" vs(nu)_vect_red:",&
    1439              :    !     matmul(crystal%gprimd, dwdq(1:3,asnu(nu))) * Bohr_meter * 0.001_dp / Time_Sec, " [km/s]"
    1440              :    !end do
    1441              :  end do
    1442              : 
    1443              :  ! Spherical average with Lebedev-Laikov grids.
    1444            1 :  converged = 0
    1445            5 :  do igrid=1,lebedev_ngrids
    1446            5 :    call lgrid%from_index(igrid)
    1447            5 :    npts = lgrid%npts; quad = zero; num_negw = 0; min_negw = zero
    1448          139 :    do ii=1,npts
    1449          134 :      if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
    1450              : 
    1451              :      ! Build q-point on sphere of radius qrad. qcart --> qred
    1452         1742 :      qred = matmul(crystal%rprimd, lgrid%versors(:, ii))
    1453          536 :      qred = qrad * (qred / normv(qred, crystal%gmet, "G"))
    1454              :      !write(std_out,*)"lebe",normv(qred, crystal%gmet, "G"), qrad
    1455          134 :      call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
    1456          536 :      if (any(phfrqs(asnu) < -tol8)) then
    1457            0 :        num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs(asnu)))
    1458              :      end if
    1459              : 
    1460          541 :      do nu=1,3
    1461         1742 :        quad(nu) = quad(nu) + lgrid%weights(ii) * sqrt(sum(dwdq(1:3,asnu(nu)) ** 2))
    1462              :        !quad(nu) = quad(nu) + lgrid%weights(ii) * abs(dot_product(lgrid%versors(:,ii), dwdq(:,asnu(nu))))
    1463              :      end do
    1464              :    end do
    1465              : 
    1466              :    ! Will use km/sec unit for echo purposes
    1467           20 :    quad = quad * Bohr_meter * 0.001_dp / Time_Sec
    1468            5 :    call xmpi_sum(quad, comm, ierr)
    1469            5 :    call xmpi_sum(num_negw, comm, ierr)
    1470            5 :    call lgrid%free()
    1471              : 
    1472              :    write(std_out,'(2(a,i6),a,3es12.4,a,es12.4)') &
    1473           20 :      " Lebedev-Laikov grid: ",igrid,", npts: ", npts, " vs_sphavg(ac_modes): ",quad, " <vs>: ",sum(quad)/3
    1474              : 
    1475            5 :    if (igrid > 1) then
    1476              :      diff = zero
    1477           16 :      do nu=1,3
    1478           16 :        diff = diff + abs(quad(nu) - prev_quad(nu)) / 3
    1479              :      end do
    1480              :      !if (abs(sum(quad - prev_quad)/3) < tolkms) then
    1481            4 :      if (diff < tolkms) then
    1482            2 :         converged = converged + 1
    1483              :      else
    1484              :         converged = 0
    1485              :      end if
    1486              :    end if
    1487            5 :    prev_quad = quad
    1488           20 :    vs(7, :) = quad
    1489           10 :    if (converged == 2) exit
    1490              :  end do ! igrid
    1491              : 
    1492            1 :  if (my_rank == master) then
    1493              :    ! vs_err: 1 if not converged, < 0 if negative freqs, == 0 if success.
    1494            1 :    vs_ierr = 0
    1495            4 :    do ii=1,3
    1496            4 :      write(ab_out,"(a,3es12.4,a,i1)")" Speed of sound:",vs(ii,:)," [km/s] along reduced direction: ",ii
    1497              :    end do
    1498              :    write(ab_out,'(2(a,es12.4),a,i0)') &
    1499            1 :      " Lebedev-Laikov integration with qradius: ", qrad, " tolkms: ",tolkms, " [km/s], npts: ", npts
    1500            4 :    write(ab_out,"(a,3es12.4,a,es12.4)")" Spherical average:",vs(7,:)," [km/s], ",sum(vs(7,:))/3
    1501            1 :    if (converged /= 2) then
    1502            0 :      vs_ierr = 1
    1503            0 :      write(msg,'(a,es12.4,a)')" WARNING: Results are not converged within: ",tolkms, " [km/s]"
    1504            0 :      call wrtout(ab_out, msg)
    1505            0 :      ABI_WARNING(msg)
    1506              :    end if
    1507            1 :    if (num_negw > 0) then
    1508            0 :      vs_ierr = -num_negw
    1509              :      write(msg,'(a,i0,a,es12.4,3a)') &
    1510            0 :        " WARNING: Detected ",num_negw, " negative frequencies. Minimum was: ",min_negw * Ha_meV, "[meV]",ch10,&
    1511            0 :        " Speed of sound could be wrong"
    1512            0 :      call wrtout(ab_out, msg)
    1513            0 :      ABI_WARNING(msg)
    1514              :    end if
    1515              : 
    1516              :    ! Dump results to netcdf file.
    1517            1 :    if (ncid /= nctk_noid) then
    1518            2 :      ncerr = nctk_def_arrays(ncid, [nctkarr_t("vsound", "dp", "seven, three")], defmode=.True.)
    1519            1 :      NCF_CHECK(ncerr)
    1520            2 :      ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: "vsound_ierr"])
    1521            1 :      NCF_CHECK(ncerr)
    1522            3 :      ncerr = nctk_def_dpscalars(ncid, [character(len=nctk_slen) :: "vsound_qrad", "vsound_tolkms"])
    1523            1 :      NCF_CHECK(ncerr)
    1524            2 :      ncerr = nctk_def_arrays(ncid, [nctkarr_t("asnu", "i", "three")], defmode=.True.)
    1525            1 :      NCF_CHECK(ncerr)
    1526              :      ! Write data.
    1527            1 :      NCF_CHECK(nctk_set_datamode(ncid))
    1528            1 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_ierr"), vs_ierr))
    1529            1 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_qrad"), qrad))
    1530            1 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_tolkms"), tolkms))
    1531            1 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound"), vs))
    1532            1 :      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "asnu"), asnu))
    1533              :    end if
    1534              :  end if
    1535              : 
    1536            1 :  call cwtime_report(" ifc_speedofsound", cpu, wall, gflops)
    1537              : 
    1538            1 : end subroutine ifc_speedofsound
    1539              : !!***
    1540              : 
    1541              : !----------------------------------------------------------------------
    1542              : 
    1543              : !!****f* m_ifc/ifc_autocutoff
    1544              : !! NAME
    1545              : !!  ifc_autocutoff
    1546              : !!
    1547              : !! FUNCTION
    1548              : !! Find the value of nsphere that gives non-negative frequencies around Gamma
    1549              : !! in a small sphere of radius qrad.
    1550              : !! Use bisection to reduce the number of attempts although there's no guarantee
    1551              : !! that the number of negative frequencies is monotonic.
    1552              : !!
    1553              : !! INPUTS
    1554              : !!  crystal<crystal_t> = Information on the crystalline structure.
    1555              : !!  comm=MPI communicator
    1556              : !!
    1557              : !! SIDE EFFECTS
    1558              : !!  ifc%wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
    1559              : !!    with the last cutoff found by the bisection algorithm applied.
    1560              : !!  ifc%atmfrc(2,3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces
    1561              : !!
    1562              : !! SOURCE
    1563              : 
    1564            1 : subroutine ifc_autocutoff(ifc, crystal, comm)
    1565              : 
    1566              : !Arguments ------------------------------------
    1567              : !scalars
    1568              :  class(ifc_type),intent(inout) :: ifc
    1569              :  type(crystal_t),intent(in) :: crystal
    1570              :  integer,intent(in) :: comm
    1571              : 
    1572              : !Local variables-------------------------------
    1573              : !scalars
    1574              :  integer,parameter :: master=0
    1575              :  integer :: iq_ibz,ierr,my_rank,nprocs,ii,nsphere,num_negw,jl,ju,jm,natom,nrpt
    1576              :  real(dp),parameter :: rifcsph0 = zero
    1577              :  real(dp) :: adiff,qrad,min_negw,xval,rcut_min
    1578            1 :  type(lebedev_t) :: lgrid
    1579              : !arrays
    1580            2 :  real(dp) :: displ_cart(2*3*ifc%natom*3*ifc%natom)
    1581            2 :  real(dp) :: qred(3),qred_vers(3),phfrqs(3*ifc%natom) !,dwdq(3,3*ifc%natom)
    1582            1 :  real(dp),allocatable :: ref_phfrq(:,:),cut_phfrq(:,:), save_wghatm(:,:,:),save_atmfrc(:,:,:,:,:)
    1583              : ! *********************************************************************
    1584              : 
    1585            1 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
    1586            1 :  natom = ifc%natom; nrpt = ifc%nrpt
    1587              : 
    1588              :  ! Compute frequencies on the ab-initio q-mesh without cutoff.
    1589         1828 :  ABI_CALLOC(ref_phfrq, (3*natom, ifc%nqibz))
    1590           97 :  do iq_ibz=1,ifc%nqibz
    1591           96 :    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
    1592           97 :    call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), ref_phfrq(:,iq_ibz), displ_cart)
    1593              :  end do
    1594            1 :  call xmpi_sum(ref_phfrq, comm, ierr)
    1595              : 
    1596            5 :  ABI_MALLOC(save_wghatm, (natom,natom,nrpt))
    1597            6 :  ABI_MALLOC(save_atmfrc, (3,natom,3,natom,ifc%nrpt))
    1598       512503 :  save_wghatm = ifc%wghatm; save_atmfrc = ifc%atmfrc
    1599              : 
    1600            4 :  ABI_MALLOC(cut_phfrq, (3*natom, ifc%nqibz))
    1601            1 :  qrad = 0.01
    1602            1 :  call lgrid%from_index(16)
    1603              : 
    1604            1 :  if (my_rank == master) then
    1605            1 :    write(ab_out, "(a)")" Apply cutoff on IFCs. Using bisection algorithm to find initial guess for nsphere."
    1606            1 :    write(ab_out, "(a,i0)")" Maximum number of atom-centered spheres: ",natom * nrpt
    1607            1 :    write(ab_out, "(a,i0,a,f5.3)")" Using Lebedev-Laikov grid with npts: ",lgrid%npts, ", qrad: ",qrad
    1608            1 :    write(ab_out, "(/,a)")" <adiff>: Average difference between ab-initio frequencies and frequencies with cutoff."
    1609            1 :    write(ab_out, "(a)")" num_negw: Number of negative freqs detected in small sphere around Gamma."
    1610            1 :    write(ab_out, "(a)")" min_negw: Min negative frequency on the small sphere."
    1611            1 :    write(ab_out, "(a,/,/)")" rifcsph: Effective cutoff radius corresponding to nsphere."
    1612            1 :    write(ab_out, "(a)")" nsphere   <adiff>[meV]   num_negw   min_negw[meV]   rifcsph"
    1613              :  end if
    1614              : 
    1615            1 :  jl = 0; ju = natom * nrpt + 1 ! Initialize lower and upper limits.
    1616           39 :  do
    1617           14 :    if (ju - jl <= 1) then
    1618              :      exit
    1619              :    end if
    1620           13 :    jm = (ju + jl) / 2  ! Compute a midpoint
    1621           13 :    nsphere = jm
    1622              : 
    1623      6662539 :    ifc%wghatm = save_wghatm; ifc%atmfrc = save_atmfrc
    1624           13 :    call corsifc9(ifc%acell,ifc%gprim, natom, nrpt,nsphere,rifcsph0,ifc%rcan,ifc%rprim,ifc%rpt,rcut_min,ifc%wghatm)
    1625           13 :    if (ifc%asr > 0) call asrif9(ifc%asr,ifc%atmfrc,ifc%natom,ifc%nrpt,ifc%rpt,ifc%wghatm)
    1626              : 
    1627        23725 :    cut_phfrq = zero
    1628         1261 :    do iq_ibz=1,ifc%nqibz
    1629         1248 :      if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
    1630         1261 :      call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), cut_phfrq(:,iq_ibz), displ_cart)
    1631              :      !write(std_out,*)cut_phfrq(1,iq_ibz),ref_phfrq(1,iq_ibz)
    1632              :    end do
    1633           13 :    call xmpi_sum(cut_phfrq, comm, ierr)
    1634              : 
    1635              :    ! Test whether there are negative frequencies around gamma, including reciprocal lattice vectors.
    1636           13 :    num_negw = 0; min_negw = zero
    1637         5694 :    do ii=1,lgrid%npts+3
    1638         5681 :      if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
    1639         5681 :      if (ii <= 3) then
    1640           39 :        qred = zero; qred(ii) = one
    1641              :      else
    1642        73346 :        qred = matmul(crystal%rprimd, lgrid%versors(:, ii-3))
    1643              :      end if
    1644        22724 :      qred_vers = (qred / normv(qred, crystal%gmet, "G"))
    1645        22724 :      qred = qrad * qred_vers
    1646         5681 :      call ifc%fourq(crystal, qred, phfrqs, displ_cart) !, dwdq=dwdq)
    1647        96036 :      if (any(phfrqs < +tol8)) then
    1648        13240 :        num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs))
    1649              :      end if
    1650              :      !do jj=1,3
    1651              :      !  xval = dot_product(dwdq(:,jj), matmul(crystal%gprimd, qred_vers))
    1652              :      !  if (xval < zero) num_negw = num_negw + 1
    1653              :      !end do
    1654              :    end do
    1655           13 :    call xmpi_sum(num_negw, comm, ierr)
    1656           13 :    xval = min_negw; call xmpi_min(xval, min_negw, comm, ierr)
    1657              : 
    1658        23725 :    adiff = sum(abs(cut_phfrq - ref_phfrq)) / (ifc%nqibz * 3 * natom)
    1659           13 :    if (my_rank == master) then
    1660              :      write(ab_out,"(a,i7,1x,es13.4,4x,i8,1x,es13.4,2x,es13.4)") &
    1661           13 :        "-",nsphere, adiff * Ha_meV, num_negw, min_negw * Ha_meV, rcut_min
    1662              :    end if
    1663              : 
    1664           14 :    if (num_negw == 0) then
    1665              :      jl = jm ! Replace lower limit
    1666              :    else
    1667            9 :      ju = jm ! Replace upper limit
    1668              :    end if
    1669              :  end do
    1670              : 
    1671            1 :  ABI_FREE(ref_phfrq)
    1672            1 :  ABI_FREE(cut_phfrq)
    1673            1 :  ABI_FREE(save_wghatm)
    1674            1 :  ABI_FREE(save_atmfrc)
    1675            1 :  call lgrid%free()
    1676              : 
    1677            2 : end subroutine ifc_autocutoff
    1678              : !!***
    1679              : 
    1680              : !----------------------------------------------------------------------
    1681              : 
    1682              : !!****f* m_ifc/corsifc9
    1683              : !! NAME
    1684              : !! corsifc9
    1685              : !!
    1686              : !! FUNCTION
    1687              : !! Applies a cutoff on the ifc in real space
    1688              : !!
    1689              : !! INPUTS
    1690              : !! acell(3)=length scales by which rprim is to be multiplied
    1691              : !! gprim(3,3)=dimensionless primitive translations in reciprocal space
    1692              : !! natom=number of atoms in unit cell
    1693              : !! nrpt= Number of R points in the Big Box
    1694              : !! rcan(3,natom)=canonical coordinates of atoms
    1695              : !! rprim(3,3)=dimensionless primitive translations in real space
    1696              : !! rpt(3,nrpt)=canonical coordinates of the points in the BigBox.
    1697              : !! nsphere=number of atoms to be included in the cut-off sphere for interatomic
    1698              : !!  force constant; if = 0 : maximum extent allowed by the grid.
    1699              : !! rifcsph=radius for cutoff of IFC
    1700              : !! wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector.
    1701              : !!
    1702              : !! OUTPUT
    1703              : !! wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
    1704              : !!  with the required cutoff applied.
    1705              : !! rcut_min=Effective cutoff. Defined by the minimum cutoff radius over the natom sites.
    1706              : !!
    1707              : !! SOURCE
    1708              : 
    1709           16 : subroutine corsifc9(acell,gprim,natom,nrpt,nsphere,rifcsph,rcan,rprim,rpt,rcut_min,wghatm)
    1710              : 
    1711              : !Arguments -------------------------------
    1712              : !scalars
    1713              :  integer,intent(in) :: natom,nrpt,nsphere
    1714              :  real(dp),intent(in) :: rifcsph
    1715              :  real(dp),intent(out) :: rcut_min
    1716              : !arrays
    1717              :  real(dp),intent(in) :: acell(3), gprim(3,3),rcan(3,natom), rprim(3,3),rpt(3,nrpt)
    1718              :  real(dp),intent(inout) :: wghatm(natom,natom,nrpt)
    1719              : 
    1720              : !Local variables -------------------------
    1721              : !scalars
    1722              :  integer :: ia,ib,ii,index,irpt
    1723              :  real(dp) :: rmax,rsigma,r0
    1724              : !arrays
    1725           16 :  integer,allocatable :: list(:)
    1726           16 :  real(dp),allocatable :: dist(:,:,:),wkdist(:)
    1727              : ! *********************************************************************
    1728              : 
    1729              :  ! Compute the distances between atoms
    1730              :  ! dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
    1731           80 :  ABI_MALLOC(dist,(natom,natom,nrpt))
    1732           16 :  call dist9(acell,dist,gprim,natom,nrpt,rcan,rprim,rpt)
    1733              : 
    1734           48 :  ABI_MALLOC(list,(natom*nrpt))
    1735           48 :  ABI_MALLOC(wkdist,(natom*nrpt))
    1736              : 
    1737              :  ! loop on all generic atoms.
    1738           16 :  rcut_min = huge(one)
    1739           99 :  do ia=1,natom
    1740              : 
    1741          166 :    wkdist = reshape(dist(ia,:,:), [natom*nrpt])
    1742       488916 :    do ii=1,natom*nrpt
    1743       488916 :      list(ii)=ii
    1744              :    end do
    1745              :    ! This sorting algorithm is slow ...
    1746           83 :    call sort_dp(natom*nrpt,wkdist,list,tol14)
    1747           83 :    rmax = wkdist(natom*nrpt)
    1748              : 
    1749              :    ! zero the outside IFCs: act on wghatm
    1750              : 
    1751              :    ! fix number of spheres
    1752           83 :    if(nsphere/=0.and.nsphere<natom*nrpt)then
    1753           80 :      rcut_min = min(rcut_min, wkdist(nsphere+1))
    1754       345170 :      do ii=nsphere+1,natom*nrpt
    1755       345090 :        index=list(ii)
    1756       345090 :        irpt=(index-1)/natom+1
    1757       345090 :        ib=index-natom*(irpt-1)
    1758       345170 :        wghatm(ia,ib,irpt)=zero
    1759              :      end do
    1760              :    end if
    1761              : 
    1762              :    ! or fix radius of maximum ifc
    1763           83 :    if(rifcsph>tol10)then
    1764         3648 :      do ii=nsphere+1,natom*nrpt
    1765         3645 :        index=list(ii)
    1766              :        ! preserve weights for atoms inside sphere of radius rifcsph
    1767         3645 :        if (wkdist(ii) < rifcsph) cycle
    1768         3464 :        rcut_min = min(rcut_min, wkdist(ii))
    1769         3464 :        irpt=(index-1)/natom+1
    1770         3464 :        ib=index-natom*(irpt-1)
    1771         3648 :        wghatm(ia,ib,irpt)=zero
    1772              :      end do
    1773              :    end if
    1774              : 
    1775              :    ! filter smoothly to 0 at edge of WS cell
    1776           99 :    if (rifcsph < -tol10) then
    1777              :      ! Use different filter
    1778            0 :      r0 = abs(rifcsph) * rmax; rsigma = half*(rmax-r0) !one
    1779            0 :      rcut_min = r0 ! Set it to r0
    1780            0 :      do ii=nsphere+1,natom*nrpt
    1781            0 :        index=list(ii)
    1782            0 :        irpt=(index-1)/natom+1
    1783            0 :        ib=index-natom*(irpt-1)
    1784            0 :        wghatm(ia,ib,irpt) = wghatm(ia,ib,irpt) * half * abi_derfc((wkdist(ii) - r0) / rsigma)
    1785              :      end do
    1786              :    end if
    1787              : 
    1788              :  end do
    1789              : 
    1790           16 :  ABI_FREE(dist)
    1791           16 :  ABI_FREE(list)
    1792           16 :  ABI_FREE(wkdist)
    1793              : 
    1794           16 : end subroutine corsifc9
    1795              : !!***
    1796              : 
    1797              : !----------------------------------------------------------------------
    1798              : 
    1799              : !!****f* m_ifc/ifc_write
    1800              : !! NAME
    1801              : !! ifc_write
    1802              : !!
    1803              : !! FUNCTION
    1804              : !! Adds the real-space interatomic force constants to:
    1805              : !!  the output file,
    1806              : !!  a NetCDF file which is already open on ncid
    1807              : !!  if prt_ifc==1, to the ifcinfo.out file
    1808              : !!  to a TDEP file named outfile.forceconstants_ABINIT
    1809              : !!
    1810              : !! INPUTS
    1811              : !! ifcana= 0 => no analysis of ifc ; 1 => full analysis
    1812              : !! atifcflg(natom) =  atifcflg(ia) equals 1 if the analysis of ifc has to be done for atom ia; otherwise 0.
    1813              : !! ifcout= Number of interatomic force constants written in the output file
    1814              : !! prt_ifc = flag to print out ifc information for dynamical matrix (AI2PS)
    1815              : !! ncid=the id of the open NetCDF file. Set to nctk_noid if netcdf output is not wanted.
    1816              : !!
    1817              : !! OUTPUT
    1818              : !!   written in the output file and in the NetCDF file
    1819              : !!
    1820              : !! NOTES
    1821              : !! This routine should be executed by one processor only
    1822              : !!
    1823              : !! TODO:
    1824              : !!  1) ifc_write should not have side effects
    1825              : !!
    1826              : !!  2) the code is unreadable and horrible - 3/4 different file formats for the
    1827              : !!  same stuff. We should make different subroutines, even if it duplicates some code
    1828              : !!
    1829              : !!  3) The name of the output files should respect the conventions of the code.
    1830              : !!     This routine should take a file prefix as argument.
    1831              : !!
    1832              : !! SOURCE
    1833              : 
    1834           65 : subroutine ifc_write(Ifc,ifcana,atifcflg,ifcout,prt_ifc,ncid,prefix,&
    1835              :                      unit_out) ! optional arguments
    1836              : 
    1837              : !Arguments -------------------------------
    1838              : !scalars
    1839              :  class(ifc_type),intent(inout) :: Ifc
    1840              :  integer,intent(in) :: ifcout,ifcana,prt_ifc,ncid
    1841              :  integer,optional,intent(in) :: unit_out
    1842              :  character(*),intent(in) :: prefix
    1843              : !arrays
    1844              :  integer,intent(in) :: atifcflg(Ifc%natom)
    1845              : 
    1846              : !Local variables -------------------------
    1847              : !scalars
    1848              :  integer :: ia,ib,ii,ncerr,iatifc,ifcout1,mu,nu,iout, irpt, unit_ifc, unit_tdep
    1849              :  real(dp) :: detdlt, maxdist_tdep
    1850              :  character(len=fnlen) :: filename
    1851              :  character(len=500) :: msg
    1852              :  character(len=4) :: str1, str2
    1853              : !arrays
    1854           65 :  integer,allocatable :: list(:),indngb(:)
    1855              :  real(dp) :: invdlt(3,3),ra(3),xred(3),dielt(3,3), gprimd(3,3),rprimd(3,3)
    1856           65 :  real(dp),allocatable :: dist(:,:,:),wkdist(:),rsiaf(:,:,:),sriaf(:,:,:),vect(:,:,:), posngb(:,:),wghia(:)
    1857              : ! *********************************************************************
    1858              : 
    1859           65 :  iout = ab_out; if (present(unit_out)) iout = unit_out
    1860          845 :  dielt = ifc%dielt
    1861              : 
    1862              :  ! Compute the distances between atoms
    1863          325 :  ABI_MALLOC(dist,(Ifc%natom,Ifc%natom,Ifc%nrpt))
    1864           65 :  call dist9(Ifc%acell,dist,Ifc%gprim,Ifc%natom,Ifc%nrpt,Ifc%rcan,Ifc%rprim,Ifc%rpt)
    1865              :  ! Now dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
    1866              : 
    1867          195 :  ABI_MALLOC(list,(Ifc%natom*Ifc%nrpt))
    1868          195 :  ABI_MALLOC(wkdist,(Ifc%natom*Ifc%nrpt))
    1869              : 
    1870              :  ! Calculating the inverse (transpose) of the dielectric tensor
    1871           65 :  call matr3inv(dielt,invdlt)
    1872              : 
    1873              :  ! Calculating the determinant of the dielectric tensor
    1874              :  detdlt=dielt(1,1)*dielt(2,2)*dielt(3,3)+dielt(1,3)*dielt(2,1)*&
    1875              :         dielt(3,2)+dielt(1,2)*dielt(2,3)*dielt(3,1)-dielt(1,3)*&
    1876              :         dielt(2,2)*dielt(3,1)-dielt(1,1)*dielt(2,3)*dielt(3,2)-&
    1877           65 :         dielt(1,2)*dielt(2,1)*dielt(3,3)
    1878              : 
    1879              : ! echo to log file
    1880           65 :  write(std_out,'(a)' )' ifc_write: analysis of interatomic force constants '
    1881           65 :  call mkrdim(Ifc%acell,Ifc%rprim,rprimd)
    1882           65 :  call matr3inv(rprimd,gprimd)
    1883              : 
    1884           65 :  if (iout > 0) then
    1885           65 :    write(iout, '(/,a,/)' )' Analysis of interatomic force constants '
    1886           65 :    if(Ifc%dipdip==1.and.Ifc%dipquad==0.and.Ifc%quadquad==0)then
    1887           17 :      write(iout, '(a)' )' Are given : column(1-3), the total force constant'
    1888           17 :      write(iout, '(a)' )'       then  column(4-6), the Ewald part'
    1889           17 :      write(iout, '(a)' )'       then  column(7-9), the short-range part'
    1890           17 :      write(iout, '(a)' )' Column 1, 4 and 7 are related to the displacement'
    1891           17 :      write(iout, '(a)' )'       of the generic atom along x,               '
    1892           17 :      write(iout, '(a)' )' column 2, 5 and 8 are related to the displacement'
    1893           17 :      write(iout, '(a)' )'       of the generic atom along y,               '
    1894           17 :      write(iout, '(a)' )' column 3, 6 and 9 are related to the displacement'
    1895           17 :      write(iout, '(a)')'       of the generic atom along z.               '
    1896           48 :    else if(Ifc%dipquad==1.or.Ifc%quadquad==1)then
    1897            0 :      write(iout, '(a)' )' Are given : column(1-3), ONLY the short-range part!!!!'
    1898            0 :      write(iout, '(a)' )' column 1 is related to the displacement'
    1899            0 :      write(iout, '(a)' )'        of the generic atom along x,    '
    1900            0 :      write(iout, '(a)' )' column 2 is related to the displacement'
    1901            0 :      write(iout, '(a)' )'        of the generic atom along y,    '
    1902            0 :      write(iout, '(a)' )' column 3 is related to the displacement'
    1903            0 :      write(iout, '(a)' )'        of the generic atom along z,    '
    1904           48 :    else if(Ifc%dipdip==0)then
    1905           48 :      write(iout, '(a)' )' column 1 is related to the displacement'
    1906           48 :      write(iout, '(a)' )'        of the generic atom along x,    '
    1907           48 :      write(iout, '(a)' )' column 2 is related to the displacement'
    1908           48 :      write(iout, '(a)' )'        of the generic atom along y,    '
    1909           48 :      write(iout, '(a)' )' column 3 is related to the displacement'
    1910           48 :      write(iout, '(a)' )'        of the generic atom along z,    '
    1911              :    end if
    1912              :  end if
    1913              : 
    1914           65 :  if (ifcout>Ifc%natom*Ifc%nrpt .or. ifcout == -1) then
    1915            0 :    ifcout1=Ifc%natom*Ifc%nrpt
    1916              :    write(msg, '(3a,i0,a)' )&
    1917            0 :     'The value of ifcout exceeds the number of atoms in the big box.', ch10, &
    1918            0 :     'Output limited to ',Ifc%natom*Ifc%nrpt,' atoms.'
    1919            0 :    ABI_WARNING(msg)
    1920              :  else
    1921           65 :    ifcout1=ifcout
    1922              :  end if
    1923              : 
    1924              :  ! set up file for real space ifc output, if required
    1925           65 :  if (prt_ifc == 1) then
    1926           53 :    filename = trim(prefix)//'_ifcinfo.dat'
    1927           53 :    if (open_file(trim(filename), msg, newunit=unit_ifc, status="replace") /= 0) then
    1928            0 :      ABI_ERROR(msg)
    1929              :    end if
    1930           53 :    write(iout, '(a,a)' )ch10,&
    1931          106 :     '  NOTE: Open file _ifcinfo.dat, for the output of interatomic force constants. This is because prt_ifc==1. '
    1932              : 
    1933           53 :    filename = trim(prefix)//'_forceconstants.dat'
    1934           53 :    if (open_file(trim(filename), msg, newunit=unit_tdep, status="replace") /= 0) then
    1935            0 :      ABI_ERROR(msg)
    1936              :    end if
    1937           53 :    write(iout, '(a,a,a)' )ch10,&
    1938           53 :     '  NOTE: Open file _forceconstants.dat, for the output of interatomic force',&
    1939          106 :     ' constants in TDEP format. This is because prt_ifc==1. '
    1940              :    ! Print necessary stuff for TDEP
    1941           53 :    write(unit_tdep,"(1X,I10,15X,'How many atoms per unit cell')") Ifc%natom
    1942              : 
    1943              :    ! look at all pairs, find furthest one with weight 1
    1944              : !   do ia
    1945              : !Ifc%wghatm(ia,ib,irpt)
    1946           53 :    maxdist_tdep = Ifc%r_inscribed_sphere !maxval(dist)*0.8_dp
    1947           53 :    write(unit_tdep,"(1X,F20.15,5X,'Realspace cutoff (A)')") maxdist_tdep*Bohr_Ang
    1948              :  end if
    1949              : 
    1950           65 :  if (ncid /= nctk_noid) then
    1951              :    ! initialize netcdf variables
    1952              :    ncerr = nctk_def_dims(ncid, [nctkdim_t("natifc", SUM(atifcflg)), nctkdim_t("number_of_r_points_big_box", Ifc%nrpt), &
    1953          499 :      nctkdim_t("number_of_atoms_big_box", Ifc%natom*Ifc%nrpt), nctkdim_t("ifcout", ifcout1)], defmode=.True.)
    1954           65 :    NCF_CHECK(ncerr)
    1955              : 
    1956              :    ncerr = nctk_def_arrays(ncid, [&
    1957              :      nctkarr_t('ifc_atoms_indices', "i", "natifc"),&
    1958              :      nctkarr_t('ifc_neighbours_indices', "i", "ifcout, natifc"),&
    1959              :      nctkarr_t('ifc_distances', "dp", "ifcout, natifc "),&
    1960              :      nctkarr_t('ifc_matrix_cart_coord', "dp", "number_of_cartesian_directions,number_of_cartesian_directions, ifcout, natifc"),&
    1961              :      nctkarr_t('ifc_atoms_cart_coord', "dp", "number_of_cartesian_directions,ifcout, natifc"),&
    1962          455 :      nctkarr_t('ifc_weights', "dp", "ifcout, natifc")])
    1963           65 :    NCF_CHECK(ncerr)
    1964              : 
    1965           65 :    if (Ifc%dipdip==1) then
    1966              :      ncerr = nctk_def_arrays(ncid, [&
    1967              :        nctkarr_t('ifc_matrix_cart_coord_short_range', "dp", &
    1968           34 :        "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
    1969           17 :      NCF_CHECK(ncerr)
    1970              :    end if
    1971              : 
    1972           65 :    if (ifcana==1) then
    1973              :      ncerr = nctk_def_arrays(ncid, [&
    1974          128 :        nctkarr_t('ifc_local_vectors', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
    1975           64 :      NCF_CHECK(ncerr)
    1976              :    end if
    1977              : 
    1978           65 :    NCF_CHECK(nctk_set_datamode(ncid))
    1979              :  end if
    1980              : 
    1981          195 :  ABI_MALLOC(rsiaf,(3,3,ifcout1))
    1982          130 :  ABI_MALLOC(sriaf,(3,3,ifcout1))
    1983          130 :  ABI_MALLOC(vect,(3,3,ifcout1))
    1984          195 :  ABI_MALLOC(indngb,(ifcout1))
    1985          195 :  ABI_MALLOC(posngb,(3,ifcout1))
    1986          195 :  ABI_MALLOC(wghia,(ifcout1))
    1987              : 
    1988           65 :  iatifc=0
    1989              : 
    1990              :  ! BIG loop on all generic atoms
    1991          239 :  do ia=1,Ifc%natom
    1992          239 :    if(atifcflg(ia)==1)then
    1993              : 
    1994          141 :      iatifc=iatifc+1
    1995              : 
    1996              :      ! First transform canonical coordinates to reduced coordinates
    1997          564 :      do ii=1,3
    1998          564 :        xred(ii)=Ifc%gprim(1,ii)*Ifc%rcan(1,ia)+Ifc%gprim(2,ii)*Ifc%rcan(2,ia)+Ifc%gprim(3,ii)*Ifc%rcan(3,ia)
    1999              :      end do
    2000              :      ! Then to cartesian coordinates
    2001          564 :      ra(:)=xred(1)*Ifc%acell(1)*Ifc%rprim(:,1)+ xred(2)*Ifc%acell(2)*Ifc%rprim(:,2)+ xred(3)*Ifc%acell(3)*Ifc%rprim(:,3)
    2002              : 
    2003              :      ! This sorting algorithm is slow ...
    2004          282 :      wkdist(:)=reshape(dist(ia,:,:),(/Ifc%natom*Ifc%nrpt/))
    2005       383886 :      do ii=1,Ifc%natom*Ifc%nrpt
    2006       383886 :        list(ii)=ii
    2007              :      end do
    2008          141 :      call sort_dp(Ifc%natom*Ifc%nrpt,wkdist,list,tol14)
    2009              : 
    2010          141 :      if (iout > 0) then
    2011          141 :        write(iout, '(a)' )
    2012          141 :        write(std_out,'(a,i4)' )' generic atom number',ia
    2013          141 :        write(iout, '(a,i4)' )' generic atom number',ia
    2014          141 :        write(std_out,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
    2015          141 :        write(iout,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
    2016          141 :        write(iout, '(a)' )
    2017              :      end if
    2018              : 
    2019              :      ! =========================================================================== !
    2020              :      ! Side effects happen here
    2021              :      ! The long-range part of the IFC (ewald_atmfrc) gets computed.
    2022              : 
    2023              :      ! BEGIN DEBUG
    2024              :      !write(*,*) 'ifc_write (1) : Writing atmfrc'
    2025              :      !write(*,*) 'atmfrc         : ', Ifc%atmfrc
    2026              :      !call flush()
    2027              :      ! END DEBUG
    2028              :      call ifc_getiaf(Ifc,ifcana,ifcout1,iout,ifc%zeff,ia,ra,list,dist,invdlt,&
    2029          141 :                      detdlt,rsiaf,sriaf,vect,indngb,posngb)
    2030              : 
    2031              :      ! =========================================================================== !
    2032              : 
    2033          141 :      if (prt_ifc == 1) then
    2034        24220 :        do ii=1,ifcout1
    2035        24220 :          if (wkdist(ii) > maxdist_tdep) exit
    2036              :        end do
    2037          123 :        ii = ii - 1
    2038          123 :        write(unit_tdep,"(1X,I10,15X,'How many neighbours does atom ',I3,' have')") ii, ia
    2039              : 
    2040        24220 :        do ii=1,ifcout1
    2041        24097 :          ib = indngb(ii)
    2042        24097 :          irpt = (list(ii)-1)/Ifc%natom+1
    2043        24097 :          wghia(ii) = Ifc%wghatm(ia,ib,irpt)
    2044              :          ! limit printing to maximum distance for tdep
    2045        24097 :          if (wkdist(ii) > maxdist_tdep) cycle
    2046              : 
    2047              :          !TDEP
    2048        24097 :          call int2char4(ii, str1)
    2049        24097 :          call int2char4(ia, str2)
    2050        24097 :          write(unit_tdep,"(1X,I10,15X,a,a,a,a)") ib, &
    2051        24097 : &            'In the unit cell, what is the index of neighbour ', &
    2052        48194 : &            trim(str1), " of atom ", trim(str2)
    2053              :          ! The lattice vector needs to be in reduced coordinates?
    2054              :          ! TODO: check whether this is correct for TDEP: might need just lattice
    2055              :          ! vector part and not full vector, and could be in integers instead of
    2056              :          ! cartesian vector...
    2057       313261 :          write (unit_tdep,'(3es28.16)') matmul(Ifc%rpt(1:3,irpt),Ifc%gprim)
    2058              : 
    2059              :          !AI2PS
    2060        24097 :          write(unit_ifc,'(i6,i6)') ia,ii
    2061        24097 :          write(unit_ifc,'(3es28.16)') posngb(1:3,ii)
    2062        96511 :          do nu=1,3
    2063              :            !TDEp
    2064              :            ! And the actual short ranged forceconstant: TODO: check if
    2065              :            ! a transpose is needed or a swap between the nu and the mu
    2066              :            !write(unit_tdep,'(3f28.16)') (sriaf(nu,mu,ii)*Ha_eV/amu_emass, mu=1, 3)
    2067       289164 :            write(unit_tdep,'(3f28.16)') (Ifc%short_atmfrc(mu,ia,nu,ib,irpt)*Ha_eV/Bohr_Ang**2, mu=1, 3)
    2068              : 
    2069              :            !AI2PS
    2070        96388 :            write(unit_ifc,'(3f28.16)')(rsiaf(nu,mu,ii),mu=1,3)
    2071              :          end do
    2072              :        end do
    2073              : 
    2074          123 :        if (ncid /= nctk_noid) then
    2075          246 :          NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_indices"), ia, start=[iatifc]))
    2076          615 :          NCF_CHECK(nf90_put_var(ncid, vid("ifc_neighbours_indices"), indngb, start=[1,iatifc], count=[ifcout1,1]))
    2077          615 :          NCF_CHECK(nf90_put_var(ncid, vid("ifc_distances"), wkdist(:ifcout1), start=[1,iatifc],count=[ifcout1,1]))
    2078         1107 :          ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord"), rsiaf, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
    2079          123 :          NCF_CHECK(ncerr)
    2080          861 :          NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_cart_coord"), posngb, start=[1,1,iatifc], count=[3,ifcout1,1]))
    2081          615 :          NCF_CHECK(nf90_put_var(ncid, vid("ifc_weights"), wghia, start=[1,iatifc], count=[ifcout1,1]))
    2082              : 
    2083          123 :          if (Ifc%dipdip==1) then
    2084              :            ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord_short_range"), sriaf, &
    2085          216 :              start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
    2086           24 :            NCF_CHECK(ncerr)
    2087              :          end if
    2088          123 :          if (ifcana==1) then
    2089         1107 :            ncerr = nf90_put_var(ncid, vid("ifc_local_vectors"), vect, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
    2090          123 :            NCF_CHECK(ncerr)
    2091              :          end if
    2092              :        end if
    2093              :      end if
    2094              :    end if ! End the condition on atifcflg
    2095              :  end do ! End Big loop on atoms in the unit cell, and corresponding test
    2096              : 
    2097              : 
    2098              : ! NB for future use: in TDEP the following can also be provided.
    2099              : !        ! Print some auxiliary information, if it is there. Such as norm of
    2100              : !        ! forceconstant per shell, which shells there are and so on.
    2101              : !        if ( fc%npairshells .gt. 0 .and. allocated(fc%pairshell) ) then
    2102              : !            write(u,"(1X,I10,15X,'Number of irreducible coordination shells')") fc%npairshells
    2103              : !            do i=1,fc%npairshells
    2104              : !                write(u,"(1X,I10,1X,F16.10,1X,F16.10,15X,'number atoms in shell, radius, norm of forceconstant',I0)") fc%pairshell(i)%n,fc%pairshell(i)%rad,fc%pairshell(i)%norm,i
    2105              : !            enddo
    2106              : !            do i=1,fc%npairshells
    2107              : !                do j=1,fc%pairshell(i)%n
    2108              : !                    write(u,"(1X,3(1X,F18.12),2(1X,I0))") lo_chop(matmul(p%inv_latticevectors,fc%pairshell(i)%vec(:,j)),lo_sqtol),fc%pairshell(i)%atind(j),fc%pairshell(i)%pairind(j)
    2109              : !                enddo
    2110              : !            enddo
    2111              : !        endif
    2112              : 
    2113           65 :  if (prt_ifc == 1) then
    2114           53 :    close(unit_ifc)
    2115           53 :    close(unit_tdep)
    2116              : 
    2117           53 :    filename = trim(prefix)//'_lotosplitting.dat'
    2118           53 :    if (open_file(trim(filename), msg, newunit=unit_tdep, status="replace") /= 0) then
    2119            0 :      ABI_ERROR(msg)
    2120              :    end if
    2121           53 :    write(unit_tdep,'(3es28.16)') dielt(:,1)
    2122           53 :    write(unit_tdep,'(3es28.16)') dielt(:,2)
    2123           53 :    write(unit_tdep,'(3es28.16)') dielt(:,3)
    2124          183 :    do ia = 1, Ifc%natom
    2125          573 :      do ii = 1, 3
    2126          520 :        write(unit_tdep,'(3es28.16)') ifc%zeff(:,ii,ia)
    2127              :      end do
    2128              :    end do
    2129           53 :    close(unit_tdep)
    2130              :  end if
    2131              : 
    2132           65 :  ABI_FREE(rsiaf)
    2133           65 :  ABI_FREE(sriaf)
    2134           65 :  ABI_FREE(vect)
    2135           65 :  ABI_FREE(indngb)
    2136           65 :  ABI_FREE(posngb)
    2137           65 :  ABI_FREE(dist)
    2138           65 :  ABI_FREE(list)
    2139           65 :  ABI_FREE(wkdist)
    2140           65 :  ABI_FREE(wghia)
    2141              : 
    2142              : contains
    2143          885 :  integer function vid(vname)
    2144              :    character(len=*),intent(in) :: vname
    2145          885 :    vid = nctk_idname(ncid, vname)
    2146              :  end function vid
    2147              : 
    2148              : end subroutine ifc_write
    2149              : !!***
    2150              : 
    2151              : !----------------------------------------------------------------------
    2152              : 
    2153              : !!****f* m_ifc/ifc_getiaf
    2154              : !!
    2155              : !! NAME
    2156              : !! ifc_getiaf
    2157              : !!
    2158              : !! FUNCTION
    2159              : !! Extracts the IFCs needed for the output for one atom in the
    2160              : !! unit cell. Accumulates the results for writing in the NetCDF file.
    2161              : !! Prints to the output file
    2162              : !!
    2163              : !! INPUTS
    2164              : !! ifcana= 0 => no analysis of ifc ; 1 => full analysis
    2165              : !! ifcout= Number of interatomic force constants written in the output file
    2166              : !! iout=unit number for nice output
    2167              : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
    2168              : !! ia=index of the atom in the unit cell for which the IFCs are being analyzed
    2169              : !! ra(3)=position of atom ia in cartesian coordinates
    2170              : !! list(ifcout)=index of permutation for distances from atom ia in ascending order
    2171              : !! dist(natom,natom,nrpt)=distance from atom ia to atom ib in unit cell irpt.
    2172              : !! invdlt(3,3)=inverse (transpose) of the dielectric tensor
    2173              : !! detdlt=determinant of the dielectric tensor
    2174              : !!
    2175              : !! OUTPUT
    2176              : !! rsiaf(3,3,ifcout)=list of real space IFCs
    2177              : !! sriaf(3,3,ifcout)=list of the short range part of the real space IFCs
    2178              : !! vect(3,3,ifcout)=base vectors for local coordinates (longitudinal/transverse), if ifc_getiaf is able to find
    2179              : !!   a third atom not aligned with the two atoms characterizing the IFC. If no, the second and third vectors are set to zero.
    2180              : !! indngb(ifcout)=indices in the unit cell of the neighbouring atoms
    2181              : !! posngb(3,ifcout)=position of the neighbouring atoms in cartesian coordinates
    2182              : !! output file
    2183              : !!
    2184              : !! SIDE EFFECTS
    2185              : !! The long-range part of the IFC (ewald_atmfrc) gets computed.
    2186              : !!
    2187              : !! NOTES
    2188              : !! This routine should be executed by one processor only
    2189              : !!
    2190              : !! SOURCE
    2191              : 
    2192          141 : subroutine ifc_getiaf(Ifc,ifcana,ifcout,iout,zeff,ia,ra,list,&
    2193          141 :                       dist,invdlt,detdlt,rsiaf,sriaf,vect,indngb,posngb)
    2194              : 
    2195              : !Arguments -------------------------------
    2196              : !scalars
    2197              :  class(ifc_type),intent(inout) :: Ifc
    2198              :  integer,intent(in) :: ia,ifcana,ifcout,iout
    2199              :  real(dp), intent(in) :: detdlt
    2200              : !arrays
    2201              :  real(dp),intent(in) :: invdlt(3,3),ra(3)
    2202              :  real(dp),intent(in) :: dist(Ifc%natom,Ifc%natom,Ifc%nrpt)
    2203              :  real(dp),intent(in) :: zeff(3,3,Ifc%natom)
    2204              :  integer,intent(in) :: list(Ifc%natom*Ifc%nrpt)
    2205              :  integer,intent(out) :: indngb(ifcout)
    2206              :  real(dp),intent(out) :: rsiaf(3,3,ifcout),sriaf(3,3,ifcout),vect(3,3,ifcout),posngb(3,ifcout)
    2207              : 
    2208              : !Local variables -------------------------
    2209              : !scalars
    2210              :  integer :: flag,ib,ii,index,jj,kk,mu,nu,irpt
    2211              :  real(dp) :: ew1,rsq,scprod,trace1,trace2,trace3, yy,dist1
    2212              :  character(len=500) :: msg
    2213              : !arrays
    2214              :  real(dp) :: ewiaf0(3,3),ewiaf1(3,3),ewloc(3,3),ifcloc(3,3)
    2215              :  real(dp) :: rcart(3),rdiff(3),rsloc(3,3), srloc(3,3),vect1(3),vect2(3),vect3(3),work(3),xx(3)
    2216              : ! *********************************************************************
    2217              : 
    2218          141 :  if(ifcana==1)then
    2219              :    ! Generate the local coordinate system for the atom ia
    2220          138 :    index=list(2)
    2221          138 :    write(std_out,*)index
    2222          138 :    call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
    2223          138 :    vect2(1)=rcart(1)-ra(1)
    2224          138 :    vect2(2)=rcart(2)-ra(2)
    2225          138 :    vect2(3)=rcart(3)-ra(3)
    2226          138 :    flag=0
    2227          160 :    do ii=3,Ifc%natom*Ifc%nrpt
    2228          160 :      index=list(ii)
    2229          160 :      call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
    2230          160 :      vect1(1)=(rcart(1)-ra(1))-vect2(1)
    2231          160 :      vect1(2)=(rcart(2)-ra(2))-vect2(2)
    2232          160 :      vect1(3)=(rcart(3)-ra(3))-vect2(3)
    2233          160 :      scprod=0.0_dp
    2234          640 :      do jj=1,3
    2235          640 :        scprod=scprod+vect1(jj)**2
    2236              :      end do
    2237          640 :      do jj=1,3
    2238          640 :        vect1(jj)=vect1(jj)/scprod**0.5
    2239              :      end do
    2240              :      scprod=0.0_dp
    2241          640 :      do jj=1,3
    2242          640 :        scprod=scprod+vect2(jj)*vect1(jj)
    2243              :      end do
    2244          640 :      do jj=1,3
    2245          640 :        work(jj)=vect2(jj)-vect1(jj)*scprod
    2246              :      end do
    2247              :      scprod=0.0_dp
    2248          640 :      do jj=1,3
    2249          640 :        scprod=scprod+work(jj)**2
    2250              :      end do
    2251          160 :      if(scprod>1.0d-10)then
    2252              :        flag=1
    2253              :      end if
    2254            0 :      if(flag==1)exit
    2255              :    end do
    2256          138 :    if(flag==0)then
    2257              :      write(msg, '(3a)' )&
    2258            0 :       'Unable to find a third atom not aligned with the two selected ones.',ch10,&
    2259            0 :       'The local analysis (longitudinal/transverse) will not be done. The two transverse vectors are set to zero.'
    2260            0 :      ABI_WARNING(msg)
    2261            0 :      vect2(:)=zero ; vect3(:)=zero
    2262              :    else
    2263          138 :      vect2(1)=work(1)/scprod**0.5
    2264          138 :      vect2(2)=work(2)/scprod**0.5
    2265          138 :      vect2(3)=work(3)/scprod**0.5
    2266          138 :      vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
    2267          138 :      vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
    2268          138 :      vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
    2269          138 :      if (iout > 0) then
    2270          138 :        write(iout, '(a)' )' Third atom defining local coordinates : '
    2271          138 :        write(iout, '(a,i4,a,i4)' )'     ib = ',ib,'   irpt = ',irpt
    2272              :      end if
    2273              :    endif
    2274              :  end if
    2275              : 
    2276              :  ! Analysis and output of force constants, ordered with respect to the distance from atom ia
    2277        24596 :  do ii=1,ifcout
    2278        24455 :    index=list(ii)
    2279        24455 :    call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,posngb(:,ii),Ifc%rprim,Ifc%rpt)
    2280        24455 :    indngb(ii)=ib
    2281        24455 :    dist1=dist(ia,ib,irpt)
    2282        24455 :    if (iout > 0) then
    2283        24455 :      write(iout, '(a)' )
    2284        24455 :      write(iout, '(i4,a,i6,a,i8)' )ii,' interaction with atom',ib,' cell',irpt
    2285        97820 :      write(iout, '(a,3es16.6)' )' with coordinates ',posngb(1:3,ii)*(one+tol8)
    2286        24455 :      write(iout, '(a,es16.6)' )' and distance ',dist1
    2287              :    end if
    2288              : 
    2289        24455 :    if(ifcana==1.and.ii/=1)then
    2290        24257 :      vect1(1)=(posngb(1,ii)-ra(1))/dist1
    2291        24257 :      vect1(2)=(posngb(2,ii)-ra(2))/dist1
    2292        24257 :      vect1(3)=(posngb(3,ii)-ra(3))/dist1
    2293              :    end if
    2294              : 
    2295        24596 :    if(Ifc%dipdip==0.or.Ifc%dipquad==1.or.Ifc%quadquad==1)then
    2296              :      ! Get the "total" force constants (=real space FC)
    2297              :      ! without taking into account the dipole-dipole interaction
    2298        79140 :      do mu=1,3
    2299       257205 :        do nu=1,3
    2300       237420 :          rsiaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt) * Ifc%wghatm(ia,ib,irpt)
    2301              :        end do
    2302              :      end do
    2303              :      ! Output of the ifcs in cartesian coordinates
    2304        19785 :      if (iout > 0) then
    2305        79140 :        do nu=1,3
    2306       237420 :          write(iout, '(1x,3f9.5)' )(rsiaf(mu,nu,ii)+tol10,mu=1,3)
    2307              :          ! transfer short range and long range
    2308       257205 :          do mu=1,3
    2309       237420 :            Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = rsiaf(mu,nu,ii) + tol10
    2310              :          end do
    2311              : 
    2312              :        end do
    2313              :      end if
    2314              : 
    2315        19785 :      if(ifcana==1)then
    2316              :        ! Further analysis
    2317        19785 :        trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
    2318        19785 :        if (iout > 0) then
    2319        19785 :          write(iout, '(a,f9.5)' ) '  Trace         ',trace1+tol10
    2320              :        end if
    2321        19785 :        if(flag==1)then
    2322        19785 :          if(ii/=1)then
    2323        19680 :            call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
    2324              :          end if
    2325        19785 :          if (iout > 0) then
    2326        19785 :            write(iout, '(a)' )' Transformation to local coordinates '
    2327        19785 :            write(iout, '(a,3f16.6)' ) ' First  local vector :',vect1
    2328        19785 :            write(iout, '(a,3f16.6)' ) ' Second local vector :',vect2
    2329        19785 :            write(iout, '(a,3f16.6)' ) ' Third  local vector :',vect3
    2330              :          end if
    2331        19785 :          call ifclo9(rsiaf(:,:,ii),ifcloc,vect1,vect2,vect3)
    2332        19785 :          if (iout > 0) then
    2333        79140 :            do nu=1,3
    2334       257205 :              write(iout, '(1x,3f9.5)' )(ifcloc(mu,nu)+tol10,mu=1,3)
    2335              :            end do
    2336              :          end if
    2337              :        endif ! flag==1
    2338              : 
    2339        79140 :        vect(:,1,ii) = vect1
    2340        79140 :        vect(:,2,ii) = vect2
    2341        79140 :        vect(:,3,ii) = vect3
    2342              : 
    2343              :      end if ! Further analysis finished
    2344              : 
    2345         4670 :    else if(Ifc%dipdip==1)then
    2346              : 
    2347              :      !write(iout,'(a)')
    2348              :      !write(iout,'(a)')' Enter dipdip section, for debugging'
    2349              :      !write(iout,'(a)')
    2350              : 
    2351              :      ! Get the Coulomb part
    2352        18680 :      do jj=1,3
    2353        18680 :        rdiff(jj)=ra(jj)-posngb(jj,ii)
    2354              :      end do
    2355         4670 :      rsq=0.0_dp
    2356         4670 :      xx(1:3)=0.0_dp
    2357        18680 :      do jj=1,3
    2358        60710 :        do kk=1,3
    2359        42030 :          ewiaf0(jj,kk)=0.0_dp
    2360        42030 :          rsq=rsq+rdiff(jj)*invdlt(kk,jj)*rdiff(kk)
    2361        56040 :          xx(kk)=xx(kk)+invdlt(kk,jj)*rdiff(jj)
    2362              :        end do
    2363              :      end do
    2364         4670 :      yy=sqrt(rsq)
    2365              :      !  Avoid zero denominators in term:
    2366         4670 :      if (sqrt(rsq)>=tol12) then
    2367        18536 :        do mu=1,3
    2368        60242 :          do nu=1,3
    2369        55608 :            ewiaf0(mu,nu)=(-3*xx(nu)*xx(mu)+invdlt(nu,mu)*yy**2)/yy**5/sqrt(detdlt)
    2370              :          end do
    2371              :        end do
    2372              :      else
    2373           36 :        if (ia/=ib)then
    2374              :          write(msg, '(a,a,a,a,a,i5,a,i5,a)' )&
    2375            0 :            'The distance between two atoms vanishes.',ch10,&
    2376            0 :            'This is not allowed.',ch10,&
    2377            0 :            'Action: check the input for the atoms number',ia,' and',ib,'.'
    2378            0 :          ABI_ERROR(msg)
    2379              :        end if
    2380              :      end if
    2381              : 
    2382              :      ! Take into account the effective charge tensor
    2383        18680 :      do mu=1,3
    2384        60710 :        do nu=1,3
    2385        42030 :          ew1=zero
    2386        42030 :          if(ii==1)then
    2387          324 :            ew1=-Ifc%dyewq0(mu,nu,ia)
    2388              :          end if
    2389       168120 :          do jj=1,3
    2390       546390 :            do kk=1,3
    2391       504360 :              ew1=ew1+zeff(jj,mu,ia)*(zeff(kk,nu,ib)* ewiaf0(jj,kk))
    2392              :            end do
    2393              :          end do
    2394        56040 :          ewiaf1(mu,nu)=ew1
    2395              :        end do
    2396              :      end do
    2397              :      ! Get the short-range force constants and the
    2398              :      ! "total" force constants (=real space FC)
    2399        18680 :      do mu=1,3
    2400        60710 :        do nu=1,3
    2401        42030 :          sriaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt)* Ifc%wghatm(ia,ib,irpt)
    2402        56040 :          rsiaf(mu,nu,ii)=ewiaf1(mu,nu)+sriaf(mu,nu,ii)
    2403              :        end do
    2404              :      end do
    2405              : 
    2406              :      ! Output of the results
    2407         4670 :      if (iout > 0) then
    2408        18680 :        do nu=1,3
    2409              :          write(iout, '(1x,3(3f9.5,1x))' )&
    2410        56040 :            (rsiaf(mu,nu,ii) +tol10,mu=1,3),&
    2411        56040 :            (ewiaf1(mu,nu)+tol10,mu=1,3),&
    2412       168120 :            (sriaf(mu,nu,ii) +tol10,mu=1,3)
    2413              : 
    2414              :          ! transfer short range and long range
    2415        60710 :          do mu=1,3
    2416        42030 :            Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = sriaf(mu,nu,ii) + tol10
    2417        56040 :            Ifc%ewald_atmfrc(mu,ia,nu,ib,irpt) = ewiaf1(mu,nu) + tol10
    2418              :          end do
    2419              :        end do
    2420              :      end if
    2421              : 
    2422         4670 :      if(ifcana==1)then
    2423              :        ! Further analysis
    2424         4610 :        if (iout > 0) then
    2425         4610 :          write(iout, '(a)' )' Traces (and ratios) :'
    2426              :        end if
    2427         4610 :        trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
    2428         4610 :        trace2=ewiaf1(1,1)+ewiaf1(2,2)+ewiaf1(3,3)
    2429         4610 :        trace3=sriaf(1,1,ii)+sriaf(2,2,ii)+sriaf(3,3,ii)
    2430         4610 :        if (iout > 0) then
    2431         4610 :          write(iout,'(3(f9.5,17x))')trace1+tol10,trace2+tol10,trace3+tol10
    2432         4610 :          write(iout,'(3(f9.5,17x))')1.0,(trace2+tol10)/(trace1+tol10),(trace3+tol10)/(trace1+tol10) !
    2433              :        end if
    2434              : 
    2435         4610 :        if(flag==1)then
    2436         4610 :          if(ii/=1)then
    2437         4577 :            call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
    2438              :          end if
    2439         4610 :          if (iout > 0) then
    2440         4610 :            write(iout, '(a)' )' Transformation to local coordinates '
    2441         4610 :            write(iout, '(a,3f16.6)' )' First  local vector :',vect1
    2442         4610 :            write(iout, '(a,3f16.6)' )' Second local vector :',vect2
    2443         4610 :            write(iout, '(a,3f16.6)' )' Third  local vector :',vect3
    2444              :          end if
    2445         4610 :          call ifclo9(rsiaf(:,:,ii),rsloc,vect1,vect2,vect3)
    2446         4610 :          call ifclo9(ewiaf1,ewloc,vect1,vect2,vect3)
    2447         4610 :          call ifclo9(sriaf(:,:,ii),srloc,vect1,vect2,vect3)
    2448         4610 :          if (iout > 0) then
    2449        18440 :            do nu=1,3
    2450              :              write(iout, '(1x,3(3f9.5,1x))' )&
    2451        55320 : &             (rsloc(mu,nu)+tol10,mu=1,3),&
    2452        55320 : &             (ewloc(mu,nu)+tol10,mu=1,3),&
    2453       170570 : &             (srloc(mu,nu)+tol10,mu=1,3)
    2454              :            end do
    2455         4610 :            if(ii/=1)then
    2456         4577 :              write(iout, '(a)' )' Ratio with respect to the longitudinal ifc'
    2457              :            else
    2458           33 :              write(iout, '(a)' )' Ratio with respect to the (1,1) element'
    2459              :            end if
    2460        18440 :            do nu=1,3
    2461              :              write(iout, '(1x,3(3f9.5,1x))' )&
    2462        55320 : &             (rsloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
    2463        55320 : &             (ewloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
    2464       170570 : &             (srloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3)
    2465              :            end do
    2466              :          end if
    2467              :        endif ! flag==1
    2468              : 
    2469        18440 :        vect(:,1,ii) = vect1
    2470        18440 :        vect(:,2,ii) = vect2
    2471        18440 :        vect(:,3,ii) = vect3
    2472              : 
    2473              :      end if ! Further analysis finished
    2474              :    end if ! End the condition on dipdip
    2475              :  end do ! End loop over all atoms in BigBox:
    2476              : 
    2477          141 : end subroutine ifc_getiaf
    2478              : !!***
    2479              : 
    2480              : !----------------------------------------------------------------------
    2481              : 
    2482              : !!****f* m_ifc/omega_decomp
    2483              : !!
    2484              : !! NAME
    2485              : !!  omega_decomp
    2486              : !!
    2487              : !! FUNCTION
    2488              : !! Compute and return the eigenvalues (frequencies) of the short-range and
    2489              : !! long-range part of the dynamical matrix  See Europhys. Lett. 33 p.713 (1996) for details.
    2490              : !! (included by U. Aschauer and EB)
    2491              : !!
    2492              : !! INPUTS
    2493              : !!
    2494              : !! OUTPUT
    2495              : !!
    2496              : !! SOURCE
    2497              : 
    2498            0 : subroutine omega_decomp(amu,natom,ntypat,typat,dynmatfl,dynmatsr,dynmatlr,iqpt,nqpt,eigenvec)
    2499              : 
    2500              : !Arguments -------------------------------
    2501              : !scalars
    2502              :  integer,intent(in) :: natom,ntypat
    2503              :  integer,intent(in) :: iqpt,nqpt
    2504              : !arrays
    2505              :  integer,intent(in) :: typat(natom)
    2506              :  real(dp),intent(in) :: amu(ntypat)
    2507              :  real(dp),intent(inout) :: dynmatfl(2,3,natom,3,natom,nqpt)
    2508              :  real(dp),intent(inout) :: dynmatsr(2,3,natom,3,natom,nqpt)
    2509              :  real(dp),intent(inout) :: dynmatlr(2,3,natom,3,natom,nqpt)
    2510              :  real(dp),intent(in)    :: eigenvec(2*3*natom*3*natom)
    2511              : 
    2512              : !Local variables -------------------------
    2513              : !scalars
    2514              :  integer :: i1,i2,idir1,idir2,imode,ipert1,ipert2,index1,index2
    2515              :  real(dp),parameter :: break_symm=1.0d-12
    2516              :  real(dp) :: fac
    2517              : !arrays
    2518              :  real(dp) :: omegafl, omegasr, omegalr, sumfl,sumlr,sumsr,asr
    2519              :  real(dp) :: nearidentity(3,3)
    2520              : ! *********************************************************************
    2521              : 
    2522              : !write(ab_out,*)''
    2523              : !write(std_out,*) 'SR/LR decomposition: enter for wavevector number :',iqpt
    2524              : 
    2525              : !apply asr (note the lr part is already asred by construction in mkifc9)
    2526            0 :  do ipert1=1,natom
    2527            0 :    do idir1=1,3
    2528            0 :      do idir2=1,3
    2529              :        asr=0.0d0
    2530            0 :        do ipert2=1,natom
    2531            0 :          asr=asr+dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)
    2532              :        end do
    2533            0 :        dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
    2534            0 :        dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
    2535              :      end do
    2536              :    end do
    2537              :  end do
    2538              : 
    2539              : !This slight breaking of the symmetry allows the results to be more portable between machines
    2540            0 :  nearidentity(:,:)=1.0
    2541            0 :  nearidentity(1,1)=1.0+break_symm
    2542            0 :  nearidentity(3,3)=1.0-break_symm
    2543              : 
    2544              : !Include Mass
    2545            0 :  do ipert1=1,natom
    2546            0 :    do ipert2=1,natom
    2547              : 
    2548            0 :      fac=1.0d0/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
    2549              : 
    2550            0 :      do idir1=1,3
    2551            0 :        do idir2=1,3
    2552              : 
    2553              :          dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2554              : &         dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)*&
    2555            0 : &         fac*nearidentity(idir1,idir2)
    2556              : 
    2557              :          dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2558              : &         dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
    2559            0 : &         fac*nearidentity(idir1,idir2)
    2560              : 
    2561              :          dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2562              : &         dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
    2563            0 : &         fac*nearidentity(idir1,idir2)
    2564              : 
    2565              :          ! This is to break slightly the translation invariance, and make
    2566              :          ! the automatic tests more portable
    2567            0 :          if(ipert1==ipert2 .and. idir1==idir2)then
    2568              :            dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2569              : &           dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)+&
    2570            0 : &           break_symm*natom/amu_emass/idir1*0.01d0
    2571              : 
    2572              :            dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2573              : &           dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
    2574            0 : &           break_symm*natom/amu_emass/idir1*0.01d0
    2575              : 
    2576              :            dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
    2577              : &           dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
    2578            0 : &           break_symm*natom/amu_emass/idir1*0.01d0
    2579              :          end if
    2580              : 
    2581              :        end do
    2582              :      end do
    2583              :    end do
    2584              :  end do
    2585              : 
    2586              : !Calculation of <eigvec|Dyn_tot,Dyn_SR,Dyn_LR|eigenvec>=omega**2
    2587              : 
    2588              : !write(ab_out,*)''
    2589              : !write(ab_out,*)'==============================================================================='
    2590            0 :  write(ab_out,*)''
    2591            0 :  write(ab_out,*) 'Long-Range/Short-Range decomposed phonon freq. (cm-1)**2'
    2592            0 :  write(ab_out,*) 'at wavevector number:',iqpt
    2593            0 :  write(ab_out,*)''
    2594            0 :  write(ab_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
    2595            0 :  write(std_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
    2596              : !write(ab_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
    2597              : !write(std_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
    2598              : 
    2599            0 :  do imode=1,3*natom
    2600            0 :    sumfl=zero; sumlr=zero; sumsr=zero
    2601              : 
    2602            0 :    do ipert1=1,natom
    2603            0 :      do ipert2=1,natom
    2604            0 :        do i1=1,3
    2605            0 :          do i2=1,3
    2606              : 
    2607            0 :            index1=i1+(ipert1-1)*3+3*natom*(imode-1)
    2608            0 :            index2=i2+(ipert2-1)*3+3*natom*(imode-1)
    2609              :            ! MG FIXME: I don't think these expressions are correct when q != 0
    2610              :            ! We should also include the imaginary part
    2611              : 
    2612            0 :            sumfl = sumfl + eigenvec(2*index1-1) * dynmatfl(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
    2613            0 :            sumlr = sumlr + eigenvec(2*index1-1) * dynmatlr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
    2614            0 :            sumsr = sumsr + eigenvec(2*index1-1) * dynmatsr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
    2615              :          end do
    2616              :        end do
    2617              :      end do
    2618              :    end do
    2619              : 
    2620            0 :    sumfl = sumfl * Ha_cmm1 * Ha_cmm1
    2621            0 :    sumsr = sumsr * Ha_cmm1 * Ha_cmm1
    2622            0 :    sumlr = sumlr * Ha_cmm1 * Ha_cmm1
    2623              : 
    2624              : !  Compute omega=sqrt(omega**2)
    2625              :    if(sumfl>=1.0d-16)then
    2626              :      omegafl=sqrt(sumfl)
    2627              :    else if(sumfl>=-1.0d-16)then
    2628              :      omegafl=zero
    2629              :    else
    2630              :      omegafl=-sqrt(-sumfl)
    2631              :    end if
    2632              : 
    2633              :    if(sumsr>=1.0d-16)then
    2634              :      omegasr=sqrt(sumsr)
    2635              :    else if(sumsr>=-1.0d-16)then
    2636              :      omegasr=zero
    2637              :    else
    2638              :      omegasr=-sqrt(-sumsr)
    2639              :    end if
    2640              : 
    2641              :    if(sumlr>=1.0d-16)then
    2642              :      omegalr=sqrt(sumlr)
    2643              :    else if(sumlr>=-1.0d-16)then
    2644              :      omegalr=zero
    2645              :    else
    2646              :      omegalr=-sqrt(-sumlr)
    2647              :    end if
    2648              : 
    2649              : !  Output
    2650            0 :    write(ab_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr  !vz_d
    2651            0 :    write(std_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr  !vz_d
    2652              : !  write(ab_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
    2653              : !  write(std_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
    2654              :  end do
    2655              : 
    2656            0 : end subroutine omega_decomp
    2657              : !!***
    2658              : 
    2659              : !----------------------------------------------------------------------
    2660              : 
    2661              : !!****f* m_ifc/ifc_outphbtrap
    2662              : !! NAME
    2663              : !! ifc_outphbtrap
    2664              : !!
    2665              : !! FUNCTION
    2666              : !!  Print out phonon frequencies on regular grid for BoltzTrap
    2667              : !!  Flag in input file is outboltztrap=1
    2668              : !!
    2669              : !! INPUTS
    2670              : !!  Crystal<crystal_t>=Info on the crystal structure
    2671              : !!  basename = file name for output to disk
    2672              : !!  ngqpt(3)=Divisions of the q-mesh
    2673              : !!  nqshft=Number of shifts
    2674              : !!  qshft(3,nqshft)=Shifts of the q-mesh.
    2675              : !!
    2676              : !! OUTPUT
    2677              : !!  only write to file. This routine should be called by a single processor.
    2678              : !!
    2679              : !! SOURCE
    2680              : 
    2681            2 : subroutine ifc_outphbtrap(ifc, cryst, ngqpt, nqshft, qshft, basename)
    2682              : 
    2683              : !Arguments -------------------------------
    2684              : !scalars
    2685              :  class(ifc_type),intent(in) :: ifc
    2686              :  integer,intent(in) :: nqshft
    2687              :  character(len=*),intent(in) :: basename
    2688              :  type(crystal_t),intent(in) :: cryst
    2689              : !arrays
    2690              :  integer,intent(in) :: ngqpt(3)
    2691              :  real(dp),intent(in) :: qshft(3,nqshft)
    2692              : 
    2693              : !Local variables -------------------------
    2694              : !scalars
    2695              :  integer,parameter :: qptopt1=1
    2696              :  integer :: natom,imode,iq_ibz,nqbz,nqibz, nreals,unit_btrap,iatom,idir
    2697              :  character(len=500) :: msg,format_nreals,format_line_btrap
    2698              :  character(len=fnlen) :: outfile
    2699              : !arrays
    2700              :  integer :: qptrlatt(3,3)
    2701            4 :  real(dp) :: d2cart(2,3,cryst%natom,3,cryst%natom),displ(2*3*cryst%natom*3*cryst%natom)
    2702            4 :  real(dp) :: phfrq(3*cryst%natom),qphon(3)
    2703            2 :  real(dp),allocatable :: qbz(:,:),qibz(:,:),wtq(:)
    2704              : ! *********************************************************************
    2705              : 
    2706              :  DBG_ENTER("COLL")
    2707            2 :  natom = cryst%natom
    2708              : 
    2709              :  ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
    2710            2 :  qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
    2711            2 :  call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
    2712              : 
    2713            2 :  outfile = trim(basename) // '_BTRAP'
    2714            2 :  write(msg, '(3a)')ch10,' Will write phonon FREQS in BoltzTrap format to file ',trim(outfile)
    2715            6 :  call wrtout([std_out, ab_out], msg)
    2716              : 
    2717            2 :  if (open_file(outfile,msg,newunit=unit_btrap,status="replace") /= 0) then
    2718            0 :    ABI_ERROR(msg)
    2719              :  end if
    2720              : 
    2721            2 :  write(unit_btrap,'(a)') '#'
    2722            2 :  write(unit_btrap,'(a)') '# ABINIT package : Boltztrap phonon file. With old BT versions remove this header before feeding to BT'
    2723            2 :  write(unit_btrap,'(a)') '#    for compatibility with PHON output the freq are in Ry (before the square)'
    2724            2 :  write(unit_btrap,'(a)') '#'
    2725            2 :  write(unit_btrap,'(a)') '#    nq, nband  '
    2726            2 :  write(unit_btrap,'(a)') '#  qx, qy, qz   '
    2727            2 :  write(unit_btrap,'(a)') '#  qpt weight   '
    2728            2 :  write(unit_btrap,'(a)') '#  freq_1^2, dynmat column for mode 1 '
    2729            2 :  write(unit_btrap,'(a)') '#  etc for mode 2,3,4... qpt 2,3,4... '
    2730            2 :  write(unit_btrap,'(2I6)') nqibz, 3*natom
    2731              : 
    2732              : ! Loop over irreducible q-points
    2733          197 :  do iq_ibz=1,nqibz
    2734          780 :    qphon(:)=qibz(:,iq_ibz)
    2735              : 
    2736          195 :    call ifc%fourq(cryst, qphon, phfrq, displ, out_d2cart=d2cart)
    2737              : 
    2738          195 :    write (unit_btrap,'(3E20.10)') qphon
    2739          195 :    write (unit_btrap,'(E20.10)') wtq(iq_ibz)
    2740          195 :    nreals=1+2*3*natom
    2741          195 :    call appdig(nreals,'(',format_nreals)
    2742          195 :    format_line_btrap=trim(format_nreals)//'E20.10)'
    2743          442 :    do iatom = 1, natom
    2744         1175 :      do idir = 1, 3
    2745          735 :        imode = idir + 3*(iatom-1)
    2746              :        ! factor two for Ry output - this may change in definitive BT and abinit formats
    2747          980 :        write (unit_btrap,trim(format_line_btrap))phfrq(imode)*two,d2cart(1:2,1:3,1:natom,idir,iatom)
    2748              :      end do
    2749              :    end do
    2750              : 
    2751              :  end do !irred q-points
    2752            2 :  close (unit_btrap)
    2753              : 
    2754            2 :  ABI_FREE(qibz)
    2755            2 :  ABI_FREE(qbz)
    2756            2 :  ABI_FREE(wtq)
    2757              : 
    2758              :  DBG_EXIT("COLL")
    2759              : 
    2760            2 : end subroutine ifc_outphbtrap
    2761              : !!***
    2762              : 
    2763              : !----------------------------------------------------------------------
    2764              : 
    2765              : !!****f* m_ifc/ifc_printbxsf
    2766              : !! NAME
    2767              : !! ifc_printbxsf
    2768              : !!
    2769              : !! FUNCTION
    2770              : !!  Output phonon isosurface in Xcrysden format.
    2771              : !!
    2772              : !! INPUTS
    2773              : !!  crystal<crystal_t>=Info on the crystal structure
    2774              : !!  ngqpt(3)=Divisions of the q-mesh
    2775              : !!  nqshft=Number of shifts
    2776              : !!  qshft(3,nqshft)=Shifts of the q-mesh.
    2777              : !!  path=File name for output to disk
    2778              : !!  comm=MPI communicator.
    2779              : !!
    2780              : !! OUTPUT
    2781              : !!  Only write to file
    2782              : !!
    2783              : !! SOURCE
    2784              : 
    2785            1 : subroutine ifc_printbxsf(ifc, cryst, ngqpt, nqshft, qshft, path, comm)
    2786              : 
    2787              : !Arguments -------------------------------
    2788              : !scalars
    2789              :  class(ifc_type),intent(in) :: ifc
    2790              :  integer,intent(in) :: nqshft,comm
    2791              :  character(len=*),intent(in) :: path
    2792              :  type(crystal_t),intent(in) :: cryst
    2793              : !arrays
    2794              :  integer,intent(in) :: ngqpt(3)
    2795              :  real(dp),intent(in) :: qshft(3,nqshft)
    2796              : 
    2797              : !Local variables -------------------------
    2798              : !scalars
    2799              :  integer,parameter :: nsppol1=1,master=0,qptopt1=1
    2800              :  integer :: my_rank,nprocs,iq_ibz,nqibz,nqbz,ierr
    2801              :  character(len=500) :: msg
    2802              : !arrays
    2803            2 :  integer :: qptrlatt(3,3),dummy_symafm(cryst%nsym)
    2804            2 :  real(dp) :: displ_cart(2,3*cryst%natom,3*cryst%natom)
    2805            1 :  real(dp),allocatable :: qibz(:,:),wtq(:),qbz(:,:),freqs_qibz(:,:)
    2806              : ! *********************************************************************
    2807              : 
    2808            1 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
    2809              : 
    2810              :  ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
    2811            1 :  qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
    2812            1 :  call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
    2813            1 :  ABI_FREE(qbz)
    2814            1 :  ABI_FREE(wtq)
    2815              : 
    2816              :  ! Compute phonon frequencies in the irreducible wedge.
    2817          585 :  ABI_CALLOC(freqs_qibz, (3*cryst%natom, nqibz))
    2818              : 
    2819          146 :  do iq_ibz=1,nqibz
    2820          145 :    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi parallelism.
    2821          146 :    call ifc%fourq(cryst, qibz(:,iq_ibz), freqs_qibz(:,iq_ibz), displ_cart)
    2822              :  end do
    2823            1 :  call xmpi_sum(freqs_qibz, comm, ierr)
    2824              : 
    2825              :  ! Output phonon isosurface.
    2826            1 :  if (my_rank == master) then
    2827           49 :    dummy_symafm = 1
    2828              :    call printbxsf(freqs_qibz, zero, zero, cryst%gprimd, qptrlatt, 3*cryst%natom,&
    2829            1 :      nqibz, qibz, cryst%nsym, .False., cryst%symrec, dummy_symafm, .True., nsppol1, qshft, nqshft, path, ierr)
    2830            1 :    if (ierr /=0) then
    2831            0 :      msg = "Cannot produce BXSF file with phonon isosurface, see log file for more info"
    2832            0 :      ABI_WARNING(msg)
    2833            0 :      call wrtout(ab_out, msg)
    2834              :    end if
    2835              :  end if
    2836              : 
    2837            1 :  ABI_FREE(freqs_qibz)
    2838            1 :  ABI_FREE(qibz)
    2839              : 
    2840            1 : end subroutine ifc_printbxsf
    2841              : !!***
    2842              : 
    2843              : !----------------------------------------------------------------------
    2844              : 
    2845              : !!****f* m_ifc/ifc_calcnwrite_nana_terms
    2846              : !! NAME
    2847              : !!  ifc_calcnwrite_nana_terms
    2848              : !!
    2849              : !! FUNCTION
    2850              : !!  Compute frequencies and phonon displacement for q-->0 in the presence of non-analytical behaviour.
    2851              : !!
    2852              : !! INPUTS
    2853              : !!  nph2l=Number of qpoints.
    2854              : !!  qph2l(3,nph2l)=List of phonon wavevector directions along which the non-analytical correction
    2855              : !!    to the Gamma-point phonon frequencies will be calculated
    2856              : !!    The direction is in CARTESIAN COORDINATES
    2857              : !!  qnrml2(nph2l)=Normalization factor.
    2858              : !!
    2859              : !! OUTPUT
    2860              : !!  (Optional)
    2861              : !!  phfrq2l(3*crystal%natom,nph2l)=List of phonon frequencies
    2862              : !!  polarity2l(3,3*crystal%natom,nph2l)=List of mode-polarities
    2863              : !!     (see Eq.(41) of Veithen et al, PRB71, 125107 (2005) [[cite:Veithen2005]])
    2864              : !!
    2865              : !! NOTES:
    2866              : !!  This routine should be called by master node and when ifcflag == 1.
    2867              : !!
    2868              : !! SOURCE
    2869              : 
    2870           32 : subroutine ifc_calcnwrite_nana_terms(ifc, crystal, nph2l, qph2l, &
    2871            6 :                                      qnrml2, ncid, phfrq2l, polarity2l) ! optional arguments
    2872              : 
    2873              : !Arguments ------------------------------------
    2874              :  class(ifc_type),intent(in) :: ifc
    2875              :  integer,intent(in) :: nph2l
    2876              :  integer,optional,intent(in) :: ncid
    2877              :  type(crystal_t),intent(in) :: crystal
    2878              : !arrays
    2879              :  real(dp),intent(in) :: qph2l(3, nph2l)
    2880              :  real(dp),optional,intent(in) :: qnrml2(nph2l)
    2881              :  real(dp),optional,intent(out) :: phfrq2l(3*crystal%natom,nph2l), polarity2l(3,3*crystal%natom,nph2l)
    2882              : 
    2883              : !Local variables-------------------------------
    2884              : !scalars
    2885              :  integer :: iatom,idir,imode,iphl2, ncerr
    2886              :  real(dp) :: eta
    2887              : !arrays
    2888              :  real(dp) :: qphnrm(3),qphon(3,3)
    2889           32 :  real(dp),allocatable :: displ_cart(:,:,:),phfrq(:),d2cart(:,:,:),eigvec(:,:,:),eigval(:)
    2890              : ! ************************************************************************
    2891              : 
    2892           32 :  if (nph2l == 0) return
    2893              : 
    2894              :  ! Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
    2895           96 :  ABI_MALLOC(phfrq, (3*crystal%natom))
    2896          128 :  ABI_MALLOC(displ_cart, (2, 3*crystal%natom, 3*crystal%natom))
    2897          128 :  ABI_MALLOC(d2cart, (2, 3*ifc%mpert, 3*ifc%mpert))
    2898           96 :  ABI_MALLOC(eigvec, (2, 3*crystal%natom, 3*crystal%natom))
    2899           64 :  ABI_MALLOC(eigval, (3*crystal%natom))
    2900              : 
    2901              :  ! Before examining every direction or the dielectric tensor, generates the dynamical matrix at gamma
    2902          128 :  qphon(:,1)=zero; qphnrm(1)=zero
    2903              : 
    2904              :  ! Generation of the dynamical matrix in cartesian coordinates
    2905              :  ! Get d2cart using the interatomic forces and the long-range coulomb interaction through Ewald summation
    2906              :  call gtdyn9(ifc%acell,ifc%atmfrc,ifc%dielt,ifc%dipdip, &
    2907              :    ifc%dyewq0,d2cart,crystal%gmet,ifc%gprim,ifc%mpert,crystal%natom, &
    2908              :    ifc%nrpt,qphnrm(1),qphon,crystal%rmet,ifc%rprim,ifc%rpt, &
    2909           32 :    ifc%trans,crystal%ucvol,ifc%wghatm,crystal%xred,ifc%zeff,ifc%qdrp_cart,ifc%ewald_option,eta,xmpi_comm_self,ifc%sys_dim)
    2910              : 
    2911           32 :  if (present(ncid)) then
    2912           29 :    iphl2 = 0
    2913           29 :    call defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, mode="define")
    2914              :    ! Add epsinf, Born effective charges and some useful metadata.
    2915              :    ncerr = nctk_def_arrays(ncid, [ &
    2916              :      nctkarr_t('emacro_cart', "dp", 'number_of_cartesian_directions, number_of_cartesian_directions'), &
    2917              :      nctkarr_t('becs_cart', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, number_of_atoms")], &
    2918           87 :      defmode=.True.)
    2919           29 :    NCF_CHECK(ncerr)
    2920              :    ! TODO chneut is missing
    2921              :    ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
    2922          116 :        "asr", "dipdip", "symdynmat"])
    2923           29 :    NCF_CHECK(ncerr)
    2924           29 :    NCF_CHECK(nctk_set_datamode(ncid))
    2925           29 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'emacro_cart'), ifc%dielt))
    2926           29 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'becs_cart'), ifc%zeff))
    2927              :    ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
    2928              :      "asr", "dipdip", "symdynmat"], &
    2929          203 :      [ifc%asr, ifc%dipdip, ifc%symdynmat])
    2930           29 :    NCF_CHECK(ncerr)
    2931              :  end if
    2932              : 
    2933              :  ! Examine every wavevector of this list
    2934        60069 :  do iphl2=1,nph2l
    2935              :    ! Initialisation of the phonon wavevector
    2936       240148 :    qphon(:,1) = qph2l(:,iphl2)
    2937        60037 :    qphnrm(1)=zero
    2938        60037 :    if(present(qnrml2)) qphnrm(1) = qnrml2(iphl2)
    2939              : 
    2940              :    ! Calculation of the eigenvectors and eigenvalues of the dynamical matrix
    2941              :    call dfpt_phfrq(ifc%amu,displ_cart,d2cart,eigval,eigvec,crystal%indsym, &
    2942              :       ifc%mpert,crystal%nsym,crystal%natom,crystal%nsym,crystal%ntypat,phfrq,qphnrm(1),qphon, &
    2943        60037 :       crystal%rprimd,ifc%symdynmat,crystal%symrel,crystal%symafm,crystal%typat,crystal%ucvol)
    2944              : 
    2945              :    ! Write the phonon frequencies
    2946              :    !call dfpt_prtph(displ_cart,inp%eivec,inp%enunit,ab_out,natom,phfrq,qphnrm(1),qphon)
    2947              : 
    2948       480037 :    if(present(phfrq2l)) phfrq2l(:,iphl2)=phfrq(:)
    2949              : 
    2950        60037 :    if(present(polarity2l))then
    2951      1740000 :      polarity2l(:,:,iphl2)=zero
    2952       480000 :      do imode=1,3*crystal%natom
    2953      1500000 :        do iatom=1,crystal%natom
    2954      4500000 :          do idir=1,3
    2955     13260000 :            polarity2l(:,imode,iphl2)=polarity2l(:,imode,iphl2)+ifc%zeff(:,idir,iatom)*displ_cart(1,idir+(iatom-1)*3,imode)
    2956              :          enddo
    2957              :        enddo
    2958              :      enddo
    2959              :    endif
    2960              : 
    2961        60069 :    if(present(ncid))then
    2962              :      ! Loop is not MPI-parallelized --> no need for MPI-IO API.
    2963           37 :      call defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, mode="write")
    2964              :    endif
    2965              :  end do ! iphl2
    2966              : 
    2967           32 :  ABI_FREE(phfrq)
    2968           32 :  ABI_FREE(displ_cart)
    2969           32 :  ABI_FREE(d2cart)
    2970           32 :  ABI_FREE(eigvec)
    2971           32 :  ABI_FREE(eigval)
    2972              : 
    2973           35 : end subroutine ifc_calcnwrite_nana_terms
    2974              : !!***
    2975              : 
    2976              : !----------------------------------------------------------------------
    2977              : 
    2978            1 : subroutine ifc_calcnwrite_nana_terms_qpath(ifc, qpath, cryst, ncid, units)
    2979              : 
    2980              : !Arguments ------------------------------------
    2981              :  class(ifc_type),intent(in) :: ifc
    2982              :  integer,intent(in) :: ncid, units(:)
    2983              :  type(kpath_t),intent(in) :: qpath
    2984              :  type(crystal_t),intent(in) :: cryst
    2985              : 
    2986              : !Local variables-------------------------------
    2987              : !scalars
    2988              :  integer :: iq, nq_vers, natom3, nu
    2989              :  character(len=500) :: msg
    2990              : !arrays
    2991            2 :  real(dp) :: phfreqs(3*cryst%natom), displ_cart(2,3,cryst%natom,3*cryst%natom)
    2992            1 :  real(dp),allocatable :: qvers_red(:,:), qvers_cart(:,:)
    2993              : ! ************************************************************************
    2994              : 
    2995            1 :  natom3 = 3 * cryst%natom
    2996            1 :  call qpath%get_versors(nq_vers, qvers_red, qvers_cart)
    2997              : 
    2998            3 :  do iq=1,nq_vers
    2999            2 :    call ifc%fourq(cryst, qvers_red(:,iq), phfreqs, displ_cart, nanaqdir="reduced")
    3000              : 
    3001            2 :    call wrtout(units, sjoin("Phonon frequencies in meV along reduced direction:", ktoa(qvers_red(:,iq)), "(reciprocal space)"))
    3002            2 :    if (iq == 1) then
    3003            1 :      call defwrite_nonana_terms(ncid, iq, nq_vers, qvers_cart, cryst%natom, phfreqs, displ_cart, mode="define")
    3004              :    end if
    3005            2 :    call defwrite_nonana_terms(ncid, iq, nq_vers, qvers_cart, cryst%natom, phfreqs, displ_cart, mode="write")
    3006              : 
    3007           15 :    do nu=1,natom3
    3008           12 :      write(msg, "(1x,i0, es16.6)") nu, phfreqs(nu) * Ha_meV
    3009           14 :      call wrtout(units, msg)
    3010              :    end do
    3011              :  end do
    3012              : 
    3013            1 :  ABI_FREE(qvers_red)
    3014            1 :  ABI_FREE(qvers_cart)
    3015              : 
    3016            1 : end subroutine ifc_calcnwrite_nana_terms_qpath
    3017              : !!***
    3018              : 
    3019              : !----------------------------------------------------------------------
    3020              : 
    3021              : !!****f* m_ifc/ifc_to_ddb
    3022              : !! NAME
    3023              : !! ifc_to_ddb
    3024              : !!
    3025              : !! FUNCTION
    3026              : !! Construct a DDB object from the IFC object.
    3027              : !!
    3028              : !! INPUTS
    3029              : !!  crystal = Crystal object
    3030              : !!
    3031              : !! OUTPUT
    3032              : !!  ddb = DDB object
    3033              : !!
    3034              : !! SOURCE
    3035              : 
    3036           44 : subroutine ifc_to_ddb(ifc, ddb, crystal)
    3037              : 
    3038              : !Arguments -----------------------------------
    3039              : !scalars
    3040              :  class(ifc_type),intent(inout) :: ifc
    3041              :  type(ddb_type),intent(out) :: ddb
    3042              :  type(crystal_t),intent(in) :: crystal
    3043              : 
    3044              : !Local variables-------------------------------
    3045              : !scalars
    3046              :  integer,parameter :: qptopt=1, nqshft=1
    3047              :  integer :: jj,iqpt,idir1,idir2,ipert1,ipert2, mpert,msize, nqibz,nqbz
    3048              :  real(dp) :: qj,qptnrm
    3049              : !arrays
    3050              :  integer :: qptrlatt(3,3)
    3051           44 :  integer,allocatable :: flg(:,:,:,:), flg_gamma(:,:,:,:)
    3052              :  real(dp) :: qpt(3), qshft(1,3)
    3053           44 :  real(dp),allocatable :: qibz(:,:),qbz(:,:), wtq(:), d2cart(:,:,:,:,:),d2red(:,:,:,:,:)
    3054              : ! *********************************************************************
    3055              : 
    3056              :   ! Initialize DDB with minimal info
    3057              :   ! ================================
    3058              : 
    3059              :   ! Crystal info
    3060           44 :   ddb%natom  = crystal%natom
    3061           44 :   ddb%ntypat = crystal%ntypat
    3062          572 :   ddb%rprim  = ifc%rprim
    3063          572 :   ddb%gprim  = ifc%gprim
    3064          176 :   ddb%acell  = ifc%acell
    3065           44 :   call alloc_copy(crystal%amu, ddb%amu)
    3066              : 
    3067              :   ! Block size
    3068              :   ! GA: TODO need to compute mpert in a more transparent way.
    3069              :   !     Also, mpert should be consistent with ifc_init.
    3070           44 :   mpert = ddb%natom + 6
    3071           44 :   msize = 3*mpert*3*mpert
    3072           44 :   ddb%mpert = mpert
    3073           44 :   ddb%msize = msize
    3074              : 
    3075              :   ! Generate q-points
    3076           44 :   qshft = zero
    3077           44 :   qptrlatt = zero
    3078           44 :   qptrlatt(1,1)=ifc%ngqpt(1)
    3079           44 :   qptrlatt(2,2)=ifc%ngqpt(2)
    3080           44 :   qptrlatt(3,3)=ifc%ngqpt(3)
    3081              : 
    3082           44 :   call kpts_ibz_from_kptrlatt(crystal,qptrlatt,qptopt,nqshft,qshft, nqibz,qibz,wtq,nqbz,qbz)
    3083              : 
    3084           44 :   ddb%nblok = nqibz
    3085      2166087 :   ABI_MALLOC(ddb%flg,(msize,nqibz))  ; ddb%flg = one
    3086        11911 :   ABI_MALLOC(ddb%nrm,(3,nqibz))      ; ddb%nrm = zero ; ddb%nrm(1,:) = one
    3087        23602 :   ABI_MALLOC(ddb%qpt,(9,nqibz))      ; ddb%qpt = zero
    3088         9476 :   ABI_MALLOC(ddb%omega,(3,nqibz))    ; ddb%omega = zero
    3089      6493215 :   ABI_MALLOC(ddb%val,(2,msize,nqibz)); ddb%val = zero
    3090          132 :   ABI_MALLOC(ddb%typ,(nqibz))
    3091              : 
    3092         2391 :   do iqpt=1,nqibz
    3093         2347 :     ddb%typ(iqpt) = BLKTYP_d2E_ns
    3094         9432 :     do jj = 1,3
    3095         7041 :       qj = qibz(jj,iqpt)
    3096         7041 :       if (abs(qj).lt.tol8) qj = zero
    3097         9388 :       ddb%qpt(jj,iqpt) = qj
    3098              :     end do
    3099              :   end do
    3100              : 
    3101           44 :   ABI_FREE(wtq)
    3102           44 :   ABI_FREE(qibz)
    3103           44 :   ABI_FREE(qbz)
    3104              : 
    3105              :   ! Compute DDB by Fourier transform of the IFC
    3106              :   ! ===========================================
    3107              : 
    3108           44 :   qptnrm = one
    3109          220 :   ABI_MALLOC(d2cart,(2,3,mpert,3,mpert))
    3110          132 :   ABI_MALLOC(d2red,(2,3,mpert,3,mpert))
    3111              : 
    3112              :   ! Set up the flags
    3113        42184 :   ABI_CALLOC(flg,(3,mpert,3,mpert))
    3114        42096 :   ABI_CALLOC(flg_gamma,(3,mpert,3,mpert))
    3115          150 :   do ipert1=1,ddb%natom
    3116          664 :     do ipert2=1,ddb%natom
    3117         2162 :       do idir1=1,3
    3118         6682 :         do idir2=1,3
    3119         4626 :           flg(idir1,ipert1,idir2,ipert2) = one
    3120         6168 :           flg_gamma(idir1,ipert1,idir2,ipert2) = one
    3121              :         end do
    3122              :       end do
    3123              :     end do
    3124              :   end do
    3125              : 
    3126              :   ! Activate dielt and zeff flag if we have them
    3127           44 :   if (ifc%dipdip > 0) then
    3128              : 
    3129              :     ! Dielectric tensor
    3130            5 :     ipert1 = ddb%natom + 2; ipert2 = ddb%natom + 2;
    3131           20 :     do idir1=1,3
    3132           65 :       do idir2=1,3
    3133           60 :         flg_gamma(idir1,ipert1,idir2,ipert2) = one
    3134              :       end do
    3135              :     end do
    3136              : 
    3137              :     ! Born effective charges
    3138           16 :     ipert1 = ddb%natom + 2
    3139           16 :     do ipert2=1,ddb%natom
    3140           49 :       do idir1=1,3
    3141          143 :         do idir2=1,3
    3142           99 :           flg_gamma(idir1,ipert1,idir2,ipert2) = one
    3143          132 :           flg_gamma(idir1,ipert2,idir2,ipert1) = one
    3144              :         end do
    3145              :       end do
    3146              :     end do
    3147              :   end if
    3148              : 
    3149         2391 :   do iqpt=1,DDB%nblok
    3150              : 
    3151         9388 :     qpt(:) = DDB%qpt(1:3,iqpt)
    3152              : 
    3153              :     ! Get d2cart using the interatomic forces and the
    3154              :     ! long-range coulomb interaction through Ewald summation
    3155              :     call gtdyn9(ddb%acell,ifc%atmfrc,ifc%dielt,ifc%dipdip,ifc%dyewq0,d2cart, &
    3156              :      crystal%gmet,ddb%gprim,ddb%mpert,crystal%natom,ifc%nrpt,qptnrm,qpt,&
    3157              :      crystal%rmet,ddb%rprim,ifc%rpt,ifc%trans,crystal%ucvol, &
    3158              :      ifc%wghatm,crystal%xred,ifc%zeff,ifc%qdrp_cart,ifc%ewald_option, ifc%eta,&
    3159         2347 :      xmpi_comm_self,ifc%sys_dim)
    3160              : 
    3161              :     ! Impose the acoustic sum rule
    3162              :     !asrq0 = ddb%get_asrq0(1,1,crystal%xcart)
    3163              :     !call asrq0%apply(ddb%natom, ddb%mpert, ddb%msize, crystal%xcart, d2cart)
    3164              : 
    3165              :     ! Transform d2cart into reduced coordinates.
    3166              :     call d2cart_to_red(d2cart,d2red,crystal%gprimd,crystal%rprimd,ddb%mpert, &
    3167         2347 :      crystal%natom,crystal%ntypat,crystal%typat,crystal%ucvol,crystal%zion)
    3168              : 
    3169              :     ! Check if this q-point is Gamma
    3170         2347 :     call gamma9(jj, qpt, qptnrm, DDB_QTOL)
    3171              : 
    3172         2391 :     if (jj == 1) then
    3173           44 :       call ddb%set_d2matr(iqpt, d2red, flg_gamma)
    3174              :     else
    3175         2303 :       call ddb%set_d2matr(iqpt, d2red, flg)
    3176              :     end if
    3177              : 
    3178              :   end do
    3179              : 
    3180           44 :   ABI_FREE(d2cart)
    3181           44 :   ABI_FREE(d2red)
    3182           44 :   ABI_FREE(flg)
    3183           44 :   ABI_FREE(flg_gamma)
    3184              : 
    3185           44 : end subroutine ifc_to_ddb
    3186              : !!***
    3187              : 
    3188              : !!****f* m_ifc/defwrite_nonana_terms
    3189              : !! NAME
    3190              : !! defwrite_nonana_terms
    3191              : !!
    3192              : !! FUNCTION
    3193              : !!  Write to ncfile the phonon frequencies and displacements for q --> 0 in the presence of non-analytical behaviour.
    3194              : !!
    3195              : !! INPUTS
    3196              : !!  ncid=netcdf file id.
    3197              : !!  iq_dir=Index of the q-point to be written to file
    3198              : !!  ndirs=Number of qpoints.
    3199              : !!  qdirs_cart(3,ndirs)=List of phonon wavevector directions along which the non-analytical correction
    3200              : !!    to the Gamma-point phonon frequencies will be calculated. The direction is in CARTESIAN COORDINATES
    3201              : !!  natom=Number of atoms
    3202              : !!  phfrq(3*natom)=Phonon frequencies in Ha
    3203              : !!  cart_displ(2,3*natom,3*natom)=displacements in CARTESIAN coordinates.
    3204              : !!
    3205              : !! OUTPUT
    3206              : !!  Only writing.
    3207              : !!
    3208              : !! SOURCE
    3209              : 
    3210          130 : subroutine defwrite_nonana_terms(ncid, iq_dir, ndirs, qdirs_cart, natom, phfrq, cart_displ, mode)
    3211              : 
    3212              : !Arguments ------------------------------------
    3213              : !scalars
    3214              :  integer,intent(in) :: ncid,iq_dir,ndirs,natom
    3215              :  character(len=*),intent(in) :: mode
    3216              : !arrays
    3217              :  real(dp),intent(in) :: qdirs_cart(3, ndirs), phfrq(3*natom), cart_displ(2,3*natom,3*natom)
    3218              : 
    3219              : !Local variables-------------------------------
    3220              :  integer :: ncerr, na_phmodes_varid, na_phdispl_varid
    3221              : ! *************************************************************************
    3222              : 
    3223           54 :  select case (mode)
    3224              :  case ("define")
    3225              :    !NCF_CHECK(nctk_def_basedims(ncid, defmode=.True.))
    3226          108 :    ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_non_analytical_directions", ndirs)], defmode=.True.)
    3227           54 :    NCF_CHECK(ncerr)
    3228              : 
    3229              :    ncerr = nctk_def_arrays(ncid, [&
    3230              :      nctkarr_t('non_analytical_directions', "dp", "number_of_cartesian_directions, number_of_non_analytical_directions"),&
    3231              :      nctkarr_t('non_analytical_phonon_modes', "dp", "number_of_phonon_modes, number_of_non_analytical_directions"),&
    3232              :      nctkarr_t('non_analytical_phdispl_cart', "dp", &
    3233          216 :                "two, number_of_phonon_modes, number_of_phonon_modes, number_of_non_analytical_directions")])
    3234           54 :    NCF_CHECK(ncerr)
    3235              : 
    3236           54 :    NCF_CHECK(nctk_set_datamode(ncid))
    3237           54 :    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "non_analytical_directions"), qdirs_cart))
    3238              : 
    3239              :  case ("write")
    3240           76 :    NCF_CHECK(nf90_inq_varid(ncid, "non_analytical_phonon_modes", na_phmodes_varid))
    3241         1154 :    NCF_CHECK(nf90_put_var(ncid,na_phmodes_varid,phfrq*Ha_eV,start=[1, iq_dir], count=[3*natom, 1]))
    3242           76 :    NCF_CHECK(nf90_inq_varid(ncid, "non_analytical_phdispl_cart", na_phdispl_varid))
    3243              :    ncerr = nf90_put_var(ncid,na_phdispl_varid,cart_displ*Bohr_Ang,&
    3244        33426 :    start=[1,1,1,iq_dir], count=[2,3*natom,3*natom, 1])
    3245           76 :    NCF_CHECK(ncerr)
    3246              : 
    3247              :  case default
    3248          130 :    ABI_ERROR(sjoin("Wrong value for mode", mode))
    3249              :  end select
    3250              : 
    3251          130 : end subroutine defwrite_nonana_terms
    3252              : !!***
    3253              : 
    3254              : !----------------------------------------------------------------------
    3255              : 
    3256            0 : end module m_ifc
    3257              : !!***
        

Generated by: LCOV version 2.3-1