TABLE OF CONTENTS


ABINIT/m_dynmat [ Modules ]

[ Top ] [ Modules ]

NAME

  m_dynmat

FUNCTION

  This module provides low-level tools to operate on the dynamical matrix

COPYRIGHT

  Copyright (C) 2014-2024 ABINIT group (XG, JCC, MJV, NH, RC, MVeithen, MM, MG, MT, DCA)
  This file is distributed under the terms of the
  GNU General Public License, see ~abinit/COPYING
  or http://www.gnu.org/copyleft/gpl.txt .

TODO

  Use more explicative names for the procedures!

SOURCE

 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_symtk,           only : mati3inv, matr3inv, littlegroup_q
 37  use m_cgtools,         only : fxphas_seq
 38  use m_ewald,           only : ewald9
 39  use m_time,            only : timab
 40 
 41  implicit none
 42 
 43  private
 44 
 45  public :: asria_calc           ! Calculate the correction for the Acoustic sum rule on
 46                                 !   the InterAtomic Forces or on the dynamical matrix directly
 47  public :: asria_corr           ! Imposition of the Acoustic sum rule on the InterAtomic Forces
 48                                 !   or on the dynamical matrix directly from the previously calculated d2asr
 49  public :: asrprs               ! Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry
 50  public :: cart29               ! Transform a second-derivative matrix from reduced  coordinates to cartesian coordinates, and also
 51                                 !   1) add the ionic part of the effective charges,
 52                                 !   2) normalize the electronic dielectric tensor, and add the vacuum polarisation
 53  public :: cart39               ! Transform a vector from reduced coordinates to cartesian coordinates,
 54                                 !   taking into account the perturbation from which it was derived,
 55                                 !   and also check the existence of the new values.
 56  public :: d2cart_to_red        ! Transform a second-derivative matrix
 57                                 ! from cartesian to reduced coordinate.
 58  public :: chkph3               ! Check the completeness of the dynamical matrix
 59  public :: chneu9               ! Imposition of the charge neutrality sum rule on the Effective charges
 60  public :: d2sym3               ! Build (nearly) all the other matrix elements that can be build using symmetries.
 61  public :: q0dy3_apply          ! Takes care of the inclusion of the ewald q=0 term in the dynamical matrix
 62  public :: q0dy3_calc           ! Calculate the q=0 correction term to the dynamical matrix
 63  ! TODO: 3 routines to symmetrize. Clarify different use cases
 64  public :: symdyma              ! Symmetrize the dynamical matrices
 65  public :: dfpt_sygra           ! Symmetrize derivatives of energy with respect to coordinates,
 66  public :: dfpt_sydy            ! Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
 67  public :: wings3               ! Suppress the wings of the cartesian 2DTE for which the diagonal element is not known
 68  public :: asrif9               ! Imposes the Acoustic Sum Rule to Interatomic Forces
 69  public :: get_bigbox_and_weights ! Compute
 70  public :: bigbx9               ! Generates a Big Box of R points for the Fourier Transforms the dynamical matrix
 71  public :: make_bigbox          ! Helper functions that faciliates the generation  of a Big Box containing
 72  public :: canat9               ! From reduced to canonical coordinates
 73  public :: canct9               ! Convert from canonical coordinates to cartesian coordinates
 74  public :: chkrp9               ! Check if the rprim used for the definition of the unit cell (in the
 75                                 ! inputs) are consistent with the rprim used in the routine generating  the Big Box
 76  public :: dist9                ! Compute the distance between atoms in the big box
 77  public :: ftifc_q2r            ! Fourier transform of the dynamical matrices to obtain interatomic forces (real space).
 78  private :: ftifc_r2q            ! Fourier transform of the interatomic forces to obtain dynamical matrices (reciprocal space).
 79  public :: dynmat_dq            ! Compute the derivative D(q)/dq via Fourier transform of the interatomic forces
 80  public :: ifclo9               ! Convert from cartesian coordinates to local coordinates
 81  public :: wght9                ! Generates a weight to each R points of the Big Box and for each pair of atoms
 82  public :: d3sym                ! Given a set of calculated elements of the 3DTE matrix,
 83                                 ! build (nearly) all the other matrix elements that can be build using symmetries.
 84  public :: d3lwsym                                
 85  public :: sylwtens             ! Determines the set of irreductible elements of the spatial-dispersion tensors
 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 
108 ! *************************************************************************
109 
110 contains

m_dynmat/asria_calc [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 asria_calc

FUNCTION

 Calculate the correction for the Acoustic sum rule on the InterAtomic Forces
 or on the dynamical matrix directly

INPUTS

 asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
      5 => impose hermitian solution using lapack call)
 d2cart=matrix of second derivatives of total energy, in cartesian coordinates
 mpert =maximum number of ipert
 natom=number of atom

OUTPUT

 d2asr=matrix used to store the correction needed to fulfill
 the acoustic sum rule.

SOURCE

134 subroutine asria_calc(asr,d2asr,d2cart,mpert,natom)
135 
136 !Arguments -------------------------------
137 !scalars
138  integer,intent(in) :: asr,mpert,natom
139 !arrays
140  real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
141  real(dp),intent(out) :: d2asr(2,3,natom,3,natom)
142 
143 !Local variables-------------------------------
144 !scalars
145  integer :: idir1,idir2,ii,ipert1,ipert2
146  integer :: constrank, imatelem, iconst, nconst, nd2_packed, info
147  !character(len=500) :: msg
148 !arrays
149  integer, allocatable :: packingindex(:,:,:,:)
150  real(dp), allocatable :: constraints(:,:,:)
151  real(dp), allocatable :: d2cart_packed(:,:)
152  real(dp), allocatable :: singvals(:)
153  real(dp), allocatable :: constr_rhs(:,:)
154  real(dp), allocatable :: work(:,:),rwork(:)
155 
156 ! *********************************************************************
157 
158  d2asr = zero
159 
160  if (asr==0) return
161 
162  !call wrtout(std_out,' asria_calc: calculation of the correction to the ASR for the interatomic forces.')
163  do ipert1=1,natom
164    do idir1=1,3
165      do idir2=1,3
166 
167 !      Compute d2asr
168        do ipert2=1,natom
169          d2asr(:,idir1,ipert1,idir2,ipert1)=&
170 &         d2asr(:,idir1,ipert1,idir2,ipert1)+&
171 &         d2cart(:,idir1,ipert1,idir2,ipert2)
172        end do
173      end do
174    end do
175  end do
176 
177 !holistic method: overwrite d2asr with hermitian solution
178  if (asr == 5) then
179    nconst = 9*natom
180    nd2_packed = 3*natom*(3*natom+1)/2
181    ABI_MALLOC(constraints,(2,nconst, nd2_packed))
182    ABI_MALLOC(d2cart_packed,(2,nd2_packed))
183    ABI_MALLOC(constr_rhs,(2,nd2_packed))
184    ABI_MALLOC(singvals,(nconst))
185    ABI_MALLOC(work,(2,3*nd2_packed))
186    ABI_MALLOC(rwork,(5*nd2_packed))
187    ABI_MALLOC(packingindex,(3,natom,3,natom))
188    ii=1
189    packingindex=-1
190    do ipert2=1,natom
191      do idir2=1,3
192        do ipert1=1,ipert2-1
193          do idir1=1,3
194            packingindex(idir1,ipert1,idir2,ipert2) = ii
195            ii = ii+1
196          end do
197        end do
198        do idir1=1,idir2
199          packingindex(idir1,ipert2,idir2,ipert2) = ii
200          ii = ii+1
201        end do
202      end do
203    end do
204 !  setup constraint matrix
205    constraints = zero
206    do ipert1=1,natom
207      do idir1=1,3
208        do idir2=1,3
209          iconst = idir2+3*(idir1-1 + 3*(ipert1-1))
210 !        set all atom forces, this component
211          do ipert2=1,natom
212            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
213            if (imatelem == -1) then
214              imatelem = packingindex(idir2,ipert2,idir1,ipert1)
215            end if
216            constraints(1,iconst,imatelem) = one
217          end do
218        end do
219      end do
220    end do
221 
222    d2cart_packed = -999.0d0
223    do ipert2=1,natom
224      do idir2=1,3
225        do ipert1=1,natom
226          do idir1=1,3
227            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
228            if (imatelem == -1) cycle
229            d2cart_packed(:,imatelem) = d2cart(:,idir1,ipert1,idir2,ipert2)
230          end do
231        end do
232      end do
233    end do
234    constr_rhs = zero
235    constr_rhs(1,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(1,:))
236    constr_rhs(2,1:nconst) = matmul(constraints(1,:,:),d2cart_packed(2,:))
237 
238 !  lwork = 3*nd2_packed
239    call zgelss (nconst,nd2_packed,1,constraints,nconst,constr_rhs,nd2_packed,&
240 &   singvals,-one,constrank,work,3*nd2_packed,rwork,info)
241    ABI_CHECK(info == 0, sjoin('zgelss returned:', itoa(info)))
242 
243 !  unpack
244    do ipert2=1,natom
245      do idir2=1,3
246        do ipert1=1,natom
247          do idir1=1,3
248            imatelem = packingindex(idir1,ipert1,idir2,ipert2)
249            if (imatelem == -1) then
250              imatelem = packingindex(idir2,ipert2,idir1,ipert1)
251 !            NOTE: should complex conjugate the correction below.
252            end if
253            d2asr(:,idir1,ipert1,idir2,ipert2) = constr_rhs(:,imatelem)
254          end do
255        end do
256      end do
257    end do
258 
259    ABI_FREE(constraints)
260    ABI_FREE(d2cart_packed)
261    ABI_FREE(singvals)
262    ABI_FREE(constr_rhs)
263    ABI_FREE(work)
264    ABI_FREE(rwork)
265    ABI_FREE(packingindex)
266  end if
267 
268 end subroutine asria_calc

m_dynmat/asria_corr [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 asria_corr

FUNCTION

 Imposition of the Acoustic sum rule on the InterAtomic Forces
 or on the dynamical matrix directly from the previously calculated d2asr

INPUTS

 asr=(0 => no ASR, 1 or 2=> the diagonal element is modified to give the ASR,
      5 => impose hermitian solution using lapack call)
 d2asr=matrix used to store the correction needed to fulfill
 the acoustic sum rule.
 mpert =maximum number of ipert
 natom=number of atom

OUTPUT

 Input/Output:
 d2cart=matrix of second derivatives of total energy, in cartesian coordinates

SOURCE

295 subroutine asria_corr(asr,d2asr,d2cart,mpert,natom)
296 
297 !Arguments -------------------------------
298 !scalars
299  integer,intent(in) :: asr,mpert,natom
300 !arrays
301  real(dp),intent(in) :: d2asr(2,3,natom,3,natom)
302  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
303 
304 !Local variables-------------------------------
305 !scalars
306  integer :: idir1,idir2,ipert1,ipert2
307 
308 ! *********************************************************************
309 
310  if (asr==0) return
311  !call wrtout(std_out,' asria_corr: imposition of the ASR for the interatomic forces.')
312 
313  ! Remove d2asr
314  do ipert2=1,natom
315    do idir2=1,3
316      do ipert1=1,natom
317        do idir1=1,3
318          d2cart(:,idir1,ipert1,idir2,ipert2)= d2cart(:,idir1,ipert1,idir2,ipert2) - d2asr(:,idir1,ipert1,idir2,ipert2)
319        end do
320      end do
321    end do
322  end do
323 
324 end subroutine asria_corr

m_dynmat/asrif9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 asrif9

FUNCTION

 Imposes the Acoustic Sum Rule to Interatomic Forces

INPUTS

 asr= Option for the imposition of the ASR
  0 => no ASR,
  1 => modify "asymmetrically" the diagonal element
  2 => modify "symmetrically" the diagonal element
 natom= Number of atoms in the unit cell
 nrpt= Number of R points in the Big Box
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
  These coordinates are normalized (=> * acell(3)!!)
 wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
 atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces

OUTPUT

 atmfrc(3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces

TODO

 List of ouput should be included.

SOURCE

2578 subroutine asrif9(asr,atmfrc,natom,nrpt,rpt,wghatm)
2579 
2580 !Arguments -------------------------------
2581 !scalars
2582  integer,intent(in) :: asr,natom,nrpt
2583 !arrays
2584  real(dp),intent(in) :: rpt(3,nrpt),wghatm(natom,natom,nrpt)
2585  real(dp),intent(inout) :: atmfrc(3,natom,3,natom,nrpt)
2586 
2587 !Local variables -------------------------
2588 !scalars
2589  integer :: found,ia,ib,irpt,izero,mu,nu
2590  real(dp) :: sumifc
2591 
2592 ! *********************************************************************
2593 
2594  if(asr==1.or.asr==2)then
2595    found=0
2596    ! Search for the R vector which is equal to ( 0 , 0 , 0 )
2597    ! This vector leaves the atom a on itself !
2598    do irpt=1,nrpt
2599      if (all(abs(rpt(:,irpt))<=1.0d-10)) then
2600        found=1
2601        izero=irpt
2602      end if
2603      if (found==1) exit
2604    end do
2605 
2606    if(found==0)then
2607      ABI_BUG('Not able to find the vector R=(0,0,0).')
2608    end if
2609 
2610    do mu=1,3
2611      do nu=1,3
2612        do ia=1,natom
2613          sumifc=zero
2614          do ib=1,natom
2615 
2616            ! Get the sumifc of interatomic forces acting on the atom ia,
2617            ! either in a symmetrical manner, or an unsymmetrical one.
2618            if(asr==1)then
2619              do irpt=1,nrpt
2620                sumifc=sumifc+wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)
2621              end do
2622            else if(asr==2)then
2623              do irpt=1,nrpt
2624                sumifc=sumifc+&
2625                 (wghatm(ia,ib,irpt)*atmfrc(mu,ia,nu,ib,irpt)+&
2626                  wghatm(ia,ib,irpt)*atmfrc(nu,ia,mu,ib,irpt))/2
2627              end do
2628            end if
2629          end do
2630 
2631          ! Correct the self-interaction in order to fulfill the ASR
2632          atmfrc(mu,ia,nu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)-sumifc
2633          if (asr==2) atmfrc(nu,ia,mu,ia,izero)=atmfrc(mu,ia,nu,ia,izero)
2634        end do
2635      end do
2636    end do
2637  end if
2638 
2639 end subroutine asrif9

m_dynmat/asrprs [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 asrprs

FUNCTION

 Imposition of the Acoustic sum rule on the InterAtomic Forces Plus Rotational Symmetry

INPUTS

  asr=(3 => 1D systems, all elements are modified to give ASR and
            rotational symmetry)
      (4 => 0D systems, all elements are modified to give ASR and
            rotational symmetry)
  asrflg=(1 => the correction to enforce asr is computed from
           d2cart, but NOT applied;
          2 => one uses the previously determined correction)
  minvers=previously calculated inverted coefficient matrix
  mpert =maximum number of ipert
  natom=number of atom
  rotinv=(1,2,3 => for linear systems along x,y,z
          4 => non-linear molecule
  xcart=cartesian coordinates of the ions

OUTPUT

  (see side effects)

SIDE EFFECTS

 Input/Output:
 d2cart=matrix of second derivatives of total energy, in cartesian coordinates
 minvers=inverse of the supermatrix for future application of the corrections

SOURCE

361 subroutine asrprs(asr,asrflag,rotinv,uinvers,vtinvers,singular,d2cart,mpert,natom,xcart)
362 
363 !Arguments ------------------------------------
364 !scalars
365  integer,intent(in) :: asr,asrflag,mpert,natom,rotinv
366 !arrays
367  real(dp),intent(in) :: xcart(3,natom)
368  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
369  real(dp),intent(inout) :: singular(1:3*natom*(3*natom-1)/2)
370  real(dp),intent(inout) :: uinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
371  real(dp),intent(inout) :: vtinvers(1:3*natom*(3*natom-1)/2,1:3*natom*(3*natom-1)/2)
372 
373 !Local variables-------------------------------
374 !scalars
375  integer :: column,idir1,idir2,ii,info,ipert1,ipert2,jj,n3,row,superdim
376  real(dp) :: rcond,test
377 ! real(dp) :: tau ! tau is present but commented out in this routine
378  character(len=500) :: msg
379 !arrays
380  integer :: check(3,natom,3)
381  real(dp) :: tmp(natom,3,3),weightf(1:natom,1:natom)
382  real(dp),allocatable :: d2cartold(:,:,:,:,:),d2vecc(:),d2veccnew(:),d2vecr(:)
383  real(dp),allocatable :: d2vecrnew(:),superm(:,:),umatrix(:,:),vtmatrix(:)
384  real(dp),allocatable :: work(:)
385 
386 ! *********************************************************************
387 
388  if(asr/=3 .and. asr/=4)then
389    write(msg,'(3a,i0)')&
390    'The argument asr should be 3 or 4,',ch10, 'however, asr = ',asr
391    ABI_BUG(msg)
392  end if
393 
394  if (asr==3.or.asr==4)then
395    write(msg, '(a,a)' ) ch10, &
396    'asrprs: imposition of the ASR for the interatomic forces and rotational invariance'
397    call wrtout(std_out,msg)
398  end if
399 
400  write(msg,'(a,i0)')' asrflag is ', asrflag
401  call wrtout([std_out, ab_out], msg)
402 
403 !variables for the dimensions of the matrices
404 
405 !n1=3*natom*(3*natom-1)/2
406 !n2=9*natom
407  n3=3*natom
408 
409  superdim=9*natom*(natom-1)/2+n3
410 
411  ABI_MALLOC(d2vecr,(1:superdim))
412  ABI_MALLOC(d2vecc,(1:superdim))
413  d2vecr=0d0
414  d2vecc=0d0
415 
416 !should be changed set to delta function for debugging
417  weightf=1d0
418 !tau=1d-10
419  do ii=1, natom
420 !  do jj=1, ii-1
421 !  weightf(ii,jj)= &
422 !  &     ((xcart(1,ii)-xcart(1,jj))**2+(xcart(2,ii)-xcart(2,jj))**2+(xcart(3,ii)-xcart(3,jj))**2)**tau
423 !  enddo
424    weightf(ii,ii)=0d0
425  end do
426 
427  ABI_MALLOC(d2cartold,(2,3,mpert,3,mpert))
428 
429  d2cartold=d2cart
430 
431 !setup vector with uncorrected derivatives
432 
433  do ipert1=1, natom
434    do ipert2=1, ipert1-1
435      do idir1=1,3
436        do idir2=1,3
437          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
438          if(abs(d2cart(1,idir1,ipert1,idir2,ipert2))<1d-6)then
439            d2cart(1,idir1,ipert1,idir2,ipert2)=0d0
440          else
441            d2vecr(row)=4*weightf(ipert1,ipert2)*d2cart(1,idir1,ipert1,idir2,ipert2)
442          end if
443          if(abs(d2cart(2,idir1,ipert1,idir2,ipert2))<1d-6) then
444            d2cart(2,idir1,ipert1,idir2,ipert2)=0d0
445          else
446            d2vecc(row)=4*weightf(ipert1,ipert2)*d2cart(2,idir1,ipert1,idir2,ipert2)
447          end if
448        end do
449      end do
450    end do
451  end do
452 
453  if(asrflag==1) then !calculate the pseudo-inverse of the supermatrix
454    ABI_MALLOC(superm,(1:superdim,1:superdim))
455 
456    superm=0d0
457 
458 !  Setting up the supermatrix containing G, A, D
459 
460    do ipert1=1, natom
461      do idir1=1, 3
462 !      Setting up G
463        idir2=mod(idir1,3)+1
464        row=3*(ipert1-1)+idir1
465        do ipert2=1, ipert1-1
466          column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
467          superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
468          column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir2
469          superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
470        end do
471        do ipert2=ipert1+1, natom
472          column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir1-1)+rotinv
473          superm(column,row)=xcart(idir2,ipert2)-xcart(idir2,ipert1)
474          column=9*(ipert2-1)*(ipert2-2)/2+9*(ipert1-1)+3*(idir2-1)+rotinv
475          superm(column,row)=xcart(idir1,ipert1)-xcart(idir1,ipert2)
476        end do
477      end do
478      do idir1=1, 3
479 !      Setting up D
480        idir2=mod(idir1,3)+1
481        ii=mod(idir1+1,3)+1
482        do ipert2=1, ipert1-1
483          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(rotinv-1)+idir1
484          column=9*natom*(natom-1)/2+3*(ipert1-1)+idir1
485          superm(column,row)=superm(column,row)+xcart(idir2,ipert2)-xcart(idir2,ipert1)
486          column=9*natom*(natom-1)/2+3*(ipert1-1)+ii
487          superm(column,row)=superm(column,row)+xcart(ii,ipert1)-xcart(ii,ipert2)
488          row=n3+9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+rotinv
489          column=9*natom*(natom-1)/2+3*(ipert2-1)+idir1
490          superm(column,row)=superm(column,row)+xcart(idir2,ipert1)-xcart(idir2,ipert2)
491          column=9*natom*(natom-1)/2+3*(ipert2-1)+ii
492          superm(column,row)=superm(column,row)+xcart(ii,ipert2)-xcart(ii,ipert1)
493        end do
494 !      Setting up A
495        do idir2=1, 3
496          do ipert2=1, ipert1-1
497            column=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
498            row=n3+column
499            superm(column,row)=4*weightf(ipert1,ipert2)
500          end do
501        end do
502      end do
503    end do
504 
505 !  calculate the pseudo-inverse of the supermatrix
506 
507    ABI_MALLOC(work,(1:6*superdim))
508    ABI_MALLOC(vtmatrix,(1:superdim))
509    ABI_MALLOC(umatrix,(1:superdim,1:superdim))
510 
511 !  singular value decomposition of superm
512 
513    call dgesvd('A','O',superdim,superdim,superm,superdim,singular,umatrix,superdim, &
514                vtmatrix, 1, work,6*superdim,info)
515    ABI_CHECK(info == 0, sjoin('dgesvd returned:', itoa(info)))
516 
517    ABI_FREE(vtmatrix)
518    ABI_FREE(work)
519 
520    write(msg, '(a,es16.8,es16.8)' )' Largest and smallest values from svd', singular(1), singular(superdim)
521    call wrtout([std_out, ab_out], msg)
522 
523 !  Invert U and V**T, orthogonal matrices
524 
525    do ii=1, superdim
526      do jj=1, superdim
527        uinvers(ii,jj)=umatrix(jj,ii)
528        vtinvers(ii,jj)=superm(jj,ii)
529      end do
530    end do
531 
532    ABI_FREE(umatrix)
533    ABI_FREE(superm)
534 
535    write(msg,'(a,a)')' asrprs: done with asrflag 1', ch10
536    call wrtout(std_out,msg)
537 
538  end if !asrflag=1
539 
540  if(asrflag==2) then
541 
542    ABI_MALLOC(d2vecrnew,(1:superdim))
543    ABI_MALLOC(d2veccnew,(1:superdim))
544 
545 !  Calculate V**T**-1 Sigma**-1 U**-1 *rhs
546 
547    do ii=1, superdim
548      d2vecrnew(ii)=0d0
549      d2veccnew(ii)=0d0
550      do jj=1, superdim
551        d2vecrnew(ii)=d2vecrnew(ii)+uinvers(ii,jj)*d2vecr(jj)
552        d2veccnew(ii)=d2veccnew(ii)+uinvers(ii,jj)*d2vecc(jj)
553      end do
554    end do
555 
556    rcond=1d-10*singular(1)
557    do ii=1, superdim
558      if(singular(ii)>rcond) then
559        d2vecrnew(ii)=d2vecrnew(ii)/singular(ii)
560        d2veccnew(ii)=d2veccnew(ii)/singular(ii)
561      else
562        d2vecrnew(ii)=0d0
563        d2veccnew(ii)=0d0
564      end if
565    end do
566 
567    do ii=1, superdim
568      d2vecr(ii)=0d0
569      d2vecc(ii)=0d0
570      do jj=1, superdim
571        d2vecr(ii)=d2vecr(ii)+vtinvers(ii,jj)*d2vecrnew(jj)
572        d2vecc(ii)=d2vecc(ii)+vtinvers(ii,jj)*d2veccnew(jj)
573      end do
574    end do
575 
576 !  Store vector back into the matrix of 2nd order derivates
577 
578    do ipert1=1, natom
579      do ipert2=1, ipert1-1
580        do idir1=1,3
581          do idir2=1,3
582            row=9*(ipert1-1)*(ipert1-2)/2+9*(ipert2-1)+3*(idir1-1)+idir2
583            d2cart(1,idir1,ipert1,idir2,ipert2)=d2vecr(row)
584            d2cart(2,idir1,ipert1,idir2,ipert2)=d2vecc(row)
585            d2cart(1,idir2,ipert2,idir1,ipert1)=d2vecr(row)
586            d2cart(2,idir2,ipert2,idir1,ipert1)=d2vecc(row)
587          end do
588        end do
589      end do
590    end do
591 
592    ABI_FREE(d2vecrnew)
593    ABI_FREE(d2veccnew)
594 
595    check=0
596 
597    do ipert1=1, natom
598      do idir1=1, 3
599        do idir2=1, 3
600          d2cart(1,idir1,ipert1,idir2,ipert1)=0d0
601          d2cart(2,idir1,ipert1,idir2,ipert1)=0d0
602          tmp(ipert1,idir1,idir2)=0d0
603          do ipert2=1, natom
604            if(ipert2/=ipert1) then
605              tmp(ipert1,idir1,idir2)=tmp(ipert1,idir1,idir2) &
606 &             -d2cart(1,idir1,ipert1,idir2,ipert2) &
607 &             -d2cart(1,idir2,ipert2,idir1,ipert1)
608            end if
609          end do
610        end do
611      end do
612    end do
613 
614    do ipert1=1, natom
615      do idir1=1, 3
616        do idir2=1, 3
617          d2cart(1,idir1,ipert1,idir2,ipert1)=tmp(ipert1,idir1,idir2)/2
618          d2cart(1,idir2,ipert1,idir1,ipert1)=d2cart(1,idir1,ipert1,idir2,ipert1)
619        end do
620      end do
621    end do
622 
623    write(std_out,*) 'this should all be zero'
624 
625    do ipert1=1, natom
626      do idir1=1, 3
627        do idir2=1, 3
628          test=0d0
629          do ipert2=1, natom
630            test=test+d2cart(1,idir1,ipert1,idir2,ipert2)+d2cart(1,idir2,ipert2,idir1,ipert1)
631          end do
632          write(std_out,'(i3,i3,i3,es11.3)') idir1,ipert1,idir2,test
633 
634          write(msg, '(i3,i3,i3,es11.3)' ) idir1,ipert1,idir2,test
635          call wrtout(ab_out,msg)
636        end do
637      end do
638    end do
639 
640    write(std_out,*) 'these as well'
641    do ipert2=1, natom
642      do idir1=1, 3
643        do idir2=1, 3
644          test=0d0
645          do ipert1=1, natom
646            test=test+d2cart(1,idir1,ipert1,idir2,ipert2)
647          end do
648          write(std_out,'(i3,i3,i3,i3,es11.3)') idir1,ipert1,idir2,ipert2,test
649        end do
650      end do
651    end do
652 
653    write(msg,'(a,a)')' asrprs: done with asrflag 2', ch10
654    call wrtout(std_out,msg)
655 
656  end if !ends asrflag=2
657 
658  ABI_FREE(d2vecr)
659  ABI_FREE(d2vecc)
660  ABI_FREE(d2cartold)
661 
662 end subroutine asrprs

m_dynmat/axial9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 axial9

FUNCTION

 Generates the local coordinates system from the
 knowledge of the first vector (longitudinal) and
 the ifc matrix in cartesian coordinates

INPUTS

 ifccar(3,3)= matrix of interatomic force constants in cartesian coordinates
 vect1(3)= cartesian coordinates of the first local vector

OUTPUT

 vect2(3)= cartesian coordinates of the second local vector
 vect3(3)= cartesian coordinates of the third local vector

SOURCE

5251 subroutine axial9(ifccar,vect1,vect2,vect3)
5252 
5253 !Arguments -------------------------------
5254 !arrays
5255  real(dp),intent(in) :: ifccar(3,3),vect1(3)
5256  real(dp),intent(out) :: vect2(3),vect3(3)
5257 
5258 !Local variables -------------------------
5259 !scalars
5260  integer :: flag,ii,itrial,jj
5261  real(dp) :: innorm,scprod
5262 !arrays
5263  real(dp) :: work(3)
5264 
5265 ! *********************************************************************
5266 
5267  do jj=1,3
5268    work(jj)=zero
5269    do ii=1,3
5270      work(jj)=work(jj)+ifccar(jj,ii)*vect1(ii)
5271    end do
5272  end do
5273 
5274  flag=0
5275  do itrial=1,4
5276    scprod=zero
5277    do ii=1,3
5278      scprod=scprod+work(ii)*vect1(ii)
5279    end do
5280 
5281    do ii=1,3
5282      work(ii)=work(ii)-vect1(ii)*scprod
5283    end do
5284 
5285    scprod=zero
5286    do ii=1,3
5287      scprod=scprod+work(ii)**2
5288    end do
5289 
5290    if(scprod<1.0d-10)then
5291      work(1:3)=zero
5292      if(itrial>1)work(itrial-1)=1.0_dp
5293    else
5294      flag=1
5295    end if
5296 
5297    if(flag==1)exit
5298  end do
5299 
5300  innorm=scprod**(-0.5_dp)
5301  do ii=1,3
5302    vect2(ii)=work(ii)*innorm
5303  end do
5304 
5305  vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
5306  vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
5307  vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
5308 
5309 end subroutine axial9

m_dynmat/bigbx9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 bigbx9

FUNCTION

 Generation of a Big Box containing all the R points (cells) in the
 cartesian real space needed to Fourier Transforms the dynamical
 matrix into its corresponding interatomic force.

INPUTS

 brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
 choice= if 0, simply count nrpt ; if 1, checks that the input mrpt
   is the same as nrpt, and generate rpt(3,mrpt)
 mrpt=dimension of rpt
 ngqpt(3)= Numbers used to generate the q points to sample the
  Brillouin zone using an homogeneous grid
 nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
  When nqshft is not 1, but 2 or 4 (only other allowed values),
  the limits for the big box have to be extended by a factor of 2.
 rprim(3,3)= Normalized coordinates in real space  !!! IS THIS CORRECT?

OUTPUT

 cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
 nprt= Number of cells (R points) in the Big Box
 rpt(3,mrpt)= canonical coordinates of the cells (R points)
  These coordinates are normalized (=> * acell(3)!!)
  (output only if choice=1)

SOURCE

2892 subroutine bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
2893 
2894 !Arguments -------------------------------
2895 !scalars
2896  integer,intent(in) :: brav,choice,mrpt,nqshft
2897  integer,intent(out) :: nrpt
2898 !arrays
2899  integer,intent(in) :: ngqpt(3)
2900  real(dp),intent(in) :: rprim(3,3)
2901  real(dp),intent(out) :: rpt(3,mrpt)
2902  integer,intent(out) :: cell(3,mrpt)
2903 
2904 !Local variables -------------------------
2905 !In some cases, the atoms coordinates are not packed in the
2906 ! [0,1]^3 cube. Then, the parameter "buffer" might be increased,
2907 !to search relevant pairs of atoms in bigger boxes than usual.
2908 !scalars
2909  integer,parameter :: buffer=1
2910  integer :: irpt,lim1,lim2,lim3,lqshft,r1,r2,r3
2911  character(len=500) :: msg
2912 
2913 ! *********************************************************************
2914 
2915  lqshft=1
2916  if(nqshft/=1)lqshft=2
2917 
2918 
2919 !Simple Cubic Lattice
2920  if (abs(brav)==1) then
2921    lim1=((ngqpt(1))+1)*lqshft+buffer
2922    lim2=((ngqpt(2))+1)*lqshft+buffer
2923    lim3=((ngqpt(3))+1)*lqshft+buffer
2924    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
2925    if(choice/=0)then
2926      if (nrpt/=mrpt) then
2927        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
2928        ABI_BUG(msg)
2929      end if
2930      irpt=0
2931      do r1=-lim1,lim1
2932        do r2=-lim2,lim2
2933          do r3=-lim3,lim3
2934            irpt=irpt+1
2935            rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
2936            rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
2937            rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
2938            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
2939          end do
2940        end do
2941      end do
2942    end if
2943 
2944 !  Face Centered Cubic Lattice
2945  else if (brav==2) then
2946    lim1=((ngqpt(1)+3)/4)*lqshft+buffer
2947    lim2=((ngqpt(2)+3)/4)*lqshft+buffer
2948    lim3=((ngqpt(3)+3)/4)*lqshft+buffer
2949    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*4
2950    if(choice/=0)then
2951      if (nrpt/=mrpt) then
2952        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt= ',mrpt
2953        ABI_BUG(msg)
2954      end if
2955      irpt=0
2956      do r1=-lim1,lim1
2957        do r2=-lim2,lim2
2958          do r3=-lim3,lim3
2959            irpt=irpt+4
2960            rpt(1,irpt-3)=r1
2961            rpt(2,irpt-3)=r2
2962            rpt(3,irpt-3)=r3
2963            rpt(1,irpt-2)=r1
2964            rpt(2,irpt-2)=r2+0.5
2965            rpt(3,irpt-2)=r3+0.5
2966            rpt(1,irpt-1)=r1+0.5
2967            rpt(2,irpt-1)=r2
2968            rpt(3,irpt-1)=r3+0.5
2969            rpt(1,irpt)=r1+0.5
2970            rpt(2,irpt)=r2+0.5
2971            rpt(3,irpt)=r3
2972 !TEST_AM
2973 !           cell(irpt-3,1)=r1;cell(irpt-3,2)=r2;cell(irpt-3,3)=r3
2974            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
2975          end do
2976        end do
2977      end do
2978    end if
2979 
2980 !  Body Centered Cubic Lattice
2981  else if (brav==3) then
2982    lim1=((ngqpt(1)+3)/4)*lqshft+buffer
2983    lim2=((ngqpt(2)+3)/4)*lqshft+buffer
2984    lim3=((ngqpt(3)+3)/4)*lqshft+buffer
2985    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)*2
2986    if(choice/=0)then
2987      if(nrpt/=mrpt) then
2988        write(msg,'(2(a,i0))')' nrpt= ',nrpt,' is not equal to mrpt= ',mrpt
2989        ABI_BUG(msg)
2990      end if
2991      irpt=0
2992      do r1=-lim1,lim1
2993        do r2=-lim2,lim2
2994          do r3=-lim3,lim3
2995            irpt=irpt+2
2996            rpt(1,irpt-1)=r1
2997            rpt(2,irpt-1)=r2
2998            rpt(3,irpt-1)=r3
2999            rpt(1,irpt)=r1+0.5
3000            rpt(2,irpt)=r2+0.5
3001            rpt(3,irpt)=r3+0.5
3002 !TEST_AM
3003 !           cell(irpt-1,1)=r1;cell(irpt-1,2)=r2;cell(irpt-1,3)=r3
3004            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
3005          end do
3006        end do
3007      end do
3008    end if
3009 
3010 !  Hexagonal Lattice
3011  else if (brav==4) then
3012    lim1=(ngqpt(1)+1)*lqshft+buffer
3013    lim2=(ngqpt(2)+1)*lqshft+buffer
3014    lim3=((ngqpt(3)/2)+1)*lqshft+buffer
3015    nrpt=(2*lim1+1)*(2*lim2+1)*(2*lim3+1)
3016    if(choice/=0)then
3017      if(nrpt/=mrpt)then
3018        write(msg,'(2(a,i0))')' nrpt=',nrpt,' is not equal to mrpt=',mrpt
3019        ABI_BUG(msg)
3020      end if
3021      irpt=0
3022      do r1=-lim1,lim1
3023        do r2=-lim2,lim2
3024          do r3=-lim3,lim3
3025            irpt=irpt+1
3026            rpt(1,irpt)=r1*rprim(1,1)+r2*rprim(1,2)+r3*rprim(1,3)
3027            rpt(2,irpt)=r1*rprim(2,1)+r2*rprim(2,2)+r3*rprim(2,3)
3028            rpt(3,irpt)=r1*rprim(3,1)+r2*rprim(3,2)+r3*rprim(3,3)
3029            cell(1,irpt)=r1;cell(2,irpt)=r2;cell(3,irpt)=r3
3030          end do
3031        end do
3032      end do
3033    end if
3034 
3035  else
3036    write(msg,'(a,i0,a)')' The value of brav= ',brav,' is not allowed (should be -1, 1, 2 or 4).'
3037    ABI_BUG(msg)
3038  end if
3039 
3040 end subroutine bigbx9

m_dynmat/canat9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 canat9

FUNCTION

 Transforms an atom whose coordinates (xred*rprim) would not be
 in the chosen unit cell used to generate the interatomic forces
 to its correspondent (rcan) in canonical coordinates.

INPUTS

 brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
 natom= Number of atoms in the unit cell
 rprim(3,3)= Normalized coordinates  of primitive vectors

OUTPUT

 rcan(3,natom)  = Atomic position in canonical coordinates
 trans(3,natom) = Atomic translations : xred = rcan + trans

SOURCE

3066 subroutine canat9(brav,natom,rcan,rprim,trans,xred)
3067 
3068 !Arguments -------------------------------
3069 !scalars
3070  integer,intent(in) :: brav,natom
3071 !arrays
3072  real(dp),intent(in) :: rprim(3,3),xred(3,natom)
3073  real(dp),intent(out) :: rcan(3,natom),trans(3,natom)
3074 
3075 !Local variables -------------------------
3076 !scalars
3077  integer :: found,iatom,ii
3078  character(len=500) :: msg
3079 !arrays
3080  real(dp) :: dontno(3,4),rec(3),rok(3),shift(3),tt(3)
3081 
3082 ! *********************************************************************
3083 
3084 !Normalization of the cartesian atomic coordinates
3085 !If not normalized : rcan(i) <- rcan(i) * acell(i)
3086  do iatom=1,natom
3087    rcan(:,iatom)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
3088  end do
3089 
3090  !Study of the different cases for the Bravais lattice:
3091  if (abs(brav)==1) then
3092    !Simple Cubic Lattice
3093 
3094    do iatom=1,natom
3095      ! Canon will produces these coordinate transformations
3096      ! (Note: here we still use reduced coordinates )
3097      call wrap2_pmhalf(xred(1,iatom),rok(1),shift(1))
3098      call wrap2_pmhalf(xred(2,iatom),rok(2),shift(2))
3099      call wrap2_pmhalf(xred(3,iatom),rok(3),shift(3))
3100 
3101 !    New coordinates : rcan
3102      rcan(:,iatom)=rok(1)*rprim(:,1)+rok(2)*rprim(:,2)+rok(3)*rprim(:,3)
3103 !    Translations between New and Old coordinates
3104      tt(:)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
3105      trans(:,iatom)=tt(:)-rcan(:,iatom)
3106    end do
3107 
3108  else if (brav==2) then
3109    ! Face Centered Lattice
3110    ! Special possible translations in the F.C.C. case
3111    dontno(:,:)=zero
3112    dontno(2,2)=0.5_dp
3113    dontno(3,2)=0.5_dp
3114    dontno(1,3)=0.5_dp
3115    dontno(3,3)=0.5_dp
3116    dontno(1,4)=0.5_dp
3117    dontno(2,4)=0.5_dp
3118    do iatom=1,natom
3119      found=0
3120      do ii=1,4
3121        if (found==1) exit
3122        ! Canon will produce these coordinate transformations
3123        call wrap2_pmhalf(rcan(1,iatom)+dontno(1,ii),rok(1),shift(1))
3124        call wrap2_pmhalf(rcan(2,iatom)+dontno(2,ii),rok(2),shift(2))
3125        call wrap2_pmhalf(rcan(3,iatom)+dontno(3,ii),rok(3),shift(3))
3126        ! In the F.C.C., ABS[ Ri ] + ABS[ Rj ] < or = 1/2
3127        ! The equal sign hase been treated using a tolerance parameter
3128        ! not to have twice the same point in the unit cell !
3129        rok(1)=rok(1)-1.0d-10
3130        rok(2)=rok(2)-2.0d-10
3131        rok(3)=rok(3)-5.0d-10
3132        if (abs(rok(1))+abs(rok(2))<=0.5_dp) then
3133          if (abs(rok(1))+abs(rok(3))<=0.5_dp) then
3134            if (abs(rok(2))+abs(rok(3))<=0.5_dp) then
3135              tt(:)=rcan(:,iatom)
3136              ! New coordinates : rcan
3137              rcan(1,iatom)=rok(1)+1.0d-10
3138              rcan(2,iatom)=rok(2)+2.0d-10
3139              rcan(3,iatom)=rok(3)+5.0d-10
3140              ! Translations between New and Old coordinates
3141              trans(:,iatom)=tt(:)-rcan(:,iatom)
3142              found=1
3143            end if
3144          end if
3145        end if
3146      end do
3147    end do
3148 
3149  else if (brav==3) then
3150    ! Body Centered Cubic Lattice
3151    ! Special possible translations in the B.C.C. case
3152    dontno(:,1)=zero
3153    dontno(:,2)=0.5_dp
3154    do iatom=1,natom
3155      found=0
3156      do ii=1,2
3157        if (found==1) exit
3158        ! Canon will produce these coordinate transformations
3159        call wrap2_pmhalf(rcan(1,iatom)+dontno(1,ii),rok(1),shift(1))
3160        call wrap2_pmhalf(rcan(2,iatom)+dontno(2,ii),rok(2),shift(2))
3161        call wrap2_pmhalf(rcan(3,iatom)+dontno(3,ii),rok(3),shift(3))
3162        ! In the F.C.C., ABS[ Ri ] < or = 1/2
3163        ! and    ABS[ R1 ] + ABS[ R2 ] + ABS[ R3 ] < or = 3/4
3164        ! The equal signs have been treated using a tolerance parameter
3165        ! not to have twice the same point in the unit cell !
3166        rok(1)=rok(1)-1.0d-10
3167        rok(2)=rok(2)-2.0d-10
3168        rok(3)=rok(3)-5.0d-10
3169        if(abs(rok(1))+abs(rok(2))+abs(rok(3))<=0.75_dp)then
3170          if ( abs(rok(1))<=0.5_dp .and. abs(rok(2))<=0.5_dp .and. abs(rok(3))<=0.5_dp) then
3171            tt(:)=rcan(:,iatom)
3172            ! New coordinates : rcan
3173            rcan(1,iatom)=rok(1)+1.0d-10
3174            rcan(2,iatom)=rok(2)+2.0d-10
3175            rcan(3,iatom)=rok(3)+5.0d-10
3176            ! Translations between New and Old coordinates
3177            trans(:,iatom)=tt(:)-rcan(:,iatom)
3178            found=1
3179          end if
3180        end if
3181      end do
3182    end do
3183 
3184  else if (brav==4) then
3185    ! Hexagonal Lattice
3186    ! In this case, it is easier first to work in reduced coordinates space !
3187    do iatom=1,natom
3188      ! Passage from the reduced space to the "lozenge" cell
3189      rec(1)=xred(1,iatom)-0.5_dp
3190      rec(2)=xred(2,iatom)-0.5_dp
3191      rec(3)=xred(3,iatom)
3192      ! Canon will produces these coordinate transformations
3193      call wrap2_pmhalf(rec(1),rok(1),shift(1))
3194      call wrap2_pmhalf(rec(2),rok(2),shift(2))
3195      call wrap2_pmhalf(rec(3),rok(3),shift(3))
3196      rec(1)=rok(1)+0.5_dp
3197      rec(2)=rok(2)+0.5_dp
3198      rec(3)=rok(3)
3199      ! Passage in Cartesian Normalized Coordinates
3200      rcan(:,iatom)=rec(1)*rprim(:,1)+rec(2)*rprim(:,2)+rec(3)*rprim(:,3)
3201      ! Use of a tolerance parameter not to have twice the same point in the unit cell !
3202      rcan(1,iatom)=rcan(1,iatom)-1.0d-10
3203      rcan(2,iatom)=rcan(2,iatom)-2.0d-10
3204      ! Passage to the honeycomb hexagonal unit cell !
3205      if (rcan(1,iatom)>0.5_dp) then
3206        rcan(1,iatom)=rcan(1,iatom)-1.0_dp
3207      end if
3208      if (rcan(1,iatom)>zero.and.rcan(1,iatom)+sqrt(3.0_dp)*rcan(2,iatom)>1.0_dp) then
3209        rcan(1,iatom)=rcan(1,iatom)-0.5_dp
3210        rcan(2,iatom)=rcan(2,iatom)-sqrt(3.0_dp)*0.5_dp
3211      end if
3212      if (rcan(1,iatom)<=zero.and.sqrt(3.0_dp)*rcan(2,iatom)-rcan(1,iatom)>1.0_dp) then
3213        rcan(1,iatom)=rcan(1,iatom)+0.5_dp
3214        rcan(2,iatom)=rcan(2,iatom)-sqrt(3.0_dp)*0.5_dp
3215      end if
3216      ! Translations between New and Old coordinates
3217      tt(:)=xred(1,iatom)*rprim(:,1)+xred(2,iatom)*rprim(:,2)+xred(3,iatom)*rprim(:,3)
3218      trans(:,iatom)=tt(:)-rcan(:,iatom)
3219    end do
3220 
3221    ! End of the possible cases for brav : -1, 1, 2, 4.
3222  else
3223    write(msg, '(a,i0,a,a,a)' )&
3224    'The required value of brav=',brav,' is not available.',ch10,&
3225    'It should be -1, 1,2 or 4 .'
3226    ABI_BUG(msg)
3227  end if
3228 
3229  call wrtout(std_out,' Canonical Atomic Coordinates ')
3230  do iatom=1,natom
3231    write(msg, '(a,i5,3es18.8)' )' atom',iatom,rcan(1,iatom),rcan(2,iatom),rcan(3,iatom)
3232    call wrtout(std_out,msg)
3233  end do
3234 
3235 end subroutine canat9

m_dynmat/canct9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 canct9

FUNCTION

 Convert from canonical coordinates to cartesian coordinates
 a vector defined by its index=ib+natom*(irpt-1)

INPUTS

 acell(3)=length scales by which rprim is to be multiplied
 gprim(3,3)=dimensionless primitive translations in reciprocal space
 index= index of the atom
 natom=number of atoms in unit cell
 nrpt= Number of R points in the Big Box
 rcan(3,natom)=canonical coordinates of atoms
 rprim(3,3)=dimensionless primitive translations in real space
 rpt(3,nrpt)=canonical coordinates of the points in the BigBox.

OUTPUT

 ib=number of the atom in the unit cell
 irpt= number of the unit cell to which belong the atom
 rcart(3)=cartesian coordinate of the atom indexed by index.

SOURCE

3266 subroutine canct9(acell,gprim,ib,index,irpt,natom,nrpt,rcan,rcart,rprim,rpt)
3267 
3268 !Arguments -------------------------------
3269 !scalars
3270  integer,intent(in) :: index,natom,nrpt
3271  integer,intent(out) :: ib,irpt
3272 !arrays
3273  real(dp),intent(in) :: acell(3),gprim(3,3),rcan(3,natom),rprim(3,3)
3274  real(dp),intent(in) :: rpt(3,nrpt)
3275  real(dp),intent(out) :: rcart(3)
3276 
3277 !Local variables -------------------------
3278 !scalars
3279  integer :: jj
3280 !arrays
3281  real(dp) :: xred(3)
3282 
3283 ! *********************************************************************
3284 
3285  irpt=(index-1)/natom+1
3286  ib=index-natom*(irpt-1)
3287 
3288 !Transform the canonical coordinates to reduced coord.
3289  do jj=1,3
3290    xred(jj)=gprim(1,jj)*(rpt(1,irpt)+rcan(1,ib))&
3291 &   +gprim(2,jj)*(rpt(2,irpt)+rcan(2,ib))&
3292 &   +gprim(3,jj)*(rpt(3,irpt)+rcan(3,ib))
3293  end do
3294 
3295 !Then to cartesian coordinates (here the position of the atom b)
3296  do jj=1,3
3297    rcart(jj)=xred(1)*acell(1)*rprim(jj,1)+&
3298 &   xred(2)*acell(2)*rprim(jj,2)+&
3299 &   xred(3)*acell(3)*rprim(jj,3)
3300  end do
3301 
3302 end subroutine canct9

m_dynmat/cart29 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 cart29

FUNCTION

 Transform a second-derivative matrix from reduced
 coordinates to cartesian coordinates, and also
 1) add the ionic part of the effective charges,
 2) normalize the electronic dielectric tensor, and
    add the vacuum polarisation

