LCOV - code coverage report
Current view: top level - src/44_abitools - m_dynmat.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 88.3 % 2158 1905
Test Date: 2026-09-21 13:49:52 Functions: 93.5 % 46 43

            Line data    Source code
       1              : !!****m* ABINIT/m_dynmat
       2              : !! NAME
       3              : !!  m_dynmat
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides low-level tools to operate on the dynamical matrix
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 2014-2026 ABINIT group (XG, JCC, MJV, NH, RC, MVeithen, MM, MG, MT, DCA)
      10              : !!  This file is distributed under the terms of the
      11              : !!  GNU General Public License, see ~abinit/COPYING
      12              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! TODO
      15              : !!  Use more explicative names for the procedures!
      16              : !!
      17              : !! SOURCE
      18              : 
      19              : #if defined HAVE_CONFIG_H
      20              : #include "config.h"
      21              : #endif
      22              : 
      23              : #include "abi_common.h"
      24              : 
      25              : module m_dynmat
      26              : 
      27              :  use, intrinsic :: iso_c_binding
      28              :  use defs_basis
      29              :  use m_abicore
      30              :  use m_errors
      31              :  use m_linalg_interfaces
      32              :  use m_xmpi
      33              : 
      34              :  use m_fstrings,        only : itoa, sjoin
      35              :  use m_numeric_tools,   only : wrap2_pmhalf, mkherm
      36              :  use m_matrix,          only : mati3inv, matr3inv
      37              :  use m_symtk,           only : littlegroup_q
      38              :  use m_cgtools,         only : fxphas_seq
      39              :  use m_crystal,        only : crystal_t
      40              :  use m_ewald,           only : ewald9, ewald9_2D
      41              :  use m_time,            only : timab
      42              : 
      43              :  implicit none
      44              : 
      45              :  private
      46              : 
      47              :  public :: asria_calc           ! Calculate the correction for the Acoustic sum rule on
      48              :                                 !   the InterAtomic Forces or on the dynamical matrix directly
      49              :  public :: asria_corr           ! Imposition of the Acoustic sum rule on the InterAtomic Forces
      50              :                                 !   or on the dynamical matrix directly from the previously calculated d2asr
      51              :  public :: asrprs               ! Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry
      52              :  public :: cart29               ! Transform a second-derivative matrix from reduced  coordinates to cartesian coordinates, and also
      53              :                                 !   1) add the ionic part of the effective charges,
      54              :                                 !   2) normalize the electronic dielectric tensor, and add the vacuum polarisation
      55              :  public :: cart39               ! Transform a vector from reduced coordinates to cartesian coordinates,
      56              :                                 !   taking into account the perturbation from which it was derived,
      57              :                                 !   and also check the existence of the new values.
      58              :  public :: d2cart_to_red        ! Transform a second-derivative matrix
      59              :                                 ! from cartesian to reduced coordinate.
      60              :  public :: chkph3               ! Check the completeness of the dynamical matrix
      61              :  public :: chneu9               ! Imposition of the charge neutrality sum rule on the Effective charges
      62              :  public :: d2sym3               ! Build (nearly) all the other matrix elements that can be build using symmetries.
      63              :  public :: q0dy3_apply          ! Takes care of the inclusion of the ewald q=0 term in the dynamical matrix
      64              :  public :: q0dy3_calc           ! Calculate the q=0 correction term to the dynamical matrix
      65              :  ! TODO: 3 routines to symmetrize. Clarify different use cases
      66              :  public :: symdyma              ! Symmetrize the dynamical matrices
      67              :  public :: dfpt_sygra           ! Symmetrize derivatives of energy with respect to coordinates,
      68              :  public :: dfpt_sydy            ! Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
      69              :  public :: wings3               ! Suppress the wings of the cartesian 2DTE for which the diagonal element is not known
      70              :  public :: asrif9               ! Imposes the Acoustic Sum Rule to Interatomic Forces
      71              :  public :: get_bigbox_and_weights ! Compute
      72              :  public :: bigbx9               ! Generates a Big Box of R points for the Fourier Transforms the dynamical matrix
      73              :  public :: make_bigbox          ! Helper functions that faciliates the generation  of a Big Box containing
      74              :  public :: canat9               ! From reduced to canonical coordinates
      75              :  public :: canct9               ! Convert from canonical coordinates to cartesian coordinates
      76              :  public :: chkrp9               ! Check if the rprim used for the definition of the unit cell (in the
      77              :                                 ! inputs) are consistent with the rprim used in the routine generating  the Big Box
      78              :  public :: dist9                ! Compute the distance between atoms in the big box
      79              :  public :: ftifc_q2r            ! Fourier transform of the dynamical matrices to obtain interatomic forces (real space).
      80              :  public :: ftifc_r2q            ! Fourier transform of the interatomic forces to obtain dynamical matrices (reciprocal space).
      81              :  public :: dynmat_dq            ! Compute the derivative D(q)/dq via Fourier transform of the interatomic forces
      82              :  public :: ifclo9               ! Convert from cartesian coordinates to local coordinates
      83              :  public :: wght9                ! Generates a weight to each R points of the Big Box and for each pair of atoms
      84              :  public :: d3sym                ! Given a set of calculated elements of the 3DTE matrix,
      85              :                                 ! build (nearly) all the other matrix elements that can be build using symmetries.
      86              :  public :: sytens               ! Determines the set of irreductible elements of the nonlinear optical susceptibility
      87              :                                 ! and Raman tensors
      88              :  public :: axial9               ! Generates the local coordinates system from the  knowledge of the first vector (longitudinal) and
      89              :                                 !   the ifc matrix in cartesian coordinates
      90              :  public :: dymfz9               ! Multiply the dynamical matrix by a phase shift to account for normalized canonical coordinates.
      91              :  public :: nanal9               ! Subtract/Add the non-analytical part from one dynamical matrix with number iqpt.
      92              :  public :: gtdyn9               ! Generates a dynamical matrix from interatomic force constants and
      93              :                                 ! long-range electrostatic interactions.
      94              :  public :: dfpt_phfrq           ! Diagonalize IFC(q), return phonon frequencies and eigenvectors.
      95              :                                 ! If q is Gamma, the non-analytical behaviour can be included.
      96              :  public :: pheigvec_normalize   ! Normalize input eigenvectors in cartesian coordinates.
      97              :  public :: phdispl_from_eigvec  ! Phonon displacements from eigenvectors
      98              :  public :: phangmom_from_eigvec ! compute phonon angular momentum for one q-point from eigenvectors
      99              :  public :: dfpt_prtph           ! Print phonon frequencies
     100              :  public :: massmult_and_breaksym  ! Multiply IFC(q) by atomic masses.
     101              :  public :: massmult_and_breaksym_cplx  ! Version for complex array
     102              : 
     103              :  ! TODO: Change name,
     104              :  public :: ftgam
     105              :  public :: ftgam_init
     106              : 
     107              :  public :: msria_calc          ! Calculate the correction for the Acoustic sum rule
     108              :                                ! + rotational invariance on the IFCs in reciprocal space
     109              :  public :: msria_apply         ! Apply the correction for the Acoustic sum rule + rotational invariance
     110              :                                ! If IFCs derivatives calculated both from LW driver and Fourier, correct the interpolation
     111              : 
     112              : ! *************************************************************************
     113              : 
     114              : contains
     115              : !!***
     116              : 
     117              : !!****f* m_dynmat/asria_calc
     118              : !! NAME
     119              : !! asria_calc
     120              : !!
     121              : !! FUNCTION
     122              : !! Calculate the correction for the Acoustic sum rule on the InterAtomic Forces
     123              : !! or on the dynamical matrix directly
     124              : !!
     125              : !! INPUTS
     126              : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
     127              : !!      5 => impose hermitian solution using lapack call)
     128              : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
     129              : !! mpert =maximum number of ipert
     130              : !! natom=number of atom
     131              : !!
     132              : !! OUTPUT
     133              : !! d2asr=matrix used to store the correction needed to fulfill
     134              : !! the acoustic sum rule.
     135              : !!
     136              : !! SOURCE
     137              : 
     138          286 : subroutine asria_calc(asr,d2asr,d2cart,mpert,natom)
     139              : 
     140              : !Arguments -------------------------------
     141              : !scalars
     142              :  integer,intent(in) :: asr,mpert,natom
     143              : !arrays
     144              :  real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
     145              :  real(dp),intent(out) :: d2asr(2,3,natom,3,natom)
     146              : 
     147              : !Local variables-------------------------------
     148              : !scalars
     149              :  integer :: idir1,idir2,ii,ipert1,ipert2
     150              :  integer :: constrank, imatelem, iconst, nconst, nd2_packed, info
     151              :  !character(len=500) :: msg
     152              : !arrays
     153          286 :  integer, allocatable :: packingindex(:,:,:,:)
     154          286 :  real(dp), allocatable :: constraints(:,:,:)
     155          286 :  real(dp), allocatable :: d2cart_packed(:,:)
     156          286 :  real(dp), allocatable :: singvals(:)
     157          286 :  real(dp), allocatable :: constr_rhs(:,:)
     158          286 :  real(dp), allocatable :: work(:,:),rwork(:)
     159              : ! *********************************************************************
     160              : 
     161       127546 :  d2asr = zero
     162              : 
     163          286 :  if (asr==0) return
     164              : 
     165              :  !call wrtout(std_out,' asria_calc: calculation of the correction to the ASR for the interatomic forces.')
     166         1156 :  do ipert1=1,natom
     167         3766 :    do idir1=1,3
     168        11310 :      do idir2=1,3
     169              : 
     170              : !      Compute d2asr
     171        47574 :        do ipert2=1,natom
     172              :          d2asr(:,idir1,ipert1,idir2,ipert1)=&
     173              : &         d2asr(:,idir1,ipert1,idir2,ipert1)+&
     174       119232 : &         d2cart(:,idir1,ipert1,idir2,ipert2)
     175              :        end do
     176              :      end do
     177              :    end do
     178              :  end do
     179              : 
     180              : !holistic method: overwrite d2asr with hermitian solution
     181          286 :  if (asr == 5) then
     182            0 :    nconst = 9*natom
     183            0 :    nd2_packed = 3*natom*(3*natom+1)/2
     184            0 :    ABI_MALLOC(constraints,(2,nconst, nd2_packed))
     185            0 :    ABI_MALLOC(d2cart_packed,(2,nd2_packed))
     186            0 :    ABI_MALLOC(constr_rhs,(2,nd2_packed))
     187            0 :    ABI_MALLOC(singvals,(nconst))
     188            0 :    ABI_MALLOC(work,(2,3*nd2_packed))
     189            0 :    ABI_MALLOC(rwork,(5*nd2_packed))
     190            0 :    ABI_MALLOC(packingindex,(3,natom,3,natom))
     191            0 :    ii=1
     192            0 :    packingindex=-1
     193            0 :    do ipert2=1,natom
     194            0 :      do idir2=1,3
     195            0 :        do ipert1=1,ipert2-1
     196            0 :          do idir1=1,3
     197            0 :            packingindex(idir1,ipert1,idir2,ipert2) = ii
     198            0 :            ii = ii+1
     199              :          end do
     200              :        end do
     201            0 :        do idir1=1,idir2
     202            0 :          packingindex(idir1,ipert2,idir2,ipert2) = ii
     203            0 :          ii = ii+1
     204              :        end do
     205              :      end do
     206              :    end do
     207              : !  setup constraint matrix
     208            0 :    constraints = zero
     209            0 :    do ipert1=1,natom
     210            0 :      do idir1=1,3
     211            0 :        do idir2=1,3
     212            0 :          iconst = idir2+3*(idir1-1 + 3*(ipert1-1))
     213              : !        set all atom forces, this component
     214            0 :          do ipert2=1,natom
     215            0 :            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
     216            0 :            if (imatelem == -1) then
     217            0 :              imatelem = packingindex(idir2,ipert2,idir1,ipert1)
     218              :            end if
     219            0 :            constraints(1,iconst,imatelem) = one
     220              :          end do
     221              :        end do
     222              :      end do
     223              :    end do
     224              : 
     225            0 :    d2cart_packed = -999.0d0
     226            0 :    do ipert2=1,natom
     227            0 :      do idir2=1,3
     228            0 :        do ipert1=1,natom
     229            0 :          do idir1=1,3
     230            0 :            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
     231            0 :            if (imatelem == -1) cycle
     232            0 :            d2cart_packed(:,imatelem) = d2cart(:,idir1,ipert1,idir2,ipert2)
     233              :          end do
     234              :        end do
     235              :      end do
     236              :    end do
     237            0 :    constr_rhs = zero
     238            0 :    constr_rhs(1,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(1,:))
     239            0 :    constr_rhs(2,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(2,:))
     240              : 
     241              : !  lwork = 3*nd2_packed
     242              :    call zgelss (nconst,nd2_packed,1,constraints,nconst,constr_rhs,nd2_packed,&
     243            0 : &   singvals,-one,constrank,work,3*nd2_packed,rwork,info)
     244            0 :    ABI_CHECK(info == 0, sjoin('zgelss returned:', itoa(info)))
     245              : 
     246              : !  unpack
     247            0 :    do ipert2=1,natom
     248            0 :      do idir2=1,3
     249            0 :        do ipert1=1,natom
     250            0 :          do idir1=1,3
     251            0 :            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
     252            0 :            if (imatelem == -1) then
     253            0 :              imatelem = packingindex(idir2,ipert2,idir1,ipert1)
     254              : !            NOTE: should complex conjugate the correction below.
     255              :            end if
     256            0 :            d2asr(:,idir1,ipert1,idir2,ipert2) = constr_rhs(:,imatelem)
     257              :          end do
     258              :        end do
     259              :      end do
     260              :    end do
     261              : 
     262            0 :    ABI_FREE(constraints)
     263            0 :    ABI_FREE(d2cart_packed)
     264            0 :    ABI_FREE(singvals)
     265            0 :    ABI_FREE(constr_rhs)
     266            0 :    ABI_FREE(work)
     267            0 :    ABI_FREE(rwork)
     268            0 :    ABI_FREE(packingindex)
     269              :  end if
     270              : 
     271              : end subroutine asria_calc
     272              : !!***
     273              : 
     274              : !----------------------------------------------------------------------
     275              : 
     276              : !!****f* m_dynmat/asria_corr
     277              : !! NAME
     278              : !! asria_corr
     279              : !!
     280              : !! FUNCTION
     281              : !! Imposition of the Acoustic sum rule on the InterAtomic Forces
     282              : !! or on the dynamical matrix directly from the previously calculated d2asr
     283              : !!
     284              : !! INPUTS
     285              : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
     286              : !!      5 => impose hermitian solution using lapack call)
     287              : !! d2asr=matrix used to store the correction needed to fulfill
     288              : !! the acoustic sum rule.
     289              : !! mpert =maximum number of ipert
     290              : !! natom=number of atom
     291              : !!
     292              : !! OUTPUT
     293              : !! Input/Output:
     294              : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
     295              : !!
     296              : !! SOURCE
     297              : 
     298          255 : subroutine asria_corr(asr,d2asr,d2cart,mpert,natom)
     299              : 
     300              : !Arguments -------------------------------
     301              : !scalars
     302              :  integer,intent(in) :: asr,mpert,natom
     303              : !arrays
     304              :  real(dp),intent(in) :: d2asr(2,3,natom,3,natom)
     305              :  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
     306              : 
     307              : !Local variables-------------------------------
     308              : !scalars
     309              :  integer :: idir1,idir2,ipert1,ipert2
     310              : ! *********************************************************************
     311              : 
     312          255 :  if (asr==0) return
     313              :  !call wrtout(std_out,' asria_corr: imposition of the ASR for the interatomic forces.')
     314              : 
     315              :  ! Remove d2asr
     316          961 :  do ipert2=1,natom
     317         3079 :    do idir2=1,3
     318        11518 :      do ipert1=1,natom
     319        36894 :        do idir1=1,3
     320        86940 :          d2cart(:,idir1,ipert1,idir2,ipert2)= d2cart(:,idir1,ipert1,idir2,ipert2) - d2asr(:,idir1,ipert1,idir2,ipert2)
     321              :        end do
     322              :      end do
     323              :    end do
     324              :  end do
     325              : 
     326              : end subroutine asria_corr
     327              : !!***
     328              : 
     329              : !----------------------------------------------------------------------
     330              : 
     331              : !!****f* m_dynmat/asrprs
     332              : !! NAME
     333              : !! asrprs
     334              : !!
     335              : !! FUNCTION
     336              : !! Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry
     337              : !!
     338              : !! INPUTS
     339              : !!  asr=(3 => 1D systems, all elements are modified to give ASR and
     340              : !!            rotational symmetry)
     341              : !!      (4 => 0D systems, all elements are modified to give ASR and
     342              : !!            rotational symmetry)
     343              : !!  asrflg=(1 => the correction to enforce asr is computed from
     344              : !!           d2cart, but NOT applied;
     345              : !!          2 => one uses the previously determined correction)
     346              : !!  minvers=previously calculated inverted coefficient matrix
     347              : !!  mpert =maximum number of ipert
     348              : !!  natom=number of atom
     349              : !!  rotinv=(1,2,3 => for linear systems along x,y,z
     350              : !!          4 => non-linear molecule
     351              : !!  xcart=cartesian coordinates of the ions
     352              : !!
     353              : !! OUTPUT
     354              : !!  (see side effects)
     355              : !!
     356              : !! SIDE EFFECTS
     357              : !! Input/Output:
     358              : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
     359              : !! minvers=inverse of the supermatrix for future application of the corrections
     360              : !!
     361              : !! SOURCE
     362              : 
     363           24 : subroutine asrprs(asr,asrflag,rotinv,uinvers,vtinvers,singular,d2cart,mpert,natom,xcart)
     364              : 
     365              : !Arguments ------------------------------------
     366              : !scalars
     367              :  integer,intent(in) :: asr,asrflag,mpert,natom,rotinv
     368              : !arrays
     369              :  real(dp),intent(in) :: xcart(3,natom)
     370              :  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
     371              :  real(dp),intent(inout) :: singular(1:3*natom*(3*natom-1)/2)
     372              :  real(dp),intent(inout) :: uinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
     373              :  real(dp),intent(inout) :: vtinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
     374              : 
     375              : !Local variables-------------------------------
     376              : !scalars
     377              :  integer :: column,idir1,idir2,ii,info,ipert1,ipert2,jj,n3,row,superdim
     378              :  real(dp) :: rcond,test
     379              : ! real(dp) :: tau ! tau is present but commented out in this routine
     380              :  character(len=500) :: msg
     381              : !arrays
     382           48 :  integer :: check(3,natom,3)
     383           48 :  real(dp) :: tmp(natom,3,3),weightf(1:natom,1:natom)
     384           24 :  real(dp),allocatable :: d2cartold(:,:,:,:,:),d2vecc(:),d2veccnew(:),d2vecr(:)
     385           24 :  real(dp),allocatable :: d2vecrnew(:),superm(:,:),umatrix(:,:),vtmatrix(:)
     386           24 :  real(dp),allocatable :: work(:)
     387              : ! *********************************************************************
     388              : 
     389           24 :  if(asr/=3 .and. asr/=4)then
     390              :    write(msg,'(3a,i0)')&
     391            0 :    'The argument asr should be 3 or 4,',ch10, 'however, asr = ',asr
     392            0 :    ABI_BUG(msg)
     393              :  end if
     394              : 
     395           24 :  if (asr==3.or.asr==4)then
     396           24 :    write(msg, '(a,a)' ) ch10, &
     397           48 :    'asrprs: imposition of the ASR for the interatomic forces and rotational invariance'
     398           24 :    call wrtout(std_out,msg)
     399              :  end if
     400              : 
     401           24 :  write(msg,'(a,i0)')' asrflag is ', asrflag
     402           72 :  call wrtout([std_out, ab_out], msg)
     403              : 
     404              : !variables for the dimensions of the matrices
     405              : 
     406              : !n1=3*natom*(3*natom-1)/2
     407              : !n2=9*natom
     408           24 :  n3=3*natom
     409              : 
     410           24 :  superdim=9*natom*(natom-1)/2+n3
     411              : 
     412           72 :  ABI_MALLOC(d2vecr,(1:superdim))
     413           48 :  ABI_MALLOC(d2vecc,(1:superdim))
     414          384 :  d2vecr=0d0
     415          384 :  d2vecc=0d0
     416              : 
     417              : !should be changed set to delta function for debugging
     418          168 :  weightf=1d0
     419              : !tau=1d-10
     420           72 :  do ii=1, natom
     421              : !  do jj=1, ii-1
     422              : !  weightf(ii,jj)= &
     423              : !  &     ((xcart(1,ii)-xcart(1,jj))**2+(xcart(2,ii)-xcart(2,jj))**2+(xcart(3,ii)-xcart(3,jj))**2)**tau
     424              : !  enddo
     425           72 :    weightf(ii,ii)=0d0
     426              :  end do
     427              : 
     428          120 :  ABI_MALLOC(d2cartold,(2,3,mpert,3,mpert))
     429              : 
     430       163488 :  d2cartold=d2cart
     431              : 
     432              : !setup vector with uncorrected derivatives
     433              : 
     434           72 :  do ipert1=1, natom
     435           96 :    do ipert2=1, ipert1-1
     436          144 :      do idir1=1,3
     437          312 :        do idir2=1,3
     438          216 :          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
     439          216 :          if(abs(d2cart(1,idir1,ipert1,idir2,ipert2))<1d-6)then
     440          110 :            d2cart(1,idir1,ipert1,idir2,ipert2)=0d0
     441              :          else
     442          106 :            d2vecr(row)=4*weightf(ipert1,ipert2)*d2cart(1,idir1,ipert1,idir2,ipert2)
     443              :          end if
     444          288 :          if(abs(d2cart(2,idir1,ipert1,idir2,ipert2))<1d-6) then
     445          126 :            d2cart(2,idir1,ipert1,idir2,ipert2)=0d0
     446              :          else
     447           90 :            d2vecc(row)=4*weightf(ipert1,ipert2)*d2cart(2,idir1,ipert1,idir2,ipert2)
     448              :          end if
     449              :        end do
     450              :      end do
     451              :    end do
     452              :  end do
     453              : 
     454           24 :  if(asrflag==1) then !calculate the pseudo-inverse of the supermatrix
     455            8 :    ABI_MALLOC(superm,(1:superdim,1:superdim))
     456              : 
     457          482 :    superm=0d0
     458              : 
     459              : !  Setting up the supermatrix containing G, A, D
     460              : 
     461            6 :    do ipert1=1, natom
     462           16 :      do idir1=1, 3
     463              : !      Setting up G
     464           12 :        idir2=mod(idir1,3)+1
     465           12 :        row=3*(ipert1-1)+idir1
     466           18 :        do ipert2=1, ipert1-1
     467            6 :          column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
     468            6 :          superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
     469            6 :          column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir2
     470           18 :          superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
     471              :        end do
     472           22 :        do ipert2=ipert1+1, natom
     473            6 :          column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir1-1)+rotinv
     474            6 :          superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
     475            6 :          column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir2-1)+rotinv
     476           18 :          superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
     477              :        end do
     478              :      end do
     479           18 :      do idir1=1, 3
     480              : !      Setting up D
     481           12 :        idir2=mod(idir1,3)+1
     482           12 :        ii=mod(idir1+1,3)+1
     483           18 :        do ipert2=1, ipert1-1
     484            6 :          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
     485            6 :          column=9*natom*(natom-1)/2+3*(ipert1-1)+idir1
     486            6 :          superm(column,row)=superm(column,row)+xcart(idir2,ipert2)-xcart(idir2,ipert1)
     487            6 :          column=9*natom*(natom-1)/2+3*(ipert1-1)+ii
     488            6 :          superm(column,row)=superm(column,row)+xcart(ii,ipert1)-xcart(ii,ipert2)
     489            6 :          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+rotinv
     490            6 :          column=9*natom*(natom-1)/2+3*(ipert2-1)+idir1
     491            6 :          superm(column,row)=superm(column,row)+xcart(idir2,ipert1)-xcart(idir2,ipert2)
     492            6 :          column=9*natom*(natom-1)/2+3*(ipert2-1)+ii
     493           18 :          superm(column,row)=superm(column,row)+xcart(ii,ipert2)-xcart(ii,ipert1)
     494              :        end do
     495              : !      Setting up A
     496           52 :        do idir2=1, 3
     497           66 :          do ipert2=1, ipert1-1
     498           18 :            column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
     499           18 :            row=n3+column
     500           54 :            superm(column,row)=4*weightf(ipert1,ipert2)
     501              :          end do
     502              :        end do
     503              :      end do
     504              :    end do
     505              : 
     506              : !  calculate the pseudo-inverse of the supermatrix
     507              : 
     508            6 :    ABI_MALLOC(work,(1:6*superdim))
     509            4 :    ABI_MALLOC(vtmatrix,(1:superdim))
     510            6 :    ABI_MALLOC(umatrix,(1:superdim,1:superdim))
     511              : 
     512              : !  singular value decomposition of superm
     513              : 
     514              :    call dgesvd('A','O',superdim,superdim,superm,superdim,singular,umatrix,superdim, &
     515            2 :                vtmatrix, 1, work,6*superdim,info)
     516            2 :    ABI_CHECK(info == 0, sjoin('dgesvd returned:', itoa(info)))
     517              : 
     518            2 :    ABI_FREE(vtmatrix)
     519            2 :    ABI_FREE(work)
     520              : 
     521            2 :    write(msg, '(a,es16.8,es16.8)' )' Largest and smallest values from svd', singular(1), singular(superdim)
     522            6 :    call wrtout([std_out, ab_out], msg)
     523              : 
     524              : !  Invert U and V**T, orthogonal matrices
     525              : 
     526          482 :    uinvers = transpose(umatrix)
     527          482 :    vtinvers = transpose(superm)
     528              : 
     529            2 :    ABI_FREE(umatrix)
     530            2 :    ABI_FREE(superm)
     531              : 
     532            2 :    write(msg,'(a,a)')' asrprs: done with asrflag 1', ch10
     533            2 :    call wrtout(std_out,msg)
     534              : 
     535              :  end if !asrflag=1
     536              : 
     537           24 :  if(asrflag==2) then
     538              : 
     539           66 :    ABI_MALLOC(d2vecrnew,(1:superdim))
     540           44 :    ABI_MALLOC(d2veccnew,(1:superdim))
     541              : 
     542              : !  Calculate V**T**-1 Sigma**-1 U**-1 *rhs
     543              : 
     544         5632 :    d2vecrnew = matmul(uinvers, d2vecr)
     545         5632 :    d2veccnew = matmul(uinvers, d2vecc)
     546              : 
     547           22 :    rcond=1d-10*singular(1)
     548          352 :    do ii=1, superdim
     549          352 :      if(singular(ii)>rcond) then
     550          286 :        d2vecrnew(ii)=d2vecrnew(ii)/singular(ii)
     551          286 :        d2veccnew(ii)=d2veccnew(ii)/singular(ii)
     552              :      else
     553           44 :        d2vecrnew(ii)=0d0
     554           44 :        d2veccnew(ii)=0d0
     555              :      end if
     556              :    end do
     557              : 
     558          352 :    do ii=1, superdim
     559          330 :      d2vecr(ii)=0d0
     560          330 :      d2vecc(ii)=0d0
     561         5302 :      do jj=1, superdim
     562         4950 :        d2vecr(ii)=d2vecr(ii)+vtinvers(ii,jj)*d2vecrnew(jj)
     563         5280 :        d2vecc(ii)=d2vecc(ii)+vtinvers(ii,jj)*d2veccnew(jj)
     564              :      end do
     565              :    end do
     566              : 
     567              : !  Store vector back into the matrix of 2nd order derivates
     568              : 
     569           66 :    do ipert1=1, natom
     570           88 :      do ipert2=1, ipert1-1
     571          132 :        do idir1=1,3
     572          286 :          do idir2=1,3
     573          198 :            row=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
     574          198 :            d2cart(1,idir1,ipert1,idir2,ipert2)=d2vecr(row)
     575          198 :            d2cart(2,idir1,ipert1,idir2,ipert2)=d2vecc(row)
     576          198 :            d2cart(1,idir2,ipert2,idir1,ipert1)=d2vecr(row)
     577          264 :            d2cart(2,idir2,ipert2,idir1,ipert1)=d2vecc(row)
     578              :          end do
     579              :        end do
     580              :      end do
     581              :    end do
     582              : 
     583           22 :    ABI_FREE(d2vecrnew)
     584           22 :    ABI_FREE(d2veccnew)
     585              : 
     586          616 :    check=0
     587              : 
     588           66 :    do ipert1=1, natom
     589          198 :      do idir1=1, 3
     590          572 :        do idir2=1, 3
     591          396 :          d2cart(1,idir1,ipert1,idir2,ipert1)=0d0
     592          396 :          d2cart(2,idir1,ipert1,idir2,ipert1)=0d0
     593          396 :          tmp(ipert1,idir1,idir2)=0d0
     594         1320 :          do ipert2=1, natom
     595         1188 :            if(ipert2/=ipert1) then
     596              :              tmp(ipert1,idir1,idir2)=tmp(ipert1,idir1,idir2) &
     597              : &             -d2cart(1,idir1,ipert1,idir2,ipert2) &
     598          396 : &             -d2cart(1,idir2,ipert2,idir1,ipert1)
     599              :            end if
     600              :          end do
     601              :        end do
     602              :      end do
     603              :    end do
     604              : 
     605           66 :    do ipert1=1, natom
     606          198 :      do idir1=1, 3
     607          572 :        do idir2=1, 3
     608          396 :          d2cart(1,idir1,ipert1,idir2,ipert1)=tmp(ipert1,idir1,idir2)/2
     609          528 :          d2cart(1,idir2,ipert1,idir1,ipert1)=d2cart(1,idir1,ipert1,idir2,ipert1)
     610              :        end do
     611              :      end do
     612              :    end do
     613              : 
     614           22 :    write(std_out,*) 'this should all be zero'
     615              : 
     616           66 :    do ipert1=1, natom
     617          198 :      do idir1=1, 3
     618          572 :        do idir2=1, 3
     619          396 :          test=0d0
     620         1188 :          do ipert2=1, natom
     621         1188 :            test=test+d2cart(1,idir1,ipert1,idir2,ipert2)+d2cart(1,idir2,ipert2,idir1,ipert1)
     622              :          end do
     623          396 :          write(std_out,'(i3,i3,i3,es11.3)') idir1,ipert1,idir2,test
     624              : 
     625          396 :          write(msg, '(i3,i3,i3,es11.3)' ) idir1,ipert1,idir2,test
     626          528 :          call wrtout(ab_out,msg)
     627              :        end do
     628              :      end do
     629              :    end do
     630              : 
     631           22 :    write(std_out,*) 'these as well'
     632           66 :    do ipert2=1, natom
     633          198 :      do idir1=1, 3
     634          572 :        do idir2=1, 3
     635          396 :          test=0d0
     636         1188 :          do ipert1=1, natom
     637         1188 :            test=test+d2cart(1,idir1,ipert1,idir2,ipert2)
     638              :          end do
     639          528 :          write(std_out,'(i3,i3,i3,i3,es11.3)') idir1,ipert1,idir2,ipert2,test
     640              :        end do
     641              :      end do
     642              :    end do
     643              : 
     644           22 :    write(msg,'(a,a)')' asrprs: done with asrflag 2', ch10
     645           22 :    call wrtout(std_out,msg)
     646              : 
     647              :  end if !ends asrflag=2
     648              : 
     649           24 :  ABI_FREE(d2vecr)
     650           24 :  ABI_FREE(d2vecc)
     651           24 :  ABI_FREE(d2cartold)
     652              : 
     653           24 : end subroutine asrprs
     654              : !!***
     655              : 
     656              : !----------------------------------------------------------------------
     657              : 
     658              : !!****f* m_dynmat/cart29
     659              : !! NAME
     660              : !! cart29
     661              : !!
     662              : !!
     663              : !! FUNCTION
     664              : !! Transform a second-derivative matrix from reduced
     665              : !! coordinates to cartesian coordinates, and also
     666              : !! 1) add the ionic part of the effective charges,
     667              : !! 2) normalize the electronic dielectric tensor, and
     668              : !!    add the vacuum polarisation
     669              : !!
     670              : !! INPUTS
     671              : !!  blkflg(3,mpert,3,mpert,nblok)=
     672              : !!   ( 1 if the element of the dynamical matrix has been calculated ;
     673              : !!     0 otherwise )
     674              : !!  blkval(2,3,mpert,3,mpert,nblok)=DDB values
     675              : !!  gprimd(3,3)=basis vector in the reciprocal space
     676              : !!  iblok=number of the blok that will be transformed
     677              : !!  mpert =maximum number of ipert
     678              : !!  natom=number of atom
     679              : !!  nblok=number of blocks (dimension of blkflg and blkval)
     680              : !!  ntypat=number of atom types
     681              : !!  rprimd(3,3)=basis vector in the real space
     682              : !!  typat(natom)=integer label of each type of atom (1,2,...)
     683              : !!  ucvol=unit cell volume
     684              : !!  zion(ntypat)=charge corresponding to the atom type
     685              : !!
     686              : !! OUTPUT
     687              : !!  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
     688              : !!  2DTE matrix has been calculated correctly ; 0 otherwise )
     689              : !!  d2cart(2,3,mpert,3,mpert)=
     690              : !!    dynamical matrix, effective charges, dielectric tensor,....
     691              : !!    all in cartesian coordinates
     692              : !!
     693              : !! SOURCE
     694              : 
     695         2315 : subroutine cart29(blkflg,blkval,carflg,d2cart,&
     696         2315 : & gprimd,iblok,mpert,natom,nblok,ntypat,rprimd,typat,ucvol,zion)
     697              : 
     698              : !Arguments -------------------------------
     699              : !scalars
     700              :  integer,intent(in) :: iblok,mpert,natom,nblok,ntypat
     701              :  real(dp),intent(in) :: ucvol
     702              : !arrays
     703              :  integer,intent(in) :: blkflg(3,mpert,3,mpert,nblok),typat(natom)
     704              :  integer,intent(out) :: carflg(3,mpert,3,mpert)
     705              :  real(dp),intent(in) :: blkval(2,3,mpert,3,mpert,nblok),gprimd(3,3),rprimd(3,3)
     706              :  real(dp),intent(in) :: zion(ntypat)
     707              :  real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert)
     708              : 
     709              : !Local variables -------------------------
     710              : !scalars
     711              :  integer :: idir1,idir2,ii,ipert1,ipert2
     712              : !arrays
     713              :  integer :: flg1(3),flg2(3)
     714         4630 :  integer :: mflg(3,mpert,3,mpert)
     715              :  real(dp) :: vec1(3),vec2(3)
     716              : ! *********************************************************************
     717              : 
     718              : !First, copy the data blok in place.
     719     21429833 :  d2cart(:,:,:,:,:)=blkval(:,:,:,:,:,iblok)
     720              : 
     721              : !Cartesian coordinates transformation (in two steps)
     722              : !First step
     723        40862 :  do ipert1=1,mpert
     724       749973 :    do ipert2=1,mpert
     725      2165880 :      do ii=1,2
     726      6381999 :        do idir1=1,3
     727     17018664 :          do idir2=1,3
     728     12763998 :            vec1(idir2)=d2cart(ii,idir1,ipert1,idir2,ipert2)
     729              : !          Note here blkflg
     730     17018664 :            flg1(idir2)=blkflg(idir1,ipert1,idir2,ipert2,iblok)
     731              :          end do
     732      4254666 :          call cart39(flg1,flg2,gprimd,ipert2,natom,rprimd,vec1,vec2)
     733     18436886 :          do idir2=1,3
     734     12763998 :            d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2)
     735              : !          And here carflg
     736     17018664 :            carflg(idir1,ipert1,idir2,ipert2)=flg2(idir2)
     737              :          end do
     738              :        end do
     739              :      end do
     740              :    end do
     741              :  end do
     742              : 
     743              : !Second step
     744        40862 :  do ipert1=1,mpert
     745       749973 :    do ipert2=1,mpert
     746      2165880 :      do ii=1,2
     747      6381999 :        do idir2=1,3
     748     17018664 :          do idir1=1,3
     749     12763998 :            vec1(idir1)=d2cart(ii,idir1,ipert1,idir2,ipert2)
     750              : !          Note here carflg
     751     17018664 :            flg1(idir1)=carflg(idir1,ipert1,idir2,ipert2)
     752              :          end do
     753      4254666 :          call cart39(flg1,flg2,gprimd,ipert1,natom,rprimd,vec1,vec2)
     754     18436886 :          do idir1=1,3
     755     12763998 :            d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1)
     756              : !          And here carflg again
     757     17018664 :            carflg(idir1,ipert1,idir2,ipert2)=flg2(idir1)
     758              :          end do
     759              :        end do
     760              :      end do
     761              :    end do
     762              :  end do
     763              : 
     764              : !For the dielectric tensor, takes into account the volume
     765              : !of the unit cell, and add the unit matrix (polarization of the vacuum)
     766         9260 :  do idir1=1,3
     767        30095 :    do idir2=1,3
     768        69450 :      do ii=1,2
     769              :        d2cart(ii,idir1,natom+2,idir2,natom+2)=&
     770        62505 : &       -four_pi/ucvol*d2cart(ii,idir1,natom+2,idir2,natom+2)
     771              :      end do
     772              :    end do
     773              :  end do
     774              : 
     775         9260 :  do idir1=1,3
     776              :    d2cart(1,idir1,natom+2,idir1,natom+2)=&
     777         9260 : &   1.0_dp+d2cart(1,idir1,natom+2,idir1,natom+2)
     778              :  end do
     779              : 
     780              : !Add the ionic charges to delta z to get the effective charges
     781        10172 :  do ipert1=1,natom
     782        33743 :    do idir1=1,3
     783              :      d2cart(1,idir1,ipert1,idir1,natom+2)=&
     784        31428 : &     zion(typat(ipert1))+d2cart(1,idir1,ipert1,idir1,natom+2)
     785              :    end do
     786              :  end do
     787        10172 :  do ipert2=1,natom
     788        33743 :    do idir2=1,3
     789              :      d2cart(1,idir2,natom+2,idir2,ipert2)=&
     790        31428 : &     zion(typat(ipert2))+d2cart(1,idir2,natom+2,idir2,ipert2)
     791              :    end do
     792              :  end do
     793              : 
     794              : !For the piezoelectric tensor, takes into account the volume of the unit cell
     795         6945 :  do ipert2=natom+3,natom+4
     796        20835 :    do idir1=1,3
     797        60190 :      do idir2=1,3
     798       138900 :        do ii=1,2
     799              :          d2cart(ii,idir1,natom+2,idir2,ipert2)=&
     800        83340 : &         (1.0_dp/ucvol)*d2cart(ii,idir1,natom+2,idir2,ipert2)
     801              :          d2cart(ii,idir2,ipert2,idir1,natom+2)=&
     802       125010 : &         (1.0_dp/ucvol)*d2cart(ii,idir2,ipert2,idir1,natom+2)
     803              :        end do
     804              :      end do
     805              :    end do
     806              :  end do
     807              : 
     808              : !MRoyo: For magnetic Zeeman perturbations, apply a negative sign to get induced magnetic moments.
     809              : !Macroscopic Zeeman
     810      8665835 :  mflg= 0
     811         2315 :  ipert1=natom+5
     812         9260 :  do idir1=1,3
     813        74501 :    do ipert2= 1, natom+6 !exclude local Zeemans, to be done below
     814       267909 :      do idir2=1,3
     815       195723 :        if (mflg(idir1,ipert1,idir2,ipert2)==0) then
     816       566334 :          do ii=1,2
     817              :            d2cart(ii,idir1,ipert1,idir2,ipert2)=&
     818       377556 : &          -one*d2cart(ii,idir1,ipert1,idir2,ipert2)
     819       566334 :            mflg(idir1,ipert1,idir2,ipert2)=1
     820              :          end do
     821              :        end if
     822       260964 :        if (mflg(idir2,ipert2,idir1,ipert1)==0) then
     823       545499 :          do ii=1,2
     824              :            d2cart(ii,idir2,ipert2,idir1,ipert1)=&
     825       363666 : &          -one*d2cart(ii,idir2,ipert2,idir1,ipert1)
     826       545499 :            mflg(idir2,ipert2,idir1,ipert1)=1
     827              :          end do
     828              :        end if
     829              :      end do
     830              :    end do
     831              :  end do
     832              : 
     833              : !Local Zeemans
     834         2315 :  if (mpert>natom+MPERT_MAX) then
     835         8854 :    do ipert1= natom+12,2*natom+11
     836        29785 :      do idir1=1,3
     837       466319 :        do ipert2= 1, mpert
     838      1774575 :          do idir2=1,3
     839      1315233 :            if (mflg(idir1,ipert1,idir2,ipert2)==0) then
     840      3508713 :              do ii=1,2
     841              :                d2cart(ii,idir1,ipert1,idir2,ipert2)=&
     842      2339142 : &              -one*d2cart(ii,idir1,ipert1,idir2,ipert2)
     843      3508713 :                mflg(idir1,ipert1,idir2,ipert2)=1
     844              :              end do
     845              :            end if
     846      1753644 :            if (mflg(idir2,ipert2,idir1,ipert1)==0) then
     847      3445920 :              do ii=1,2
     848              :                d2cart(ii,idir2,ipert2,idir1,ipert1)=&
     849      2297280 : &              -one*d2cart(ii,idir2,ipert2,idir1,ipert1)
     850      3445920 :                mflg(idir2,ipert2,idir1,ipert1)=1
     851              :              end do
     852              :            end if
     853              :          end do
     854              :        end do
     855              :      end do
     856              :    end do
     857              :  end if
     858              : 
     859              :  !For magnetoelectric and magnetic susceptibility apply a 1/ucvol factor
     860         2315 :  ipert1= natom + 2
     861         2315 :  ipert2= natom + 5
     862         9260 :  do idir1= 1, 3
     863        30095 :    do idir2= 1, 3
     864        69450 :      do ii=1,2
     865              :        d2cart(ii,idir1,ipert1,idir2,ipert2)=&
     866        41670 : &      d2cart(ii,idir1,ipert1,idir2,ipert2)/ucvol
     867              :        d2cart(ii,idir2,ipert2,idir1,ipert1)=&
     868        41670 : &      d2cart(ii,idir2,ipert2,idir1,ipert1)/ucvol
     869              :        d2cart(ii,idir1,ipert2,idir2,ipert2)=&
     870        62505 : &      d2cart(ii,idir1,ipert2,idir2,ipert2)/ucvol
     871              :      end do
     872              :    end do
     873              :  end do
     874              : 
     875         2315 : end subroutine cart29
     876              : !!***
     877              : 
     878              : !----------------------------------------------------------------------
     879              : 
     880              : !!****f* m_dynmat/cart39
     881              : !! NAME
     882              : !! cart39
     883              : !!
     884              : !!
     885              : !! FUNCTION
     886              : !! Transform a vector from reduced coordinates to cartesian coordinates,
     887              : !! taking into account the perturbation from which it was derived,
     888              : !! and also check the existence of the new values.
     889              : !!
     890              : !! INPUTS
     891              : !!  flg1(3)=tell if information of each component of vec1 is valid
     892              : !!  gprimd(3,3)=basis vector in the reciprocal space
     893              : !!  ipert=number of the perturbation
     894              : !!  natom=number of atom
     895              : !!  rprimd(3,3)=basis vector in the real space
     896              : !!  vec1(3)=input vector, in reduced coordinates
     897              : !!
     898              : !! OUTPUT
     899              : !!  flg2(3)=tell if information of each component of vec2 is valid
     900              : !!  vec2(3)=output vector, in cartesian coordinates
     901              : !!
     902              : !! SOURCE
     903              : 
     904     19173000 : subroutine cart39(flg1,flg2,gprimd,ipert,natom,rprimd,vec1,vec2)
     905              : 
     906              : !Arguments -------------------------------
     907              : !scalars
     908              :  integer,intent(in) :: ipert,natom
     909              : !arrays
     910              :  integer,intent(in) :: flg1(3)
     911              :  integer,intent(out) :: flg2(3)
     912              :  real(dp),intent(in) :: gprimd(3,3),rprimd(3,3),vec1(3)
     913              :  real(dp),intent(out) :: vec2(3)
     914              : 
     915              : !Local variables -------------------------
     916              : !scalars
     917              :  integer :: idir,ii
     918              : ! *********************************************************************
     919              : 
     920              : !Treat phonon-type perturbation
     921     19173000 :  if(ipert>=1.and.ipert<=natom)then
     922              : 
     923     20667576 :    do idir=1,3
     924     15500682 :      vec2(idir)=zero
     925     15500682 :      flg2(idir)=1
     926     62002728 :      do ii=1,3
     927     62002728 :        if(abs(gprimd(idir,ii))>1.0d-10)then
     928     22552956 :          if(flg1(ii)==1)then
     929      8150317 :            vec2(idir)=vec2(idir)+gprimd(idir,ii)*vec1(ii)
     930              :          else
     931     14402639 :            flg2(idir)=0
     932              :          end if
     933              :        end if
     934              :      end do
     935     20667576 :      if(flg2(idir)==0)vec2(idir)=zero
     936              :    end do
     937              : 
     938              : !  Treat electric field and qvec perturbations
     939     14006106 :  else if(ipert==natom+2.or.ipert==natom+8) then
     940              : !  OCL SCALAR
     941      7958304 :    do idir=1,3
     942      5968728 :      vec2(idir)=zero
     943      5968728 :      flg2(idir)=1
     944              : !    OCL SCALAR
     945     23874912 :      do ii=1,3
     946     23874912 :        if(abs(rprimd(idir,ii))>1.0d-10)then
     947      8750976 :          if(flg1(ii)==1)then
     948      1547889 :            vec2(idir)=vec2(idir)+rprimd(idir,ii)*vec1(ii)/two_pi
     949              :          else
     950      7203087 :            flg2(idir)=0
     951              :          end if
     952              :        end if
     953              :      end do
     954      7958304 :      if(flg2(idir)==0)vec2(idir)=zero
     955              :    end do
     956              : 
     957              : !  Treat other perturbations
     958              :  else
     959     48066120 :    do idir=1,3
     960     36049590 :      vec2(idir)=vec1(idir)
     961     48066120 :      flg2(idir)=flg1(idir)
     962              :    end do
     963              :  end if
     964              : 
     965     19173000 : end subroutine cart39
     966              : !!***
     967              : 
     968              : !----------------------------------------------------------------------
     969              : 
     970              : !!****f* m_dynmat/d2cart_to_red
     971              : !! NAME
     972              : !! d2cart_to_red
     973              : !!
     974              : !!
     975              : !! FUNCTION
     976              : !! Transform a second-derivative matrix from cartesian
     977              : !! coordinates to reduced coordinate. Also,
     978              : !! 1) remove the ionic part of the effective charges,
     979              : !! 2) remove the vacuum polarisation from the dielectric tensor
     980              : !!    and scale it with the unit cell volume
     981              : !! In short, does the inverse operation of cart29.
     982              : !!
     983              : !! INPUTS
     984              : !!  d2cart(2,3,mpert,3,mpert)=
     985              : !!    second-derivative matrix in cartesian coordinates
     986              : !!  gprimd(3,3)=basis vector in the reciprocal space
     987              : !!  rprimd(3,3)=basis vector in the real space
     988              : !!  mpert =maximum number of ipert
     989              : !!  natom=number of atom
     990              : !!
     991              : !! OUTPUT
     992              : !!  d2red(2,3,mpert,3,mpert)=
     993              : !!    second-derivative matrix in reduced coordinates
     994              : !!
     995              : !! SOURCE
     996              : 
     997         2355 : subroutine d2cart_to_red(d2cart, d2red, gprimd, rprimd, mpert, natom, &
     998         2355 : &                        ntypat,typat,ucvol,zion)
     999              : 
    1000              : !Arguments -------------------------------
    1001              : !scalars
    1002              :  integer,intent(in) :: mpert,natom,ntypat
    1003              :  real(dp),intent(in) :: ucvol
    1004              : !arrays
    1005              :  integer,intent(in) :: typat(natom)
    1006              :  real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
    1007              :  real(dp),intent(out) :: d2red(2,3,mpert,3,mpert)
    1008              :  real(dp),intent(in) :: gprimd(3,3),rprimd(3,3)
    1009              :  real(dp),intent(in) :: zion(ntypat)
    1010              : 
    1011              : !Local variables -------------------------
    1012              : !scalars
    1013              :  integer :: idir1,idir2,ii,ipert1,ipert2
    1014              :  real(dp) :: fac
    1015              : !arrays
    1016              :  integer :: flg1(3),flg2(3)
    1017              :  real(dp) :: vec1(3),vec2(3)
    1018              :  real(dp) :: gprimdt(3,3),rprimdt(3,3)
    1019              : ! *********************************************************************
    1020              : 
    1021         9420 :  flg1 = one
    1022         9420 :  flg2 = one
    1023              : 
    1024      7356547 :  d2red = d2cart
    1025              : 
    1026              : !Remove the ionic charges to z to get the change in effective charges
    1027        10247 :  do ipert1=1,natom
    1028        33923 :    do idir1=1,3
    1029              :      d2red(1,idir1,ipert1,idir1,natom+2)=&
    1030        31568 : &     d2red(1,idir1,ipert1,idir1,natom+2) - zion(typat(ipert1))
    1031              :    end do
    1032              :  end do
    1033        10247 :  do ipert2=1,natom
    1034        33923 :    do idir2=1,3
    1035              :      d2red(1,idir2,natom+2,idir2,ipert2)=&
    1036        31568 : &     d2red(1,idir2,natom+2,idir2,ipert2) - zion(typat(ipert2))
    1037              :    end do
    1038              :  end do
    1039              : 
    1040              :  ! Remove the vacuum polarizability from the dielectric tensor
    1041         9420 :  do idir1=1,3
    1042              :    d2red(1,idir1,natom+2,idir1,natom+2)=&
    1043         9420 : &   d2red(1,idir1,natom+2,idir1,natom+2) - 1.0_dp
    1044              :  end do
    1045              : 
    1046              : ! Scale the dielectric tensor with the volue of the unit cell
    1047         9420 :  do idir1=1,3
    1048        30615 :    do idir2=1,3
    1049        70650 :      do ii=1,2
    1050              :        d2red(ii,idir1,natom+2,idir2,natom+2)=&
    1051        63585 : &       - (ucvol / four_pi) * d2red(ii,idir1,natom+2,idir2,natom+2)
    1052              :      end do
    1053              :    end do
    1054              :  end do
    1055              : 
    1056              : !For the piezoelectric tensor, takes into account the volume of the unit cell
    1057         7065 :  do ipert2=natom+3,natom+4
    1058        21195 :    do idir1=1,3
    1059        61230 :      do idir2=1,3
    1060       141300 :        do ii=1,2
    1061              :          d2red(ii,idir1,natom+2,idir2,ipert2)=&
    1062        84780 : &         (ucvol)*d2red(ii,idir1,natom+2,idir2,ipert2)
    1063              :          d2red(ii,idir2,ipert2,idir1,natom+2)=&
    1064       127170 : &         (ucvol)*d2red(ii,idir2,ipert2,idir1,natom+2)
    1065              :        end do
    1066              :      end do
    1067              :    end do
    1068              :  end do
    1069              : 
    1070              : ! Reduced coordinates transformation (in two steps)
    1071              : ! Note that rprimd and gprimd are swapped, compared to what cart39 expects
    1072              : ! A factor of (2pi) ** 2 is added to transform the electric field perturbations
    1073              : 
    1074        30615 :  rprimdt = transpose(rprimd)
    1075        30615 :  gprimdt = transpose(gprimd)
    1076              : 
    1077              : !First step
    1078        24433 :  do ipert1=1,mpert
    1079        22078 :    fac = one; if (ipert1==natom+2) fac = two_pi ** 2
    1080              : 
    1081       266629 :    do ipert2=1,mpert
    1082       748666 :      do ii=1,2
    1083      2179764 :        do idir1=1,3
    1084      5812704 :          do idir2=1,3
    1085      5812704 :            vec1(idir2)=d2red(ii,idir1,ipert1,idir2,ipert2)
    1086              :          end do
    1087              :          ! Transform vector from cartesian to reduced coordinates
    1088      1453176 :          call cart39(flg1,flg2,rprimdt,ipert1,natom,gprimdt,vec1,vec2)
    1089      6297096 :          do idir2=1,3
    1090      5812704 :            d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2) * fac
    1091              :          end do
    1092              :        end do
    1093              :      end do
    1094              :    end do
    1095              :  end do
    1096              : 
    1097              : !Second step
    1098        24433 :  do ipert1=1,mpert
    1099       266629 :    do ipert2=1,mpert
    1100       242196 :      fac = one; if (ipert2==natom+2) fac = two_pi ** 2
    1101              : 
    1102       748666 :      do ii=1,2
    1103      2179764 :        do idir2=1,3
    1104      5812704 :          do idir1=1,3
    1105      5812704 :            vec1(idir1)=d2red(ii,idir1,ipert1,idir2,ipert2)
    1106              :          end do
    1107              :          ! Transform vector from cartesian to reduced coordinates
    1108      1453176 :          call cart39(flg1,flg2,rprimdt,ipert2,natom,gprimdt,vec1,vec2)
    1109      6297096 :          do idir1=1,3
    1110      5812704 :            d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1) * fac
    1111              :          end do
    1112              :        end do
    1113              :      end do
    1114              :    end do
    1115              :  end do
    1116              : 
    1117              : 
    1118         2355 : end subroutine d2cart_to_red
    1119              : !!***
    1120              : 
    1121              : !----------------------------------------------------------------------
    1122              : 
    1123              : !!****f* m_dynmat/chkph3
    1124              : !! NAME
    1125              : !! chkph3
    1126              : !!
    1127              : !! FUNCTION
    1128              : !! Check the completeness of the dynamical matrix and eventually send a warning
    1129              : !!
    1130              : !! INPUTS
    1131              : !!  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
    1132              : !!  2DTE matrix has been calculated correctly ; 0 otherwise )
    1133              : !!  idir = direction of the eventual electric field
    1134              : !!  mpert =maximum number of ipert
    1135              : !!  natom=number of atoms in unit cell
    1136              : !!
    1137              : !! OUTPUT
    1138              : !!  eventually send a warning message
    1139              : !!
    1140              : !! SOURCE
    1141              : 
    1142          601 : subroutine chkph3(carflg,idir,mpert,natom)
    1143              : 
    1144              : !Arguments -------------------------------
    1145              : !scalars
    1146              :  integer,intent(in) :: idir,mpert,natom
    1147              : !arrays
    1148              :  integer,intent(in) :: carflg(3,mpert,3,mpert)
    1149              : 
    1150              : !Local variables -------------------------
    1151              : !scalars
    1152              :  integer :: idir1,idir2,ipert1,ipert2,send
    1153              :  character(len=500) :: msg
    1154              : ! *********************************************************************
    1155              : 
    1156          601 :  send=0
    1157              : 
    1158              : !Check the elements of the analytical part of the dynamical matrix
    1159         1852 :  do ipert2=1,natom
    1160         5605 :    do idir2=1,3
    1161        14967 :      do ipert1=1,natom
    1162        43605 :        do idir1=1,3
    1163        39852 :          if(carflg(idir1,ipert1,idir2,ipert2)==0)then
    1164         8501 :            send=1
    1165              :          end if
    1166              :        end do
    1167              :      end do
    1168              :    end do
    1169              :  end do
    1170              : 
    1171              : !If some electric field is present
    1172          601 :  if(idir/=0)then
    1173              : 
    1174              : !  Check the dielectric constant
    1175          219 :    if(carflg(idir,natom+2,idir,natom+2)==0)then
    1176            0 :      send=1
    1177              :    end if
    1178              : 
    1179              : !  Check the effective charges
    1180          707 :    do ipert1=1,natom
    1181         2171 :      do idir1=1,3
    1182         1952 :        if(carflg(idir1,ipert1,idir,natom+2)==0)then
    1183           39 :          send=1
    1184              :        end if
    1185              :      end do
    1186              :    end do
    1187              : 
    1188              :  end if
    1189              : 
    1190              :  ! If needed, send the message
    1191          601 :  if(send==1)then
    1192              :    write(msg, '(a,a,a,a)' )&
    1193           75 : &    ' chkph3 : WARNING -',ch10,&
    1194          150 : &    '  Dynamical matrix incomplete, phonon frequencies may be wrong, see the log file for more explanations.'
    1195           75 :    call wrtout(ab_out,msg)
    1196              :    write(msg, '(11a)' )&
    1197           75 : &   ' chkph3 : WARNING -',ch10,&
    1198           75 : &   '  Dynamical matrix incomplete, phonon frequencies may be wrong.',ch10,&
    1199           75 : &   '  Likely due to a list of perturbations, as defined by rfatpol and rfdir, that does not include',ch10,&
    1200           75 : &   '  all displacements of all atoms and (if non-metallic material) electric field type perturbation.',ch10,&
    1201           75 : &   '  Then, the dynamical matrix includes zeroes when the matrix element is not computed.',ch10,&
    1202          150 : &   '  This is allowed for testing purposes. But the phonon frequencies may be wrong.'
    1203           75 :    call wrtout(std_out,msg)
    1204              :    write(msg, '(9a)' )&
    1205           75 : &  '  If there are symmetries, perhaps these matrix elements are zero by symmetry anyhow, and phonon frequencies might be right.',ch10,&
    1206           75 : &  '  Please check the input variables rfatpol and rfdir, to determine whether abinit is doing what you intend it to do.',ch10,&
    1207           75 : &  '  Note that ANADDB is able to detect whether the symmetries allow one to reconstruct the full dynamical matrix from',ch10,&
    1208           75 : &  '  an incomplete one. In this case, passing to ANADDB the delivered _DDB file might confirm (or not) that',ch10,&
    1209          150 : &  '  phonon frequencies are right.'
    1210           75 :    call wrtout(std_out,msg)
    1211              :  end if
    1212              : 
    1213          601 : end subroutine chkph3
    1214              : !!***
    1215              : 
    1216              : !----------------------------------------------------------------------
    1217              : 
    1218              : !!****f* m_dynmat/chneu9
    1219              : !! NAME
    1220              : !! chneu9
    1221              : !!
    1222              : !! FUNCTION
    1223              : !! Imposition of the charge neutrality sum rule on the Effective charges
    1224              : !! and suppress the imaginary part of the dynamical matrix
    1225              : !!
    1226              : !! INPUTS
    1227              : !!  chneut=(0 => no ASR, 1 => equal repartition, 2 => weighted repartition )
    1228              : !!  mpert =maximum number of ipert
    1229              : !!  natom=number of atom
    1230              : !!  ntypat=number of types of atoms in unit cell
    1231              : !!  selectz=selection of some parts of the effective charge tensor attached to one atom.
    1232              : !!    (0=> no selection, 1=> trace only, 2=> symmetric part only)
    1233              : !!  typat(natom)=type of the atom
    1234              : !!  zion(ntypat)=atomic charge for every type of atom
    1235              : !!
    1236              : !! SIDE EFFECTS
    1237              : !!  Input/Output
    1238              : !!  d2cart=matrix of second derivatives of total energy, in cartesian
    1239              : !!       coordinates
    1240              : !!
    1241              : !! SOURCE
    1242              : 
    1243          194 : subroutine chneu9(chneut,d2cart,mpert,natom,ntypat,selectz,typat,zion)
    1244              : 
    1245              : !Arguments -------------------------------
    1246              : !scalars
    1247              :  integer,intent(in) :: chneut,mpert,natom,ntypat,selectz
    1248              : !arrays
    1249              :  integer,intent(in) :: typat(natom)
    1250              :  real(dp),intent(in) :: zion(ntypat)
    1251              :  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
    1252              : 
    1253              : !Local variables -------------------------
    1254              : !scalars
    1255              :  integer :: idir1,idir2,ii,ipert1,ipert2
    1256              :  character(len=500) :: msg
    1257              : !arrays
    1258              :  real(dp) :: sumwght(2)
    1259          194 :  real(dp),allocatable :: wghtat(:)
    1260              : ! *********************************************************************
    1261              : 
    1262          582 :  ABI_MALLOC(wghtat,(natom))
    1263              : 
    1264              : !In case of acoustic sum rule imposition, compute the weights on each atom.
    1265          194 :  if (chneut==1)then
    1266              : 
    1267              : !  The weight is the same for all atom
    1268          659 :    do ipert1=1,natom
    1269          659 :      wghtat(ipert1)=1./natom
    1270              :    end do
    1271              : 
    1272           22 :  else if (chneut==2) then
    1273              : 
    1274              : !  The weight is proportional to the diagonal electronic screening charge of the atom
    1275           11 :    sumwght(1)=zero
    1276           66 :    do ipert1=1,natom
    1277           55 :      wghtat(ipert1)=zero
    1278          220 :      do idir1=1,3
    1279              :        wghtat(ipert1)=wghtat(ipert1)+&
    1280              : &       d2cart(1,idir1,ipert1,idir1,natom+2)+&
    1281          220 : &       d2cart(1,idir1,natom+2,idir1,ipert1)-2*zion(typat(ipert1))
    1282              :      end do
    1283           66 :      sumwght(1)=sumwght(1)+wghtat(ipert1)
    1284              :    end do
    1285              : 
    1286              : !  Normalize the weights to unity
    1287           66 :    wghtat(1:natom) = wghtat(1:natom) / sumwght(1)
    1288              :  end if
    1289              : 
    1290              : !Calculation of the violation of the charge neutrality
    1291              : !and imposition of the charge neutrality condition
    1292          194 :  if (chneut/=0)then
    1293              :    write(msg, '(a,a,a,a,a,a,a)' )&
    1294          183 :     ' The violation of the charge neutrality conditions',ch10,&
    1295          183 :     ' by the effective charges is as follows :',ch10,&
    1296          183 :     '    atom        electric field',ch10,&
    1297          366 :     ' displacement     direction   '
    1298          183 :    call wrtout(ab_out,msg)
    1299          732 :    do idir1=1,3
    1300         2379 :      do idir2=1,3
    1301         4941 :        do ii=1,2
    1302         3294 :          sumwght(ii)=zero
    1303        13050 :          do ipert1=1,natom
    1304        13050 :            sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir2,natom+2)
    1305              :          end do
    1306        14697 :          do ipert1=1,natom
    1307              :            d2cart(ii,idir1,ipert1,idir2,natom+2)=&
    1308        13050 :            d2cart(ii,idir1,ipert1,idir2,natom+2)-sumwght(ii)*wghtat(ipert1)
    1309              :          end do
    1310              :        end do
    1311         1647 :        write(msg, '(i8,i16,2f16.6)' ) idir1,idir2,sumwght(1),sumwght(2)
    1312         2196 :        call wrtout(ab_out,msg)
    1313              :      end do
    1314              :    end do
    1315          183 :    write(msg, '(a)' )' '
    1316          183 :    call wrtout(ab_out,msg)
    1317              : 
    1318              : !  The same for the symmetrical part
    1319          732 :    do idir1=1,3
    1320         2379 :      do idir2=1,3
    1321         5490 :        do ii=1,2
    1322         3294 :          sumwght(ii)=zero
    1323        13050 :          do ipert2=1,natom
    1324        13050 :            sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir2,ipert2)
    1325              :          end do
    1326        14697 :          do ipert2=1,natom
    1327              :            d2cart(ii,idir1,natom+2,idir2,ipert2)=&
    1328        13050 :            d2cart(ii,idir1,natom+2,idir2,ipert2)-sumwght(ii)*wghtat(ipert2)
    1329              :          end do
    1330              :        end do
    1331              :      end do
    1332              :    end do
    1333              :  end if
    1334              : 
    1335              : !Selection of the trace of the effective charge tensor attached to each atom
    1336          194 :  if(selectz==1)then
    1337            0 :    do ipert1=1,natom
    1338            0 :      do ii=1,2
    1339            0 :        sumwght(ii)=zero
    1340            0 :        do idir1=1,3
    1341            0 :          sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir1,natom+2)
    1342              :        end do
    1343            0 :        do idir1=1,3
    1344            0 :          do idir2=1,3
    1345            0 :            d2cart(ii,idir1,ipert1,idir2,natom+2)=zero
    1346              :          end do
    1347              :        end do
    1348            0 :        do idir1=1,3
    1349            0 :          d2cart(ii,idir1,ipert1,idir1,natom+2)=sumwght(ii)/3.0_dp
    1350              :        end do
    1351              :      end do
    1352              :    end do
    1353              : !  Do the same for the symmetrical part of d2cart
    1354            0 :    do ipert2=1,natom
    1355            0 :      do ii=1,2
    1356            0 :        sumwght(ii)=zero
    1357            0 :        do idir1=1,3
    1358            0 :          sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir1,ipert2)
    1359              :        end do
    1360            0 :        do idir1=1,3
    1361            0 :          do idir2=1,3
    1362            0 :            d2cart(ii,idir1,natom+2,idir2,ipert2)=zero
    1363              :          end do
    1364              :        end do
    1365            0 :        do idir1=1,3
    1366            0 :          d2cart(ii,idir1,natom+2,idir1,ipert2)=sumwght(ii)/3.0_dp
    1367              :        end do
    1368              :      end do
    1369              :    end do
    1370              :  end if
    1371              : 
    1372              : !Selection of the symmetric part of the effective charge tensor attached to each atom
    1373          194 :  if(selectz==2)then
    1374            0 :    do ipert1=1,natom
    1375            0 :      do ii=1,2
    1376            0 :        do idir1=1,3
    1377            0 :          do idir2=1,3
    1378              :            sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
    1379            0 : &           +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
    1380            0 :            d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
    1381            0 :            d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
    1382              :          end do
    1383              :        end do
    1384              :      end do
    1385              :    end do
    1386              : !  Do the same for the symmetrical part of d2cart
    1387            0 :    do ipert1=1,natom
    1388            0 :      do ii=1,2
    1389            0 :        do idir1=1,3
    1390            0 :          do idir2=1,3
    1391              :            sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
    1392            0 : &           +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
    1393            0 :            d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
    1394            0 :            d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
    1395              :          end do
    1396              :        end do
    1397              :      end do
    1398              :    end do
    1399              :  end if
    1400              : 
    1401              : !Write the effective charge tensor
    1402              :  write(msg, '(a,a,a,a,a,a,a)' )&
    1403          194 :    ' Effective charge tensors after ',ch10,&
    1404          194 :    ' imposition of the charge neutrality (if requested by user),',ch10,&
    1405          194 :    ' and eventual restriction to some part :',ch10,&
    1406          388 :   '   atom    displacement  '
    1407          194 :  call wrtout(ab_out,msg)
    1408              : 
    1409          770 :  do ipert1=1,natom
    1410         2498 :    do idir1=1,3
    1411         6912 :      write(msg, '(2i10,3es16.6)' )ipert1,idir1,(d2cart(1,idir1,ipert1,idir2,natom+2),idir2=1,3)
    1412         2304 :      call wrtout(ab_out,msg)
    1413              :    end do
    1414              :  end do
    1415              : 
    1416              : !Zero the imaginary part of the dynamical matrix
    1417          194 :  write(msg, '(a)' )' Now, the imaginary part of the dynamical matrix is zeroed '
    1418          194 :  call wrtout(ab_out,msg)
    1419          194 :  call wrtout(std_out,msg)
    1420              : 
    1421        32474 :  d2cart(2, 1:3, 1:natom, 1:3, 1:natom) = zero
    1422              : 
    1423          194 :  ABI_FREE(wghtat)
    1424              : 
    1425          194 : end subroutine chneu9
    1426              : !!***
    1427              : 
    1428              : !----------------------------------------------------------------------
    1429              : 
    1430              : !!****f* m_dynmat/d2sym3
    1431              : !! NAME
    1432              : !! d2sym3
    1433              : !!
    1434              : !! FUNCTION
    1435              : !! Given a set of calculated elements of the 2DTE matrix d2,
    1436              : !! build (nearly) all the other matrix elements that can be build using symmetries.
    1437              : !!
    1438              : !! 1. Perform first some completion by symmetrisation (exchange)
    1439              : !!    over the two defining perturbations
    1440              : !! 2. For each element, uses every symmetry, and build the element, in case
    1441              : !!    EITHER all the needed elements are available,
    1442              : !!    OR the only missing is itself
    1443              : !!    OR the perturbation is the electric field, in a diamond
    1444              : !!    symmetry (the last case was coded rather dirty)
    1445              : !!
    1446              : !! INPUTS
    1447              : !!  indsym(4,nsym,natom)=indirect indexing array : for each
    1448              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    1449              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    1450              : !!   translations which must be subtracted after the transformation to get back
    1451              : !!   to the original unit cell.
    1452              : !!  mpert =maximum number of ipert
    1453              : !!  natom= number of atoms
    1454              : !!  nsym=number of space group symmetries
    1455              : !!  qpt(3)=wavevector of the perturbation
    1456              : !!  symq(4,2,nsym)= (integer) three first numbers define the G vector ;
    1457              : !!   fourth number is zero if the q-vector is not preserved,
    1458              : !!              is 1 otherwise
    1459              : !!   second index is one without time-reversal symmetry,
    1460              : !!                two with time-reversal symmetry
    1461              : !!  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
    1462              : !!  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
    1463              : !!  timrev=1 if the time-reversal symmetry preserves the wavevector,
    1464              : !!     modulo a reciprocal lattice vector, timrev=0 otherwise
    1465              : !!  zero_by_symm= if 1, set blkflg to 1 for the elements that must be zero by symmetry, and zero them.
    1466              : !!    This has the indirect effect of being able to resymmetrize the whole matrix, thus
    1467              : !!    enforcing better the symmetry for the 2DTE.
    1468              : !!
    1469              : !! SIDE EFFECTS
    1470              : !!  Input/Output
    1471              : !!  d2(2,3,mpert,3,mpert)= matrix of the 2DTE
    1472              : !!  blkflg(3,mpert,3,mpert)= ( 1 if the element of the dynamical
    1473              : !!     matrix has been calculated ; 0 otherwise)
    1474              : !!
    1475              : !! NOTES
    1476              : !!   The complete search would be to have the possibility
    1477              : !!   of a set of missing elements. See notes of July 2, 1994,
    1478              : !!   in the blue notebook 'computer codes'
    1479              : !!   The partial solution adopted here takes into
    1480              : !!   account some mirror symmetries
    1481              : !!   as well as the tetrahedral symmetry of the diamond lattice
    1482              : !!   On 010331, replaced the loops up to mpert by loops up to
    1483              : !!   natom+2, because of a crash bug under Windows. However,
    1484              : !!   the problem lies likely in the use of the indsym array.
    1485              : !!
    1486              : !! SOURCE
    1487              : 
    1488       174682 : subroutine d2sym3(blkflg,d2,indsym,mpert,natom,nsym,qpt,symq,symrec,symrel,timrev,zero_by_symm,eta)
    1489              : 
    1490              : !Arguments -------------------------------
    1491              : !scalars
    1492              :  integer,intent(in) :: mpert,natom,nsym,timrev,zero_by_symm
    1493              : !arrays
    1494              :  integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym)
    1495              :  integer,intent(in),target :: symrec(3,3,nsym),symrel(3,3,nsym)
    1496              :  integer,intent(inout) :: blkflg(3,mpert,3,mpert)
    1497              :  real(dp),intent(in) :: qpt(3)
    1498              :  real(dp),intent(inout) :: d2(2,3,mpert,3,mpert)
    1499              :  real(dp),optional,intent(in) :: eta
    1500              : 
    1501              : !Local variables -------------------------
    1502              : !scalars
    1503              :  logical, parameter :: do_final_sym=.true.
    1504              :  logical :: qzero
    1505              :  integer :: exch12,found,idir1,idir2,idisy1,idisy2,ipert1,ipert2
    1506              :  integer :: ipesy1,ipesy2,isgn,isym,ithree,itirev,nblkflg_is_one,noccur,nsym_used,quit,quit1
    1507              :  real(dp) :: arg1,arg2,im,norm,eta_,re,sumi,sumr,xi,xr
    1508              : !arrays
    1509       174682 :  integer,pointer :: sym1_(:,:,:),sym2_(:,:,:)
    1510       174682 :  real(dp),allocatable :: d2tmp1(:,:,:),d2tmp2(:,:,:),d2work(:,:,:,:,:)
    1511              : ! *********************************************************************
    1512              : 
    1513       174682 :  qzero=(qpt(1)**2+qpt(2)**2+qpt(3)**2<tol16)
    1514              : 
    1515              : !Here look after exchange of 1 and 2 axis,
    1516              : !for electric field in diamond symmetry
    1517       174682 :  exch12=0
    1518       174682 :  if (qzero) then
    1519      1467356 :    do isym=1,nsym
    1520      1466947 :      exch12=1
    1521      1466947 :      if(symrel(1,1,isym)/=0)exch12=0
    1522      1466947 :      if(symrel(1,2,isym)/=1)exch12=0
    1523      1466947 :      if(symrel(1,3,isym)/=0)exch12=0
    1524      1466947 :      if(symrel(2,1,isym)/=1)exch12=0
    1525      1466947 :      if(symrel(2,2,isym)/=0)exch12=0
    1526      1466947 :      if(symrel(2,3,isym)/=0)exch12=0
    1527      1466947 :      if(symrel(3,1,isym)/=0)exch12=0
    1528      1466947 :      if(symrel(3,2,isym)/=0)exch12=0
    1529      1466947 :      if(symrel(3,3,isym)/=1)exch12=0
    1530              : !    if(exch12==1) write(std_out,*)' d2sym3 : found exchange 1 2 =',isym
    1531       390083 :      if(exch12==1)exit
    1532              :    end do
    1533              :  end if
    1534              : 
    1535       174682 :  eta_=zero; if(present(eta)) eta_=eta
    1536              : 
    1537              : !Consider two cases : either time-reversal symmetry
    1538              : !conserves the wavevector, or not
    1539       174682 :  if(timrev==0.and.abs(eta_)<tol8)then
    1540              : 
    1541       530536 :   do ipert1=1,mpert !See notes
    1542              : !   do ipert1=1,min(natom+2,mpert)
    1543      1763503 :      do idir1=1,3
    1544              : 
    1545              : !      Since the matrix is hermitian, the diagonal elements are real
    1546      1232967 :        d2(2,idir1,ipert1,idir1,ipert1)=zero
    1547              : 
    1548      7223125 :       do ipert2=1,mpert !See notes
    1549              : !       do ipert2=1,min(natom+2,mpert)
    1550     23549643 :          do idir2=1,3
    1551              : 
    1552              :            ! FIXME use is_type functions
    1553              : !          If an element exists
    1554     22316676 :            if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
    1555              : 
    1556              : !            Either complete the symmetric missing element
    1557      2028269 :              if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
    1558              : 
    1559         1207 :                d2(1,idir2,ipert2,idir1,ipert1)= d2(1,idir1,ipert1,idir2,ipert2)
    1560         1207 :                d2(2,idir2,ipert2,idir1,ipert1)=-d2(2,idir1,ipert1,idir2,ipert2)
    1561              : 
    1562         1207 :                blkflg(idir2,ipert2,idir1,ipert1)=1
    1563              : 
    1564              : !              Or symmetrize (the matrix is hermitian) in case both exists
    1565              : !              (Note : this opportunity has been disabled for more
    1566              : !              obvious search for bugs in the code )
    1567              : !              else
    1568              : !              sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
    1569              : !              sumi=d2(1,idir2,ipert2,idir1,ipert1)-d2(1,idir1,ipert1,idir2,ipert2)
    1570              : !              d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
    1571              : !              d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
    1572              : !              d2(2,idir2,ipert2,idir1,ipert1)=half*sumi
    1573              : !              d2(2,idir1,ipert1,idir2,ipert2)=-half*sumi
    1574              :              end if
    1575              :            end if
    1576              : 
    1577              :          end do
    1578              :        end do
    1579              : 
    1580              :      end do
    1581              :    end do
    1582              : 
    1583              : !  Here, case with time-reversal symmetry
    1584              :  else
    1585              : 
    1586       233391 :   do ipert1=1,mpert !See notes
    1587              : !   do ipert1=1,min(natom+2,mpert)
    1588       768159 :      do idir1=1,3
    1589      2623184 :       do ipert2=1,mpert !See notes
    1590              : !       do ipert2=1,min(natom+2,mpert)
    1591      8175408 :          do idir2=1,3
    1592      5730480 :            d2(2,idir1,ipert1,idir2,ipert2)=zero
    1593              : 
    1594              : !          If an element exists
    1595      7640640 :            if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
    1596              : 
    1597              : !            Either complete the symmetric missing element
    1598       777582 :              if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
    1599              : 
    1600         7372 :                d2(1,idir2,ipert2,idir1,ipert1)=d2(1,idir1,ipert1,idir2,ipert2)
    1601         7372 :                blkflg(idir2,ipert2,idir1,ipert1)=1
    1602              : 
    1603              : !              Or symmetrize (the matrix is hermitian) in case both exists
    1604              : !              (Note : this opportunity has been disabled for more
    1605              : !              obvious search for bugs in the code )
    1606              : !              else
    1607              : !              sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
    1608              : !              d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
    1609              : !              d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
    1610              :              end if
    1611              : 
    1612              :            end if
    1613              :          end do
    1614              :        end do
    1615              :      end do
    1616              :    end do
    1617              :  end if
    1618              : 
    1619              : !Big Big Loop : symmetrize three times, because
    1620              : !of some cases in which one element is not yet available
    1621              : !at the first pass, and even at the second one !
    1622       698728 :  do ithree=1,3
    1623              : 
    1624              : !  Big loop on all elements
    1625      2466463 :   do ipert1=1,mpert !See notes
    1626              : !   do ipert1=1,min(natom+2,mpert)
    1627              : 
    1628              : !    Select the symmetries according to pertubation 1
    1629      1767735 :      if (ipert1<=natom)then
    1630       642897 :        sym1_ => symrec
    1631              :      else
    1632      1124838 :        sym1_ => symrel
    1633              :      end if
    1634              : 
    1635      7594986 :      do idir1=1,3
    1636     29538927 :       do ipert2=1,mpert !See notes
    1637              : !       do ipert2=1,min(natom+2,mpert)
    1638              : 
    1639              :     !    Select the symmetries according to pertubation 2
    1640     22467987 :          if (ipert2<=natom)then
    1641      7575489 :            sym2_ => symrec
    1642              :          else
    1643     14892498 :            sym2_ => symrel
    1644              :          end if
    1645              : 
    1646     95175153 :          do idir2=1,3
    1647              : 
    1648              : !          Will get element (idir1,ipert1,idir2,ipert2)
    1649              : !          so this element should not yet be present ...
    1650     89871948 :            if(blkflg(idir1,ipert1,idir2,ipert2)/=1)then
    1651              : 
    1652     57508094 :              d2(1,idir1,ipert1,idir2,ipert2)=zero
    1653     57508094 :              d2(2,idir1,ipert1,idir2,ipert2)=zero
    1654              : 
    1655              : !            Loop on all symmetries, including time-reversal
    1656     57508094 :              quit1=0
    1657   2174508361 :              do isym=1,nsym
    1658   6351736674 :                do itirev=1,2
    1659   4234736407 :                  isgn=3-2*itirev
    1660              : 
    1661   6351736674 :                  if(symq(4,itirev,isym)/=0)then
    1662   1817820617 :                    found=1
    1663              : 
    1664              : !                  Here select the symmetric of ipert1
    1665   1817820617 :                    if(ipert1<=natom)then
    1666    415311059 :                      ipesy1=indsym(4,isym,ipert1)
    1667   1402509558 :                    else if(ipert1==(natom+2).and.qzero)then
    1668              :                      ipesy1=ipert1
    1669              :                    else
    1670   1122607581 :                      found=0
    1671              :                    end if
    1672              : 
    1673              : !                  Here select the symmetric of ipert2
    1674   1817820617 :                    if(ipert2<=natom)then
    1675    417907445 :                      ipesy2=indsym(4,isym,ipert2)
    1676   1399913172 :                    else if(ipert2==(natom+2).and.qzero)then
    1677              :                      ipesy2=ipert2
    1678              :                    else
    1679              :                      found=0
    1680              :                    end if
    1681              : 
    1682              : !                  Now that a symmetric perturbation has been obtained,
    1683              : !                  including the expression of the symmetry matrix, see
    1684              : !                  if the symmetric values are available
    1685    695213036 :                    if( found==1 ) then
    1686              : 
    1687              :                      sumr=zero
    1688              :                      sumi=zero
    1689              :                      noccur=0
    1690              :                      nblkflg_is_one=0
    1691              :                      quit=0
    1692    505121346 :                      do idisy1=1,3
    1693   1465486933 :                        do idisy2=1,3
    1694   1465486933 :                          if(sym1_(idir1,idisy1,isym)/=0 .and. sym2_(idir2,idisy2,isym)/=0 )then
    1695    273775434 :                            if(blkflg(idisy1,ipesy1,idisy2,ipesy2)==1)then
    1696     40998557 :                              nblkflg_is_one=nblkflg_is_one+1
    1697              :                              sumr=sumr+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
    1698     40998557 : &                             d2(1,idisy1,ipesy1,idisy2,ipesy2)
    1699              :                              sumi=sumi+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
    1700     40998557 : &                             d2(2,idisy1,ipesy1,idisy2,ipesy2)
    1701              : 
    1702              : !                            Here, in case the symmetric of the element
    1703              : !                            is the element, or the symmetric with
    1704              : !                            respect to permutation of perturbations
    1705              : !                            (some more conditions on the time-reversal
    1706              : !                            symmetry must be fulfilled although)
    1707              :                            else if(  idisy1==idir1 .and. ipesy1==ipert1&
    1708              : &                             .and. idisy2==idir2 .and. ipesy2==ipert2&
    1709    232776877 : &                             .and.(isgn==1 .or. timrev==1 &
    1710              : &                             .or. (idir1==idir2 .and. ipert1==ipert2)))&
    1711              : &                             then
    1712     58712890 :                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
    1713              :                            else if(  idisy1==idir2 .and. ipesy1==ipert2&
    1714              : &                             .and. idisy2==idir1 .and. ipesy2==ipert1&
    1715    174063987 : &                             .and.(isgn==-1 .or. timrev==1&
    1716              : &                             .or. (idir1==idir2 .and. ipert1==ipert2)))&
    1717              : &                             then
    1718     12296011 :                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
    1719              : 
    1720              : !                            Here, electric field case
    1721              :                            else if( exch12==1 .and. &
    1722              : &                             ipert1==natom+2 .and. ipert2==natom+2&
    1723    161767976 : &                             .and.(( idisy1+idir1 ==3 &
    1724              : &                             .and. idisy2==3 .and. idir2==3)&
    1725              : &                             .or. ( idisy1+idir2 ==3&
    1726              : &                             .and. idisy2==3 .and. idir1==3)&
    1727              : &                             .or. ( idisy2+idir2 ==3&
    1728              : &                             .and. idisy1==3 .and. idir1==3)&
    1729              : &                             .or. ( idisy2+idir1 ==3&
    1730              : &                             .and. idisy1==3 .and. idir2==3)))&
    1731              : &                             then
    1732     15375464 :                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
    1733              : 
    1734              :                            else
    1735              : !                            Not found
    1736              :                              found=0
    1737              :                              quit=1
    1738              :                              exit
    1739              :                            end if
    1740              : 
    1741              :                          end if
    1742              :                        end do
    1743    505121346 :                        if(quit==1)exit
    1744              :                      end do
    1745              :                    end if
    1746              : 
    1747              : !                  In case zero_by_symm==0, the computed matrix element must be associated to at least one really computed matrix element
    1748   1817820617 :                    if(zero_by_symm==0 .and. nblkflg_is_one==0)then
    1749              :                      found=0
    1750              :                    endif
    1751              : 
    1752              : !                  Now, if still found and associated to at least one really computed matrix element, put the correct value into array d2
    1753   1817786153 :                    if(found==1)then
    1754              : 
    1755              : !                    In case of phonons, need to take into account the
    1756              : !                    time-reversal symmetry, and the shift back to the unit cell
    1757              : !
    1758              : !                    XG990712 : I am not sure this must be kept for electric field ...
    1759              : !                    1) Consider time-reversal symmetry
    1760     59422310 :                      sumi=isgn*sumi
    1761              : 
    1762     59422310 :                      if(ipert1<=natom .and. ipert2<=natom)then
    1763              : !                      2) Shift the atoms back to the unit cell.
    1764              :                        arg1=two_pi*( qpt(1)*indsym(1,isym,ipert1)&
    1765              : &                       +qpt(2)*indsym(2,isym,ipert1)&
    1766       199758 : &                       +qpt(3)*indsym(3,isym,ipert1) )
    1767              :                        arg2=two_pi*( qpt(1)*indsym(1,isym,ipert2)&
    1768              : &                       +qpt(2)*indsym(2,isym,ipert2)&
    1769       199758 : &                       +qpt(3)*indsym(3,isym,ipert2) )
    1770       199758 :                        re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
    1771              : !                      XG010117 Must use isgn
    1772       199758 :                        im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
    1773              :                      else
    1774              :                        re=one
    1775              :                        im=zero
    1776              :                      end if
    1777              : 
    1778              : !                    Final check, could still fail if the
    1779              : !                    element was its own symmetric
    1780     59422310 :                      if (abs(1.0_dp-re*noccur)< 1.0d-6.and.abs(im*noccur) <1.0d-6) then
    1781              :                        found=0
    1782              :                      end if
    1783              : 
    1784              :                    end if
    1785              : 
    1786              :                    if(found==1)then
    1787              : 
    1788       735390 :                      if(noccur==0)then
    1789       600529 :                        d2(1,idir1,ipert1,idir2,ipert2)=re*sumr-im*sumi
    1790       600529 :                        d2(2,idir1,ipert1,idir2,ipert2)=re*sumi+im*sumr
    1791              :                      else
    1792              : !                      See page July 2, 1994 in computer codes notebook
    1793       134861 :                        xr=re*sumr-im*sumi
    1794       134861 :                        xi=re*sumi+im*sumr
    1795       134861 :                        norm=one+noccur**2-two*re*noccur
    1796       134861 :                        xr=xr/norm
    1797       134861 :                        xi=xi/norm
    1798              :                        d2(1,idir1,ipert1,idir2,ipert2)=&
    1799       134861 : &                       (one-re*noccur)*xr-im*noccur*xi
    1800              :                        d2(2,idir1,ipert1,idir2,ipert2)=&
    1801       134861 : &                       (one-re*noccur)*xi+im*noccur*xr
    1802              :                      end if
    1803              : 
    1804              : !                    The element has been constructed !
    1805       735390 :                      blkflg(idir1,ipert1,idir2,ipert2)=1
    1806              : 
    1807              :                      quit1=1
    1808              :                      exit ! Exit loop on symmetry operations
    1809              :                    end if
    1810              : 
    1811              : !                  End loop on all symmetries + time-reversal
    1812              :                  end if
    1813              :                end do
    1814     56772704 :                if(quit1==1)exit
    1815              :              end do
    1816              : 
    1817              :            end if
    1818              :          end do ! End big loop on all elements
    1819              :        end do
    1820              :      end do
    1821              :    end do
    1822              : 
    1823              :  end do !  End Big Big Loop
    1824              : 
    1825              : !MT oct. 20, 2014:
    1826              : !Once the matrix has been built, it does not necessarily fulfill the correct symmetries.
    1827              : !It has just been filled up from rows or columns that only fulfill symmetries preserving
    1828              : !one particular perturbation.
    1829              : !An additional symmetrization might solve this (do not consider TR-symmetry)
    1830              :  if (do_final_sym) then
    1831       174682 :    ABI_MALLOC(d2tmp1,(2,3,3))
    1832       174682 :    ABI_MALLOC(d2tmp2,(2,3,3))
    1833       873410 :    ABI_MALLOC(d2work,(2,3,mpert,3,mpert))
    1834     77424952 :    d2work(:,:,:,:,:)=d2(:,:,:,:,:)
    1835       763927 :    do ipert1=1,mpert
    1836              :    !do ipert1=1,min(natom+2,mpert)
    1837       589245 :      if ((ipert1==natom+1.or.ipert1==natom+10.or.ipert1==natom+11).or.(ipert1==natom+2.and.(.not.qzero))) cycle
    1838       291628 :      if (ipert1<=natom)then
    1839       214299 :        sym1_ => symrec
    1840              :      else
    1841        77329 :        sym1_ => symrel
    1842              :      end if
    1843      1894154 :      do ipert2=1,mpert
    1844              :      !do ipert2=1,min(natom+2,mpert)
    1845              : !      if (any(blkflg(:,ipert1,:,ipert2)==0)) cycle
    1846      1427844 :        if ((ipert2==natom+1.or.ipert2==natom+10.or.ipert2==natom+11).or.(ipert2==natom+2.and.(.not.qzero))) cycle
    1847       913608 :        if (ipert2<=natom)then
    1848       464406 :          sym2_ => symrec
    1849              :        else
    1850       449202 :          sym2_ => symrel
    1851              :        end if
    1852       913608 :        nsym_used=0
    1853     28321848 :        d2tmp2(:,:,:)=zero
    1854     30619939 :        do isym=1,nsym
    1855     30619939 :          if (symq(4,1,isym)==1) then
    1856     16085572 :            ipesy1=ipert1;if (ipert1<=natom) ipesy1=indsym(4,isym,ipert1)
    1857     16085572 :            ipesy2=ipert2;if (ipert2<=natom) ipesy2=indsym(4,isym,ipert2)
    1858              : !          The condition on next line is too severe, since some elements of sym1_ or sym2_ might be zero,
    1859              : !          which means not all blkflg(:,ipesy1,:,ipesy2) would need to be 1 to symmetrize the matrix.
    1860              : !          However, coding something more refined is really more difficult.
    1861              : !          This condition then has the side effect that more symmetries can be applied when zero_by_symm==1,
    1862              : !          since blkflg can be set to 1 when the symmetries guarantee the matrix element to be zero.
    1863     82408363 :            if (all(blkflg(:,ipesy1,:,ipesy2)==1)) then
    1864      5523960 :              nsym_used=nsym_used+1
    1865      5523960 :              re=one;im=zero
    1866      5523960 :              if (ipert1<=natom.and.ipert2<=natom.and.(.not.qzero)) then
    1867              :                arg1=two_pi*(qpt(1)*(indsym(1,isym,ipert1)-indsym(1,isym,ipert2)) &
    1868              : &                          +qpt(2)*(indsym(2,isym,ipert1)-indsym(2,isym,ipert2)) &
    1869      2626726 : &                          +qpt(3)*(indsym(3,isym,ipert1)-indsym(3,isym,ipert2)))
    1870      2626726 :                re=cos(arg1);im=sin(arg1)
    1871              :              end if
    1872    171242760 :              d2tmp1(:,:,:)=zero
    1873     22095840 :              do idir2=1,3 !kappa
    1874     71811480 :                do idir1=1,3 !mu
    1875    215434440 :                  do idisy1=1,3 !nu
    1876              :                    d2tmp1(:,idir1,idir2)=d2tmp1(:,idir1,idir2) &
    1877    497156400 : &                     +sym1_(idir1,idisy1,isym)*d2(:,idisy1,ipesy1,idir2,ipesy2)
    1878              :                  end do
    1879              :                end do
    1880              :              end do
    1881     22095840 :              do idir2=1,3 !mu
    1882     71811480 :                do idir1=1,3 !kappa
    1883    215434440 :                  do idisy2=1,3 !nu
    1884              :                    d2tmp2(1,idir1,idir2)=d2tmp2(1,idir1,idir2) &
    1885    149146920 : &                  +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*re-d2tmp1(2,idir1,idisy2)*im)
    1886              :                    d2tmp2(2,idir1,idir2)=d2tmp2(2,idir1,idir2) &
    1887    198862560 : &                  +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*im+d2tmp1(2,idir1,idisy2)*re)
    1888              :                  end do
    1889              :                end do
    1890              :              end do
    1891              :            end if
    1892              :          end if
    1893              :        end do ! isym
    1894     10897233 :        if (nsym_used>0) d2work(:,1:3,ipert1,1:3,ipert2)=d2tmp2(:,1:3,1:3)/dble(nsym_used)
    1895              :      end do !ipert2
    1896              :    end do !ipert1
    1897     10400248 :    if (mpert>=natom)   d2(:,1:3,1:natom,1:3,1:natom)=d2work(:,1:3,1:natom,1:3,1:natom)
    1898       174682 :    if (mpert>=natom+2) then
    1899      6801530 :      d2(:,1:3,natom+2,1:3,1:natom)=d2work(:,1:3,natom+2,1:3,1:natom)
    1900      7111082 :      d2(:,1:3,1:natom,1:3,natom+2)=d2work(:,1:3,1:natom,1:3,natom+2)
    1901      5407733 :      d2(:,1:3,natom+2,1:3,natom+2)=d2work(:,1:3,natom+2,1:3,natom+2)
    1902              :    end if
    1903       174682 :    ABI_FREE(d2tmp1)
    1904       174682 :    ABI_FREE(d2tmp2)
    1905       174682 :    ABI_FREE(d2work)
    1906              :  end if
    1907              : 
    1908       174682 : end subroutine d2sym3
    1909              : !!***
    1910              : 
    1911              : !----------------------------------------------------------------------
    1912              : 
    1913              : !!****f* m_dynmat/q0dy3_apply
    1914              : !! NAME
    1915              : !! q0dy3_apply
    1916              : !!
    1917              : !! FUNCTION
    1918              : !! Takes care of the inclusion of the ewald q=0 term in the dynamical
    1919              : !! matrix - corrects the dyew matrix provided as input
    1920              : !! See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
    1921              : !! get the left hand side.
    1922              : !!
    1923              : !! INPUTS
    1924              : !!  dyewq0(3,3,natom) = part needed to correct the dynamical matrix for atom self-interaction.
    1925              : !!  natom= number of atom in the unit cell
    1926              : !!
    1927              : !! SIDE EFFECTS
    1928              : !!  dyew(2,3,natom,3,natom)= dynamical matrix corrected on output
    1929              : !!
    1930              : !! NOTES
    1931              : !! Should be used just after each call to dfpt_ewald, for both
    1932              : !! q==0 and the real wavelength.
    1933              : !!
    1934              : !! The q0dy3_apply should be used in conjunction with the subroutine dfpt_ewald (or ewald9):
    1935              : !! First, the call of dfpt_ewald with q==0 should be done,
    1936              : !!   then the call to q0dy3_calc will produce
    1937              : !!   the dyewq0 matrix from the (q=0) dyew matrix
    1938              : !! Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
    1939              : !!   should be done, then the call to q0dy3_apply
    1940              : !!   will produce the correct dynamical matrix dyew starting from
    1941              : !!   the previously calculated dyewq0 and the bare(non-corrected)
    1942              : !!   dyew matrix
    1943              : !!
    1944              : !! SOURCE
    1945              : 
    1946       181435 : subroutine q0dy3_apply(natom,dyewq0,dyew)
    1947              : 
    1948              : !Arguments -------------------------------
    1949              : !scalars
    1950              :  integer,intent(in) :: natom
    1951              : !arrays
    1952              :  real(dp),intent(in) :: dyewq0(3,3,natom)
    1953              :  real(dp),intent(inout) :: dyew(2,3,natom,3,natom)
    1954              : 
    1955              : !Local variables -------------------------
    1956              : !scalars
    1957              :  integer :: ia,mu,nu
    1958              : ! *********************************************************************
    1959              : 
    1960       725740 :  do mu=1,3
    1961      2358655 :    do nu=1,3
    1962      5821248 :      do ia=1,natom
    1963      5276943 :        dyew(1,mu,ia,nu,ia)=dyew(1,mu,ia,nu,ia)-dyewq0(mu,nu,ia)
    1964              :      end do
    1965              :    end do
    1966              :  end do
    1967              : 
    1968       181435 : end subroutine q0dy3_apply
    1969              : !!***
    1970              : 
    1971              : !----------------------------------------------------------------------
    1972              : 
    1973              : !!****f* m_dynmat/q0dy3_calc
    1974              : !! NAME
    1975              : !! q0dy3_calc
    1976              : !!
    1977              : !! FUNCTION
    1978              : !! Calculate the q=0 correction term to the dynamical matrix
    1979              : !! See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], the sum over \kappa"
    1980              : !!
    1981              : !! INPUTS
    1982              : !!  dyew(2,3,natom,3,natom)= dynamical matrix
    1983              : !!    input, non-corrected, for q=0 if option=1 or 2
    1984              : !!  natom= number of atom in the unit cell
    1985              : !!  option= either 1 or 2:
    1986              : !!     1: use dyew to calculate dyewq0 symmetrical form
    1987              : !!     2: use dyew to calculate dyewq0 symmetrical form
    1988              : !!
    1989              : !! OUTPUT
    1990              : !!  dyewq0(3,3,natom) = part needed to correct
    1991              : !!    the dynamical matrix for atom self-interaction.
    1992              : !!
    1993              : !! NOTES
    1994              : !! Should be used just after each call to dfpt_ewald, for both
    1995              : !! q==0 and the real wavelength.
    1996              : !!
    1997              : !! If option=1 or 2, q0dy3_calc uses an Ewald dynamical matrix at q=0,
    1998              : !! called dyew, to produce a contracted form called dyewq0 :
    1999              : !! either:
    2000              : !!   in an unsymmetrical form (if option=1), or
    2001              : !!   in a symmetrical form (if option=2).
    2002              : !!
    2003              : !! The q0dy3_calc should be used in conjunction with the subroutine dfpt_ewald (or ewald9).
    2004              : !! First, the call of dfpt_ewald with q==0 should be done ,
    2005              : !!   then the call to q0dy3_calc will produce
    2006              : !!   the dyewq0 matrix from the (q=0) dyew matrix
    2007              : !! Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
    2008              : !!   should be done, then the call to q0dy3_apply
    2009              : !!   will produce the correct dynamical matrix dyew starting from
    2010              : !!   the previously calculated dyewq0 and the bare(non-corrected)
    2011              : !!   dyew matrix
    2012              : !!
    2013              : !! SOURCE
    2014              : 
    2015          608 : subroutine q0dy3_calc(natom,dyewq0,dyew,option)
    2016              : 
    2017              : !Arguments -------------------------------
    2018              : !scalars
    2019              :  integer,intent(in) :: natom,option
    2020              : !arrays
    2021              :  real(dp),intent(in) :: dyew(2,3,natom,3,natom)
    2022              :  real(dp),intent(out) :: dyewq0(3,3,natom)
    2023              : 
    2024              : !Local variables -------------------------
    2025              : !scalars
    2026              :  integer :: ia,ib,mu,nu
    2027              :  character(len=500) :: msg
    2028              : ! *********************************************************************
    2029              : 
    2030          608 :  if(option==1.or.option==2.or.option==6)then
    2031         2432 :    do mu=1,3
    2032         7904 :      do nu=1,3
    2033        19419 :        do ia=1,natom
    2034        12123 :          dyewq0(mu,nu,ia)=zero
    2035        56160 :          do ib=1,natom
    2036        50688 :            dyewq0(mu,nu,ia)=dyewq0(mu,nu,ia)+dyew(1,mu,ia,nu,ib)
    2037              :          end do
    2038              :        end do
    2039              :      end do
    2040              :    end do
    2041              :  else
    2042              :    write (msg, '(3a)')&
    2043            0 : &   'option should be 1 or 2 or 6.',ch10,&
    2044            0 : &   'action: correct calling routine'
    2045            0 :    ABI_BUG(msg)
    2046              :  end if
    2047              : 
    2048          608 :  if(option==2)then
    2049          141 :    do ia=1,natom
    2050          477 :      do mu=1,3
    2051         1120 :        do nu=mu,3
    2052          672 :          dyewq0(mu,nu,ia)=(dyewq0(mu,nu,ia)+dyewq0(nu,mu,ia))/2
    2053         1008 :          dyewq0(nu,mu,ia)=dyewq0(mu,nu,ia)
    2054              :        end do
    2055              :      end do
    2056              :    end do
    2057              :  end if
    2058              : 
    2059          608 : end subroutine q0dy3_calc
    2060              : !!***
    2061              : 
    2062              : !----------------------------------------------------------------------
    2063              : 
    2064              : !!****f* m_dynmat/symdyma
    2065              : !!
    2066              : !! NAME
    2067              : !! symdyma
    2068              : !!
    2069              : !! FUNCTION
    2070              : !! Symmetrize the dynamical matrices
    2071              : !!
    2072              : !! INPUTS
    2073              : !! indsym(4,nsym*natom)=indirect indexing array : for each
    2074              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    2075              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    2076              : !!   translations which must be subtracted after the transformation to get back
    2077              : !!   to the original unit cell.
    2078              : !! natom=number of atoms in unit cell
    2079              : !! nsym=number of space group symmetries
    2080              : !! qptn(3)=normalized phonon wavevector
    2081              : !! rprimd(3,3)=dimensional primitive translations (bohr)
    2082              : !! symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
    2083              : !!
    2084              : !! SIDE EFFECTS
    2085              : !! Input/Output
    2086              : !! dmati(2*3*natom*3*natom)=dynamical matrices in cartesian coordinates relative to the q
    2087              : !!  points of the B.Z. sampling
    2088              : !!
    2089              : !! NOTES
    2090              : !! the procedure of the symmetrization of the dynamical matrix follows the
    2091              : !! equations in: Hendrikse et al., Computer Phys. Comm. 86, 297 (1995) [[cite:Hendrikse1995]]
    2092              : !!
    2093              : !! TODO
    2094              : !! A full description of the equations should be included
    2095              : !!
    2096              : !! SOURCE
    2097              : 
    2098       302511 : subroutine symdyma(dmati,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
    2099              : 
    2100              : !Arguments -------------------------------
    2101              : !scalars
    2102              :  integer,intent(in) :: natom,nsym
    2103              : !arrays
    2104              :  integer,intent(in) :: indsym(4,nsym,natom),symrel(3,3,nsym)
    2105              :  integer,intent(in) :: symafm(nsym)
    2106              :  real(dp),intent(in) :: qptn(3),rprimd(3,3)
    2107              :  real(dp),intent(inout) :: dmati(2*3*natom*3*natom)
    2108              : 
    2109              : !Local variables -------------------------
    2110              : !scalars
    2111              :  integer :: i1,i2,iat,idir,ii,index,isgn,isym,itirev,jat,jdir,jj,kk,ll
    2112              :  integer :: niat,njat,timrev
    2113              :  real(dp) :: arg1,arg2,dmint,im,re,sumi,sumr
    2114              : !arrays
    2115       605022 :  integer :: indij(natom,natom),symq(4,2,nsym),symrec(3,3,nsym)
    2116       605022 :  real(dp) :: TqR(3,3),TqS_(3,3),dynmat(2,3,natom,3,natom)
    2117       605022 :  real(dp) :: dynmatint(2*nsym,2,3,natom,3,natom),gprimd(3,3)
    2118       605022 :  real(dp) :: symcart(3,3,nsym)
    2119              : ! *********************************************************************
    2120              : !FIXME Disabling optimization with NVHPC in this routine
    2121              : !      because of significant numerical divergence
    2122              : !nvf$r opt=0
    2123              : 
    2124              :  ! 0) initializations
    2125       302511 :  call matr3inv(rprimd,gprimd)
    2126      8724728 :  do isym=1,nsym
    2127      8724728 :    call mati3inv(symrel(:,:,isym),symrec(:,:,isym))
    2128              :  end do
    2129              : 
    2130              :  TqR=zero
    2131              :  TqS_=zero
    2132     70867389 :  dynmat=zero
    2133              : 
    2134              : !Note: dynmat is used as work space here
    2135              :  i1=0
    2136       955428 :  do iat=1,natom
    2137      2914179 :    do idir=1,3
    2138      1958751 :      i1=i1+1
    2139      1958751 :      i2=0
    2140      9406989 :      do jat=1,natom
    2141     29140035 :        do jdir=1,3
    2142     20385963 :          i2=i2+1
    2143     20385963 :          index=i1+3*natom*(i2-1)
    2144     20385963 :          dynmat(1,idir,iat,jdir,jat)=dmati(2*index-1)
    2145     27181284 :          dynmat(2,idir,iat,jdir,jat)=dmati(2*index  )
    2146              :        end do
    2147              :      end do
    2148              :    end do
    2149              :  end do
    2150              : 
    2151              : !Transform symrel to cartesian coordinates (RC coding)
    2152              : !do isym=1,nsym
    2153              : !symcart(:,:,isym)=matmul(rprimd,matmul(dble(symrel(:,:,isym)),gprimd))
    2154              : !end do
    2155              : 
    2156              : !Coding from symdm9
    2157      8724728 :  do isym=1,nsym
    2158     33991379 :    do jj=1,3
    2159    101066604 :      symcart(:,jj,isym)=zero
    2160    109488821 :      do kk=1,3
    2161    328466463 :        do ll=1,3
    2162    985399389 :          symcart(:,jj,isym)=symcart(:,jj,isym)+rprimd(:,kk)*gprimd(jj,ll)*symrel(kk,ll,isym)
    2163              :        end do
    2164              :      end do
    2165              :    end do
    2166              :  end do
    2167              : 
    2168              :  ! Get the symq of the CURRENT Q POINT
    2169              :  ! mjv: set prtvol=0 for production runs.
    2170       302511 :  call littlegroup_q(nsym,qptn,symq,symrec,symafm,timrev,prtvol=0)
    2171              : 
    2172      3220535 :  indij(:,:)=0
    2173   1460580249 :  dynmatint=zero
    2174              : 
    2175      8724728 :  do isym=1,nsym  ! loop over all the symmetries
    2176              :    ! write(std_out,*) 'current symmetry',isym
    2177     25569162 :    do itirev=1,2  ! loop over the time-reversal symmetry
    2178     16844434 :      isgn=3-2*itirev
    2179              :      ! write(std_out,*) 'timereversal',isgn
    2180              : 
    2181     25266651 :      if (symq(4,itirev,isym)==1) then ! isym belongs to the wave vector point group
    2182              :        ! write(std_out,*) 'isym belongs to the wave vector point group'
    2183      3293629 :        do iat=1,natom
    2184     10551773 :          do jat=1,natom
    2185      7258144 :            niat=indsym(4,isym,iat)  ! niat={R|t}iat
    2186      7258144 :            njat=indsym(4,isym,jat)  ! njat={R|t}jat
    2187      7258144 :            indij(niat,njat)=indij(niat,njat)+1
    2188              :            ! write(std_out,'(a,5i5)') 'current status:',iat,jat,niat,njat,indij(niat,njat)
    2189              :            ! phase calculation, arg1 and arg2 because of two-atom derivative
    2190              :            arg1=two_pi*( qptn(1)*indsym(1,isym,iat)+&
    2191              :              qptn(2)*indsym(2,isym,iat)+&
    2192      7258144 :              qptn(3)*indsym(3,isym,iat) )
    2193              :            arg2=two_pi*( qptn(1)*indsym(1,isym,jat)+&
    2194              :              qptn(2)*indsym(2,isym,jat)+&
    2195      7258144 :              qptn(3)*indsym(3,isym,jat) )
    2196              : 
    2197      7258144 :            re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
    2198      7258144 :            im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
    2199              : 
    2200     31266626 :            do idir=1,3     ! loop over displacements
    2201     94355872 :              do jdir=1,3   ! loop over displacements
    2202              :                ! we pick the (iat,jat) (3x3) block of the dyn.mat.
    2203              :                sumr=zero
    2204              :                sumi=zero
    2205    261293184 :                do ii=1,3
    2206    849202848 :                  do jj=1,3
    2207    587909664 :                    sumr=sumr+symcart(idir,ii,isym)*dynmat(1,ii,niat,jj,njat)*symcart(jdir,jj,isym)
    2208    783879552 :                    sumi=sumi+symcart(idir,ii,isym)*dynmat(2,ii,niat,jj,njat)*symcart(jdir,jj,isym)
    2209              :                  end do
    2210              :                end do
    2211     65323296 :                sumi=isgn*sumi
    2212              : 
    2213     65323296 :                dynmatint(nsym*(itirev-1)+isym,1,idir,iat,jdir,jat)=re*sumr-im*sumi
    2214     87097728 :                dynmatint(nsym*(itirev-1)+isym,2,idir,iat,jdir,jat)=re*sumi+im*sumr
    2215              :              end do
    2216              :            end do
    2217              :          end do
    2218              :        end do ! end treatment of the (iat,jat) (3x3) block of dynmat
    2219              :      end if ! symmetry check
    2220              :    end do ! time-reversal
    2221              :  end do ! symmetries
    2222              : 
    2223              :  !4) make the average, get the final symmetric dynamical matrix
    2224       955428 :  do iat=1,natom
    2225      3220535 :    do jat=1,natom
    2226      9713345 :      do idir=1,3
    2227     29446391 :        do jdir=1,3
    2228              :          dmint=zero
    2229    715242393 :          do isym=1,2*nsym
    2230    715242393 :            dmint=dmint+dynmatint(isym,1,idir,iat,jdir,jat)
    2231              :          end do
    2232     20385963 :          dynmat(1,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
    2233     20385963 :          dmint=zero
    2234    715242393 :          do isym=1,2*nsym
    2235    715242393 :            dmint=dmint+dynmatint(isym,2,idir,iat,jdir,jat)
    2236              :          end do
    2237     27181284 :          dynmat(2,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
    2238              :        end do
    2239              :      end do
    2240              :    end do
    2241              :  end do
    2242              : 
    2243              :  i1=0
    2244       955428 :  do iat=1,natom
    2245      2914179 :    do idir=1,3
    2246      1958751 :      i1=i1+1
    2247      1958751 :      i2=0
    2248      9406989 :      do jat=1,natom
    2249     29140035 :        do jdir=1,3
    2250     20385963 :          i2=i2+1
    2251     20385963 :          index=i1+3*natom*(i2-1)
    2252     20385963 :          dmati(2*index-1)=dynmat(1,idir,iat,jdir,jat)
    2253     27181284 :          dmati(2*index  )=dynmat(2,idir,iat,jdir,jat)
    2254              :        end do
    2255              :      end do
    2256              :    end do
    2257              :  end do
    2258              : 
    2259       302511 : end subroutine symdyma
    2260              : !!***
    2261              : 
    2262              : !!****f* m_dynmat/dfpt_sygra
    2263              : !!
    2264              : !! NAME
    2265              : !! dfpt_sygra
    2266              : !!
    2267              : !! FUNCTION
    2268              : !! Symmetrize derivatives of energy with respect to coordinates,
    2269              : !! as appearing in phonon calculations.
    2270              : !! Unsymmetrized gradients are input as deunsy; symmetrized grads are then placed in desym.
    2271              : !! If nsym=1 simply copy deunsy into desym (only symmetry is identity).
    2272              : !! The index of the initial perturbation is needed, in case there is a change
    2273              : !! of atom position (moved in another cell) due to the symmetry operation.
    2274              : !!
    2275              : !! INPUTS
    2276              : !!  natom=number of atoms in cell
    2277              : !!  deunsy(2,3,natom)=unsymmetrized gradients wrt dimensionless tn (hartree)
    2278              : !!  note: there is a real and a imaginary part ...
    2279              : !!  indsym(4,nsym,natom)=label given by subroutine symatm, indicating atom
    2280              : !!   label which gets rotated into given atom by given symmetry
    2281              : !!   (first three elements are related primitive translation--
    2282              : !!   see symatm where this is computed)
    2283              : !!  nsym=number of symmetry operators in group
    2284              : !!  ipert=index of the initial perturbation
    2285              : !!  qpt(3)= wavevector of the phonon, in reduced coordinates
    2286              : !!  symrec(3,3,nsym)=symmetries of group in terms of operations on
    2287              : !!    reciprocal space primitive translations--see comments below
    2288              : !!
    2289              : !! OUTPUT
    2290              : !! desym(2,3,natom)=symmetrized gradients wrt dimensionless tn (hartree)
    2291              : !!
    2292              : !! NOTES
    2293              : !! Written by X. Gonze starting from sygrad, written by D.C. Allan:
    2294              : !!    introduction of the q vector for phonon symmetrization
    2295              : !! This routine should once be merged with sygrad...
    2296              : !!
    2297              : !! SOURCE
    2298              : 
    2299         2521 : subroutine dfpt_sygra(natom,desym,deunsy,indsym,ipert,nsym,qpt,symrec)
    2300              : 
    2301              : !Arguments -------------------------------
    2302              : !scalars
    2303              :  integer,intent(in) :: ipert,natom,nsym
    2304              : !arrays
    2305              :  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym)
    2306              :  real(dp),intent(in) :: deunsy(2,3,natom),qpt(3)
    2307              :  real(dp),intent(out) :: desym(2,3,natom)
    2308              : 
    2309              : !Local variables -------------------------
    2310              : !scalars
    2311              :  integer :: ia,ind,isym,mu
    2312              :  real(dp) :: arg,im,re,sumi,sumr
    2313              : ! *********************************************************************
    2314              : 
    2315         2521 :  if (nsym==1) then
    2316              : 
    2317              : !  Only symmetry is identity so simply copy
    2318        45738 :    desym(:,:,:)=deunsy(:,:,:)
    2319              : 
    2320              :  else
    2321              : 
    2322              : !  Actually conduct symmetrization
    2323              : !  write(std_out,*)' dfpt_sygra : desym(:2,:3,:natom),qpt(:)',desym(:2,:3,:natom),qpt(:)
    2324         2249 :    do ia=1,natom
    2325              : !    write(std_out,*)' dfpt_sygra : ia=',ia
    2326         7067 :      do mu=1,3
    2327              :        sumr=zero
    2328              :        sumi=zero
    2329              : !      write(std_out,*)' dfpt_sygra : mu=',mu
    2330        23760 :        do isym=1,nsym
    2331        18942 :          ind=indsym(4,isym,ia)
    2332              : !        Must shift the atoms back to the unit cell.
    2333              : !        arg=two_pi*( qpt(1)*indsym(1,isym,ia)&
    2334              : !        &         +qpt(2)*indsym(2,isym,ia)&
    2335              : !        &         +qpt(3)*indsym(3,isym,ia) )
    2336              : !        Selection of non-zero q point, to avoid ipert being outside the 1 ... natom range
    2337        18942 :          if(qpt(1)**2+qpt(2)**2+qpt(3)**2 > tol16)then
    2338              :            arg=two_pi*( qpt(1)*(indsym(1,isym,ia)-indsym(1,isym,ipert))&
    2339              : &           +qpt(2)* (indsym(2,isym,ia)-indsym(2,isym,ipert))&
    2340         1896 : &           +qpt(3)* (indsym(3,isym,ia)-indsym(3,isym,ipert)))
    2341              :          else
    2342              :            arg=zero
    2343              :          end if
    2344              : 
    2345              :          re=dble(symrec(mu,1,isym))*deunsy(1,1,ind)+&
    2346              : &         dble(symrec(mu,2,isym))*deunsy(1,2,ind)+&
    2347        18942 : &         dble(symrec(mu,3,isym))*deunsy(1,3,ind)
    2348              :          im=dble(symrec(mu,1,isym))*deunsy(2,1,ind)+&
    2349              : &         dble(symrec(mu,2,isym))*deunsy(2,2,ind)+&
    2350        18942 : &         dble(symrec(mu,3,isym))*deunsy(2,3,ind)
    2351        18942 :          sumr=sumr+re*cos(arg)-im*sin(arg)
    2352        23760 :          sumi=sumi+re*sin(arg)+im*cos(arg)
    2353              : !        sumr=sumr+re
    2354              : !        sumi=sumi+im
    2355              : !        write(std_out,*)' dfpt_sygra : isym,indsym(4,isym,ia),arg,re,im,sumr,sumi',&
    2356              : !        &      isym,indsym(4,isym,ia),arg,re,im,sumr,sumi
    2357              :        end do
    2358         4818 :        desym(1,mu,ia)=sumr/dble(nsym)
    2359         6424 :        desym(2,mu,ia)=sumi/dble(nsym)
    2360              : !      write(std_out,*)' dfpt_sygra : desym(:,mu,ia)',desym(:,mu,ia)
    2361              :      end do
    2362              :    end do
    2363              :  end if
    2364              : 
    2365         2521 : end subroutine dfpt_sygra
    2366              : !!***
    2367              : 
    2368              : !!****f* m_dynmat/dfpt_sydy
    2369              : !! NAME
    2370              : !! dfpt_sydy
    2371              : !!
    2372              : !! FUNCTION
    2373              : !! Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
    2374              : !! Unsymmetrized dynamical matrix is input as dyfrow;
    2375              : !! symmetrized dynamical matrix is then placed in sdyfro.
    2376              : !! If nsym=1 simply copy dyfrow into sdyfro.
    2377              : !!
    2378              : !! INPUTS
    2379              : !!  cplex=1 if dynamical matrix is real, 2 if it is complex
    2380              : !!  dyfrow(3,3,natom,1+(natom-1)*nondiag)=unsymmetrized dynamical matrix
    2381              : !!  indsym(4,msym*natom)=indirect indexing array: for each
    2382              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    2383              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    2384              : !!   translations which must be subtracted after the transformation to get back
    2385              : !!   to the original unit cell.
    2386              : !!  natom=number of atoms in cell.
    2387              : !!  nondiag=0 if dynamical matrix is     diagonal with respect to atoms
    2388              : !           1 if dynamical matrix is non diagonal with respect to atoms
    2389              : !!  nsym=number of symmetry operators in group.
    2390              : !!  qphon(3)=wavevector of the phonon
    2391              : !!  symq(4,2,nsym)=1 if symmetry preserves present qpoint. From littlegroup_q
    2392              : !!  symrec(3,3,nsym)=symmetries of group in terms of operations on real
    2393              : !!    space primitive translations (integers).
    2394              : !!
    2395              : !! OUTPUT
    2396              : !!  sdyfro(3,3,natom,1+(natom-1)*nondiag)=symmetrized dynamical matrix
    2397              : !!
    2398              : !! NOTES
    2399              : !! Symmetrization of gradients with respect to reduced
    2400              : !! coordinates tn is conducted according to the expression
    2401              : !! $[d(e)/d(t(n,a))]_{symmetrized} = (1/Nsym)*Sum(S)*symrec(n,m,S)*
    2402              : !!              [d(e)/d(t(m,b))]_{unsymmetrized}$
    2403              : !! where $t(m,b)= (symrel^{-1})(m,n)*(t(n,a)-tnons(n))$ and tnons
    2404              : !! is a possible nonsymmorphic translation.  The label "b" here
    2405              : !! refers to the atom which gets rotated into "a" under symmetry "S".
    2406              : !! symrel is the symmetry matrix in real space, which is the inverse
    2407              : !! transpose of symrec.  symrec is the symmetry matrix in reciprocal
    2408              : !! space.  $sym_{cartesian} = R * symrel * R^{-1} = G * symrec * G^{-1}$
    2409              : !! where the columns of R and G are the dimensional primitive translations
    2410              : !! in real and reciprocal space respectively.
    2411              : !! Note the use of "symrec" in the symmetrization expression above.
    2412              : !!
    2413              : !! SOURCE
    2414              : 
    2415         1350 : subroutine dfpt_sydy(cplex,dyfrow,indsym,natom,nondiag,nsym,qphon,sdyfro,symq,symrec)
    2416              : 
    2417              : !Arguments -------------------------------
    2418              : !scalars
    2419              :  integer,intent(in) :: cplex,natom,nondiag,nsym
    2420              : !arrays
    2421              :  integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym),symrec(3,3,nsym)
    2422              :  real(dp),intent(in) :: dyfrow(cplex,3,3,natom,1+(natom-1)*nondiag),qphon(3)
    2423              :  real(dp),intent(out) :: sdyfro(cplex,3,3,natom,1+(natom-1)*nondiag)
    2424              : 
    2425              : !Local variables -------------------------
    2426              : !scalars
    2427              :  integer :: ia,indi,indj,isym,ja,kappa,mu,natom_nondiag,nsym_used,nu
    2428              :  logical :: qeq0
    2429              :  real(dp) :: arg,div,phasei,phaser
    2430              : !arrays
    2431         2700 :  real(dp) :: work(cplex,3,3)
    2432              : ! *********************************************************************
    2433              : 
    2434         1350 :  if (nsym==1) then
    2435              : 
    2436              : !  Only symmetry is identity so simply copy
    2437        17883 :    sdyfro(:,:,:,:,:)=dyfrow(:,:,:,:,:)
    2438              : 
    2439              :  else
    2440              : 
    2441              : !  Actually carry out symmetrization
    2442        57491 :    sdyfro(:,:,:,:,:)=zero
    2443          999 :    qeq0=(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)
    2444              : !  === Diagonal dyn. matrix OR q=0
    2445          999 :    if (nondiag==0.or.qeq0) then
    2446          985 :      natom_nondiag=1;if (nondiag==1) natom_nondiag=natom
    2447         2045 :      do ja=1,natom_nondiag
    2448         4493 :        do ia=1,natom
    2449        59594 :          do isym=1,nsym
    2450        56086 :            indi=indsym(4,isym,ia)
    2451        56086 :            indj=1;if (nondiag==1) indj=indsym(4,isym,ja)
    2452      1233892 :            work(:,:,:)=zero
    2453       224344 :            do mu=1,3
    2454       729118 :              do nu=1,3
    2455      2187354 :                do kappa=1,3
    2456      3533418 :                  work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
    2457              :                end do
    2458              :              end do
    2459              :            end do
    2460       226792 :            do mu=1,3
    2461       729118 :              do nu=1,3
    2462      2187354 :                do kappa=1,3
    2463      3533418 :                  sdyfro(:,kappa,mu,ia,ja)=sdyfro(:,kappa,mu,ia,ja)+symrec(mu,nu,isym)*work(:,kappa,nu)
    2464              :                end do
    2465              :              end do
    2466              :            end do
    2467              :          end do
    2468              :        end do
    2469              :      end do
    2470          985 :      div=one/dble(nsym)
    2471        55901 :      sdyfro(:,:,:,:,:)=div*sdyfro(:,:,:,:,:)
    2472              : !    === Non diagonal dyn. matrix AND q<>0
    2473              :    else
    2474           40 :      do ja=1,natom
    2475           90 :        do ia=1,natom
    2476              :          nsym_used=0
    2477         1298 :          do isym=1,nsym
    2478         1298 :            if (symq(4,1,isym)==1) then
    2479              :              arg=two_pi*(qphon(1)*(indsym(1,isym,ia)-indsym(1,isym,ja)) &
    2480              : &             +qphon(2)*(indsym(2,isym,ia)-indsym(2,isym,ja)) &
    2481          256 : &             +qphon(3)*(indsym(3,isym,ia)-indsym(3,isym,ja)))
    2482          256 :              phaser=cos(arg);phasei=sin(arg)
    2483          256 :              nsym_used=nsym_used+1
    2484          256 :              indi=indsym(4,isym,ia)
    2485          256 :              indj=indsym(4,isym,ja)
    2486         7936 :              work(:,:,:)=zero
    2487         1024 :              do mu=1,3
    2488         3328 :                do nu=1,3
    2489         9984 :                  do kappa=1,3
    2490        23040 :                    work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
    2491              :                  end do
    2492              :                end do
    2493              :              end do
    2494         1024 :              do mu=1,3
    2495         3328 :                do nu=1,3
    2496         9984 :                  do kappa=1,3
    2497              :                    sdyfro(1,kappa,mu,ia,ja)=sdyfro(1,kappa,mu,ia,ja) &
    2498         9216 : &                   +symrec(mu,nu,isym)*(work(1,kappa,nu)*phaser-work(2,kappa,nu)*phasei)
    2499              :                  end do
    2500              :                end do
    2501              :              end do
    2502          256 :              if (cplex==2) then
    2503         1024 :                do mu=1,3
    2504         3328 :                  do nu=1,3
    2505         9984 :                    do kappa=1,3
    2506              :                      sdyfro(2,kappa,mu,ia,ja)=sdyfro(2,kappa,mu,ia,ja) &
    2507         9216 : &                     +symrec(mu,nu,isym)*(work(1,kappa,nu)*phasei+work(2,kappa,nu)*phaser)
    2508              :                    end do
    2509              :                  end do
    2510              :                end do
    2511              :              end if
    2512              :            end if
    2513              :          end do
    2514           50 :          div=one/dble(nsym_used)
    2515         1576 :          sdyfro(:,:,:,ia,ja)=div*sdyfro(:,:,:,ia,ja)
    2516              :        end do
    2517              :      end do
    2518              :    end if
    2519              : 
    2520              :  end if
    2521              : 
    2522         1350 : end subroutine dfpt_sydy
    2523              : !!***
    2524              : 
    2525              : !    CODE TO BE EVENTUALLY REUSED
    2526              : !    Sym preserves direction and atom
    2527              : !    if (symq(1,1,isym)==0.and.symq(2,1,isym)==0.and.symq(3,1,isym)==0.and.symq(4,1,isym)==1)then
    2528              : !      if (ipert==indsym(4,isym,ipert)) then
    2529              : !        tok=1
    2530              : !        do idir1=1,3
    2531              : !          if ((idir1==idir.and.symrec(idir,idir1,isym)/=1).or.&
    2532              : ! &            (idir1/=idir.and.symrec(idir,idir1,isym)/=0)) tok=0
    2533              : !        end do
    2534              : !      end if
    2535              : !    end if
    2536              : !    div=one/dble(count(symq(4,1,:)==1))
    2537              : 
    2538              : !----------------------------------------------------------------------
    2539              : 
    2540              : !!****f* m_dynmat/wings3
    2541              : !! NAME
    2542              : !! wings3
    2543              : !!
    2544              : !! FUNCTION
    2545              : !!  Suppress the wings of the cartesian 2DTE for which
    2546              : !!  the diagonal element is not known
    2547              : !!
    2548              : !! INPUTS
    2549              : !!  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
    2550              : !!  2DTE matrix has been calculated correctly ; 0 otherwise )
    2551              : !!  d2cart(2,3,mpert,3,mpert)=
    2552              : !!   dynamical matrix, effective charges, dielectric tensor,....
    2553              : !!   all in cartesian coordinates
    2554              : !!  mpert =maximum number of ipert
    2555              : !!
    2556              : !! OUTPUT
    2557              : !!  d2cart(2,3,mpert,3,mpert) without the wings
    2558              : !!
    2559              : !! SOURCE
    2560              : 
    2561          382 : subroutine wings3(carflg,d2cart,mpert)
    2562              : 
    2563              : !Arguments -------------------------------
    2564              : !scalars
    2565              :  integer,intent(in) :: mpert
    2566              : !arrays
    2567              :  integer,intent(inout) :: carflg(3,mpert,3,mpert)
    2568              :  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
    2569              : 
    2570              : !Local variables -------------------------
    2571              : !scalars
    2572              :  integer :: idir,idir1,ipert,ipert1
    2573              : ! *********************************************************************
    2574              : 
    2575         3849 :  do ipert=1,mpert
    2576        14250 :    do idir=1,3
    2577        13868 :      if(carflg(idir,ipert,idir,ipert)==0)then
    2578        85788 :        do ipert1=1,mpert
    2579       318444 :          do idir1=1,3
    2580       232656 :            carflg(idir,ipert,idir1,ipert1)=0
    2581       232656 :            carflg(idir1,ipert1,idir,ipert)=0
    2582       232656 :            d2cart(1,idir,ipert,idir1,ipert1)=zero
    2583       232656 :            d2cart(2,idir,ipert,idir1,ipert1)=zero
    2584       232656 :            d2cart(1,idir1,ipert1,idir,ipert)=zero
    2585       310208 :            d2cart(2,idir1,ipert1,idir,ipert)=zero
    2586              :          end do
    2587              :        end do
    2588              :      end if
    2589              :    end do
    2590              :  end do
    2591              : 
    2592          382 : end subroutine wings3
    2593              : !!***
    2594              : 
    2595              : !----------------------------------------------------------------------
    2596              : 
    2597              : !!****f* m_dynmat/asrif9
    2598              : !!
    2599              : !! NAME
    2600              : !! asrif9
    2601              : !!
    2602              : !! FUNCTION
    2603              : !! Imposes the Acoustic Sum Rule to Interatomic Forces
    2604              : !!
    2605              : !! INPUTS
    2606              : !! asr= Option for the imposition of the ASR
    2607              : !!  0 => no ASR,
    2608              : !!  1 => modify "asymmetrically" the diagonal element
    2609              : !!  2 => modify "symmetrically" the diagonal element
    2610              : !! natom= Number of atoms in the unit cell
    2611              : !! nrpt= Number of R points in the Big Box
    2612              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    2613              : !!  These coordinates are normalized (=> * acell(3)!!)
    2614              : !! wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
    2615              : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces
    2616              : !!
    2617              : !! OUTPUT
    2618              : !! atmfrc(3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces
    2619              : !!
    2620              : !! TODO
    2621              : !! List of ouput should be included.
    2622              : !!
    2623              : !! SOURCE
    2624              : 
    2625          308 : subroutine asrif9(asr,atmfrc,natom,nrpt,rpt,wghatm)
    2626              : 
    2627              : !Arguments -------------------------------
    2628              : !scalars
    2629              :  integer,intent(in) :: asr,natom,nrpt
    2630              : !arrays
    2631              :  real(dp),intent(in) :: rpt(3,nrpt),wghatm(natom,natom,nrpt)
    2632              :  real(dp),intent(inout) :: atmfrc(3,natom,3,natom,nrpt)
    2633              : 
    2634              : !Local variables -------------------------
    2635              : !scalars
    2636              :  integer :: found,ia,ib,irpt,izero,mu,nu
    2637              :  real(dp) :: sumifc
    2638              : ! *********************************************************************
    2639              : 
    2640          308 :  if(asr==1.or.asr==2)then
    2641              :    found=0
    2642              :    ! Search for the R vector which is equal to ( 0 , 0 , 0 )
    2643              :    ! This vector leaves the atom a on itself !
    2644       291166 :    do irpt=1,nrpt
    2645       311387 :      if (all(abs(rpt(:,irpt))<=1.0d-10)) then
    2646              :        found=1
    2647              :        izero=irpt
    2648              :      end if
    2649            0 :      if (found==1) exit
    2650              :    end do
    2651              : 
    2652          307 :    if(found==0)then
    2653            0 :      ABI_BUG('Not able to find the vector R=(0,0,0).')
    2654              :    end if
    2655              : 
    2656         1228 :    do mu=1,3
    2657         3991 :      do nu=1,3
    2658        11172 :        do ia=1,natom
    2659              :          sumifc=zero
    2660        41238 :          do ib=1,natom
    2661              : 
    2662              :            ! Get the sumifc of interatomic forces acting on the atom ia,
    2663              :            ! either in a symmetrical manner, or an unsymmetrical one.
    2664        41238 :            if(asr==1)then
    2665     53477559 :              do irpt=1,nrpt
    2666     53477559 :                sumifc=sumifc+wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)
    2667              :              end do
    2668              :            else if(asr==2)then
    2669     31825188 :              do irpt=1,nrpt
    2670              :                sumifc=sumifc+&
    2671              :                 (wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)+&
    2672     31825188 :                  wghatm(ia,ib,irpt)*atmfrc(nu,ia,mu,ib,irpt))/2
    2673              :              end do
    2674              :            end if
    2675              :          end do
    2676              : 
    2677              :          ! Correct the self-interaction in order to fulfill the ASR
    2678         7488 :          atmfrc(mu,ia,nu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)-sumifc
    2679        10251 :          if (asr==2) atmfrc(nu,ia,mu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)
    2680              :        end do
    2681              :      end do
    2682              :    end do
    2683              :  end if
    2684              : 
    2685          308 : end subroutine asrif9
    2686              : !!***
    2687              : 
    2688              : !----------------------------------------------------------------------
    2689              : 
    2690              : !!****f* m_dynmat/get_bigbox_and_weights
    2691              : !! NAME
    2692              : !! get_bigbox_and_weights
    2693              : !!
    2694              : !! FUNCTION
    2695              : !! Compute the Big Box containing the R points in the cartesian real space needed to Fourier Transform
    2696              : !! the dynamical matrix into its corresponding interatomic force.
    2697              : !!
    2698              : !! INPUTS
    2699              : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
    2700              : !! natom= Number of atoms
    2701              : !! nqbz= Number of q-points in BZ.
    2702              : !! ngqpt(3)= Numbers used to generate the q points to sample the Brillouin zone using an homogeneous grid
    2703              : !! nqshift= number of shifts in q-mesh
    2704              : !! qshift(3, nqshift) = Q-mesh shifts
    2705              : !! rprim(3,3)= Normalized coordinates in real space.
    2706              : !! rprimd, gprimd
    2707              : !! rcan(3,natom)  = Atomic position in canonical coordinates
    2708              : !! cutmode=Define the cutoff used to filter the output R-points according to their weights.
    2709              : !!   0 --> No cutoff (mainly for debugging)
    2710              : !!   1 --> Include only those R-points for which sum(abs(wg(:,:,irpt)) < tol20
    2711              : !!         This is the approach used for the dynamical matrix.
    2712              : !!   2 --> Include only those R-points for which the trace over iatom of abs(wg(iat,iat,irpt)) < tol20
    2713              : !!         This option is used for objects that depend on a single atomic index.
    2714              : !! comm= MPI communicator
    2715              : !!
    2716              : !! OUTPUT
    2717              : !! nrpt= Total Number of R points in the Big Box
    2718              : !! cell(3,nrpt) Give the index of the the cell and irpt
    2719              : !! rpt(3,nrpt)= Canonical coordinates of the R points in the unit cell. These coordinates are normalized (=> * acell(3)!!)
    2720              : !! r_inscribed_sphere
    2721              : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
    2722              : !!
    2723              : !! SOURCE
    2724              : 
    2725            0 : subroutine get_bigbox_and_weights(brav, natom, nqbz, ngqpt, nqshift, qshift, rprim, rprimd, gprim, rcan, &
    2726              :                                   cutmode, nrpt, rpt, cell, wghatm, r_inscribed_sphere, comm)
    2727              : 
    2728              : !Arguments -------------------------------
    2729              : !scalars
    2730              :  integer,intent(in) :: brav, natom, nqbz, nqshift, cutmode, comm
    2731              :  integer,intent(out) :: nrpt
    2732              :  real(dp),intent(out) :: r_inscribed_sphere
    2733              : !arrays
    2734              :  integer,intent(in) :: ngqpt(3)
    2735              :  real(dp),intent(in) :: gprim(3,3),rprim(3,3),rprimd(3,3), rcan(3, natom)
    2736              :  real(dp),intent(in) :: qshift(3, nqshift)
    2737              :  integer,allocatable,intent(out) :: cell(:,:)
    2738              :  real(dp),allocatable,intent(out) :: rpt(:,:), wghatm(:,:,:)
    2739              : 
    2740              : !Local variables -------------------------
    2741              : !scalars
    2742              :  integer :: my_ierr, ierr, ii, irpt, all_nrpt
    2743              :  real(dp) :: toldist
    2744              :  integer :: ngqpt9(9)
    2745              :  character(len=500*4) :: msg
    2746              : !arrays
    2747            0 :  integer,allocatable :: all_cell(:,:)
    2748            0 :  real(dp),allocatable :: all_rpt(:,:), all_wghatm(:,:,:)
    2749              : ! *********************************************************************
    2750              : 
    2751            0 :  ABI_CHECK(any(cutmode == [0, 1, 2]), "cutmode should be in [0, 1, 2]")
    2752              : 
    2753              :  ! Create the Big Box of R vectors in real space and compute the number of points (cells) in real space
    2754            0 :  call make_bigbox(brav, all_cell, ngqpt, nqshift, rprim, all_nrpt, all_rpt)
    2755              : 
    2756              :  ! Weights associated to these R points and to atomic pairs
    2757            0 :  ABI_MALLOC(all_wghatm, (natom, natom, all_nrpt))
    2758              : 
    2759              :  ! HM: this tolerance is highly dependent on the compilation/architecture
    2760              :  !     numeric errors in the DDB text file. Try a few tolerances and check whether all the weights are found.
    2761            0 :  ngqpt9 = 0; ngqpt9(1:3) = ngqpt(1:3)
    2762            0 :  toldist = tol8
    2763            0 :  do while (toldist <= tol6)
    2764              :    ! Note ngqpt(9) with intent(inout)!
    2765              :    call wght9(brav, gprim, natom, ngqpt9, nqbz, nqshift, all_nrpt, qshift, rcan, &
    2766            0 :               all_rpt, rprimd, toldist, r_inscribed_sphere, all_wghatm, my_ierr)
    2767            0 :    call xmpi_max(my_ierr, ierr, comm, ii)
    2768            0 :    if (ierr > 0) toldist = toldist * 10
    2769            0 :    if (ierr == 0) exit
    2770              :  end do
    2771              : 
    2772            0 :  if (ierr > 0) then
    2773              :    write(msg, '(3a,es14.4,2a,i0, 14a)' ) &
    2774            0 :     'The sum of the weight is not equal to nqpt.',ch10,&
    2775            0 :     'The sum of the weights is: ',sum(all_wghatm),ch10,&
    2776            0 :     'The number of q points is: ',nqbz, ch10, &
    2777            0 :     'This might have several sources.',ch10,&
    2778            0 :     'If toldist is larger than 1.0e-8, the atom positions might be loose.',ch10,&
    2779            0 :     'and the q point weights not computed properly.',ch10,&
    2780            0 :     'Action: make input atomic positions more symmetric.',ch10,&
    2781            0 :     'Otherwise, you might increase "buffer" in m_dynmat.F90 see bigbx9 subroutine and recompile.',ch10,&
    2782            0 :     'Actually, this can also happen when ngqpt is 0 0 0,',ch10,&
    2783            0 :     'if abs(brav) /= 1, in this case you should change brav to 1. If brav is already set to 1 (default) try -1.'
    2784            0 :    ABI_ERROR(msg)
    2785              :  end if
    2786              : 
    2787              :  ! Only conserve the necessary points in rpt.
    2788            0 :  nrpt = 0
    2789            0 :  do irpt=1,all_nrpt
    2790            0 :    if (filterw(all_wghatm(:,:,irpt))) cycle
    2791            0 :    nrpt = nrpt + 1
    2792              :  end do
    2793              : 
    2794              :  ! Allocate output arrays and transfer data.
    2795            0 :  ABI_MALLOC(rpt, (3, nrpt))
    2796            0 :  ABI_MALLOC(cell, (3, nrpt))
    2797            0 :  ABI_MALLOC(wghatm, (natom, natom, nrpt))
    2798              : 
    2799            0 :  ii = 0
    2800            0 :  do irpt=1,all_nrpt
    2801            0 :    if (filterw(all_wghatm(:,:,irpt))) cycle
    2802            0 :    ii = ii + 1
    2803            0 :    rpt(:, ii) = all_rpt(:,irpt)
    2804            0 :    wghatm(:,:,ii) = all_wghatm(:,:,irpt)
    2805            0 :    cell(:,ii) = all_cell(:,irpt)
    2806              :  end do
    2807              : 
    2808            0 :  ABI_FREE(all_rpt)
    2809            0 :  ABI_FREE(all_wghatm)
    2810            0 :  ABI_FREE(all_cell)
    2811              : 
    2812              : contains
    2813              : 
    2814            0 : logical pure function filterw(wg)
    2815              : 
    2816              :  real(dp),intent(in) :: wg(natom,natom)
    2817              :  integer :: iat
    2818              :  real(dp) :: trace
    2819              : 
    2820            0 :  select case (cutmode)
    2821              :  case (1)
    2822            0 :    filterw = sum(abs(wg)) < tol20
    2823              :  case (2)
    2824              :    trace = zero
    2825            0 :    do iat=1,natom
    2826            0 :      trace = trace + abs(wg(iat,iat))
    2827              :    end do
    2828            0 :    filterw = trace < tol20
    2829              :  case default
    2830            0 :    filterw = .False.
    2831              :  end select
    2832              : 
    2833            0 : end function filterw
    2834              : 
    2835              : end subroutine get_bigbox_and_weights
    2836              : !!***
    2837              : 
    2838              : !----------------------------------------------------------------------
    2839              : 
    2840              : !!****f* m_dynmat/make_bigbox
    2841              : !! NAME
    2842              : !! make_bigbox
    2843              : !!
    2844              : !! FUNCTION
    2845              : !! Helper functions to faciliate the generation of a Big Box containing
    2846              : !! all the R points in the cartesian real space needed to Fourier Transform
    2847              : !! the dynamical matrix into its corresponding interatomic force.
    2848              : !! See bigbx9 for the algorithm.
    2849              : !!
    2850              : !! INPUTS
    2851              : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
    2852              : !! ngqpt(3)= Numbers used to generate the q points to sample the
    2853              : !!   Brillouin zone using an homogeneous grid
    2854              : !! nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
    2855              : !!  When nqshft is not 1, but 2 or 4 (only other allowed values),
    2856              : !!  the limits for the big box have to be extended by a factor of 2.
    2857              : !! rprim(3,3)= Normalized coordinates in real space  !!! IS THIS CORRECT?
    2858              : !!
    2859              : !! OUTPUT
    2860              : !! cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
    2861              : !! nprt= Number of cells (R points) in the Big Box
    2862              : !! rpt(3,mrpt)= canonical coordinates of the cells (R points)
    2863              : !!  These coordinates are normalized (=> * acell(3)!!)
    2864              : !!  The array is allocated here with the proper dimension. Client code is responsible
    2865              : !!  for the deallocation.
    2866              : !!
    2867              : !! SOURCE
    2868              : 
    2869          242 : subroutine make_bigbox(brav, cell, ngqpt, nqshft, rprim, nrpt, rpt)
    2870              : 
    2871              : !Arguments -------------------------------
    2872              : !scalars
    2873              :  integer,intent(in) :: brav,nqshft
    2874              :  integer,intent(out) :: nrpt
    2875              : !arrays
    2876              :  integer,intent(in) :: ngqpt(3)
    2877              :  real(dp),intent(in) :: rprim(3,3)
    2878              :  real(dp),allocatable,intent(out) :: rpt(:,:)
    2879              :  integer,allocatable,intent(out) :: cell(:,:)
    2880              : 
    2881              : !Local variables -------------------------
    2882              : !scalars
    2883              :  integer :: choice,mrpt
    2884              : !arrays
    2885              :  real(dp) :: dummy_rpt(3,1)
    2886              :  integer:: dummy_cell(1,3)
    2887              : ! *********************************************************************
    2888              : 
    2889              :  ! Compute the number of points (cells) in real space
    2890          242 :  choice=0
    2891          242 :  call bigbx9(brav,dummy_cell,choice,1,ngqpt,nqshft,mrpt,rprim,dummy_rpt)
    2892              : 
    2893              :  ! Now we can allocate and calculate the points and the weights.
    2894          242 :  nrpt = mrpt
    2895          726 :  ABI_MALLOC(rpt,(3,nrpt))
    2896          726 :  ABI_MALLOC(cell,(3,nrpt))
    2897              : 
    2898          242 :  choice=1
    2899          242 :  call bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
    2900              : 
    2901          242 : end subroutine make_bigbox
    2902              : !!***
    2903              : 
    2904              : !----------------------------------------------------------------------
    2905              : 
    2906              : !!****f* m_dynmat/bigbx9
    2907              : !! NAME
    2908              : !! bigbx9
    2909              : !!
    2910              : !! FUNCTION
    2911              : !! Generation of a Big Box containing all the R points (cells) in the
    2912              : !! cartesian real space needed to Fourier Transforms the dynamical
    2913              : !! matrix into its corresponding interatomic force.
    2914              : !!
    2915              : !! INPUTS
    2916              : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
    2917              : !! choice= if 0, simply count nrpt ; if 1, checks that the input mrpt
    2918              : !!   is the same as nrpt, and generate rpt(3,mrpt)
    2919              : !! mrpt=dimension of rpt
    2920              : !! ngqpt(3)= Numbers used to generate the q points to sample the
    2921              : !!  Brillouin zone using an homogeneous grid
    2922              : !! nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
    2923              : !!  When nqshft is not 1, but 2 or 4 (only other allowed values),
    2924              : !!  the limits for the big box have to be extended by a factor of 2.
    2925              : !! rprim(3,3)= Normalized coordinates in real space  !!! IS THIS CORRECT?
    2926              : !!
    2927              : !! OUTPUT
    2928              : !! cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
    2929              : !! nprt= Number of cells (R points) in the Big Box
    2930              : !! rpt(3,mrpt)= canonical coordinates of the cells (R points)
    2931              : !!  These coordinates are normalized (=> * acell(3)!!)
    2932              : !!  (output only if choice=1)
    2933              : !!
    2934              : !! SOURCE
    2935              : 
    2936          484 : subroutine bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
    2937              : 
    2938              : !Arguments -------------------------------
    2939              : !scalars
    2940              :  integer,intent(in) :: brav,choice,mrpt,nqshft
    2941              :  integer,intent(out) :: nrpt
    2942              : !arrays
    2943              :  integer,intent(in) :: ngqpt(3)
    2944              :  real(dp),intent(in) :: rprim(3,3)
    2945              :  real(dp),intent(out) :: rpt(3,mrpt)
    2946              :  integer,intent(out) :: cell(3,mrpt)
    2947              : 
    2948              : !Local variables -------------------------
    2949              : !In some cases, the atoms coordinates are not packed in the
    2950              : ! [0,1]^3 cube. Then, the parameter "buffer" might be increased,
    2951              : !to search relevant pairs of atoms in bigger boxes than usual.
    2952              : !scalars
    2953              :  integer,parameter :: buffer=1
    2954              :  integer :: irpt,lim1,lim2,lim3,lqshft,r1,r2,r3
    2955              :  character(len=500) :: msg
    2956              : ! *********************************************************************
    2957              : 
    2958          484 :  lqshft=1
    2959          484 :  if(nqshft/=1)lqshft=2
    2960              : 
    2961              : 
    2962              : !Simple Cubic Lattice
    2963          484 :  if (abs(brav)==1) then
    2964          398 :    lim1=((ngqpt(1))+1)*lqshft+buffer
    2965          398 :    lim2=((ngqpt(2))+1)*lqshft+buffer
    2966          398 :    lim3=((ngqpt(3))+1)*lqshft+buffer
    2967          398 :    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
    2968          398 :    if(choice/=0)then
    2969          199 :      if (nrpt/=mrpt) then
    2970            0 :        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
    2971            0 :        ABI_BUG(msg)
    2972              :      end if
    2973          199 :      irpt=0
    2974         2612 :      do r1=-lim1,lim1
    2975        37035 :        do r2=-lim2,lim2
    2976       528549 :          do r3=-lim3,lim3
    2977       491713 :            irpt=irpt+1
    2978       491713 :            rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
    2979       491713 :            rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
    2980       491713 :            rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
    2981       526136 :            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
    2982              :          end do
    2983              :        end do
    2984              :      end do
    2985              :    end if
    2986              : 
    2987              : !  Face Centered Cubic Lattice
    2988           86 :  else if (brav==2) then
    2989           58 :    lim1=((ngqpt(1)+3)/4)*lqshft+buffer
    2990           58 :    lim2=((ngqpt(2)+3)/4)*lqshft+buffer
    2991           58 :    lim3=((ngqpt(3)+3)/4)*lqshft+buffer
    2992           58 :    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*4
    2993           58 :    if(choice/=0)then
    2994           29 :      if (nrpt/=mrpt) then
    2995            0 :        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
    2996            0 :        ABI_BUG(msg)
    2997              :      end if
    2998           29 :      irpt=0
    2999          220 :      do r1=-lim1,lim1
    3000         1497 :        do r2=-lim2,lim2
    3001        10107 :          do r3=-lim3,lim3
    3002         8639 :            irpt=irpt+4
    3003         8639 :            rpt(1,irpt-3)=r1
    3004         8639 :            rpt(2,irpt-3)=r2
    3005         8639 :            rpt(3,irpt-3)=r3
    3006         8639 :            rpt(1,irpt-2)=r1
    3007         8639 :            rpt(2,irpt-2)=r2+0.5
    3008         8639 :            rpt(3,irpt-2)=r3+0.5
    3009         8639 :            rpt(1,irpt-1)=r1+0.5
    3010         8639 :            rpt(2,irpt-1)=r2
    3011         8639 :            rpt(3,irpt-1)=r3+0.5
    3012         8639 :            rpt(1,irpt)=r1+0.5
    3013         8639 :            rpt(2,irpt)=r2+0.5
    3014         8639 :            rpt(3,irpt)=r3
    3015              : !TEST_AM
    3016              : !           cell(irpt-3,1)=r1;cell(irpt-3,2)=r2;cell(irpt-3,3)=r3
    3017         9916 :            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
    3018              :          end do
    3019              :        end do
    3020              :      end do
    3021              :    end if
    3022              : 
    3023              : !  Body Centered Cubic Lattice
    3024           28 :  else if (brav==3) then
    3025           14 :    lim1=((ngqpt(1)+3)/4)*lqshft+buffer
    3026           14 :    lim2=((ngqpt(2)+3)/4)*lqshft+buffer
    3027           14 :    lim3=((ngqpt(3)+3)/4)*lqshft+buffer
    3028           14 :    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*2
    3029           14 :    if(choice/=0)then
    3030            7 :      if(nrpt/=mrpt) then
    3031            0 :        write(msg,'(2(a,i0))')' nrpt= ',nrpt,' is not equal to mrpt= ',mrpt
    3032            0 :        ABI_BUG(msg)
    3033              :      end if
    3034            7 :      irpt=0
    3035           56 :      do r1=-lim1,lim1
    3036          399 :        do r2=-lim2,lim2
    3037         2793 :          do r3=-lim3,lim3
    3038         2401 :            irpt=irpt+2
    3039         2401 :            rpt(1,irpt-1)=r1
    3040         2401 :            rpt(2,irpt-1)=r2
    3041         2401 :            rpt(3,irpt-1)=r3
    3042         2401 :            rpt(1,irpt)=r1+0.5
    3043         2401 :            rpt(2,irpt)=r2+0.5
    3044         2401 :            rpt(3,irpt)=r3+0.5
    3045              : !TEST_AM
    3046              : !           cell(irpt-1,1)=r1;cell(irpt-1,2)=r2;cell(irpt-1,3)=r3
    3047         2744 :            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
    3048              :          end do
    3049              :        end do
    3050              :      end do
    3051              :    end if
    3052              : 
    3053              : !  Hexagonal Lattice
    3054           14 :  else if (brav==4) then
    3055           14 :    lim1=(ngqpt(1)+1)*lqshft+buffer
    3056           14 :    lim2=(ngqpt(2)+1)*lqshft+buffer
    3057           14 :    lim3=((ngqpt(3)/2)+1)*lqshft+buffer
    3058           14 :    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
    3059           14 :    if(choice/=0)then
    3060            7 :      if(nrpt/=mrpt)then
    3061            0 :        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt=',mrpt
    3062            0 :        ABI_BUG(msg)
    3063              :      end if
    3064            7 :      irpt=0
    3065          124 :      do r1=-lim1,lim1
    3066         2275 :        do r2=-lim2,lim2
    3067        23871 :          do r3=-lim3,lim3
    3068        21603 :            irpt=irpt+1
    3069        21603 :            rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
    3070        21603 :            rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
    3071        21603 :            rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
    3072        23754 :            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
    3073              :          end do
    3074              :        end do
    3075              :      end do
    3076              :    end if
    3077              : 
    3078              :  else
    3079            0 :    write(msg,'(a,i0,a)')' The value of brav= ',brav,' is not allowed (should be -1, 1, 2 or 4).'
    3080            0 :    ABI_BUG(msg)
    3081              :  end if
    3082              : 
    3083          484 : end subroutine bigbx9
    3084              : !!***
    3085              : 
    3086              : !----------------------------------------------------------------------
    3087              : 
    3088              : !!****f* m_dynmat/canat9
    3089              : !! NAME
    3090              : !! canat9
    3091              : !!
    3092              : !! FUNCTION
    3093              : !! Transforms an atom whose coordinates (xred*rprim) would not be
    3094              : !! in the chosen unit cell used to generate the interatomic forces
    3095              : !! to its correspondent (rcan) in canonical coordinates.
    3096              : !!
    3097              : !! INPUTS
    3098              : !! brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
    3099              : !! natom= Number of atoms in the unit cell
    3100              : !! rprim(3,3)= Normalized coordinates  of primitive vectors
    3101              : !!
    3102              : !! OUTPUT
    3103              : !! rcan(3,natom)  = Atomic position in canonical coordinates
    3104              : !! trans(3,natom) = Atomic translations : xred = rcan + trans
    3105              : !!
    3106              : !! SOURCE
    3107              : 
    3108              : 
    3109          242 : subroutine canat9(brav,natom,rcan,rprim,trans,xred)
    3110              : 
    3111              : !Arguments -------------------------------
    3112              : !scalars
    3113              :  integer,intent(in) :: brav,natom
    3114              : !arrays
    3115              :  real(dp),intent(in) :: rprim(3,3),xred(3,natom)
    3116              :  real(dp),intent(out) :: rcan(3,natom),trans(3,natom)
    3117              : 
    3118              : !Local variables -------------------------
    3119              : !scalars
    3120              :  integer :: found,iatom,ii
    3121              :  character(len=500) :: msg
    3122              : !arrays
    3123              :  real(dp) :: dontno(3,4),rec(3),rok(3),shift(3),tt(3)
    3124              : ! *********************************************************************
    3125              : 
    3126              : !Normalization of the cartesian atomic coordinates
    3127              : !If not normalized : rcan(i) <- rcan(i) * acell(i)
    3128          881 :  do iatom=1,natom
    3129         2798 :    rcan(:,iatom)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
    3130              :  end do
    3131              : 
    3132              :  !Study of the different cases for the Bravais lattice:
    3133          242 :  if (abs(brav)==1) then
    3134              :    !Simple Cubic Lattice
    3135              : 
    3136          745 :    do iatom=1,natom
    3137              :      ! Canon will produces these coordinate transformations
    3138              :      ! (Note: here we still use reduced coordinates )
    3139          546 :      call wrap2_pmhalf(xred(1,iatom),rok(1),shift(1))
    3140          546 :      call wrap2_pmhalf(xred(2,iatom),rok(2),shift(2))
    3141          546 :      call wrap2_pmhalf(xred(3,iatom),rok(3),shift(3))
    3142              : 
    3143              : !    New coordinates : rcan
    3144         2184 :      rcan(:,iatom)=rok(1)*rprim(:,1)+rok(2)*rprim(:,2)+rok(3)*rprim(:,3)
    3145              : !    Translations between New and Old coordinates
    3146         2184 :      tt(:)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
    3147         2383 :      trans(:,iatom)=tt(:)-rcan(:,iatom)
    3148              :    end do
    3149              : 
    3150           43 :  else if (brav==2) then
    3151              :    ! Face Centered Lattice
    3152              :    ! Special possible translations in the F.C.C. case
    3153           29 :    dontno(:,:)=zero
    3154           29 :    dontno(2,2)=0.5_dp
    3155           29 :    dontno(3,2)=0.5_dp
    3156           29 :    dontno(1,3)=0.5_dp
    3157           29 :    dontno(3,3)=0.5_dp
    3158           29 :    dontno(1,4)=0.5_dp
    3159           29 :    dontno(2,4)=0.5_dp
    3160           87 :    do iatom=1,natom
    3161              :      found=0
    3162          164 :      do ii=1,4
    3163          131 :        if (found==1) exit
    3164              :        ! Canon will produce these coordinate transformations
    3165           77 :        call wrap2_pmhalf(rcan(1,iatom)+dontno(1,ii),rok(1),shift(1))
    3166           77 :        call wrap2_pmhalf(rcan(2,iatom)+dontno(2,ii),rok(2),shift(2))
    3167           77 :        call wrap2_pmhalf(rcan(3,iatom)+dontno(3,ii),rok(3),shift(3))
    3168              :        ! In the F.C.C., ABS[ Ri ] + ABS[ Rj ] < or = 1/2
    3169              :        ! The equal sign hase been treated using a tolerance parameter
    3170              :        ! not to have twice the same point in the unit cell !
    3171           77 :        rok(1)=rok(1)-1.0d-10
    3172           77 :        rok(2)=rok(2)-2.0d-10
    3173           77 :        rok(3)=rok(3)-5.0d-10
    3174          135 :        if (abs(rok(1))+abs(rok(2))<=0.5_dp) then
    3175           62 :          if (abs(rok(1))+abs(rok(3))<=0.5_dp) then
    3176           62 :            if (abs(rok(2))+abs(rok(3))<=0.5_dp) then
    3177          232 :              tt(:)=rcan(:,iatom)
    3178              :              ! New coordinates : rcan
    3179           58 :              rcan(1,iatom)=rok(1)+1.0d-10
    3180           58 :              rcan(2,iatom)=rok(2)+2.0d-10
    3181           58 :              rcan(3,iatom)=rok(3)+5.0d-10
    3182              :              ! Translations between New and Old coordinates
    3183          232 :              trans(:,iatom)=tt(:)-rcan(:,iatom)
    3184              :              found=1
    3185              :            end if
    3186              :          end if
    3187              :        end if
    3188              :      end do
    3189              :    end do
    3190              : 
    3191           14 :  else if (brav==3) then
    3192              :    ! Body Centered Cubic Lattice
    3193              :    ! Special possible translations in the B.C.C. case
    3194           28 :    dontno(:,1)=zero
    3195           28 :    dontno(:,2)=0.5_dp
    3196           14 :    do iatom=1,natom
    3197              :      found=0
    3198           21 :      do ii=1,2
    3199           14 :        if (found==1) exit
    3200              :        ! Canon will produce these coordinate transformations
    3201            7 :        call wrap2_pmhalf(rcan(1,iatom)+dontno(1,ii),rok(1),shift(1))
    3202            7 :        call wrap2_pmhalf(rcan(2,iatom)+dontno(2,ii),rok(2),shift(2))
    3203            7 :        call wrap2_pmhalf(rcan(3,iatom)+dontno(3,ii),rok(3),shift(3))
    3204              :        ! In the F.C.C., ABS[ Ri ] < or = 1/2
    3205              :        ! and    ABS[ R1 ] + ABS[ R2 ] + ABS[ R3 ] < or = 3/4
    3206              :        ! The equal signs have been treated using a tolerance parameter
    3207              :        ! not to have twice the same point in the unit cell !
    3208            7 :        rok(1)=rok(1)-1.0d-10
    3209            7 :        rok(2)=rok(2)-2.0d-10
    3210            7 :        rok(3)=rok(3)-5.0d-10
    3211           14 :        if(abs(rok(1))+abs(rok(2))+abs(rok(3))<=0.75_dp)then
    3212            7 :          if ( abs(rok(1))<=0.5_dp .and. abs(rok(2))<=0.5_dp .and. abs(rok(3))<=0.5_dp) then
    3213           28 :            tt(:)=rcan(:,iatom)
    3214              :            ! New coordinates : rcan
    3215            7 :            rcan(1,iatom)=rok(1)+1.0d-10
    3216            7 :            rcan(2,iatom)=rok(2)+2.0d-10
    3217            7 :            rcan(3,iatom)=rok(3)+5.0d-10
    3218              :            ! Translations between New and Old coordinates
    3219           28 :            trans(:,iatom)=tt(:)-rcan(:,iatom)
    3220              :            found=1
    3221              :          end if
    3222              :        end if
    3223              :      end do
    3224              :    end do
    3225              : 
    3226            7 :  else if (brav==4) then
    3227              :    ! Hexagonal Lattice
    3228              :    ! In this case, it is easier first to work in reduced coordinates space !
    3229           35 :    do iatom=1,natom
    3230              :      ! Passage from the reduced space to the "lozenge" cell
    3231           28 :      rec(1)=xred(1,iatom)-0.5_dp
    3232           28 :      rec(2)=xred(2,iatom)-0.5_dp
    3233           28 :      rec(3)=xred(3,iatom)
    3234              :      ! Canon will produces these coordinate transformations
    3235           28 :      call wrap2_pmhalf(rec(1),rok(1),shift(1))
    3236           28 :      call wrap2_pmhalf(rec(2),rok(2),shift(2))
    3237           28 :      call wrap2_pmhalf(rec(3),rok(3),shift(3))
    3238           28 :      rec(1)=rok(1)+0.5_dp
    3239           28 :      rec(2)=rok(2)+0.5_dp
    3240           28 :      rec(3)=rok(3)
    3241              :      ! Passage in Cartesian Normalized Coordinates
    3242          112 :      rcan(:,iatom)=rec(1)*rprim(:,1)+rec(2)*rprim(:,2)+rec(3)*rprim(:,3)
    3243              :      ! Use of a tolerance parameter not to have twice the same point in the unit cell !
    3244           28 :      rcan(1,iatom)=rcan(1,iatom)-1.0d-10
    3245           28 :      rcan(2,iatom)=rcan(2,iatom)-2.0d-10
    3246              :      ! Passage to the honeycomb hexagonal unit cell !
    3247           28 :      if (rcan(1,iatom)>0.5_dp) then
    3248            6 :        rcan(1,iatom)=rcan(1,iatom)-1.0_dp
    3249              :      end if
    3250           28 :      if (rcan(1,iatom)>zero.and.rcan(1,iatom)+sqrt(3.0_dp)*rcan(2,iatom)>1.0_dp) then
    3251            9 :        rcan(1,iatom)=rcan(1,iatom)-0.5_dp
    3252            9 :        rcan(2,iatom)=rcan(2,iatom)-sqrt(3.0_dp)*0.5_dp
    3253              :      end if
    3254           28 :      if (rcan(1,iatom)<=zero.and.sqrt(3.0_dp)*rcan(2,iatom)-rcan(1,iatom)>1.0_dp) then
    3255            6 :        rcan(1,iatom)=rcan(1,iatom)+0.5_dp
    3256            6 :        rcan(2,iatom)=rcan(2,iatom)-sqrt(3.0_dp)*0.5_dp
    3257              :      end if
    3258              :      ! Translations between New and Old coordinates
    3259          112 :      tt(:)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
    3260          119 :      trans(:,iatom)=tt(:)-rcan(:,iatom)
    3261              :    end do
    3262              : 
    3263              :    ! End of the possible cases for brav : -1, 1, 2, 4.
    3264              :  else
    3265              :    write(msg, '(a,i0,a,a,a)' )&
    3266            0 :    'The required value of brav=',brav,' is not available.',ch10,&
    3267            0 :    'It should be -1, 1,2 or 4 .'
    3268            0 :    ABI_BUG(msg)
    3269              :  end if
    3270              : 
    3271          242 :  call wrtout(std_out,' Canonical Atomic Coordinates ')
    3272          881 :  do iatom=1,natom
    3273          639 :    write(msg, '(a,i5,3es18.8)' )' atom',iatom,rcan(1,iatom),rcan(2,iatom),rcan(3,iatom)
    3274          881 :    call wrtout(std_out,msg)
    3275              :  end do
    3276              : 
    3277          242 : end subroutine canat9
    3278              : !!***
    3279              : 
    3280              : !----------------------------------------------------------------------
    3281              : 
    3282              : !!****f* m_dynmat/canct9
    3283              : !!
    3284              : !! NAME
    3285              : !! canct9
    3286              : !!
    3287              : !! FUNCTION
    3288              : !! Convert from canonical coordinates to cartesian coordinates
    3289              : !! a vector defined by its index=ib+natom*(irpt-1)
    3290              : !!
    3291              : !! INPUTS
    3292              : !! acell(3)=length scales by which rprim is to be multiplied
    3293              : !! gprim(3,3)=dimensionless primitive translations in reciprocal space
    3294              : !! index= index of the atom
    3295              : !! natom=number of atoms in unit cell
    3296              : !! nrpt= Number of R points in the Big Box
    3297              : !! rcan(3,natom)=canonical coordinates of atoms
    3298              : !! rprim(3,3)=dimensionless primitive translations in real space
    3299              : !! rpt(3,nrpt)=canonical coordinates of the points in the BigBox.
    3300              : !!
    3301              : !! OUTPUT
    3302              : !! ib=number of the atom in the unit cell
    3303              : !! irpt= number of the unit cell to which belong the atom
    3304              : !! rcart(3)=cartesian coordinate of the atom indexed by index.
    3305              : !!
    3306              : !! SOURCE
    3307              : 
    3308        24753 : subroutine canct9(acell,gprim,ib,index,irpt,natom,nrpt,rcan,rcart,rprim,rpt)
    3309              : 
    3310              : !Arguments -------------------------------
    3311              : !scalars
    3312              :  integer,intent(in) :: index,natom,nrpt
    3313              :  integer,intent(out) :: ib,irpt
    3314              : !arrays
    3315              :  real(dp),intent(in) :: acell(3),gprim(3,3),rcan(3,natom),rprim(3,3)
    3316              :  real(dp),intent(in) :: rpt(3,nrpt)
    3317              :  real(dp),intent(out) :: rcart(3)
    3318              : 
    3319              : !Local variables -------------------------
    3320              : !scalars
    3321              :  integer :: jj
    3322              : !arrays
    3323              :  real(dp) :: xred(3)
    3324              : ! *********************************************************************
    3325              : 
    3326        24753 :  irpt=(index-1)/natom+1
    3327        24753 :  ib=index-natom*(irpt-1)
    3328              : 
    3329              : !Transform the canonical coordinates to reduced coord.
    3330        99012 :  do jj=1,3
    3331              :    xred(jj)=gprim(1,jj)*(rpt(1,irpt)+rcan(1,ib))&
    3332              : &   +gprim(2,jj)*(rpt(2,irpt)+rcan(2,ib))&
    3333        99012 : &   +gprim(3,jj)*(rpt(3,irpt)+rcan(3,ib))
    3334              :  end do
    3335              : 
    3336              : !Then to cartesian coordinates (here the position of the atom b)
    3337        99012 :  do jj=1,3
    3338              :    rcart(jj)=xred(1)*acell(1)*rprim(jj,1)+&
    3339              : &   xred(2)*acell(2)*rprim(jj,2)+&
    3340        99012 : &   xred(3)*acell(3)*rprim(jj,3)
    3341              :  end do
    3342              : 
    3343        24753 : end subroutine canct9
    3344              : !!***
    3345              : 
    3346              : !----------------------------------------------------------------------
    3347              : 
    3348              : !!****f* m_dynmat/chkrp9
    3349              : !! NAME
    3350              : !! chkrp9
    3351              : !!
    3352              : !! FUNCTION
    3353              : !! Check if the rprim used for the definition of the unit cell (in the
    3354              : !! inputs) are consistent with the rprim used in the routine generating
    3355              : !! the Big Box needed to generate the interatomic forces.
    3356              : !!
    3357              : !! INPUTS
    3358              : !! brav=bravais lattice (1 or -1=simple lattice,2=face centered lattice,
    3359              : !!  3=centered lattice,4=hexagonal lattice)
    3360              : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
    3361              : !!
    3362              : !! OUTPUT
    3363              : !!  (only checking)
    3364              : !!
    3365              : !! SOURCE
    3366              : 
    3367          242 : subroutine chkrp9(brav,rprim)
    3368              : 
    3369              : !Arguments -------------------------------
    3370              : !scalars
    3371              :  integer,intent(in) :: brav
    3372              : !arrays
    3373              :  real(dp),intent(in) :: rprim(3,3)
    3374              : 
    3375              : !Local variables -------------------------
    3376              : !scalars
    3377              :  integer :: ii,jj
    3378              :  character(len=500) :: msg
    3379              : ! *********************************************************************
    3380              : 
    3381          242 :  if (abs(brav)==1) then
    3382              : !  Simple Cubic Lattice No condition in this case !
    3383              :    continue
    3384              : 
    3385           43 :  else if (brav==2) then
    3386              : !  Face Centered Lattice
    3387          116 :    do ii=1,3
    3388          377 :      do jj=1,3
    3389          348 :        if (  ( ii==jj .and. abs(rprim(ii,jj))>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
    3390              :          write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
    3391            0 :          'The input variable rprim does not correspond to the',ch10,&
    3392            0 :          'fixed rprim to be used with brav=2 and ifcflag=1 :',ch10,&
    3393            0 :          '   0  1/2  1/2',ch10,&
    3394            0 :          '  1/2  0   1/2',ch10,&
    3395            0 :          '  1/2 1/2   0 ',ch10,&
    3396            0 :          'Action: rebuild your DDB by using the latter rprim.'
    3397            0 :          ABI_ERROR(msg)
    3398              :        end if
    3399              :      end do
    3400              :    end do
    3401              : 
    3402           14 :  else if (brav==3) then
    3403              : !  Body Centered Cubic Lattice
    3404           28 :    do ii=1,3
    3405           91 :      do jj=1,3
    3406           84 :        if (  ( ii==jj .and. abs(rprim(ii,jj)+.5_dp)>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
    3407              :          write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
    3408            0 :          'The input variable rprim does not correspond to the',ch10,&
    3409            0 :          'fixed rprim to be used with brav=3 and ifcflag=1 :',ch10,&
    3410            0 :          '  -1/2  1/2  1/2',ch10,&
    3411            0 :          '   1/2 -1/2  1/2',ch10,&
    3412            0 :          '   1/2  1/2 -1/2',ch10,&
    3413            0 :          'Action: rebuild your DDB by using the latter rprim.'
    3414            0 :          ABI_ERROR(msg)
    3415              :        end if
    3416              :      end do
    3417              :    end do
    3418              : 
    3419            7 :  else if (brav==4) then
    3420              : !  Hexagonal Lattice
    3421              :    if (abs(rprim(1,1)-1.0_dp)>tol10 .or. &
    3422              :        abs(rprim(3,3)-1.0_dp)>tol10 .or. &
    3423              :        abs(rprim(2,1)      )>tol10 .or. &
    3424              :        abs(rprim(3,1)      )>tol10 .or. &
    3425              :        abs(rprim(1,3)      )>tol10 .or. &
    3426              :        abs(rprim(2,3)      )>tol10 .or. &
    3427              :        abs(rprim(3,2)      )>tol10 .or. &
    3428            7 :        abs(rprim(1,2)+0.5_dp)>tol10 .or. &
    3429              :        abs(rprim(2,2)-0.5_dp*sqrt(3.0_dp))>tol10 ) then
    3430              :      write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
    3431            0 :       'The input variable rprim does not correspond to the',ch10,&
    3432            0 :       'fixed rprim to be used with brav=4 and ifcflag=1 :',ch10,&
    3433            0 :       '   1      0      0',ch10,&
    3434            0 :       '  -1/2 sqrt[3]/2 0',ch10,&
    3435            0 :       '   0      0      1',ch10,&
    3436            0 :       'Action: rebuild your DDB by using the latter rprim.'
    3437            0 :      ABI_ERROR(msg)
    3438              :    end if
    3439              : 
    3440              :  else
    3441              :    write(msg, '(a,i4,a,a,a,a,a)' )&
    3442            0 :    'The value of brav=',brav,' is not allowed.',ch10,&
    3443            0 :    'Only  -1, 1,2,3 or 4 are allowed.',ch10,&
    3444            0 :    'Action: change the value of brav in your input file.'
    3445            0 :    ABI_ERROR(msg)
    3446              :  end if
    3447              : 
    3448          242 : end subroutine chkrp9
    3449              : !!***
    3450              : 
    3451              : !----------------------------------------------------------------------
    3452              : 
    3453              : !!****f* m_dynmat/dist9
    3454              : !! NAME
    3455              : !! dist9
    3456              : !!
    3457              : !! FUNCTION
    3458              : !! Compute the distance between atoms
    3459              : !!
    3460              : !! INPUTS
    3461              : !! acell(3)=length scales by which rprim is to be multiplied
    3462              : !! dist(natom,natom,nrpt)=distances between atoms
    3463              : !! gprim(3,3)=dimensionless primitive translations in reciprocal space
    3464              : !! natom=number of atoms in unit cell
    3465              : !! nrpt= Number of R points in the Big Box
    3466              : !! rcan(3,natom)=canonical coordinates of atoms
    3467              : !! rprim(3,3)=dimensionless primitive translations in real space
    3468              : !! rpt(3,nrpt)=cartesian coordinates of the points in the BigBox.
    3469              : !!
    3470              : !! OUTPUT
    3471              : !! dist(natom,natom,nrpt)=distances between atoms
    3472              : !!
    3473              : !! SOURCE
    3474              : 
    3475           81 : subroutine dist9(acell,dist,gprim,natom,nrpt,rcan,rprim,rpt)
    3476              : 
    3477              : !Arguments -------------------------------
    3478              : !scalars
    3479              :  integer,intent(in) :: natom,nrpt
    3480              : !arrays
    3481              :  real(dp),intent(in) :: acell(3),gprim(3,3),rcan(3,natom),rprim(3,3)
    3482              :  real(dp),intent(in) :: rpt(3,nrpt)
    3483              :  real(dp),intent(out) :: dist(natom,natom,nrpt)
    3484              : 
    3485              : !Local variables -------------------------
    3486              : !scalars
    3487              :  integer :: ia,ib,ii,irpt
    3488              : !arrays
    3489              :  real(dp) :: ra(3),rb(3),rdiff(3),red(3),rptcar(3),xred(3)
    3490              : ! *********************************************************************
    3491              : 
    3492              : !BIG loop on all generic atoms
    3493          338 :  do ia=1,natom
    3494              :    ! First transform canonical coordinates to reduced coordinates
    3495         1028 :    do ii=1,3
    3496         1028 :      xred(ii)=gprim(1,ii)*rcan(1,ia)+gprim(2,ii)*rcan(2,ia)+gprim(3,ii)*rcan(3,ia)
    3497              :    end do
    3498              :    ! Then to cartesian coordinates
    3499         1028 :    ra(:)=xred(1)*acell(1)*rprim(:,1)+xred(2)*acell(2)*rprim(:,2)+xred(3)*acell(3)*rprim(:,3)
    3500         1713 :    do ib=1,natom
    3501         5500 :      do ii=1,3
    3502         5500 :        xred(ii)=gprim(1,ii)*rcan(1,ib)+gprim(2,ii)*rcan(2,ib)+gprim(3,ii)*rcan(3,ib)
    3503              :      end do
    3504         5500 :      do ii=1,3
    3505         5500 :        rb(ii)=xred(1)*acell(1)*rprim(ii,1)+xred(2)*acell(2)*rprim(ii,2)+xred(3)*acell(3)*rprim(ii,3)
    3506              :      end do
    3507       883797 :      do irpt=1,nrpt
    3508              :        ! First transform it to reduced coordinates
    3509      3528660 :        do ii=1,3
    3510      3528660 :          red(ii)=gprim(1,ii)*rpt(1,irpt)+gprim(2,ii)*rpt(2,irpt)+gprim(3,ii)*rpt(3,irpt)
    3511              :        end do
    3512              :        ! Then to cartesian coordinates
    3513      3528660 :        do ii=1,3
    3514      3528660 :          rptcar(ii)=red(1)*acell(1)*rprim(ii,1)+red(2)*acell(2)*rprim(ii,2)+red(3)*acell(3)*rprim(ii,3)
    3515              :        end do
    3516      3528660 :        do ii=1,3
    3517      3528660 :          rdiff(ii)=-rptcar(ii)+ra(ii)-rb(ii)
    3518              :        end do
    3519       883540 :        dist(ia,ib,irpt)=(rdiff(1)**2+rdiff(2)**2+rdiff(3)**2)**0.5
    3520              :      end do
    3521              :    end do
    3522              :  end do
    3523              : 
    3524           81 : end subroutine dist9
    3525              : !!***
    3526              : 
    3527              : !----------------------------------------------------------------------
    3528              : 
    3529              : !!****f* m_dynmat/ftifc_q2r
    3530              : !!
    3531              : !! NAME
    3532              : !! ftifc_q2r
    3533              : !!
    3534              : !! FUNCTION
    3535              : !!  Generates the Fourier transform of the dynamical matrices
    3536              : !!  to obtain interatomic forces (real space).
    3537              : !!
    3538              : !! INPUTS
    3539              : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
    3540              : !! gprim(3,3)= Normalized coordinates in reciprocal space
    3541              : !! natom= Number of atoms in the unit cell
    3542              : !! nqpt= Number of q points in the Brillouin zone
    3543              : !! nrpt= Number of R points in the Big Box
    3544              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    3545              : !!           These coordinates are normalized (=> * acell(3)!!)
    3546              : !! spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
    3547              : !! comm=MPI communicator.
    3548              : !!
    3549              : !! OUTPUT
    3550              : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space.
    3551              : !!
    3552              : !! SOURCE
    3553              : 
    3554          242 : subroutine ftifc_q2r(atmfrc,dynmat,gprim,natom,nqpt,nrpt,rpt,spqpt,comm)
    3555              : 
    3556              : !Arguments -------------------------------
    3557              : !scalars
    3558              :  integer,intent(in) :: natom,nqpt,nrpt,comm
    3559              : !arrays
    3560              :  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
    3561              :  real(dp),intent(out) :: atmfrc(3,natom,3,natom,nrpt)
    3562              :  real(dp),intent(in) :: dynmat(2,3,natom,3,natom,nqpt)
    3563              : 
    3564              : !Local variables -------------------------
    3565              : !scalars
    3566              :  integer :: ia,ib,iqpt,irpt,mu,nu,nprocs,my_rank,ierr
    3567              :  real(dp) :: im,kr,re
    3568              : !arrays
    3569              :  real(dp) :: kk(3)
    3570              : ! *********************************************************************
    3571              : 
    3572          242 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    3573              : 
    3574              :  ! Interatomic Forces from Dynamical Matrices
    3575    112726196 :  atmfrc = zero
    3576       552916 :  do irpt=1,nrpt
    3577       552674 :    if (mod(irpt, nprocs) /= my_rank) cycle ! mpi-parallelism
    3578    162279051 :    do iqpt=1,nqpt
    3579              : 
    3580              :      ! Calculation of the k coordinates in Normalized Reciprocal coordinates
    3581   2102475427 :      kk(:) = matmul(gprim, spqpt(:, iqpt))
    3582              : 
    3583              :      ! Product of k and r
    3584    646915516 :      kr=dot_product(kk,rpt(:,irpt))
    3585              : 
    3586              :      ! Get the phase factor
    3587    161728879 :      re=cos(two_pi*kr)
    3588    161728879 :      im=sin(two_pi*kr)
    3589              : 
    3590              :      ! Now, big inner loops on atoms and directions
    3591              :      ! The indices are ordered to give better speed
    3592    753754264 :      do ib=1,natom
    3593   2527619723 :        do nu=1,3
    3594  12379941907 :          do ia=1,natom
    3595  41830622385 :            do mu=1,3
    3596              :              ! Real part of the interatomic forces
    3597              :              atmfrc(mu,ia,nu,ib,irpt)=atmfrc(mu,ia,nu,ib,irpt) &
    3598              :               +re*dynmat(1,mu,ia,nu,ib,iqpt)&
    3599  40056204252 :               +im*dynmat(2,mu,ia,nu,ib,iqpt)
    3600              :              !The imaginary part should be equal to zero !!!!!!
    3601              :              !atmfrc(2,mu,ia,nu,ib,irpt)=atmfrc(2,mu,ia,nu,ib,irpt) &
    3602              :              !          +re*dynmat(2,mu,ia,nu,ib,iqpt) &
    3603              :              !          -im*dynmat(1,mu,ia,nu,ib,iqpt)
    3604              :            end do
    3605              :          end do
    3606              :        end do
    3607              :      end do
    3608              : 
    3609              :    end do
    3610              :  end do
    3611              : 
    3612          242 :  call xmpi_sum(atmfrc, comm, ierr)
    3613              :  !The sumifc has to be weighted by a normalization factor of 1/nqpt
    3614    112726196 :  atmfrc = atmfrc/nqpt
    3615              : 
    3616          242 : end subroutine ftifc_q2r
    3617              : !!***
    3618              : 
    3619              : !----------------------------------------------------------------------
    3620              : 
    3621              : !!****f* m_dynmat/ftifc_r2q
    3622              : !!
    3623              : !! NAME
    3624              : !! ftifc_r2q
    3625              : !!
    3626              : !! FUNCTION
    3627              : !! Generates the Fourier transform of the interatomic forces
    3628              : !! to obtain dynamical matrices in reciprocal space: R --> q.
    3629              : !!
    3630              : !! INPUTS
    3631              : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
    3632              : !! gprim(3,3)= Normalized coordinates in reciprocal space
    3633              : !! natom= Number of atoms in the unit cell
    3634              : !! nqpt= Number of q points in the Brillouin zone
    3635              : !! nrpt= Number of R points in the Big Box
    3636              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    3637              : !!   These coordinates are normalized (=> * acell(3)!!)
    3638              : !! spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
    3639              : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
    3640              : !! comm: MPI communicator
    3641              : !!
    3642              : !! OUTPUT
    3643              : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
    3644              : !!
    3645              : !! SOURCE
    3646              : 
    3647       314611 : subroutine ftifc_r2q(atmfrc, dynmat, gprim, natom, nqpt, nrpt, rpt, spqpt, wghatm, comm)
    3648              : 
    3649              : !Arguments -------------------------------
    3650              : !scalars
    3651              :  integer,intent(in) :: natom,nqpt,nrpt,comm
    3652              : !arrays
    3653              :  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
    3654              :  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
    3655              :  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
    3656              :  real(dp),intent(out) :: dynmat(2,3,natom,3,natom,nqpt)
    3657              : 
    3658              : !Local variables -------------------------
    3659              : !scalars
    3660              :  integer :: ia,ib,iqpt,irpt,mu,nu,cnt,my_rank,nprocs, ierr
    3661              :  real(dp) :: facti,factr,im,kr,re
    3662              :  !real(dp) : w(2, natom, natom)
    3663              : !arrays
    3664              :  real(dp) :: kk(3)
    3665              : ! *********************************************************************
    3666              : 
    3667       314611 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
    3668     76157170 :  dynmat = zero; cnt = 0
    3669              : 
    3670              :  ! MG: This is an hotspot. I don'tknow whether one should rewrite with BLAS1 dot or not.
    3671              :  ! Note, however, that simply removing the check on the weights inside the loop over atoms.
    3672              :  ! leads to a non-negligible speedup with intel (~30% if dipdip -1 is used)
    3673       629222 :  do iqpt=1,nqpt
    3674              : 
    3675              :    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
    3676      4089943 :    kk(:) = matmul(gprim, spqpt(:, iqpt))
    3677              : 
    3678    146606425 :    do irpt=1,nrpt
    3679    145977203 :      cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! MPI parallelism.
    3680              : 
    3681              :      ! k.R
    3682    583908812 :      kr=dot_product(kk,rpt(:,irpt))
    3683              :      ! Get phase factor
    3684    145977203 :      re = cos(two_pi*kr); im = sin(two_pi*kr)
    3685              : 
    3686              :      ! Inner loop on atoms and directions
    3687    524061670 :      do ib=1,natom
    3688   2101176939 :        do ia=1,natom
    3689              :          !if (abs(wghatm(ia,ib,irpt)) > tol10) then  ! Commented by MG
    3690   1577429880 :            factr = re * wghatm(ia,ib,irpt)
    3691   1577429880 :            facti = im * wghatm(ia,ib,irpt)
    3692   6687489376 :            do nu=1,3
    3693  20506588440 :              do mu=1,3
    3694              :                ! Real and imaginary part of the dynamical matrices
    3695              :                ! Atmfrc should be real
    3696  14196868920 :                dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + factr * atmfrc(mu,ia,nu,ib,irpt)
    3697  18929158560 :                dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + facti * atmfrc(mu,ia,nu,ib,irpt)
    3698              :              end do
    3699              :            end do
    3700              :          !end if
    3701              :        end do
    3702              :      end do
    3703              : 
    3704              :      ! MG: New version: I don't know if it's faster.
    3705              :      !w(1,:,:) = re * wghatm(:,:,irpt)
    3706              :      !w(2,:,:) = im * wghatm(:,:,irpt)
    3707              :      !do ib=1,natom
    3708              :      !  do nu=1,3
    3709              :      !    do ia=1,natom
    3710              :      !      do mu=1,3
    3711              :      !        ! Real and imaginary part of the dynamical matrices
    3712              :      !        ! Atmfrc should be real
    3713              :      !        dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + w(1,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
    3714              :      !        dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + w(2,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
    3715              :      !     end do
    3716              :      !    end do
    3717              :      !  end do
    3718              :      !end do
    3719              : 
    3720              :    end do
    3721              :  end do
    3722              : 
    3723       314611 :  if (nprocs > 1) call xmpi_sum(dynmat, comm, ierr)
    3724              : 
    3725       314611 : end subroutine ftifc_r2q
    3726              : !!***
    3727              : 
    3728              : !----------------------------------------------------------------------
    3729              : 
    3730              : !!****f* m_dynmat/dynmat_dq
    3731              : !!
    3732              : !! NAME
    3733              : !! dynmat_dq
    3734              : !!
    3735              : !! FUNCTION
    3736              : !!  Compute the derivative D(q)/dq of the dynamical matrix via Fourier transform
    3737              : !!  of the interatomic forces
    3738              : !!
    3739              : !! INPUTS
    3740              : !! qpt(3)= Reduced coordinates of the q vector in reciprocal space
    3741              : !! natom= Number of atoms in the unit cell
    3742              : !! gprim(3,3)= Normalized coordinates in reciprocal space
    3743              : !! nrpt= Number of R points in the Big Box
    3744              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    3745              : !!   These coordinates are normalized (=> * acell(3)!!)
    3746              : !! atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
    3747              : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
    3748              : !!
    3749              : !! OUTPUT
    3750              : !! dddq(2,3,natom,3,natom,3)= Derivate of the dynamical matrix in cartesian coordinates.
    3751              : !!  The three directions are stored in the last dimension.
    3752              : !!  These coordinates are normalized (=> * acell(3)!!)
    3753              : !!
    3754              : !! SOURCE
    3755              : 
    3756       227649 : subroutine dynmat_dq(qpt,natom,gprim,nrpt,rpt,atmfrc,wghatm,dddq)
    3757              : 
    3758              : !Arguments -------------------------------
    3759              : !scalars
    3760              :  integer,intent(in) :: natom,nrpt
    3761              : !arrays
    3762              :  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt(3)
    3763              :  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
    3764              :  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
    3765              :  real(dp),intent(out) :: dddq(2,3,natom,3,natom,3)
    3766              : 
    3767              : !Local variables -------------------------
    3768              : !scalars
    3769              :  integer :: ia,ib,irpt,mu,nu,ii
    3770              :  real(dp) :: im,kr,re
    3771              : !arrays
    3772              :  real(dp) :: kk(3),fact(2,3)
    3773              : ! *********************************************************************
    3774              : 
    3775    138876162 :  dddq = zero
    3776    117105202 :  do irpt=1,nrpt
    3777              :    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
    3778   1519408189 :    kk(:) = matmul(gprim, qpt)
    3779              : 
    3780              :    ! Product of k and r
    3781    467510212 :    kr=dot_product(kk,rpt(:,irpt))
    3782              : 
    3783              :    ! Get phase factor
    3784    116877553 :    re=cos(two_pi*kr); im=sin(two_pi*kr)
    3785              : 
    3786              :    ! Inner loop on atoms and directions
    3787    389265835 :    do ib=1,natom
    3788   1359078587 :      do ia=1,natom
    3789   1242201034 :        if (abs(wghatm(ia,ib,irpt))>1.0d-10) then
    3790              :          ! take into account rotation due to i.
    3791   3070003548 :          fact(1,:) = -im * wghatm(ia,ib,irpt) * rpt(:,irpt)
    3792   3070003548 :          fact(2,:) =  re * wghatm(ia,ib,irpt) * rpt(:,irpt)
    3793   3070003548 :          do nu=1,3
    3794   9977511531 :            do mu=1,3
    3795              :              ! Real and imaginary part of the dynamical matrices
    3796              :              ! Atmfrc should be real
    3797  29932534593 :              do ii=1,3
    3798  20722523949 :                dddq(1,mu,ia,nu,ib,ii) = dddq(1,mu,ia,nu,ib,ii) + fact(1,ii) * atmfrc(mu,ia,nu,ib,irpt)
    3799  27630031932 :                dddq(2,mu,ia,nu,ib,ii) = dddq(2,mu,ia,nu,ib,ii) + fact(2,ii) * atmfrc(mu,ia,nu,ib,irpt)
    3800              :              end do
    3801              :            end do
    3802              :          end do
    3803              :        end if
    3804              :      end do
    3805              :    end do
    3806              :  end do
    3807       227649 : end subroutine dynmat_dq
    3808              : !!***
    3809              : 
    3810              : !----------------------------------------------------------------------
    3811              : 
    3812              : !!****f* m_dynmat/ifclo9
    3813              : !! NAME
    3814              : !! ifclo9
    3815              : !!
    3816              : !! FUNCTION
    3817              : !! Convert from cartesian coordinates to local coordinates
    3818              : !! the 3*3 interatomic force constant matrix
    3819              : !!
    3820              : !! INPUTS
    3821              : !! ifccar(3,3)= matrix of interatomic force constants in cartesian
    3822              : !!  coordinates
    3823              : !! vect1(3)= cartesian coordinates of the first local vector
    3824              : !! vect2(3)= cartesian coordinates of the second local vector
    3825              : !! vect3(3)= cartesian coordinates of the third local vector
    3826              : !!
    3827              : !! OUTPUT
    3828              : !! ifcloc(3,3)= matrix of interatomic force constants in local coordinates
    3829              : !!
    3830              : !! SOURCE
    3831              : 
    3832        33615 : subroutine ifclo9(ifccar,ifcloc,vect1,vect2,vect3)
    3833              : 
    3834              : !Arguments -------------------------------
    3835              : !arrays
    3836              :  real(dp),intent(in) :: ifccar(3,3),vect1(3),vect2(3),vect3(3)
    3837              :  real(dp),intent(out) :: ifcloc(3,3)
    3838              : 
    3839              : !Local variables -------------------------
    3840              : !scalars
    3841              :  integer :: ii,jj
    3842              : !arrays
    3843              :  real(dp) :: work(3,3)
    3844              : ! *********************************************************************
    3845              : 
    3846       134460 :  do jj=1,3
    3847       403380 :    do ii=1,3
    3848       403380 :      work(jj,ii)=zero
    3849              :    end do
    3850       436995 :    do ii=1,3
    3851       302535 :      work(jj,1)=work(jj,1)+ifccar(jj,ii)*vect1(ii)
    3852       302535 :      work(jj,2)=work(jj,2)+ifccar(jj,ii)*vect2(ii)
    3853       403380 :      work(jj,3)=work(jj,3)+ifccar(jj,ii)*vect3(ii)
    3854              :    end do
    3855              :  end do
    3856              : 
    3857       134460 :  do jj=1,3
    3858       403380 :    do ii=1,3
    3859       403380 :      ifcloc(ii,jj)=zero
    3860              :    end do
    3861       436995 :    do ii=1,3
    3862       302535 :      ifcloc(1,jj)=ifcloc(1,jj)+vect1(ii)*work(ii,jj)
    3863       302535 :      ifcloc(2,jj)=ifcloc(2,jj)+vect2(ii)*work(ii,jj)
    3864       403380 :      ifcloc(3,jj)=ifcloc(3,jj)+vect3(ii)*work(ii,jj)
    3865              :    end do
    3866              :  end do
    3867              : 
    3868        33615 : end subroutine ifclo9
    3869              : !!***
    3870              : 
    3871              : !----------------------------------------------------------------------
    3872              : 
    3873              : !!****f* m_dynmat/wght9
    3874              : !! NAME
    3875              : !! wght9
    3876              : !!
    3877              : !! FUNCTION
    3878              : !! Generates a weight to each R point of the Big Box and for each pair of atoms
    3879              : !! For each R points included in the space generates by moving
    3880              : !! the unit cell around each atom; the weight will be one.
    3881              : !! Border conditions are provided.
    3882              : !! The R points outside the chosen space will have a 0 weight.
    3883              : !!
    3884              : !! INPUTS
    3885              : !! brav = Bravais lattice (1 or -1=S.C.;2=F.C.C.;4=Hex. -1 is for old algo to find weights, =1 is for Wigner-Seitz algo)
    3886              : !! gprim(3,3)= Normalized coordinates in reciprocal space
    3887              : !! natom= Number of atoms in the unit cell
    3888              : !! ngqpt(6)= Numbers used to sample the Brillouin zone
    3889              : !! nqpt= Number of q points used in the homogeneous grid
    3890              : !!  sampling the Brillouin zone
    3891              : !! nqshft=number of shift vectors in the repeated cell
    3892              : !! nrpt=Number of R points in the Big Box
    3893              : !! qshft(3,nqshft)=vectors that will be used to determine
    3894              : !!  the shifts from (0. 0. 0.)
    3895              : !! rcan(3,natom)=Atomic position in canonical coordinates
    3896              : !! rpt(3,nprt)=Canonical coordinates of the R points in the unit cell
    3897              : !!  These coordinates are normalized (=> * acell(3))
    3898              : !! rprimd(3,3)=dimensional primitive translations for real space (bohr)
    3899              : !! toldist= Tolerance on the distance between two R points.
    3900              : !!
    3901              : !! OUTPUT
    3902              : !! wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
    3903              : !!  The vector r(atom2)-r(atom1)+rpt should be inside the moving box
    3904              : !! r_inscribed_sphere= The radius of the sphere inscribed inside the big box.
    3905              : !! ngqpt(6)= can be modified
    3906              : !!
    3907              : !! SOURCE
    3908              : 
    3909          243 : subroutine wght9(brav,gprim,natom,ngqpt,nqpt,nqshft,nrpt,qshft,rcan,rpt,rprimd,toldist,r_inscribed_sphere,wghatm,ierr)
    3910              : 
    3911              : !Arguments -------------------------------
    3912              : !scalars
    3913              :  integer,intent(in) :: brav,natom,nqpt,nqshft,nrpt
    3914              :  integer,intent(out) :: ierr
    3915              :  real(dp),intent(out) :: r_inscribed_sphere
    3916              :  real(dp),intent(in) :: toldist
    3917              : !arrays
    3918              :  integer,intent(inout) :: ngqpt(9)
    3919              :  real(dp),intent(in) :: gprim(3,3),qshft(3,4),rcan(3,natom),rpt(3,nrpt),rprimd(3,3)
    3920              :  real(dp),intent(out) :: wghatm(natom,natom,nrpt)
    3921              : 
    3922              : !Local variables -------------------------
    3923              : !scalars
    3924              :  integer :: ia,ib,ii,jj,kk,iqshft,irpt,jqshft,nbordh,tok,nptws,nreq,idir
    3925              :  real(dp) :: factor,sumwght,normsq,proj
    3926              :  character(len=500) :: msg
    3927              : !arrays
    3928              :  integer :: nbord(9)
    3929              :  real(dp) :: rdiff(9),red(3,3),ptws(4, 729),pp(3),rdiff_tmp(3)
    3930              : ! *********************************************************************
    3931              : 
    3932          243 :  ierr = 0
    3933              : 
    3934              :  ! First analyze the vectors qshft
    3935          243 :  if (nqshft /= 1) then
    3936              : 
    3937            6 :    if (brav == 4) then
    3938              :      write(msg,'(3a,i0,3a)' )&
    3939            0 :      'For the time being, only nqshft=1',ch10,&
    3940            0 :      'is allowed with brav=4, while it is nqshft=',nqshft,'.',ch10,&
    3941            0 :      'Action: in the input file, correct either brav or nqshft.'
    3942            0 :      ABI_ERROR(msg)
    3943              :    end if
    3944              : 
    3945            6 :    if (nqshft == 2) then
    3946              :      ! Make sure that the q vectors form a BCC lattice
    3947            8 :      do ii=1,3
    3948            8 :        if(abs(abs(qshft(ii,1)-qshft(ii,2))-.5_dp)>1.d-10)then
    3949              :          write(msg, '(a,a,a,a,a,a,a)' )&
    3950            0 :          'The test of the q1shft vectors shows that they',ch10,&
    3951            0 :          'do not generate a body-centered lattice, which',ch10,&
    3952            0 :          'is mandatory for nqshft=2.',ch10,&
    3953            0 :          'Action: change the q1shft vectors in your input file.'
    3954            0 :          ABI_ERROR(msg)
    3955              :        end if
    3956              :      end do
    3957            4 :    else if (nqshft == 4) then
    3958              :      ! Make sure that the q vectors form a FCC lattice
    3959           16 :      do iqshft=1,3
    3960           40 :        do jqshft=iqshft+1,4
    3961              :          tok=0
    3962           96 :          do ii=1,3
    3963              :            ! Test on the presence of a +-0.5 difference
    3964           72 :            if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-.5_dp) <1.d-10) tok=tok+1
    3965              :            ! Test on the presence of a 0 or +-1.0 difference
    3966           72 :            if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-1._dp) <1.d-10  .or.&
    3967          120 :               abs(qshft(ii,iqshft)-qshft(ii,jqshft)) < 1.d-10) tok=tok+4
    3968              :          end do
    3969              :          ! Test 1 should be satisfied twice, and test 2 once
    3970           36 :          if(tok/=6)then
    3971              :            write(msg, '(7a)' )&
    3972            0 :            'The test of the q1shft vectors shows that they',ch10,&
    3973            0 :            'do not generate a face-centered lattice, which',ch10,&
    3974            0 :            'is mandatory for nqshft=4.',ch10,&
    3975            0 :            'Action: change the q1shft vectors in your input file.'
    3976            0 :            ABI_ERROR(msg)
    3977              :          end if
    3978              :        end do
    3979              :      end do
    3980              :    else
    3981              :      write(msg, '(a,i4,3a)' )&
    3982            0 :      'nqshft must be 1, 2 or 4. It is nqshft=',nqshft,'.',ch10,&
    3983            0 :      'Action: change nqshft in your input file.'
    3984            0 :      ABI_ERROR(msg)
    3985              :    end if
    3986              :  end if
    3987              : 
    3988          243 :  factor=0.5_dp
    3989          243 :  if(brav==2 .or. brav==3) factor=0.25_dp
    3990          243 :  if(nqshft/=1)factor=factor*2
    3991              : 
    3992          243 :  if (brav==1) then
    3993              :    ! Does not support multiple shifts
    3994          197 :    if (nqshft/=1) then
    3995            0 :      ABI_ERROR('This version of the weights does not support nqshft/=1.')
    3996              :    end if
    3997              : 
    3998              :    ! Find the points of the lattice given by ngqpt*acell. These are used to define
    3999              :    ! a Wigner-Seitz cell around the origin. The origin is excluded from the list.
    4000              :    ! TODO : in principle this should be only -1 to +1 for ii jj kk!
    4001              :    nptws=0
    4002         1182 :    do ii=-2,2
    4003         6107 :      do jj=-2,2
    4004        30535 :        do kk=-2,2
    4005        98500 :          do idir=1,3
    4006        98500 :            pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
    4007              :          end do
    4008        24625 :          normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
    4009        29550 :          if (normsq > tol6) then
    4010        24428 :            nptws = nptws + 1
    4011        97712 :            ptws(:3,nptws) = pp(:)
    4012        24428 :            ptws(4,nptws) = half*normsq
    4013              :          end if
    4014              :        end do
    4015              :      end do
    4016              :    end do
    4017              :  end if ! end new_wght
    4018              :  !write(std_out,*)'factor,ngqpt',factor,ngqpt(1:3)
    4019              : 
    4020         4617 :  r_inscribed_sphere = sum((matmul(rprimd(:,:),ngqpt(1:3)))**2)
    4021          972 :  do ii=-1,1
    4022         3159 :    do jj=-1,1
    4023         9477 :      do kk=-1,1
    4024         6561 :        if (ii==0 .and. jj==0 .and. kk==0) cycle
    4025        25272 :        do idir=1,3
    4026        25272 :          pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
    4027              :        end do
    4028         6318 :        normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
    4029         8748 :        r_inscribed_sphere = min(r_inscribed_sphere, normsq)
    4030              :      end do
    4031              :    end do
    4032              :  end do
    4033          243 :  r_inscribed_sphere = sqrt(r_inscribed_sphere)
    4034              : 
    4035              : 
    4036              : !Begin the big loop on ia and ib
    4037          886 :  do ia=1,natom
    4038         3665 :    do ib=1,natom
    4039              : 
    4040              :      ! Simple Lattice
    4041         2779 :      if (abs(brav)==1) then
    4042              :        ! In this case, it is better to work in reduced coordinates
    4043              :        ! As rcan is in canonical coordinates, => multiplication by gprim
    4044         9568 :        do ii=1,3
    4045         7176 :          red(1,ii)=  rcan(1,ia)*gprim(1,ii) +rcan(2,ia)*gprim(2,ii) +rcan(3,ia)*gprim(3,ii)
    4046         9568 :          red(2,ii)=  rcan(1,ib)*gprim(1,ii) +rcan(2,ib)*gprim(2,ii) +rcan(3,ib)*gprim(3,ii)
    4047              :        end do
    4048              :      end if
    4049              : 
    4050      8878440 :      do irpt=1,nrpt
    4051              : 
    4052              :        ! Initialization of the weights to 1.0
    4053      8875018 :        wghatm(ia,ib,irpt)=1.0_dp
    4054              : 
    4055              :        ! Compute the difference vector
    4056              : 
    4057              :        ! Simple Cubic Lattice
    4058      8875018 :        if (abs(brav)==1) then
    4059              :          ! Change of rpt to reduced coordinates
    4060     33769080 :          do ii=1,3
    4061     25326810 :            red(3,ii)=  rpt(1,irpt)*gprim(1,ii) +rpt(2,irpt)*gprim(2,ii) +rpt(3,irpt)*gprim(3,ii)
    4062     33769080 :            rdiff(ii)=red(2,ii)-red(1,ii)+red(3,ii)
    4063              :          end do
    4064      8442270 :          if (brav==1) then
    4065              :            ! rdiff in cartesian coordinates
    4066     33072784 :            do ii=1,3
    4067     33072784 :              rdiff_tmp(ii)=rdiff(1)*rprimd(ii,1)+rdiff(2)*rprimd(ii,2)+rdiff(3)*rprimd(ii,3)
    4068              :            end do
    4069     33072784 :            rdiff(1:3)=rdiff_tmp(1:3)
    4070              :          end if
    4071              : 
    4072              :        else
    4073              :          ! Other lattices
    4074      1730992 :          do ii=1,3
    4075      1730992 :            rdiff(ii)=rcan(ii,ib)-rcan(ii,ia)+rpt(ii,irpt)
    4076              :          end do
    4077              :        end if
    4078              : 
    4079              :        ! Assignement of weights
    4080              : 
    4081      8877797 :        if(nqshft==1 .and. brav/=4)then
    4082              : 
    4083      8387270 :          if (brav/=1) then
    4084       476296 :            do ii=1,3
    4085              :              ! If the rpt vector is greater than the allowed space => weight = 0.0
    4086       476296 :              if (abs(rdiff(ii))-tol10>factor*ngqpt(ii)) then
    4087       173985 :                wghatm(ia,ib,irpt)=zero
    4088       183237 :              else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
    4089              :                ! If the point is in a boundary position => weight/2
    4090        35058 :                wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
    4091              :              end if
    4092              :            end do
    4093              :          else
    4094              :            ! new weights
    4095      8268196 :            wghatm(ia,ib,irpt)=zero
    4096      8268196 :            nreq = 1
    4097    344222748 :            do ii=1,nptws
    4098    343774880 :              proj = rdiff(1)*ptws(1,ii)+rdiff(2)*ptws(2,ii)+rdiff(3)*ptws(3,ii)
    4099              :              ! if rdiff closer to ptws than the origin the weight is zero
    4100              :              ! if rdiff close to the origin with respect to all the other ptws the weight is 1
    4101              :              ! if rdiff is equidistant from the origin and N other ptws the weight is 1/(N+1)
    4102    344222748 :              if (proj - ptws(4,ii) > toldist) then
    4103              :                nreq = 0
    4104              :                EXIT
    4105    335954552 :              else if(abs(proj-ptws(4,ii)) <= toldist) then
    4106      1173541 :                nreq=nreq+1
    4107              :              end if
    4108              :            end do
    4109      8268196 :            if (nreq>0) then
    4110       447868 :              wghatm(ia,ib,irpt)=one/DBLE(nreq)
    4111              :            end if
    4112              :          end if
    4113              : 
    4114       487748 :        else if(brav==4)then
    4115              :          ! Hexagonal
    4116              :          ! Examination of the X and Y boundaries in order to form an hexagon
    4117              :          ! First generate the relevant boundaries
    4118       173730 :          rdiff(4)=0.5_dp*( rdiff(1)+sqrt(3.0_dp)*rdiff(2) )
    4119       173730 :          ngqpt(4)=ngqpt(1)
    4120       173730 :          rdiff(5)=0.5_dp*( rdiff(1)-sqrt(3.0_dp)*rdiff(2) )
    4121       173730 :          ngqpt(5)=ngqpt(1)
    4122              : 
    4123              :          ! Test the four inequalities
    4124      1042380 :          do ii=1,5
    4125      1042380 :            if(ii/=2)then
    4126              : 
    4127       694920 :              nbord(ii)=0
    4128              :              ! If the rpt vector is greater than the allowed space => weight = 0.0
    4129       694920 :              if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
    4130       421728 :                wghatm(ia,ib,irpt)=zero
    4131       273192 :              else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
    4132              :                ! If the point is in a boundary position increment nbord(ii)
    4133        30540 :                nbord(ii)=1
    4134              :              end if
    4135              : 
    4136              :            end if
    4137              :          end do
    4138              : 
    4139              :          ! Computation of weights
    4140       173730 :          nbordh=nbord(1)+nbord(4)+nbord(5)
    4141       173730 :          if (nbordh==1) then
    4142        18040 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
    4143       155690 :          else if (nbordh==2) then
    4144         1872 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
    4145       153818 :          else if (nbordh/=0) then
    4146            0 :            ABI_BUG('There is a problem of borders and weights (hex).')
    4147              :          end if
    4148       173730 :          if (nbord(3)==1)then
    4149         8756 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
    4150              :          end if
    4151              : 
    4152       314018 :        else if(nqshft==2 .and. brav/=4)then
    4153              : 
    4154              :          ! BCC packing of k-points
    4155              :          ! First, generate the relevant boundaries
    4156       221575 :          rdiff(4)= rdiff(1)+rdiff(2)
    4157       221575 :          rdiff(5)= rdiff(1)-rdiff(2)
    4158       221575 :          rdiff(6)= rdiff(1)+rdiff(3)
    4159       221575 :          rdiff(7)= rdiff(1)-rdiff(3)
    4160       221575 :          rdiff(8)= rdiff(3)+rdiff(2)
    4161       221575 :          rdiff(9)= rdiff(3)-rdiff(2)
    4162       221575 :          if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
    4163              :            write(msg, '(a,a,a,3i6,a,a,a,a)' )&
    4164            0 :            'In the BCC case, the three ngqpt numbers ',ch10,&
    4165            0 :            '    ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
    4166            0 :            'should be equal.',ch10,&
    4167            0 :            'Action: use identical ngqpt(1:3) in your input file.'
    4168            0 :            ABI_ERROR(msg)
    4169              :          end if
    4170      1551025 :          do ii=4,9
    4171      1551025 :            ngqpt(ii)=ngqpt(1)
    4172              :          end do
    4173              : 
    4174              :          ! Test the relevant inequalities
    4175       221575 :          nbord(1)=0
    4176      1551025 :          do ii=4,9
    4177              :            ! If the rpt vector is greater than the allowed space => weight = 0.0
    4178      1551025 :            if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
    4179      1050176 :              wghatm(ia,ib,irpt)=zero
    4180       279274 :            else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
    4181              :              ! If the point is in a boundary position increment nbord(1)
    4182        86756 :              nbord(1)=nbord(1)+1
    4183              :            end if
    4184              :          end do
    4185              : 
    4186              :          ! Computation of weights
    4187       221575 :          if (nbord(1)==1) then
    4188        59196 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
    4189       162379 :          else if (nbord(1)==2) then
    4190        12268 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
    4191       150111 :          else if (nbord(1)==3) then
    4192          648 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
    4193       149463 :          else if (nbord(1)==4) then
    4194          270 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/6
    4195       149193 :          else if (nbord(1)/=0) then
    4196            0 :            ABI_ERROR(' There is a problem of borders and weights (BCC).')
    4197              :          end if
    4198              : 
    4199        92443 :        else if(nqshft==4 .and. brav/=4)then
    4200              : 
    4201              :          ! FCC packing of k-points
    4202              :          ! First, generate the relevant boundaries
    4203        92443 :          rdiff(4)= (rdiff(1)+rdiff(2)+rdiff(3))*2._dp/3._dp
    4204        92443 :          rdiff(5)= (rdiff(1)-rdiff(2)+rdiff(3))*2._dp/3._dp
    4205        92443 :          rdiff(6)= (rdiff(1)+rdiff(2)-rdiff(3))*2._dp/3._dp
    4206        92443 :          rdiff(7)= (rdiff(1)-rdiff(2)-rdiff(3))*2._dp/3._dp
    4207        92443 :          if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
    4208              :            write(msg, '(a,a,a,3i6,a,a,a,a)' )&
    4209            0 :            'In the FCC case, the three ngqpt numbers ',ch10,&
    4210            0 :            '    ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
    4211            0 :            'should be equal.',ch10,&
    4212            0 :            'Action: use identical ngqpt(1:3) in your input file.'
    4213            0 :            ABI_ERROR(msg)
    4214              :          end if
    4215       462215 :          do ii=4,7
    4216       462215 :            ngqpt(ii)=ngqpt(1)
    4217              :          end do
    4218              : 
    4219              :          ! Test the relevant inequalities
    4220        92443 :          nbord(1)=0
    4221       739544 :          do ii=1,7
    4222              :            ! If the rpt vector is greater than the allowed space => weight = 0.0
    4223       739544 :            if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
    4224       442496 :              wghatm(ia,ib,irpt)=zero
    4225              :              ! If the point is in a boundary position increment nbord(1)
    4226       204605 :            else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
    4227        44182 :              nbord(1)=nbord(1)+1
    4228              :            end if
    4229              :          end do
    4230              : 
    4231              :          ! Computation of weights
    4232        92443 :          if (nbord(1)==1) then
    4233        26290 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
    4234        66153 :          else if (nbord(1)==2) then
    4235         7590 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
    4236        58563 :          else if (nbord(1)==3) then
    4237          664 :            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
    4238        57899 :          else if (nbord(1)/=0 .and. wghatm(ia,ib,irpt)>1.d-10) then
    4239              :            ! Interestingly nbord(1)==4 happens for some points outside of the volume
    4240            0 :            ABI_BUG(' There is a problem of borders and weights (FCC).')
    4241              :          end if
    4242              : 
    4243              :        else
    4244              :          write(msg, '(3a,i0,a)' )&
    4245            0 :          'One should not arrive here ... ',ch10,&
    4246            0 :          'The value nqshft ',nqshft,' is not available'
    4247            0 :          ABI_BUG(msg)
    4248              :        end if
    4249              :      end do ! Assignement of weights is done
    4250              :    end do ! End of the double loop on ia and ib
    4251              :  end do
    4252              : 
    4253              :  ! Check the results
    4254          886 :  do ia=1,natom
    4255         3665 :    do ib=1,natom
    4256              :      sumwght=zero
    4257      8877797 :      do irpt=1,nrpt
    4258              :        ! Check if the sum of the weights is equal to the number of q points
    4259      8877797 :        sumwght=sumwght+wghatm(ia,ib,irpt)
    4260              :        !write(std_out,'(a,3(i0,1x))' )' atom1, atom2, irpt ; rpt ; wghatm ',ia,ib,irpt
    4261              :        !write(std_out,'(3es16.6,es18.6)' )rpt(1,irpt),rpt(2,irpt),rpt(3,irpt),wghatm(ia,ib,irpt)
    4262              :      end do
    4263         3422 :      if (abs(sumwght-nqpt)>tol10) ierr = 1
    4264              :    end do
    4265              :  end do
    4266              : 
    4267          243 : end subroutine wght9
    4268              : !!***
    4269              : 
    4270              : !----------------------------------------------------------------------
    4271              : 
    4272              : !!****f* m_dynmat/d3sym
    4273              : !! NAME
    4274              : !! d3sym
    4275              : !!
    4276              : !! FUNCTION
    4277              : !! Given a set of calculated elements of the 3DTE matrix,
    4278              : !! build (nearly) all the other matrix elements that can be build using symmetries.
    4279              : !!
    4280              : !! INPUTS
    4281              : !!  indsym(4,nsym,natom)=indirect indexing array : for each
    4282              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    4283              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    4284              : !!   translations which must be subtracted after the transformation to get back
    4285              : !!   to the original unit cell.
    4286              : !!  mpert =maximum number of ipert
    4287              : !!  natom= number of atoms
    4288              : !!  nsym=number of space group symmetries
    4289              : !!  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
    4290              : !!  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
    4291              : !!
    4292              : !! SIDE EFFECTS
    4293              : !!  Input/Output
    4294              : !!  blkflg(3,mpert,3,mpert,3,mpert)= matrix that indicates if an
    4295              : !!   element of d3 is available (1 if available, 0 otherwise)
    4296              : !!  d3(2,3,mpert,3,mpert,3,mpert)= matrix of the 3DTE
    4297              : !!
    4298              : !! SOURCE
    4299              : 
    4300           41 : subroutine d3sym(blkflg,d3,indsym,mpert,natom,nsym,symrec,symrel)
    4301              : 
    4302              : !Arguments -------------------------------
    4303              : !scalars
    4304              :  integer,intent(in) :: mpert,natom,nsym
    4305              : !arrays
    4306              :  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
    4307              :  integer,intent(inout) :: blkflg(3,mpert,3,mpert,3,mpert)
    4308              :  real(dp),intent(inout) :: d3(2,3,mpert,3,mpert,3,mpert)
    4309              : 
    4310              : !Local variables -------------------------
    4311              : !scalars
    4312              :  integer :: found,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert,idisy1,idisy2,idisy3
    4313              :  integer :: ipesy1,ipesy2,ipesy3,isym,ithree
    4314              :  real(dp) :: sumi,sumr
    4315              : !arrays
    4316              :  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
    4317              : ! *********************************************************************
    4318              : 
    4319              : !DEBUG
    4320              : !write(std_out,*)'d3sym : enter'
    4321              : !do i1dir = 1, 3
    4322              : !do i2dir = 1, 3
    4323              : !do i3dir = 1, 3
    4324              : !write(std_out,*)i1dir,i2dir,i3dir,blkflg(i1dir,natom+2,i2dir,natom+2,i3dir,natom+2)
    4325              : !end do
    4326              : !end do
    4327              : !end do
    4328              : !stop
    4329              : !ENDDEBUG
    4330              : 
    4331              : !First, take into account the permutations symmetry of
    4332              : !(i1pert,i1dir) and (i3pert,i3dir)
    4333          397 :  do i1pert = 1, mpert
    4334         3665 :    do i2pert = 1, mpert
    4335        36068 :      do i3pert = 1, mpert
    4336              : 
    4337       133044 :        do i1dir = 1, 3
    4338       421772 :          do i2dir = 1, 3
    4339      1265316 :            do i3dir = 1, 3
    4340              : 
    4341       875988 :              if ((blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1).and. &
    4342       291996 : &             (blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert)/=1)) then
    4343              : 
    4344              :                d3(:,i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = &
    4345         3711 : &              d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
    4346              : 
    4347         1237 :                blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = 1
    4348              : 
    4349              :              end if
    4350              : 
    4351              :            end do
    4352              :          end do
    4353              :        end do
    4354              : 
    4355              :      end do
    4356              :    end do
    4357              :  end do
    4358              : 
    4359              : !Big Big Loop : symmetrize three times, because
    4360              : !of some cases in which one element is not yet available
    4361              : !at the first pass, and even at the second one !
    4362              : 
    4363          164 :  do ithree=1,3
    4364              : 
    4365              : !  Loop over perturbations
    4366         1232 :    do i1pert = 1, mpert
    4367        10995 :      do i2pert = 1, mpert
    4368       108204 :        do i3pert = 1, mpert
    4369              : 
    4370       399132 :          do i1dir = 1, 3
    4371      1265316 :            do i2dir = 1, 3
    4372      3795948 :              do i3dir = 1, 3
    4373              : 
    4374              : !              Will get element (idir1,ipert1,idir2,ipert2)
    4375              : !              so this element should not yet be present ...
    4376      3503952 :                if(blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)/=1)then
    4377              : 
    4378      7831485 :                  d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 0_dp
    4379              : 
    4380     47609064 :                  do isym = 1, nsym
    4381              : 
    4382     44998569 :                    found = 1
    4383              : 
    4384     44998569 :                    if (i1pert <= natom) then
    4385      8178639 :                      ipesy1 = indsym(4,isym,i1pert)
    4386    106322307 :                      sym1(:,:) = symrec(:,:,isym)
    4387     36819930 :                    else if (i1pert == natom + 2) then
    4388      3953370 :                      ipesy1 = i1pert
    4389     51393810 :                      sym1(:,:) = symrel(:,:,isym)
    4390              :                    else
    4391              :                      found = 0
    4392              :                    end if
    4393              : 
    4394     44998569 :                    if (i2pert <= natom) then
    4395      8178639 :                      ipesy2 = indsym(4,isym,i2pert)
    4396    106322307 :                      sym2(:,:) = symrec(:,:,isym)
    4397     36819930 :                    else if (i2pert == natom + 2) then
    4398      3953370 :                      ipesy2 = i2pert
    4399     51393810 :                      sym2(:,:) = symrel(:,:,isym)
    4400              :                    else
    4401              :                      found = 0
    4402              :                    end if
    4403              : 
    4404     44998569 :                    if (i3pert <= natom) then
    4405      8178639 :                      ipesy3 = indsym(4,isym,i3pert)
    4406    106322307 :                      sym3(:,:) = symrec(:,:,isym)
    4407     36819930 :                    else if (i3pert == natom + 2) then
    4408      3953370 :                      ipesy3 = i3pert
    4409     51393810 :                      sym3(:,:) = symrel(:,:,isym)
    4410              :                    else
    4411              :                      found = 0
    4412              :                    end if
    4413              : 
    4414     44998569 :                    sumr = 0_dp ; sumi = 0_dp;
    4415    179994276 :                    do idisy1 = 1, 3
    4416    584981397 :                      do idisy2 = 1, 3
    4417   1754944191 :                        do idisy3 = 1, 3
    4418              : 
    4419              :                          if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir,idisy2) /=0) &
    4420   1619948484 : &                         .and.(sym3(i3dir,idisy3) /=0)) then
    4421              : 
    4422    189920457 :                            if (blkflg(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 1) then
    4423              : 
    4424              :                              sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
    4425    144869984 : &                             sym3(i3dir,idisy3)*d3(1,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
    4426              :                              sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
    4427    144869984 : &                             sym3(i3dir,idisy3)*d3(2,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
    4428              : 
    4429              :                            else
    4430              : 
    4431              :                              found = 0
    4432              : 
    4433              :                            end if
    4434              : 
    4435              :                          end if
    4436              : 
    4437              :                        end do
    4438              :                      end do
    4439              :                    end do
    4440              : 
    4441     47609064 :                    if (found == 1) then
    4442        18245 :                      d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumr
    4443        18245 :                      d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumi
    4444        18245 :                      blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
    4445              :                    end if
    4446              : 
    4447              :                  end do  ! isym
    4448              : 
    4449              :                end if  ! blkflg
    4450              : 
    4451              : !              Close loop over perturbations
    4452              :              end do
    4453              :            end do
    4454              :          end do
    4455              :        end do
    4456              :      end do
    4457              :    end do
    4458              : 
    4459              :  end do  ! close loop over ithree
    4460              : 
    4461           41 : end subroutine d3sym
    4462              : !!***
    4463              : 
    4464              : !----------------------------------------------------------------------
    4465              : 
    4466              : !!****f* m_dynmat/sytens
    4467              : !!
    4468              : !! NAME
    4469              : !! sytens
    4470              : !!
    4471              : !! FUNCTION
    4472              : !! Determines the set of irreductible elements of the non-linear
    4473              : !! optical susceptibility and Raman tensors
    4474              : !!
    4475              : !! INPUTS
    4476              : !!  indsym(4,nsym,natom)=indirect indexing array described above: for each
    4477              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    4478              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    4479              : !!   translations which must be subtracted after the transformation to get back
    4480              : !!   to the original unit cell.
    4481              : !!  mpert =maximum number of ipert
    4482              : !!  natom= number of atoms
    4483              : !!  nsym=number of space group symmetries
    4484              : !!  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
    4485              : !!  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
    4486              : !!
    4487              : !! OUTPUT
    4488              : !!  (see side effects)
    4489              : !!
    4490              : !! SIDE EFFECTS
    4491              : !!  rfpert(3,mpert,3,mpert,3,mpert) = array defining the type of perturbations
    4492              : !!       that have to be computed
    4493              : !!    At the input :
    4494              : !!       1   ->   element has to be computed explicitely
    4495              : !!    At the output :
    4496              : !!       1   ->   element has to be computed explicitely
    4497              : !!      -1   ->   use symmetry operations to obtain the corresponding element
    4498              : !!      -2   ->   element is zero by symmetry
    4499              : !!
    4500              : !! SOURCE
    4501              : 
    4502           46 : subroutine sytens(indsym,mpert,natom,nsym,rfpert,symrec,symrel)
    4503              : 
    4504              : !Arguments -------------------------------
    4505              : !scalars
    4506              :  integer,intent(in) :: mpert,natom,nsym
    4507              : !arrays
    4508              :  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
    4509              :  integer,intent(inout) :: rfpert(3,mpert,3,mpert,3,mpert)
    4510              : 
    4511              : !Local variables -------------------------
    4512              : !scalars
    4513              :  integer :: flag,found,i1dir,i1dir_,i1pert,i1pert_,i2dir,i2dir_,i2pert,i2pert_
    4514              :  integer :: i3dir,i3dir_,i3pert,i3pert_,idisy1,idisy2,idisy3,ipesy1,ipesy2
    4515              :  integer :: ipesy3,isym
    4516              : !arrays
    4517              :  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
    4518           46 :  integer,allocatable :: pertsy(:,:,:,:,:,:)
    4519              : !***********************************************************************
    4520              : 
    4521          322 :  ABI_MALLOC(pertsy,(3,mpert,3,mpert,3,mpert))
    4522      1070750 :  pertsy(:,:,:,:,:,:) = 0
    4523              : 
    4524              : !Loop over perturbations
    4525              : 
    4526          386 :  do i1pert_ = 1, mpert
    4527         3302 :    do i2pert_ = 1, mpert
    4528        31988 :      do i3pert_ = 1, mpert
    4529              : 
    4530       117844 :        do i1dir_ = 1, 3
    4531       373516 :          do i2dir_ = 1, 3
    4532      1120548 :            do i3dir_ = 1, 3
    4533              : 
    4534       775764 :              i1pert = (mpert - i1pert_ + 1)
    4535       775764 :              if (i1pert <= natom) i1pert = natom + 1 - i1pert
    4536       775764 :              i2pert = (mpert - i2pert_ + 1)
    4537       775764 :              if (i2pert <= natom) i2pert = natom + 1 - i2pert
    4538       775764 :              i3pert = (mpert - i3pert_ + 1)
    4539       775764 :              if (i3pert <= natom) i3pert = natom + 1 - i3pert
    4540              : 
    4541       775764 :              if (i1pert <= natom) then
    4542              :                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
    4543       618300 :              else if (i2pert <= natom) then
    4544              :                i1dir = i2dir_ ; i2dir = i1dir_ ; i3dir = i3dir_
    4545       497556 :              else if (i3pert <= natom) then
    4546              :                i1dir = i3dir_ ; i2dir = i2dir_ ; i3dir = i1dir_
    4547              :              else
    4548       561060 :                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
    4549              :              end if
    4550              : 
    4551      1034352 :              if (rfpert(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) /= 0) then
    4552              : 
    4553              : !              Loop over all symmetries
    4554              : 
    4555              :                flag = 0
    4556       118983 :                do isym = 1, nsym
    4557              : 
    4558       113997 :                  found = 1
    4559              : 
    4560              : !                Select the symmetric element of i1pert,i2pert,i3pert
    4561              : 
    4562       113997 :                  if (i1pert <= natom) then
    4563        31603 :                    ipesy1 = indsym(4,isym,i1pert)
    4564       410839 :                    sym1(:,:) = symrec(:,:,isym)
    4565        82394 :                  else if (i1pert == natom + 2) then
    4566        82394 :                    ipesy1 = i1pert
    4567      1071122 :                    sym1(:,:) = symrel(:,:,isym)
    4568              :                  else
    4569              :                    found = 0
    4570              :                  end if
    4571              : 
    4572       113997 :                  if (i2pert <= natom) then
    4573        31603 :                    ipesy2 = indsym(4,isym,i2pert)
    4574       410839 :                    sym2(:,:) = symrec(:,:,isym)
    4575        82394 :                  else if (i2pert == natom + 2) then
    4576        82394 :                    ipesy2 = i2pert
    4577      1071122 :                    sym2(:,:) = symrel(:,:,isym)
    4578              :                  else
    4579              :                    found = 0
    4580              :                  end if
    4581              : 
    4582       113997 :                  if (i3pert <= natom) then
    4583        31603 :                    ipesy3 = indsym(4,isym,i3pert)
    4584       410839 :                    sym3(:,:) = symrec(:,:,isym)
    4585        82394 :                  else if (i3pert == natom + 2) then
    4586        82394 :                    ipesy3 = i3pert
    4587      1071122 :                    sym3(:,:) = symrel(:,:,isym)
    4588              :                  else
    4589              :                    found = 0
    4590              :                  end if
    4591              : 
    4592              : !                See if the symmetric element is available and check if some
    4593              : !                of the elements may be zeor. In the latter case, they do not need
    4594              : !                to be computed.
    4595              : 
    4596              : 
    4597              :                  if ((flag /= -1).and.&
    4598       113997 : &                 (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
    4599       113997 :                    flag = sym1(i1dir,i1dir)*sym2(i2dir,i2dir)*sym3(i3dir,i3dir)
    4600              :                  end if
    4601              : 
    4602              : 
    4603       455988 :                  do idisy1 = 1, 3
    4604      1481961 :                    do idisy2 = 1, 3
    4605      4445883 :                      do idisy3 = 1, 3
    4606              : 
    4607      3077919 :                        if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir,idisy2) /= 0).and.&
    4608              : &                       (sym3(i3dir,idisy3) /= 0)) then
    4609       394809 :                          if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
    4610      3077919 :                            found = 0
    4611              : !                          exit      ! exit loop over symmetries
    4612              :                          end if
    4613              :                        end if
    4614              : 
    4615              : 
    4616      3077919 :                        if ((flag == -1).and.&
    4617      1025973 : &                       ((idisy1/=i1dir).or.(idisy2/=i2dir).or.(idisy3/=i3dir))) then
    4618       127890 :                          if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir,idisy2)/=0).and.&
    4619              : &                         (sym3(i3dir,idisy3)/=0)) then
    4620      3077919 :                            flag = 0
    4621              :                          end if
    4622              :                        end if
    4623              : 
    4624              :                      end do
    4625              :                    end do
    4626              :                  end do
    4627              : 
    4628       113997 :                  if (found == 1) then
    4629        42006 :                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -1
    4630              :                  end if
    4631              : 
    4632              : !                In case a symmetry operation only changes the sign of an
    4633              : !                element, this element has to be equal to zero
    4634              : 
    4635       118983 :                  if (flag == -1) then
    4636         2228 :                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -2
    4637         2228 :                    exit
    4638              :                  end if
    4639              : 
    4640              :                end do    ! close loop on symmetries
    4641              : 
    4642              : !              If the elemetn i1pert,i2pert,i3pert is not symmetric
    4643              : !              to a basis element, it is a basis element
    4644              : 
    4645         7214 :                if (pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) > -1) then
    4646         2239 :                  pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
    4647              :                end if
    4648              : 
    4649              :              end if ! rfpert /= 0
    4650              : 
    4651              :            end do        ! close loop over perturbations
    4652              :          end do
    4653              :        end do
    4654              :      end do
    4655              :    end do
    4656              :  end do
    4657              : 
    4658              : !Now, take into account the permutation of (i1pert,i1dir)
    4659              : !and (i3pert,i3dir)
    4660              : 
    4661          386 :  do i1pert = 1, mpert
    4662         3302 :    do i2pert = 1, mpert
    4663        31988 :      do i3pert = 1, mpert
    4664              : 
    4665       117844 :        do i1dir = 1, 3
    4666       373516 :          do i2dir = 1, 3
    4667      1120548 :            do i3dir = 1, 3
    4668              : 
    4669      1034352 :              if ((i1pert /= i3pert).or.(i1dir /= i3dir)) then
    4670              : 
    4671       749520 :                if ((pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) == 1).and.&
    4672              : &               (pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) == 1)) then
    4673          899 :                  pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = -1
    4674              :                end if
    4675              : 
    4676              :              end if
    4677              : 
    4678              :            end do
    4679              :          end do
    4680              :        end do
    4681              : 
    4682              :      end do
    4683              :    end do
    4684              :  end do
    4685              : 
    4686      1070750 :  rfpert(:,:,:,:,:,:) = pertsy(:,:,:,:,:,:)
    4687              : 
    4688           46 :  ABI_FREE(pertsy)
    4689              : 
    4690           46 : end subroutine sytens
    4691              : !!***
    4692              : 
    4693              : 
    4694              : !----------------------------------------------------------------------
    4695              : 
    4696              : !!****f* m_dynmat/axial9
    4697              : !!
    4698              : !! NAME
    4699              : !! axial9
    4700              : !!
    4701              : !! FUNCTION
    4702              : !! Generates the local coordinates system from the
    4703              : !! knowledge of the first vector (longitudinal) and
    4704              : !! the ifc matrix in cartesian coordinates
    4705              : !!
    4706              : !! INPUTS
    4707              : !! ifccar(3,3)= matrix of interatomic force constants in cartesian coordinates
    4708              : !! vect1(3)= cartesian coordinates of the first local vector
    4709              : !!
    4710              : !! OUTPUT
    4711              : !! vect2(3)= cartesian coordinates of the second local vector
    4712              : !! vect3(3)= cartesian coordinates of the third local vector
    4713              : !!
    4714              : !! SOURCE
    4715              : 
    4716        24257 : subroutine axial9(ifccar,vect1,vect2,vect3)
    4717              : 
    4718              : !Arguments -------------------------------
    4719              : !arrays
    4720              :  real(dp),intent(in) :: ifccar(3,3),vect1(3)
    4721              :  real(dp),intent(out) :: vect2(3),vect3(3)
    4722              : 
    4723              : !Local variables -------------------------
    4724              : !scalars
    4725              :  integer :: flag,ii,itrial
    4726              :  real(dp) :: innorm,scprod
    4727              : !arrays
    4728              :  real(dp) :: work(3)
    4729              : ! *********************************************************************
    4730              : 
    4731       315341 :  work (:) = matmul(ifccar,vect1)
    4732              : 
    4733              :  flag=0
    4734        61603 :  do itrial=1,4
    4735              :    scprod=zero
    4736       246412 :    do ii=1,3
    4737       246412 :      scprod=scprod+work(ii)*vect1(ii)
    4738              :    end do
    4739              : 
    4740       246412 :    work(:)=work(:)-vect1(:)*scprod
    4741              : 
    4742       246412 :    scprod=dot_product(work,work)
    4743              : 
    4744        61603 :    if(scprod<1.0d-10)then
    4745        37346 :      work(1:3)=zero
    4746        37346 :      if(itrial>1)work(itrial-1)=1.0_dp
    4747              :    else
    4748              :      flag=1
    4749              :    end if
    4750              : 
    4751            0 :    if(flag==1)exit
    4752              :  end do
    4753              : 
    4754        24257 :  innorm=scprod**(-0.5_dp)
    4755        97028 :  vect2(:)=work(:)*innorm
    4756              : 
    4757        24257 :  vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
    4758        24257 :  vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
    4759        24257 :  vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
    4760              : 
    4761        24257 : end subroutine axial9
    4762              : !!***
    4763              : 
    4764              : !----------------------------------------------------------------------
    4765              : 
    4766              : !!****f* m_dynmat/dymfz9
    4767              : !!
    4768              : !! NAME
    4769              : !! dymfz9
    4770              : !!
    4771              : !! FUNCTION
    4772              : !! As the subroutine canatm has transformed the coordinates of the
    4773              : !! atoms in normalized canonical coordinates, the corresponding
    4774              : !! dynamical matrix should be multiplied by a phase shift corresponding
    4775              : !! to the translation between New and Old coordinates of its two
    4776              : !! corresponding atoms.
    4777              : !!
    4778              : !! INPUTS
    4779              : !! dynmat = non-phase shifted dynamical matrices
    4780              : !! natom = number of atoms
    4781              : !! nqpt = number of qpoints
    4782              : !! gprim = reciprocal lattice vectors (cartesian but dimensionless)
    4783              : !! option=1 : the matrices are transformed from the old (tn)
    4784              : !!  coordinate system to the new (normalized canonical)
    4785              : !!        2 : the matrices are restored from the normalized
    4786              : !!  canonical coordinate system to the usual (tn) one...
    4787              : !! rcan = canonical coordinates of atoms
    4788              : !! spqpt = qpoint coordinates (reduced reciprocal)
    4789              : !! trans = Atomic translations : xred = rcan + trans
    4790              : !!
    4791              : !! OUTPUT
    4792              : !! dynmat = phase shifted dynamical matrices
    4793              : !!
    4794              : !! SOURCE
    4795              : 
    4796       997800 : subroutine dymfz9(dynmat,natom,nqpt,gprim,option,spqpt,trans)
    4797              : 
    4798              : !Arguments -------------------------------
    4799              : !scalars
    4800              :  integer,intent(in) :: natom,nqpt,option
    4801              : !arrays
    4802              :  real(dp),intent(in) :: gprim(3,3),spqpt(3,nqpt),trans(3,natom)
    4803              :  real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
    4804              : 
    4805              : !Local variables -------------------------
    4806              : !scalars
    4807              :  integer :: ia,ib,iqpt,mu,nu
    4808              :  real(dp) :: im,ktrans,re
    4809              : !arrays
    4810              :  real(dp) :: kk(3)
    4811              : ! *********************************************************************
    4812              : 
    4813      2021658 :  do iqpt=1,nqpt
    4814              :    ! Definition of q in normalized reciprocal space
    4815     13310154 :    kk(:) = matmul(gprim, spqpt(:, iqpt))
    4816              : 
    4817              : 
    4818      1023858 :    if(option==1)then
    4819       105200 :      kk(:)=-kk(:)
    4820              :    end if
    4821              : 
    4822      4207150 :    do ia=1,natom
    4823     10451434 :      do ib=1,natom
    4824              :        ! Product of q with the differences between the two atomic translations
    4825      7242084 :        ktrans=kk(1)*(trans(1,ia)-trans(1,ib))+kk(2)*(trans(2,ia)-trans(2,ib))+kk(3)*(trans(3,ia)-trans(3,ib))
    4826     31153828 :        do mu=1,3
    4827     94147092 :          do nu=1,3
    4828     65178756 :            re=dynmat(1,mu,ia,nu,ib,iqpt)
    4829     65178756 :            im=dynmat(2,mu,ia,nu,ib,iqpt)
    4830              :            ! Transformation of the Old dynamical matrices by New ones by multiplication by a phase shift
    4831     65178756 :            dynmat(1,mu,ia,nu,ib,iqpt)=re*cos(two_pi*ktrans)-im*sin(two_pi*ktrans)
    4832     86905008 :            dynmat(2,mu,ia,nu,ib,iqpt)=re*sin(two_pi*ktrans)+im*cos(two_pi*ktrans)
    4833              :          end do
    4834              :        end do
    4835              :      end do
    4836              :    end do
    4837              :  end do
    4838              : 
    4839       997800 : end subroutine dymfz9
    4840              : !!***
    4841              : 
    4842              : !----------------------------------------------------------------------
    4843              : 
    4844              : !!****f* m_dynmat/nanal9
    4845              : !!
    4846              : !! NAME
    4847              : !! nanal9
    4848              : !!
    4849              : !! FUNCTION
    4850              : !! If plus=0 then substracts the non-analytical part from one dynamical
    4851              : !!           matrices, with number iqpt.
    4852              : !! If plus=1 then adds the non-analytical part to the dynamical
    4853              : !!           matrices, with number iqpt.
    4854              : !!
    4855              : !! For plus=0, see Eq.(76) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
    4856              : !! get the left hand side.
    4857              : !!
    4858              : !! INPUTS
    4859              : !! dyew(2,3,natom,3,natom)= Non-analytical part
    4860              : !! natom= Number of atoms in the unit cell
    4861              : !! iqpt= Referenced q point for the dynamical matrix
    4862              : !! nqpt= Number of q points
    4863              : !! plus= (see above)
    4864              : !!
    4865              : !! OUTPUT
    4866              : !! dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
    4867              : !!
    4868              : !! SOURCE
    4869              : 
    4870        76903 : subroutine nanal9(dyew,dynmat,iqpt,natom,nqpt,plus)
    4871              : 
    4872              : !Arguments -------------------------------
    4873              : !scalars
    4874              :  integer,intent(in) :: iqpt,natom,nqpt,plus
    4875              : !arrays
    4876              :  real(dp),intent(in) :: dyew(2,3,natom,3,natom)
    4877              :  real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
    4878              : 
    4879              : !Local variables -------------------------
    4880              : !scalars
    4881              :  integer :: ia,ib,mu,nu
    4882              :  character(len=500) :: msg
    4883              : ! *********************************************************************
    4884              : 
    4885        76903 :  if (plus==0) then
    4886              : 
    4887        49959 :    do ia=1,natom
    4888       211388 :      do ib=1,natom
    4889       684307 :        do mu=1,3
    4890      2098577 :          do nu=1,3
    4891              :            ! The following four lines are OK
    4892      1452861 :            dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) - dyew(1,mu,ia,nu,ib)
    4893      1937148 :            dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) - dyew(2,mu,ia,nu,ib)
    4894              :          end do
    4895              :        end do
    4896              :      end do
    4897              :    end do
    4898              : 
    4899        65535 :  else if (plus==1) then
    4900       230792 :    do ia=1,natom
    4901       812383 :      do ib=1,natom
    4902      2491621 :        do mu=1,3
    4903      7560683 :          do nu=1,3
    4904      5234319 :            dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) + dyew(1,mu,ia,nu,ib)
    4905      6979092 :            dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) + dyew(2,mu,ia,nu,ib)
    4906              :          end do
    4907              :        end do
    4908              :      end do
    4909              :    end do
    4910              : 
    4911              :  else
    4912              :    write(msg,'(3a,i0,a)' )&
    4913            0 :     'The argument "plus" must be equal to 0 or 1.',ch10,&
    4914            0 :     'The value: ',plus,' is not available.'
    4915            0 :    ABI_BUG(msg)
    4916              :  end if
    4917              : 
    4918        76903 : end subroutine nanal9
    4919              : !!***
    4920              : 
    4921              : !----------------------------------------------------------------------
    4922              : 
    4923              : !!****f* m_dynmat/gtdyn9
    4924              : !!
    4925              : !! NAME
    4926              : !! gtdyn9
    4927              : !!
    4928              : !! FUNCTION
    4929              : !! Generates a dynamical matrix from interatomic force
    4930              : !! constants and long-range electrostatic interactions.
    4931              : !!
    4932              : !! INPUTS
    4933              : !! acell(3)=length scales by which rprim is to be multiplied
    4934              : !! atmfrc(3,natom,3,natom,nrpt) = Interatomic Forces in real space
    4935              : !! dielt(3,3) = dielectric tensor
    4936              : !! dipdip= if 0, no dipole-dipole interaction was subtracted in atmfrc
    4937              : !!  if 1, atmfrc has been build without dipole-dipole part
    4938              : !! dyewq0(3,3,natom)= Ewald part of the dynamical matrix, at q=0.
    4939              : !! gmet(3,3)= metric tensor in reciprocal space.
    4940              : !! gprim(3,3)= Normalized coordinates in reciprocal space
    4941              : !! mpert =maximum number of ipert
    4942              : !! natom= Number of atoms in the unit cell
    4943              : !! nrpt= Number of R points in the Big Box
    4944              : !! qphnrm= Normalisation coefficient for qpt
    4945              : !! qpt(3)= Reduced coordinates of the q vectors in reciprocal space
    4946              : !! rmet(3,3)= Metric tensor in real space.
    4947              : !! rprim(3,3)= dimensionless primitive translations in real space
    4948              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    4949              : !!  These coordinates are normalized (=> * acell(3)!!)
    4950              : !! trans(3,natom)= Atomic translations : xred = rcan + trans
    4951              : !! ucvol= unit cell volume
    4952              : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
    4953              : !! xred(3,natom)= relative coords of atoms in unit cell (dimensionless)
    4954              : !! zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
    4955              : !! comm=MPI communicator.
    4956              : !! [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
    4957              : !! [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part
    4958              : !!
    4959              : !! OUTPUT
    4960              : !! d2cart(2,3,mpert,3,mpert)=dynamical matrix obtained for the wavevector qpt (normalized using qphnrm)
    4961              : !! eta: parameter used to split R and G-space summation
    4962              : !!
    4963              : !! SOURCE
    4964              : 
    4965       314611 : subroutine gtdyn9(acell,atmfrc,dielt,dipdip,dyewq0,d2cart,gmet,gprim,mpert,natom,&
    4966       314611 :                   nrpt,qphnrm,qpt,rmet,rprim,rpt,trans,ucvol,wghatm,xred,zeff,qdrp_cart,ewald_option,eta,comm,&
    4967              :                   sys_dim,dipquad,quadquad,dielt_env,dielt_thick)  ! optional
    4968              : 
    4969              : !Arguments -------------------------------
    4970              : !scalars
    4971              :  integer,intent(in) :: dipdip,mpert,natom,nrpt,ewald_option,comm,sys_dim
    4972              :  real(dp),intent(in) :: qphnrm,ucvol
    4973              :  real(dp),optional,intent(in) :: dielt_env
    4974              :  integer,optional,intent(in) :: dipquad, quadquad
    4975              : !arrays
    4976              :  real(dp), optional,intent(in):: dielt_thick(2)
    4977              :  real(dp),intent(in) :: acell(3),dielt(3,3),gmet(3,3),gprim(3,3),qpt(3)
    4978              :  real(dp),intent(in) :: rmet(3,3),rprim(3,3),rpt(3,nrpt)
    4979              :  real(dp),intent(in) :: trans(3,natom),wghatm(natom,natom,nrpt),xred(3,natom)
    4980              :  real(dp),intent(in) :: zeff(3,3,natom)
    4981              :  real(dp),intent(in) :: qdrp_cart(3,3,3,natom)
    4982              :  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
    4983              :  real(dp),intent(in) :: dyewq0(3,3,natom)
    4984              :  real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert), eta
    4985              : 
    4986              : !Local variables -------------------------
    4987              : !scalars
    4988              :  integer,parameter :: nqpt1 = 1, option2 = 2, sumg0 = 0, plus1 = 1, iqpt1 = 1
    4989              :  integer :: i1, i2, ib, nsize, dipquad_, quadquad_
    4990              : !arrays
    4991              :  real(dp) :: qphon(3) !, tsec(2)
    4992       314611 :  real(dp),allocatable :: dq(:,:,:,:,:),dyew(:,:,:,:,:)
    4993              : ! *********************************************************************
    4994              : 
    4995              :  ! Keep track of time spent in gtdyn9
    4996              :  !call timab(1750, 1, tsec)
    4997              : 
    4998      1573055 :  ABI_MALLOC(dq,(2,3,natom,3,natom))
    4999              : 
    5000              :  ! Define quadrupolar options
    5001       314611 :  dipquad_=0; if(present(dipquad)) dipquad_=dipquad
    5002       314611 :  quadquad_=0; if(present(quadquad)) quadquad_=quadquad
    5003              : 
    5004              :  ! Get the normalized wavevector
    5005       314611 :  if(abs(qphnrm)<1.0d-7)then
    5006        18502 :    qphon(1:3)=zero
    5007              :  else
    5008      1184436 :    qphon(1:3)=qpt(1:3)/qphnrm
    5009              :  end if
    5010              : 
    5011              :  ! Generate the analytical part from the interatomic forces
    5012       314611 :  call ftifc_r2q(atmfrc, dq, gprim, natom, nqpt1, nrpt, rpt, qphon, wghatm, comm)
    5013              : 
    5014              :  ! The analytical dynamical matrix dq has been generated
    5015              :  ! in the normalized canonical coordinate system.
    5016              :  ! Now, the phase is modified, in order to recover the usual (xred) coordinate of atoms.
    5017       314611 :  call dymfz9(dq,natom,nqpt1,gprim,option2,qphon,trans)
    5018              : 
    5019       314611 :  if (dipdip==1.or.dipquad_==1.or.quadquad_==1) then
    5020              :    ! Add the non-analytical part
    5021              :    ! Compute dyew(2,3,natom,3,natom)= Ewald part of the dynamical matrix,
    5022              :    ! second energy derivative wrt xred(3,natom) in Hartrees (Denoted A-bar in the notes)
    5023       196605 :    ABI_MALLOC(dyew,(2,3,natom,3,natom))
    5024        65535 :    if (sys_dim==1) then ! 3D case
    5025              :      call ewald9(acell,dielt,dyew,gmet,gprim,natom,qphon,rmet,rprim,sumg0,ucvol,xred,zeff,&
    5026        65313 :         qdrp_cart,eta,option=ewald_option,dipquad=dipquad_,quadquad=quadquad_)
    5027          222 :    elseif (sys_dim<5) then
    5028          222 :      call ewald9_2D(natom,acell,xred,rprim,dielt,dyew,qpt,zeff,qdrp_cart,dielt_env,dielt_thick,sys_dim)
    5029              :    end if
    5030              : 
    5031        65535 :    call q0dy3_apply(natom,dyewq0,dyew)
    5032        65535 :    call nanal9(dyew,dq,iqpt1,natom,nqpt1,plus1)
    5033              : 
    5034        65535 :    ABI_FREE(dyew)
    5035              :  end if
    5036              : 
    5037              :  ! Copy the dynamical matrix in the proper location
    5038              :  ! First zero all the elements
    5039       314611 :  nsize=2*(3*mpert)**2
    5040   1074744173 :  d2cart = zero
    5041              : 
    5042              :  ! Copy the elements from dq to d2cart
    5043     75842559 :  d2cart(:,:,1:natom,:,1:natom)=dq(:,:,1:natom,:,1:natom)
    5044              : 
    5045              :  ! In case we have the gamma point,
    5046       314611 :  if(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)then
    5047              :    ! Copy the effective charge and dielectric constant in the final array
    5048        77368 :    do i1=1,3
    5049       251446 :      do i2=1,3
    5050       174078 :        d2cart(1,i1,natom+2,i2,natom+2)=dielt(i1,i2)
    5051       582960 :        do ib=1,natom
    5052       350856 :          d2cart(1,i1,natom+2,i2,ib)=zeff(i1,i2,ib)
    5053       524934 :          d2cart(1,i2,ib,i1,natom+2)=zeff(i1,i2,ib)
    5054              :        end do
    5055              :      end do
    5056              :    end do
    5057              :  end if
    5058              : 
    5059       314611 :  ABI_FREE(dq)
    5060              : 
    5061              :  !call timab(1750, 2, tsec)
    5062              : 
    5063       314611 : end subroutine gtdyn9
    5064              : !!***
    5065              : 
    5066              : !----------------------------------------------------------------------
    5067              : 
    5068              : !!****f* m_dynmat/dfpt_phfrq
    5069              : !! NAME
    5070              : !! dfpt_phfrq
    5071              : !!
    5072              : !! FUNCTION
    5073              : !! Get the phonon frequencies and eigenvectors (as well as the corresponding displacements)
    5074              : !! If q is at Gamma, the non-analytical behaviour can be included.
    5075              : !! Then, the effective dielectric tensor, the effective charges
    5076              : !! and oscillator strengths for the limiting direction are also returned
    5077              : !!
    5078              : !! INPUTS
    5079              : !!  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
    5080              : !!  d2cart(2,3,mpert,3,mpert)=dynamical matrix, effective charges, dielectric tensor,.... all in cartesian coordinates
    5081              : !!  indsym(4,msym*natom)=indirect indexing array : for each
    5082              : !!   isym,iatom, fourth element is label of atom into which iatom is sent by
    5083              : !!   INVERSE of symmetry operation isym; first three elements are the primitive
    5084              : !!   translations which must be subtracted after the transformation to get back to the original unit cell.
    5085              : !!  mpert =maximum number of ipert
    5086              : !!  msym=maximum number of symmetries
    5087              : !!  natom=number of atoms in unit cell
    5088              : !!  nsym=number of space group symmetries
    5089              : !!  ntypat=number of atom types
    5090              : !!  qphnrm=(described above)
    5091              : !!  qphon(3)= to be divided by qphnrm, give the phonon wavevector;
    5092              : !!     if qphnrm==0.0_dp, then the wavevector is zero (Gamma point)
    5093              : !!     and qphon gives the direction of the induced electric field in **CARTESIAN** coordinates.
    5094              : !!     in the latter case, if qphon is zero, no non-analytical contribution is included.
    5095              : !!  rprimd(3,3)=dimensional primitive translations (bohr)
    5096              : !!  symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
    5097              : !!  symrel(3,3,nsym)=matrices of the group symmetries (real space)
    5098              : !!  typat(natom)=integer label of each type of atom (1,2,...)
    5099              : !!  ucvol=unit cell volume
    5100              : !!
    5101              : !! OUTPUT
    5102              : !!  displ(2*3*natom*3*natom)= at the end, contains the displacements of atoms in cartesian coordinates.
    5103              : !!    The first index means either the real or the imaginary part,
    5104              : !!    The second index runs on the direction and the atoms displaced
    5105              : !!    The third index runs on the modes.
    5106              : !!  eigval(3*natom)=contains the eigenvalues of the dynamical matrix
    5107              : !!  eigvec(2*3*natom*3*natom)= at the end, contains the eigenvectors of the dynamical matrix in cartesian coordinates.
    5108              : !!  phfrq(3*natom)=phonon frequencies (square root of the dynamical matrix eigenvalues,
    5109              : !!    except if these are negative, and in this case, give minus the square root of the absolute value
    5110              : !!    of the matrix eigenvalues). Hartree units.
    5111              : !!
    5112              : !! NOTES
    5113              : !!   1) One makes the dynamical matrix hermitian...
    5114              : !!   2) In case of q=Gamma, only the real part is used.
    5115              : !!      (MR: Modified since at finite omega imaginary components may arise
    5116              : !!      also at Gamma in broken time-reversal symmetry crystals)
    5117              : !!
    5118              : !! SOURCE
    5119              : 
    5120       372977 : subroutine dfpt_phfrq(amu,displ,d2cart,eigval,eigvec,indsym,&
    5121       372977 : & mpert,msym,natom,nsym,ntypat,phfrq,qphnrm,qphon,rprimd,&
    5122       372977 : & symdynmat,symrel,symafm,typat,ucvol)
    5123              : 
    5124              : !Arguments -------------------------------
    5125              : !scalars
    5126              :  integer,intent(in) :: mpert,msym,natom,nsym,ntypat,symdynmat
    5127              :  real(dp),intent(in) :: qphnrm,ucvol
    5128              : !arrays
    5129              :  integer,intent(in) :: indsym(4,msym*natom),symrel(3,3,nsym),typat(natom)
    5130              :  integer,intent(in) :: symafm(nsym)
    5131              :  real(dp),intent(in) :: amu(ntypat),d2cart(2,3,mpert,3,mpert),rprimd(3,3)
    5132              :  real(dp),intent(inout) :: qphon(3)
    5133              :  real(dp),intent(out) :: displ(2*3*natom*3*natom),eigval(3*natom)
    5134              :  real(dp),intent(out) :: eigvec(2*3*natom*3*natom),phfrq(3*natom)
    5135              : 
    5136              : !Local variables -------------------------
    5137              : !scalars
    5138              :  integer :: analyt,i1,i2,idir1,idir2,ier,ii,imode,ipert1,ipert2
    5139              :  integer :: jmode,indexi,indexj,index
    5140              :  real(dp) :: epsq,qphon2
    5141              :  logical,parameter :: debug = .False.
    5142              :  real(dp) :: sc_prod
    5143              : !arrays
    5144              :  real(dp) :: qptn(3),dum(2,0) !, tsec(2)
    5145       372977 :  real(dp),allocatable :: matrx(:,:),zeff(:,:),zhpev1(:,:),zhpev2(:)
    5146              : ! *********************************************************************
    5147              : 
    5148              :  ! Keep track of time spent in dfpt_phfrq
    5149              :  !call timab(1751, 1, tsec)
    5150              : 
    5151              :  ! GA: I find it strange that both msym and nsym are needed here.
    5152              :  !     Moreover, there is an inconsistency in the dimensions of indsym
    5153              :  !     when it is passed to symdyma.
    5154              :  !     TODO: eliminate msym.
    5155              : 
    5156              :  ! Prepare the diagonalisation: analytical part.
    5157              :  ! Note: displ is used as work space here
    5158       372977 :  i1=0
    5159      1200027 :  do ipert1=1,natom
    5160      3681177 :    do idir1=1,3
    5161      2481150 :      i1=i1+1
    5162      2481150 :      i2=0
    5163     11434708 :      do ipert2=1,natom
    5164     34987182 :        do idir2=1,3
    5165     24379524 :          i2=i2+1
    5166     24379524 :          index=i1+3*natom*(i2-1)
    5167     24379524 :          displ(2*index-1)=d2cart(1,idir1,ipert1,idir2,ipert2)
    5168     32506032 :          displ(2*index  )=d2cart(2,idir1,ipert1,idir2,ipert2)
    5169              :        end do
    5170              :      end do
    5171              :    end do
    5172              :  end do
    5173              : 
    5174              :  ! Determine the analyticity of the matrix.
    5175       372977 :  analyt=1; if(abs(qphnrm)<tol8) analyt=0
    5176       372977 :  if(abs(qphon(1))<tol8.and.abs(qphon(2))<tol8.and.abs(qphon(3))<tol8) analyt=2
    5177              : 
    5178              :  ! In case of q=Gamma, only the real part is used
    5179       372977 :  if(analyt==0 .or. analyt==2)then
    5180       620040 :    do i1=1,3*natom
    5181      4449135 :      do i2=1,3*natom
    5182      3829095 :        index=i1+3*natom*(i2-1)
    5183      4369350 :        if (abs(displ(2*index)) < tol14) displ(2*index)=zero
    5184              :      end do
    5185              :    end do
    5186              :  end if
    5187              : 
    5188              :  ! In the case the non-analyticity is required:
    5189              :  ! the tensor is in cartesian coordinates and this means that qphon must be in given in Cartesian coordinates.
    5190        79785 :  if(analyt==0)then
    5191              : 
    5192              :    ! Normalize the limiting direction
    5193        78727 :    qphon2=qphon(1)**2+qphon(2)**2+qphon(3)**2
    5194       314908 :    qphon(:)=qphon(:)/sqrt(qphon2)
    5195              : 
    5196              :    ! Get the dielectric constant for the limiting direction
    5197              :    epsq=zero
    5198       314908 :    do idir1=1,3
    5199      1023451 :      do idir2=1,3
    5200       944724 :        epsq= epsq + qphon(idir1)*qphon(idir2) * d2cart(1,idir1,natom+2,idir2,natom+2)
    5201              :      end do
    5202              :    end do
    5203              : 
    5204       236181 :    ABI_MALLOC(zeff,(3,natom))
    5205              : 
    5206              :    ! Get the effective charges for the limiting direction
    5207       314908 :    do idir1=1,3
    5208       847738 :      do ipert1=1,natom
    5209       532830 :        zeff(idir1,ipert1)=zero
    5210      2367501 :        do idir2=1,3
    5211      2131320 :          zeff(idir1,ipert1) = zeff(idir1,ipert1) + qphon(idir2)* d2cart(1,idir1,ipert1,idir2,natom+2)
    5212              :        end do
    5213              :      end do
    5214              :    end do
    5215              : 
    5216              :    ! Get the non-analytical part of the dynamical matrix, and suppress its imaginary part.
    5217              :    i1=0
    5218       256337 :    do ipert1=1,natom
    5219       789167 :      do idir1=1,3
    5220       532830 :        i1=i1+1
    5221       532830 :        i2=0
    5222      1958770 :        do ipert2=1,natom
    5223      5526150 :          do idir2=1,3
    5224      3744990 :            i2=i2+1
    5225      3744990 :            index=i1+3*natom*(i2-1)
    5226      3744990 :            displ(2*index-1)=displ(2*index-1)+four_pi/ucvol*zeff(idir1,ipert1)*zeff(idir2,ipert2)/epsq
    5227      4993320 :            if (abs(displ(2*index)) < tol14) displ(2*index)=zero
    5228              :          end do
    5229              :        end do
    5230              :      end do
    5231              :    end do
    5232              : 
    5233        78727 :    ABI_FREE(zeff)
    5234              :  end if !  End of the non-analyticity treatment
    5235              : 
    5236              :  ! Multiply IFC(q) by masses
    5237       372977 :  call massmult_and_breaksym(natom, ntypat, typat, amu, displ)
    5238              :  ! ***********************************************************************
    5239              :  ! Diagonalize the dynamical matrix
    5240              : 
    5241              :  !Symmetrize the dynamical matrix
    5242              :  !FIXME: swap the next 2 lines and update test files to include symmetrization
    5243              :  !       for Gamma point too (except in non-analytic case)
    5244              :  !if (symdynmat==1 .and. analyt > 0) then
    5245       372977 :  if (symdynmat==1 .and. analyt == 1) then
    5246       287699 :    qptn(:)=qphon(:)
    5247      1150796 :    if (analyt==1) qptn(:)=qphon(:)/qphnrm
    5248       287699 :    call symdyma(displ,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
    5249              :  end if
    5250              : 
    5251       372977 :  ii=1
    5252      1118931 :  ABI_MALLOC(matrx,(2,(3*natom*(3*natom+1))/2))
    5253      2854127 :  do i2=1,3*natom
    5254     16284464 :    do i1=1,i2
    5255     13430337 :      matrx(1,ii)=displ(1+2*(i1-1)+2*(i2-1)*3*natom)
    5256     13430337 :      matrx(2,ii)=displ(2+2*(i1-1)+2*(i2-1)*3*natom)
    5257     15911487 :      ii=ii+1
    5258              :    end do
    5259              :  end do
    5260              : 
    5261      1118931 :  ABI_MALLOC(zhpev1,(2,2*3*natom-1))
    5262      1118931 :  ABI_MALLOC(zhpev2,(3*3*natom-2))
    5263              : 
    5264       372977 :  call ZHPEV ('V','U',3*natom,matrx,eigval,eigvec,3*natom,zhpev1,zhpev2,ier)
    5265       372977 :  ABI_CHECK(ier == 0, sjoin('zhpev returned:', itoa(ier)))
    5266              : 
    5267       372977 :  ABI_FREE(matrx)
    5268       372977 :  ABI_FREE(zhpev1)
    5269       372977 :  ABI_FREE(zhpev2)
    5270              : 
    5271              :  if (debug) then
    5272              :    ! Check the orthonormality of the eigenvectors
    5273              :    do imode=1,3*natom
    5274              :      do jmode=imode,3*natom
    5275              :        indexi=2*3*natom*(imode-1)
    5276              :        indexj=2*3*natom*(jmode-1)
    5277              :        sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
    5278              :        write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
    5279              :      end do
    5280              :    end do
    5281              :  end if
    5282              :  !***********************************************************************
    5283              : 
    5284              :  ! Get the phonon frequencies (negative by convention, if the eigenvalue of the dynamical matrix is negative)
    5285      2854127 :  do imode=1,3*natom
    5286      2854127 :    if(eigval(imode)>=1.0d-16)then
    5287      2263797 :      phfrq(imode)=sqrt(eigval(imode))
    5288       217353 :    else if(eigval(imode)>=-1.0d-16)then
    5289       158407 :      phfrq(imode)=zero
    5290              :    else
    5291        58946 :      phfrq(imode)=-sqrt(-eigval(imode))
    5292              :    end if
    5293              :  end do
    5294              : 
    5295              :  ! Fix the phase of the eigenvectors
    5296       372977 :  call fxphas_seq(eigvec,dum, 0, 0, 1, 3*natom*3*natom, 0, 3*natom, 3*natom, 0)
    5297              : 
    5298              :  ! Normalise the eigenvectors
    5299       372977 :  call pheigvec_normalize(natom, eigvec)
    5300              : 
    5301              :  ! Get the phonon displacements
    5302       372977 :  call phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
    5303              : 
    5304              :  if (debug) then
    5305              :    write(std_out,'(a)')' Phonon eigenvectors and displacements '
    5306              :    do imode=1,3*natom
    5307              :      indexi=2*3*natom*(imode-1)
    5308              :      write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' eigvec(1:6*natom)=',eigvec(indexi+1:indexi+6*natom)
    5309              :      write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' displ(1:6*natom)=',displ(indexi+1:indexi+6*natom)
    5310              :    end do
    5311              : 
    5312              :    ! Check the orthonormality of the eigenvectors
    5313              :    do imode=1,3*natom
    5314              :      do jmode=imode,3*natom
    5315              :        indexi=2*3*natom*(imode-1)
    5316              :        indexj=2*3*natom*(jmode-1)
    5317              :        sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
    5318              :        write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
    5319              :      end do
    5320              :    end do
    5321              :  end if
    5322              : 
    5323              :  !call timab(1751, 2, tsec)
    5324              : 
    5325       372977 : end subroutine dfpt_phfrq
    5326              : !!***
    5327              : 
    5328              : !----------------------------------------------------------------------
    5329              : 
    5330              : !!****f* m_dynmat/pheigvec_normalize
    5331              : !!
    5332              : !! NAME
    5333              : !! pheigvec_normalize
    5334              : !!
    5335              : !! FUNCTION
    5336              : !!  Normalize input eigenvectors in cartesian coordinates
    5337              : !!
    5338              : !! INPUTS
    5339              : !!  natom: number of atoms in unit cell
    5340              : !!
    5341              : !! SIDE EFFECTS
    5342              : !!  eigvec(2*3*natom*3*natom)=in output the normalized eigenvectors in cartesian coordinates.
    5343              : !!
    5344              : !! SOURCE
    5345              : 
    5346       373007 : pure subroutine pheigvec_normalize(natom, eigvec)
    5347              : 
    5348              : !Arguments -------------------------------
    5349              : !scalars
    5350              :  integer,intent(in) :: natom
    5351              : !arrays
    5352              :  real(dp),intent(inout) :: eigvec(2*3*natom*3*natom)
    5353              : 
    5354              : !Local variables -------------------------
    5355              : !scalars
    5356              :  integer :: i1,idir1,imode,ipert1,index
    5357              :  real(dp) :: norm
    5358              : ! *********************************************************************
    5359              : 
    5360      2854697 :  do imode=1,3*natom
    5361              : 
    5362              :    norm=zero
    5363      9926760 :    do idir1=1,3
    5364     34316004 :      do ipert1=1,natom
    5365     24389244 :        i1=idir1+(ipert1-1)*3
    5366     24389244 :        index=i1+3*natom*(imode-1)
    5367     31834314 :        norm=norm+eigvec(2*index-1)**2+eigvec(2*index)**2
    5368              :      end do
    5369              :    end do
    5370      2481690 :    norm=sqrt(norm)
    5371              : 
    5372     10299767 :    do idir1=1,3
    5373     34316004 :      do ipert1=1,natom
    5374     24389244 :        i1=idir1+(ipert1-1)*3
    5375     24389244 :        index=i1+3*natom*(imode-1)
    5376     24389244 :        eigvec(2*index-1)=eigvec(2*index-1)/norm
    5377     31834314 :        eigvec(2*index)=eigvec(2*index)/norm
    5378              :      end do
    5379              :    end do
    5380              : 
    5381              :  end do
    5382              : 
    5383       373007 : end subroutine pheigvec_normalize
    5384              : !!***
    5385              : 
    5386              : !----------------------------------------------------------------------
    5387              : 
    5388              : !!****f* m_dynmat/phdispl_from_eigvec
    5389              : !! NAME
    5390              : !! phdispl_from_eigvec
    5391              : !!
    5392              : !! FUNCTION
    5393              : !!  Phonon displacements in cart coords from eigenvectors
    5394              : !!
    5395              : !! INPUTS
    5396              : !!  natom: number of atoms in unit cell
    5397              : !!  ntypat=number of atom types
    5398              : !!  typat(natom)=integer label of each type of atom (1,2,...)
    5399              : !!  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
    5400              : !!  eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.
    5401              : !!
    5402              : !! OUTPUT
    5403              : !!  displ(2*3*natom*3*natom)=displacements of atoms in cartesian coordinates.
    5404              : !!
    5405              : !! SOURCE
    5406              : 
    5407       379832 : pure subroutine phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
    5408              : 
    5409              : !Arguments -------------------------------
    5410              : !scalars
    5411              :  integer,intent(in) :: natom, ntypat
    5412              : !arrays
    5413              :  integer,intent(in) :: typat(natom)
    5414              :  real(dp),intent(in) :: amu(ntypat)
    5415              :  real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
    5416              :  real(dp),intent(out) :: displ(2*3*natom*3*natom)
    5417              : 
    5418              : !Local variables -------------------------
    5419              : !scalars
    5420              :  integer :: i1,idir1,imode,ipert1, index
    5421              : ! *********************************************************************
    5422              : 
    5423      2899916 :  do imode=1,3*natom
    5424              : 
    5425     10460168 :    do idir1=1,3
    5426     34692276 :      do ipert1=1,natom
    5427     24611940 :        i1=idir1+(ipert1-1)*3
    5428     24611940 :        index=i1+3*natom*(imode-1)
    5429     24611940 :        displ(2*index-1)=eigvec(2*index-1) / sqrt(amu(typat(ipert1))*amu_emass)
    5430     32172192 :        displ(2*index  )=eigvec(2*index  ) / sqrt(amu(typat(ipert1))*amu_emass)
    5431              :      end do
    5432              :    end do
    5433              : 
    5434              :  end do
    5435              : 
    5436       379832 : end subroutine phdispl_from_eigvec
    5437              : !!***
    5438              : 
    5439              : !!****f* m_dynmat/phangmom_from_eigvec
    5440              : !! NAME
    5441              : !! phangmom_from_eigvec
    5442              : !!
    5443              : !! FUNCTION
    5444              : !!  Phonon angular momenta in cart coords from eigenvectors
    5445              : !!
    5446              : !! INPUTS
    5447              : !!  natom: number of atoms in unit cell
    5448              : !!  eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.
    5449              : !!
    5450              : !! OUTPUT
    5451              : !!  phangmom(3*3*natom)= angular momentum of each phonon mode in cartesian coordinates.
    5452              : !!    The first index runs on the direction,
    5453              : !!    The second index runs on the modes.
    5454              : !!
    5455              : !! SOURCE
    5456              : 
    5457         3178 : pure subroutine phangmom_from_eigvec(natom, eigvec, phangmom)
    5458              : 
    5459              : !Arguments -------------------------------
    5460              : !scalars
    5461              :  integer,intent(in) :: natom
    5462              : !arrays
    5463              :  real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
    5464              :  real(dp),intent(out) :: phangmom(3*3*natom)
    5465              : 
    5466              : !Local variables -------------------------
    5467              : !scalars
    5468              :  integer :: imode,ipert, index
    5469              : !arrays
    5470              :  real(dp) :: eigvecatom(2*3)
    5471              : ! *********************************************************************
    5472              : 
    5473        75907 :  phangmom = zero
    5474              : 
    5475        27421 :  do imode=1,3*natom
    5476       110704 :    do ipert=1,natom
    5477        83283 :      index = 3*natom*(imode-1) + 3*(ipert-1)
    5478       582981 :      eigvecatom = eigvec(2*index+1 : 2*index + 2*3) ! = Re(u_x), Im(u_x), Re(u_y), Im(u_y), Re(u_z), Im(u_z)
    5479              :      phangmom(3*(imode-1)+1) = phangmom(3*(imode-1)+1)&
    5480        83283 :              + two * (eigvecatom(3) * eigvecatom(6) - eigvecatom(4) * eigvecatom(5)) ! Re(u_y)*Im(u_z) - Im(u_y)*Re(u_z)
    5481              :      phangmom(3*(imode-1)+2) = phangmom(3*(imode-1)+2)&
    5482        83283 :              + two * (eigvecatom(5) * eigvecatom(2) - eigvecatom(6) * eigvecatom(1)) ! Re(u_z)*Im(u_x) - Im(u_z)*Re(u_x)
    5483              :      phangmom(3*(imode-1)+3) = phangmom(3*(imode-1)+3)&
    5484       107526 :              + two * (eigvecatom(1) * eigvecatom(4) - eigvecatom(2) * eigvecatom(3)) ! Re(u_x)*Im(u_y) - Im(u_x)*Re(u_y)
    5485              :    end do
    5486              :  end do
    5487              : 
    5488         3178 : end subroutine phangmom_from_eigvec
    5489              : !!***
    5490              : 
    5491              : !!****f* m_dynmat/dfpt_prtph
    5492              : !! NAME
    5493              : !! dfpt_prtph
    5494              : !!
    5495              : !! FUNCTION
    5496              : !! Print the phonon frequencies, on unit 6 as well as the printing
    5497              : !! unit (except if the associated number -iout- is negative),
    5498              : !! and for the latter, in Hartree, meV, Thz, Kelvin or cm-1.
    5499              : !! If eivec==1,2, also print the eigenmodes : displacements in cartesian coordinates.
    5500              : !! If eivec==4, generate output files for band2eps (drawing tool for the phonon band structure
    5501              : !!
    5502              : !! INPUTS
    5503              : !!  displ(2,3*natom,3*natom)= contains the displacements of atoms in cartesian coordinates.
    5504              : !!  The first index means either the real or the imaginary part,
    5505              : !!  The second index runs on the direction and the atoms displaced
    5506              : !!  The third index runs on the modes.
    5507              : !!  eivec=(if eivec==0, the eigendisplacements are not printed,
    5508              : !!    if eivec==1,2, the eigendisplacements are printed,
    5509              : !!    if eivec==4, files for band2eps
    5510              : !!  enunit=units for output of the phonon frequencies :
    5511              : !!    0=> Hartree and cm-1, 1=> eV and Thz, other=> Ha,Thz,eV,cm-1 and K
    5512              : !!  iout= unit for long print (if negative, the routine only print on unit 6, and in Hartree only).
    5513              : !!  natom= number of atom
    5514              : !!  phfrq(3*natom)= phonon frequencies in Hartree
    5515              : !!  qphnrm=phonon wavevector normalisation factor
    5516              : !!  qphon(3)=phonon wavevector
    5517              : !!
    5518              : !! OUTPUT
    5519              : !!  Only printing
    5520              : !!
    5521              : !! NOTES
    5522              : !! called by one processor only
    5523              : !!
    5524              : !! SOURCE
    5525              : 
    5526         1967 : subroutine dfpt_prtph(displ,eivec,enunit,iout,natom,phfrq,qphnrm,qphon)
    5527              : 
    5528              : !Arguments -------------------------------
    5529              : !scalars
    5530              :  integer,intent(in) :: eivec,enunit,iout,natom
    5531              :  real(dp),intent(in) :: qphnrm
    5532              : !arrays
    5533              :  real(dp),intent(in) :: displ(2,3*natom,3*natom),phfrq(3*natom),qphon(3)
    5534              : 
    5535              : !Local variables -------------------------
    5536              : !scalars
    5537              :  integer :: i,idir,ii,imode,jj
    5538              :  real(dp) :: tolerance
    5539              :  logical :: t_degenerate
    5540              :  character(len=500) :: msg
    5541              : !arrays
    5542              :  real(dp) :: vecti(3),vectr(3)
    5543         3934 :  character(len=1) :: metacharacter(3*natom)
    5544              : ! *********************************************************************
    5545              : 
    5546              : !Check the value of eivec
    5547         3829 :  if (all(eivec /= [0,1,2,4])) then
    5548              :    write(msg, '(a,i0,a,a)' )&
    5549            0 :    'In the calling subroutine, eivec is',eivec,ch10,&
    5550            0 :    'but allowed values are between 0 and 4.'
    5551            0 :    ABI_BUG(msg)
    5552              :  end if
    5553              : 
    5554              : !write the phonon frequencies on unit std_out
    5555         1967 :  write(msg,'(4a)' )' ',ch10,' phonon wavelength (reduced coordinates) , ','norm, and energies in hartree'
    5556         1967 :  call wrtout(std_out,msg)
    5557              : 
    5558              : !The next format should be rewritten
    5559         1967 :  write(msg,'(a,4f5.2)' )' ',(qphon(i),i=1,3),qphnrm
    5560         1967 :  call wrtout(std_out,msg)
    5561         6726 :  do jj=1,3*natom,5
    5562         4759 :    if (3*natom-jj<5) then
    5563         1967 :      write(msg,'(5es17.9)') (phfrq(ii),ii=jj,3*natom)
    5564              :    else
    5565         2792 :      write(msg,'(5es17.9)') (phfrq(ii),ii=jj,jj+4)
    5566              :    end if
    5567         6726 :    call wrtout(std_out,msg)
    5568              :  end do
    5569        20657 :  write(msg,'(a,a,es17.9)') ch10,' Zero Point Motion energy (sum of freqs/2)=',sum(phfrq(1:3*natom))/2
    5570         1967 :  call wrtout(std_out,msg)
    5571              : 
    5572              : !Put the wavevector in nice format
    5573         1967 :  if(iout>=0)then
    5574         1931 :    call wrtout(iout,' ')
    5575         1931 :    if(qphnrm/=0.0_dp)then
    5576              :      write(msg, '(a,3f9.5)' )&
    5577         6632 :      '  Phonon wavevector (reduced coordinates) :',(qphon(i)/qphnrm+tol10,i=1,3)
    5578              :    else
    5579              :      write(msg, '(3a,3f9.5)' )&
    5580          273 :      '  Phonon at Gamma, with non-analyticity in the',ch10,&
    5581         1365 :      '  direction (cartesian coordinates)',qphon(1:3)+tol10
    5582              :    end if
    5583         1931 :    call wrtout(iout,msg)
    5584              : 
    5585              : !  Write it, in different units.
    5586         1931 :    if(enunit/=1)then
    5587         1931 :      write(iout, '(a)' )' Phonon energies in Hartree :'
    5588         6582 :      do jj=1,3*natom,5
    5589         4651 :        if (3*natom-jj<5) then
    5590         1931 :          write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,3*natom)
    5591              :        else
    5592         2720 :          write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,jj+4)
    5593              :        end if
    5594         6582 :        call wrtout(iout,msg)
    5595              :      end do
    5596              :    end if
    5597         1931 :    if(enunit/=0)then
    5598          158 :      write(iout, '(a)' )' Phonon energies in meV     :'
    5599          388 :      do jj=1,3*natom,5
    5600          230 :        if (3*natom-jj<5) then
    5601          488 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,3*natom)
    5602              :        else
    5603          432 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,jj+4)
    5604              :        end if
    5605          388 :        call wrtout(iout,msg)
    5606              :      end do
    5607              :    end if
    5608         1931 :    if(enunit/=1)then
    5609         1931 :      write(iout, '(a)' )' Phonon frequencies in cm-1    :'
    5610         6582 :      do jj=1,3*natom,5
    5611         4651 :        if (3*natom-jj<5) then
    5612         6577 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,3*natom)
    5613              :        else
    5614        16320 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,jj+4)
    5615              :        end if
    5616         6582 :        call wrtout(iout,msg)
    5617              :      end do
    5618              :    end if
    5619         1931 :    if(enunit/=0)then
    5620          158 :      write(iout, '(a)' )' Phonon frequencies in Thz     :'
    5621          388 :      do jj=1,3*natom,5
    5622          230 :        if (3*natom-jj<5) then
    5623          488 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,3*natom)
    5624              :        else
    5625          432 :          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,jj+4)
    5626              :        end if
    5627          388 :        call wrtout(iout,msg)
    5628              :      end do
    5629              :    end if
    5630         1931 :    if(enunit/=0.and.enunit/=1)then
    5631          158 :      write(iout, '(a)' )' Phonon energies in Kelvin  :'
    5632          388 :      do jj=1,3*natom,5
    5633          230 :        if (3*natom-jj<5) then
    5634          488 :          write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,3*natom)
    5635              :        else
    5636          432 :          write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,jj+4)
    5637              :        end if
    5638          388 :        call wrtout(iout,msg)
    5639              :      end do
    5640              :    end if
    5641              :  end if
    5642              : 
    5643              : !Take care of the eigendisplacements
    5644         1967 :  if(eivec==1 .or. eivec==2)then
    5645           83 :    write(msg, '(a,a,a,a,a,a,a,a)' ) ch10,&
    5646           83 :    ' Eigendisplacements ',ch10,&
    5647           83 :    ' (will be given, for each mode : in cartesian coordinates',ch10,&
    5648           83 :    '   for each atom the real part of the displacement vector,',ch10,&
    5649          166 :    '   then the imaginary part of the displacement vector - absolute values smaller than 1.0d-7 are set to zero)'
    5650           83 :    call wrtout(std_out,msg)
    5651           83 :    if(iout>=0) then
    5652           83 :      call wrtout(iout,msg)
    5653              :    end if
    5654              : 
    5655              : !  Examine the degeneracy of each mode. The portability of the echo of the eigendisplacements
    5656              : !  is very hard to obtain, and has not been attempted.
    5657          452 :    do imode=1,3*natom
    5658              : !    The degenerate modes are not portable
    5659          369 :      t_degenerate=.false.
    5660          369 :      if(imode>1)then
    5661          286 :        if(phfrq(imode)-phfrq(imode-1)<tol6)t_degenerate=.true.
    5662              :      end if
    5663          369 :      if(imode<3*natom)then
    5664          286 :        if(phfrq(imode+1)-phfrq(imode)<tol6)t_degenerate=.true.
    5665              :      end if
    5666          452 :      metacharacter(imode)=';'; if(t_degenerate)metacharacter(imode)='-'
    5667              :    end do
    5668              : 
    5669          452 :    do imode=1,3*natom
    5670          369 :      write(msg,'(a,i4,a,es16.6)' )'  Mode number ',imode,'   Energy',phfrq(imode)
    5671          369 :      call wrtout(std_out,msg)
    5672          369 :      if(iout>=0)then
    5673          369 :        write(msg, '(a,i4,a,es16.6)' )'  Mode number ',imode,'   Energy',phfrq(imode)
    5674          369 :        call wrtout(iout,msg)
    5675              :      end if
    5676          369 :      tolerance=1.0d-7
    5677          369 :      if(abs(phfrq(imode))<1.0d-5)tolerance=2.0d-7
    5678          369 :      if(phfrq(imode)<1.0d-5)then
    5679          202 :        write(msg,'(3a)' )' Attention : low frequency mode.',ch10,&
    5680          404 :        '   (Could be unstable or acoustic mode)'
    5681          202 :        call wrtout(std_out,msg)
    5682          202 :        if(iout>=0)then
    5683          202 :          write(iout, '(3a)' )' Attention : low frequency mode.',ch10,&
    5684          404 :          '   (Could be unstable or acoustic mode)'
    5685              :        end if
    5686              :      end if
    5687         1277 :      do ii=1,natom
    5688         3300 :        do idir=1,3
    5689         2475 :          vectr(idir)=displ(1,idir+(ii-1)*3,imode)
    5690         2475 :          if(abs(vectr(idir))<tolerance)vectr(idir)=0.0_dp
    5691         2475 :          vecti(idir)=displ(2,idir+(ii-1)*3,imode)
    5692         3300 :          if(abs(vecti(idir))<tolerance)vecti(idir)=0.0_dp
    5693              :        end do
    5694          825 :        write(msg,'(i4,3es16.8,a,4x,3es16.8)' ) ii,vectr(:),ch10,vecti(:)
    5695          825 :        call wrtout(std_out,msg)
    5696         1194 :        if(iout>=0)then
    5697          825 :          write(msg,'(a,i3,3es16.8,2a,3x,3es16.8)') metacharacter(imode),ii,vectr(:),ch10,&
    5698         1650 :            metacharacter(imode), vecti(:)
    5699          825 :          call wrtout(iout,msg)
    5700              :        end if
    5701              :      end do
    5702              :    end do
    5703              :  end if
    5704              : 
    5705         1967 : end subroutine dfpt_prtph
    5706              : !!***
    5707              : 
    5708              : !!****f* m_dynmat/massmult_and_breaksym
    5709              : !! NAME
    5710              : !!  mult_masses_and_break_symms
    5711              : !!
    5712              : !! FUNCTION
    5713              : !!  Multiply the IFC(q) by the atomic masses, slightly break symmetry to make tests more
    5714              : !!  portable and make the matrix hermitian before returning.
    5715              : !!
    5716              : !! INPUTS
    5717              : !!  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
    5718              : !!  natom=number of atoms in unit cell
    5719              : !!  ntypat=number of atom types
    5720              : !!  typat(natom)=integer label of each type of atom (1,2,...)
    5721              : !!  [herm_opt]= 1 to hermitianize mat (default)
    5722              : !!              0 if no symmetrization should be performed
    5723              : !!
    5724              : !! SIDE EFFECTS
    5725              : !!  mat(2*3*natom*3*natom)=Multiplies by atomic masses in output.
    5726              : !!
    5727              : !! SOURCE
    5728              : 
    5729      1056608 : subroutine massmult_and_breaksym(natom, ntypat, typat, amu, mat, &
    5730              :                                  herm_opt) ! optional
    5731              : 
    5732              : !Arguments -------------------------------
    5733              : !scalars
    5734              :  integer,intent(in) :: natom,ntypat
    5735              :  integer,optional,intent(in) :: herm_opt
    5736              : !arrays
    5737              :  integer,intent(in) :: typat(natom)
    5738              :  real(dp),intent(in) :: amu(ntypat)
    5739              :  real(dp),intent(inout) :: mat(2*3*natom*3*natom)
    5740              : 
    5741              : !Local variables -------------------------
    5742              : !scalars
    5743              :  integer :: i1,i2,idir1,idir2,index,ipert1,ipert2, herm_opt__
    5744              :  real(dp),parameter :: break_symm=1.0d-12
    5745              :  !real(dp),parameter :: break_symm=zero
    5746              :  real(dp) :: fac
    5747              : !arrays
    5748              :  real(dp) :: nearidentity(3,3)
    5749              : ! *********************************************************************
    5750              : 
    5751      1056608 :  herm_opt__ = 1; if (present(herm_opt)) herm_opt__ = herm_opt
    5752              : 
    5753              :  ! This slight breaking of the symmetry allows the results to be more portable between machines
    5754     13735904 :  nearidentity(:,:)=one
    5755      1056608 :  nearidentity(1,1)=one+break_symm
    5756      1056608 :  nearidentity(3,3)=one-break_symm
    5757              : 
    5758              :  ! Include the masses in the dynamical matrix
    5759      3297309 :  do ipert1=1,natom
    5760     10422940 :    do ipert2=1,natom
    5761      7125631 :      fac=1.0_dp/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
    5762     30743225 :      do idir1=1,3
    5763     92633203 :        do idir2=1,3
    5764     64130679 :          i1=idir1+(ipert1-1)*3
    5765     64130679 :          i2=idir2+(ipert2-1)*3
    5766     64130679 :          index=i1+3*natom*(i2-1)
    5767     64130679 :          mat(2*index-1)=mat(2*index-1)*fac*nearidentity(idir1,idir2)
    5768     64130679 :          mat(2*index  )=mat(2*index  )*fac*nearidentity(idir1,idir2)
    5769              :          ! This is to break slightly the translation invariance, and make the automatic tests more portable
    5770     85507572 :          if(ipert1==ipert2 .and. idir1==idir2)then
    5771      6722103 :            mat(2*index-1)=mat(2*index-1)+break_symm*natom/amu_emass/idir1*0.01_dp
    5772              :          end if
    5773              :        end do
    5774              :      end do
    5775              :    end do
    5776              :  end do
    5777              : 
    5778              :  ! Make the dynamical matrix hermitian
    5779      1056608 :  if (herm_opt__ == 1) call mkherm(mat,3*natom)
    5780              : 
    5781      1056608 : end subroutine massmult_and_breaksym
    5782              : !!***
    5783              : 
    5784              : !!****f* m_dynmat/massmult_and_breaksym_cplx
    5785              : !! NAME
    5786              : !!  mult_masses_and_break_symms_cplx
    5787              : !!
    5788              : !! FUNCTION
    5789              : !!  Similar to massmult_and_breaksym, the only difference is that it receives complex array.
    5790              : 
    5791            0 : subroutine massmult_and_breaksym_cplx(natom, ntypat, typat, amu, cmat, &
    5792              :                                       herm_opt) ! optional
    5793              : 
    5794              : !Arguments -------------------------------
    5795              : !scalars
    5796              :  integer,intent(in) :: natom,ntypat
    5797              :  integer,optional,intent(in) :: herm_opt
    5798              : !arrays
    5799              :  integer,intent(in) :: typat(natom)
    5800              :  real(dp),intent(in) :: amu(ntypat)
    5801              :  complex(dp),target,intent(inout) :: cmat(2*3*natom*3*natom)
    5802              : 
    5803              : !Local variables -------------------------
    5804              :  integer :: herm_opt__
    5805              :  real(dp),pointer :: rmat_ptr(:)
    5806              : ! *************************************************************************
    5807              : 
    5808            0 :  call C_F_pointer(c_loc(cmat), rmat_ptr, shape=[3*natom*3*natom])
    5809            0 :  herm_opt__ = 1; if (present(herm_opt)) herm_opt__ = herm_opt
    5810            0 :  call massmult_and_breaksym(natom, ntypat, typat, amu, rmat_ptr, herm_opt=herm_opt__)
    5811              : 
    5812            0 : end subroutine massmult_and_breaksym_cplx
    5813              : !!***
    5814              : 
    5815              : !!****f* m_dynmat/ftgam
    5816              : !! NAME
    5817              : !! ftgam
    5818              : !!
    5819              : !! FUNCTION
    5820              : !! If qtor=1 (q->r):
    5821              : !!  Generates the Fourier transform of the recip space gkk matrices
    5822              : !!  to obtain the real space ones.
    5823              : !! If qtor=0 (r->q):
    5824              : !!  Generates the Fourier transform of the real space gkk matrices
    5825              : !!  to obtain the reciprocal space ones.
    5826              : !!
    5827              : !! INPUTS
    5828              : !! natom= Number of atoms in the unit cell
    5829              : !! nqpt= Number of q points in the Brillouin zone
    5830              : !!           if qtor=0 this number is read in the input file
    5831              : !! nrpt= Number of R points in the Big Box
    5832              : !! qtor= ( q to r : see above )
    5833              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    5834              : !!           These coordinates are normalized (=> * acell(3)!!)
    5835              : !! qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
    5836              : !!           if qtor=0 these vectors are read in the input file
    5837              : !! wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
    5838              : !!
    5839              : !! OUTPUT
    5840              : !!  (see side effects)
    5841              : !!
    5842              : !! SIDE EFFECTS
    5843              : !! Input/output
    5844              : !! gam_qpt(2,3*natom*3*natom,nqpt)
    5845              : !!  = gamma matrices in recip space coming from the Derivative Data Base
    5846              : !! gam_rpt(2,3*natom*3*natom,nrpt)
    5847              : !!  = gamma matrices in real space stored in file unit_gkk_rpt
    5848              : !!
    5849              : !! NOTES
    5850              : !!   copied from ftiaf9.f
    5851              : !!   recip to real space: real space is forced to disk file unit_gkk_rpt
    5852              : !!                        recip space depends on gkqwrite and unitgkq3
    5853              : !!   real to recip space: real space is forced to disk file unit_gkk_rpt
    5854              : !!                        recip space is necessarily in memory in gkk_qpt
    5855              : !!
    5856              : !!    real space elements are complex, but could be reduced, as (-r) = (+r)*
    5857              : !!
    5858              : !! SOURCE
    5859              : 
    5860        26898 : subroutine ftgam (wghatm,gam_qpt,gam_rpt,natom,nqpt,nrpt,qtor,coskr, sinkr)
    5861              : 
    5862              : !Arguments -------------------------------
    5863              : !scalars
    5864              :  integer,intent(in) :: natom,nqpt,nrpt,qtor
    5865              : !arrays
    5866              :  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
    5867              :  real(dp),intent(inout) :: gam_qpt(2,3*natom*3*natom,nqpt)
    5868              :  real(dp),intent(inout) :: gam_rpt(2,3*natom*3*natom,nrpt)
    5869              :  real(dp),intent(in) :: coskr(nqpt,nrpt)
    5870              :  real(dp),intent(in) :: sinkr(nqpt,nrpt)
    5871              : 
    5872              : !Local variables -------------------------
    5873              : !scalars
    5874              :  integer :: iatom,idir,ip,iqpt,irpt,jatom,jdir
    5875              :  real(dp) :: im,re
    5876              :  character(len=500) :: msg
    5877              : ! *********************************************************************
    5878              : 
    5879        26898 :  select case (qtor)
    5880              :  case (1)
    5881              :    ! Recip to real space
    5882       428974 :    gam_rpt(:,:,:) = zero
    5883        11392 :    do irpt=1,nrpt
    5884      1387296 :      do iqpt=1,nqpt
    5885              :        ! Get the phase factor with normalization!
    5886      1375904 :        re=coskr(iqpt,irpt)
    5887      1375904 :        im=sinkr(iqpt,irpt)
    5888     14078031 :        do ip=1,3*natom*3*natom
    5889              :          ! Real and imaginary part of the real-space gam matrices
    5890     12690936 :          gam_rpt(1,ip,irpt) = gam_rpt(1,ip,irpt) + re*gam_qpt(1,ip,iqpt) + im*gam_qpt(2,ip,iqpt)
    5891     14066840 :          gam_rpt(2,ip,irpt) = gam_rpt(2,ip,irpt) + re*gam_qpt(2,ip,iqpt) - im*gam_qpt(1,ip,iqpt)
    5892              :        end do
    5893              :      end do
    5894              :    end do
    5895       428974 :    gam_rpt = gam_rpt/nqpt
    5896              : 
    5897              :  case (0)
    5898              :    ! Recip space from real space
    5899      1073346 :    gam_qpt(:,:,:)=zero
    5900              : 
    5901      1590618 :    do irpt=1,nrpt
    5902      3154539 :      do iqpt=1,nqpt
    5903              : 
    5904      4784088 :        do iatom=1,natom
    5905      5061063 :          do jatom=1,natom
    5906      1840896 :            re = coskr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
    5907      1840896 :            im = sinkr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
    5908              : 
    5909      9019830 :            do idir=1,3
    5910     23931648 :              do jdir=1,3
    5911              :                ! Get phase factor
    5912              : 
    5913     16568064 :                ip= jdir + (jatom-1)*3 + (idir-1)*3*natom + (iatom-1)*9*natom
    5914              :                ! Real and imaginary part of the interatomic forces
    5915     16568064 :                gam_qpt(1,ip,iqpt) = gam_qpt(1,ip,iqpt) + re*gam_rpt(1,ip,irpt) - im*gam_rpt(2,ip,irpt)
    5916     22090752 :                gam_qpt(2,ip,iqpt) = gam_qpt(2,ip,iqpt) + im*gam_rpt(1,ip,irpt) + re*gam_rpt(2,ip,irpt)
    5917              :              end do ! end jdir
    5918              :            end do ! end idir
    5919              :          end do
    5920              :        end do ! end iatom
    5921              : 
    5922              :      end do ! end iqpt
    5923              :    end do ! end irpt
    5924              : 
    5925              :  case default
    5926            0 :    write(msg,'(a,i0,a)' )'The only allowed values for qtor are 0 or 1, while qtor= ',qtor,' has been required.'
    5927        26898 :    ABI_BUG(msg)
    5928              :  end select
    5929              : 
    5930        26898 : end subroutine ftgam
    5931              : !!***
    5932              : 
    5933              : !!****f* m_dynmat/ftgam_init
    5934              : !!
    5935              : !! NAME
    5936              : !! ftgam_init
    5937              : !!
    5938              : !! FUNCTION
    5939              : !!  Generates the sin and cos phases for the Fourier transform of the gkk matrices
    5940              : !!
    5941              : !! INPUTS
    5942              : !! gprim = reciprocal space vectors to get cartesian coord for qpt
    5943              : !! nqpt= Number of q points in the Brillouin zone
    5944              : !! nrpt= Number of R points in the Big Box
    5945              : !! rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
    5946              : !!           These coordinates are normalized (=> * acell(3)!!)
    5947              : !! qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
    5948              : !!           if qtor=0 these vectors are read in the input file
    5949              : !!
    5950              : !! OUTPUT
    5951              : !! coskr, sinkr = cosine and sine of phase factors for given r and q points
    5952              : !!
    5953              : !! SOURCE
    5954              : 
    5955         1715 : subroutine ftgam_init (gprim,nqpt,nrpt,qpt_full,rpt,coskr, sinkr)
    5956              : 
    5957              : !Arguments -------------------------------
    5958              : !scalars
    5959              :  integer,intent(in) :: nqpt,nrpt
    5960              : !arrays
    5961              :  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt_full(3,nqpt)
    5962              :  real(dp),intent(out) :: coskr(nqpt,nrpt)
    5963              :  real(dp),intent(out) :: sinkr(nqpt,nrpt)
    5964              : 
    5965              : !Local variables -------------------------
    5966              : !scalars
    5967              :  integer :: iqpt,irpt
    5968              :  real(dp) :: kr
    5969              : !arrays
    5970              :  real(dp) :: kk(3)
    5971              : ! *********************************************************************
    5972              : 
    5973              : ! Prepare the phase factors
    5974        10311 :  do iqpt=1,nqpt
    5975              :    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
    5976       111748 :    kk(:) = matmul(gprim,qpt_full(:,iqpt))
    5977       417383 :    do irpt=1,nrpt
    5978              :      ! Product of k and r
    5979      1628288 :      kr =dot_product(kk,rpt(:,irpt))
    5980       407072 :      coskr(iqpt,irpt)=cos(two_pi*kr)
    5981       415668 :      sinkr(iqpt,irpt)=sin(two_pi*kr)
    5982              :    end do
    5983              :  end do
    5984              : 
    5985         1715 : end subroutine ftgam_init
    5986              : !!***
    5987              : 
    5988              : !----------------------------------------------------------------------
    5989              : 
    5990              : !!****f* m_dynmat/msria_calc
    5991              : !! NAME
    5992              : !! msria_calc
    5993              : !!
    5994              : !! FUNCTION
    5995              : !! Calculate the corrections on the zone-center IFCs and their derivatives with respect to the phonon
    5996              : !! wavevector q to achieve both translational (acoustic sum rule) and rotational invariances,
    5997              : !! i.e. there is not remanent forces on the atoms if they are moved or rotated globablly.
    5998              : !! This function needs the dimensionality of the system (0D, 1D, 2D, ...) to work properly, as well
    5999              : !! as the moment of the IFCs, i.e. Phi^(1). It can be obtained by a long wave calculation
    6000              : !! or with the Fourier transform. Be careful for the second option that the non-analytical part
    6001              : !! is not (yet) treated for the 1D and 2D cases; ideally this routine should only impacts the
    6002              : !! short-range IFCs (and the long-range subtracted before entering this routine)
    6003              : !!
    6004              : !! INPUTS
    6005              : !!  asr=(6 Impose accoustic sum rules + rotational invariance)
    6006              : !!  crystal<type(crystal_t)>=Crystal structure parameters
    6007              : !!  d2cart(2,3,natom,3,natom)= Dynamical matrices coming from the Derivative Data Base at Gamma
    6008              : !!  d2dq (3,natom,3,natom,3): moment of IFCs (Phi^(1)) in cartesian coordinates
    6009              : !!  sys_dim=System dimensionality (0D, 1D, ...) used for rotational invariance
    6010              : !!  mpert =maximum number of ipert
    6011              : !!  natom=number of atom
    6012              : !!
    6013              : !! OUTPUT
    6014              : !! d2asr= (2,3,natom,3,natom) matrix used to store the correction needed to fulfill
    6015              : !! the acoustic + rotational sum rule on IFCs.
    6016              : !! d2dqmsr= (3,natom,3,natom,3) matrix used to store the correction on IFCs moments
    6017              : !!
    6018              : !! SOURCE
    6019              : 
    6020              : !!***
    6021              : !
    6022            2 : subroutine msria_calc(asr,crystal,d2asr,d2cart,d2dq,d2dqdq,d2dqmsr,d2dqdqmsr,sys_dim,mpert,natom)
    6023              : !Arguments ------------------------------------
    6024              : !scalars
    6025              :  integer,intent(in) :: sys_dim,asr,mpert,natom
    6026              :  type(crystal_t),intent(in) :: crystal
    6027              : !arrays
    6028              :  real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
    6029              :  real(dp),intent(in) :: d2dq(3,natom,3,natom,3)
    6030              :  real(dp),intent(in) :: d2dqdq(3,natom,3,3,3)
    6031              :  real(dp),intent(out) :: d2asr(2,3,natom,3,natom)
    6032              :  real(dp),intent(out) :: d2dqmsr(3,natom,3,natom,3)
    6033              :  real(dp),intent(out) :: d2dqdqmsr(3,natom,3,natom,3,3)
    6034              : !Local variables-------------------------------
    6035              : !scalars
    6036              :  integer :: idir1,idir2,idir3,idir4,idir5,info,ipert1,ipert2,col,ncol,nrow,row
    6037              :  character(len=500) :: msg,msg2
    6038              :  integer :: bool_kdir(3), bool_ldir(3)
    6039              : !arrays
    6040            4 :  real(dp) :: tmp,tmp2,Levi_Civita(3,3,3), d2dqdqcart(3,natom,3,natom,3,3)
    6041            4 :  real(dp) :: d2dqred(3,natom,3,natom,3),d2dqdqred(3,natom,3,natom,3,3)
    6042            2 :  real(dp),allocatable :: msr(:,:,:),msr_init(:,:,:)
    6043            2 :  real(dp),allocatable :: d2cart_vec(:),rcond(:,:),cond(:)
    6044            2 :  real(dp),allocatable :: mat_tmp(:,:),mat_tmp2(:,:),mat_tmp3(:,:),d2cart_sol(:),umat(:,:),vtmat(:,:)
    6045            2 :  real(dp),allocatable :: vmat(:,:),sing(:),work(:),sing1(:,:),sing2(:,:)
    6046              : 
    6047              : ! *********************************************************************
    6048            2 :  if(asr/=6)then
    6049              :    write(msg,'(3a,i0)')&
    6050            0 :    'The argument asr should be 6,',ch10, 'however, asr = ',asr
    6051            0 :    ABI_BUG(msg)
    6052              :  end if
    6053              : 
    6054            2 :  if (asr==6)then
    6055            2 :    write(msg, '(a,a,a,a,a,a,a,a)' ) ch10, &
    6056            2 :    ' Imposition of the ASR + rotational invariance for the interatomic forces (AMSR)', ch10, &
    6057            2 :    ' Rotational invariance impose conditions on the IFCs moments and their derivatives',ch10,&
    6058            2 :    ' At the moment, because of missing long-range contributions to the second IFCs derivatives',ch10,&
    6059            4 :    ' rotational invariance is only imposed on the first-derivatives (first-order condition)'
    6060            2 :    call wrtout(std_out,msg)
    6061              :  end if
    6062            2 :  bool_kdir = 0
    6063            2 :  bool_ldir = 0
    6064              :  ! When periodic, additional variable spaces coming from dynamical matrices derivatives
    6065            2 :  if (sys_dim == 1) then ! 3D
    6066            0 :     bool_kdir = 0 ; bool_ldir = 1
    6067            0 :     msg2=' 3D treatment'
    6068              :  elseif (sys_dim == 2) then ! 2D yz
    6069            0 :     bool_kdir(1) = 1 ; bool_ldir(2) = 1 ; bool_ldir(3) = 1
    6070            0 :     msg2=' 2D with x as out-of-plane direction'
    6071              :  elseif (sys_dim == 3) then ! 2D xz
    6072            0 :     bool_kdir(2) = 1 ; bool_ldir(1) = 1 ; bool_ldir(3) = 1
    6073            0 :     msg2=' 2D with y as out-of-plane direction'
    6074              :  elseif (sys_dim == 4) then ! 2D xy
    6075            1 :     bool_kdir(3) = 1 ; bool_ldir(1) = 1 ; bool_ldir(2) = 1
    6076            1 :     msg2=' 2D with z as out-of-plane direction'
    6077              :  elseif (sys_dim == 5) then ! 1D x
    6078            0 :     bool_kdir(2) = 1 ; bool_kdir(3) = 1 ; bool_ldir(1) = 1
    6079            0 :     msg2=' 1D with x as periodic direction'
    6080              :  elseif (sys_dim == 6) then ! 1D y
    6081            0 :     bool_kdir(1) = 1 ; bool_kdir(2) = 1 ; bool_ldir(2) = 1
    6082            0 :     msg2=' 1D with y as periodic direction'
    6083              :  elseif (sys_dim == 7) then ! 1D z
    6084            0 :     bool_kdir(1) = 1 ;  bool_kdir(2) = 1 ; bool_ldir(3) = 1
    6085            0 :     msg2=' 1D with z as periodic direction'
    6086              :  elseif (sys_dim == 8) then ! Molecule
    6087            4 :     bool_kdir = 1 ; bool_ldir = 0
    6088            1 :     msg2=' 0D treatment (molecules)'
    6089              :  else
    6090              :     write(msg,'(3a,i0)')&
    6091            0 :    'The argument sys_dim should be between 1 and 8,',ch10, 'however, sys_dim = ',sys_dim
    6092            0 :    ABI_BUG(msg)
    6093              :  end if
    6094              : 
    6095            2 :  write(msg, '(a,a)' ) ch10, trim(msg2)
    6096            2 :  call wrtout(std_out,msg)
    6097              : 
    6098              :  ! Matrix sizing for pseudoinverse and alocation of corresponding matrix
    6099            2 :  nrow = 3+2*3*3*natom ! 9*natom conditions for ASR, 9*natom+3 conditions for MSR
    6100            2 :  nrow = nrow +4*(3*natom)**2 ! + Hermiticity
    6101              : 
    6102              :  ncol = (3*natom)**2 ! 9*natom**2 variable workspace (for dynamical matrices, initial)
    6103              :  ncol = ncol + 3*(3*natom)**2 ! Aditional variable space coming from dD/dq (only for periodic systems)
    6104            2 :  ncol = ncol + 9*(3*natom)**2 ! d2D/dqdq
    6105            8 :  ABI_MALLOC(msr,(1:3,1:natom,1:3))
    6106            4 :  ABI_MALLOC(msr_init,(1:3,1:natom,1:3))
    6107            6 :  ABI_MALLOC(d2cart_vec,(1:ncol))
    6108            4 :  ABI_MALLOC(d2cart_sol,(1:ncol))
    6109            6 :  ABI_MALLOC(cond,(1:nrow))
    6110            8 :  ABI_MALLOC(rcond,(1:nrow,1:ncol))
    6111         2927 :  d2cart_vec=0d0
    6112         2927 :  d2cart_sol=0d0
    6113         1034 :  cond = 0d0
    6114      1622792 :  rcond = 0d0
    6115              : 
    6116            2 :  Levi_Civita(:,:,:)=zero
    6117            2 :  Levi_Civita(1,2,3)=+1 ; Levi_Civita(2,3,1)=+1 ; Levi_Civita(3,1,2)=+1
    6118            2 :  Levi_Civita(3,2,1)=-1 ; Levi_Civita(1,3,2)=-1 ; Levi_Civita(2,1,3)=-1
    6119              : 
    6120              :  ! We only have access to \sum d^2 Phi(kappa alpha, kappa' beta)/dqdq through the
    6121              :  ! long-wavelength driver, we need to construct the full tensor. Here we split
    6122              :  ! an equal contribution on all atoms
    6123         2978 :  d2dqdqcart(:,:,:,:,:,:)=zero
    6124            9 :  do ipert1=1,natom
    6125           30 :    do idir1=1,3
    6126           91 :      do idir2=1,3
    6127          309 :        do ipert2=1,natom
    6128          963 :          do idir3=1,3
    6129              :              d2dqdqcart(idir1,ipert1,idir2,ipert1,idir3,idir3)=&
    6130          900 :                      -two*d2dqdq(idir1,ipert1,idir2,idir3,idir3)/dble(natom)
    6131              :          end do
    6132              :        end do
    6133              :      end do
    6134              :    end do
    6135              :  end do
    6136              :  ! Convert d2dq and d2dqdq in relative coordinates with respect to q
    6137          992 :  d2dqred = zero
    6138         2978 :  d2dqdqred = zero
    6139            8 :  do idir1=1,3
    6140           26 :    do idir2=1,3
    6141         2970 :      d2dqred(:,:,:,:,idir1)=d2dqred(:,:,:,:,idir1)+d2dq(:,:,:,:,idir2)*crystal%gprimd(idir2,idir1)
    6142           78 :      do idir3=1,3
    6143          234 :        do idir4=1,3
    6144              :          d2dqdqred(:,:,:,:,idir2,idir4)=d2dqdqred(:,:,:,:,idir2,idir4)+&
    6145        26784 :          d2dqdqcart(:,:,:,:,idir1,idir3)*crystal%gprimd(idir1,idir2)*crystal%gprimd(idir3,idir4)
    6146              :        end do
    6147              :      end do
    6148              :    end do
    6149              :  end do
    6150              :  ! Now building the condition matrix
    6151            8 :  do idir1=1,3
    6152           29 :   do ipert1=1,natom
    6153           90 :     do idir2=1,3
    6154          309 :       do ipert2=1,natom
    6155          225 :         col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6156          225 :         d2cart_vec(col) = d2cart(1,idir1,ipert1,idir2,ipert2)
    6157          225 :         row= idir2+3*(ipert1-1)+3*natom*(idir1-1) ! Acoustic sum rule
    6158          225 :         rcond(row,col) = one ! Sum of IFCs along ipert2 = 0
    6159              :         ! Rotational invariance
    6160          900 :         do idir3=1,3
    6161              :           ! Treat separately confined and periodic directions
    6162          675 :           if ( bool_kdir(idir3) == 1) then ! confined direction
    6163         1548 :             do idir4 = 1,3
    6164         1161 :                 col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6165         1161 :                 row = 9*natom+idir4+3*(ipert1-1)+3*natom*(idir1-1)
    6166              :                 rcond(row,col) = rcond(row,col)+ & ! first moment of IFCs
    6167         1548 :                 (crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
    6168              :             end do
    6169              :             ! Conditions on the second moments of IFCs
    6170              :             ! In molecules, already fulfilled with rotational invariance
    6171              :             ! For 1D systems, should only consider pair of direction when 1 is
    6172              :             ! periodic, the other is not. Currently desactivated
    6173              :             if (idir1 == idir2 .and. bool_ldir(idir1) ==1) then !
    6174              :               col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6175              :               row = 2*9*natom+idir2 ! second moment of IFCs
    6176              :               ! Currently desactivated because long-range electrostatics, only need to uncomment
    6177              :               ! when it will be available.
    6178              :               !rcond(row,col) = -(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))**2
    6179              :               col= ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
    6180              :               !rcond(row,col) = -(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))**2
    6181              :             end if
    6182              :           end if
    6183          900 :           if ( bool_ldir(idir3) == 1 ) then ! periodic direction
    6184              :             ! Initialize the IFCs derivatives
    6185          288 :             col= (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6186          288 :             d2cart_vec(col) = d2dqred(idir1,ipert1,idir2,ipert2,idir3)
    6187         1152 :             do idir5 = 1,3
    6188         3744 :               do idir4 = 1,3
    6189         2592 :                 row = 9*natom+idir4+3*(ipert1-1)+3*natom*(idir1-1)
    6190         3456 :                 rcond(row,col) = rcond(row,col)+ Levi_Civita(idir2,idir5,idir4)*crystal%rprimd(idir5,idir3)!/two_pi
    6191              :               end do
    6192              :             end do
    6193         1152 :             do idir4=1,3
    6194          288 :               if ( bool_ldir(idir4) == 1 ) then ! periodic direction
    6195              :                 col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
    6196          864 :                 (3*natom)**2*(idir3-1)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6197              :                 !d2cart_vec(col) = d2dqdqred(idir1,ipert1,idir2,ipert2,idir3,idir4)
    6198              :               end if
    6199              :             end do
    6200          288 :             if (idir2 == idir1 .and. bool_kdir(idir1)==1) then
    6201          128 :               do idir4=1,3
    6202              :                 col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
    6203           96 :                 (3*natom)**2*(idir4-1)+ipert2+natom*(idir1-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6204           96 :                 row = 2*9*natom+idir3 ! second moment of IFCs
    6205              :                 !rcond(row,col) =  crystal%rprimd(idir4,idir3)**2!/two_pi
    6206              :                 col= 4*(3*natom)**2+(3*natom)**2*3*(idir4-1)+&
    6207          128 :                 (3*natom)**2*(idir4-1)+ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir1-1)
    6208              :                 !rcond(row,col) =  crystal%rprimd(idir4,idir3)**2!/two_pi
    6209              :               end do
    6210              :             end if
    6211              :           end if
    6212              :         end do
    6213              :         ! Additionally, add the condition of matrix Hermiticity, both on IFCs and their derivatives
    6214          225 :         col= ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6215          225 :         row= 3+2*(9*natom)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6216          225 :         rcond(row,col) = rcond(row,col)+ one ! Hermicity
    6217          225 :         col= ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
    6218          225 :         rcond(row,col) = rcond(row,col)- one ! Hermicity
    6219          963 :          do idir3=1,3
    6220          675 :             row= 3+2*(9*natom)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)+9*natom**2*(idir3)
    6221          675 :             col= (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6222          675 :             rcond(row,col) = rcond(row,col)+ one
    6223          675 :             col= (3*natom)**2*idir3+ipert1+natom*(idir1-1)+3*natom*(ipert2-1)+3*natom**2*(idir2-1)
    6224          900 :             rcond(row,col) = rcond(row,col)+ one
    6225              :          end do
    6226              :        end do
    6227              :      end do
    6228              :    end do
    6229              :  end do
    6230              : 
    6231              : 
    6232              : ! Use LAPACK singular value decomposition
    6233            4 :  ABI_MALLOC(sing,(1:nrow))
    6234            8 :  ABI_MALLOC(umat,(1:nrow,1:nrow))
    6235            8 :  ABI_MALLOC(vtmat,(1:ncol,1:ncol))
    6236            6 :  ABI_MALLOC(work,(1:5*max(nrow,ncol)))
    6237              :  call dgesvd('A','A',nrow,ncol,rcond,nrow,sing,umat,nrow, &
    6238            2 :          vtmat, ncol, work,5*max(nrow,ncol),info)
    6239            2 :  ABI_CHECK(info == 0, sjoin('dgesvd returned:', itoa(info)))
    6240            2 :  ABI_FREE(umat)
    6241            2 :  ABI_FREE(work)
    6242              : 
    6243            2 :  write(msg, '(a,es16.8,es16.8)' )' Largest and smallest values from Singular Value Decomposition', sing(1), sing(nrow)
    6244            4 :  call wrtout([std_out], msg)
    6245              : 
    6246            8 :  ABI_MALLOC(vmat,(1:ncol,1:ncol))
    6247            8 :  ABI_MALLOC(sing1,(1:nrow,1:ncol))
    6248            6 :  ABI_MALLOC(sing2,(1:ncol,1:nrow))
    6249      4616120 :  vmat = zero
    6250      1622792 :  sing1 = zero
    6251      1620899 :  sing2 = zero
    6252         2927 :  do ipert1=1,ncol
    6253      4616120 :    do ipert2 =1,ncol
    6254      4616118 :      vmat(ipert1,ipert2) = vtmat(ipert2,ipert1)
    6255              :    end do
    6256              :  end do
    6257              :  ! To compute the pseudoinverse, product of the singular matrix with its inverse
    6258         1034 :  do ipert1=1,min(nrow,ncol)
    6259         1032 :    sing1(ipert1,ipert1) = sing(ipert1)
    6260         1034 :    if (sing(ipert1)>tol12) then ! Avoids numerical problems
    6261          576 :      sing2(ipert1,ipert1) = 1_dp/sing(ipert1)
    6262              :    end if
    6263              :  end do
    6264              : 
    6265            6 :  ABI_MALLOC(mat_tmp,(1:ncol,1:ncol))
    6266            6 :  ABI_MALLOC(mat_tmp2,(1:ncol,1:ncol))
    6267            6 :  ABI_MALLOC(mat_tmp3,(1:ncol,1:ncol))
    6268              : 
    6269            2 :  mat_tmp = matmul(sing2,sing1)
    6270            2 :  mat_tmp2 = matmul(vmat,mat_tmp)
    6271            2 :  mat_tmp3 = matmul(mat_tmp2,vtmat)
    6272              : 
    6273              :  ! Change of IFCs and its derivatives
    6274      4619045 :  d2cart_sol = matmul(mat_tmp3,d2cart_vec)
    6275            2 :  ABI_FREE(sing)
    6276            2 :  ABI_FREE(sing1)
    6277            2 :  ABI_FREE(vmat)
    6278            2 :  ABI_FREE(sing2)
    6279            2 :  ABI_FREE(mat_tmp)
    6280            2 :  ABI_FREE(mat_tmp2)
    6281            2 :  ABI_FREE(mat_tmp3)
    6282              : 
    6283              :  ! Now unravel the IFCs and derivatives in arrays
    6284              : 
    6285          780 :  d2asr = zero
    6286          992 :  d2dqmsr = zero
    6287         2978 :  d2dqdqmsr = zero
    6288            8 :  do idir1=1,3
    6289           29 :    do ipert1=1, natom
    6290           90 :      do idir2=1,3
    6291          309 :        do ipert2=1, natom
    6292          225 :          col = ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6293          225 :          d2asr(1,idir1,ipert1,idir2,ipert2) = d2cart_sol(col)
    6294          963 :          do idir3=1,3
    6295          675 :            col = (3*natom)**2*idir3+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6296          675 :            d2dqmsr(idir1,ipert1,idir2,ipert2,idir3) = d2cart_sol(col)
    6297         2925 :            do idir4=1,3
    6298              :              col = 4*(3*natom)**2+3*(3*natom)**2*(idir4-1)+&
    6299         2700 :              (3*natom)**2*(idir3-1)+ipert2+natom*(idir2-1)+3*natom*(ipert1-1)+3*natom**2*(idir1-1)
    6300              :              !d2dqdqmsr(idir1,ipert1,idir2,ipert2,idir3,idir4) = d2cart_sol(col)
    6301              :            end do
    6302              :          end do
    6303              :        end do
    6304              :      end do
    6305              :    end do
    6306              :  end do
    6307              : 
    6308              : 
    6309           92 :  msr = zero
    6310           92 :  msr_init = zero
    6311            9 :  do ipert1=1, natom
    6312           30 :    do idir1=1,3
    6313           91 :      do idir2=1,3
    6314          309 :        do ipert2=1, natom
    6315          963 :          do idir3=1,3
    6316          675 :            if ( bool_kdir(idir3) == 1) then ! Contribution from zone-center
    6317          387 :              tmp = d2cart(1,idir1,ipert1,idir2,ipert2)
    6318          387 :              tmp2 = tmp-d2asr(1,idir1,ipert1,idir2,ipert2)
    6319         1548 :              do idir4 = 1,3
    6320              :                msr_init(idir1,ipert1,idir4)=msr_init(idir1,ipert1,idir4)+&
    6321         1161 :                tmp*(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
    6322              :                msr(idir1,ipert1,idir4)=msr(idir1,ipert1,idir4)+&
    6323         1548 :                tmp2*(crystal%xcart(idir3,ipert2)-crystal%xcart(idir3,ipert1))*Levi_Civita(idir2,idir3,idir4)
    6324              :              end do
    6325              :            end if
    6326          900 :            if ( bool_ldir(idir3) == 1 ) then ! Contribution from dC/dq
    6327          288 :              tmp =d2dqred(idir1,ipert1,idir2,ipert2,idir3)
    6328          288 :              tmp2=tmp-d2dqmsr(idir1,ipert1,idir2,ipert2,idir3)
    6329         1152 :              do idir4 = 1,3
    6330         3744 :               do idir5 = 1,3
    6331              :                 msr_init(idir1,ipert1,idir4)=msr_init(idir1,ipert1,idir4)+&
    6332         2592 :                         tmp*crystal%rprimd(idir5,idir3)*Levi_Civita(idir2,idir5,idir4)
    6333              :                 msr(idir1,ipert1,idir4)=msr(idir1,ipert1,idir4)+&
    6334         3456 :                         tmp2*crystal%rprimd(idir5,idir3)*Levi_Civita(idir2,idir5,idir4)
    6335              :               end do
    6336              :             end do
    6337              :            end if
    6338              :          end do
    6339              :        end do
    6340              :      end do
    6341              :    end do
    6342              :  end do
    6343            2 :  write(msg, '(a,a,a,a)' ) ch10, &
    6344            2 :    ' Rotational invariance breaking, before and after imposition', ch10, &
    6345            4 :    '    ipert1   idir1   idir2   torque initial  [Ha/Bohr]  torque final [Ha/Bohr]'
    6346            6 :    call wrtout([std_out, ab_out],msg)
    6347            9 :  do ipert1=1,natom
    6348           30 :    do idir1=1,3
    6349           91 :      do idir4=1,3
    6350           63 :        write(msg, '(a,i0,a,i0,a,i0,a, es16.8,a,es16.8)') '     ', ipert1,'        ', idir1, &
    6351          126 :               '        ', idir4 , '    ', msr_init(idir1,ipert1,idir4),'           ', msr(idir1,ipert1,idir4)
    6352          210 :        call wrtout([std_out, ab_out],msg)
    6353              :      end do
    6354              :    end do
    6355              :  end do
    6356              : 
    6357            2 :  ABI_FREE(msr)
    6358            2 :  ABI_FREE(msr_init)
    6359            2 :  ABI_FREE(d2cart_vec)
    6360            2 :  ABI_FREE(d2cart_sol)
    6361            2 :  ABI_FREE(vtmat)
    6362            2 :  ABI_FREE(cond)
    6363            2 :  ABI_FREE(rcond)
    6364              : 
    6365            2 : end subroutine msria_calc
    6366              : 
    6367              : !----------------------------------------------------------------------
    6368              : 
    6369              : !!****f* m_dynmat/msria_apply
    6370              : !! NAME
    6371              : !! msria_corr
    6372              : !!
    6373              : !! FUNCTION
    6374              : !! Imposition of the Accoustic sum rule and rotational invariance on the InterAtomic Forces
    6375              : !! respecting crystal symmetries. Note that when IFCs derivatives are estimated previously
    6376              : !! based on the Fourier transforms, they do not strictly respect them; this is only solved
    6377              : !! when using the IFCs derivatives from the LW driver. Eventually, if the latter are available,
    6378              : !! correct the IFCs to match the ones from the LW driver close to the zone-center
    6379              : !!
    6380              : !! INPUTS
    6381              : !! asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
    6382              : !!      5 => impose hermitian solution using lapack call, 6 => rotational invariance)
    6383              : !! d2asr=matrix used to store the correction needed to fulfill the acoustic sum rule.
    6384              : !! d2dqmsr = same, but for the first IFCs moment for rotational invariance
    6385              : !! d2dqdqmsr = same, but for the second IFCs moment for rotational invariance
    6386              : !! mpert =maximum number of ipert
    6387              : !! natom=number of atom
    6388              : !! qphon(3,3)=wavevectors for the three possible phonons
    6389              : !! crystal<type(crystal_t)>=Crystal structure parameters
    6390              : !!
    6391              : !! OUTPUT
    6392              : !! Input/Output:
    6393              : !! d2cart=matrix of second derivatives of total energy, in cartesian coordinates
    6394              : !!
    6395              : !! SOURCE
    6396              : 
    6397          162 : subroutine msria_apply(asr,d2asr,d2dqmsr,d2cart,mpert,natom,qphon,crystal)
    6398              : 
    6399              : !Arguments -------------------------------
    6400              : !scalars
    6401              :  integer,intent(in) :: asr,mpert,natom
    6402              :  type(crystal_t),intent(in) :: crystal
    6403              : !arrays
    6404              :  real(dp),intent(in) :: d2dqmsr(3,natom,3,natom,3)!, d2dqdqmsr(3,natom,3,natom,3,3)
    6405              :  real(dp),intent(in) :: d2asr(2,3,natom,3,natom), qphon(3,3)
    6406              :  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
    6407              : !Local variables-------------------------------
    6408              : !scalars
    6409              :  integer :: idir1,idir2,ipert1,ipert2,idir3,ii,jj
    6410            0 :  integer :: tiat,tjat,isym,indij(natom,natom),indij2(natom,natom,3)
    6411              :  integer :: isgn, itirev,acc,acc2
    6412          324 :  real(dp) :: qsym(3), qsym2(3), symcart(3,3,crystal%nsym),arg1,arg2
    6413              :  real(dp) :: re,im,re2,im2,sumr,sumi,valr,vali,carttmp
    6414          162 :  real(dp), allocatable :: pert(:,:,:,:,:,:), pert2(:,:,:,:,:,:,:)
    6415              :  real(dp) :: Levi_Civita(3,3,3)
    6416              : ! *********************************************************************
    6417          972 :  ABI_MALLOC(pert,(1:2,1:3,1:natom,1:3,1:natom,1:2*crystal%nsym))
    6418          972 :  ABI_MALLOC(pert2,(1:2,1:3,1:natom,1:3,1:natom,1:2*crystal%nsym,1:3))
    6419          162 :  if (asr/=6) return
    6420              :  Levi_Civita(:,:,:)=zero
    6421              :  Levi_Civita(1,2,3)=+1 ; Levi_Civita(2,3,1)=+1 ; Levi_Civita(3,1,2)=+1
    6422              :  Levi_Civita(3,2,1)=-1 ; Levi_Civita(1,3,2)=-1 ; Levi_Civita(2,1,3)=-1
    6423              :  ! By convention, Fourier transform in ABINIT is only using the cell
    6424              :  ! coordinates, not the reduced coordinates of the atoms
    6425              :  ! The code that follows already take this into account
    6426              :  ! for sake of legibility
    6427              :  ! Define symmetry tensor for IFCs
    6428         1454 :  do isym=1,crystal%nsym
    6429         5330 :    do idir1=1,3
    6430        15504 :      symcart(:,idir1,isym)=zero
    6431        16796 :      do idir2=1,3
    6432        50388 :        do idir3=1,3
    6433              :          symcart(:,idir1,isym)=symcart(:,idir1,isym)+crystal%rprimd(:,idir2)&
    6434       151164 :                  *crystal%gprimd(idir1,idir3)*crystal%symrel(idir2,idir3,isym)
    6435              :        end do
    6436              :      end do
    6437              :    end do
    6438              :  end do
    6439      5130792 :  pert = zero;  pert2 = zero
    6440        13576 :  indij = 0 ; indij2 = 0
    6441              :  ! Need to loop over symmetries to properly impose rotational invariance
    6442         1454 :  do isym=1,crystal%nsym
    6443         4038 :    do itirev=1,2  ! loop over the time-reversal symmetry
    6444         2584 :      isgn=3-2*itirev
    6445        14204 :      do ipert1=1,natom
    6446        54200 :        do ipert2=1,natom
    6447        41288 :          tiat = crystal%indsym(4,isym,ipert1) ! symmetric atom of i
    6448        41288 :          tjat = crystal%indsym(4,isym,ipert2) ! symmetric atom of j
    6449       165152 :          qsym(:) = crystal%indsym(1:3,isym,ipert2)-crystal%indsym(1:3,isym,ipert1)
    6450       165152 :          qsym= -isgn*qsym
    6451       165152 :          arg1 = two_pi*DOT_PRODUCT(qsym,qphon(:,1))
    6452        41288 :          acc=indij(tiat,tjat)+1
    6453        41288 :          indij(tiat,tjat)=acc
    6454       165152 :          do idir1=1,3
    6455       536744 :            do idir2=1,3
    6456       371592 :              sumr=zero
    6457       371592 :              re = cos(arg1)
    6458       371592 :              im = sin(arg1)
    6459      1486368 :              do ii=1,3
    6460      4830696 :                do jj=1,3
    6461              : !                Correction from on-site and first-neighbors in the same cells (or images)
    6462      4459104 :                   sumr=sumr+symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*d2asr(1,ii,tiat,jj,tjat)
    6463              :                   ! Second order desactivated because of missing contribution from electrostatics
    6464              :                   ! simply uncomment when available
    6465              :                   !do idir3=1,3
    6466              :                   !  sumr=sumr-symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
    6467              :                   !          d2dqdqmsr(ii,tiat,jj,tjat,idir3,idir3)/four
    6468              :                   !end do
    6469              :                end do
    6470              :              end do
    6471       371592 :              valr = re*sumr
    6472       371592 :              vali = im*sumr
    6473       371592 :              pert(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym) = valr
    6474       495456 :              pert(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym) = vali
    6475              :            end do
    6476              :          end do
    6477       175480 :          do idir3=1,3
    6478       123864 :            acc2=indij2(tiat,tjat,idir3)+1
    6479       123864 :            indij2(tiat,tjat,idir3)=acc2
    6480       495456 :            qsym2(:) = crystal%symrel(:,idir3,isym)
    6481       495456 :            qsym2(:)=-isgn*(qsym2(:))
    6482       495456 :            arg2 = two_pi*DOT_PRODUCT(qsym2,qphon(:,1))
    6483       536744 :            do idir1=1,3
    6484      1610232 :              do idir2=1,3
    6485              :                sumi=zero
    6486      4459104 :                sumr=zero
    6487      4459104 :                do ii=1,3
    6488     14492088 :                  do jj=1,3
    6489              :                    ! second order desactivated
    6490              :                    !sumr=sumr+symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
    6491              :                    !     d2dqdqmsr(ii,tiat,jj,tjat,idir3,idir3)/four
    6492              :                    sumi=sumi+isgn*symcart(idir1,ii,isym)*symcart(idir2,jj,isym)*&
    6493     13377312 :                         d2dqmsr(ii,tiat,jj,tjat,idir3)
    6494              :                  end do
    6495              :                end do
    6496      1114776 :                im = -cos(arg1)*sin(arg2)
    6497      1114776 :                re = sin(arg1)*sin(arg2)
    6498      1114776 :                re2 = cos(arg1)*cos(two*arg2)
    6499      1114776 :                im2 = sin(arg1)*cos(two*arg2)
    6500      1114776 :                valr = re*sumi+re2*sumr
    6501      1114776 :                vali = im*sumi+im2*sumr
    6502      1114776 :                pert2(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)= valr
    6503      1486368 :                pert2(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)= vali
    6504              :              end do !idir1
    6505              :            end do !idir2
    6506              :          end do !idir3
    6507              :        end do !ipert2
    6508              :      end do !ipert1
    6509              :    end do !itirev
    6510              :  end do !isym
    6511          809 :  do ipert1=1,natom
    6512         2750 :    do idir1 =1,3
    6513         8411 :      do idir2=1,3
    6514        31029 :        do ipert2=1,natom
    6515       214884 :          do isym=1,crystal%nsym
    6516       580653 :            do itirev=1,2  ! loop over the time-reversal symmetry
    6517       371592 :              isgn=3-2*itirev
    6518              :              carttmp = d2cart(1,idir1,ipert1,idir2,ipert2)- &
    6519       371592 :              pert(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym)/dble(indij(ipert1,ipert2))
    6520       371592 :              d2cart(1,idir1,ipert1,idir2,ipert2) = carttmp
    6521              :              carttmp = d2cart(2,idir1,ipert1,idir2,ipert2)- &
    6522       371592 :              pert(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym)/dble(indij(ipert1,ipert2))
    6523       371592 :              d2cart(2,idir1,ipert1,idir2,ipert2) = carttmp
    6524      1672164 :              do idir3=1,3
    6525              :                carttmp = d2cart(1,idir1,ipert1,idir2,ipert2)- &
    6526      1114776 :                pert2(1,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)/dble(indij2(ipert1,ipert2,idir3))
    6527      1114776 :                d2cart(1,idir1,ipert1,idir2,ipert2) = carttmp
    6528              :                carttmp = d2cart(2,idir1,ipert1,idir2,ipert2)- &
    6529      1114776 :                pert2(2,idir1,ipert1,idir2,ipert2,crystal%nsym*(itirev-1)+isym,idir3)/dble(indij2(ipert1,ipert2,idir3))
    6530      1486368 :                d2cart(2,idir1,ipert1,idir2,ipert2) = carttmp
    6531              :              end do
    6532              :            end do
    6533              :          end do
    6534              :        end do
    6535              :      end do
    6536              :    end do
    6537              :  end do
    6538          162 :  ABI_FREE(pert)
    6539          162 :  ABI_FREE(pert2)
    6540            0 : end subroutine msria_apply
    6541              : !!***
    6542              : end module m_dynmat
        

Generated by: LCOV version 2.3-1