INPUTS

  blkflg(3,mpert,3,mpert,nblok)=
   ( 1 if the element of the dynamical matrix has been calculated ;
     0 otherwise )
  blkval(2,3,mpert,3,mpert,nblok)=DDB values
  gprimd(3,3)=basis vector in the reciprocal space
  iblok=number of the blok that will be transformed
  mpert =maximum number of ipert
  natom=number of atom
  nblok=number of blocks (dimension of blkflg and blkval)
  ntypat=number of atom types
  rprimd(3,3)=basis vector in the real space
  typat(natom)=integer label of each type of atom (1,2,...)
  ucvol=unit cell volume
  zion(ntypat)=charge corresponding to the atom type

OUTPUT

  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
  2DTE matrix has been calculated correctly ; 0 otherwise )
  d2cart(2,3,mpert,3,mpert)=
    dynamical matrix, effective charges, dielectric tensor,....
    all in cartesian coordinates

SOURCE

704 subroutine cart29(blkflg,blkval,carflg,d2cart,&
705 & gprimd,iblok,mpert,natom,nblok,ntypat,rprimd,typat,ucvol,zion)
706 
707 !Arguments -------------------------------
708 !scalars
709  integer,intent(in) :: iblok,mpert,natom,nblok,ntypat
710  real(dp),intent(in) :: ucvol
711 !arrays
712  integer,intent(in) :: blkflg(3,mpert,3,mpert,nblok),typat(natom)
713  integer,intent(out) :: carflg(3,mpert,3,mpert)
714  real(dp),intent(in) :: blkval(2,3,mpert,3,mpert,nblok),gprimd(3,3),rprimd(3,3)
715  real(dp),intent(in) :: zion(ntypat)
716  real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert)
717 
718 !Local variables -------------------------
719 !scalars
720  integer :: idir1,idir2,ii,ipert1,ipert2
721 !arrays
722  integer :: flg1(3),flg2(3)
723  real(dp) :: vec1(3),vec2(3)
724 
725 ! *********************************************************************
726 
727 !First, copy the data blok in place.
728  d2cart(:,:,:,:,:)=blkval(:,:,:,:,:,iblok)
729 
730 !Cartesian coordinates transformation (in two steps)
731 !First step
732  do ipert1=1,mpert
733    do ipert2=1,mpert
734      do ii=1,2
735        do idir1=1,3
736          do idir2=1,3
737            vec1(idir2)=d2cart(ii,idir1,ipert1,idir2,ipert2)
738 !          Note here blkflg
739            flg1(idir2)=blkflg(idir1,ipert1,idir2,ipert2,iblok)
740          end do
741          call cart39(flg1,flg2,gprimd,ipert2,natom,rprimd,vec1,vec2)
742          do idir2=1,3
743            d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2)
744 !          And here carflg
745            carflg(idir1,ipert1,idir2,ipert2)=flg2(idir2)
746          end do
747        end do
748      end do
749    end do
750  end do
751 
752 !Second step
753  do ipert1=1,mpert
754    do ipert2=1,mpert
755      do ii=1,2
756        do idir2=1,3
757          do idir1=1,3
758            vec1(idir1)=d2cart(ii,idir1,ipert1,idir2,ipert2)
759 !          Note here carflg
760            flg1(idir1)=carflg(idir1,ipert1,idir2,ipert2)
761          end do
762          call cart39(flg1,flg2,gprimd,ipert1,natom,rprimd,vec1,vec2)
763          do idir1=1,3
764            d2cart(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1)
765 !          And here carflg again
766            carflg(idir1,ipert1,idir2,ipert2)=flg2(idir1)
767          end do
768        end do
769      end do
770    end do
771  end do
772 
773 !For the dielectric tensor, takes into account the volume
774 !of the unit cell, and add the unit matrix (polarization of the vacuum)
775  do idir1=1,3
776    do idir2=1,3
777      do ii=1,2
778        d2cart(ii,idir1,natom+2,idir2,natom+2)=&
779 &       -four_pi/ucvol*d2cart(ii,idir1,natom+2,idir2,natom+2)
780      end do
781    end do
782  end do
783 
784  do idir1=1,3
785    d2cart(1,idir1,natom+2,idir1,natom+2)=&
786 &   1.0_dp+d2cart(1,idir1,natom+2,idir1,natom+2)
787  end do
788 
789 !Add the ionic charges to delta z to get the effective charges
790  do ipert1=1,natom
791    do idir1=1,3
792      d2cart(1,idir1,ipert1,idir1,natom+2)=&
793 &     zion(typat(ipert1))+d2cart(1,idir1,ipert1,idir1,natom+2)
794    end do
795  end do
796  do ipert2=1,natom
797    do idir2=1,3
798      d2cart(1,idir2,natom+2,idir2,ipert2)=&
799 &     zion(typat(ipert2))+d2cart(1,idir2,natom+2,idir2,ipert2)
800    end do
801  end do
802 
803 !For the piezoelectric tensor, takes into account the volume of the unit cell
804  do ipert2=natom+3,natom+4
805    do idir1=1,3
806      do idir2=1,3
807        do ii=1,2
808          d2cart(ii,idir1,natom+2,idir2,ipert2)=&
809 &         (1.0_dp/ucvol)*d2cart(ii,idir1,natom+2,idir2,ipert2)
810          d2cart(ii,idir2,ipert2,idir1,natom+2)=&
811 &         (1.0_dp/ucvol)*d2cart(ii,idir2,ipert2,idir1,natom+2)
812        end do
813      end do
814    end do
815  end do
816 
817 end subroutine cart29

m_dynmat/cart39 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 cart39

FUNCTION

 Transform a vector from reduced coordinates to cartesian coordinates,
 taking into account the perturbation from which it was derived,
 and also check the existence of the new values.

INPUTS

  flg1(3)=tell if information of each component of vec1 is valid
  gprimd(3,3)=basis vector in the reciprocal space
  ipert=number of the perturbation
  natom=number of atom
  rprimd(3,3)=basis vector in the real space
  vec1(3)=input vector, in reduced coordinates

OUTPUT

  flg2(3)=tell if information of each component of vec2 is valid
  vec2(3)=output vector, in cartesian coordinates

SOURCE

846 subroutine cart39(flg1,flg2,gprimd,ipert,natom,rprimd,vec1,vec2)
847 
848 !Arguments -------------------------------
849 !scalars
850  integer,intent(in) :: ipert,natom
851 !arrays
852  integer,intent(in) :: flg1(3)
853  integer,intent(out) :: flg2(3)
854  real(dp),intent(in) :: gprimd(3,3),rprimd(3,3),vec1(3)
855  real(dp),intent(out) :: vec2(3)
856 
857 !Local variables -------------------------
858 !scalars
859  integer :: idir,ii
860 
861 ! *********************************************************************
862 
863 !Treat phonon-type perturbation
864  if(ipert>=1.and.ipert<=natom)then
865 
866    do idir=1,3
867      vec2(idir)=zero
868      flg2(idir)=1
869      do ii=1,3
870        if(abs(gprimd(idir,ii))>1.0d-10)then
871          if(flg1(ii)==1)then
872            vec2(idir)=vec2(idir)+gprimd(idir,ii)*vec1(ii)
873          else
874            flg2(idir)=0
875          end if
876        end if
877      end do
878      if(flg2(idir)==0)vec2(idir)=zero
879    end do
880 
881 !  Treat electric field and qvec perturbations
882  else if(ipert==natom+2.or.ipert==natom+8) then
883 !  OCL SCALAR
884    do idir=1,3
885      vec2(idir)=zero
886      flg2(idir)=1
887 !    OCL SCALAR
888      do ii=1,3
889        if(abs(rprimd(idir,ii))>1.0d-10)then
890          if(flg1(ii)==1)then
891            vec2(idir)=vec2(idir)+rprimd(idir,ii)*vec1(ii)/two_pi
892          else
893            flg2(idir)=0
894          end if
895        end if
896      end do
897      if(flg2(idir)==0)vec2(idir)=zero
898    end do
899 
900 !  Treat other perturbations
901  else
902    do idir=1,3
903      vec2(idir)=vec1(idir)
904      flg2(idir)=flg1(idir)
905    end do
906  end if
907 
908 end subroutine cart39

m_dynmat/chkph3 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 chkph3

FUNCTION

 Check the completeness of the dynamical matrix and eventually send a warning

INPUTS

  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
  2DTE matrix has been calculated correctly ; 0 otherwise )
  idir = direction of the eventual electric field
  mpert =maximum number of ipert
  natom=number of atoms in unit cell

OUTPUT

  eventually send a warning message

SOURCE

1082 subroutine chkph3(carflg,idir,mpert,natom)
1083 
1084 !Arguments -------------------------------
1085 !scalars
1086  integer,intent(in) :: idir,mpert,natom
1087 !arrays
1088  integer,intent(in) :: carflg(3,mpert,3,mpert)
1089 
1090 !Local variables -------------------------
1091 !scalars
1092  integer :: idir1,idir2,ipert1,ipert2,send
1093  character(len=500) :: msg
1094 
1095 ! *********************************************************************
1096 
1097  send=0
1098 
1099 !Check the elements of the analytical part of the dynamical matrix
1100  do ipert2=1,natom
1101    do idir2=1,3
1102      do ipert1=1,natom
1103        do idir1=1,3
1104          if(carflg(idir1,ipert1,idir2,ipert2)==0)then
1105            send=1
1106          end if
1107        end do
1108      end do
1109    end do
1110  end do
1111 
1112 !If some electric field is present
1113  if(idir/=0)then
1114 
1115 !  Check the dielectric constant
1116    if(carflg(idir,natom+2,idir,natom+2)==0)then
1117      send=1
1118    end if
1119 
1120 !  Check the effective charges
1121    do ipert1=1,natom
1122      do idir1=1,3
1123        if(carflg(idir1,ipert1,idir,natom+2)==0)then
1124          send=1
1125        end if
1126      end do
1127    end do
1128 
1129  end if
1130 
1131  ! If needed, send the message
1132  if(send==1)then
1133    write(msg, '(a,a,a,a)' )&
1134 &    ' chkph3 : WARNING -',ch10,&
1135 &    '  Dynamical matrix incomplete, phonon frequencies may be wrong, see the log file for more explanations.'
1136    call wrtout(ab_out,msg)
1137    write(msg, '(11a)' )&
1138 &   ' chkph3 : WARNING -',ch10,&
1139 &   '  Dynamical matrix incomplete, phonon frequencies may be wrong.',ch10,&
1140 &   '  Likely due to a list of perturbations, as defined by rfatpol and rfdir, that does not include',ch10,&
1141 &   '  all displacements of all atoms and (if non-metallic material) electric field type perturbation.',ch10,&
1142 &   '  Then, the dynamical matrix includes zeroes when the matrix element is not computed.',ch10,&
1143 &   '  This is allowed for testing purposes. But the phonon frequencies may be wrong.'
1144    call wrtout(std_out,msg)
1145    write(msg, '(9a)' )&
1146 &  '  If there are symmetries, perhaps these matrix elements are zero by symmetry anyhow, and phonon frequencies might be right.',ch10,&
1147 &  '  Please check the input variables rfatpol and rfdir, to determine whether abinit is doing what you intend it to do.',ch10,&
1148 &  '  Note that ANADDB is able to detect whether the symmetries allow one to reconstruct the full dynamical matrix from',ch10,&
1149 &  '  an incomplete one. In this case, passing to ANADDB the delivered _DDB file might confirm (or not) that',ch10,&
1150 &  '  phonon frequencies are right.'
1151    call wrtout(std_out,msg)
1152  end if
1153 
1154 end subroutine chkph3

m_dynmat/chkrp9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 chkrp9

FUNCTION

 Check if the rprim used for the definition of the unit cell (in the
 inputs) are consistent with the rprim used in the routine generating
 the Big Box needed to generate the interatomic forces.

INPUTS

 brav=bravais lattice (1 or -1=simple lattice,2=face centered lattice,
  3=centered lattice,4=hexagonal lattice)
 rprimd(3,3)=dimensional primitive translations for real space (bohr)

OUTPUT

  (only checking)

SOURCE

3326 subroutine chkrp9(brav,rprim)
3327 
3328 !Arguments -------------------------------
3329 !scalars
3330  integer,intent(in) :: brav
3331 !arrays
3332  real(dp),intent(in) :: rprim(3,3)
3333 
3334 !Local variables -------------------------
3335 !scalars
3336  integer :: ii,jj
3337  character(len=500) :: msg
3338 
3339 ! *********************************************************************
3340 
3341  if (abs(brav)==1) then
3342 !  Simple Cubic Lattice No condition in this case !
3343    continue
3344 
3345  else if (brav==2) then
3346 !  Face Centered Lattice
3347    do ii=1,3
3348      do jj=1,3
3349        if (  ( ii==jj .and. abs(rprim(ii,jj))>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
3350          write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3351          'The input variable rprim does not correspond to the',ch10,&
3352          'fixed rprim to be used with brav=2 and ifcflag=1 :',ch10,&
3353          '   0  1/2  1/2',ch10,&
3354          '  1/2  0   1/2',ch10,&
3355          '  1/2 1/2   0 ',ch10,&
3356          'Action: rebuild your DDB by using the latter rprim.'
3357          ABI_ERROR(msg)
3358        end if
3359      end do
3360    end do
3361 
3362  else if (brav==3) then
3363 !  Body Centered Cubic Lattice
3364    do ii=1,3
3365      do jj=1,3
3366        if (  ( ii==jj .and. abs(rprim(ii,jj)+.5_dp)>tol10) .or. (ii/=jj .and. abs(rprim(ii,jj)-.5_dp)>tol10) ) then
3367          write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3368          'The input variable rprim does not correspond to the',ch10,&
3369          'fixed rprim to be used with brav=3 and ifcflag=1 :',ch10,&
3370          '  -1/2  1/2  1/2',ch10,&
3371          '   1/2 -1/2  1/2',ch10,&
3372          '   1/2  1/2 -1/2',ch10,&
3373          'Action: rebuild your DDB by using the latter rprim.'
3374          ABI_ERROR(msg)
3375        end if
3376      end do
3377    end do
3378 
3379  else if (brav==4) then
3380 !  Hexagonal Lattice
3381    if (abs(rprim(1,1)-1.0_dp)>tol10 .or. &
3382        abs(rprim(3,3)-1.0_dp)>tol10 .or. &
3383        abs(rprim(2,1)      )>tol10 .or. &
3384        abs(rprim(3,1)      )>tol10 .or. &
3385        abs(rprim(1,3)      )>tol10 .or. &
3386        abs(rprim(2,3)      )>tol10 .or. &
3387        abs(rprim(3,2)      )>tol10 .or. &
3388        abs(rprim(1,2)+0.5_dp)>tol10 .or. &
3389        abs(rprim(2,2)-0.5_dp*sqrt(3.0_dp))>tol10 ) then
3390      write(msg, '(a,a,a,a,a,a,a,a,a,a,a)' )&
3391       'The input variable rprim does not correspond to the',ch10,&
3392       'fixed rprim to be used with brav=4 and ifcflag=1 :',ch10,&
3393       '   1      0      0',ch10,&
3394       '  -1/2 sqrt[3]/2 0',ch10,&
3395       '   0      0      1',ch10,&
3396       'Action: rebuild your DDB by using the latter rprim.'
3397      ABI_ERROR(msg)
3398    end if
3399 
3400  else
3401    write(msg, '(a,i4,a,a,a,a,a)' )&
3402    'The value of brav=',brav,' is not allowed.',ch10,&
3403    'Only  -1, 1,2,3 or 4 are allowed.',ch10,&
3404    'Action: change the value of brav in your input file.'
3405    ABI_ERROR(msg)
3406  end if
3407 
3408 end subroutine chkrp9

m_dynmat/chneu9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 chneu9

FUNCTION

 Imposition of the charge neutrality sum rule on the Effective charges
 and suppress the imaginary part of the dynamical matrix

INPUTS

  chneut=(0 => no ASR, 1 => equal repartition, 2 => weighted repartition )
  mpert =maximum number of ipert
  natom=number of atom
  ntypat=number of types of atoms in unit cell
  selectz=selection of some parts of the effective charge tensor attached to one atom.
    (0=> no selection, 1=> trace only, 2=> symmetric part only)
  typat(natom)=type of the atom
  zion(ntypat)=atomic charge for every type of atom

SIDE EFFECTS

  Input/Output
  d2cart=matrix of second derivatives of total energy, in cartesian
       coordinates

SOURCE

1184 subroutine chneu9(chneut,d2cart,mpert,natom,ntypat,selectz,typat,zion)
1185 
1186 !Arguments -------------------------------
1187 !scalars
1188  integer,intent(in) :: chneut,mpert,natom,ntypat,selectz
1189 !arrays
1190  integer,intent(in) :: typat(natom)
1191  real(dp),intent(in) :: zion(ntypat)
1192  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
1193 
1194 !Local variables -------------------------
1195 !scalars
1196  integer :: idir1,idir2,ii,ipert1,ipert2
1197  character(len=500) :: msg
1198 !arrays
1199  real(dp) :: sumwght(2)
1200  real(dp),allocatable :: wghtat(:)
1201 
1202 ! *********************************************************************
1203 
1204  ABI_MALLOC(wghtat,(natom))
1205 
1206 !In case of acoustic sum rule imposition, compute the weights on each atom.
1207  if (chneut==1)then
1208 
1209 !  The weight is the same for all atom
1210    do ipert1=1,natom
1211      wghtat(ipert1)=1./natom
1212    end do
1213 
1214  else if (chneut==2) then
1215 
1216 !  The weight is proportional to the diagonal electronic screening charge of the atom
1217    sumwght(1)=zero
1218    do ipert1=1,natom
1219      wghtat(ipert1)=zero
1220      do idir1=1,3
1221        wghtat(ipert1)=wghtat(ipert1)+&
1222 &       d2cart(1,idir1,ipert1,idir1,natom+2)+&
1223 &       d2cart(1,idir1,natom+2,idir1,ipert1)-2*zion(typat(ipert1))
1224      end do
1225      sumwght(1)=sumwght(1)+wghtat(ipert1)
1226    end do
1227 
1228 !  Normalize the weights to unity
1229    do ipert1=1,natom
1230      wghtat(ipert1)=wghtat(ipert1)/sumwght(1)
1231    end do
1232  end if
1233 
1234 !Calculation of the violation of the charge neutrality
1235 !and imposition of the charge neutrality condition
1236  if (chneut/=0)then
1237    write(msg, '(a,a,a,a,a,a,a)' )&
1238     ' The violation of the charge neutrality conditions',ch10,&
1239     ' by the effective charges is as follows :',ch10,&
1240     '    atom        electric field',ch10,&
1241     ' displacement     direction   '
1242    call wrtout(ab_out,msg)
1243    do idir1=1,3
1244      do idir2=1,3
1245        do ii=1,2
1246          sumwght(ii)=zero
1247          do ipert1=1,natom
1248            sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir2,natom+2)
1249          end do
1250          do ipert1=1,natom
1251            d2cart(ii,idir1,ipert1,idir2,natom+2)=&
1252            d2cart(ii,idir1,ipert1,idir2,natom+2)-sumwght(ii)*wghtat(ipert1)
1253          end do
1254        end do
1255        write(msg, '(i8,i16,2f16.6)' ) idir1,idir2,sumwght(1),sumwght(2)
1256        call wrtout(ab_out,msg)
1257      end do
1258    end do
1259    write(msg, '(a)' )' '
1260    call wrtout(ab_out,msg)
1261 
1262 !  The same for the symmetrical part
1263    do idir1=1,3
1264      do idir2=1,3
1265        do ii=1,2
1266          sumwght(ii)=zero
1267          do ipert2=1,natom
1268            sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir2,ipert2)
1269          end do
1270          do ipert2=1,natom
1271            d2cart(ii,idir1,natom+2,idir2,ipert2)=&
1272            d2cart(ii,idir1,natom+2,idir2,ipert2)-sumwght(ii)*wghtat(ipert2)
1273          end do
1274        end do
1275      end do
1276    end do
1277  end if
1278 
1279 !Selection of the trace of the effective charge tensor attached to each atom
1280  if(selectz==1)then
1281    do ipert1=1,natom
1282      do ii=1,2
1283        sumwght(ii)=zero
1284        do idir1=1,3
1285          sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,ipert1,idir1,natom+2)
1286        end do
1287        do idir1=1,3
1288          do idir2=1,3
1289            d2cart(ii,idir1,ipert1,idir2,natom+2)=zero
1290          end do
1291        end do
1292        do idir1=1,3
1293          d2cart(ii,idir1,ipert1,idir1,natom+2)=sumwght(ii)/3.0_dp
1294        end do
1295      end do
1296    end do
1297 !  Do the same for the symmetrical part of d2cart
1298    do ipert2=1,natom
1299      do ii=1,2
1300        sumwght(ii)=zero
1301        do idir1=1,3
1302          sumwght(ii)=sumwght(ii)+d2cart(ii,idir1,natom+2,idir1,ipert2)
1303        end do
1304        do idir1=1,3
1305          do idir2=1,3
1306            d2cart(ii,idir1,natom+2,idir2,ipert2)=zero
1307          end do
1308        end do
1309        do idir1=1,3
1310          d2cart(ii,idir1,natom+2,idir1,ipert2)=sumwght(ii)/3.0_dp
1311        end do
1312      end do
1313    end do
1314  end if
1315 
1316 !Selection of the symmetric part of the effective charge tensor attached to each atom
1317  if(selectz==2)then
1318    do ipert1=1,natom
1319      do ii=1,2
1320        do idir1=1,3
1321          do idir2=1,3
1322            sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
1323 &           +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
1324            d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
1325            d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
1326          end do
1327        end do
1328      end do
1329    end do
1330 !  Do the same for the symmetrical part of d2cart
1331    do ipert1=1,natom
1332      do ii=1,2
1333        do idir1=1,3
1334          do idir2=1,3
1335            sumwght(ii)=(d2cart(ii,idir1,ipert1,idir2,natom+2)&
1336 &           +d2cart(ii,idir2,ipert1,idir1,natom+2))/2.0_dp
1337            d2cart(ii,idir1,ipert1,idir2,natom+2)=sumwght(ii)
1338            d2cart(ii,idir2,ipert1,idir1,natom+2)=sumwght(ii)
1339          end do
1340        end do
1341      end do
1342    end do
1343  end if
1344 
1345 !Write the effective charge tensor
1346  write(msg, '(a,a,a,a,a,a,a)' )&
1347    ' Effective charge tensors after ',ch10,&
1348    ' imposition of the charge neutrality (if requested by user),',ch10,&
1349    ' and eventual restriction to some part :',ch10,&
1350   '   atom    displacement  '
1351  call wrtout(ab_out,msg)
1352 
1353  do ipert1=1,natom
1354    do idir1=1,3
1355      write(msg, '(2i10,3es16.6)' )ipert1,idir1,(d2cart(1,idir1,ipert1,idir2,natom+2),idir2=1,3)
1356      call wrtout(ab_out,msg)
1357    end do
1358  end do
1359 
1360 !Zero the imaginary part of the dynamical matrix
1361  write(msg, '(a)' )' Now, the imaginary part of the dynamical matrix is zeroed '
1362  call wrtout(ab_out,msg)
1363  call wrtout(std_out,msg)
1364 
1365  do ipert1=1,natom
1366    do ipert2=1,natom
1367      do idir1=1,3
1368        do idir2=1,3
1369          d2cart(2,idir1,ipert1,idir2,ipert2)=zero
1370        end do
1371      end do
1372    end do
1373  end do
1374 
1375  ABI_FREE(wghtat)
1376 
1377 end subroutine chneu9

m_dynmat/d2cart_to_red [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 d2cart_to_red

FUNCTION

 Transform a second-derivative matrix from cartesian
 coordinates to reduced coordinate. Also,
 1) remove the ionic part of the effective charges,
 2) remove the vacuum polarisation from the dielectric tensor
    and scale it with the unit cell volume
 In short, does the inverse operation of cart29.

INPUTS

  d2cart(2,3,mpert,3,mpert)=
    second-derivative matrix in cartesian coordinates
  gprimd(3,3)=basis vector in the reciprocal space
  rprimd(3,3)=basis vector in the real space
  mpert =maximum number of ipert
  natom=number of atom

OUTPUT

  d2red(2,3,mpert,3,mpert)=
    second-derivative matrix in reduced coordinates

SOURCE

 940 subroutine d2cart_to_red(d2cart, d2red, gprimd, rprimd, mpert, natom, &
 941 &                        ntypat,typat,ucvol,zion)
 942 
 943 !Arguments -------------------------------
 944 !scalars
 945  integer,intent(in) :: mpert,natom,ntypat
 946  real(dp),intent(in) :: ucvol
 947 !arrays
 948  integer,intent(in) :: typat(natom)
 949  real(dp),intent(in) :: d2cart(2,3,mpert,3,mpert)
 950  real(dp),intent(out) :: d2red(2,3,mpert,3,mpert)
 951  real(dp),intent(in) :: gprimd(3,3),rprimd(3,3)
 952  real(dp),intent(in) :: zion(ntypat)
 953 
 954 !Local variables -------------------------
 955 !scalars
 956  integer :: idir1,idir2,ii,ipert1,ipert2
 957  real(dp) :: fac
 958 !arrays
 959  integer :: flg1(3),flg2(3)
 960  real(dp) :: vec1(3),vec2(3)
 961 
 962 ! *********************************************************************
 963 
 964  flg1 = one
 965  flg2 = one
 966 
 967  d2red = d2cart
 968 
 969 !Remove the ionic charges to z to get the change in effective charges
 970  do ipert1=1,natom
 971    do idir1=1,3
 972      d2red(1,idir1,ipert1,idir1,natom+2)=&
 973 &     d2red(1,idir1,ipert1,idir1,natom+2) - zion(typat(ipert1))
 974    end do
 975  end do
 976  do ipert2=1,natom
 977    do idir2=1,3
 978      d2red(1,idir2,natom+2,idir2,ipert2)=&
 979 &     d2red(1,idir2,natom+2,idir2,ipert2) - zion(typat(ipert2))
 980    end do
 981  end do
 982 
 983  ! Remove the vacuum polarizability from the dielectric tensor
 984  do idir1=1,3
 985    d2red(1,idir1,natom+2,idir1,natom+2)=&
 986 &   d2red(1,idir1,natom+2,idir1,natom+2) - 1.0_dp
 987  end do
 988 
 989 ! Scale the dielectric tensor with the volue of the unit cell
 990  do idir1=1,3
 991    do idir2=1,3
 992      do ii=1,2
 993        d2red(ii,idir1,natom+2,idir2,natom+2)=&
 994 &       - (ucvol / four_pi) * d2red(ii,idir1,natom+2,idir2,natom+2)
 995      end do
 996    end do
 997  end do
 998 
 999 !For the piezoelectric tensor, takes into account the volume of the unit cell
1000  do ipert2=natom+3,natom+4
1001    do idir1=1,3
1002      do idir2=1,3
1003        do ii=1,2
1004          d2red(ii,idir1,natom+2,idir2,ipert2)=&
1005 &         (ucvol)*d2red(ii,idir1,natom+2,idir2,ipert2)
1006          d2red(ii,idir2,ipert2,idir1,natom+2)=&
1007 &         (ucvol)*d2red(ii,idir2,ipert2,idir1,natom+2)
1008        end do
1009      end do
1010    end do
1011  end do
1012 
1013 ! Reduced coordinates transformation (in two steps)
1014 ! Note that rprimd and gprimd are swapped, compared to what cart39 expects
1015 ! A factor of (2pi) ** 2 is added to transform the electric field perturbations
1016 
1017 !First step
1018  do ipert1=1,mpert
1019    fac = one; if (ipert1==natom+2) fac = two_pi ** 2
1020 
1021    do ipert2=1,mpert
1022      do ii=1,2
1023        do idir1=1,3
1024          do idir2=1,3
1025            vec1(idir2)=d2red(ii,idir1,ipert1,idir2,ipert2)
1026          end do
1027          ! Transform vector from cartesian to reduced coordinates
1028          call cart39(flg1,flg2,transpose(rprimd),ipert1,natom,transpose(gprimd),vec1,vec2)
1029          do idir2=1,3
1030            d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir2) * fac
1031          end do
1032        end do
1033      end do
1034    end do
1035  end do
1036 
1037 !Second step
1038  do ipert1=1,mpert
1039    do ipert2=1,mpert
1040      fac = one; if (ipert2==natom+2) fac = two_pi ** 2
1041 
1042      do ii=1,2
1043        do idir2=1,3
1044          do idir1=1,3
1045            vec1(idir1)=d2red(ii,idir1,ipert1,idir2,ipert2)
1046          end do
1047          ! Transform vector from cartesian to reduced coordinates
1048          call cart39(flg1,flg2,transpose(rprimd),ipert2,natom,transpose(gprimd),vec1,vec2)
1049          do idir1=1,3
1050            d2red(ii,idir1,ipert1,idir2,ipert2)=vec2(idir1) * fac
1051          end do
1052        end do
1053      end do
1054    end do
1055  end do
1056 
1057 
1058 end subroutine d2cart_to_red

m_dynmat/d2sym3 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 d2sym3

FUNCTION

 Given a set of calculated elements of the 2DTE matrix d2,
 build (nearly) all the other matrix elements that can be build using symmetries.

 1. Perform first some completion by symmetrisation (exchange)
    over the two defining perturbations
 2. For each element, uses every symmetry, and build the element, in case
    EITHER all the needed elements are available,
    OR the only missing is itself
    OR the perturbation is the electric field, in a diamond
    symmetry (the last case was coded rather dirty)

INPUTS

  indsym(4,nsym,natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of ipert
  natom= number of atoms
  nsym=number of space group symmetries
  qpt(3)=wavevector of the perturbation
  symq(4,2,nsym)= (integer) three first numbers define the G vector ;
   fourth number is zero if the q-vector is not preserved,
              is 1 otherwise
   second index is one without time-reversal symmetry,
                two with time-reversal symmetry
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
  timrev=1 if the time-reversal symmetry preserves the wavevector,
     modulo a reciprocal lattice vector, timrev=0 otherwise
  zero_by_symm= if 1, set blkflg to 1 for the elements that must be zero by symmetry, and zero them.
    This has the indirect effect of being able to resymmetrize the whole matrix, thus
    enforcing better the symmetry for the 2DTE.

SIDE EFFECTS

  Input/Output
  d2(2,3,mpert,3,mpert)= matrix of the 2DTE
  blkflg(3,mpert,3,mpert)= ( 1 if the element of the dynamical
     matrix has been calculated ; 0 otherwise)

NOTES

   The complete search would be to have the possibility
   of a set of missing elements. See notes of July 2, 1994,
   in the blue notebook 'computer codes'
   The partial solution adopted here takes into
   account some mirror symmetries
   as well as the tetrahedral symmetry of the diamond lattice
   On 010331, replaced the loops up to mpert by loops up to
   natom+2, because of a crash bug under Windows. However,
   the problem lies likely in the use of the indsym array.

SOURCE

1440 subroutine d2sym3(blkflg,d2,indsym,mpert,natom,nsym,qpt,symq,symrec,symrel,timrev,zero_by_symm)
1441 
1442 !Arguments -------------------------------
1443 !scalars
1444  integer,intent(in) :: mpert,natom,nsym,timrev,zero_by_symm
1445 !arrays
1446  integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym)
1447  integer,intent(in),target :: symrec(3,3,nsym),symrel(3,3,nsym)
1448  integer,intent(inout) :: blkflg(3,mpert,3,mpert)
1449  real(dp),intent(in) :: qpt(3)
1450  real(dp),intent(inout) :: d2(2,3,mpert,3,mpert)
1451 
1452 !Local variables -------------------------
1453 !scalars
1454  logical, parameter :: do_final_sym=.true.
1455  logical :: qzero
1456  integer :: exch12,found,idir1,idir2,idisy1,idisy2,ipert1,ipert2
1457  integer :: ipesy1,ipesy2,isgn,isym,ithree,itirev,nblkflg_is_one,noccur,nsym_used,quit,quit1
1458  real(dp) :: arg1,arg2,im,norm,re,sumi,sumr,xi,xr
1459 !arrays
1460  integer,pointer :: sym1_(:,:,:),sym2_(:,:,:)
1461  real(dp),allocatable :: d2tmp1(:,:,:),d2tmp2(:,:,:),d2work(:,:,:,:,:)
1462 
1463 ! *********************************************************************
1464 
1465  qzero=(qpt(1)**2+qpt(2)**2+qpt(3)**2<tol16)
1466 
1467 !Here look after exchange of 1 and 2 axis,
1468 !for electric field in diamond symmetry
1469  exch12=0
1470  if (qzero) then
1471    do isym=1,nsym
1472      exch12=1
1473      if(symrel(1,1,isym)/=0)exch12=0
1474      if(symrel(1,2,isym)/=1)exch12=0
1475      if(symrel(1,3,isym)/=0)exch12=0
1476      if(symrel(2,1,isym)/=1)exch12=0
1477      if(symrel(2,2,isym)/=0)exch12=0
1478      if(symrel(2,3,isym)/=0)exch12=0
1479      if(symrel(3,1,isym)/=0)exch12=0
1480      if(symrel(3,2,isym)/=0)exch12=0
1481      if(symrel(3,3,isym)/=1)exch12=0
1482 !    if(exch12==1) write(std_out,*)' d2sym3 : found exchange 1 2 =',isym
1483      if(exch12==1)exit
1484    end do
1485  end if
1486 
1487 !Exchange of perturbations
1488 
1489 !Consider two cases : either time-reversal symmetry
1490 !conserves the wavevector, or not
1491  if(timrev==0)then
1492 
1493 !  do ipert1=1,mpert  See notes
1494    do ipert1=1,min(natom+2,mpert)
1495      do idir1=1,3
1496 
1497 !      Since the matrix is hermitian, the diagonal elements are real
1498        d2(2,idir1,ipert1,idir1,ipert1)=zero
1499 
1500 !      do ipert2=1,mpert See notes
1501        do ipert2=1,min(natom+2,mpert)
1502          do idir2=1,3
1503 
1504            ! FIXME use is_type functions
1505 !          If an element exists
1506            if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
1507 
1508 !            Either complete the symmetric missing element
1509              if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
1510 
1511                d2(1,idir2,ipert2,idir1,ipert1)= d2(1,idir1,ipert1,idir2,ipert2)
1512                d2(2,idir2,ipert2,idir1,ipert1)=-d2(2,idir1,ipert1,idir2,ipert2)
1513 
1514                blkflg(idir2,ipert2,idir1,ipert1)=1
1515 
1516 !              Or symmetrize (the matrix is hermitian) in case both exists
1517 !              (Note : this opportunity has been disabled for more
1518 !              obvious search for bugs in the code )
1519 !              else
1520 !              sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
1521 !              sumi=d2(1,idir2,ipert2,idir1,ipert1)-d2(1,idir1,ipert1,idir2,ipert2)
1522 !              d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
1523 !              d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
1524 !              d2(2,idir2,ipert2,idir1,ipert1)=half*sumi
1525 !              d2(2,idir1,ipert1,idir2,ipert2)=-half*sumi
1526              end if
1527            end if
1528 
1529          end do
1530        end do
1531 
1532      end do
1533    end do
1534 
1535 !  Here, case with time-reversal symmetry
1536  else
1537 
1538 !  do ipert1=1,mpert See notes
1539    do ipert1=1,min(natom+2,mpert)
1540      do idir1=1,3
1541 !      do ipert2=1,mpert See notes
1542        do ipert2=1,min(natom+2,mpert)
1543          do idir2=1,3
1544            d2(2,idir1,ipert1,idir2,ipert2)=zero
1545 
1546 !          If an element exists
1547            if(blkflg(idir1,ipert1,idir2,ipert2)==1)then
1548 
1549 !            Either complete the symmetric missing element
1550              if(blkflg(idir2,ipert2,idir1,ipert1)==0)then
1551 
1552                d2(1,idir2,ipert2,idir1,ipert1)=d2(1,idir1,ipert1,idir2,ipert2)
1553                blkflg(idir2,ipert2,idir1,ipert1)=1
1554 
1555 !              Or symmetrize (the matrix is hermitian) in case both exists
1556 !              (Note : this opportunity has been disabled for more
1557 !              obvious search for bugs in the code )
1558 !              else
1559 !              sumr=d2(1,idir2,ipert2,idir1,ipert1)+d2(1,idir1,ipert1,idir2,ipert2)
1560 !              d2(1,idir2,ipert2,idir1,ipert1)=half*sumr
1561 !              d2(1,idir1,ipert1,idir2,ipert2)=half*sumr
1562              end if
1563 
1564            end if
1565          end do
1566        end do
1567      end do
1568    end do
1569  end if
1570 
1571 !Big Big Loop : symmetrize three times, because
1572 !of some cases in which one element is not yet available
1573 !at the first pass, and even at the second one !
1574  do ithree=1,3
1575 
1576 !  Big loop on all elements
1577 !  do ipert1=1,mpert See notes
1578    do ipert1=1,min(natom+2,mpert)
1579 
1580 !    Select the symmetries according to pertubation 1
1581      if (ipert1<=natom)then
1582        sym1_ => symrec
1583      else
1584        sym1_ => symrel
1585      end if
1586 
1587      do idir1=1,3
1588 !      do ipert2=1,mpert See notes
1589        do ipert2=1,min(natom+2,mpert)
1590 
1591     !    Select the symmetries according to pertubation 2
1592          if (ipert2<=natom)then
1593            sym2_ => symrec
1594          else
1595            sym2_ => symrel
1596          end if
1597 
1598          do idir2=1,3
1599 
1600 !          Will get element (idir1,ipert1,idir2,ipert2)
1601 !          so this element should not yet be present ...
1602            if(blkflg(idir1,ipert1,idir2,ipert2)/=1)then
1603 
1604              d2(1,idir1,ipert1,idir2,ipert2)=zero
1605              d2(2,idir1,ipert1,idir2,ipert2)=zero
1606 
1607 !            Loop on all symmetries, including time-reversal
1608              quit1=0
1609              do isym=1,nsym
1610                do itirev=1,2
1611                  isgn=3-2*itirev
1612 
1613                  if(symq(4,itirev,isym)/=0)then
1614                    found=1
1615 
1616 !                  Here select the symmetric of ipert1
1617                    if(ipert1<=natom)then
1618                      ipesy1=indsym(4,isym,ipert1)
1619                    else if(ipert1==(natom+2).and.qzero)then
1620                      ipesy1=ipert1
1621                    else
1622                      found=0
1623                    end if
1624 
1625 !                  Here select the symmetric of ipert2
1626                    if(ipert2<=natom)then
1627                      ipesy2=indsym(4,isym,ipert2)
1628                    else if(ipert2==(natom+2).and.qzero)then
1629                      ipesy2=ipert2
1630                    else
1631                      found=0
1632                    end if
1633 
1634 !                  Now that a symmetric perturbation has been obtained,
1635 !                  including the expression of the symmetry matrix, see
1636 !                  if the symmetric values are available
1637                    if( found==1 ) then
1638 
1639                      sumr=zero
1640                      sumi=zero
1641                      noccur=0
1642                      nblkflg_is_one=0
1643                      quit=0
1644                      do idisy1=1,3
1645                        do idisy2=1,3
1646                          if(sym1_(idir1,idisy1,isym)/=0 .and. sym2_(idir2,idisy2,isym)/=0 )then
1647                            if(blkflg(idisy1,ipesy1,idisy2,ipesy2)==1)then
1648                              nblkflg_is_one=nblkflg_is_one+1
1649                              sumr=sumr+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
1650 &                             d2(1,idisy1,ipesy1,idisy2,ipesy2)
1651                              sumi=sumi+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)*&
1652 &                             d2(2,idisy1,ipesy1,idisy2,ipesy2)
1653 
1654 !                            Here, in case the symmetric of the element
1655 !                            is the element, or the symmetric with
1656 !                            respect to permutation of perturbations
1657 !                            (some more conditions on the time-reversal
1658 !                            symmetry must be fulfilled although)
1659                            else if(  idisy1==idir1 .and. ipesy1==ipert1&
1660 &                             .and. idisy2==idir2 .and. ipesy2==ipert2&
1661 &                             .and.(isgn==1 .or. timrev==1 &
1662 &                             .or. (idir1==idir2 .and. ipert1==ipert2)))&
1663 &                             then
1664                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1665                            else if(  idisy1==idir2 .and. ipesy1==ipert2&
1666 &                             .and. idisy2==idir1 .and. ipesy2==ipert1&
1667 &                             .and.(isgn==-1 .or. timrev==1&
1668 &                             .or. (idir1==idir2 .and. ipert1==ipert2)))&
1669 &                             then
1670                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1671 
1672 !                            Here, electric field case
1673                            else if( exch12==1 .and. &
1674 &                             ipert1==natom+2 .and. ipert2==natom+2&
1675 &                             .and.(( idisy1+idir1 ==3 &
1676 &                             .and. idisy2==3 .and. idir2==3)&
1677 &                             .or. ( idisy1+idir2 ==3&
1678 &                             .and. idisy2==3 .and. idir1==3)&
1679 &                             .or. ( idisy2+idir2 ==3&
1680 &                             .and. idisy1==3 .and. idir1==3)&
1681 &                             .or. ( idisy2+idir1 ==3&
1682 &                             .and. idisy1==3 .and. idir2==3)))&
1683 &                             then
1684                              noccur=noccur+sym1_(idir1,idisy1,isym)*sym2_(idir2,idisy2,isym)
1685 
1686                            else
1687 !                            Not found
1688                              found=0
1689                              quit=1
1690                              exit
1691                            end if
1692 
1693                          end if
1694                        end do
1695                        if(quit==1)exit
1696                      end do
1697                    end if
1698 
1699 !                  In case zero_by_symm==0, the computed materix element must be associated to at least one really computed matrix element
1700                    if(zero_by_symm==0 .and. nblkflg_is_one==0)then
1701                      found=0
1702                    endif
1703 
1704 !                  Now, if still found and associated to at least one really computed matrix element, put the correct value into array d2
1705                    if(found==1)then
1706 
1707 !                    In case of phonons, need to take into account the
1708 !                    time-reversal symmetry, and the shift back to the unit cell
1709 !
1710 !                    XG990712 : I am not sure this must be kept for electric field ...
1711 !                    1) Consider time-reversal symmetry
1712                      sumi=isgn*sumi
1713 
1714                      if(ipert1<=natom .and. ipert2<=natom)then
1715 !                      2) Shift the atoms back to the unit cell.
1716                        arg1=two_pi*( qpt(1)*indsym(1,isym,ipert1)&
1717 &                       +qpt(2)*indsym(2,isym,ipert1)&
1718 &                       +qpt(3)*indsym(3,isym,ipert1) )
1719                        arg2=two_pi*( qpt(1)*indsym(1,isym,ipert2)&
1720 &                       +qpt(2)*indsym(2,isym,ipert2)&
1721 &                       +qpt(3)*indsym(3,isym,ipert2) )
1722                        re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
1723 !                      XG010117 Must use isgn
1724                        im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
1725                      else
1726                        re=one
1727                        im=zero
1728                      end if
1729 
1730 !                    Final check, could still fail if the
1731 !                    element was its own symmetric
1732                      if (abs(1.0_dp-re*noccur)< 1.0d-6.and.abs(im*noccur) <1.0d-6) then
1733                        found=0
1734                      end if
1735 
1736                    end if
1737 
1738                    if(found==1)then
1739 
1740                      if(noccur==0)then
1741                        d2(1,idir1,ipert1,idir2,ipert2)=re*sumr-im*sumi
1742                        d2(2,idir1,ipert1,idir2,ipert2)=re*sumi+im*sumr
1743                      else
1744 !                      See page July 2, 1994 in computer codes notebook
1745                        xr=re*sumr-im*sumi
1746                        xi=re*sumi+im*sumr
1747                        norm=one+noccur**2-two*re*noccur
1748                        xr=xr/norm
1749                        xi=xi/norm
1750                        d2(1,idir1,ipert1,idir2,ipert2)=&
1751 &                       (one-re*noccur)*xr-im*noccur*xi
1752                        d2(2,idir1,ipert1,idir2,ipert2)=&
1753 &                       (one-re*noccur)*xi+im*noccur*xr
1754                      end if
1755 
1756 !                    The element has been constructed !
1757                      blkflg(idir1,ipert1,idir2,ipert2)=1
1758 
1759                      quit1=1
1760                      exit ! Exit loop on symmetry operations
1761                    end if
1762 
1763 !                  End loop on all symmetries + time-reversal
1764                  end if
1765                end do
1766                if(quit1==1)exit
1767              end do
1768 
1769            end if
1770          end do ! End big loop on all elements
1771        end do
1772      end do
1773    end do
1774 
1775  end do !  End Big Big Loop
1776 
1777 !MT oct. 20, 2014:
1778 !Once the matrix has been built, it does not necessarily fulfill the correct symmetries.
1779 !It has just been filled up from rows or columns that only fulfill symmetries preserving
1780 !one particular perturbation.
1781 !An additional symmetrization might solve this (do not consider TR-symmetry)
1782  if (do_final_sym) then
1783    ABI_MALLOC(d2tmp1,(2,3,3))
1784    ABI_MALLOC(d2tmp2,(2,3,3))
1785    ABI_MALLOC(d2work,(2,3,mpert,3,mpert))
1786    d2work(:,:,:,:,:)=d2(:,:,:,:,:)
1787    do ipert1=1,min(natom+2,mpert)
1788      if ((ipert1==natom+1.or.ipert1==natom+10.or.ipert1==natom+11).or.(ipert1==natom+2.and.(.not.qzero))) cycle
1789      if (ipert1<=natom)then
1790        sym1_ => symrec
1791      else
1792        sym1_ => symrel
1793      end if
1794      do ipert2=1,min(natom+2,mpert)
1795 !      if (any(blkflg(:,ipert1,:,ipert2)==0)) cycle
1796        if ((ipert2==natom+1.or.ipert2==natom+10.or.ipert2==natom+11).or.(ipert2==natom+2.and.(.not.qzero))) cycle
1797        if (ipert2<=natom)then
1798          sym2_ => symrec
1799        else
1800          sym2_ => symrel
1801        end if
1802        nsym_used=0
1803        d2tmp2(:,:,:)=zero
1804        do isym=1,nsym
1805          if (symq(4,1,isym)==1) then
1806            ipesy1=ipert1;if (ipert1<=natom) ipesy1=indsym(4,isym,ipert1)
1807            ipesy2=ipert2;if (ipert2<=natom) ipesy2=indsym(4,isym,ipert2)
1808 !          The condition on next line is too severe, since some elements of sym1_ or sym2_ might be zero,
1809 !          which means not all blkflg(:,ipesy1,:,ipesy2) would need to be 1 to symmetrize the matrix.
1810 !          However, coding something more refined is really more difficult.
1811 !          This condition then has the side effect that more symmetries can be applied when zero_by_symm==1,
1812 !          since blkflg can be set to 1 when the symmetries guarantee the matrix element to be zero.
1813            if (all(blkflg(:,ipesy1,:,ipesy2)==1)) then
1814              nsym_used=nsym_used+1
1815              re=one;im=zero
1816              if (ipert1<=natom.and.ipert2<=natom.and.(.not.qzero)) then
1817                arg1=two_pi*(qpt(1)*(indsym(1,isym,ipert1)-indsym(1,isym,ipert2)) &
1818 &                          +qpt(2)*(indsym(2,isym,ipert1)-indsym(2,isym,ipert2)) &
1819 &                          +qpt(3)*(indsym(3,isym,ipert1)-indsym(3,isym,ipert2)))
1820                re=cos(arg1);im=sin(arg1)
1821              end if
1822              d2tmp1(:,:,:)=zero
1823              do idir2=1,3 !kappa
1824                do idir1=1,3 !mu
1825                  do idisy1=1,3 !nu
1826                    d2tmp1(:,idir1,idir2)=d2tmp1(:,idir1,idir2) &
1827 &                     +sym1_(idir1,idisy1,isym)*d2(:,idisy1,ipesy1,idir2,ipesy2)
1828                  end do
1829                end do
1830              end do
1831              do idir2=1,3 !mu
1832                do idir1=1,3 !kappa
1833                  do idisy2=1,3 !nu
1834                    d2tmp2(1,idir1,idir2)=d2tmp2(1,idir1,idir2) &
1835 &                  +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*re-d2tmp1(2,idir1,idisy2)*im)
1836                    d2tmp2(2,idir1,idir2)=d2tmp2(2,idir1,idir2) &
1837 &                  +sym2_(idir2,idisy2,isym)*(d2tmp1(1,idir1,idisy2)*im+d2tmp1(2,idir1,idisy2)*re)
1838                  end do
1839                end do
1840              end do
1841            end if
1842          end if
1843        end do ! isym
1844        if (nsym_used>0) d2work(:,1:3,ipert1,1:3,ipert2)=d2tmp2(:,1:3,1:3)/dble(nsym_used)
1845      end do !ipert2
1846    end do !ipert1
1847    if (mpert>=natom)   d2(:,1:3,1:natom,1:3,1:natom)=d2work(:,1:3,1:natom,1:3,1:natom)
1848    if (mpert>=natom+2) then
1849      d2(:,1:3,natom+2,1:3,1:natom)=d2work(:,1:3,natom+2,1:3,1:natom)
1850      d2(:,1:3,1:natom,1:3,natom+2)=d2work(:,1:3,1:natom,1:3,natom+2)
1851      d2(:,1:3,natom+2,1:3,natom+2)=d2work(:,1:3,natom+2,1:3,natom+2)
1852    end if
1853    ABI_FREE(d2tmp1)
1854    ABI_FREE(d2tmp2)
1855    ABI_FREE(d2work)
1856  end if
1857 
1858 end subroutine d2sym3

m_dynmat/d3lwsym [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 d3lwsym

FUNCTION

 Given a set of calculated elements of the 3DTE matrix,
 build (nearly) all the other matrix elements that can be build using symmetries.

INPUTS

  has_strain = if .true. i2pert includes strain perturbation
  indsym(4,nsym,natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of ipert
  natom= number of atoms
  nsym=number of space group symmetries
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal reduced space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real reduced space)
  symrel_cart(3,3,nsym)=3x3 matrices of the group symmetries (real cartesian space)

SIDE EFFECTS

  Input/Output
  blkflg(3,mpert,3,mpert,3,mpert)= matrix that indicates if an
   element of d3 is available (1 if available, 0 otherwise)
  d3(2,3,mpert,3,mpert,3,mpert)= matrix of the 3DTE

PARENTS

      m_ddb,m_nonlinear

CHILDREN

SOURCE

4473 !subroutine d3lwsym(blkflg,d3,has_strain,indsym,mpert,natom,nsym,symrec,symrel,symrel_cart)
4474 subroutine d3lwsym(blkflg,d3,indsym,mpert,natom,nsym,symrec,symrel)
4475 
4476 !Arguments -------------------------------
4477 !scalars
4478  integer,intent(in) :: mpert,natom,nsym
4479 ! logical,intent(in) :: has_strain
4480 !arrays
4481  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4482  integer,intent(inout) :: blkflg(3,mpert,3,mpert,3,mpert)
4483  real(dp),intent(inout) :: d3(2,3,mpert,3,mpert,3,mpert)
4484 ! real(dp),intent(in) :: symrel_cart(3,3,nsym)
4485 
4486 !Local variables -------------------------
4487 !scalars
4488  integer :: found,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert,idisy1,idisy2,idisy3
4489  integer :: ipesy1,ipesy2,ipesy3,isym,ithree
4490 !integer :: istr,i2dir_a,i2dir_b,disy2_a,idisy2_b
4491  real(dp) :: sumi,sumr
4492  logical :: is_strain
4493 !arrays
4494 ! integer,save :: idx(18)=(/1,1,2,2,3,3,3,2,3,1,2,1,2,3,1,3,1,2/)
4495  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
4496 ! integer :: strflg(3,mpert,3,3,3,mpert),strflg_car(3,mpert,3,3,3,mpert)
4497 ! real(dp) :: d3str(2,3,mpert,3,3,3,mpert)
4498 
4499 ! *********************************************************************
4500 
4501 !First, take into account the permutations symmetry of
4502 !(i1pert,i1dir) and (i2pert,i2dir)
4503  do i1pert = 1, mpert
4504    do i2pert = 1, mpert
4505      do i3pert = 1, mpert
4506 
4507        do i1dir = 1, 3
4508          do i2dir = 1, 3
4509            do i3dir = 1, 3
4510 
4511              if ((blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1).and. &
4512               (blkflg(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert)/=1)) then
4513 
4514                d3(1,i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = &
4515                d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
4516                d3(2,i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = &
4517               -d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
4518 
4519                blkflg(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = 1
4520 
4521              end if
4522 
4523            end do
4524          end do
4525        end do
4526 
4527      end do
4528    end do
4529  end do
4530 
4531 !For strain perturbation we need an array with the two strain indexes
4532 ! if (has_strain) then
4533 !   strflg=0
4534 !   d3str=zero
4535 !   do i3pert=1, mpert
4536 !     do i3dir=1,3
4537 !       do i2pert=natom+3,natom+4
4538 !         do i2dir=1,3
4539 !           if (i2pert==natom+3) istr=i2dir
4540 !           if (i2pert==natom+4) istr=3+i2dir
4541 !           i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
4542 !           do i1pert=1,mpert
4543 !             do i1dir=1,3
4544 !               if (blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1) then
4545 !                 strflg(i1dir,i1pert,i2dir_a,i2dir_b,i3dir,i3pert)=1
4546 !                 d3str(:,i1dir,i1pert,i2dir_a,i2dir_b,i3dir,i3pert)= &
4547 !               & d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)          
4548 !                 if (i2pert==natom+4) then
4549 !                   strflg(i1dir,i1pert,i2dir_b,i2dir_a,i3dir,i3pert)=1
4550 !                   d3str(:,i1dir,i1pert,i2dir_b,i2dir_a,i3dir,i3pert)= &
4551 !                 & d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)          
4552 !                 end if
4553 !               end if
4554 !             end do
4555 !           end do
4556 !         end do
4557 !       end do
4558 !     end do
4559 !   end do
4560 ! end if
4561 
4562 !Big Big Loop : symmetrize three times, because
4563 !of some cases in which one element is not yet available
4564 !at the first pass, and even at the second one !
4565 
4566  do ithree=1,3
4567 
4568 !  Loop over perturbations
4569    do i1pert = 1, mpert
4570      do i2pert = 1, mpert
4571        is_strain=.false.    
4572        do i3pert = 1, mpert
4573 
4574          do i1dir = 1, 3
4575            do i2dir = 1, 3
4576              do i3dir = 1, 3
4577 
4578 !              Will get element (idir1,ipert1,idir2,ipert2)
4579 !              so this element should not yet be present ...
4580                if(blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)/=1)then
4581 
4582                  d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 0_dp
4583 
4584                  do isym = 1, nsym
4585 
4586                    found = 1
4587 
4588                    if (i1pert <= natom) then
4589                      ipesy1 = indsym(4,isym,i1pert)
4590                      sym1(:,:) = symrec(:,:,isym)
4591                    else if (i1pert == natom + 2) then
4592                      ipesy1 = i1pert
4593                      sym1(:,:) = symrel(:,:,isym)
4594                    else
4595                      found = 0
4596                    end if
4597 
4598                    if (i2pert <= natom) then
4599                      ipesy2 = indsym(4,isym,i2pert)
4600                      sym2(:,:) = symrec(:,:,isym)
4601                    else if (i2pert == natom + 2) then
4602                      ipesy2 = i2pert
4603                      sym2(:,:) = symrel(:,:,isym)
4604                    else if (i2pert == natom + 3.or. i2pert == natom + 4) then
4605                      !TODO: Symmetries on strain perturbation do not work yet.
4606                      found = 0
4607                      is_strain=.true.
4608 
4609 !                     ipesy2 = i2pert
4610 !                     sym2(:,:) = NINT(symrel_cart(:,:,isym))
4611 !                     if (i2pert==natom+3) istr=i2dir
4612 !                     if (i2pert==natom+4) istr=3+i2dir
4613 !                     i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
4614                    else
4615                      found = 0
4616                    end if
4617 
4618                    if (i3pert <= natom) then
4619                      ipesy3 = indsym(4,isym,i3pert)
4620                      sym3(:,:) = symrec(:,:,isym)
4621                    else if (i3pert == natom + 2.or.i3pert == natom + 8) then
4622                      ipesy3 = i3pert
4623                      sym3(:,:) = symrel(:,:,isym)
4624                    else
4625                      found = 0
4626                    end if
4627 
4628                    sumr = 0_dp ; sumi = 0_dp;
4629                    if (.not.is_strain) then
4630                      do idisy1 = 1, 3
4631                        do idisy2 = 1, 3
4632                          do idisy3 = 1, 3
4633 
4634                            if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir,idisy2) /=0) &
4635 &                           .and.(sym3(i3dir,idisy3) /=0)) then
4636 
4637                              if (blkflg(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 1) then
4638 
4639                                sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4640 &                               sym3(i3dir,idisy3)*d3(1,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4641                                sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4642 &                               sym3(i3dir,idisy3)*d3(2,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4643 
4644                              else
4645 
4646                                found = 0
4647 
4648                              end if
4649 
4650                            end if
4651 
4652                          end do
4653                        end do
4654                      end do
4655                    else 
4656 !                     do idisy1 = 1, 3
4657 !                       !do idisy2_a = 1, 3
4658 !                       !  do idisy2_b = 1, 3
4659 !                       do idisy2 = 1, 3
4660 !                         if (ipesy2==natom+3) istr=idisy2
4661 !                         if (ipesy2==natom+4) istr=3+idisy2
4662 !                         idisy2_a=idx(2*istr-1); idisy2_b=idx(2*istr)
4663 !                           do idisy3 = 1, 3
4664 !
4665 !                             if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir_a,idisy2_a) /=0) &
4666 !&                             .and.(sym2(i2dir_b,idisy2_b) /=0).and.(sym3(i3dir,idisy3) /=0)) then
4667 !
4668 !                               if (strflg(idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3) == 1) then
4669 !
4670 !                                 sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir_a,idisy2_a)* &
4671 !&                                sym2(i2dir_b,idisy2_b)*sym3(i3dir,idisy3)*& 
4672 !&                                d3str(1,idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3)
4673 !                                 sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir_a,idisy2_b)*&
4674 !&                                sym2(i2dir_b,idisy2_b)*sym3(i3dir,idisy3)*& 
4675 !&                                d3str(2,idisy1,ipesy1,idisy2_a,idisy2_b,idisy3,ipesy3)
4676 !
4677 !                               else
4678 !
4679 !                                 found = 0
4680 !
4681 !                               end if
4682 !
4683 !                             end if
4684 !
4685 !                           end do
4686 !                         !end do
4687 !                       end do
4688 !                     end do
4689                    end if        
4690 
4691                    if (found == 1) then
4692                      d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumr
4693                      d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumi
4694                      blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4695                    end if
4696 
4697                  end do  ! isym
4698 
4699                end if  ! blkflg
4700 
4701 !              Close loop over perturbations
4702              end do
4703            end do
4704          end do
4705        end do
4706      end do
4707    end do
4708 
4709  end do  ! close loop over ithree
4710 
4711 end subroutine d3lwsym

m_dynmat/d3sym [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 d3sym

FUNCTION

 Given a set of calculated elements of the 3DTE matrix,
 build (nearly) all the other matrix elements that can be build using symmetries.

INPUTS

  indsym(4,nsym,natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of ipert
  natom= number of atoms
  nsym=number of space group symmetries
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)

SIDE EFFECTS

  Input/Output
  blkflg(3,mpert,3,mpert,3,mpert)= matrix that indicates if an
   element of d3 is available (1 if available, 0 otherwise)
  d3(2,3,mpert,3,mpert,3,mpert)= matrix of the 3DTE

SOURCE

4273 subroutine d3sym(blkflg,d3,indsym,mpert,natom,nsym,symrec,symrel)
4274 
4275 !Arguments -------------------------------
4276 !scalars
4277  integer,intent(in) :: mpert,natom,nsym
4278 !arrays
4279  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4280  integer,intent(inout) :: blkflg(3,mpert,3,mpert,3,mpert)
4281  real(dp),intent(inout) :: d3(2,3,mpert,3,mpert,3,mpert)
4282 
4283 !Local variables -------------------------
4284 !scalars
4285  integer :: found,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert,idisy1,idisy2,idisy3
4286  integer :: ipesy1,ipesy2,ipesy3,isym,ithree
4287  real(dp) :: sumi,sumr
4288 !arrays
4289  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
4290 
4291 ! *********************************************************************
4292 
4293 !DEBUG
4294 !write(std_out,*)'d3sym : enter'
4295 !do i1dir = 1, 3
4296 !do i2dir = 1, 3
4297 !do i3dir = 1, 3
4298 !write(std_out,*)i1dir,i2dir,i3dir,blkflg(i1dir,natom+2,i2dir,natom+2,i3dir,natom+2)
4299 !end do
4300 !end do
4301 !end do
4302 !stop
4303 !ENDDEBUG
4304 
4305 !First, take into account the permutations symmetry of
4306 !(i1pert,i1dir) and (i3pert,i3dir)
4307  do i1pert = 1, mpert
4308    do i2pert = 1, mpert
4309      do i3pert = 1, mpert
4310 
4311        do i1dir = 1, 3
4312          do i2dir = 1, 3
4313            do i3dir = 1, 3
4314 
4315              if ((blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)==1).and. &
4316 &             (blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert)/=1)) then
4317 
4318                d3(:,i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = &
4319 &              d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)
4320 
4321                blkflg(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = 1
4322 
4323              end if
4324 
4325            end do
4326          end do
4327        end do
4328 
4329      end do
4330    end do
4331  end do
4332 
4333 !Big Big Loop : symmetrize three times, because
4334 !of some cases in which one element is not yet available
4335 !at the first pass, and even at the second one !
4336 
4337  do ithree=1,3
4338 
4339 !  Loop over perturbations
4340    do i1pert = 1, mpert
4341      do i2pert = 1, mpert
4342        do i3pert = 1, mpert
4343 
4344          do i1dir = 1, 3
4345            do i2dir = 1, 3
4346              do i3dir = 1, 3
4347 
4348 !              Will get element (idir1,ipert1,idir2,ipert2)
4349 !              so this element should not yet be present ...
4350                if(blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert)/=1)then
4351 
4352                  d3(:,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 0_dp
4353 
4354                  do isym = 1, nsym
4355 
4356                    found = 1
4357 
4358                    if (i1pert <= natom) then
4359                      ipesy1 = indsym(4,isym,i1pert)
4360                      sym1(:,:) = symrec(:,:,isym)
4361                    else if (i1pert == natom + 2) then
4362                      ipesy1 = i1pert
4363                      sym1(:,:) = symrel(:,:,isym)
4364                    else
4365                      found = 0
4366                    end if
4367 
4368                    if (i2pert <= natom) then
4369                      ipesy2 = indsym(4,isym,i2pert)
4370                      sym2(:,:) = symrec(:,:,isym)
4371                    else if (i2pert == natom + 2) then
4372                      ipesy2 = i2pert
4373                      sym2(:,:) = symrel(:,:,isym)
4374                    else
4375                      found = 0
4376                    end if
4377 
4378                    if (i3pert <= natom) then
4379                      ipesy3 = indsym(4,isym,i3pert)
4380                      sym3(:,:) = symrec(:,:,isym)
4381                    else if (i3pert == natom + 2) then
4382                      ipesy3 = i3pert
4383                      sym3(:,:) = symrel(:,:,isym)
4384                    else
4385                      found = 0
4386                    end if
4387 
4388                    sumr = 0_dp ; sumi = 0_dp;
4389                    do idisy1 = 1, 3
4390                      do idisy2 = 1, 3
4391                        do idisy3 = 1, 3
4392 
4393                          if ((sym1(i1dir,idisy1) /=0).and.(sym2(i2dir,idisy2) /=0) &
4394 &                         .and.(sym3(i3dir,idisy3) /=0)) then
4395 
4396                            if (blkflg(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 1) then
4397 
4398                              sumr = sumr + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4399 &                             sym3(i3dir,idisy3)*d3(1,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4400                              sumi = sumi + sym1(i1dir,idisy1)*sym2(i2dir,idisy2)*&
4401 &                             sym3(i3dir,idisy3)*d3(2,idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3)
4402 
4403                            else
4404 
4405                              found = 0
4406 
4407                            end if
4408 
4409                          end if
4410 
4411                        end do
4412                      end do
4413                    end do
4414 
4415                    if (found == 1) then
4416                      d3(1,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumr
4417                      d3(2,i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = sumi
4418                      blkflg(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4419                    end if
4420 
4421                  end do  ! isym
4422 
4423                end if  ! blkflg
4424 
4425 !              Close loop over perturbations
4426              end do
4427            end do
4428          end do
4429        end do
4430      end do
4431    end do
4432 
4433  end do  ! close loop over ithree
4434 
4435 end subroutine d3sym

m_dynmat/dfpt_phfrq [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dfpt_phfrq

FUNCTION

 Get the phonon frequencies and eigenvectors (as well as the corresponding displacements)
 If q is at Gamma, the non-analytical behaviour can be included.
 Then, the effective dielectric tensor, the effective charges
 and oscillator strengths for the limiting direction are also returned

INPUTS

  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
  d2cart(2,3,mpert,3,mpert)=dynamical matrix, effective charges, dielectric tensor,.... all in cartesian coordinates
  indsym(4,msym*natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back to the original unit cell.
  mpert =maximum number of ipert
  msym=maximum number of symmetries
  natom=number of atoms in unit cell
  nsym=number of space group symmetries
  ntypat=number of atom types
  qphnrm=(described above)
  qphon(3)= to be divided by qphnrm, give the phonon wavevector;
     if qphnrm==0.0_dp, then the wavevector is zero (Gamma point)
     and qphon gives the direction of the induced electric field in **CARTESIAN** coordinates.
     in the latter case, if qphon is zero, no non-analytical contribution is included.
  rprimd(3,3)=dimensional primitive translations (bohr)
  symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
  symrel(3,3,nsym)=matrices of the group symmetries (real space)
  typat(natom)=integer label of each type of atom (1,2,...)
  ucvol=unit cell volume

OUTPUT

  displ(2*3*natom*3*natom)= at the end, contains the displacements of atoms in cartesian coordinates.
    The first index means either the real or the imaginary part,
    The second index runs on the direction and the atoms displaced
    The third index runs on the modes.
  eigval(3*natom)=contains the eigenvalues of the dynamical matrix
  eigvec(2*3*natom*3*natom)= at the end, contains the eigenvectors of the dynamical matrix in cartesian coordinates.
  phfrq(3*natom)=phonon frequencies (square root of the dynamical matrix eigenvalues,
    except if these are negative, and in this case, give minus the square root of the absolute value
    of the matrix eigenvalues). Hartree units.

NOTES

   1) One makes the dynamical matrix hermitian...
   2) In case of q=Gamma, only the real part is used.

SOURCE

5667 subroutine dfpt_phfrq(amu,displ,d2cart,eigval,eigvec,indsym,&
5668 & mpert,msym,natom,nsym,ntypat,phfrq,qphnrm,qphon,rprimd,&
5669 & symdynmat,symrel,symafm,typat,ucvol)
5670 
5671 !Arguments -------------------------------
5672 !scalars
5673  integer,intent(in) :: mpert,msym,natom,nsym,ntypat,symdynmat
5674  real(dp),intent(in) :: qphnrm,ucvol
5675 !arrays
5676  integer,intent(in) :: indsym(4,msym*natom),symrel(3,3,nsym),typat(natom)
5677  integer,intent(in) :: symafm(nsym)
5678  real(dp),intent(in) :: amu(ntypat),d2cart(2,3,mpert,3,mpert),rprimd(3,3)
5679  real(dp),intent(inout) :: qphon(3)
5680  real(dp),intent(out) :: displ(2*3*natom*3*natom),eigval(3*natom)
5681  real(dp),intent(out) :: eigvec(2*3*natom*3*natom),phfrq(3*natom)
5682 
5683 !Local variables -------------------------
5684 !scalars
5685  integer :: analyt,i1,i2,idir1,idir2,ier,ii,imode,ipert1,ipert2
5686  integer :: jmode,indexi,indexj,index
5687  real(dp) :: epsq,qphon2
5688  logical,parameter :: debug = .False.
5689  real(dp) :: sc_prod
5690 !arrays
5691  real(dp) :: qptn(3),dum(2,0) !, tsec(2)
5692  real(dp),allocatable :: matrx(:,:),zeff(:,:),zhpev1(:,:),zhpev2(:)
5693 
5694 ! *********************************************************************
5695 
5696  ! Keep track of time spent in dfpt_phfrq
5697  !call timab(1751, 1, tsec)
5698 
5699  ! Prepare the diagonalisation: analytical part.
5700  ! Note: displ is used as work space here
5701  i1=0
5702  do ipert1=1,natom
5703    do idir1=1,3
5704      i1=i1+1
5705      i2=0
5706      do ipert2=1,natom
5707        do idir2=1,3
5708          i2=i2+1
5709          index=i1+3*natom*(i2-1)
5710          displ(2*index-1)=d2cart(1,idir1,ipert1,idir2,ipert2)
5711          displ(2*index  )=d2cart(2,idir1,ipert1,idir2,ipert2)
5712        end do
5713      end do
5714    end do
5715  end do
5716 
5717  ! Determine the analyticity of the matrix.
5718  analyt=1; if(abs(qphnrm)<tol8) analyt=0
5719  if(abs(qphon(1))<tol8.and.abs(qphon(2))<tol8.and.abs(qphon(3))<tol8) analyt=2
5720 
5721  ! In case of q=Gamma, only the real part is used
5722  if(analyt==0 .or. analyt==2)then
5723    do i1=1,3*natom
5724      do i2=1,3*natom
5725        index=i1+3*natom*(i2-1)
5726        displ(2*index)=zero
5727      end do
5728    end do
5729  end if
5730 
5731  ! In the case the non-analyticity is required:
5732  ! the tensor is in cartesian coordinates and this means that qphon must be in given in Cartesian coordinates.
5733  if(analyt==0)then
5734 
5735    ! Normalize the limiting direction
5736    qphon2=qphon(1)**2+qphon(2)**2+qphon(3)**2
5737    qphon(:)=qphon(:)/sqrt(qphon2)
5738 
5739    ! Get the dielectric constant for the limiting direction
5740    epsq=zero
5741    do idir1=1,3
5742      do idir2=1,3
5743        epsq= epsq + qphon(idir1)*qphon(idir2) * d2cart(1,idir1,natom+2,idir2,natom+2)
5744      end do
5745    end do
5746 
5747    ABI_MALLOC(zeff,(3,natom))
5748 
5749    ! Get the effective charges for the limiting direction
5750    do idir1=1,3
5751      do ipert1=1,natom
5752        zeff(idir1,ipert1)=zero
5753        do idir2=1,3
5754          zeff(idir1,ipert1) = zeff(idir1,ipert1) + qphon(idir2)* d2cart(1,idir1,ipert1,idir2,natom+2)
5755        end do
5756      end do
5757    end do
5758 
5759    ! Get the non-analytical part of the dynamical matrix, and suppress its imaginary part.
5760    i1=0
5761    do ipert1=1,natom
5762      do idir1=1,3
5763        i1=i1+1
5764        i2=0
5765        do ipert2=1,natom
5766          do idir2=1,3
5767            i2=i2+1
5768            index=i1+3*natom*(i2-1)
5769            displ(2*index-1)=displ(2*index-1)+four_pi/ucvol*zeff(idir1,ipert1)*zeff(idir2,ipert2)/epsq
5770            displ(2*index  )=zero
5771          end do
5772        end do
5773      end do
5774    end do
5775 
5776    ABI_FREE(zeff)
5777  end if !  End of the non-analyticity treatment
5778 
5779  ! Multiply IFC(q) by masses
5780  call massmult_and_breaksym(natom, ntypat, typat, amu, displ)
5781 
5782  ! ***********************************************************************
5783  ! Diagonalize the dynamical matrix
5784 
5785  !Symmetrize the dynamical matrix
5786  !FIXME: swap the next 2 lines and update test files to include symmetrization
5787  !       for Gamma point too (except in non-analytic case)
5788  !if (symdynmat==1 .and. analyt > 0) then
5789  if (symdynmat==1 .and. analyt == 1) then
5790    qptn(:)=qphon(:)
5791    if (analyt==1) qptn(:)=qphon(:)/qphnrm
5792    call symdyma(displ,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
5793  end if
5794 
5795  ii=1
5796  ABI_MALLOC(matrx,(2,(3*natom*(3*natom+1))/2))
5797  do i2=1,3*natom
5798    do i1=1,i2
5799      matrx(1,ii)=displ(1+2*(i1-1)+2*(i2-1)*3*natom)
5800      matrx(2,ii)=displ(2+2*(i1-1)+2*(i2-1)*3*natom)
5801      ii=ii+1
5802    end do
5803  end do
5804 
5805  ABI_MALLOC(zhpev1,(2,2*3*natom-1))
5806  ABI_MALLOC(zhpev2,(3*3*natom-2))
5807 
5808  call ZHPEV ('V','U',3*natom,matrx,eigval,eigvec,3*natom,zhpev1,zhpev2,ier)
5809  ABI_CHECK(ier == 0, sjoin('zhpev returned:', itoa(ier)))
5810 
5811  ABI_FREE(matrx)
5812  ABI_FREE(zhpev1)
5813  ABI_FREE(zhpev2)
5814 
5815  if (debug) then
5816    ! Check the orthonormality of the eigenvectors
5817    do imode=1,3*natom
5818      do jmode=imode,3*natom
5819        indexi=2*3*natom*(imode-1)
5820        indexj=2*3*natom*(jmode-1)
5821        sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
5822        write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
5823      end do
5824    end do
5825  end if
5826 
5827  !***********************************************************************
5828 
5829  ! Get the phonon frequencies (negative by convention, if the eigenvalue of the dynamical matrix is negative)
5830  do imode=1,3*natom
5831    if(eigval(imode)>=1.0d-16)then
5832      phfrq(imode)=sqrt(eigval(imode))
5833    else if(eigval(imode)>=-1.0d-16)then
5834      phfrq(imode)=zero
5835    else
5836      phfrq(imode)=-sqrt(-eigval(imode))
5837    end if
5838  end do
5839 
5840  ! Fix the phase of the eigenvectors
5841  call fxphas_seq(eigvec,dum, 0, 0, 1, 3*natom*3*natom, 0, 3*natom, 3*natom, 0)
5842 
5843  ! Normalise the eigenvectors
5844  call pheigvec_normalize(natom, eigvec)
5845 
5846  ! Get the phonon displacements
5847  call phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
5848 
5849  if (debug) then
5850    write(std_out,'(a)')' Phonon eigenvectors and displacements '
5851    do imode=1,3*natom
5852      indexi=2*3*natom*(imode-1)
5853      write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' eigvec(1:6*natom)=',eigvec(indexi+1:indexi+6*natom)
5854      write(std_out,'(a,i4,a,12es16.6)')' imode=',imode,' displ(1:6*natom)=',displ(indexi+1:indexi+6*natom)
5855    end do
5856 
5857    ! Check the orthonormality of the eigenvectors
5858    do imode=1,3*natom
5859      do jmode=imode,3*natom
5860        indexi=2*3*natom*(imode-1)
5861        indexj=2*3*natom*(jmode-1)
5862        sc_prod=sum(eigvec(indexi+1:indexi+6*natom)*eigvec(indexj+1:indexj+6*natom))
5863        write(std_out,'(a,2i4,a,es16.6)')' imode,jmode=',imode,jmode,' real scalar product =',sc_prod
5864      end do
5865    end do
5866  end if
5867 
5868  !call timab(1751, 2, tsec)
5869 
5870 end subroutine dfpt_phfrq

m_dynmat/dfpt_prtph [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dfpt_prtph

FUNCTION

 Print the phonon frequencies, on unit 6 as well as the printing
 unit (except if the associated number -iout- is negative),
 and for the latter, in Hartree, meV, Thz, Kelvin or cm-1.
 If eivec==1,2, also print the eigenmodes : displacements in cartesian coordinates.
 If eivec==4, generate output files for band2eps (drawing tool for the phonon band structure

INPUTS

  displ(2,3*natom,3*natom)= contains the displacements of atoms in cartesian coordinates.
  The first index means either the real or the imaginary part,
  The second index runs on the direction and the atoms displaced
  The third index runs on the modes.
  eivec=(if eivec==0, the eigendisplacements are not printed,
    if eivec==1,2, the eigendisplacements are printed,
    if eivec==4, files for band2eps
  enunit=units for output of the phonon frequencies :
    0=> Hartree and cm-1, 1=> eV and Thz, other=> Ha,Thz,eV,cm-1 and K
  iout= unit for long print (if negative, the routine only print on unit 6, and in Hartree only).
  natom= number of atom
  phfrq(3*natom)= phonon frequencies in Hartree
  qphnrm=phonon wavevector normalisation factor
  qphon(3)=phonon wavevector

OUTPUT

  Only printing

NOTES

 called by one processor only

SOURCE

6074 subroutine dfpt_prtph(displ,eivec,enunit,iout,natom,phfrq,qphnrm,qphon)
6075 
6076 !Arguments -------------------------------
6077 !scalars
6078  integer,intent(in) :: eivec,enunit,iout,natom
6079  real(dp),intent(in) :: qphnrm
6080 !arrays
6081  real(dp),intent(in) :: displ(2,3*natom,3*natom),phfrq(3*natom),qphon(3)
6082 
6083 !Local variables -------------------------
6084 !scalars
6085  integer :: i,idir,ii,imode,jj
6086  real(dp) :: tolerance
6087  logical :: t_degenerate
6088  character(len=500) :: msg
6089 !arrays
6090  real(dp) :: vecti(3),vectr(3)
6091  character(len=1) :: metacharacter(3*natom)
6092 
6093 ! *********************************************************************
6094 
6095 !Check the value of eivec
6096  if (all(eivec /= [0,1,2,4])) then
6097    write(msg, '(a,i0,a,a)' )&
6098    'In the calling subroutine, eivec is',eivec,ch10,&
6099    'but allowed values are between 0 and 4.'
6100    ABI_BUG(msg)
6101  end if
6102 
6103 !write the phonon frequencies on unit std_out
6104  write(msg,'(4a)' )' ',ch10,' phonon wavelength (reduced coordinates) , ','norm, and energies in hartree'
6105  call wrtout(std_out,msg)
6106 
6107 !The next format should be rewritten
6108  write(msg,'(a,4f5.2)' )' ',(qphon(i),i=1,3),qphnrm
6109  call wrtout(std_out,msg)
6110  do jj=1,3*natom,5
6111    if (3*natom-jj<5) then
6112      write(msg,'(5es17.9)') (phfrq(ii),ii=jj,3*natom)
6113    else
6114      write(msg,'(5es17.9)') (phfrq(ii),ii=jj,jj+4)
6115    end if
6116    call wrtout(std_out,msg)
6117  end do
6118  write(msg,'(a,a,es17.9)') ch10,' Zero Point Motion energy (sum of freqs/2)=',sum(phfrq(1:3*natom))/2
6119  call wrtout(std_out,msg)
6120 
6121 !Put the wavevector in nice format
6122  if(iout>=0)then
6123    call wrtout(iout,' ')
6124    if(qphnrm/=0.0_dp)then
6125      write(msg, '(a,3f9.5)' )&
6126      '  Phonon wavevector (reduced coordinates) :',(qphon(i)/qphnrm+tol10,i=1,3)
6127    else
6128      write(msg, '(3a,3f9.5)' )&
6129      '  Phonon at Gamma, with non-analyticity in the',ch10,&
6130      '  direction (cartesian coordinates)',qphon(1:3)+tol10
6131    end if
6132    call wrtout(iout,msg)
6133 
6134 !  Write it, in different units.
6135    if(enunit/=1)then
6136      write(iout, '(a)' )' Phonon energies in Hartree :'
6137      do jj=1,3*natom,5
6138        if (3*natom-jj<5) then
6139          write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,3*natom)
6140        else
6141          write(msg, '(1x,5es14.6)') (phfrq(ii),ii=jj,jj+4)
6142        end if
6143        call wrtout(iout,msg)
6144      end do
6145    end if
6146    if(enunit/=0)then
6147      write(iout, '(a)' )' Phonon energies in meV     :'
6148      do jj=1,3*natom,5
6149        if (3*natom-jj<5) then
6150          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,3*natom)
6151        else
6152          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_eV*1.0d3,ii=jj,jj+4)
6153        end if
6154        call wrtout(iout,msg)
6155      end do
6156    end if
6157    if(enunit/=1)then
6158      write(iout, '(a)' )' Phonon frequencies in cm-1    :'
6159      do jj=1,3*natom,5
6160        if (3*natom-jj<5) then
6161          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,3*natom)
6162        else
6163          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_cmm1,ii=jj,jj+4)
6164        end if
6165        call wrtout(iout,msg)
6166      end do
6167    end if
6168    if(enunit/=0)then
6169      write(iout, '(a)' )' Phonon frequencies in Thz     :'
6170      do jj=1,3*natom,5
6171        if (3*natom-jj<5) then
6172          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,3*natom)
6173        else
6174          write(msg, '("-",5es14.6)') (phfrq(ii)*Ha_THz,ii=jj,jj+4)
6175        end if
6176        call wrtout(iout,msg)
6177      end do
6178    end if
6179    if(enunit/=0.and.enunit/=1)then
6180      write(iout, '(a)' )' Phonon energies in Kelvin  :'
6181      do jj=1,3*natom,5
6182        if (3*natom-jj<5) then
6183          write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,3*natom)
6184        else
6185          write(msg, '("-",5es14.6)') (phfrq(ii)/kb_HaK,ii=jj,jj+4)
6186        end if
6187        call wrtout(iout,msg)
6188      end do
6189    end if
6190  end if
6191 
6192 !Take care of the eigendisplacements
6193  if(eivec==1 .or. eivec==2)then
6194    write(msg, '(a,a,a,a,a,a,a,a)' ) ch10,&
6195    ' Eigendisplacements ',ch10,&
6196    ' (will be given, for each mode : in cartesian coordinates',ch10,&
6197    '   for each atom the real part of the displacement vector,',ch10,&
6198    '   then the imaginary part of the displacement vector - absolute values smaller than 1.0d-7 are set to zero)'
6199    call wrtout(std_out,msg)
6200    if(iout>=0) then
6201      call wrtout(iout,msg)
6202    end if
6203 
6204 !  Examine the degeneracy of each mode. The portability of the echo of the eigendisplacements
6205 !  is very hard to obtain, and has not been attempted.
6206    do imode=1,3*natom
6207 !    The degenerate modes are not portable
6208      t_degenerate=.false.
6209      if(imode>1)then
6210        if(phfrq(imode)-phfrq(imode-1)<tol6)t_degenerate=.true.
6211      end if
6212      if(imode<3*natom)then
6213        if(phfrq(imode+1)-phfrq(imode)<tol6)t_degenerate=.true.
6214      end if
6215      metacharacter(imode)=';'; if(t_degenerate)metacharacter(imode)='-'
6216    end do
6217 
6218    do imode=1,3*natom
6219      write(msg,'(a,i4,a,es16.6)' )'  Mode number ',imode,'   Energy',phfrq(imode)
6220      call wrtout(std_out,msg)
6221      if(iout>=0)then
6222        write(msg, '(a,i4,a,es16.6)' )'  Mode number ',imode,'   Energy',phfrq(imode)
6223        call wrtout(iout,msg)
6224      end if
6225      tolerance=1.0d-7
6226      if(abs(phfrq(imode))<1.0d-5)tolerance=2.0d-7
6227      if(phfrq(imode)<1.0d-5)then
6228        write(msg,'(3a)' )' Attention : low frequency mode.',ch10,&
6229        '   (Could be unstable or acoustic mode)'
6230        call wrtout(std_out,msg)
6231        if(iout>=0)then
6232          write(iout, '(3a)' )' Attention : low frequency mode.',ch10,&
6233          '   (Could be unstable or acoustic mode)'
6234        end if
6235      end if
6236      do ii=1,natom
6237        do idir=1,3
6238          vectr(idir)=displ(1,idir+(ii-1)*3,imode)
6239          if(abs(vectr(idir))<tolerance)vectr(idir)=0.0_dp
6240          vecti(idir)=displ(2,idir+(ii-1)*3,imode)
6241          if(abs(vecti(idir))<tolerance)vecti(idir)=0.0_dp
6242        end do
6243        write(msg,'(i4,3es16.8,a,4x,3es16.8)' ) ii,vectr(:),ch10,vecti(:)
6244        call wrtout(std_out,msg)
6245        if(iout>=0)then
6246          write(msg,'(a,i3,3es16.8,2a,3x,3es16.8)') metacharacter(imode),ii,vectr(:),ch10,&
6247            metacharacter(imode), vecti(:)
6248          call wrtout(iout,msg)
6249        end if
6250      end do
6251    end do
6252  end if
6253 
6254 end subroutine dfpt_prtph

m_dynmat/dfpt_sydy [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dfpt_sydy

FUNCTION

 Symmetrize dynamical matrix (eventually diagonal wrt to the atoms)
 Unsymmetrized dynamical matrix is input as dyfrow;
 symmetrized dynamical matrix is then placed in sdyfro.
 If nsym=1 simply copy dyfrow into sdyfro.

INPUTS

  cplex=1 if dynamical matrix is real, 2 if it is complex
  dyfrow(3,3,natom,1+(natom-1)*nondiag)=unsymmetrized dynamical matrix
  indsym(4,msym*natom)=indirect indexing array: for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  natom=number of atoms in cell.
  nondiag=0 if dynamical matrix is     diagonal with respect to atoms
  nsym=number of symmetry operators in group.
  qphon(3)=wavevector of the phonon
  symq(4,2,nsym)=1 if symmetry preserves present qpoint. From littlegroup_q
  symrec(3,3,nsym)=symmetries of group in terms of operations on real
    space primitive translations (integers).

OUTPUT

  sdyfro(3,3,natom,1+(natom-1)*nondiag)=symmetrized dynamical matrix

NOTES

 Symmetrization of gradients with respect to reduced
 coordinates tn is conducted according to the expression
 $[d(e)/d(t(n,a))]_{symmetrized} = (1/Nsym)*Sum(S)*symrec(n,m,S)*
              [d(e)/d(t(m,b))]_{unsymmetrized}$
 where $t(m,b)= (symrel^{-1})(m,n)*(t(n,a)-tnons(n))$ and tnons
 is a possible nonsymmorphic translation.  The label "b" here
 refers to the atom which gets rotated into "a" under symmetry "S".
 symrel is the symmetry matrix in real space, which is the inverse
 transpose of symrec.  symrec is the symmetry matrix in reciprocal
 space.  $sym_{cartesian} = R * symrel * R^{-1} = G * symrec * G^{-1}$
 where the columns of R and G are the dimensional primitive translations
 in real and reciprocal space respectively.
 Note the use of "symrec" in the symmetrization expression above.

SOURCE

2366 subroutine dfpt_sydy(cplex,dyfrow,indsym,natom,nondiag,nsym,qphon,sdyfro,symq,symrec)
2367 
2368 !Arguments -------------------------------
2369 !scalars
2370  integer,intent(in) :: cplex,natom,nondiag,nsym
2371 !arrays
2372  integer,intent(in) :: indsym(4,nsym,natom),symq(4,2,nsym),symrec(3,3,nsym)
2373  real(dp),intent(in) :: dyfrow(cplex,3,3,natom,1+(natom-1)*nondiag),qphon(3)
2374  real(dp),intent(out) :: sdyfro(cplex,3,3,natom,1+(natom-1)*nondiag)
2375 
2376 !Local variables -------------------------
2377 !scalars
2378  integer :: ia,indi,indj,isym,ja,kappa,mu,natom_nondiag,nsym_used,nu
2379  logical :: qeq0
2380  real(dp) :: arg,div,phasei,phaser
2381 !arrays
2382  real(dp) :: work(cplex,3,3)
2383 
2384 ! *********************************************************************
2385 
2386  if (nsym==1) then
2387 
2388 !  Only symmetry is identity so simply copy
2389    sdyfro(:,:,:,:,:)=dyfrow(:,:,:,:,:)
2390 
2391  else
2392 
2393 !  Actually carry out symmetrization
2394    sdyfro(:,:,:,:,:)=zero
2395    qeq0=(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)
2396 !  === Diagonal dyn. matrix OR q=0
2397    if (nondiag==0.or.qeq0) then
2398      natom_nondiag=1;if (nondiag==1) natom_nondiag=natom
2399      do ja=1,natom_nondiag
2400        do ia=1,natom
2401          do isym=1,nsym
2402            indi=indsym(4,isym,ia)
2403            indj=1;if (nondiag==1) indj=indsym(4,isym,ja)
2404            work(:,:,:)=zero
2405            do mu=1,3
2406              do nu=1,3
2407                do kappa=1,3
2408                  work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
2409                end do
2410              end do
2411            end do
2412            do mu=1,3
2413              do nu=1,3
2414                do kappa=1,3
2415                  sdyfro(:,kappa,mu,ia,ja)=sdyfro(:,kappa,mu,ia,ja)+symrec(mu,nu,isym)*work(:,kappa,nu)
2416                end do
2417              end do
2418            end do
2419          end do
2420        end do
2421      end do
2422      div=one/dble(nsym)
2423      sdyfro(:,:,:,:,:)=div*sdyfro(:,:,:,:,:)
2424 !    === Non diagonal dyn. matrix AND q<>0
2425    else
2426      do ja=1,natom
2427        do ia=1,natom
2428          nsym_used=0
2429          do isym=1,nsym
2430            if (symq(4,1,isym)==1) then
2431              arg=two_pi*(qphon(1)*(indsym(1,isym,ia)-indsym(1,isym,ja)) &
2432 &             +qphon(2)*(indsym(2,isym,ia)-indsym(2,isym,ja)) &
2433 &             +qphon(3)*(indsym(3,isym,ia)-indsym(3,isym,ja)))
2434              phaser=cos(arg);phasei=sin(arg)
2435              nsym_used=nsym_used+1
2436              indi=indsym(4,isym,ia)
2437              indj=indsym(4,isym,ja)
2438              work(:,:,:)=zero
2439              do mu=1,3
2440                do nu=1,3
2441                  do kappa=1,3
2442                    work(:,mu,kappa)=work(:,mu,kappa)+symrec(mu,nu,isym)*dyfrow(:,nu,kappa,indi,indj)
2443                  end do
2444                end do
2445              end do
2446              do mu=1,3
2447                do nu=1,3
2448                  do kappa=1,3
2449                    sdyfro(1,kappa,mu,ia,ja)=sdyfro(1,kappa,mu,ia,ja) &
2450 &                   +symrec(mu,nu,isym)*(work(1,kappa,nu)*phaser-work(2,kappa,nu)*phasei)
2451                  end do
2452                end do
2453              end do
2454              if (cplex==2) then
2455                do mu=1,3
2456                  do nu=1,3
2457                    do kappa=1,3
2458                      sdyfro(2,kappa,mu,ia,ja)=sdyfro(2,kappa,mu,ia,ja) &
2459 &                     +symrec(mu,nu,isym)*(work(1,kappa,nu)*phasei+work(2,kappa,nu)*phaser)
2460                    end do
2461                  end do
2462                end do
2463              end if
2464            end if
2465          end do
2466          div=one/dble(nsym_used)
2467          sdyfro(:,:,:,ia,ja)=div*sdyfro(:,:,:,ia,ja)
2468        end do
2469      end do
2470    end if
2471 
2472  end if
2473 
2474 end subroutine dfpt_sydy

m_dynmat/dfpt_sygra [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dfpt_sygra

FUNCTION

 Symmetrize derivatives of energy with respect to coordinates,
 as appearing in phonon calculations.
 Unsymmetrized gradients are input as deunsy; symmetrized grads are then placed in desym.
 If nsym=1 simply copy deunsy into desym (only symmetry is identity).
 The index of the initial perturbation is needed, in case there is a change
 of atom position (moved in another cell) due to the symmetry operation.

INPUTS

  natom=number of atoms in cell
  deunsy(2,3,natom)=unsymmetrized gradients wrt dimensionless tn (hartree)
  note: there is a real and a imaginary part ...
  indsym(4,nsym,natom)=label given by subroutine symatm, indicating atom
   label which gets rotated into given atom by given symmetry
   (first three elements are related primitive translation--
   see symatm where this is computed)
  nsym=number of symmetry operators in group
  ipert=index of the initial perturbation
  qpt(3)= wavevector of the phonon, in reduced coordinates
  symrec(3,3,nsym)=symmetries of group in terms of operations on
    reciprocal space primitive translations--see comments below

OUTPUT

 desym(2,3,natom)=symmetrized gradients wrt dimensionless tn (hartree)

NOTES

 Written by X. Gonze starting from sygrad, written by D.C. Allan:
    introduction of the q vector for phonon symmetrization
 This routine should once be merged with sygrad...

SOURCE

2249 subroutine dfpt_sygra(natom,desym,deunsy,indsym,ipert,nsym,qpt,symrec)
2250 
2251 !Arguments -------------------------------
2252 !scalars
2253  integer,intent(in) :: ipert,natom,nsym
2254 !arrays
2255  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym)
2256  real(dp),intent(in) :: deunsy(2,3,natom),qpt(3)
2257  real(dp),intent(out) :: desym(2,3,natom)
2258 
2259 !Local variables -------------------------
2260 !scalars
2261  integer :: ia,ind,isym,mu
2262  real(dp) :: arg,im,re,sumi,sumr
2263 
2264 ! *********************************************************************
2265 
2266  if (nsym==1) then
2267 
2268 !  Only symmetry is identity so simply copy
2269    desym(:,:,:)=deunsy(:,:,:)
2270 
2271  else
2272 
2273 !  Actually conduct symmetrization
2274 !  write(std_out,*)' dfpt_sygra : desym(:2,:3,:natom),qpt(:)',desym(:2,:3,:natom),qpt(:)
2275    do ia=1,natom
2276 !    write(std_out,*)' dfpt_sygra : ia=',ia
2277      do mu=1,3
2278        sumr=zero
2279        sumi=zero
2280 !      write(std_out,*)' dfpt_sygra : mu=',mu
2281        do isym=1,nsym
2282          ind=indsym(4,isym,ia)
2283 !        Must shift the atoms back to the unit cell.
2284 !        arg=two_pi*( qpt(1)*indsym(1,isym,ia)&
2285 !        &         +qpt(2)*indsym(2,isym,ia)&
2286 !        &         +qpt(3)*indsym(3,isym,ia) )
2287 !        Selection of non-zero q point, to avoid ipert being outside the 1 ... natom range
2288          if(qpt(1)**2+qpt(2)**2+qpt(3)**2 > tol16)then
2289            arg=two_pi*( qpt(1)*(indsym(1,isym,ia)-indsym(1,isym,ipert))&
2290 &           +qpt(2)* (indsym(2,isym,ia)-indsym(2,isym,ipert))&
2291 &           +qpt(3)* (indsym(3,isym,ia)-indsym(3,isym,ipert)))
2292          else
2293            arg=zero
2294          end if
2295 
2296          re=dble(symrec(mu,1,isym))*deunsy(1,1,ind)+&
2297 &         dble(symrec(mu,2,isym))*deunsy(1,2,ind)+&
2298 &         dble(symrec(mu,3,isym))*deunsy(1,3,ind)
2299          im=dble(symrec(mu,1,isym))*deunsy(2,1,ind)+&
2300 &         dble(symrec(mu,2,isym))*deunsy(2,2,ind)+&
2301 &         dble(symrec(mu,3,isym))*deunsy(2,3,ind)
2302          sumr=sumr+re*cos(arg)-im*sin(arg)
2303          sumi=sumi+re*sin(arg)+im*cos(arg)
2304 !        sumr=sumr+re
2305 !        sumi=sumi+im
2306 !        write(std_out,*)' dfpt_sygra : isym,indsym(4,isym,ia),arg,re,im,sumr,sumi',&
2307 !        &      isym,indsym(4,isym,ia),arg,re,im,sumr,sumi
2308        end do
2309        desym(1,mu,ia)=sumr/dble(nsym)
2310        desym(2,mu,ia)=sumi/dble(nsym)
2311 !      write(std_out,*)' dfpt_sygra : desym(:,mu,ia)',desym(:,mu,ia)
2312      end do
2313    end do
2314  end if
2315 
2316 end subroutine dfpt_sygra

m_dynmat/dist9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dist9

FUNCTION

 Compute the distance between atoms

INPUTS

 acell(3)=length scales by which rprim is to be multiplied
 dist(natom,natom,nrpt)=distances between atoms
 gprim(3,3)=dimensionless primitive translations in reciprocal space
 natom=number of atoms in unit cell
 nrpt= Number of R points in the Big Box
 rcan(3,natom)=canonical coordinates of atoms
 rprim(3,3)=dimensionless primitive translations in real space
 rpt(3,nrpt)=cartesian coordinates of the points in the BigBox.

OUTPUT

 dist(natom,natom,nrpt)=distances between atoms

SOURCE

3435 subroutine dist9(acell,dist,gprim,natom,nrpt,rcan,rprim,rpt)
3436 
3437 !Arguments -------------------------------
3438 !scalars
3439  integer,intent(in) :: natom,nrpt
3440 !arrays
3441  real(dp),intent(in) :: acell(3),gprim(3,3),rcan(3,natom),rprim(3,3)
3442  real(dp),intent(in) :: rpt(3,nrpt)
3443  real(dp),intent(out) :: dist(natom,natom,nrpt)
3444 
3445 !Local variables -------------------------
3446 !scalars
3447  integer :: ia,ib,ii,irpt
3448 !arrays
3449  real(dp) :: ra(3),rb(3),rdiff(3),red(3),rptcar(3),xred(3)
3450 
3451 ! *********************************************************************
3452 
3453 !BIG loop on all generic atoms
3454  do ia=1,natom
3455    ! First transform canonical coordinates to reduced coordinates
3456    do ii=1,3
3457      xred(ii)=gprim(1,ii)*rcan(1,ia)+gprim(2,ii)*rcan(2,ia)+gprim(3,ii)*rcan(3,ia)
3458    end do
3459    ! Then to cartesian coordinates
3460    ra(:)=xred(1)*acell(1)*rprim(:,1)+xred(2)*acell(2)*rprim(:,2)+xred(3)*acell(3)*rprim(:,3)
3461    do ib=1,natom
3462      do ii=1,3
3463        xred(ii)=gprim(1,ii)*rcan(1,ib)+gprim(2,ii)*rcan(2,ib)+gprim(3,ii)*rcan(3,ib)
3464      end do
3465      do ii=1,3
3466        rb(ii)=xred(1)*acell(1)*rprim(ii,1)+xred(2)*acell(2)*rprim(ii,2)+xred(3)*acell(3)*rprim(ii,3)
3467      end do
3468      do irpt=1,nrpt
3469        ! First transform it to reduced coordinates
3470        do ii=1,3
3471          red(ii)=gprim(1,ii)*rpt(1,irpt)+gprim(2,ii)*rpt(2,irpt)+gprim(3,ii)*rpt(3,irpt)
3472        end do
3473        ! Then to cartesian coordinates
3474        do ii=1,3
3475          rptcar(ii)=red(1)*acell(1)*rprim(ii,1)+red(2)*acell(2)*rprim(ii,2)+red(3)*acell(3)*rprim(ii,3)
3476        end do
3477        do ii=1,3
3478          rdiff(ii)=-rptcar(ii)+ra(ii)-rb(ii)
3479        end do
3480        dist(ia,ib,irpt)=(rdiff(1)**2+rdiff(2)**2+rdiff(3)**2)**0.5
3481      end do
3482    end do
3483  end do
3484 
3485 end subroutine dist9

m_dynmat/dymfz9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dymfz9

FUNCTION

 As the subroutine canatm has transformed the coordinates of the
 atoms in normalized canonical coordinates, the corresponding
 dynamical matrix should be multiplied by a phase shift corresponding
 to the translation between New and Old coordinates of its two
 corresponding atoms.

INPUTS

 dynmat = non-phase shifted dynamical matrices
 natom = number of atoms
 nqpt = number of qpoints
 gprim = reciprocal lattice vectors (cartesian but dimensionless)
 option=1 : the matrices are transformed from the old (tn)
  coordinate system to the new (normalized canonical)
        2 : the matrices are restored from the normalized
  canonical coordinate system to the usual (tn) one...
 rcan = canonical coordinates of atoms
 spqpt = qpoint coordinates (reduced reciprocal)
 trans = Atomic translations : xred = rcan + trans

OUTPUT

 dynmat = phase shifted dynamical matrices

SOURCE

5344 subroutine dymfz9(dynmat,natom,nqpt,gprim,option,spqpt,trans)
5345 
5346 !Arguments -------------------------------
5347 !scalars
5348  integer,intent(in) :: natom,nqpt,option
5349 !arrays
5350  real(dp),intent(in) :: gprim(3,3),spqpt(3,nqpt),trans(3,natom)
5351  real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
5352 
5353 !Local variables -------------------------
5354 !scalars
5355  integer :: ia,ib,iqpt,mu,nu
5356  real(dp) :: im,ktrans,re
5357 !arrays
5358  real(dp) :: kk(3)
5359 
5360 ! *********************************************************************
5361 
5362  do iqpt=1,nqpt
5363    ! Definition of q in normalized reciprocal space
5364    kk(1)=spqpt(1,iqpt)*gprim(1,1)+spqpt(2,iqpt)*gprim(1,2)+spqpt(3,iqpt)*gprim(1,3)
5365    kk(2)=spqpt(1,iqpt)*gprim(2,1)+spqpt(2,iqpt)*gprim(2,2)+spqpt(3,iqpt)*gprim(2,3)
5366    kk(3)=spqpt(1,iqpt)*gprim(3,1)+spqpt(2,iqpt)*gprim(3,2)+spqpt(3,iqpt)*gprim(3,3)
5367 
5368    if(option==1)then
5369      kk(1)=-kk(1)
5370      kk(2)=-kk(2)
5371      kk(3)=-kk(3)
5372    end if
5373 
5374    do ia=1,natom
5375      do ib=1,natom
5376        ! Product of q with the differences between the two atomic translations
5377        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))
5378        do mu=1,3
5379          do nu=1,3
5380            re=dynmat(1,mu,ia,nu,ib,iqpt)
5381            im=dynmat(2,mu,ia,nu,ib,iqpt)
5382            ! Transformation of the Old dynamical matrices by New ones by multiplication by a phase shift
5383            dynmat(1,mu,ia,nu,ib,iqpt)=re*cos(two_pi*ktrans)-im*sin(two_pi*ktrans)
5384            dynmat(2,mu,ia,nu,ib,iqpt)=re*sin(two_pi*ktrans)+im*cos(two_pi*ktrans)
5385          end do
5386        end do
5387      end do
5388    end do
5389  end do
5390 
5391 end subroutine dymfz9

m_dynmat/dynmat_dq [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 dynmat_dq

FUNCTION

  Compute the derivative D(q)/dq of the dynamical matrix via Fourier transform
  of the interatomic forces

INPUTS

 qpt(3)= Reduced coordinates of the q vector in reciprocal space
 natom= Number of atoms in the unit cell
 gprim(3,3)= Normalized coordinates in reciprocal space
 nrpt= Number of R points in the Big Box
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
   These coordinates are normalized (=> * acell(3)!!)
 atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
 wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector

OUTPUT

 dddq(2,3,natom,3,natom,3)= Derivate of the dynamical matrix in cartesian coordinates.
  The tree directions are stored in the last dimension.
  These coordinates are normalized (=> * acell(3)!!)

SOURCE

3723 subroutine dynmat_dq(qpt,natom,gprim,nrpt,rpt,atmfrc,wghatm,dddq)
3724 
3725 !Arguments -------------------------------
3726 !scalars
3727  integer,intent(in) :: natom,nrpt
3728 !arrays
3729  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt(3)
3730  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
3731  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
3732  real(dp),intent(out) :: dddq(2,3,natom,3,natom,3)
3733 
3734 !Local variables -------------------------
3735 !scalars
3736  integer :: ia,ib,irpt,mu,nu,ii
3737  real(dp) :: im,kr,re
3738 !arrays
3739  real(dp) :: kk(3),fact(2,3)
3740 
3741 ! *********************************************************************
3742 
3743  dddq = zero
3744 
3745  do irpt=1,nrpt
3746    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3747    kk(1) = qpt(1)*gprim(1,1)+ qpt(2)*gprim(1,2) + qpt(3)*gprim(1,3)
3748    kk(2) = qpt(1)*gprim(2,1)+ qpt(2)*gprim(2,2) + qpt(3)*gprim(2,3)
3749    kk(3) = qpt(1)*gprim(3,1)+ qpt(2)*gprim(3,2) + qpt(3)*gprim(3,3)
3750 
3751    ! Product of k and r
3752    kr=kk(1)*rpt(1,irpt)+kk(2)*rpt(2,irpt)+kk(3)*rpt(3,irpt)
3753 
3754    ! Get phase factor
3755    re=cos(two_pi*kr); im=sin(two_pi*kr)
3756 
3757    ! Inner loop on atoms and directions
3758    do ib=1,natom
3759      do ia=1,natom
3760        if (abs(wghatm(ia,ib,irpt))>1.0d-10) then
3761          ! take into account rotation due to i.
3762          fact(1,:) = -im * wghatm(ia,ib,irpt) * rpt(:,irpt)
3763          fact(2,:) =  re * wghatm(ia,ib,irpt) * rpt(:,irpt)
3764          do nu=1,3
3765            do mu=1,3
3766              ! Real and imaginary part of the dynamical matrices
3767              ! Atmfrc should be real
3768              do ii=1,3
3769                dddq(1,mu,ia,nu,ib,ii) = dddq(1,mu,ia,nu,ib,ii) + fact(1,ii) * atmfrc(mu,ia,nu,ib,irpt)
3770                dddq(2,mu,ia,nu,ib,ii) = dddq(2,mu,ia,nu,ib,ii) + fact(2,ii) * atmfrc(mu,ia,nu,ib,irpt)
3771              end do
3772            end do
3773          end do
3774        end if
3775      end do
3776    end do
3777  end do
3778 
3779 end subroutine dynmat_dq

m_dynmat/ftgam [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 ftgam

FUNCTION

 If qtor=1 (q->r):
  Generates the Fourier transform of the recip space gkk matrices
  to obtain the real space ones.
 If qtor=0 (r->q):
  Generates the Fourier transform of the real space gkk matrices
  to obtain the reciprocal space ones.

INPUTS

 natom= Number of atoms in the unit cell
 nqpt= Number of q points in the Brillouin zone
           if qtor=0 this number is read in the input file
 nrpt= Number of R points in the Big Box
 qtor= ( q to r : see above )
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
           These coordinates are normalized (=> * acell(3)!!)
 qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
           if qtor=0 these vectors are read in the input file
 wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector

OUTPUT

  (see side effects)

SIDE EFFECTS

 Input/output
 gam_qpt(2,3*natom*3*natom,nqpt)
  = gamma matrices in recip space coming from the Derivative Data Base
 gam_rpt(2,3*natom*3*natom,nrpt)
  = gamma matrices in real space stored in file unit_gkk_rpt

NOTES

   copied from ftiaf9.f
   recip to real space: real space is forced to disk file unit_gkk_rpt
                        recip space depends on gkqwrite and unitgkq3
   real to recip space: real space is forced to disk file unit_gkk_rpt
                        recip space is necessarily in memory in gkk_qpt

    real space elements are complex, but could be reduced, as (-r) = (+r)*

SOURCE

6410 subroutine ftgam (wghatm,gam_qpt,gam_rpt,natom,nqpt,nrpt,qtor,coskr, sinkr)
6411 
6412 !Arguments -------------------------------
6413 !scalars
6414  integer,intent(in) :: natom,nqpt,nrpt,qtor
6415 !arrays
6416  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
6417  real(dp),intent(inout) :: gam_qpt(2,3*natom*3*natom,nqpt)
6418  real(dp),intent(inout) :: gam_rpt(2,3*natom*3*natom,nrpt)
6419  real(dp),intent(in) :: coskr(nqpt,nrpt)
6420  real(dp),intent(in) :: sinkr(nqpt,nrpt)
6421 
6422 !Local variables -------------------------
6423 !scalars
6424  integer :: iatom,idir,ip,iqpt,irpt,jatom,jdir
6425  real(dp) :: im,re
6426  character(len=500) :: msg
6427 
6428 ! *********************************************************************
6429 
6430  select case (qtor)
6431  case (1)
6432    ! Recip to real space
6433    gam_rpt(:,:,:) = zero
6434    do irpt=1,nrpt
6435      do iqpt=1,nqpt
6436        ! Get the phase factor with normalization!
6437        re=coskr(iqpt,irpt)
6438        im=sinkr(iqpt,irpt)
6439        do ip=1,3*natom*3*natom
6440          ! Real and imaginary part of the real-space gam matrices
6441          gam_rpt(1,ip,irpt) = gam_rpt(1,ip,irpt) + re*gam_qpt(1,ip,iqpt) + im*gam_qpt(2,ip,iqpt)
6442          gam_rpt(2,ip,irpt) = gam_rpt(2,ip,irpt) + re*gam_qpt(2,ip,iqpt) - im*gam_qpt(1,ip,iqpt)
6443        end do
6444      end do
6445    end do
6446    gam_rpt = gam_rpt/nqpt
6447 
6448  case (0)
6449    ! Recip space from real space
6450    gam_qpt(:,:,:)=zero
6451 
6452    do irpt=1,nrpt
6453      do iqpt=1,nqpt
6454 
6455        do iatom=1,natom
6456          do jatom=1,natom
6457            re = coskr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
6458            im = sinkr(iqpt,irpt)*wghatm(iatom,jatom,irpt)
6459 
6460            do idir=1,3
6461              do jdir=1,3
6462                ! Get phase factor
6463 
6464                ip= jdir + (jatom-1)*3 + (idir-1)*3*natom + (iatom-1)*9*natom
6465                ! Real and imaginary part of the interatomic forces
6466                gam_qpt(1,ip,iqpt) = gam_qpt(1,ip,iqpt) + re*gam_rpt(1,ip,irpt) - im*gam_rpt(2,ip,irpt)
6467                !DEBUG
6468                gam_qpt(2,ip,iqpt) = gam_qpt(2,ip,iqpt) + im*gam_rpt(1,ip,irpt) + re*gam_rpt(2,ip,irpt)
6469                !ENDDEBUG
6470              end do ! end jdir
6471            end do ! end idir
6472          end do
6473        end do ! end iatom
6474 
6475      end do ! end iqpt
6476    end do ! end irpt
6477 
6478  case default
6479    write(msg,'(a,i0,a)' )'The only allowed values for qtor are 0 or 1, while qtor= ',qtor,' has been required.'
6480    ABI_BUG(msg)
6481  end select
6482 
6483 end subroutine ftgam

m_dynmat/ftgam_init [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 ftgam_init

FUNCTION

  Generates the sin and cos phases for the Fourier transform of the gkk matrices

INPUTS

 gprim = reciprocal space vectors to get cartesian coord for qpt
 nqpt= Number of q points in the Brillouin zone
 nrpt= Number of R points in the Big Box
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
           These coordinates are normalized (=> * acell(3)!!)
 qpt_full(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
           if qtor=0 these vectors are read in the input file

OUTPUT

 coskr, sinkr = cosine and sine of phase factors for given r and q points

SOURCE

6508 subroutine ftgam_init (gprim,nqpt,nrpt,qpt_full,rpt,coskr, sinkr)
6509 
6510 !Arguments -------------------------------
6511 !scalars
6512  integer,intent(in) :: nqpt,nrpt
6513 !arrays
6514  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),qpt_full(3,nqpt)
6515  real(dp),intent(out) :: coskr(nqpt,nrpt)
6516  real(dp),intent(out) :: sinkr(nqpt,nrpt)
6517 
6518 !Local variables -------------------------
6519 !scalars
6520  integer :: iqpt,irpt
6521  real(dp) :: kr
6522 !arrays
6523  real(dp) :: kk(3)
6524 
6525 ! *********************************************************************
6526 
6527 ! Prepare the phase factors
6528  do iqpt=1,nqpt
6529    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
6530    kk(1) = qpt_full(1,iqpt)*gprim(1,1) + qpt_full(2,iqpt)*gprim(1,2) + qpt_full(3,iqpt)*gprim(1,3)
6531    kk(2) = qpt_full(1,iqpt)*gprim(2,1) + qpt_full(2,iqpt)*gprim(2,2) + qpt_full(3,iqpt)*gprim(2,3)
6532    kk(3) = qpt_full(1,iqpt)*gprim(3,1) + qpt_full(2,iqpt)*gprim(3,2) + qpt_full(3,iqpt)*gprim(3,3)
6533    do irpt=1,nrpt
6534      ! Product of k and r
6535      kr = kk(1)*rpt(1,irpt)+ kk(2)*rpt(2,irpt)+ kk(3)*rpt(3,irpt)
6536      coskr(iqpt,irpt)=cos(two_pi*kr)
6537      sinkr(iqpt,irpt)=sin(two_pi*kr)
6538    end do
6539  end do
6540 
6541 end subroutine ftgam_init

m_dynmat/ftifc_q2r [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 ftifc_q2r

FUNCTION

  Generates the Fourier transform of the dynamical matrices
  to obtain interatomic forces (real space).

INPUTS

 dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base
 gprim(3,3)= Normalized coordinates in reciprocal space
 natom= Number of atoms in the unit cell
 nqpt= Number of q points in the Brillouin zone
 nrpt= Number of R points in the Big Box
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
           These coordinates are normalized (=> * acell(3)!!)
 spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
 comm=MPI communicator.

OUTPUT

 atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space.

SOURCE

3515 subroutine ftifc_q2r(atmfrc,dynmat,gprim,natom,nqpt,nrpt,rpt,spqpt,comm)
3516 
3517 !Arguments -------------------------------
3518 !scalars
3519  integer,intent(in) :: natom,nqpt,nrpt,comm
3520 !arrays
3521  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
3522  real(dp),intent(out) :: atmfrc(3,natom,3,natom,nrpt)
3523  real(dp),intent(in) :: dynmat(2,3,natom,3,natom,nqpt)
3524 
3525 !Local variables -------------------------
3526 !scalars
3527  integer :: ia,ib,iqpt,irpt,mu,nu,nprocs,my_rank,ierr
3528  real(dp) :: im,kr,re
3529 !arrays
3530  real(dp) :: kk(3)
3531 
3532 ! *********************************************************************
3533 
3534  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
3535 
3536  ! Interatomic Forces from Dynamical Matrices
3537  atmfrc = zero
3538  do irpt=1,nrpt
3539    if (mod(irpt, nprocs) /= my_rank) cycle ! mpi-parallelism
3540    do iqpt=1,nqpt
3541 
3542      ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3543      kk(1)=spqpt(1,iqpt)*gprim(1,1)+spqpt(2,iqpt)*gprim(1,2)+spqpt(3,iqpt)*gprim(1,3)
3544      kk(2)=spqpt(1,iqpt)*gprim(2,1)+spqpt(2,iqpt)*gprim(2,2)+spqpt(3,iqpt)*gprim(2,3)
3545      kk(3)=spqpt(1,iqpt)*gprim(3,1)+spqpt(2,iqpt)*gprim(3,2)+spqpt(3,iqpt)*gprim(3,3)
3546 
3547      ! Product of k and r
3548      kr=kk(1)*rpt(1,irpt)+kk(2)*rpt(2,irpt)+kk(3)*rpt(3,irpt)
3549 
3550      ! Get the phase factor
3551      re=cos(two_pi*kr)
3552      im=sin(two_pi*kr)
3553 
3554      ! Now, big inner loops on atoms and directions
3555      ! The indices are ordered to give better speed
3556      do ib=1,natom
3557        do nu=1,3
3558          do ia=1,natom
3559            do mu=1,3
3560              ! Real and imaginary part of the interatomic forces
3561              atmfrc(mu,ia,nu,ib,irpt)=atmfrc(mu,ia,nu,ib,irpt) &
3562               +re*dynmat(1,mu,ia,nu,ib,iqpt)&
3563               +im*dynmat(2,mu,ia,nu,ib,iqpt)
3564              !The imaginary part should be equal to zero !!!!!!
3565              !atmfrc(2,mu,ia,nu,ib,irpt)=atmfrc(2,mu,ia,nu,ib,irpt) &
3566              !          +re*dynmat(2,mu,ia,nu,ib,iqpt) &
3567              !          -im*dynmat(1,mu,ia,nu,ib,iqpt)
3568            end do
3569          end do
3570        end do
3571      end do
3572 
3573    end do
3574  end do
3575 
3576  call xmpi_sum(atmfrc, comm, ierr)
3577  !The sumifc has to be weighted by a normalization factor of 1/nqpt
3578  atmfrc = atmfrc/nqpt
3579 
3580 end subroutine ftifc_q2r

m_dynmat/ftifc_r2q [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 ftifc_r2q

FUNCTION

 Generates the Fourier transform of the interatomic forces
 to obtain dynamical matrices in reciprocal space: R --> q.

INPUTS

 atmfrc(3,natom,3,natom,nrpt)= Interatomic Forces in real space
 gprim(3,3)= Normalized coordinates in reciprocal space
 natom= Number of atoms in the unit cell
 nqpt= Number of q points in the Brillouin zone
 nrpt= Number of R points in the Big Box
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
   These coordinates are normalized (=> * acell(3)!!)
 spqpt(3,nqpt)= Reduced coordinates of the q vectors in reciprocal space
 wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
 comm: MPI communicator

OUTPUT

 dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base

SOURCE

3611 subroutine ftifc_r2q(atmfrc, dynmat, gprim, natom, nqpt, nrpt, rpt, spqpt, wghatm, comm)
3612 
3613 !Arguments -------------------------------
3614 !scalars
3615  integer,intent(in) :: natom,nqpt,nrpt,comm
3616 !arrays
3617  real(dp),intent(in) :: gprim(3,3),rpt(3,nrpt),spqpt(3,nqpt)
3618  real(dp),intent(in) :: wghatm(natom,natom,nrpt)
3619  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
3620  real(dp),intent(out) :: dynmat(2,3,natom,3,natom,nqpt)
3621 
3622 !Local variables -------------------------
3623 !scalars
3624  integer :: ia,ib,iqpt,irpt,mu,nu,cnt,my_rank,nprocs, ierr
3625  real(dp) :: facti,factr,im,kr,re
3626  !real(dp) : w(2, natom, natom)
3627 !arrays
3628  real(dp) :: kk(3)
3629 
3630 ! *********************************************************************
3631 
3632  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
3633  dynmat = zero; cnt = 0
3634 
3635  ! MG: This is an hotspot. I don'tknow whether one should rewrite with BLAS1 dot or not.
3636  ! Note, however, that simply removing the check on the weights inside the loop over atoms.
3637  ! leads to a non-negligible speedup with intel (~30% if dipdip -1 is used)
3638  do iqpt=1,nqpt
3639 
3640    ! Calculation of the k coordinates in Normalized Reciprocal coordinates
3641    kk(1)=spqpt(1,iqpt)*gprim(1,1)+spqpt(2,iqpt)* gprim(1,2)+spqpt(3,iqpt)*gprim(1,3)
3642    kk(2)=spqpt(1,iqpt)*gprim(2,1)+spqpt(2,iqpt)* gprim(2,2)+spqpt(3,iqpt)*gprim(2,3)
3643    kk(3)=spqpt(1,iqpt)*gprim(3,1)+spqpt(2,iqpt)* gprim(3,2)+spqpt(3,iqpt)*gprim(3,3)
3644 
3645    do irpt=1,nrpt
3646      cnt = cnt + 1; if (mod(cnt, nprocs) /= my_rank) cycle ! MPI parallelism.
3647 
3648      ! k.R
3649      kr = kk(1)*rpt(1,irpt)+kk(2)*rpt(2,irpt)+kk(3)*rpt(3,irpt)
3650      ! Get phase factor
3651      re = cos(two_pi*kr); im = sin(two_pi*kr)
3652 
3653      ! Inner loop on atoms and directions
3654      do ib=1,natom
3655        do ia=1,natom
3656          !if (abs(wghatm(ia,ib,irpt)) > tol10) then  ! Commented by MG
3657            factr = re * wghatm(ia,ib,irpt)
3658            facti = im * wghatm(ia,ib,irpt)
3659            do nu=1,3
3660              do mu=1,3
3661                ! Real and imaginary part of the dynamical matrices
3662                ! Atmfrc should be real
3663                dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + factr * atmfrc(mu,ia,nu,ib,irpt)
3664                dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + facti * atmfrc(mu,ia,nu,ib,irpt)
3665              end do
3666            end do
3667          !end if
3668        end do
3669      end do
3670 
3671      ! MG: New version: I don't know if it's faster.
3672      !w(1,:,:) = re * wghatm(:,:,irpt)
3673      !w(2,:,:) = im * wghatm(:,:,irpt)
3674      !do ib=1,natom
3675      !  do nu=1,3
3676      !    do ia=1,natom
3677      !      do mu=1,3
3678      !        ! Real and imaginary part of the dynamical matrices
3679      !        ! Atmfrc should be real
3680      !        dynmat(1,mu,ia,nu,ib,iqpt) = dynmat(1,mu,ia,nu,ib,iqpt) + w(1,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
3681      !        dynmat(2,mu,ia,nu,ib,iqpt) = dynmat(2,mu,ia,nu,ib,iqpt) + w(2,ia,ib) * atmfrc(mu,ia,nu,ib,irpt)
3682      !     end do
3683      !    end do
3684      !  end do
3685      !end do
3686 
3687    end do
3688  end do
3689 
3690  if (nprocs > 1) call xmpi_sum(dynmat, comm, ierr)
3691 
3692 end subroutine ftifc_r2q

m_dynmat/get_bigbox_and_weights [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 get_bigbox_and_weights

FUNCTION

 Compute the Big Box containing the R points in the cartesian real space needed to Fourier Transform
 the dynamical matrix into its corresponding interatomic force.

INPUTS

 brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
 natom= Number of atoms
 nqbz= Number of q-points in BZ.
 ngqpt(3)= Numbers used to generate the q points to sample the Brillouin zone using an homogeneous grid
 nqshift= number of shifts in q-mesh
 qshift(3, nqshift) = Q-mesh shifts
 rprim(3,3)= Normalized coordinates in real space.
 rprimd, gprimd
 rcan(3,natom)  = Atomic position in canonical coordinates
 cutmode=Define the cutoff used to filter the output R-points according to their weights.
   0 --> No cutoff (mainly for debugging)
   1 --> Include only those R-points for which sum(abs(wg(:,:,irpt)) < tol20
         This is the approach used for the dynamical matrix.
   2 --> Include only those R-points for which the trace over iatom of abs(wg(iat,iat,irpt)) < tol20
         This option is used for objects that depend on a single atomic index.
 comm= MPI communicator

OUTPUT

 nrpt= Total Number of R points in the Big Box
 cell(3,nrpt) Give the index of the the cell and irpt
 rpt(3,nrpt)= Canonical coordinates of the R points in the unit cell. These coordinates are normalized (=> * acell(3)!!)
 r_inscribed_sphere
 wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector

SOURCE

2679 subroutine get_bigbox_and_weights(brav, natom, nqbz, ngqpt, nqshift, qshift, rprim, rprimd, gprim, rcan, &
2680                                   cutmode, nrpt, rpt, cell, wghatm, r_inscribed_sphere, comm)
2681 
2682 !Arguments -------------------------------
2683 !scalars
2684  integer,intent(in) :: brav, natom, nqbz, nqshift, cutmode, comm
2685  integer,intent(out) :: nrpt
2686  real(dp),intent(out) :: r_inscribed_sphere
2687 !arrays
2688  integer,intent(in) :: ngqpt(3)
2689  real(dp),intent(in) :: gprim(3,3),rprim(3,3),rprimd(3,3), rcan(3, natom)
2690  real(dp),intent(in) :: qshift(3, nqshift)
2691  integer,allocatable,intent(out) :: cell(:,:)
2692  real(dp),allocatable,intent(out) :: rpt(:,:), wghatm(:,:,:)
2693 
2694 !Local variables -------------------------
2695 !scalars
2696  integer :: my_ierr, ierr, ii, irpt, all_nrpt
2697  real(dp) :: toldist
2698  integer :: ngqpt9(9)
2699  character(len=500*4) :: msg
2700 !arrays
2701  integer,allocatable :: all_cell(:,:)
2702  real(dp),allocatable :: all_rpt(:,:), all_wghatm(:,:,:)
2703 
2704 ! *********************************************************************
2705 
2706  ABI_CHECK(any(cutmode == [0, 1, 2]), "cutmode should be in [0, 1, 2]")
2707 
2708  ! Create the Big Box of R vectors in real space and compute the number of points (cells) in real space
2709  call make_bigbox(brav, all_cell, ngqpt, nqshift, rprim, all_nrpt, all_rpt)
2710 
2711  ! Weights associated to these R points and to atomic pairs
2712  ABI_MALLOC(all_wghatm, (natom, natom, all_nrpt))
2713 
2714  ! HM: this tolerance is highly dependent on the compilation/architecture
2715  !     numeric errors in the DDB text file. Try a few tolerances and check whether all the weights are found.
2716  ngqpt9 = 0; ngqpt9(1:3) = ngqpt(1:3)
2717  toldist = tol8
2718  do while (toldist <= tol6)
2719    ! Note ngqpt(9) with intent(inout)!
2720    call wght9(brav, gprim, natom, ngqpt9, nqbz, nqshift, all_nrpt, qshift, rcan, &
2721               all_rpt, rprimd, toldist, r_inscribed_sphere, all_wghatm, my_ierr)
2722    call xmpi_max(my_ierr, ierr, comm, ii)
2723    if (ierr > 0) toldist = toldist * 10
2724    if (ierr == 0) exit
2725  end do
2726 
2727  if (ierr > 0) then
2728    write(msg, '(3a,es14.4,2a,i0, 14a)' ) &
2729     'The sum of the weight is not equal to nqpt.',ch10,&
2730     'The sum of the weights is: ',sum(all_wghatm),ch10,&
2731     'The number of q points is: ',nqbz, ch10, &
2732     'This might have several sources.',ch10,&
2733     'If toldist is larger than 1.0e-8, the atom positions might be loose.',ch10,&
2734     'and the q point weights not computed properly.',ch10,&
2735     'Action: make input atomic positions more symmetric.',ch10,&
2736     'Otherwise, you might increase "buffer" in m_dynmat.F90 see bigbx9 subroutine and recompile.',ch10,&
2737     'Actually, this can also happen when ngqpt is 0 0 0,',ch10,&
2738     'if abs(brav) /= 1, in this case you should change brav to 1. If brav is already set to 1 (default) try -1.'
2739    ABI_ERROR(msg)
2740  end if
2741 
2742  ! Only conserve the necessary points in rpt.
2743  nrpt = 0
2744  do irpt=1,all_nrpt
2745    if (filterw(all_wghatm(:,:,irpt))) cycle
2746    nrpt = nrpt + 1
2747  end do
2748 
2749  ! Allocate output arrays and transfer data.
2750  ABI_MALLOC(rpt, (3, nrpt))
2751  ABI_MALLOC(cell, (3, nrpt))
2752  ABI_MALLOC(wghatm, (natom, natom, nrpt))
2753 
2754  ii = 0
2755  do irpt=1,all_nrpt
2756    if (filterw(all_wghatm(:,:,irpt))) cycle
2757    ii = ii + 1
2758    rpt(:, ii) = all_rpt(:,irpt)
2759    wghatm(:,:,ii) = all_wghatm(:,:,irpt)
2760    cell(:,ii) = all_cell(:,irpt)
2761  end do
2762 
2763  ABI_FREE(all_rpt)
2764  ABI_FREE(all_wghatm)
2765  ABI_FREE(all_cell)
2766 
2767 contains
2768 
2769 logical pure function filterw(wg)
2770 
2771  real(dp),intent(in) :: wg(natom,natom)
2772  integer :: iat
2773  real(dp) :: trace
2774 
2775  select case (cutmode)
2776  case (1)
2777    filterw = sum(abs(wg)) < tol20
2778  case (2)
2779    trace = zero
2780    do iat=1,natom
2781      trace = trace + abs(wg(iat,iat))
2782    end do
2783    filterw = trace < tol20
2784  case default
2785    filterw = .False.
2786  end select
2787 
2788 end function filterw
2789 
2790 end subroutine get_bigbox_and_weights

m_dynmat/gtdyn9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 gtdyn9

FUNCTION

 Generates a dynamical matrix from interatomic force
 constants and long-range electrostatic interactions.

INPUTS

 acell(3)=length scales by which rprim is to be multiplied
 atmfrc(3,natom,3,natom,nrpt) = Interatomic Forces in real space
 dielt(3,3) = dielectric tensor
 dipdip= if 0, no dipole-dipole interaction was subtracted in atmfrc
  if 1, atmfrc has been build without dipole-dipole part
 dyewq0(3,3,natom)= Ewald part of the dynamical matrix, at q=0.
 gmet(3,3)= metric tensor in reciprocal space.
 gprim(3,3)= Normalized coordinates in reciprocal space
 mpert =maximum number of ipert
 natom= Number of atoms in the unit cell
 nrpt= Number of R points in the Big Box
 qphnrm= Normalisation coefficient for qpt
 qpt(3)= Reduced coordinates of the q vectors in reciprocal space
 rmet(3,3)= Metric tensor in real space.
 rprim(3,3)= dimensionless primitive translations in real space
 rpt(3,nprt)= Canonical coordinates of the R points in the unit cell
  These coordinates are normalized (=> * acell(3)!!)
 trans(3,natom)= Atomic translations : xred = rcan + trans
 ucvol= unit cell volume
 wghatm(natom,natom,nrpt)= Weights associated to a pair of atoms and to a R vector
 xred(3,natom)= relative coords of atoms in unit cell (dimensionless)
 zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
 comm=MPI communicator.
 [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
 [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part

OUTPUT

 d2cart(2,3,mpert,3,mpert)=dynamical matrix obtained for the wavevector qpt (normalized using qphnrm)

SOURCE

5517 subroutine gtdyn9(acell,atmfrc,dielt,dipdip,dyewq0,d2cart,gmet,gprim,mpert,natom,&
5518                   nrpt,qphnrm,qpt,rmet,rprim,rpt,trans,ucvol,wghatm,xred,zeff,qdrp_cart,ewald_option,comm,&
5519                   dipquad,quadquad)  ! optional
5520 
5521 !Arguments -------------------------------
5522 !scalars
5523  integer,intent(in) :: dipdip,mpert,natom,nrpt,ewald_option,comm
5524  real(dp),intent(in) :: qphnrm,ucvol
5525  integer,optional,intent(in) :: dipquad, quadquad
5526 !arrays
5527  real(dp),intent(in) :: acell(3),dielt(3,3),gmet(3,3),gprim(3,3),qpt(3)
5528  real(dp),intent(in) :: rmet(3,3),rprim(3,3),rpt(3,nrpt)
5529  real(dp),intent(in) :: trans(3,natom),wghatm(natom,natom,nrpt),xred(3,natom)
5530  real(dp),intent(in) :: zeff(3,3,natom)
5531  real(dp),intent(in) :: qdrp_cart(3,3,3,natom)
5532  real(dp),intent(in) :: atmfrc(3,natom,3,natom,nrpt)
5533  real(dp),intent(in) :: dyewq0(3,3,natom)
5534  real(dp),intent(out) :: d2cart(2,3,mpert,3,mpert)
5535 
5536 !Local variables -------------------------
5537 !scalars
5538  integer,parameter :: nqpt1 = 1, option2 = 2, sumg0 = 0, plus1 = 1, iqpt1 = 1
5539  integer :: i1, i2, ib, nsize, dipquad_, quadquad_
5540 !arrays
5541  real(dp) :: qphon(3) !, tsec(2)
5542  real(dp),allocatable :: dq(:,:,:,:,:),dyew(:,:,:,:,:)
5543 
5544 ! *********************************************************************
5545 
5546  ! Keep track of time spent in gtdyn9
5547  !call timab(1750, 1, tsec)
5548 
5549  ABI_MALLOC(dq,(2,3,natom,3,natom))
5550 
5551  ! Define quadrupolar options
5552  dipquad_=0; if(present(dipquad)) dipquad_=dipquad
5553  quadquad_=0; if(present(quadquad)) quadquad_=quadquad
5554 
5555  ! Get the normalized wavevector
5556  if(abs(qphnrm)<1.0d-7)then
5557    qphon(1:3)=zero
5558  else
5559    qphon(1:3)=qpt(1:3)/qphnrm
5560  end if
5561 
5562  ! Generate the analytical part from the interatomic forces
5563  call ftifc_r2q(atmfrc, dq, gprim, natom, nqpt1, nrpt, rpt, qphon, wghatm, comm)
5564 
5565  ! The analytical dynamical matrix dq has been generated
5566  ! in the normalized canonical coordinate system.
5567  ! Now, the phase is modified, in order to recover the usual (xred) coordinate of atoms.
5568  call dymfz9(dq,natom,nqpt1,gprim,option2,qphon,trans)
5569 
5570  if (dipdip==1.or.dipquad_==1.or.quadquad_==1) then
5571    ! Add the non-analytical part
5572    ! Compute dyew(2,3,natom,3,natom)= Ewald part of the dynamical matrix,
5573    ! second energy derivative wrt xred(3,natom) in Hartrees (Denoted A-bar in the notes)
5574    ABI_MALLOC(dyew,(2,3,natom,3,natom))
5575 
5576    call ewald9(acell,dielt,dyew,gmet,gprim,natom,qphon,rmet,rprim,sumg0,ucvol,xred,zeff,&
5577       qdrp_cart,option=ewald_option,dipquad=dipquad_,quadquad=quadquad_)
5578 
5579    call q0dy3_apply(natom,dyewq0,dyew)
5580    call nanal9(dyew,dq,iqpt1,natom,nqpt1,plus1)
5581 
5582    ABI_FREE(dyew)
5583  end if
5584 
5585  ! Copy the dynamical matrix in the proper location
5586  ! First zero all the elements
5587  nsize=2*(3*mpert)**2
5588  d2cart = zero
5589 
5590  ! Copy the elements from dq to d2cart
5591  d2cart(:,:,1:natom,:,1:natom)=dq(:,:,1:natom,:,1:natom)
5592 
5593  ! In case we have the gamma point,
5594  if(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-14)then
5595    ! Copy the effective charge and dielectric constant in the final array
5596    do i1=1,3
5597      do i2=1,3
5598        d2cart(1,i1,natom+2,i2,natom+2)=dielt(i1,i2)
5599        do ib=1,natom
5600          d2cart(1,i1,natom+2,i2,ib)=zeff(i1,i2,ib)
5601          d2cart(1,i2,ib,i1,natom+2)=zeff(i1,i2,ib)
5602        end do
5603      end do
5604    end do
5605  end if
5606 
5607  ABI_FREE(dq)
5608 
5609  !call timab(1750, 2, tsec)
5610 
5611 end subroutine gtdyn9

m_dynmat/ifclo9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 ifclo9

FUNCTION

 Convert from cartesian coordinates to local coordinates
 the 3*3 interatomic force constant matrix

INPUTS

 ifccar(3,3)= matrix of interatomic force constants in cartesian
  coordinates
 vect1(3)= cartesian coordinates of the first local vector
 vect2(3)= cartesian coordinates of the second local vector
 vect3(3)= cartesian coordinates of the third local vector

OUTPUT

 ifcloc(3,3)= matrix of interatomic force constants in local coordinates

SOURCE

3804 subroutine ifclo9(ifccar,ifcloc,vect1,vect2,vect3)
3805 
3806 !Arguments -------------------------------
3807 !arrays
3808  real(dp),intent(in) :: ifccar(3,3),vect1(3),vect2(3),vect3(3)
3809  real(dp),intent(out) :: ifcloc(3,3)
3810 
3811 !Local variables -------------------------
3812 !scalars
3813  integer :: ii,jj
3814 !arrays
3815  real(dp) :: work(3,3)
3816 
3817 ! *********************************************************************
3818 
3819  do jj=1,3
3820    do ii=1,3
3821      work(jj,ii)=zero
3822    end do
3823    do ii=1,3
3824      work(jj,1)=work(jj,1)+ifccar(jj,ii)*vect1(ii)
3825      work(jj,2)=work(jj,2)+ifccar(jj,ii)*vect2(ii)
3826      work(jj,3)=work(jj,3)+ifccar(jj,ii)*vect3(ii)
3827    end do
3828  end do
3829 
3830  do jj=1,3
3831    do ii=1,3
3832      ifcloc(ii,jj)=zero
3833    end do
3834    do ii=1,3
3835      ifcloc(1,jj)=ifcloc(1,jj)+vect1(ii)*work(ii,jj)
3836      ifcloc(2,jj)=ifcloc(2,jj)+vect2(ii)*work(ii,jj)
3837      ifcloc(3,jj)=ifcloc(3,jj)+vect3(ii)*work(ii,jj)
3838    end do
3839  end do
3840 
3841 end subroutine ifclo9

m_dynmat/make_bigbox [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 make_bigbox

FUNCTION

 Helper functions to faciliate the generation of a Big Box containing
 all the R points in the cartesian real space needed to Fourier Transform
 the dynamical matrix into its corresponding interatomic force.
 See bigbx9 for the algorithm.

INPUTS

 brav= Bravais Lattice (1 or -1=S.C.;2=F.C.C.;3=BCC;4=Hex.)
 ngqpt(3)= Numbers used to generate the q points to sample the
   Brillouin zone using an homogeneous grid
 nqshft= number of q-points in the repeated cell for the Brillouin zone sampling
  When nqshft is not 1, but 2 or 4 (only other allowed values),
  the limits for the big box have to be extended by a factor of 2.
 rprim(3,3)= Normalized coordinates in real space  !!! IS THIS CORRECT?

OUTPUT

 cell(3,nrpt)= integer coordinates of the cells (R points) in the rprim basis
 nprt= Number of cells (R points) in the Big Box
 rpt(3,mrpt)= canonical coordinates of the cells (R points)
  These coordinates are normalized (=> * acell(3)!!)
  The array is allocated here with the proper dimension. Client code is responsible
  for the deallocation.

SOURCE

2824 subroutine make_bigbox(brav, cell, ngqpt, nqshft, rprim, nrpt, rpt)
2825 
2826 !Arguments -------------------------------
2827 !scalars
2828  integer,intent(in) :: brav,nqshft
2829  integer,intent(out) :: nrpt
2830 !arrays
2831  integer,intent(in) :: ngqpt(3)
2832  real(dp),intent(in) :: rprim(3,3)
2833  real(dp),allocatable,intent(out) :: rpt(:,:)
2834  integer,allocatable,intent(out) :: cell(:,:)
2835 
2836 !Local variables -------------------------
2837 !scalars
2838  integer :: choice,mrpt
2839 !arrays
2840  real(dp) :: dummy_rpt(3,1)
2841  integer:: dummy_cell(1,3)
2842 
2843 ! *********************************************************************
2844 
2845  ! Compute the number of points (cells) in real space
2846  choice=0
2847  call bigbx9(brav,dummy_cell,choice,1,ngqpt,nqshft,mrpt,rprim,dummy_rpt)
2848 
2849  ! Now we can allocate and calculate the points and the weights.
2850  nrpt = mrpt
2851  ABI_MALLOC(rpt,(3,nrpt))
2852  ABI_MALLOC(cell,(3,nrpt))
2853 
2854  choice=1
2855  call bigbx9(brav,cell,choice,mrpt,ngqpt,nqshft,nrpt,rprim,rpt)
2856 
2857 end subroutine make_bigbox

m_dynmat/massmult_and_breaksym [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

  mult_masses_and_break_symms

FUNCTION

  Multiply the IFC(q) by the atomic masses, slightly break symmetry to make tests more
  portable and make the matrix hermitian before returning.

INPUTS

  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
  natom=number of atoms in unit cell
  ntypat=number of atom types
  typat(natom)=integer label of each type of atom (1,2,...)
  [herm_opt]= 1 to hermitianize mat (default)
              0 if no symmetrization should be performed

SIDE EFFECTS

  mat(2*3*natom*3*natom)=Multiplies by atomic masses in output.

SOURCE

6278 subroutine massmult_and_breaksym(natom, ntypat, typat, amu, mat, &
6279                                  herm_opt) ! optional
6280 
6281 !Arguments -------------------------------
6282 !scalars
6283  integer,intent(in) :: natom,ntypat
6284  integer,optional,intent(in) :: herm_opt
6285 !arrays
6286  integer,intent(in) :: typat(natom)
6287  real(dp),intent(in) :: amu(ntypat)
6288  real(dp),intent(inout) :: mat(2*3*natom*3*natom)
6289 
6290 !Local variables -------------------------
6291 !scalars
6292  integer :: i1,i2,idir1,idir2,index,ipert1,ipert2, herm_opt__
6293  real(dp),parameter :: break_symm=1.0d-12
6294  !real(dp),parameter :: break_symm=zero
6295  real(dp) :: fac
6296 !arrays
6297  real(dp) :: nearidentity(3,3)
6298 
6299 ! *********************************************************************
6300 
6301  herm_opt__ = 1; if (present(herm_opt)) herm_opt__ = herm_opt
6302 
6303  ! This slight breaking of the symmetry allows the results to be more portable between machines
6304  nearidentity(:,:)=one
6305  nearidentity(1,1)=one+break_symm
6306  nearidentity(3,3)=one-break_symm
6307 
6308  ! Include the masses in the dynamical matrix
6309  do ipert1=1,natom
6310    do ipert2=1,natom
6311      fac=1.0_dp/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
6312      do idir1=1,3
6313        do idir2=1,3
6314          i1=idir1+(ipert1-1)*3
6315          i2=idir2+(ipert2-1)*3
6316          index=i1+3*natom*(i2-1)
6317          mat(2*index-1)=mat(2*index-1)*fac*nearidentity(idir1,idir2)
6318          mat(2*index  )=mat(2*index  )*fac*nearidentity(idir1,idir2)
6319          ! This is to break slightly the translation invariance, and make the automatic tests more portable
6320          if(ipert1==ipert2 .and. idir1==idir2)then
6321            mat(2*index-1)=mat(2*index-1)+break_symm*natom/amu_emass/idir1*0.01_dp
6322          end if
6323        end do
6324      end do
6325    end do
6326  end do
6327 
6328  ! Make the dynamical matrix hermitian
6329  if (herm_opt__ == 1) call mkherm(mat,3*natom)
6330 
6331 end subroutine massmult_and_breaksym

m_dynmat/massmult_and_breaksym_cplx [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

  mult_masses_and_break_symms_cplx

FUNCTION

  Similar to massmult_and_breaksym, the only difference is that it receives complex array.

m_dynmat/nanal9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 nanal9

FUNCTION

 If plus=0 then substracts the non-analytical part from one dynamical
           matrices, with number iqpt.
 If plus=1 then adds the non-analytical part to the dynamical
           matrices, with number iqpt.

 For plus=0, see Eq.(76) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
 get the left hand side.

INPUTS

 dyew(2,3,natom,3,natom)= Non-analytical part
 natom= Number of atoms in the unit cell
 iqpt= Referenced q point for the dynamical matrix
 nqpt= Number of q points
 plus= (see above)

OUTPUT

 dynmat(2,3,natom,3,natom,nqpt)= Dynamical matrices coming from the Derivative Data Base

SOURCE

5422 subroutine nanal9(dyew,dynmat,iqpt,natom,nqpt,plus)
5423 
5424 !Arguments -------------------------------
5425 !scalars
5426  integer,intent(in) :: iqpt,natom,nqpt,plus
5427 !arrays
5428  real(dp),intent(in) :: dyew(2,3,natom,3,natom)
5429  real(dp),intent(inout) :: dynmat(2,3,natom,3,natom,nqpt)
5430 
5431 !Local variables -------------------------
5432 !scalars
5433  integer :: ia,ib,mu,nu
5434  character(len=500) :: msg
5435 
5436 ! *********************************************************************
5437 
5438  if (plus==0) then
5439 
5440    do ia=1,natom
5441      do ib=1,natom
5442        do mu=1,3
5443          do nu=1,3
5444            ! The following four lines are OK
5445            dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) - dyew(1,mu,ia,nu,ib)
5446            dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) - dyew(2,mu,ia,nu,ib)
5447          end do
5448        end do
5449      end do
5450    end do
5451 
5452  else if (plus==1) then
5453    do ia=1,natom
5454      do ib=1,natom
5455        do mu=1,3
5456          do nu=1,3
5457            dynmat(1,mu,ia,nu,ib,iqpt)=dynmat(1,mu,ia,nu,ib,iqpt) + dyew(1,mu,ia,nu,ib)
5458            dynmat(2,mu,ia,nu,ib,iqpt)=dynmat(2,mu,ia,nu,ib,iqpt) + dyew(2,mu,ia,nu,ib)
5459          end do
5460        end do
5461      end do
5462    end do
5463 
5464  else
5465    write(msg,'(3a,i0,a)' )&
5466     'The argument "plus" must be equal to 0 or 1.',ch10,&
5467     'The value ',plus,' is not available.'
5468    ABI_BUG(msg)
5469  end if
5470 
5471 end subroutine nanal9

m_dynmat/phangmom_from_eigvec [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 phangmom_from_eigvec

FUNCTION

  Phonon angular momenta in cart coords from eigenvectors

INPUTS

  natom: number of atoms in unit cell
  eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.

OUTPUT

  phangmom(3*3*natom)= angular momentum of each phonon mode in cartesian coordinates.
    The first index runs on the direction,
    The second index runs on the modes.

SOURCE

6004 pure subroutine phangmom_from_eigvec(natom, eigvec, phangmom)
6005 
6006 !Arguments -------------------------------
6007 !scalars
6008  integer,intent(in) :: natom
6009 !arrays
6010  real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
6011  real(dp),intent(out) :: phangmom(3*3*natom)
6012 
6013 !Local variables -------------------------
6014 !scalars
6015  integer :: imode,ipert, index
6016 !arrays
6017  real(dp) :: eigvecatom(2*3)
6018 
6019 ! *********************************************************************
6020 
6021  phangmom = zero
6022 
6023  do imode=1,3*natom
6024    do ipert=1,natom
6025      index = 3*natom*(imode-1) + 3*(ipert-1)
6026      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)
6027      phangmom(3*(imode-1)+1) = phangmom(3*(imode-1)+1)&
6028              + two * (eigvecatom(3) * eigvecatom(6) - eigvecatom(4) * eigvecatom(5)) ! Re(u_y)*Im(u_z) - Im(u_y)*Re(u_z)
6029      phangmom(3*(imode-1)+2) = phangmom(3*(imode-1)+2)&
6030              + two * (eigvecatom(5) * eigvecatom(2) - eigvecatom(6) * eigvecatom(1)) ! Re(u_z)*Im(u_x) - Im(u_z)*Re(u_x)
6031      phangmom(3*(imode-1)+3) = phangmom(3*(imode-1)+3)&
6032              + two * (eigvecatom(1) * eigvecatom(4) - eigvecatom(2) * eigvecatom(3)) ! Re(u_x)*Im(u_y) - Im(u_x)*Re(u_y)
6033    end do
6034  end do
6035 
6036 end subroutine phangmom_from_eigvec

m_dynmat/phdispl_from_eigvec [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 phdispl_from_eigvec

FUNCTION

  Phonon displacements in cart coords from eigenvectors

INPUTS

  natom: number of atoms in unit cell
  ntypat=number of atom types
  typat(natom)=integer label of each type of atom (1,2,...)
  amu(ntypat)=mass of the atoms (atomic mass unit) matrix (diagonal in the atoms)
  eigvec(2*3*natom*3*natom)= eigenvectors of the dynamical matrix in cartesian coordinates.

OUTPUT

  displ(2*3*natom*3*natom)=displacements of atoms in cartesian coordinates.

SOURCE

5953 pure subroutine phdispl_from_eigvec(natom, ntypat, typat, amu, eigvec, displ)
5954 
5955 !Arguments -------------------------------
5956 !scalars
5957  integer,intent(in) :: natom, ntypat
5958 !arrays
5959  integer,intent(in) :: typat(natom)
5960  real(dp),intent(in) :: amu(ntypat)
5961  real(dp),intent(in) :: eigvec(2*3*natom*3*natom)
5962  real(dp),intent(out) :: displ(2*3*natom*3*natom)
5963 
5964 !Local variables -------------------------
5965 !scalars
5966  integer :: i1,idir1,imode,ipert1, index
5967 
5968 ! *********************************************************************
5969 
5970  do imode=1,3*natom
5971 
5972    do idir1=1,3
5973      do ipert1=1,natom
5974        i1=idir1+(ipert1-1)*3
5975        index=i1+3*natom*(imode-1)
5976        displ(2*index-1)=eigvec(2*index-1) / sqrt(amu(typat(ipert1))*amu_emass)
5977        displ(2*index  )=eigvec(2*index  ) / sqrt(amu(typat(ipert1))*amu_emass)
5978      end do
5979    end do
5980 
5981  end do
5982 
5983 end subroutine phdispl_from_eigvec

m_dynmat/pheigvec_normalize [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 pheigvec_normalize

FUNCTION

  Normalize input eigenvectors in cartesian coordinates

INPUTS

  natom: number of atoms in unit cell

SIDE EFFECTS

  eigvec(2*3*natom*3*natom)=in output the normalized eigenvectors in cartesian coordinates.

SOURCE

5891 pure subroutine pheigvec_normalize(natom, eigvec)
5892 
5893 !Arguments -------------------------------
5894 !scalars
5895  integer,intent(in) :: natom
5896 !arrays
5897  real(dp),intent(inout) :: eigvec(2*3*natom*3*natom)
5898 
5899 !Local variables -------------------------
5900 !scalars
5901  integer :: i1,idir1,imode,ipert1,index
5902  real(dp) :: norm
5903 
5904 ! *********************************************************************
5905 
5906  do imode=1,3*natom
5907 
5908    norm=zero
5909    do idir1=1,3
5910      do ipert1=1,natom
5911        i1=idir1+(ipert1-1)*3
5912        index=i1+3*natom*(imode-1)
5913        norm=norm+eigvec(2*index-1)**2+eigvec(2*index)**2
5914      end do
5915    end do
5916    norm=sqrt(norm)
5917 
5918    do idir1=1,3
5919      do ipert1=1,natom
5920        i1=idir1+(ipert1-1)*3
5921        index=i1+3*natom*(imode-1)
5922        eigvec(2*index-1)=eigvec(2*index-1)/norm
5923        eigvec(2*index)=eigvec(2*index)/norm
5924      end do
5925    end do
5926 
5927  end do
5928 
5929 end subroutine pheigvec_normalize

m_dynmat/q0dy3_apply [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 q0dy3_apply

FUNCTION

 Takes care of the inclusion of the ewald q=0 term in the dynamical
 matrix - corrects the dyew matrix provided as input
 See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]],
 get the left hand side.

INPUTS

  dyewq0(3,3,natom) = part needed to correct the dynamical matrix for atom self-interaction.
  natom= number of atom in the unit cell

SIDE EFFECTS

  dyew(2,3,natom,3,natom)= dynamical matrix corrected on output

NOTES

 Should be used just after each call to dfpt_ewald, for both
 q==0 and the real wavelength.

 The q0dy3_apply should be used in conjunction with the subroutine dfpt_ewald (or ewald9):
 First, the call of dfpt_ewald with q==0 should be done,
   then the call to q0dy3_calc will produce
   the dyewq0 matrix from the (q=0) dyew matrix
 Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
   should be done, then the call to q0dy3_apply
   will produce the correct dynamical matrix dyew starting from
   the previously calculated dyewq0 and the bare(non-corrected)
   dyew matrix

SOURCE

1896 subroutine q0dy3_apply(natom,dyewq0,dyew)
1897 
1898 !Arguments -------------------------------
1899 !scalars
1900  integer,intent(in) :: natom
1901 !arrays
1902  real(dp),intent(in) :: dyewq0(3,3,natom)
1903  real(dp),intent(inout) :: dyew(2,3,natom,3,natom)
1904 
1905 !Local variables -------------------------
1906 !scalars
1907  integer :: ia,mu,nu
1908 
1909 ! *********************************************************************
1910 
1911  do mu=1,3
1912    do nu=1,3
1913      do ia=1,natom
1914        dyew(1,mu,ia,nu,ia)=dyew(1,mu,ia,nu,ia)-dyewq0(mu,nu,ia)
1915      end do
1916    end do
1917  end do
1918 
1919 end subroutine q0dy3_apply

m_dynmat/q0dy3_calc [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 q0dy3_calc

FUNCTION

 Calculate the q=0 correction term to the dynamical matrix
 See Eq.(71) in Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], the sum over \kappa"

INPUTS

  dyew(2,3,natom,3,natom)= dynamical matrix
    input, non-corrected, for q=0 if option=1 or 2
  natom= number of atom in the unit cell
  option= either 1 or 2:
     1: use dyew to calculate dyewq0 symmetrical form
     2: use dyew to calculate dyewq0 symmetrical form

OUTPUT

  dyewq0(3,3,natom) = part needed to correct
    the dynamical matrix for atom self-interaction.

NOTES

 Should be used just after each call to dfpt_ewald, for both
 q==0 and the real wavelength.

 If option=1 or 2, q0dy3_calc uses an Ewald dynamical matrix at q=0,
 called dyew, to produce a contracted form called dyewq0 :
 either:
   in an unsymmetrical form (if option=1), or
   in a symmetrical form (if option=2).

 The q0dy3_calc should be used in conjunction with the subroutine dfpt_ewald (or ewald9).
 First, the call of dfpt_ewald with q==0 should be done ,
   then the call to q0dy3_calc will produce
   the dyewq0 matrix from the (q=0) dyew matrix
 Second, the call of dfpt_ewald with the real q (either =0 or diff 0)
   should be done, then the call to q0dy3_apply
   will produce the correct dynamical matrix dyew starting from
   the previously calculated dyewq0 and the bare(non-corrected)
   dyew matrix

SOURCE

1966 subroutine q0dy3_calc(natom,dyewq0,dyew,option)
1967 
1968 !Arguments -------------------------------
1969 !scalars
1970  integer,intent(in) :: natom,option
1971 !arrays
1972  real(dp),intent(in) :: dyew(2,3,natom,3,natom)
1973  real(dp),intent(out) :: dyewq0(3,3,natom)
1974 
1975 !Local variables -------------------------
1976 !scalars
1977  integer :: ia,ib,mu,nu
1978  character(len=500) :: msg
1979 
1980 ! *********************************************************************
1981 
1982  if(option==1.or.option==2)then
1983    do mu=1,3
1984      do nu=1,3
1985        do ia=1,natom
1986          dyewq0(mu,nu,ia)=zero
1987          do ib=1,natom
1988            dyewq0(mu,nu,ia)=dyewq0(mu,nu,ia)+dyew(1,mu,ia,nu,ib)
1989          end do
1990        end do
1991      end do
1992    end do
1993  else
1994    write (msg, '(3a)')&
1995 &   'option should be 1 or 2.',ch10,&
1996 &   'action: correct calling routine'
1997    ABI_BUG(msg)
1998  end if
1999 
2000  if(option==2)then
2001    do ia=1,natom
2002      do mu=1,3
2003        do nu=mu,3
2004          dyewq0(mu,nu,ia)=(dyewq0(mu,nu,ia)+dyewq0(nu,mu,ia))/2
2005          dyewq0(nu,mu,ia)=dyewq0(mu,nu,ia)
2006        end do
2007      end do
2008    end do
2009  end if
2010 
2011 end subroutine q0dy3_calc

m_dynmat/sylwtens [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 sylwtens

FUNCTION

 Determines the set of irreductible elements of the non-linear
 optical susceptibility and Raman tensors

INPUTS

  has_strain = if .true. i2pert includes strain perturbation
  indsym(4,nsym,natom)=indirect indexing array described above: for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of ipert
  natom= number of atoms
  nsym=number of space group symmetries
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal reduced space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real reduced space)
  symrel_cart(3,3,nsym)=3x3 matrices of the group symmetries (real cartesian space)

OUTPUT

  (see side effects)

SIDE EFFECTS

  rfpert(3,mpert,3,mpert,3,mpert) = array defining the type of perturbations
       that have to be computed
    At the input :
       1   ->   element has to be computed explicitely
    At the output :
       1   ->   element has to be computed explicitely
      -1   ->   use symmetry operations to obtain the corresponding element
      -2   ->   element is zero by symmetry

PARENTS

      m_ddb,m_nonlinear,m_respfn_driver

CHILDREN

SOURCE

4987 !subroutine sylwtens(indsym,mpert,natom,nsym,rfpert,symrec,symrel,symrel_cart)
4988 subroutine sylwtens(indsym,mpert,natom,nsym,rfpert,symrec,symrel)
4989 
4990 !Arguments -------------------------------
4991 !scalars
4992  integer,intent(in) :: mpert,natom,nsym
4993 !arrays
4994  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4995  integer,intent(inout) :: rfpert(3,mpert,3,mpert,3,mpert)
4996 ! real(dp),intent(in) :: symrel_cart(3,3,nsym)
4997 
4998 !Local variables -------------------------
4999 !scalars
5000  integer :: flag,found,i1dir,i1dir_,i1pert,i1pert_,i2dir,i2dir_,i2pert,i2pert_
5001 ! integer :: i2dir_a,i2dir_b
5002  integer :: i3dir,i3dir_,i3pert,i3pert_,idisy1,idisy2,idisy3,ipesy1,ipesy2
5003  integer :: ipesy3,isym
5004 ! integer :: istr,idisy2_a,idisy2_b
5005  logical :: is_strain
5006 ! real(dp) :: flag_dp
5007 !arrays
5008 ! integer,save :: idx(18)=(/1,1,2,2,3,3,3,2,3,1,2,1,2,3,1,3,1,2/)
5009  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
5010  integer,allocatable :: pertsy(:,:,:,:,:,:)
5011 
5012 !***********************************************************************
5013 
5014  ABI_MALLOC(pertsy,(3,mpert,3,mpert,3,mpert))
5015  pertsy(:,:,:,:,:,:) = 0
5016 
5017 !Loop over perturbations
5018 
5019  do i1pert_ = 1, mpert
5020    do i2pert_ = 1, mpert
5021      is_strain=.false.    
5022      do i3pert_ = 1, mpert
5023 
5024        do i1dir_ = 1, 3
5025          do i2dir_ = 1, 3
5026            do i3dir_ = 1, 3
5027 
5028              i1pert = (mpert - i1pert_ + 1)
5029              if (i1pert <= natom) i1pert = natom + 1 - i1pert
5030              i2pert = (mpert - i2pert_ + 1)
5031              if (i2pert <= natom) i2pert = natom + 1 - i2pert
5032              i3pert = (mpert - i3pert_ + 1)
5033              if (i3pert <= natom) i3pert = natom + 1 - i3pert
5034 
5035              if (i1pert <= natom) then
5036                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
5037              else if (i2pert <= natom) then
5038                i1dir = i2dir_ ; i2dir = i1dir_ ; i3dir = i3dir_
5039              else if (i3pert <= natom) then
5040                i1dir = i3dir_ ; i2dir = i2dir_ ; i3dir = i1dir_
5041              else
5042                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
5043              end if
5044 
5045              if (rfpert(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) /= 0) then
5046 
5047 !              Loop over all symmetries
5048 
5049                flag = 0
5050                do isym = 1, nsym
5051 
5052                  found = 1
5053 
5054 !                Select the symmetric element of i1pert,i2pert,i3pert
5055 
5056                  if (i1pert <= natom) then
5057                    ipesy1 = indsym(4,isym,i1pert)
5058                    sym1(:,:) = symrec(:,:,isym)
5059                  else if (i1pert == natom + 2) then
5060                    ipesy1 = i1pert
5061                    sym1(:,:) = symrel(:,:,isym)
5062                  else
5063                    found = 0
5064                  end if
5065 
5066                  if (i2pert <= natom) then
5067                    ipesy2 = indsym(4,isym,i2pert)
5068                    sym2(:,:) = symrec(:,:,isym)
5069                  else if (i2pert == natom + 2) then
5070                    ipesy2 = i2pert
5071                    sym2(:,:) = symrel(:,:,isym)
5072                  else if (i2pert == natom + 3.or. i2pert == natom + 4) then
5073 !                  !TODO: Symmetries on strain perturbation do not work yet.
5074                    found = 0
5075                    is_strain=.true.
5076 !
5077 !                   ipesy2 = i2pert
5078 !                   sym2(:,:) = NINT(symrel_cart(:,:,isym))
5079 !                   if (i2pert==natom+3) istr=i2dir
5080 !                   if (i2pert==natom+4) istr=3+i2dir
5081 !                   i2dir_a=idx(2*istr-1); i2dir_b=idx(2*istr)
5082                  else
5083                    found = 0
5084                  end if
5085 
5086                  if (i3pert == natom + 8) then
5087                    ipesy3 = i3pert
5088                    sym3(:,:) = symrel(:,:,isym)
5089                  else
5090                    found = 0
5091                  end if
5092 
5093 
5094 !                See if the symmetric element is available and check if some
5095 !                of the elements may be zero. In the latter case, they do not need
5096 !                to be computed.
5097 
5098                  if (.not.is_strain) then
5099                    if ((flag /= -1).and.&
5100 &                   (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
5101                      flag = sym1(i1dir,i1dir)*sym2(i2dir,i2dir)*sym3(i3dir,i3dir)
5102                    end if
5103 
5104                    do idisy1 = 1, 3
5105                      do idisy2 = 1, 3
5106                        do idisy3 = 1, 3
5107 
5108                          if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir,idisy2) /= 0).and.&
5109 &                         (sym3(i3dir,idisy3) /= 0)) then
5110                            if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
5111                              found = 0
5112 !                            exit      ! exit loop over symmetries
5113                            end if
5114                          end if
5115 
5116 
5117                          if ((flag == -1).and.&
5118 &                         ((idisy1/=i1dir).or.(idisy2/=i2dir).or.(idisy3/=i3dir))) then
5119                            if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir,idisy2)/=0).and.&
5120 &                           (sym3(i3dir,idisy3)/=0)) then
5121                              flag = 0
5122                            end if
5123                          end if
5124 
5125                        end do
5126                      end do
5127                    end do
5128 !                 else 
5129 !                   if ((flag_dp /= -1).and.&
5130 !&                   (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
5131 !                     flag = sym1(i1dir,i1dir)*sym2(i2dir_a,i2dir_a)* &
5132 !                   & sym2(i2dir_b,i2dir_b)*sym3(i3dir,i3dir)
5133 !                   end if
5134 !
5135 !                   do idisy1 = 1, 3
5136 !                     do idisy2 = 1, 3
5137 !                       if (ipesy2==natom+3) istr=idisy2
5138 !                       if (ipesy2==natom+4) istr=3+idisy2
5139 !                       idisy2_a=idx(2*istr-1); idisy2_b=idx(2*istr)
5140 !                       do idisy3 = 1, 3
5141 !
5142 !                         if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir_a,idisy2_a) /= 0).and.&
5143 !&                          (sym2(i2dir_b,idisy2_b) /= 0).and.(sym3(i3dir,idisy3) /= 0)) then
5144 !                           if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
5145 !                             found = 0
5146 !!                            exit      ! exit loop over symmetries
5147 !                           end if
5148 !                         end if
5149 !
5150 !
5151 !                         if ((flag == -1).and.&
5152 !&                         ((idisy1/=i1dir).or.(idisy2_a/=i2dir_a).or.(idisy2_b/=i2dir_b).or.(idisy3/=i3dir))) then
5153 !                           if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir_a,idisy2_a)/=0).and.&
5154 !&                           (sym2(i2dir_b,idisy2_b)/=0).and.(sym3(i3dir,idisy3)/=0)) then
5155 !                             flag = 0
5156 !                           end if
5157 !                         end if
5158 !
5159 !                       end do
5160 !                     end do
5161 !                   end do
5162                  end if
5163 
5164                  if (found == 1) then
5165                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -1
5166                  end if
5167 
5168 !                In case a symmetry operation only changes the sign of an
5169 !                element, this element has to be equal to zero
5170 
5171                  if (flag == -1) then
5172                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -2
5173                    exit
5174                  end if
5175 
5176                end do    ! close loop on symmetries
5177 
5178 !              If the elemetn i1pert,i2pert,i3pert is not symmetric
5179 !              to a basis element, it is a basis element
5180 
5181                if (pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) > -1) then
5182                  pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
5183                end if
5184 
5185              end if ! rfpert /= 0
5186 
5187            end do        ! close loop over perturbations
5188          end do
5189        end do
5190      end do
5191    end do
5192  end do
5193 
5194 !Now, take into account the permutation of (i1pert,i1dir)
5195 !and (i2pert,i2dir)
5196 
5197  do i1pert = 1, mpert
5198    do i2pert = 1, mpert
5199      do i3pert = 1, mpert
5200 
5201        do i1dir = 1, 3
5202          do i2dir = 1, 3
5203            do i3dir = 1, 3
5204 
5205              if ((i1pert /= i2pert).or.(i1dir /= i2dir)) then
5206 
5207                if ((pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) == 1).and.&
5208                 (pertsy(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) == 1)) then
5209                  pertsy(i2dir,i2pert,i1dir,i1pert,i3dir,i3pert) = -1
5210                end if
5211 
5212              end if
5213 
5214            end do
5215          end do
5216        end do
5217 
5218      end do
5219    end do
5220  end do
5221 
5222  rfpert(:,:,:,:,:,:) = pertsy(:,:,:,:,:,:)
5223 
5224  ABI_FREE(pertsy)
5225 
5226 end subroutine sylwtens

m_dynmat/symdyma [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 symdyma

FUNCTION

 Symmetrize the dynamical matrices

INPUTS

 indsym(4,nsym*natom)=indirect indexing array : for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
 natom=number of atoms in unit cell
 nsym=number of space group symmetries
 qptn(3)=normalized phonon wavevector
 rprimd(3,3)=dimensional primitive translations (bohr)
 symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)

SIDE EFFECTS

 Input/Output
 dmati(2*3*natom*3*natom)=dynamical matrices in cartesian coordinates relative to the q
  points of the B.Z. sampling

NOTES

 the procedure of the symmetrization of the dynamical matrix follows the
 equations in: Hendrikse et al., Computer Phys. Comm. 86, 297 (1995) [[cite:Hendrikse1995]]

TODO

 A full description of the equations should be included

SOURCE

2050 subroutine symdyma(dmati,indsym,natom,nsym,qptn,rprimd,symrel,symafm)
2051 
2052 !Arguments -------------------------------
2053 !scalars
2054  integer,intent(in) :: natom,nsym
2055 !arrays
2056  integer,intent(in) :: indsym(4,nsym,natom),symrel(3,3,nsym)
2057  integer,intent(in) :: symafm(nsym)
2058  real(dp),intent(in) :: qptn(3),rprimd(3,3)
2059  real(dp),intent(inout) :: dmati(2*3*natom*3*natom)
2060 
2061 !Local variables -------------------------
2062 !scalars
2063  integer :: i1,i2,iat,idir,ii,index,isgn,isym,itirev,jat,jdir,jj,kk,ll
2064  integer :: niat,njat,timrev
2065  real(dp) :: arg1,arg2,dmint,im,re,sumi,sumr
2066 !arrays
2067  integer :: indij(natom,natom),symq(4,2,nsym),symrec(3,3,nsym)
2068  real(dp) :: TqR(3,3),TqS_(3,3),dynmat(2,3,natom,3,natom)
2069  real(dp) :: dynmatint(2*nsym,2,3,natom,3,natom),gprimd(3,3)
2070  real(dp) :: symcart(3,3,nsym)
2071 
2072 ! *********************************************************************
2073 
2074  ! 0) initializations
2075  call matr3inv(rprimd,gprimd)
2076  do isym=1,nsym
2077    call mati3inv(symrel(:,:,isym),symrec(:,:,isym))
2078  end do
2079 
2080  TqR=zero
2081  TqS_=zero
2082  dynmat=zero
2083 
2084 !Note: dynmat is used as work space here
2085  i1=0
2086  do iat=1,natom
2087    do idir=1,3
2088      i1=i1+1
2089      i2=0
2090      do jat=1,natom
2091        do jdir=1,3
2092          i2=i2+1
2093          index=i1+3*natom*(i2-1)
2094          dynmat(1,idir,iat,jdir,jat)=dmati(2*index-1)
2095          dynmat(2,idir,iat,jdir,jat)=dmati(2*index  )
2096        end do
2097      end do
2098    end do
2099  end do
2100 
2101 !Transform symrel to cartesian coordinates (RC coding)
2102 !do isym=1,nsym
2103 !symcart(:,:,isym)=matmul(rprimd,matmul(dble(symrel(:,:,isym)),gprimd))
2104 !end do
2105 
2106 !Coding from symdm9
2107  do isym=1,nsym
2108    do jj=1,3
2109      symcart(:,jj,isym)=zero
2110      do kk=1,3
2111        do ll=1,3
2112          symcart(:,jj,isym)=symcart(:,jj,isym)+rprimd(:,kk)*gprimd(jj,ll)*symrel(kk,ll,isym)
2113        end do
2114      end do
2115    end do
2116  end do
2117 
2118  ! Get the symq of the CURRENT Q POINT
2119  ! mjv: set prtvol=0 for production runs.
2120  call littlegroup_q(nsym,qptn,symq,symrec,symafm,timrev,prtvol=0)
2121 
2122  indij(:,:)=0
2123  dynmatint=zero
2124 
2125  do isym=1,nsym  ! loop over all the symmetries
2126    ! write(std_out,*) 'current symmetry',isym
2127    do itirev=1,2  ! loop over the time-reversal symmetry
2128      isgn=3-2*itirev
2129      ! write(std_out,*) 'timereversal',isgn
2130 
2131      if (symq(4,itirev,isym)==1) then ! isym belongs to the wave vector point group
2132        ! write(std_out,*) 'isym belongs to the wave vector point group'
2133        do iat=1,natom
2134          do jat=1,natom
2135            niat=indsym(4,isym,iat)  ! niat={R|t}iat
2136            njat=indsym(4,isym,jat)  ! njat={R|t}jat
2137            indij(niat,njat)=indij(niat,njat)+1
2138            ! write(std_out,'(a,5i5)') 'current status:',iat,jat,niat,njat,indij(niat,njat)
2139            ! phase calculation, arg1 and arg2 because of two-atom derivative
2140            arg1=two_pi*( qptn(1)*indsym(1,isym,iat)+&
2141              qptn(2)*indsym(2,isym,iat)+&
2142              qptn(3)*indsym(3,isym,iat) )
2143            arg2=two_pi*( qptn(1)*indsym(1,isym,jat)+&
2144              qptn(2)*indsym(2,isym,jat)+&
2145              qptn(3)*indsym(3,isym,jat) )
2146 
2147            re=cos(arg1)*cos(arg2)+sin(arg1)*sin(arg2)
2148            im=isgn*(cos(arg2)*sin(arg1)-cos(arg1)*sin(arg2))
2149 
2150            do idir=1,3     ! loop over displacements
2151              do jdir=1,3   ! loop over displacements
2152                ! we pick the (iat,jat) (3x3) block of the dyn.mat.
2153                sumr=zero
2154                sumi=zero
2155                do ii=1,3
2156                  do jj=1,3
2157                    sumr=sumr+symcart(idir,ii,isym)*dynmat(1,ii,niat,jj,njat)*symcart(jdir,jj,isym)
2158                    sumi=sumi+symcart(idir,ii,isym)*dynmat(2,ii,niat,jj,njat)*symcart(jdir,jj,isym)
2159                  end do
2160                end do
2161                sumi=isgn*sumi
2162 
2163                dynmatint(nsym*(itirev-1)+isym,1,idir,iat,jdir,jat)=re*sumr-im*sumi
2164                dynmatint(nsym*(itirev-1)+isym,2,idir,iat,jdir,jat)=re*sumi+im*sumr
2165              end do
2166            end do
2167          end do
2168        end do ! end treatment of the (iat,jat) (3x3) block of dynmat
2169      end if ! symmetry check
2170    end do ! time-reversal
2171  end do ! symmetries
2172 
2173  !4) make the average, get the final symmetric dynamical matrix
2174  do iat=1,natom
2175    do jat=1,natom
2176      do idir=1,3
2177        do jdir=1,3
2178          dmint=zero
2179          do isym=1,2*nsym
2180            dmint=dmint+dynmatint(isym,1,idir,iat,jdir,jat)
2181          end do
2182          dynmat(1,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
2183          dmint=zero
2184          do isym=1,2*nsym
2185            dmint=dmint+dynmatint(isym,2,idir,iat,jdir,jat)
2186          end do
2187          dynmat(2,idir,iat,jdir,jat)=dmint/dble(indij(iat,jat))
2188        end do
2189      end do
2190    end do
2191  end do
2192 
2193  i1=0
2194  do iat=1,natom
2195    do idir=1,3
2196      i1=i1+1
2197      i2=0
2198      do jat=1,natom
2199        do jdir=1,3
2200          i2=i2+1
2201          index=i1+3*natom*(i2-1)
2202          dmati(2*index-1)=dynmat(1,idir,iat,jdir,jat)
2203          dmati(2*index  )=dynmat(2,idir,iat,jdir,jat)
2204        end do
2205      end do
2206    end do
2207  end do
2208 
2209 end subroutine symdyma

m_dynmat/sytens [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 sytens

FUNCTION

 Determines the set of irreductible elements of the non-linear
 optical susceptibility and Raman tensors

INPUTS

  indsym(4,nsym,natom)=indirect indexing array described above: for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of ipert
  natom= number of atoms
  nsym=number of space group symmetries
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)

OUTPUT

  (see side effects)

SIDE EFFECTS

  rfpert(3,mpert,3,mpert,3,mpert) = array defining the type of perturbations
       that have to be computed
    At the input :
       1   ->   element has to be computed explicitely
    At the output :
       1   ->   element has to be computed explicitely
      -1   ->   use symmetry operations to obtain the corresponding element
      -2   ->   element is zero by symmetry

SOURCE

4752 subroutine sytens(indsym,mpert,natom,nsym,rfpert,symrec,symrel)
4753 
4754 !Arguments -------------------------------
4755 !scalars
4756  integer,intent(in) :: mpert,natom,nsym
4757 !arrays
4758  integer,intent(in) :: indsym(4,nsym,natom),symrec(3,3,nsym),symrel(3,3,nsym)
4759  integer,intent(inout) :: rfpert(3,mpert,3,mpert,3,mpert)
4760 
4761 !Local variables -------------------------
4762 !scalars
4763  integer :: flag,found,i1dir,i1dir_,i1pert,i1pert_,i2dir,i2dir_,i2pert,i2pert_
4764  integer :: i3dir,i3dir_,i3pert,i3pert_,idisy1,idisy2,idisy3,ipesy1,ipesy2
4765  integer :: ipesy3,isym
4766 !arrays
4767  integer :: sym1(3,3),sym2(3,3),sym3(3,3)
4768  integer,allocatable :: pertsy(:,:,:,:,:,:)
4769 
4770 !***********************************************************************
4771 
4772  ABI_MALLOC(pertsy,(3,mpert,3,mpert,3,mpert))
4773  pertsy(:,:,:,:,:,:) = 0
4774 
4775 !Loop over perturbations
4776 
4777  do i1pert_ = 1, mpert
4778    do i2pert_ = 1, mpert
4779      do i3pert_ = 1, mpert
4780 
4781        do i1dir_ = 1, 3
4782          do i2dir_ = 1, 3
4783            do i3dir_ = 1, 3
4784 
4785              i1pert = (mpert - i1pert_ + 1)
4786              if (i1pert <= natom) i1pert = natom + 1 - i1pert
4787              i2pert = (mpert - i2pert_ + 1)
4788              if (i2pert <= natom) i2pert = natom + 1 - i2pert
4789              i3pert = (mpert - i3pert_ + 1)
4790              if (i3pert <= natom) i3pert = natom + 1 - i3pert
4791 
4792              if (i1pert <= natom) then
4793                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
4794              else if (i2pert <= natom) then
4795                i1dir = i2dir_ ; i2dir = i1dir_ ; i3dir = i3dir_
4796              else if (i3pert <= natom) then
4797                i1dir = i3dir_ ; i2dir = i2dir_ ; i3dir = i1dir_
4798              else
4799                i1dir = i1dir_ ; i2dir = i2dir_ ; i3dir = i3dir_
4800              end if
4801 
4802              if (rfpert(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) /= 0) then
4803 
4804 !              Loop over all symmetries
4805 
4806                flag = 0
4807                do isym = 1, nsym
4808 
4809                  found = 1
4810 
4811 !                Select the symmetric element of i1pert,i2pert,i3pert
4812 
4813                  if (i1pert <= natom) then
4814                    ipesy1 = indsym(4,isym,i1pert)
4815                    sym1(:,:) = symrec(:,:,isym)
4816                  else if (i1pert == natom + 2) then
4817                    ipesy1 = i1pert
4818                    sym1(:,:) = symrel(:,:,isym)
4819                  else
4820                    found = 0
4821                  end if
4822 
4823                  if (i2pert <= natom) then
4824                    ipesy2 = indsym(4,isym,i2pert)
4825                    sym2(:,:) = symrec(:,:,isym)
4826                  else if (i2pert == natom + 2) then
4827                    ipesy2 = i2pert
4828                    sym2(:,:) = symrel(:,:,isym)
4829                  else
4830                    found = 0
4831                  end if
4832 
4833                  if (i3pert <= natom) then
4834                    ipesy3 = indsym(4,isym,i3pert)
4835                    sym3(:,:) = symrec(:,:,isym)
4836                  else if (i3pert == natom + 2) then
4837                    ipesy3 = i3pert
4838                    sym3(:,:) = symrel(:,:,isym)
4839                  else
4840                    found = 0
4841                  end if
4842 
4843 !                See if the symmetric element is available and check if some
4844 !                of the elements may be zeor. In the latter case, they do not need
4845 !                to be computed.
4846 
4847 
4848                  if ((flag /= -1).and.&
4849 &                 (ipesy1==i1pert).and.(ipesy2==i2pert).and.(ipesy3==i3pert)) then
4850                    flag = sym1(i1dir,i1dir)*sym2(i2dir,i2dir)*sym3(i3dir,i3dir)
4851                  end if
4852 
4853 
4854                  do idisy1 = 1, 3
4855                    do idisy2 = 1, 3
4856                      do idisy3 = 1, 3
4857 
4858                        if ((sym1(i1dir,idisy1) /= 0).and.(sym2(i2dir,idisy2) /= 0).and.&
4859 &                       (sym3(i3dir,idisy3) /= 0)) then
4860                          if (pertsy(idisy1,ipesy1,idisy2,ipesy2,idisy3,ipesy3) == 0) then
4861                            found = 0
4862 !                          exit      ! exit loop over symmetries
4863                          end if
4864                        end if
4865 
4866 
4867                        if ((flag == -1).and.&
4868 &                       ((idisy1/=i1dir).or.(idisy2/=i2dir).or.(idisy3/=i3dir))) then
4869                          if ((sym1(i1dir,idisy1)/=0).and.(sym2(i2dir,idisy2)/=0).and.&
4870 &                         (sym3(i3dir,idisy3)/=0)) then
4871                            flag = 0
4872                          end if
4873                        end if
4874 
4875                      end do
4876                    end do
4877                  end do
4878 
4879                  if (found == 1) then
4880                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -1
4881                  end if
4882 
4883 !                In case a symmetry operation only changes the sign of an
4884 !                element, this element has to be equal to zero
4885 
4886                  if (flag == -1) then
4887                    pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = -2
4888                    exit
4889                  end if
4890 
4891                end do    ! close loop on symmetries
4892 
4893 !              If the elemetn i1pert,i2pert,i3pert is not symmetric
4894 !              to a basis element, it is a basis element
4895 
4896                if (pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) > -1) then
4897                  pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) = 1
4898                end if
4899 
4900              end if ! rfpert /= 0
4901 
4902            end do        ! close loop over perturbations
4903          end do
4904        end do
4905      end do
4906    end do
4907  end do
4908 
4909 !Now, take into account the permutation of (i1pert,i1dir)
4910 !and (i3pert,i3dir)
4911 
4912  do i1pert = 1, mpert
4913    do i2pert = 1, mpert
4914      do i3pert = 1, mpert
4915 
4916        do i1dir = 1, 3
4917          do i2dir = 1, 3
4918            do i3dir = 1, 3
4919 
4920              if ((i1pert /= i3pert).or.(i1dir /= i3dir)) then
4921 
4922                if ((pertsy(i1dir,i1pert,i2dir,i2pert,i3dir,i3pert) == 1).and.&
4923 &               (pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) == 1)) then
4924                  pertsy(i3dir,i3pert,i2dir,i2pert,i1dir,i1pert) = -1
4925                end if
4926 
4927              end if
4928 
4929            end do
4930          end do
4931        end do
4932 
4933      end do
4934    end do
4935  end do
4936 
4937  rfpert(:,:,:,:,:,:) = pertsy(:,:,:,:,:,:)
4938 
4939  ABI_FREE(pertsy)
4940 
4941 end subroutine sytens

m_dynmat/wght9 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 wght9

FUNCTION

 Generates a weight to each R point of the Big Box and for each pair of atoms
 For each R points included in the space generates by moving
 the unit cell around each atom; the weight will be one.
 Border conditions are provided.
 The R points outside the chosen space will have a 0 weight.

INPUTS

 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)
 gprim(3,3)= Normalized coordinates in reciprocal space
 natom= Number of atoms in the unit cell
 ngqpt(6)= Numbers used to sample the Brillouin zone
 nqpt= Number of q points used in the homogeneous grid
  sampling the Brillouin zone
 nqshft=number of shift vectors in the repeated cell
 nrpt=Number of R points in the Big Box
 qshft(3,nqshft)=vectors that will be used to determine
  the shifts from (0. 0. 0.)
 rcan(3,natom)=Atomic position in canonical coordinates
 rpt(3,nprt)=Canonical coordinates of the R points in the unit cell
  These coordinates are normalized (=> * acell(3))
 rprimd(3,3)=dimensional primitive translations for real space (bohr)
 toldist= Tolerance on the distance between two R points.

OUTPUT

 wghatm(natom,natom,nrpt)= Weight associated to the couple of atoms and the R vector
  The vector r(atom2)-r(atom1)+rpt should be inside the moving box
 ngqpt(6)= can be modified

SOURCE

3881 subroutine wght9(brav,gprim,natom,ngqpt,nqpt,nqshft,nrpt,qshft,rcan,rpt,rprimd,toldist,r_inscribed_sphere,wghatm,ierr)
3882 
3883 !Arguments -------------------------------
3884 !scalars
3885  integer,intent(in) :: brav,natom,nqpt,nqshft,nrpt
3886  integer,intent(out) :: ierr
3887  real(dp),intent(out) :: r_inscribed_sphere
3888  real(dp),intent(in) :: toldist
3889 !arrays
3890  integer,intent(inout) :: ngqpt(9)
3891  real(dp),intent(in) :: gprim(3,3),qshft(3,4),rcan(3,natom),rpt(3,nrpt),rprimd(3,3)
3892  real(dp),intent(out) :: wghatm(natom,natom,nrpt)
3893 
3894 !Local variables -------------------------
3895 !scalars
3896  integer :: ia,ib,ii,jj,kk,iqshft,irpt,jqshft,nbordh,tok,nptws,nreq,idir
3897  real(dp) :: factor,sumwght,normsq,proj
3898  character(len=500) :: msg
3899 !arrays
3900  integer :: nbord(9)
3901  real(dp) :: rdiff(9),red(3,3),ptws(4, 729),pp(3),rdiff_tmp(3)
3902 
3903 ! *********************************************************************
3904 
3905  ierr = 0
3906 
3907  ! First analyze the vectors qshft
3908  if (nqshft /= 1) then
3909 
3910    if (brav == 4) then
3911      write(msg,'(3a,i0,3a)' )&
3912      'For the time being, only nqshft=1',ch10,&
3913      'is allowed with brav=4, while it is nqshft=',nqshft,'.',ch10,&
3914      'Action: in the input file, correct either brav or nqshft.'
3915      ABI_ERROR(msg)
3916    end if
3917 
3918    if (nqshft == 2) then
3919      ! Make sure that the q vectors form a BCC lattice
3920      do ii=1,3
3921        if(abs(abs(qshft(ii,1)-qshft(ii,2))-.5_dp)>1.d-10)then
3922          write(msg, '(a,a,a,a,a,a,a)' )&
3923          'The test of the q1shft vectors shows that they',ch10,&
3924          'do not generate a body-centered lattice, which',ch10,&
3925          'is mandatory for nqshft=2.',ch10,&
3926          'Action: change the q1shft vectors in your input file.'
3927          ABI_ERROR(msg)
3928        end if
3929      end do
3930    else if (nqshft == 4) then
3931      ! Make sure that the q vectors form a FCC lattice
3932      do iqshft=1,3
3933        do jqshft=iqshft+1,4
3934          tok=0
3935          do ii=1,3
3936            ! Test on the presence of a +-0.5 difference
3937            if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-.5_dp) <1.d-10) tok=tok+1
3938            ! Test on the presence of a 0 or +-1.0 difference
3939            if(abs(abs(qshft(ii,iqshft)-qshft(ii,jqshft))-1._dp) <1.d-10  .or.&
3940               abs(qshft(ii,iqshft)-qshft(ii,jqshft)) < 1.d-10) tok=tok+4
3941          end do
3942          ! Test 1 should be satisfied twice, and test 2 once
3943          if(tok/=6)then
3944            write(msg, '(7a)' )&
3945            'The test of the q1shft vectors shows that they',ch10,&
3946            'do not generate a face-centered lattice, which',ch10,&
3947            'is mandatory for nqshft=4.',ch10,&
3948            'Action: change the q1shft vectors in your input file.'
3949            ABI_ERROR(msg)
3950          end if
3951        end do
3952      end do
3953    else
3954      write(msg, '(a,i4,3a)' )&
3955      'nqshft must be 1, 2 or 4. It is nqshft=',nqshft,'.',ch10,&
3956      'Action: change nqshft in your input file.'
3957      ABI_ERROR(msg)
3958    end if
3959  end if
3960 
3961  factor=0.5_dp
3962  if(brav==2 .or. brav==3) factor=0.25_dp
3963  if(nqshft/=1)factor=factor*2
3964 
3965  if (brav==1) then
3966    ! Does not support multiple shifts
3967    if (nqshft/=1) then
3968      ABI_ERROR('This version of the weights does not support nqshft/=1.')
3969    end if
3970 
3971    ! Find the points of the lattice given by ngqpt*acell. These are used to define
3972    ! a Wigner-Seitz cell around the origin. The origin is excluded from the list.
3973    ! TODO : in principle this should be only -1 to +1 for ii jj kk!
3974    nptws=0
3975    do ii=-2,2
3976      do jj=-2,2
3977        do kk=-2,2
3978          do idir=1,3
3979            pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
3980          end do
3981          normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
3982          if (normsq > tol6) then
3983            nptws = nptws + 1
3984            ptws(:3,nptws) = pp(:)
3985            ptws(4,nptws) = half*normsq
3986          end if
3987        end do
3988      end do
3989    end do
3990  end if ! end new_wght
3991  !write(std_out,*)'factor,ngqpt',factor,ngqpt(1:3)
3992 
3993  r_inscribed_sphere = sum((matmul(rprimd(:,:),ngqpt(1:3)))**2)
3994  do ii=-1,1
3995    do jj=-1,1
3996      do kk=-1,1
3997        if (ii==0 .and. jj==0 .and. kk==0) cycle
3998        do idir=1,3
3999          pp(idir)=ii*ngqpt(1)*rprimd(idir,1)+ jj*ngqpt(2)*rprimd(idir,2)+ kk*ngqpt(3)*rprimd(idir,3)
4000        end do
4001        normsq = pp(1)*pp(1)+pp(2)*pp(2)+pp(3)*pp(3)
4002        r_inscribed_sphere = min(r_inscribed_sphere, normsq)
4003      end do
4004    end do
4005  end do
4006  r_inscribed_sphere = sqrt(r_inscribed_sphere)
4007 
4008 
4009 !Begin the big loop on ia and ib
4010  do ia=1,natom
4011    do ib=1,natom
4012 
4013      ! Simple Lattice
4014      if (abs(brav)==1) then
4015        ! In this case, it is better to work in reduced coordinates
4016        ! As rcan is in canonical coordinates, => multiplication by gprim
4017        do ii=1,3
4018          red(1,ii)=  rcan(1,ia)*gprim(1,ii) +rcan(2,ia)*gprim(2,ii) +rcan(3,ia)*gprim(3,ii)
4019          red(2,ii)=  rcan(1,ib)*gprim(1,ii) +rcan(2,ib)*gprim(2,ii) +rcan(3,ib)*gprim(3,ii)
4020        end do
4021      end if
4022 
4023      do irpt=1,nrpt
4024 
4025        ! Initialization of the weights to 1.0
4026        wghatm(ia,ib,irpt)=1.0_dp
4027 
4028        ! Compute the difference vector
4029 
4030        ! Simple Cubic Lattice
4031        if (abs(brav)==1) then
4032          ! Change of rpt to reduced coordinates
4033          do ii=1,3
4034            red(3,ii)=  rpt(1,irpt)*gprim(1,ii) +rpt(2,irpt)*gprim(2,ii) +rpt(3,irpt)*gprim(3,ii)
4035            rdiff(ii)=red(2,ii)-red(1,ii)+red(3,ii)
4036          end do
4037          if (brav==1) then
4038            ! rdiff in cartesian coordinates
4039            do ii=1,3
4040              rdiff_tmp(ii)=rdiff(1)*rprimd(ii,1)+rdiff(2)*rprimd(ii,2)+rdiff(3)*rprimd(ii,3)
4041            end do
4042            rdiff(1:3)=rdiff_tmp(1:3)
4043          end if
4044 
4045        else
4046          ! Other lattices
4047          do ii=1,3
4048            rdiff(ii)=rcan(ii,ib)-rcan(ii,ia)+rpt(ii,irpt)
4049          end do
4050        end if
4051 
4052        ! Assignement of weights
4053 
4054        if(nqshft==1 .and. brav/=4)then
4055 
4056          if (brav/=1) then
4057            do ii=1,3
4058              ! If the rpt vector is greater than the allowed space => weight = 0.0
4059              if (abs(rdiff(ii))-tol10>factor*ngqpt(ii)) then
4060                wghatm(ia,ib,irpt)=zero
4061              else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4062                ! If the point is in a boundary position => weight/2
4063                wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4064              end if
4065            end do
4066          else
4067            ! new weights
4068            wghatm(ia,ib,irpt)=zero
4069            nreq = 1
4070            do ii=1,nptws
4071              proj = rdiff(1)*ptws(1,ii)+rdiff(2)*ptws(2,ii)+rdiff(3)*ptws(3,ii)
4072              ! if rdiff closer to ptws than the origin the weight is zero
4073              ! if rdiff close to the origin with respect to all the other ptws the weight is 1
4074              ! if rdiff is equidistant from the origin and N other ptws the weight is 1/(N+1)
4075              if (proj - ptws(4,ii) > toldist) then
4076                nreq = 0
4077                EXIT
4078              else if(abs(proj-ptws(4,ii)) <= toldist) then
4079                nreq=nreq+1
4080              end if
4081            end do
4082            if (nreq>0) then
4083              wghatm(ia,ib,irpt)=one/DBLE(nreq)
4084            end if
4085          end if
4086 
4087        else if(brav==4)then
4088          ! Hexagonal
4089          ! Examination of the X and Y boundaries in order to form an hexagon
4090          ! First generate the relevant boundaries
4091          rdiff(4)=0.5_dp*( rdiff(1)+sqrt(3.0_dp)*rdiff(2) )
4092          ngqpt(4)=ngqpt(1)
4093          rdiff(5)=0.5_dp*( rdiff(1)-sqrt(3.0_dp)*rdiff(2) )
4094          ngqpt(5)=ngqpt(1)
4095 
4096          ! Test the four inequalities
4097          do ii=1,5
4098            if(ii/=2)then
4099 
4100              nbord(ii)=0
4101              ! If the rpt vector is greater than the allowed space => weight = 0.0
4102              if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
4103                wghatm(ia,ib,irpt)=zero
4104              else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4105                ! If the point is in a boundary position increment nbord(ii)
4106                nbord(ii)=1
4107              end if
4108 
4109            end if
4110          end do
4111 
4112          ! Computation of weights
4113          nbordh=nbord(1)+nbord(4)+nbord(5)
4114          if (nbordh==1) then
4115            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4116          else if (nbordh==2) then
4117            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
4118          else if (nbordh/=0) then
4119            ABI_BUG('There is a problem of borders and weights (hex).')
4120          end if
4121          if (nbord(3)==1)then
4122            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4123          end if
4124 
4125        else if(nqshft==2 .and. brav/=4)then
4126 
4127          ! BCC packing of k-points
4128          ! First, generate the relevant boundaries
4129          rdiff(4)= rdiff(1)+rdiff(2)
4130          rdiff(5)= rdiff(1)-rdiff(2)
4131          rdiff(6)= rdiff(1)+rdiff(3)
4132          rdiff(7)= rdiff(1)-rdiff(3)
4133          rdiff(8)= rdiff(3)+rdiff(2)
4134          rdiff(9)= rdiff(3)-rdiff(2)
4135          if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
4136            write(msg, '(a,a,a,3i6,a,a,a,a)' )&
4137            'In the BCC case, the three ngqpt numbers ',ch10,&
4138            '    ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
4139            'should be equal.',ch10,&
4140            'Action: use identical ngqpt(1:3) in your input file.'
4141            ABI_ERROR(msg)
4142          end if
4143          do ii=4,9
4144            ngqpt(ii)=ngqpt(1)
4145          end do
4146 
4147          ! Test the relevant inequalities
4148          nbord(1)=0
4149          do ii=4,9
4150            ! If the rpt vector is greater than the allowed space => weight = 0.0
4151            if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
4152              wghatm(ia,ib,irpt)=zero
4153            else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4154              ! If the point is in a boundary position increment nbord(1)
4155              nbord(1)=nbord(1)+1
4156            end if
4157          end do
4158 
4159          ! Computation of weights
4160          if (nbord(1)==1) then
4161            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4162          else if (nbord(1)==2) then
4163            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
4164          else if (nbord(1)==3) then
4165            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
4166          else if (nbord(1)==4) then
4167            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/6
4168          else if (nbord(1)/=0) then
4169            ABI_ERROR(' There is a problem of borders and weights (BCC).')
4170          end if
4171 
4172        else if(nqshft==4 .and. brav/=4)then
4173 
4174          ! FCC packing of k-points
4175          ! First, generate the relevant boundaries
4176          rdiff(4)= (rdiff(1)+rdiff(2)+rdiff(3))*2._dp/3._dp
4177          rdiff(5)= (rdiff(1)-rdiff(2)+rdiff(3))*2._dp/3._dp
4178          rdiff(6)= (rdiff(1)+rdiff(2)-rdiff(3))*2._dp/3._dp
4179          rdiff(7)= (rdiff(1)-rdiff(2)-rdiff(3))*2._dp/3._dp
4180          if(ngqpt(2)/=ngqpt(1) .or. ngqpt(3)/=ngqpt(1))then
4181            write(msg, '(a,a,a,3i6,a,a,a,a)' )&
4182            'In the FCC case, the three ngqpt numbers ',ch10,&
4183            '    ',ngqpt(1),ngqpt(2),ngqpt(3),ch10,&
4184            'should be equal.',ch10,&
4185            'Action: use identical ngqpt(1:3) in your input file.'
4186            ABI_ERROR(msg)
4187          end if
4188          do ii=4,7
4189            ngqpt(ii)=ngqpt(1)
4190          end do
4191 
4192          ! Test the relevant inequalities
4193          nbord(1)=0
4194          do ii=1,7
4195            ! If the rpt vector is greater than the allowed space => weight = 0.0
4196            if (abs(rdiff(ii))-1.0d-10>factor*ngqpt(ii)) then
4197              wghatm(ia,ib,irpt)=zero
4198              ! If the point is in a boundary position increment nbord(1)
4199            else if (abs(abs(rdiff(ii))-factor*ngqpt(ii)) <=1.0d-10) then
4200              nbord(1)=nbord(1)+1
4201            end if
4202          end do
4203 
4204          ! Computation of weights
4205          if (nbord(1)==1) then
4206            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/2
4207          else if (nbord(1)==2) then
4208            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/3
4209          else if (nbord(1)==3) then
4210            wghatm(ia,ib,irpt)=wghatm(ia,ib,irpt)/4
4211          else if (nbord(1)/=0 .and. wghatm(ia,ib,irpt)>1.d-10) then
4212            ! Interestingly nbord(1)==4 happens for some points outside of the volume
4213            ABI_BUG(' There is a problem of borders and weights (FCC).')
4214          end if
4215 
4216        else
4217          write(msg, '(3a,i0,a)' )&
4218          'One should not arrive here ... ',ch10,&
4219          'The value nqshft ',nqshft,' is not available'
4220          ABI_BUG(msg)
4221        end if
4222      end do ! Assignement of weights is done
4223    end do ! End of the double loop on ia and ib
4224  end do
4225 
4226  ! Check the results
4227  do ia=1,natom
4228    do ib=1,natom
4229      sumwght=zero
4230      do irpt=1,nrpt
4231        ! Check if the sum of the weights is equal to the number of q points
4232        sumwght=sumwght+wghatm(ia,ib,irpt)
4233        !write(std_out,'(a,3(i0,1x))' )' atom1, atom2, irpt ; rpt ; wghatm ',ia,ib,irpt
4234        !write(std_out,'(3es16.6,es18.6)' )rpt(1,irpt),rpt(2,irpt),rpt(3,irpt),wghatm(ia,ib,irpt)
4235      end do
4236      if (abs(sumwght-nqpt)>tol10) ierr = 1
4237    end do
4238  end do
4239 
4240 end subroutine wght9

m_dynmat/wings3 [ Functions ]

[ Top ] [ m_dynmat ] [ Functions ]

NAME

 wings3

FUNCTION

  Suppress the wings of the cartesian 2DTE for which
  the diagonal element is not known

INPUTS

  carflg(3,mpert,3,mpert)= ( 1 if the element of the cartesian
  2DTE matrix has been calculated correctly ; 0 otherwise )
  d2cart(2,3,mpert,3,mpert)=
   dynamical matrix, effective charges, dielectric tensor,....
   all in cartesian coordinates
  mpert =maximum number of ipert

OUTPUT

  d2cart(2,3,mpert,3,mpert) without the wings

SOURCE

2513 subroutine wings3(carflg,d2cart,mpert)
2514 
2515 !Arguments -------------------------------
2516 !scalars
2517  integer,intent(in) :: mpert
2518 !arrays
2519  integer,intent(inout) :: carflg(3,mpert,3,mpert)
2520  real(dp),intent(inout) :: d2cart(2,3,mpert,3,mpert)
2521 
2522 !Local variables -------------------------
2523 !scalars
2524  integer :: idir,idir1,ipert,ipert1
2525 
2526 ! *********************************************************************
2527 
2528  do ipert=1,mpert
2529    do idir=1,3
2530      if(carflg(idir,ipert,idir,ipert)==0)then
2531        do ipert1=1,mpert
2532          do idir1=1,3
2533            carflg(idir,ipert,idir1,ipert1)=0
2534            carflg(idir1,ipert1,idir,ipert)=0
2535            d2cart(1,idir,ipert,idir1,ipert1)=zero
2536            d2cart(2,idir,ipert,idir1,ipert1)=zero
2537            d2cart(1,idir1,ipert1,idir,ipert)=zero
2538            d2cart(2,idir1,ipert1,idir,ipert)=zero
2539          end do
2540        end do
2541      end if
2542    end do
2543  end do
2544 
2545 end subroutine wings3