quantum-espresso/PHonon/PH/matdyn.f90

3024 lines
105 KiB
Fortran

! Copyright (C) 2001-2012 Quantum ESPRESSO group
! This file is distributed under the terms of the
! GNU General Public License. See the file `License'
! in the root directory of the present distribution,
! or http://www.gnu.org/copyleft/gpl.txt .
!
!
Module ifconstants
!
!! All variables read from file that need dynamical allocation.
!
USE kinds, ONLY: DP
!
REAL(DP), ALLOCATABLE :: frc(:,:,:,:,:,:,:)
!! interatomic force constants in real space
REAL(DP), ALLOCATABLE :: frc_lr(:,:,:,:,:,:,:)
!! long-range part of interatomic force constants in real space
REAL(DP), ALLOCATABLE :: tau_blk(:,:)
!! atomic positions for the original cell
REAL(DP), ALLOCATABLE :: zeu(:,:,:)
!! effective charges for the original cell
REAL(DP), ALLOCATABLE :: m_loc(:,:)
!! the magnetic moments of each atom
INTEGER, ALLOCATABLE :: ityp_blk(:)
!! atomic types for each atom of the original cell
!
CHARACTER(LEN=3), ALLOCATABLE :: atm(:)
!
end Module ifconstants
!
!
!---------------------------------------------------------------------
PROGRAM matdyn
!-----------------------------------------------------------------------
!! This program calculates the phonon frequencies for a list of generic
!! q vectors starting from the interatomic force constants generated
!! from the dynamical matrices as written by DFPT phonon code through
!! the companion program \(\texttt{q2r}\).
!
!! \(\texttt{matdyn}\) can generate a supercell of the original cell for
!! mass approximation calculation. If supercell data are not specified
!! in input, the unit cell, lattice vectors, atom types and positions
!! are read from the force constant file.
!
! Input cards: namelist &input
! flfrc file produced by q2r containing force constants (needed)
! It is the same as in the input of q2r.x (+ the .xml extension
! if the dynamical matrices produced by ph.x were in xml
! format). No default value: must be specified.
! asr (character) indicates the type of Acoustic Sum Rule imposed
! - 'no': no Acoustic Sum Rules imposed (default)
! - 'simple': previous implementation of the asr used
! (3 translational asr imposed by correction of
! the diagonal elements of the force constants matrix)
! - 'crystal': 3 translational asr imposed by optimized
! correction of the force constants (projection).
! - 'all': 3 translational asr + 3 rotational asr + 15 Huang
! conditions for vanishing stress tensor, imposed by
! optimized correction of the force constants (projection).
! Remember to set write_lr to .true. to write long-range
! force constants into file when running q2r and set read_lr
! to .true. when running matdyn for the case of polar system.
! - 'one-dim': 3 translational asr + 1 rotational asr
! imposed by optimized correction of the force constants
! (the rotation axis is the direction of periodicity;
! it will work only if this axis considered is one of
! the cartesian axis).
! - 'zero-dim': 3 translational asr + 3 rotational asr
! imposed by optimized correction of the force constants
! Note that in certain cases, not all the rotational asr
! can be applied (e.g. if there are only 2 atoms in a
! molecule or if all the atoms are aligned, etc.).
! In these cases the supplementary asr are cancelled
! during the orthonormalization procedure (see below).
! huang if .true. (default) Huang conditions for vanishing
! stress tensor are included in asr='all'.
! dos if .true. calculate phonon Density of States (DOS)
! using tetrahedra and a uniform q-point grid (see below)
! NB: may not work properly in noncubic materials
! if .false. calculate phonon bands from the list of q-points
! supplied in input (default)
! nk1,nk2,nk3 uniform q-point grid for DOS calculation (includes q=0)
! (must be specified if dos=.true., ignored otherwise)
! deltaE energy step, in cm^(-1), for DOS calculation: from min
! to max phonon energy (default: 1 cm^(-1) if ndos, see
! below, is not specified)
! ndos number of energy steps for DOS calculations
! (default: calculated from deltaE if not specified)
! degauss DOS broadening (in cm^-1). Default 0 - meaning use tetrahedra
! fldos output file for dos (default: 'matdyn.dos')
! the dos is in states/cm(-1) plotted vs omega in cm(-1)
! and is normalised to 3*nat, i.e. the number of phonons
! flfrq output file for frequencies (default: 'matdyn.freq')
! flvec output file for normalized phonon displacements
! (default: 'matdyn.modes'). The normalized phonon displacements
! are the eigenvectors divided by the square root of the mass,
! then normalized. As such they are not orthogonal.
! fleig output file for phonon eigenvectors (default: 'matdyn.eig')
! The phonon eigenvectors are the eigenvectors of the dynamical
! matrix. They are orthogonal.
! fldyn output file for dynamical matrix (default: ' ' i.e. not written)
! at supercell lattice vectors - must form a superlattice of the
! original lattice (default: use original cell)
! l1,l2,l3 supercell lattice vectors are original cell vectors times
! l1, l2, l3 respectively (default: 1, ignored if at specified)
! ntyp number of atom types in the supercell (default: ntyp of the
! original cell)
! amass masses of atoms in the supercell (a.m.u.), one per atom type
! (default: use masses read from file flfrc)
! readtau read atomic positions of the supercell from input
! (used to specify different masses) (default: .false.)
! fltau write atomic positions of the supercell to file "fltau"
! (default: fltau=' ', do not write)
! la2F if .true. interpolates also the el-ph coefficients.
! q_in_band_form if .true. the q points are given in band form:
! Only the first and last point of one or more lines
! are given. See below. (default: .false.).
! q_in_cryst_coord if .true. input q points are in crystalline
! coordinates (default: .false.)
! eigen_similarity: use similarity of the displacements to order
! frequencies (default: .false.)
! NB: You cannot use this option with the symmetry
! analysis of the modes.
! fd (logical) if .t. the ifc come from the finite displacement calculation
! na_ifc (logical) add non analitic contributions to the interatomic force
! constants if finite displacement method is used (as in Wang et al.
! Phys. Rev. B 85, 224303 (2012)) [to be used in conjunction with fd.x]
! nosym if .true., no symmetry and no time reversal are imposed
! loto_2d set to .true. to activate two-dimensional treatment of LO-TO splitting.
! loto_disable (logical) if .true. do not apply LO-TO splitting for q=0
! (default: .false.)
! read_lr set to .true. to read long-range force constants from file,
! when enforcing asr='all' for polar solids in matdyn.
! write_frc set to .true. to write force constants into file.
! The filename would be flfrc+".matdyn".
!
! if (readtau) atom types and positions in the supercell follow:
! (tau(i,na),i=1,3), ityp(na)
! IF (q_in_band_form.and..not.dos) THEN
! nq ! number of q points
! (q(i,n),i=1,3), nptq nptq is the number of points between this point
! and the next. These points are automatically
! generated. the q points are given in Cartesian
! coordinates, 2pi/a units (a=lattice parameters)
! ELSE, if (.not.dos) :
! nq number of q-points
! (q(i,n), i=1,3) nq q-points in cartesian coordinates, 2pi/a units
! If q = 0, the direction qhat (q=>0) for the non-analytic part
! is extracted from the sequence of q-points as follows:
! qhat = q(n) - q(n-1) or qhat = q(n) - q(n+1)
! depending on which one is available and nonzero.
! For low-symmetry crystals, specify twice q = 0 in the list
! if you want to have q = 0 results for two different directions
!
USE kinds, ONLY : DP
USE mp, ONLY : mp_bcast
USE mp_world, ONLY : world_comm
USE mp_global, ONLY : mp_startup, mp_global_end
USE environment, ONLY : environment_start, environment_end
USE io_global, ONLY : ionode, ionode_id, stdout
USE io_dyn_mat, ONLY : read_dyn_mat_param, read_dyn_mat_header, &
read_ifc_param, read_ifc
USE cell_base, ONLY : at, bg, celldm
USE constants, ONLY : RY_TO_THZ, RY_TO_CMM1, amu_ry
USE symm_base, ONLY : set_sym
USE rap_point_group, ONLY : code_group
USE bz_form, ONLY : transform_label_coord
USE parser, ONLY : read_line
USE rigid, ONLY : dyndiag, nonanal, nonanal_ifc
USE el_phon, ONLY : el_ph_nsigma
USE ifconstants, ONLY : frc, frc_lr, atm, zeu, tau_blk, ityp_blk, m_loc
!
IMPLICIT NONE
!
INTEGER :: gid
!
! variables *_blk refer to the original cell, other variables
! to the (super)cell (which may coincide with the original cell)
!
INTEGER:: nax, nax_blk
INTEGER, PARAMETER:: ntypx=10, nrwsx=200
REAL(DP), PARAMETER :: eps=1.0d-6
INTEGER :: nr1, nr2, nr3, nsc, nk1, nk2, nk3, ibrav
CHARACTER(LEN=256) :: flfrc, flfrq, flvec, fltau, fldos, filename, fldyn, &
fleig, fildyn, fildyn_prefix
CHARACTER(LEN=10) :: asr
LOGICAL :: dos, has_zstar, q_in_cryst_coord, eigen_similarity, loto_disable
COMPLEX(DP), ALLOCATABLE :: dyn(:,:,:,:), dyn_blk(:,:,:,:), frc_ifc(:,:,:,:)
COMPLEX(DP), ALLOCATABLE :: z(:,:)
REAL(DP), ALLOCATABLE:: tau(:,:), q(:,:), w2(:,:), freq(:,:), wq(:), &
dynq(:,:,:), DOSofE(:), zq(:, :, :)
INTEGER, ALLOCATABLE:: ityp(:), itau_blk(:)
REAL(DP) :: omega,alat, &! cell parameters and volume
at_blk(3,3), bg_blk(3,3), &! original cell
omega_blk, &! original cell volume
epsil(3,3), &! dielectric tensor
amass(ntypx), &! atomic masses
amass_blk(ntypx), &! original atomic masses
atws(3,3), &! lattice vector for WS initialization
rws(0:3,nrwsx) ! nearest neighbor list, rws(0,*) = norm^2
REAL(DP) :: alph ! Ewald coefficient for non-analytical term
!
INTEGER :: nat, nat_blk, ntyp, ntyp_blk, &
l1, l2, l3, &! supercell dimensions
nrws, &! number of nearest neighbor
code_group_old
INTEGER :: nspin_mag, nqs, ios, ipol
!
LOGICAL :: readtau, la2F, xmlifc, lo_to_split, na_ifc, fd, nosym, loto_2d, &
huang, read_lr, write_frc
!
REAL(DP) :: qhat(3), qh, DeltaE, Emin=0._dp, Emax, E, qq, degauss
REAL(DP) :: delta, pathL
REAL(DP), ALLOCATABLE :: xqaux(:,:)
INTEGER, ALLOCATABLE :: nqb(:)
INTEGER :: n, i, j, it, nq, nqx, na, nb, ndos, iout, nqtot, iout_dyn, iout_eig
LOGICAL, EXTERNAL :: has_xml
INTEGER, ALLOCATABLE :: num_rap_mode(:,:)
LOGICAL, ALLOCATABLE :: high_sym(:)
LOGICAL :: q_in_band_form
! .... variables for band plotting based on similarity of eigenvalues
COMPLEX(DP), ALLOCATABLE :: tmp_z(:,:)
REAL(DP), ALLOCATABLE :: abs_similarity(:,:), tmp_w2(:)
COMPLEX(DP), ALLOCATABLE :: f_of_q(:,:,:,:)
INTEGER :: location(1), isig
CHARACTER(LEN=6) :: int_to_char
LOGICAL, ALLOCATABLE :: mask(:)
INTEGER :: npk_label, nch
CHARACTER(LEN=3), ALLOCATABLE :: letter(:)
INTEGER, ALLOCATABLE :: label_list(:)
LOGICAL :: tend, terr
CHARACTER(LEN=256) :: input_line, buffer
CHARACTER(LEN=10) :: point_label_type
CHARACTER(len=80) :: k_points = 'tpiba'
!
REAL(DP), external :: dos_broad, dos_gam
!
NAMELIST /input/ flfrc, amass, asr, flfrq, flvec, fleig, at, dos, &
& fldos, nk1, nk2, nk3, l1, l2, l3, ntyp, readtau, fltau, &
& la2F, ndos, DeltaE, degauss, q_in_band_form, q_in_cryst_coord, &
& eigen_similarity, fldyn, na_ifc, fd, point_label_type, &
& nosym, loto_2d, fildyn, fildyn_prefix, el_ph_nsigma, &
& loto_disable, huang, read_lr, write_frc
!
CALL mp_startup()
CALL environment_start('MATDYN')
!
IF (ionode) CALL input_from_file ( )
!
! ... all calculations are done by the first cpu
!
! set namelist default
!
dos = .FALSE.
deltaE = 1.0d0
degauss = 0
ndos = 1
nk1 = 0
nk2 = 0
nk3 = 0
asr ='no'
readtau=.FALSE.
flfrc=' '
fldos='matdyn.dos'
flfrq='matdyn.freq'
flvec='matdyn.modes'
fleig=' '
fldyn=' '
fltau=' '
fildyn = ' '
fildyn_prefix = ' '
amass(:) =0.d0
amass_blk(:) =0.d0
at(:,:) = 0.d0
ntyp = 0
l1=1
l2=1
l3=1
la2F=.false.
q_in_band_form=.FALSE.
eigen_similarity=.FALSE.
q_in_cryst_coord = .FALSE.
na_ifc=.FALSE.
fd=.FALSE.
point_label_type='SC'
nosym = .false.
loto_2d=.false.
el_ph_nsigma=10
loto_disable = .false.
huang = .true.
read_lr = .false.
write_frc = .false.
!
!
IF (ionode) READ (5,input,IOSTAT=ios)
CALL mp_bcast(ios, ionode_id, world_comm)
CALL errore('matdyn', 'reading input namelist', ABS(ios))
CALL mp_bcast(dos,ionode_id, world_comm)
CALL mp_bcast(deltae,ionode_id, world_comm)
CALL mp_bcast(ndos,ionode_id, world_comm)
CALL mp_bcast(degauss,ionode_id, world_comm)
CALL mp_bcast(nk1,ionode_id, world_comm)
CALL mp_bcast(nk2,ionode_id, world_comm)
CALL mp_bcast(nk3,ionode_id, world_comm)
CALL mp_bcast(asr,ionode_id, world_comm)
CALL mp_bcast(readtau,ionode_id, world_comm)
CALL mp_bcast(flfrc,ionode_id, world_comm)
CALL mp_bcast(fldos,ionode_id, world_comm)
CALL mp_bcast(flfrq,ionode_id, world_comm)
CALL mp_bcast(flvec,ionode_id, world_comm)
CALL mp_bcast(fleig,ionode_id, world_comm)
CALL mp_bcast(fldyn,ionode_id, world_comm)
CALL mp_bcast(fltau,ionode_id, world_comm)
CALL mp_bcast(fildyn,ionode_id, world_comm)
CALL mp_bcast(fildyn_prefix,ionode_id, world_comm)
CALL mp_bcast(amass,ionode_id, world_comm)
CALL mp_bcast(amass_blk,ionode_id, world_comm)
CALL mp_bcast(at,ionode_id, world_comm)
CALL mp_bcast(ntyp,ionode_id, world_comm)
CALL mp_bcast(l1,ionode_id, world_comm)
CALL mp_bcast(l2,ionode_id, world_comm)
CALL mp_bcast(l3,ionode_id, world_comm)
CALL mp_bcast(na_ifc,ionode_id, world_comm)
CALL mp_bcast(fd,ionode_id, world_comm)
CALL mp_bcast(la2F,ionode_id, world_comm)
CALL mp_bcast(q_in_band_form,ionode_id, world_comm)
CALL mp_bcast(eigen_similarity,ionode_id, world_comm)
CALL mp_bcast(q_in_cryst_coord,ionode_id, world_comm)
CALL mp_bcast(point_label_type,ionode_id, world_comm)
CALL mp_bcast(loto_2d,ionode_id, world_comm)
CALL mp_bcast(loto_disable,ionode_id, world_comm)
CALL mp_bcast(el_ph_nsigma,ionode_id, world_comm)
CALL mp_bcast(huang,ionode_id, world_comm)
CALL mp_bcast(read_lr,ionode_id, world_comm)
CALL mp_bcast(write_frc,ionode_id, world_comm)
!
IF (loto_2d .AND. loto_disable) CALL errore('matdyn', &
'loto_2d and loto_disable cannot be both true', 1)
!
! read force constants
!
IF ( trim( fildyn ) /= ' ' ) THEN
IF (ionode) THEN
WRITE(stdout, *)
WRITE(stdout, '(4x,a)') ' fildyn has been provided, running q2r...'
END IF
CALL do_q2r(fildyn, flfrc, fildyn_prefix, asr, la2F, loto_2d, read_lr)
END IF
!
ntyp_blk = ntypx ! avoids fake out-of-bound error
xmlifc=has_xml(flfrc)
IF (xmlifc) THEN
CALL read_dyn_mat_param(flfrc,ntyp_blk,nat_blk)
ALLOCATE (m_loc(3,nat_blk))
ALLOCATE (tau_blk(3,nat_blk))
ALLOCATE (ityp_blk(nat_blk))
ALLOCATE (atm(ntyp_blk))
ALLOCATE (zeu(3,3,nat_blk))
CALL read_dyn_mat_header(ntyp_blk, nat_blk, ibrav, nspin_mag, &
celldm, at_blk, bg_blk, omega_blk, atm, amass_blk, &
tau_blk, ityp_blk, m_loc, nqs, has_zstar, epsil, zeu )
alat=celldm(1)
call volume(alat,at_blk(1,1),at_blk(1,2),at_blk(1,3),omega_blk)
CALL read_ifc_param(nr1,nr2,nr3)
ALLOCATE(frc(nr1,nr2,nr3,3,3,nat_blk,nat_blk))
ALLOCATE(frc_lr(nr1,nr2,nr3,3,3,nat_blk,nat_blk))
frc_lr = 0.d0
if (read_lr) THEN
CALL read_ifc(alph,nr1,nr2,nr3,nat_blk,frc,frc_lr)
else
CALL read_ifc(alph,nr1,nr2,nr3,nat_blk,frc)
end if
ELSE
CALL readfc ( flfrc, nr1, nr2, nr3, epsil, nat_blk, &
ibrav, alat, at_blk, ntyp_blk, &
amass_blk, omega_blk, has_zstar, alph, read_lr)
ENDIF
!
CALL recips ( at_blk(1,1),at_blk(1,2),at_blk(1,3), &
bg_blk(1,1),bg_blk(1,2),bg_blk(1,3) )
!
! set up (super)cell
!
if (ntyp < 0) then
call errore ('matdyn','wrong ntyp ', abs(ntyp))
else if (ntyp == 0) then
ntyp=ntyp_blk
end if
!
! masses (for mass approximation)
!
DO it=1,ntyp
IF (amass(it) < 0.d0) THEN
CALL errore ('matdyn','wrong mass in the namelist',it)
ELSE IF (amass(it) == 0.d0) THEN
IF (it.LE.ntyp_blk) THEN
WRITE (stdout,'(a,i3,a,a)') ' mass for atomic type ',it, &
& ' not given; uses mass from file ',flfrc
amass(it) = amass_blk(it)
ELSE
CALL errore ('matdyn','missing mass in the namelist',it)
END IF
END IF
END DO
!
! lattice vectors
!
IF (SUM(ABS(at(:,:))) == 0.d0) THEN
IF (l1.LE.0 .OR. l2.LE.0 .OR. l3.LE.0) CALL &
& errore ('matdyn',' wrong l1,l2 or l3',1)
at(:,1) = at_blk(:,1)*DBLE(l1)
at(:,2) = at_blk(:,2)*DBLE(l2)
at(:,3) = at_blk(:,3)*DBLE(l3)
END IF
!
CALL check_at(at,bg_blk,alat,omega)
!
! the supercell contains "nsc" times the original unit cell
!
nsc = NINT(omega/omega_blk)
IF (ABS(omega/omega_blk-nsc) > eps) &
CALL errore ('matdyn', 'volume ratio not integer', 1)
!
! read/generate atomic positions of the (super)cell
!
nat = nat_blk * nsc
nax = nat
nax_blk = nat_blk
!
ALLOCATE ( tau (3, nat), ityp(nat), itau_blk(nat) )
!
IF (readtau) THEN
CALL read_tau &
(nat, nat_blk, ntyp, bg_blk, tau, tau_blk, ityp, itau_blk)
ELSE
CALL set_tau &
(nat, nat_blk, at, at_blk, tau, tau_blk, ityp, ityp_blk, itau_blk)
ENDIF
!
IF (fltau.NE.' ') CALL write_tau (fltau, nat, tau, ityp)
!
! reciprocal lattice vectors
!
CALL recips (at(1,1),at(1,2),at(1,3),bg(1,1),bg(1,2),bg(1,3))
!
! build the WS cell corresponding to the force constant grid
!
atws(:,1) = at_blk(:,1)*DBLE(nr1)
atws(:,2) = at_blk(:,2)*DBLE(nr2)
atws(:,3) = at_blk(:,3)*DBLE(nr3)
! initialize WS r-vectors
CALL wsinit(rws,nrwsx,nrws,atws)
!
! end of (super)cell setup
!
IF (dos) THEN
IF (nk1 < 1 .OR. nk2 < 1 .OR. nk3 < 1) &
CALL errore ('matdyn','specify correct q-point grid!',1)
nqx = nk1*nk2*nk3
ALLOCATE ( q(3,nqx), wq(nqx) )
CALL gen_qpoints (ibrav, at, bg, nat, tau, ityp, nk1, nk2, nk3, &
nqx, nq, q, nosym, wq)
ELSE
!
! read q-point list
!
IF (ionode) READ (5,*) nq
CALL mp_bcast(nq, ionode_id, world_comm)
ALLOCATE ( q(3,nq) )
IF (.NOT.q_in_band_form) THEN
ALLOCATE(wq(nq))
DO n = 1,nq
IF (ionode) READ (5,*) (q(i,n),i=1,3)
END DO
CALL mp_bcast(q, ionode_id, world_comm)
!
IF (q_in_cryst_coord) CALL cryst_to_cart(nq,q,bg,+1)
ELSE
ALLOCATE( nqb(nq) )
ALLOCATE( xqaux(3,nq) )
ALLOCATE( letter(nq) )
ALLOCATE( label_list(nq) )
npk_label=0
DO n = 1, nq
CALL read_line( input_line, end_of_file = tend, error = terr )
IF (tend) CALL errore('matdyn','Missing lines',1)
IF (terr) CALL errore('matdyn','Error reading q points',1)
DO j=1,256 ! loop over all characters of input_line
IF ( (ICHAR(input_line(j:j)) < 58 .AND. & ! a digit
ICHAR(input_line(j:j)) > 47) &
.OR.ICHAR(input_line(j:j)) == 43 .OR. & ! the + sign
ICHAR(input_line(j:j)) == 45 .OR. & ! the - sign
ICHAR(input_line(j:j)) == 46 ) THEN ! a dot .
!
! This is a digit, therefore this line contains the coordinates of the
! k point. We read it and exit from the loop on characters
!
READ(input_line,*) xqaux(1,n), xqaux(2,n), xqaux(3,n), &
nqb(n)
EXIT
ELSEIF ((ICHAR(input_line(j:j)) < 123 .AND. &
ICHAR(input_line(j:j)) > 64)) THEN
!
! This is a letter, not a space character. We read the next three
! characters and save them in the letter array, save also which k point
! it is
!
npk_label=npk_label+1
READ(input_line(j:),'(a3)') letter(npk_label)
label_list(npk_label)=n
!
! now we remove the letters from input_line and read the number of points
! of the line. The next two line should account for the case in which
! there is only one space between the letter and the number of points.
!
nch=3
IF ( ICHAR(input_line(j+1:j+1))==32 .OR. &
ICHAR(input_line(j+2:j+2))==32 ) nch=2
buffer=input_line(j+nch:)
READ(buffer,*,err=20,iostat=ios) nqb(n)
20 IF (ios /=0) CALL errore('matdyn',&
'problem reading number of points',1)
EXIT
ENDIF
ENDDO
ENDDO
IF (q_in_cryst_coord) k_points='crystal'
IF ( npk_label > 0 ) &
CALL transform_label_coord(ibrav, celldm, xqaux, letter, &
label_list, npk_label, nq, k_points, point_label_type )
DEALLOCATE(letter)
DEALLOCATE(label_list)
CALL mp_bcast(xqaux, ionode_id, world_comm)
CALL mp_bcast(nqb, ionode_id, world_comm)
IF (q_in_cryst_coord) CALL cryst_to_cart(nq,xqaux,bg,+1)
nqtot=SUM(nqb(1:nq-1))+1
DO i=1,nq-1
IF (nqb(i)==0) nqtot=nqtot+1
ENDDO
DEALLOCATE(q)
ALLOCATE(q(3,nqtot))
ALLOCATE(wq(nqtot))
CALL generate_k_along_lines(nq, xqaux, nqb, q, wq, nqtot)
nq=nqtot
DEALLOCATE(xqaux)
DEALLOCATE(nqb)
END IF
!
END IF
!
IF (asr /= 'no') THEN
CALL set_asr (asr, nr1, nr2, nr3, frc, frc_lr, zeu, &
nat_blk, ibrav, tau_blk, at_blk, huang)
END IF
!
IF (write_frc) THEN
CALL writefc(flfrc, xmlifc, has_zstar, nr1, nr2, nr3, ibrav, alat, at_blk, bg_blk, &
ntyp_blk, nat_blk, amass_blk, omega_blk, epsil, alph, nspin_mag, nqs)
END IF
!
IF (flvec.EQ.' ') THEN
iout=0
ELSE
iout=4
IF (ionode) OPEN (unit=iout,file=flvec,status='unknown',form='formatted')
END IF
IF (fldyn.EQ.' ') THEN
iout_dyn=0
ELSE
iout_dyn=44
OPEN (unit=iout_dyn,file=fldyn,status='unknown',form='formatted')
END IF
IF (fleig.EQ.' ') THEN
iout_eig=0
ELSE
iout_eig=313
IF (ionode) OPEN (unit=iout_eig,file=fleig,status='unknown',form='formatted')
END IF
ALLOCATE ( dyn(3,3,nat,nat), dyn_blk(3,3,nat_blk,nat_blk) )
ALLOCATE ( z(3*nat,3*nat), w2(3*nat,nq), f_of_q(3,3,nat,nat), &
dynq(3*nat,nq,nat), DOSofE(nat), zq(nq, 3*nat, 3*nat) )
ALLOCATE ( tmp_w2(3*nat), abs_similarity(3*nat,3*nat), mask(3*nat) )
if(la2F.and.ionode) open(unit=300,file='dyna2F',status='unknown')
IF (xmlifc) CALL set_sym(nat, tau, ityp, nspin_mag, m_loc )
ALLOCATE(num_rap_mode(3*nat,nq))
ALLOCATE(high_sym(nq))
num_rap_mode=-1
high_sym=.TRUE.
zq(:, :, :) = (0.d0, 0.d0)
DO n=1, nq
dyn(:,:,:,:) = (0.d0, 0.d0)
lo_to_split=.FALSE.
f_of_q(:,:,:,:) = (0.d0,0.d0)
IF(na_ifc) THEN
qq=sqrt(q(1,n)**2+q(2,n)**2+q(3,n)**2)
if(abs(qq) < 1d-8) qq=1.0
qhat(1)=q(1,n)/qq
qhat(2)=q(2,n)/qq
qhat(3)=q(3,n)/qq
CALL nonanal_ifc (nat,nat_blk,itau_blk,epsil,qhat,zeu,omega,dyn, &
nr1, nr2, nr3,f_of_q)
END IF
CALL setupmat (q(1,n), dyn, nat, at, bg, tau, itau_blk, nsc, alat, &
dyn_blk, nat_blk, at_blk, bg_blk, tau_blk, omega_blk, &
loto_2d, epsil, zeu, alph, &
frc, nr1,nr2,nr3, has_zstar, rws, nrws, na_ifc,f_of_q,fd)
IF (.not.loto_2d) THEN
qhat(1) = q(1,n)*at(1,1)+q(2,n)*at(2,1)+q(3,n)*at(3,1)
qhat(2) = q(1,n)*at(1,2)+q(2,n)*at(2,2)+q(3,n)*at(3,2)
qhat(3) = q(1,n)*at(1,3)+q(2,n)*at(2,3)+q(3,n)*at(3,3)
IF ( ABS( qhat(1) - NINT (qhat(1) ) ) <= eps .AND. &
ABS( qhat(2) - NINT (qhat(2) ) ) <= eps .AND. &
ABS( qhat(3) - NINT (qhat(3) ) ) <= eps ) THEN
!
! q = 0 : we need the direction q => 0 for the non-analytic part
!
IF ( n == 1 ) THEN
! if q is the first point in the list
IF ( nq > 1 ) THEN
! one more point
qhat(:) = q(:,n) - q(:,n+1)
ELSE
! no more points
qhat(:) = 0.d0
END IF
ELSE IF ( n > 1 ) THEN
! if q is not the first point in the list
IF ( q(1,n-1)==0.d0 .AND. &
q(2,n-1)==0.d0 .AND. &
q(3,n-1)==0.d0 .AND. n < nq ) THEN
! if the preceding q is also 0 :
qhat(:) = q(:,n) - q(:,n+1)
ELSE
! if the preceding q is npt 0 :
qhat(:) = q(:,n) - q(:,n-1)
END IF
END IF
qh = SQRT(qhat(1)**2+qhat(2)**2+qhat(3)**2)
! write(*,*) ' qh, has_zstar ',qh, has_zstar
IF (qh /= 0.d0) qhat(:) = qhat(:) / qh
IF (qh /= 0.d0 .AND. .NOT. has_zstar) THEN
CALL infomsg &
('matdyn','Z* not found in file '//TRIM(flfrc)// &
', TO-LO splitting at q=0 will be absent!')
ELSEIF (loto_disable) THEN
CALL infomsg('matdyn', &
'loto_disable is true. Disable LO-TO splitting at q=0.')
ELSE
lo_to_split=.TRUE.
ENDIF
!
IF (lo_to_split) CALL nonanal (nat, nat_blk, itau_blk, epsil, qhat, zeu, omega, dyn)
!
END IF
!
END IF
if(iout_dyn.ne.0) THEN
call write_dyn_on_file(q(1,n),dyn,nat, iout_dyn)
if(sum(abs(q(:,n)))==0._dp) call write_epsilon_and_zeu (zeu, epsil, nat, iout_dyn)
endif
CALL dyndiag(nat,ntyp,amass,ityp,dyn,w2(1,n),z)
!
! Convert from displacements to eigenvectors (see rigid.f90 :: dyndiag)
do i = 1, 3*nat
do na = 1, nat
do ipol = 1,3
zq(n, (na-1)*3+ipol,i) = z((na-1)*3+ipol,i) * sqrt(amu_ry * amass(ityp(na)))
end do
end do
end do
!
! Atom projection of dynamical matrix
DO i = 1, 3*nat
DO na = 1, nat
dynq(i, n, na) = DOT_PRODUCT(z(3*(na-1)+1:3*na, i), &
& z(3*(na-1)+1:3*na, i) ) &
& * amu_ry * amass(ityp(na))
END DO
END DO
IF (ionode.and.iout_eig.ne.0) &
& CALL write_eigenvectors(nat,ntyp,amass,ityp,q(1,n),w2(1,n),z,iout_eig)
!
! Cannot use the small group of \Gamma to analize the symmetry
! of the mode if there is an electric field.
!
IF (xmlifc.AND..NOT.lo_to_split) THEN
WRITE(stdout,'(10x,"xq=",3F8.4)') q(:,n)
CALL find_representations_mode_q(nat,ntyp,q(:,n), &
w2(:,n),z,tau,ityp,amass, num_rap_mode(:,n), nspin_mag)
IF (code_group==code_group_old.OR.high_sym(n-1)) high_sym(n)=.FALSE.
code_group_old=code_group
ENDIF
IF (eigen_similarity) THEN
! ... order phonon dispersions using similarity of eigenvalues
! ... Courtesy of Takeshi Nishimatsu, IMR, Tohoku University
IF (.NOT.ALLOCATED(tmp_z)) THEN
ALLOCATE(tmp_z(3*nat,3*nat))
ELSE
abs_similarity = ABS ( MATMUL ( CONJG( TRANSPOSE(z)), tmp_z ) )
mask(:) = .true.
DO na=1,3*nat
location = maxloc( abs_similarity(:,na), mask(:) )
mask(location(1)) = .false.
tmp_w2(na) = w2(location(1),n)
tmp_z(:,na) = z(:,location(1))
END DO
w2(:,n) = tmp_w2(:)
z(:,:) = tmp_z(:,:)
END IF
tmp_z(:,:) = z(:,:)
ENDIF
!
if(la2F.and.ionode) then
write(300,*) n
do na=1,3*nat
write(300,*) (z(na,nb),nb=1,3*nat)
end do ! na
endif
!
IF (ionode.and.iout.ne.0) CALL writemodes(nat,q(1,n),w2(1,n),z,iout)
!
END DO !nq
DEALLOCATE (tmp_w2, abs_similarity, mask)
IF (eigen_similarity) DEALLOCATE(tmp_z)
if(la2F.and.ionode) close(300)
!
IF(iout .NE. 0.and.ionode) CLOSE(unit=iout)
IF(iout_dyn .NE. 0) CLOSE(unit=iout_dyn)
IF(iout_eig .NE. 0) CLOSE(unit=iout_eig)
!
ALLOCATE (freq(3*nat, nq))
DO n=1,nq
! freq(i,n) = frequencies in cm^(-1), with negative sign if omega^2 is negative
DO i=1,3*nat
freq(i,n)= SQRT(ABS(w2(i,n))) * RY_TO_CMM1
IF (w2(i,n) < 0.0d0) freq(i,n) = -freq(i,n)
END DO
END DO
!
IF(flfrq.NE.' '.and.ionode) THEN
OPEN (unit=2,file=flfrq ,status='unknown',form='formatted')
WRITE(2, '(" &plot nbnd=",i4,", nks=",i4," /")') 3*nat, nq
DO n=1, nq
WRITE(2, '(10x,3f10.6)') q(1,n), q(2,n), q(3,n)
WRITE(2,'(6f10.4)') (freq(i,n), i=1,3*nat)
END DO
CLOSE(unit=2)
OPEN (unit=2,file=trim(flfrq)//'.gp' ,status='unknown',form='formatted')
pathL = 0._dp
WRITE(2, '(f10.6,3x,999f10.4)') pathL, (freq(i,1), i=1,3*nat)
DO n=2, nq
pathL=pathL+(SQRT(SUM( (q(:,n)-q(:,n-1))**2 )))
WRITE(2, '(f10.6,3x,999f10.4)') pathL, (freq(i,n), i=1,3*nat)
END DO
CLOSE(unit=2)
END IF
!
! If the force constants are in the xml format we write also
! the file with the representations of each mode
!
IF (flfrq.NE.' '.AND.xmlifc.AND.ionode) THEN
filename=TRIM(flfrq)//'.rap'
OPEN (unit=2,file=filename ,status='unknown',form='formatted')
WRITE(2, '(" &plot_rap nbnd_rap=",i4,", nks_rap=",i4," /")') 3*nat, nq
DO n=1, nq
WRITE(2,'(10x,3f10.6,l6)') q(1,n), q(2,n), q(3,n), high_sym(n)
WRITE(2,'(6i10)') (num_rap_mode(i,n), i=1,3*nat)
END DO
CLOSE(unit=2)
END IF
!
IF (dos) THEN
Emin = 0.0d0
Emax = 0.0d0
DO n=1,nq
DO i=1, 3*nat
Emin = MIN (Emin, freq(i,n))
Emax = MAX (Emax, freq(i,n))
END DO
END DO
!
if (ndos > 1) then
DeltaE = (Emax - Emin)/(ndos-1)
else
ndos = NINT ( (Emax - Emin) / DeltaE + 1.51d0 )
end if
IF (ionode) OPEN (unit=2,file=fldos,status='unknown',form='formatted')
IF (ionode) WRITE (2, *) "# Frequency[cm^-1] DOS PDOS"
!
IF (degauss .EQ. 0) THEN
! Use tetrahedra
DO na = 1, nat
dynq(1:3*nat,1:nq,na) = dynq(1:3*nat,1:nq,na) * freq(1:3*nat,1:nq)
END DO
END IF
!
DO n= 1, ndos
E = Emin + (n - 1) * DeltaE
DO na = 1, nat
DOSofE(na) = 0d0
!
IF (degauss .EQ. 0) THEN
! Use tetrahedra
DO i = 1, 3*nat
DOSofE(na) = DOSofE(na) &
& + dos_gam(3*nat, nq, i, dynq(1:3*nat,1:nq,na), freq, E)
END DO
ELSE
! Use broadening
DOSofE(na) = DOSofE(na) &
& + dos_broad(na, 3*nat, nq, freq, zq, wq, E, degauss)
END IF
!
END DO
!
IF (ionode) WRITE (2, '(2ES18.10,1000ES12.4)') E, SUM(DOSofE(1:nat)), DOSofE(1:nat)
END DO
IF (ionode) CLOSE(unit=2)
END IF !dos
DEALLOCATE (z, zq, w2, dyn, dyn_blk)
!
! for a2F
!
IF(la2F) THEN
!
IF (.NOT. dos) THEN
DO isig=1,el_ph_nsigma
OPEN (unit=200+isig,file='elph.gamma.'//&
TRIM(int_to_char(isig)), status='unknown',form='formatted')
WRITE(200+isig, '(" &plot nbnd=",i4,", nks=",i4," /")') 3*nat, nq
END DO
END IF
!
! convert frequencies to Ry
!
freq(:,:)= freq(:,:) / RY_TO_CMM1
Emin = Emin / RY_TO_CMM1
DeltaE=DeltaE/ RY_TO_CMM1
!
call a2Fdos (nat, nq, nr1, nr2, nr3, ibrav, at, bg, tau, alat, &
nsc, nat_blk, at_blk, bg_blk, itau_blk, omega_blk, &
rws, nrws, dos, Emin, DeltaE, ndos, &
asr, q, freq,fd, wq, huang)
!
IF (.NOT.dos) THEN
DO isig=1,el_ph_nsigma
CLOSE(UNIT=200+isig)
ENDDO
ENDIF
END IF
DEALLOCATE ( freq)
DEALLOCATE(num_rap_mode)
DEALLOCATE(high_sym)
DEALLOCATE(frc_lr)
!
CALL environment_end('MATDYN')
!
CALL mp_global_end()
!
IF (asr == 'all') THEN
WRITE(stdout, '(/A117/)') " You are using asr="//'"all"'//", please consider citing "// &
"C. Lin, S. Ponc\'e and N. Marzari, npj Comput Mater 8, 236 (2022)."
ENDIF
!
STOP
!
END PROGRAM matdyn
!
!-----------------------------------------------------------------------
SUBROUTINE readfc ( flfrc, nr1, nr2, nr3, epsil, nat, &
ibrav, alat, at, ntyp, amass, omega, &
has_zstar, alph, read_lr )
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE ifconstants,ONLY : tau => tau_blk, ityp => ityp_blk, frc, frc_lr, zeu, atm
USE cell_base, ONLY : celldm
USE io_global, ONLY : ionode, ionode_id, stdout
USE mp, ONLY : mp_bcast
USE mp_world, ONLY : world_comm
USE constants, ONLY : amu_ry
!
IMPLICIT NONE
! I/O variable
CHARACTER(LEN=256) :: flfrc
CHARACTER(LEN=80) :: line
INTEGER :: ibrav, nr1,nr2,nr3,nat, ntyp
REAL(DP) :: alat, at(3,3), epsil(3,3), alph
LOGICAL :: has_zstar, read_lr
! local variables
INTEGER :: i, j, na, nb, m1,m2,m3
INTEGER :: ios, ibid, jbid, nabid, nbbid, m1bid,m2bid,m3bid
REAL(DP) :: amass(ntyp), amass_from_file, omega
INTEGER :: nt
!
!
IF (ionode) OPEN (unit=1,file=flfrc,status='old',form='formatted')
!
! read cell data
!
IF (ionode)THEN
READ(1,*) ntyp,nat,ibrav,(celldm(i),i=1,6)
if (ibrav==0) then
read(1,*) ((at(i,j),i=1,3),j=1,3)
end if
ENDIF
CALL mp_bcast(ntyp, ionode_id, world_comm)
CALL mp_bcast(nat, ionode_id, world_comm)
CALL mp_bcast(ibrav, ionode_id, world_comm)
CALL mp_bcast(celldm, ionode_id, world_comm)
IF (ibrav==0) THEN
CALL mp_bcast(at, ionode_id, world_comm)
ENDIF
!
CALL latgen(ibrav,celldm,at(1,1),at(1,2),at(1,3),omega)
alat = celldm(1)
at = at / alat ! bring at in units of alat
CALL volume(alat,at(1,1),at(1,2),at(1,3),omega)
!
! read atomic types, positions and masses
!
ALLOCATE (atm(ntyp))
DO nt = 1,ntyp
IF (ionode) READ(1,*) i,atm(nt),amass_from_file
CALL mp_bcast(i,ionode_id, world_comm)
CALL mp_bcast(amass_from_file,ionode_id, world_comm)
IF (i.NE.nt) CALL errore ('readfc','wrong data read',nt)
IF (amass(nt).EQ.0.d0) THEN
amass(nt) = amass_from_file/amu_ry
ELSE
WRITE(stdout,*) 'for atomic type',nt,' mass from file not used'
END IF
END DO
CALL mp_bcast(atm,ionode_id, world_comm)
CALL mp_bcast(amass,ionode_id, world_comm)
!
ALLOCATE (tau(3,nat), ityp(nat), zeu(3,3,nat))
!
DO na=1,nat
IF (ionode) READ(1,*) i,ityp(na),(tau(j,na),j=1,3)
CALL mp_bcast(i,ionode_id, world_comm)
IF (i.NE.na) CALL errore ('readfc','wrong data read',na)
END DO
CALL mp_bcast(ityp,ionode_id, world_comm)
CALL mp_bcast(tau,ionode_id, world_comm)
!
! read macroscopic variables
!
alph = 1.0_dp
IF (ionode) THEN
READ (1,'(a)') line
READ(line,*,iostat=ios) has_zstar, alph
IF ( ios /= 0 ) READ(line,*) has_zstar
ENDIF
!
CALL mp_bcast(has_zstar,ionode_id, world_comm)
IF (has_zstar) THEN
CALL mp_bcast(alph,ionode_id, world_comm)
IF (ionode) READ(1,*) ((epsil(i,j),j=1,3),i=1,3)
CALL mp_bcast(epsil,ionode_id, world_comm)
IF (ionode) THEN
DO na=1,nat
READ(1,*)
READ(1,*) ((zeu(i,j,na),j=1,3),i=1,3)
END DO
ENDIF
CALL mp_bcast(zeu,ionode_id, world_comm)
ELSE
zeu (:,:,:) = 0.d0
epsil(:,:) = 0.d0
END IF
!
IF (ionode) READ (1,*) nr1,nr2,nr3
CALL mp_bcast(nr1,ionode_id, world_comm)
CALL mp_bcast(nr2,ionode_id, world_comm)
CALL mp_bcast(nr3,ionode_id, world_comm)
!
! read real-space interatomic force constants
!
ALLOCATE ( frc(nr1,nr2,nr3,3,3,nat,nat) )
frc(:,:,:,:,:,:,:) = 0.d0
ALLOCATE ( frc_lr(nr1,nr2,nr3,3,3,nat,nat) )
frc_lr(:,:,:,:,:,:,:) = 0.d0
DO i=1,3
DO j=1,3
DO na=1,nat
DO nb=1,nat
IF (ionode) READ (1,*) ibid, jbid, nabid, nbbid
CALL mp_bcast(ibid,ionode_id, world_comm)
CALL mp_bcast(jbid,ionode_id, world_comm)
CALL mp_bcast(nabid,ionode_id, world_comm)
CALL mp_bcast(nbbid,ionode_id, world_comm)
IF(i .NE.ibid .OR. j .NE.jbid .OR. &
na.NE.nabid .OR. nb.NE.nbbid) &
CALL errore ('readfc','error in reading',1)
IF (read_lr) THEN
IF (ionode) READ (1,*) (((m1bid, m2bid, m3bid, &
frc(m1,m2,m3,i,j,na,nb), &
frc_lr(m1,m2,m3,i,j,na,nb), &
m1=1,nr1),m2=1,nr2),m3=1,nr3)
ELSE
IF (ionode) READ (1,*) (((m1bid, m2bid, m3bid, &
frc(m1,m2,m3,i,j,na,nb), &
m1=1,nr1),m2=1,nr2),m3=1,nr3)
END IF
CALL mp_bcast(frc(:,:,:,i,j,na,nb),ionode_id, world_comm)
CALL mp_bcast(frc_lr(:,:,:,i,j,na,nb),ionode_id, world_comm)
END DO
END DO
END DO
END DO
!
IF (ionode) CLOSE(unit=1)
!
RETURN
END SUBROUTINE readfc
!
!-----------------------------------------------------------------------
SUBROUTINE writefc(flfrc, xmlifc, has_zstar, nr1, nr2, nr3, ibrav, alat, &
at, bg, ntyp, nat, amass, omega, epsil, alph, nspin_mag, nqs)
!---------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : ionode
USE io_dyn_mat, ONLY : write_dyn_mat_header, write_ifc
USE cell_base, ONLY : celldm
USE constants, ONLY : amu_ry
USE ifconstants,ONLY : tau => tau_blk, ityp => ityp_blk, &
frc, frc_lr, zeu, atm, m_loc
!
IMPLICIT NONE
! I/O variable
CHARACTER(LEN=256) :: flfrc
INTEGER :: nr1, nr2, nr3, ibrav, nat, ntyp, nspin_mag, nqs
REAL(DP) :: alat, omega, at(3,3), bg(3,3), amass(ntyp), epsil(3,3)
REAL(DP) :: alph
LOGICAL :: xmlifc, has_zstar
! local variables
INTEGER :: i, j, nt, na, nb, nn, m1, m2, m3, leng
CHARACTER(LEN=256) :: flfrc2
COMPLEX(DP) :: frc2(nr1*nr2*nr3,3,3,nat,nat)
!
leng = LEN_TRIM(flfrc)
flfrc2 = flfrc(1:leng) // ".matdyn"
IF (xmlifc) THEN
frc2 = RESHAPE(frc, (/nr1*nr2*nr3,3,3,nat,nat/))
IF (has_zstar) THEN
CALL write_dyn_mat_header(flfrc2, ntyp, nat, ibrav, nspin_mag, celldm, &
at, bg, omega, atm, amass, tau, ityp, m_loc, nqs, epsil, zeu)
ELSE
CALL write_dyn_mat_header(flfrc2, ntyp, nat, ibrav, nspin_mag, &
celldm, at, bg, omega, atm, amass, tau, ityp, m_loc, nqs)
ENDIF
CALL write_ifc(alph,nr1, nr2, nr3, nat, frc2)
ELSE IF (ionode) THEN
OPEN(unit=1, file=flfrc2, status='unknown', form='formatted')
WRITE(1,'(i3,i5,i4,6f11.7)') ntyp, nat, ibrav, celldm
IF (ibrav == 0) WRITE(1,'(2x,3f15.9)') ((at(i,j),i=1,3),j=1,3)
DO nt = 1, ntyp
WRITE(1,*) nt, " '", atm(nt), "' ", amass(nt)*amu_ry
END DO
DO na = 1, nat
WRITE(1,'(2i5,3f18.10)') na, ityp(na), (tau(j,na),j=1,3)
END DO
WRITE (1,*) has_zstar, alph
IF (has_zstar) THEN
WRITE(1,'(3f24.12)') ((epsil(i,j),j=1,3),i=1,3)
DO na = 1, nat
WRITE(1,'(i5)') na
WRITE(1,'(3f15.7)') ((zeu(i,j,na),j=1,3),i=1,3)
END DO
END IF
WRITE (1,'(4i4)') nr1, nr2, nr3
DO i = 1, 3
DO j = 1,3
DO na = 1, nat
DO nb = 1, nat
WRITE (1,'(4i4)') i, j, na, nb
nn = 0
DO m3 = 1, nr3
DO m2 = 1, nr2
DO m1 = 1, nr1
nn = nn+1
WRITE (1,'(3i4,2x,1pe18.11)') &
m1,m2,m3, DBLE(frc(m1,m2,m3,i,j,na,nb))
END DO
END DO
END DO
END DO
END DO
END DO
END DO
CLOSE(1)
END IF
END SUBROUTINE writefc
!
!-----------------------------------------------------------------------
SUBROUTINE frc_blk(dyn,q,tau,nat,nr1,nr2,nr3,frc,at,bg,rws,nrws,f_of_q,fd)
!-----------------------------------------------------------------------
! calculates the dynamical matrix at q from the (short-range part of the)
! force constants
!
USE kinds, ONLY : DP
USE constants, ONLY : tpi
USE io_global, ONLY : stdout
!
IMPLICIT NONE
INTEGER nr1, nr2, nr3, nat, n1, n2, n3, nr1_, nr2_, nr3_, &
ipol, jpol, na, nb, m1, m2, m3, nint, i,j, nrws, nax
COMPLEX(DP) dyn(3,3,nat,nat), f_of_q(3,3,nat,nat)
REAL(DP) frc(nr1,nr2,nr3,3,3,nat,nat), tau(3,nat), q(3), arg, &
at(3,3), bg(3,3), r(3), weight, r_ws(3), &
total_weight, rws(0:3,nrws), alat
REAL(DP), EXTERNAL :: wsweight
REAL(DP),SAVE,ALLOCATABLE :: wscache(:,:,:,:,:)
LOGICAL,SAVE :: first=.true.
LOGICAL :: fd
!
nr1_=2*nr1
nr2_=2*nr2
nr3_=2*nr3
FIRST_TIME : IF (first) THEN
first=.false.
ALLOCATE( wscache(-nr3_:nr3_, -nr2_:nr2_, -nr1_:nr1_, nat,nat) )
DO na=1, nat
DO nb=1, nat
total_weight=0.0d0
!
! SUM OVER R VECTORS IN THE SUPERCELL - VERY VERY VERY SAFE RANGE!
!
DO n1=-nr1_,nr1_
DO n2=-nr2_,nr2_
DO n3=-nr3_,nr3_
DO i=1, 3
r(i) = n1*at(i,1)+n2*at(i,2)+n3*at(i,3)
r_ws(i) = r(i) + tau(i,na)-tau(i,nb)
if (fd) r_ws(i) = r(i) + tau(i,nb)-tau(i,na)
END DO
wscache(n3,n2,n1,nb,na) = wsweight(r_ws,rws,nrws)
total_weight=total_weight + wscache(n3,n2,n1,nb,na)
ENDDO
ENDDO
ENDDO
IF (ABS(total_weight-nr1*nr2*nr3).GT.1.0d-8) THEN
WRITE(stdout,*) na,nb,total_weight
CALL errore ('frc_blk','wrong total_weight',1)
END IF
ENDDO
ENDDO
ENDIF FIRST_TIME
!
DO na=1, nat
DO nb=1, nat
DO n1=-nr1_,nr1_
DO n2=-nr2_,nr2_
DO n3=-nr3_,nr3_
!
! SUM OVER R VECTORS IN THE SUPERCELL - VERY VERY SAFE RANGE!
!
DO i=1, 3
r(i) = n1*at(i,1)+n2*at(i,2)+n3*at(i,3)
END DO
weight = wscache(n3,n2,n1,nb,na)
IF (weight .GT. 0.0d0) THEN
!
! FIND THE VECTOR CORRESPONDING TO R IN THE ORIGINAL CELL
!
m1 = MOD(n1+1,nr1)
IF(m1.LE.0) m1=m1+nr1
m2 = MOD(n2+1,nr2)
IF(m2.LE.0) m2=m2+nr2
m3 = MOD(n3+1,nr3)
IF(m3.LE.0) m3=m3+nr3
! write(*,'(6i4)') n1,n2,n3,m1,m2,m3
!
! FOURIER TRANSFORM
!
arg = tpi*(q(1)*r(1) + q(2)*r(2) + q(3)*r(3))
DO ipol=1, 3
DO jpol=1, 3
dyn(ipol,jpol,na,nb) = dyn(ipol,jpol,na,nb) + &
(frc(m1,m2,m3,ipol,jpol,na,nb)+f_of_q(ipol,jpol,na,nb)) &
*CMPLX(COS(arg),-SIN(arg),kind=DP)*weight
END DO
END DO
END IF
END DO
END DO
END DO
END DO
END DO
!
RETURN
END SUBROUTINE frc_blk
!
!-----------------------------------------------------------------------
SUBROUTINE setupmat (q,dyn,nat,at,bg,tau,itau_blk,nsc,alat, &
& dyn_blk,nat_blk,at_blk,bg_blk,tau_blk,omega_blk, &
& loto_2d, epsil, zeu, alph, &
& frc,nr1,nr2,nr3,has_zstar,rws,nrws,na_ifc,f_of_q,fd)
!-----------------------------------------------------------------------
! compute the dynamical matrix (the analytic part only)
!
USE kinds, ONLY : DP
USE constants, ONLY : tpi
USE cell_base, ONLY : celldm
USE rigid, ONLY : rgd_blk
!
IMPLICIT NONE
!
! I/O variables
!
INTEGER:: nr1, nr2, nr3, nat, nat_blk, nsc, nrws, itau_blk(nat)
REAL(DP) :: q(3), tau(3,nat), at(3,3), bg(3,3), alat, alph, &
epsil(3,3), zeu(3,3,nat_blk), rws(0:3,nrws), &
frc(nr1,nr2,nr3,3,3,nat_blk,nat_blk)
REAL(DP) :: tau_blk(3,nat_blk), at_blk(3,3), bg_blk(3,3), omega_blk
COMPLEX(DP) dyn_blk(3,3,nat_blk,nat_blk), f_of_q(3,3,nat,nat)
COMPLEX(DP) :: dyn(3,3,nat,nat)
LOGICAL :: has_zstar, na_ifc, fd, loto_2d
!
! local variables
!
REAL(DP) :: arg
COMPLEX(DP) :: cfac(nat)
INTEGER :: i,j,k, na,nb, na_blk, nb_blk, iq
REAL(DP) :: qp(3), qbid(3,nsc) ! automatic array
!
!
CALL q_gen(nsc,qbid,at_blk,bg_blk,at,bg)
!
DO iq=1,nsc
!
DO k=1,3
qp(k)= q(k) + qbid(k,iq)
END DO
!
dyn_blk(:,:,:,:) = (0.d0,0.d0)
CALL frc_blk (dyn_blk,qp,tau_blk,nat_blk, &
& nr1,nr2,nr3,frc,at_blk,bg_blk,rws,nrws,f_of_q,fd)
IF (has_zstar .and. .not.na_ifc) &
CALL rgd_blk(nr1, nr2, nr3, nat_blk, dyn_blk, qp, tau_blk, &
epsil, zeu, alph, bg_blk, omega_blk, celldm(1), loto_2d, +1.d0 )
!
DO na=1,nat
na_blk = itau_blk(na)
DO nb=1,nat
nb_blk = itau_blk(nb)
!
arg=tpi* ( qp(1) * ( (tau(1,na)-tau_blk(1,na_blk)) - &
(tau(1,nb)-tau_blk(1,nb_blk)) ) + &
qp(2) * ( (tau(2,na)-tau_blk(2,na_blk)) - &
(tau(2,nb)-tau_blk(2,nb_blk)) ) + &
qp(3) * ( (tau(3,na)-tau_blk(3,na_blk)) - &
(tau(3,nb)-tau_blk(3,nb_blk)) ) )
!
cfac(nb) = CMPLX(COS(arg),SIN(arg),kind=DP)/nsc
!
END DO ! nb
!
DO i=1,3
DO j=1,3
!
DO nb=1,nat
nb_blk = itau_blk(nb)
dyn(i,j,na,nb) = dyn(i,j,na,nb) + cfac(nb) * &
dyn_blk(i,j,na_blk,nb_blk)
END DO ! nb
!
END DO ! j
END DO ! i
END DO ! na
!
END DO ! iq
!
RETURN
END SUBROUTINE setupmat
!
!
!----------------------------------------------------------------------
SUBROUTINE set_asr (asr, nr1, nr2, nr3, frc, frc_lr, zeu, nat, ibrav, tau_blk, at_blk, huang)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : stdout
!
IMPLICIT NONE
CHARACTER (LEN=10), intent(in) :: asr
LOGICAL, intent(in) :: huang
INTEGER, intent(in) :: nr1, nr2, nr3, nat, ibrav
REAL(DP), intent(in) :: tau_blk(3,nat), at_blk(3,3), frc_lr(nr1,nr2,nr3,3,3,nat,nat)
REAL(DP), intent(inout) :: frc(nr1,nr2,nr3,3,3,nat,nat), zeu(3,3,nat)
!
INTEGER :: axis, n, i, j, na, nb, n1,n2,n3, m,p,k,l,q,r, i1,j1,na1, ip,ieq,neq
INTEGER :: huang_set(4,15)
REAL(DP) :: zeu_new(3,3,nat), tau(3,48), rcell(3), r_ws(3), eps
REAL(DP), ALLOCATABLE :: frc_new(:,:,:,:,:,:,:)
parameter (eps=1.0d-8)
type vector
real(DP),pointer :: vec(:,:,:,:,:,:,:)
end type vector
!
type (vector) u(6*3*nat+15)
! These are the "vectors" associated with the sum rules on force-constants
!
integer :: u_less(6*3*nat),n_less,i_less
! indices of the vectors u that are not independent to the preceding ones,
! n_less = number of such vectors, i_less = temporary parameter
!
integer, allocatable :: ind_v(:,:,:)
real(DP), allocatable :: v(:,:)
! These are the "vectors" associated with symmetry conditions, coded by
! indicating the positions (i.e. the seven indices) of the non-zero elements (there
! should be only 2 of them) and the value of that element. We do so in order
! to limit the amount of memory used.
!
real(DP), allocatable :: w(:,:,:,:,:,:,:), x(:,:,:,:,:,:,:)
! temporary vectors and parameters
real(DP) :: scal,norm2, sum
!
real(DP) :: zeu_u(6*3,3,3,nat)
! These are the "vectors" associated with the sum rules on effective charges
!
integer :: zeu_less(6*3),nzeu_less,izeu_less
! indices of the vectors zeu_u that are not independent to the preceding ones,
! nzeu_less = number of such vectors, izeu_less = temporary parameter
!
real(DP) :: zeu_w(3,3,nat), zeu_x(3,3,nat)
! temporary vectors
! Initialization. n is the number of sum rules to be considered (if asr.ne.'simple')
! and 'axis' is the rotation axis in the case of a 1D system
! (i.e. the rotation axis is (Ox) if axis='1', (Oy) if axis='2' and (Oz) if axis='3')
!
if((asr.ne.'simple').and.(asr.ne.'crystal').and.(asr.ne.'one-dim') &
.and.(asr.ne.'zero-dim').and.(asr.ne.'all')) then
call errore('set_asr','invalid Acoustic Sum Rule:' // asr, 1)
endif
!
if(asr.eq.'simple') then
!
! Simple Acoustic Sum Rule on effective charges
!
do i=1,3
do j=1,3
sum=0.0d0
do na=1,nat
sum = sum + zeu(i,j,na)
end do
do na=1,nat
zeu(i,j,na) = zeu(i,j,na) - sum/nat
end do
end do
end do
!
! Simple Acoustic Sum Rule on force constants in real space
!
do i=1,3
do j=1,3
do na=1,nat
sum=0.0d0
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
sum=sum+frc(n1,n2,n3,i,j,na,nb)
end do
end do
end do
end do
frc(1,1,1,i,j,na,na) = frc(1,1,1,i,j,na,na) - sum
! write(6,*) ' na, i, j, sum = ',na,i,j,sum
end do
end do
end do
!
return
!
end if
if(asr.eq.'crystal') n=3
if(asr.eq.'one-dim') then
! the direction of periodicity is the rotation axis
! It will work only if the crystal axis considered is one of
! the cartesian axis (typically, ibrav=1, 6 or 8, or 4 along the
! z-direction)
if (nr1*nr2*nr3.eq.1) axis=3
if ((nr1.ne.1).and.(nr2*nr3.eq.1)) axis=1
if ((nr2.ne.1).and.(nr1*nr3.eq.1)) axis=2
if ((nr3.ne.1).and.(nr1*nr2.eq.1)) axis=3
if (((nr1.ne.1).and.(nr2.ne.1)).or.((nr2.ne.1).and. &
(nr3.ne.1)).or.((nr1.ne.1).and.(nr3.ne.1))) then
call errore('set_asr','too many directions of &
& periodicity in 1D system',axis)
endif
if ((ibrav.ne.1).and.(ibrav.ne.6).and.(ibrav.ne.8).and. &
((ibrav.ne.4).or.(axis.ne.3)) ) then
write(stdout,*) 'asr: rotational axis may be wrong'
endif
write(stdout,'("asr rotation axis in 1D system= ",I4)') axis
n=4
endif
if(asr.eq.'zero-dim') n=6
if(asr.eq.'all') n=21
!
! Acoustic Sum Rule on effective charges
!
! generating the vectors of the orthogonal of the subspace to project
! the effective charges matrix on
!
zeu_u(:,:,:,:)=0.0d0
do i=1,3
do j=1,3
do na=1,nat
zeu_new(i,j,na)=zeu(i,j,na)
enddo
enddo
enddo
!
p=0
do i=1,3
do j=1,3
! These are the 3*3 vectors associated with the
! translational acoustic sum rules
p=p+1
zeu_u(p,i,j,:)=1.0d0
!
enddo
enddo
!
if (n.eq.4) then
do i=1,3
! These are the 3 vectors associated with the
! single rotational sum rule (1D system)
p=p+1
do na=1,nat
zeu_u(p,i,MOD(axis,3)+1,na)=-tau_blk(MOD(axis+1,3)+1,na)
zeu_u(p,i,MOD(axis+1,3)+1,na)=tau_blk(MOD(axis,3)+1,na)
enddo
!
enddo
endif
!
if (n.eq.6) then
do i=1,3
do j=1,3
! These are the 3*3 vectors associated with the
! three rotational sum rules (0D system - typ. molecule)
p=p+1
do na=1,nat
zeu_u(p,i,MOD(j,3)+1,na)=-tau_blk(MOD(j+1,3)+1,na)
zeu_u(p,i,MOD(j+1,3)+1,na)=tau_blk(MOD(j,3)+1,na)
enddo
!
enddo
enddo
endif
!
! Gram-Schmidt orthonormalization of the set of vectors created.
!
nzeu_less=0
do k=1,p
zeu_w(:,:,:)=zeu_u(k,:,:,:)
zeu_x(:,:,:)=zeu_u(k,:,:,:)
do q=1,k-1
r=1
do izeu_less=1,nzeu_less
if (zeu_less(izeu_less).eq.q) r=0
enddo
if (r.ne.0) then
call sp_zeu(zeu_x,zeu_u(q,:,:,:),nat,scal)
zeu_w(:,:,:) = zeu_w(:,:,:) - scal* zeu_u(q,:,:,:)
endif
enddo
call sp_zeu(zeu_w,zeu_w,nat,norm2)
if (norm2.gt.1.0d-16) then
zeu_u(k,:,:,:) = zeu_w(:,:,:) / DSQRT(norm2)
else
nzeu_less=nzeu_less+1
zeu_less(nzeu_less)=k
endif
enddo
!
! Projection of the effective charge "vector" on the orthogonal of the
! subspace of the vectors verifying the sum rules
!
zeu_w(:,:,:)=0.0d0
do k=1,p
r=1
do izeu_less=1,nzeu_less
if (zeu_less(izeu_less).eq.k) r=0
enddo
if (r.ne.0) then
zeu_x(:,:,:)=zeu_u(k,:,:,:)
call sp_zeu(zeu_x,zeu_new,nat,scal)
zeu_w(:,:,:) = zeu_w(:,:,:) + scal*zeu_u(k,:,:,:)
endif
enddo
!
! Final substraction of the former projection to the initial zeu, to get
! the new "projected" zeu
!
zeu_new(:,:,:)=zeu_new(:,:,:) - zeu_w(:,:,:)
call sp_zeu(zeu_w,zeu_w,nat,norm2)
write(stdout,'(" Norm of the difference between old and new effective ", &
& "charges: ",F25.20/)') SQRT(norm2)
!
! Check projection
!
!write(6,'("Check projection of zeu")')
!do k=1,p
! zeu_x(:,:,:)=zeu_u(k,:,:,:)
! call sp_zeu(zeu_x,zeu_new,nat,scal)
! if (DABS(scal).gt.1d-10) write(6,'("k= ",I8," zeu_new|zeu_u(k)= ",F15.10)') k,scal
!enddo
!
do i=1,3
do j=1,3
do na=1,nat
zeu(i,j,na)=zeu_new(i,j,na)
enddo
enddo
enddo
!
! Acoustic Sum Rule on force constants
!
!
! generating the vectors of the orthogonal of the subspace to project
! the force-constants matrix on
!
do k=1,18*nat+15
allocate(u(k) % vec(nr1,nr2,nr3,3,3,nat,nat))
u(k) % vec (:,:,:,:,:,:,:)=0.0d0
enddo
ALLOCATE (frc_new(nr1,nr2,nr3,3,3,nat,nat))
if (asr.eq.'all') then
frc_new(:,:,:,:,:,:,:)=frc(:,:,:,:,:,:,:)+frc_lr(:,:,:,:,:,:,:)
else
frc_new(:,:,:,:,:,:,:)=frc(:,:,:,:,:,:,:)
endif
!
p=0
do i=1,3
do j=1,3
do na=1,nat
! These are the 3*3*nat vectors associated with the
! translational acoustic sum rules
p=p+1
u(p) % vec (:,:,:,i,j,na,:)=1.0d0
!
enddo
enddo
enddo
!
if (n.eq.4) then
do i=1,3
do na=1,nat
! These are the 3*nat vectors associated with the
! single rotational sum rule (1D system)
p=p+1
do nb=1,nat
u(p) % vec (:,:,:,i,MOD(axis,3)+1,na,nb)=-tau_blk(MOD(axis+1,3)+1,nb)
u(p) % vec (:,:,:,i,MOD(axis+1,3)+1,na,nb)=tau_blk(MOD(axis,3)+1,nb)
enddo
!
enddo
enddo
endif
!
if (n.eq.6) then
do i=1,3
do j=1,3
do na=1,nat
! These are the 3*3*nat vectors associated with the
! three rotational sum rules (0D system - typ. molecule)
p=p+1
do nb=1,nat
u(p) % vec (:,:,:,i,MOD(j,3)+1,na,nb)=-tau_blk(MOD(j+1,3)+1,nb)
u(p) % vec (:,:,:,i,MOD(j+1,3)+1,na,nb)=tau_blk(MOD(j,3)+1,nb)
enddo
!
enddo
enddo
enddo
endif
!
if (n.eq.21) then
!
!! Please consider citing C. Lin, S. Ponc\'e and N. Marzari, npj Comput Mater 8, 236 (2022)
!! if asr='all' is used.
!
! Born-Huang invariance conditions
do i=1,3
do j=1,3
do na=1,nat
! These are 3*3*nat vectors associated with the three
! rotational sum rules (valid for system of any dimension).
! These differ from the case of n=6 (zero-dim), where atom b is
! in supercell and its position is wrapped to its nearest periodic
! image with the correct weight in the case of degeneracy.
p=p+1
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
rcell=matmul(at_blk,(/n1,n2,n3/)-(/1,1,1/))
r_ws=rcell-tau_blk(:,nb)+tau_blk(:,na)
call ws_all(tau,neq,nr1,nr2,nr3,r_ws,at_blk)
do ieq=1,neq
u(p) % vec (n1,n2,n3,i,MOD(j,3)+1,na,nb)=&
u(p) % vec (n1,n2,n3,i,MOD(j,3)+1,na,nb)-(tau(MOD(j+1,3)+1,ieq)-tau_blk(MOD(j+1,3)+1,na))/DBLE(neq)
u(p) % vec (n1,n2,n3,i,MOD(j+1,3)+1,na,nb)=&
u(p) % vec (n1,n2,n3,i,MOD(j+1,3)+1,na,nb)+(tau(MOD(j,3)+1,ieq)-tau_blk(MOD(j,3)+1,na))/DBLE(neq)
enddo
enddo
enddo
enddo
enddo
!call sp1(frc_new, u(p) % vec (:,:,:,:,:,:,:), nr1,nr2,nr3,nat,scal)
!write(*,*) scal
!
where(abs(u(p) % vec)<eps) u(p) % vec=0.d0
enddo
enddo
enddo
!
! Huang conditions
if (huang) then
do na=1,nat
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
! These are 15 vectors for vanishing stress tensor
rcell=matmul(at_blk,(/n1,n2,n3/)-(/1,1,1/))
r_ws=rcell-tau_blk(:,nb)+tau_blk(:,na)
call ws_all(tau,neq,nr1,nr2,nr3,r_ws,at_blk)
!
do ieq=1,neq
! 1 1 1 2, yx
huang_set(:,1)=(/1,1,1,2/)
u(p+1) % vec (n1,n2,n3,1,1,na,nb)=&
u(p+1) % vec (n1,n2,n3,1,1,na,nb)-tau(1,ieq)*tau(2,ieq)/DBLE(neq)
u(p+1) % vec (n1,n2,n3,1,2,na,nb)=&
u(p+1) % vec (n1,n2,n3,1,2,na,nb)+tau(1,ieq)*tau(1,ieq)/DBLE(neq)
! 1 1 1 3, zx
huang_set(:,2)=(/1,1,1,3/)
u(p+2) % vec (n1,n2,n3,1,1,na,nb)=&
u(p+2) % vec (n1,n2,n3,1,1,na,nb)-tau(1,ieq)*tau(3,ieq)/DBLE(neq)
u(p+2) % vec (n1,n2,n3,1,3,na,nb)=&
u(p+2) % vec (n1,n2,n3,1,3,na,nb)+tau(1,ieq)*tau(1,ieq)/DBLE(neq)
! 1 1 2 2, xx-yy
huang_set(:,3)=(/1,1,2,2/)
u(p+3) % vec (n1,n2,n3,1,1,na,nb)=&
u(p+3) % vec (n1,n2,n3,1,1,na,nb)-tau(2,ieq)*tau(2,ieq)/DBLE(neq)
u(p+3) % vec (n1,n2,n3,2,2,na,nb)=&
u(p+3) % vec (n1,n2,n3,2,2,na,nb)+tau(1,ieq)*tau(1,ieq)/DBLE(neq)
! 1 1 2 3
huang_set(:,4)=(/1,1,2,3/)
u(p+4) % vec (n1,n2,n3,1,1,na,nb)=&
u(p+4) % vec (n1,n2,n3,1,1,na,nb)-tau(2,ieq)*tau(3,ieq)/DBLE(neq)
u(p+4) % vec (n1,n2,n3,2,3,na,nb)=&
u(p+4) % vec (n1,n2,n3,2,3,na,nb)+tau(1,ieq)*tau(1,ieq)/DBLE(neq)
! 1 1 3 3, xx-zz
huang_set(:,5)=(/1,1,3,3/)
u(p+5) % vec (n1,n2,n3,1,1,na,nb)=&
u(p+5) % vec (n1,n2,n3,1,1,na,nb)-tau(3,ieq)*tau(3,ieq)/DBLE(neq)
u(p+5) % vec (n1,n2,n3,3,3,na,nb)=&
u(p+5) % vec (n1,n2,n3,3,3,na,nb)+tau(1,ieq)*tau(1,ieq)/DBLE(neq)
! 1 2 1 3
huang_set(:,6)=(/1,2,1,3/)
u(p+6) % vec (n1,n2,n3,1,2,na,nb)=&
u(p+6) % vec (n1,n2,n3,1,2,na,nb)-tau(1,ieq)*tau(3,ieq)/DBLE(neq)
u(p+6) % vec (n1,n2,n3,1,3,na,nb)=&
u(p+6) % vec (n1,n2,n3,1,3,na,nb)+tau(1,ieq)*tau(2,ieq)/DBLE(neq)
! 1 2 2 2, xy
huang_set(:,7)=(/1,2,2,2/)
u(p+7) % vec (n1,n2,n3,1,2,na,nb)=&
u(p+7) % vec (n1,n2,n3,1,2,na,nb)-tau(2,ieq)*tau(2,ieq)/DBLE(neq)
u(p+7) % vec (n1,n2,n3,2,2,na,nb)=&
u(p+7) % vec (n1,n2,n3,2,2,na,nb)+tau(1,ieq)*tau(2,ieq)/DBLE(neq)
! 1 2 2 3
huang_set(:,8)=(/1,2,2,3/)
u(p+8) % vec (n1,n2,n3,1,2,na,nb)=&
u(p+8) % vec (n1,n2,n3,1,2,na,nb)-tau(2,ieq)*tau(3,ieq)/DBLE(neq)
u(p+8) % vec (n1,n2,n3,2,3,na,nb)=&
u(p+8) % vec (n1,n2,n3,2,3,na,nb)+tau(1,ieq)*tau(2,ieq)/DBLE(neq)
! 1 2 3 3
huang_set(:,9)=(/1,2,3,3/)
u(p+9) % vec (n1,n2,n3,1,2,na,nb)=&
u(p+9) % vec (n1,n2,n3,1,2,na,nb)-tau(3,ieq)*tau(3,ieq)/DBLE(neq)
u(p+9) % vec (n1,n2,n3,3,3,na,nb)=&
u(p+9) % vec (n1,n2,n3,3,3,na,nb)+tau(1,ieq)*tau(2,ieq)/DBLE(neq)
! 1 3 2 2
huang_set(:,10)=(/1,3,2,2/)
u(p+10) % vec (n1,n2,n3,1,3,na,nb)=&
u(p+10) % vec (n1,n2,n3,1,3,na,nb)-tau(2,ieq)*tau(2,ieq)/DBLE(neq)
u(p+10) % vec (n1,n2,n3,2,2,na,nb)=&
u(p+10) % vec (n1,n2,n3,2,2,na,nb)+tau(1,ieq)*tau(3,ieq)/DBLE(neq)
! 1 3 2 3
huang_set(:,11)=(/1,3,2,3/)
u(p+11) % vec (n1,n2,n3,1,3,na,nb)=&
u(p+11) % vec (n1,n2,n3,1,3,na,nb)-tau(2,ieq)*tau(3,ieq)/DBLE(neq)
u(p+11) % vec (n1,n2,n3,2,3,na,nb)=&
u(p+11) % vec (n1,n2,n3,2,3,na,nb)+tau(1,ieq)*tau(3,ieq)/DBLE(neq)
! 1 3 3 3, xz
huang_set(:,12)=(/1,3,3,3/)
u(p+12) % vec (n1,n2,n3,1,3,na,nb)=&
u(p+12) % vec (n1,n2,n3,1,3,na,nb)-tau(3,ieq)*tau(3,ieq)/DBLE(neq)
u(p+12) % vec (n1,n2,n3,3,3,na,nb)=&
u(p+12) % vec (n1,n2,n3,3,3,na,nb)+tau(1,ieq)*tau(3,ieq)/DBLE(neq)
! 2 2 2 3, zy
huang_set(:,13)=(/2,2,2,3/)
u(p+13) % vec (n1,n2,n3,2,2,na,nb)=&
u(p+13) % vec (n1,n2,n3,2,2,na,nb)-tau(2,ieq)*tau(3,ieq)/DBLE(neq)
u(p+13) % vec (n1,n2,n3,2,3,na,nb)=&
u(p+13) % vec (n1,n2,n3,2,3,na,nb)+tau(2,ieq)*tau(2,ieq)/DBLE(neq)
! 2 2 3 3, yy-zz
huang_set(:,14)=(/2,2,3,3/)
u(p+14) % vec (n1,n2,n3,2,2,na,nb)=&
u(p+14) % vec (n1,n2,n3,2,2,na,nb)-tau(3,ieq)*tau(3,ieq)/DBLE(neq)
u(p+14) % vec (n1,n2,n3,3,3,na,nb)=&
u(p+14) % vec (n1,n2,n3,3,3,na,nb)+tau(2,ieq)*tau(2,ieq)/DBLE(neq)
! 2 3 3 3, yz
huang_set(:,15)=(/2,3,3,3/)
u(p+15) % vec (n1,n2,n3,2,3,na,nb)=&
u(p+15) % vec (n1,n2,n3,2,3,na,nb)-tau(3,ieq)*tau(3,ieq)/DBLE(neq)
u(p+15) % vec (n1,n2,n3,3,3,na,nb)=&
u(p+15) % vec (n1,n2,n3,3,3,na,nb)+tau(2,ieq)*tau(3,ieq)/DBLE(neq)
enddo
!
enddo
enddo
enddo
enddo
enddo
!
do ip=1,15
where(abs(u(p+ip) % vec)<eps) u(p+ip) % vec=0.d0
call sp1(u(p+ip) % vec (:,:,:,:,:,:,:), frc_new, nr1,nr2,nr3,nat,scal)
write(stdout,'(A, 4I4, A, F20.16)') " Huang before: ", huang_set(:,ip), ", residual stress: ", scal
enddo
write(stdout,*)
p=p+15
endif
!
endif
!
allocate (ind_v(9*nat*nat*nr1*nr2*nr3,2,7), v(9*nat*nat*nr1*nr2*nr3,2) )
m=0
do i=1,3
do j=1,3
do na=1,nat
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
! These are the vectors associated with the symmetry constraints
q=1
l=1
do while((l.le.m).and.(q.ne.0))
if ((ind_v(l,1,1).eq.n1).and.(ind_v(l,1,2).eq.n2).and. &
(ind_v(l,1,3).eq.n3).and.(ind_v(l,1,4).eq.i).and. &
(ind_v(l,1,5).eq.j).and.(ind_v(l,1,6).eq.na).and. &
(ind_v(l,1,7).eq.nb)) q=0
if ((ind_v(l,2,1).eq.n1).and.(ind_v(l,2,2).eq.n2).and. &
(ind_v(l,2,3).eq.n3).and.(ind_v(l,2,4).eq.i).and. &
(ind_v(l,2,5).eq.j).and.(ind_v(l,2,6).eq.na).and. &
(ind_v(l,2,7).eq.nb)) q=0
l=l+1
enddo
if ((n1.eq.MOD(nr1+1-n1,nr1)+1).and.(n2.eq.MOD(nr2+1-n2,nr2)+1) &
.and.(n3.eq.MOD(nr3+1-n3,nr3)+1).and.(i.eq.j).and.(na.eq.nb)) q=0
if (q.ne.0) then
m=m+1
ind_v(m,1,1)=n1
ind_v(m,1,2)=n2
ind_v(m,1,3)=n3
ind_v(m,1,4)=i
ind_v(m,1,5)=j
ind_v(m,1,6)=na
ind_v(m,1,7)=nb
v(m,1)=1.0d0/DSQRT(2.0d0)
ind_v(m,2,1)=MOD(nr1+1-n1,nr1)+1
ind_v(m,2,2)=MOD(nr2+1-n2,nr2)+1
ind_v(m,2,3)=MOD(nr3+1-n3,nr3)+1
ind_v(m,2,4)=j
ind_v(m,2,5)=i
ind_v(m,2,6)=nb
ind_v(m,2,7)=na
v(m,2)=-1.0d0/DSQRT(2.0d0)
endif
enddo
enddo
enddo
enddo
enddo
enddo
enddo
!
! Gram-Schmidt orthonormalization of the set of vectors created.
! Note that the vectors corresponding to symmetry constraints are already
! orthonormalized by construction.
!
n_less=0
allocate (w(nr1,nr2,nr3,3,3,nat,nat), x(nr1,nr2,nr3,3,3,nat,nat))
do k=1,p
w(:,:,:,:,:,:,:)=u(k) % vec (:,:,:,:,:,:,:)
x(:,:,:,:,:,:,:)=u(k) % vec (:,:,:,:,:,:,:)
do l=1,m
!
call sp2(x,v(l,:),ind_v(l,:,:),nr1,nr2,nr3,nat,scal)
do r=1,2
n1=ind_v(l,r,1)
n2=ind_v(l,r,2)
n3=ind_v(l,r,3)
i=ind_v(l,r,4)
j=ind_v(l,r,5)
na=ind_v(l,r,6)
nb=ind_v(l,r,7)
w(n1,n2,n3,i,j,na,nb)=w(n1,n2,n3,i,j,na,nb)-scal*v(l,r)
enddo
enddo
if (k.le.(9*nat)) then
na1=MOD(k,nat)
if (na1.eq.0) na1=nat
j1=MOD((k-na1)/nat,3)+1
i1=MOD((((k-na1)/nat)-j1+1)/3,3)+1
else
q=k-9*nat
if (k.le.(18*nat)) then
if (n.eq.4) then
na1=MOD(q,nat)
if (na1.eq.0) na1=nat
i1=MOD((q-na1)/nat,3)+1
else
na1=MOD(q,nat)
if (na1.eq.0) na1=nat
j1=MOD((q-na1)/nat,3)+1
i1=MOD((((q-na1)/nat)-j1+1)/3,3)+1
endif
endif
endif
do q=1,k-1
r=1
do i_less=1,n_less
if (u_less(i_less).eq.q) r=0
enddo
if (r.ne.0) then
if (k.le.(18*nat)) then
call sp3(x,u(q) % vec (:,:,:,:,:,:,:), i1,na1,nr1,nr2,nr3,nat,scal)
else
call sp1(x,u(q) % vec (:,:,:,:,:,:,:), nr1,nr2,nr3,nat,scal)
endif
w(:,:,:,:,:,:,:) = w(:,:,:,:,:,:,:) - scal * u(q) % vec (:,:,:,:,:,:,:)
endif
enddo
call sp1(w,w,nr1,nr2,nr3,nat,norm2)
if (norm2.gt.eps) then
u(k) % vec (:,:,:,:,:,:,:) = w(:,:,:,:,:,:,:) / DSQRT(norm2)
else
n_less=n_less+1
u_less(n_less)=k
endif
enddo
!
! Projection of the force-constants "vector" on the orthogonal of the
! subspace of the vectors verifying the sum rules and symmetry contraints
!
w(:,:,:,:,:,:,:)=0.0d0
do l=1,m
call sp2(frc_new,v(l,:),ind_v(l,:,:),nr1,nr2,nr3,nat,scal)
do r=1,2
n1=ind_v(l,r,1)
n2=ind_v(l,r,2)
n3=ind_v(l,r,3)
i=ind_v(l,r,4)
j=ind_v(l,r,5)
na=ind_v(l,r,6)
nb=ind_v(l,r,7)
w(n1,n2,n3,i,j,na,nb)=w(n1,n2,n3,i,j,na,nb)+scal*v(l,r)
enddo
enddo
do k=1,p
r=1
do i_less=1,n_less
if (u_less(i_less).eq.k) r=0
enddo
if (r.ne.0) then
x(:,:,:,:,:,:,:)=u(k) % vec (:,:,:,:,:,:,:)
call sp1(x,frc_new,nr1,nr2,nr3,nat,scal)
w(:,:,:,:,:,:,:) = w(:,:,:,:,:,:,:) + scal*u(k)%vec(:,:,:,:,:,:,:)
endif
deallocate(u(k) % vec)
enddo
!
! Final substraction of the former projection to the initial frc, to get
! the new "projected" frc
!
frc_new(:,:,:,:,:,:,:)=frc_new(:,:,:,:,:,:,:) - w(:,:,:,:,:,:,:)
if (asr.eq.'all') frc_new(:,:,:,:,:,:,:)=frc_new(:,:,:,:,:,:,:) - frc_lr(:,:,:,:,:,:,:)
call sp1(w,w,nr1,nr2,nr3,nat,norm2)
write(stdout,'(" Norm of the difference between old and new force-constants:",&
& F25.20/)') SQRT(norm2)
!
! Check projection
!
!write(6,'("Check projection IFC")')
!do l=1,m
! call sp2(frc_new,v(l,:),ind_v(l,:,:),nr1,nr2,nr3,nat,scal)
! if (DABS(scal).gt.1d-10) write(6,'("l= ",I8," frc_new|v(l)= ",F15.10)') l,scal
!enddo
!do k=1,p
! x(:,:,:,:,:,:,:)=u(k) % vec (:,:,:,:,:,:,:)
! call sp1(x,frc_new,nr1,nr2,nr3,nat,scal)
! if (DABS(scal).gt.1d-10) write(6,'("k= ",I8," frc_new|u(k)= ",F15.10)') k,scal
! deallocate(u(k) % vec)
!enddo
!
frc(:,:,:,:,:,:,:)=frc_new(:,:,:,:,:,:,:)
!
deallocate (x, w)
deallocate (v, ind_v)
deallocate (frc_new)
!
return
end subroutine set_asr
!
!----------------------------------------------------------------------
subroutine sp_zeu(zeu_u,zeu_v,nat,scal)
!-----------------------------------------------------------------------
!
! does the scalar product of two effective charges matrices zeu_u and zeu_v
! (considered as vectors in the R^(3*3*nat) space, and coded in the usual way)
!
USE kinds, ONLY: DP
implicit none
integer i,j,na,nat
real(DP) zeu_u(3,3,nat)
real(DP) zeu_v(3,3,nat)
real(DP) scal
!
!
scal=0.0d0
do i=1,3
do j=1,3
do na=1,nat
scal=scal+zeu_u(i,j,na)*zeu_v(i,j,na)
enddo
enddo
enddo
!
return
!
end subroutine sp_zeu
!
!
!----------------------------------------------------------------------
subroutine sp1(u,v,nr1,nr2,nr3,nat,scal)
!-----------------------------------------------------------------------
!
! does the scalar product of two force-constants matrices u and v (considered as
! vectors in the R^(3*3*nat*nat*nr1*nr2*nr3) space, and coded in the usual way)
!
USE kinds, ONLY: DP
implicit none
integer nr1,nr2,nr3,i,j,na,nb,n1,n2,n3,nat
real(DP) u(nr1,nr2,nr3,3,3,nat,nat)
real(DP) v(nr1,nr2,nr3,3,3,nat,nat)
real(DP) scal
!
!
scal=0.0d0
do i=1,3
do j=1,3
do na=1,nat
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
scal=scal+u(n1,n2,n3,i,j,na,nb)*v(n1,n2,n3,i,j,na,nb)
enddo
enddo
enddo
enddo
enddo
enddo
enddo
!
return
!
end subroutine sp1
!
!----------------------------------------------------------------------
subroutine sp2(u,v,ind_v,nr1,nr2,nr3,nat,scal)
!-----------------------------------------------------------------------
!
! does the scalar product of two force-constants matrices u and v (considered as
! vectors in the R^(3*3*nat*nat*nr1*nr2*nr3) space). u is coded in the usual way
! but v is coded as explained when defining the vectors corresponding to the
! symmetry constraints
!
USE kinds, ONLY: DP
implicit none
integer nr1,nr2,nr3,i,nat
real(DP) u(nr1,nr2,nr3,3,3,nat,nat)
integer ind_v(2,7)
real(DP) v(2)
real(DP) scal
!
!
scal=0.0d0
do i=1,2
scal=scal+u(ind_v(i,1),ind_v(i,2),ind_v(i,3),ind_v(i,4),ind_v(i,5),ind_v(i,6), &
ind_v(i,7))*v(i)
enddo
!
return
!
end subroutine sp2
!
!----------------------------------------------------------------------
subroutine sp3(u,v,i,na,nr1,nr2,nr3,nat,scal)
!-----------------------------------------------------------------------
!
! like sp1, but in the particular case when u is one of the u(k)%vec
! defined in set_asr (before orthonormalization). In this case most of the
! terms are zero (the ones that are not are characterized by i and na), so
! that a lot of computer time can be saved (during Gram-Schmidt).
!
USE kinds, ONLY: DP
implicit none
integer nr1,nr2,nr3,i,j,na,nb,n1,n2,n3,nat
real(DP) u(nr1,nr2,nr3,3,3,nat,nat)
real(DP) v(nr1,nr2,nr3,3,3,nat,nat)
real(DP) scal
!
!
scal=0.0d0
do j=1,3
do nb=1,nat
do n1=1,nr1
do n2=1,nr2
do n3=1,nr3
scal=scal+u(n1,n2,n3,i,j,na,nb)*v(n1,n2,n3,i,j,na,nb)
enddo
enddo
enddo
enddo
enddo
!
return
!
end subroutine sp3
!
!-----------------------------------------------------------------------
SUBROUTINE ws_all(tau,neq,nr1,nr2,nr3,r_ws,at_blk)
!-----------------------------------------------------------------------
!! Used in set_asr
!! Determine the nearest periodic image for an atom pair
!! Calculte the number of degeneracies as weight when
!! on the surface of the optimal Wigner-Seitz cell
!
USE kinds, ONLY: DP
!
IMPLICIT NONE
!
INTEGER, INTENT(in) :: nr1,nr2,nr3
!! Supercell size
INTEGER, INTENT(out) :: neq
!! Weight of the degeneracy
REAL(DP), INTENT(in) :: r_ws(3)
!! Original position in the supercell
REAL(DP), INTENT(in) :: at_blk(3, 3)
!! Lattice vector of the primitive cell
REAL(DP), INTENT(out) :: tau(3, 48)
!! Nearest periodic atomic position
!
! Local variable
INTEGER :: n1, n2, n3
!! Search around the cell to a maximum of 2 around
REAL(DP) :: rnorm
!! Distance betweem origin cell and current cell
REAL(DP) :: eps
!! Tolerence
REAL(DP) :: tau_tmp(3)
!! Position of the current cell
REAL(DP) :: at(3,3)
!! Lattice vector of the supercell
REAL(DP) :: rmin
!! Minimal distance
!
! Large tolerence to find degeneracy position in case of bad relaxation
eps = 1.0d-5
!
at(:, 1) = at_blk(:, 1) * DBLE(nr1)
at(:, 2) = at_blk(:, 2) * DBLE(nr2)
at(:, 3) = at_blk(:, 3) * DBLE(nr3)
!
rmin = HUGE(rmin)
DO n1 = -2,2
DO n2 = -2,2
DO n3 = -2,2
tau_tmp = r_ws + n1 * at(:, 1) + n2 * at(:, 2) + n3 * at(:, 3)
rnorm = NORM2(tau_tmp)
IF (ABS(rnorm - rmin) .gt. eps) THEN
IF (rnorm .lt. rmin) THEN
neq = 1
rmin = rnorm
tau(:, neq) = tau_tmp
ENDIF
ELSE
neq = neq + 1
tau(:, neq) = tau_tmp
ENDIF
ENDDO
ENDDO
ENDDO
!
RETURN
!
!-----------------------------------------------------------------------
END SUBROUTINE ws_all
!-----------------------------------------------------------------------
!
!-----------------------------------------------------------------------
SUBROUTINE q_gen(nsc,qbid,at_blk,bg_blk,at,bg)
!-----------------------------------------------------------------------
! generate list of q (qbid) that are G-vectors of the supercell
! but not of the bulk
!
USE kinds, ONLY : DP
!
IMPLICIT NONE
INTEGER :: nsc
REAL(DP) qbid(3,nsc), at_blk(3,3), bg_blk(3,3), at(3,3), bg(3,3)
!
INTEGER, PARAMETER:: nr1=4, nr2=4, nr3=4, &
nrm=(2*nr1+1)*(2*nr2+1)*(2*nr3+1)
REAL(DP), PARAMETER:: eps=1.0d-7
INTEGER :: i, j, k,i1, i2, i3, idum(nrm), iq
REAL(DP) :: qnorm(nrm), qbd(3,nrm) ,qwork(3), delta
LOGICAL lbho
!
i = 0
DO i1=-nr1,nr1
DO i2=-nr2,nr2
DO i3=-nr3,nr3
i = i + 1
DO j=1,3
qwork(j) = i1*bg(j,1) + i2*bg(j,2) + i3*bg(j,3)
END DO ! j
!
qnorm(i) = qwork(1)**2 + qwork(2)**2 + qwork(3)**2
!
DO j=1,3
!
qbd(j,i) = at_blk(1,j)*qwork(1) + &
at_blk(2,j)*qwork(2) + &
at_blk(3,j)*qwork(3)
END DO ! j
!
idum(i) = 1
!
END DO ! i3
END DO ! i2
END DO ! i1
!
DO i=1,nrm-1
IF (idum(i).EQ.1) THEN
DO j=i+1,nrm
IF (idum(j).EQ.1) THEN
lbho=.TRUE.
DO k=1,3
delta = qbd(k,i)-qbd(k,j)
lbho = lbho.AND. (ABS(NINT(delta)-delta).LT.eps)
END DO ! k
IF (lbho) THEN
IF(qnorm(i).GT.qnorm(j)) THEN
qbd(1,i) = qbd(1,j)
qbd(2,i) = qbd(2,j)
qbd(3,i) = qbd(3,j)
qnorm(i) = qnorm(j)
END IF
idum(j) = 0
END IF
END IF
END DO ! j
END IF
END DO ! i
!
iq = 0
DO i=1,nrm
IF (idum(i).EQ.1) THEN
iq=iq+1
qbid(1,iq)= bg_blk(1,1)*qbd(1,i) + &
bg_blk(1,2)*qbd(2,i) + &
bg_blk(1,3)*qbd(3,i)
qbid(2,iq)= bg_blk(2,1)*qbd(1,i) + &
bg_blk(2,2)*qbd(2,i) + &
bg_blk(2,3)*qbd(3,i)
qbid(3,iq)= bg_blk(3,1)*qbd(1,i) + &
bg_blk(3,2)*qbd(2,i) + &
bg_blk(3,3)*qbd(3,i)
END IF
END DO ! i
!
IF (iq.NE.nsc) CALL errore('q_gen',' probably nr1,nr2,nr3 too small ', iq)
RETURN
END SUBROUTINE q_gen
!
!-----------------------------------------------------------------------
SUBROUTINE check_at(at,bg_blk,alat,omega)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : stdout
!
IMPLICIT NONE
!
REAL(DP) :: at(3,3), bg_blk(3,3), alat, omega
REAL(DP) :: work(3,3)
INTEGER :: i,j
REAL(DP), PARAMETER :: small=1.d-6
!
work(:,:) = at(:,:)
CALL cryst_to_cart(3,work,bg_blk,-1)
!
DO j=1,3
DO i =1,3
IF ( ABS(work(i,j)-NINT(work(i,j))) > small) THEN
WRITE (stdout,'(3f9.4)') work(:,:)
CALL errore ('check_at','at not multiple of at_blk',1)
END IF
END DO
END DO
!
omega =alat**3 * ABS(at(1,1)*(at(2,2)*at(3,3)-at(3,2)*at(2,3))- &
at(1,2)*(at(2,1)*at(3,3)-at(2,3)*at(3,1))+ &
at(1,3)*(at(2,1)*at(3,2)-at(2,2)*at(3,1)))
!
RETURN
END SUBROUTINE check_at
!
!-----------------------------------------------------------------------
SUBROUTINE set_tau (nat, nat_blk, at, at_blk, tau, tau_blk, &
ityp, ityp_blk, itau_blk)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
!
IMPLICIT NONE
INTEGER nat, nat_blk,ityp(nat),ityp_blk(nat_blk), itau_blk(nat)
REAL(DP) at(3,3),at_blk(3,3),tau(3,nat),tau_blk(3,nat_blk)
!
REAL(DP) bg(3,3), r(3) ! work vectors
INTEGER i,i1,i2,i3,na,na_blk
REAL(DP) small
INTEGER NN1,NN2,NN3
PARAMETER (NN1=8, NN2=8, NN3=8, small=1.d-8)
!
CALL recips (at(1,1),at(1,2),at(1,3),bg(1,1),bg(1,2),bg(1,3))
!
na = 0
!
DO i1 = -NN1,NN1
DO i2 = -NN2,NN2
DO i3 = -NN3,NN3
r(1) = i1*at_blk(1,1) + i2*at_blk(1,2) + i3*at_blk(1,3)
r(2) = i1*at_blk(2,1) + i2*at_blk(2,2) + i3*at_blk(2,3)
r(3) = i1*at_blk(3,1) + i2*at_blk(3,2) + i3*at_blk(3,3)
CALL cryst_to_cart(1,r,bg,-1)
!
IF ( r(1).GT.-small .AND. r(1).LT.1.d0-small .AND. &
r(2).GT.-small .AND. r(2).LT.1.d0-small .AND. &
r(3).GT.-small .AND. r(3).LT.1.d0-small ) THEN
CALL cryst_to_cart(1,r,at,+1)
!
DO na_blk=1, nat_blk
na = na + 1
IF (na.GT.nat) CALL errore('set_tau','too many atoms',na)
tau(1,na) = tau_blk(1,na_blk) + r(1)
tau(2,na) = tau_blk(2,na_blk) + r(2)
tau(3,na) = tau_blk(3,na_blk) + r(3)
ityp(na) = ityp_blk(na_blk)
itau_blk(na) = na_blk
END DO
!
END IF
!
END DO
END DO
END DO
!
IF (na.NE.nat) CALL errore('set_tau','too few atoms: increase NNs',na)
!
RETURN
END SUBROUTINE set_tau
!
!-----------------------------------------------------------------------
SUBROUTINE read_tau &
(nat, nat_blk, ntyp, bg_blk, tau, tau_blk, ityp, itau_blk)
!---------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : ionode_id, ionode
USE mp, ONLY : mp_bcast
USE mp_world, ONLY : world_comm
!
IMPLICIT NONE
!
INTEGER nat, nat_blk, ntyp, ityp(nat),itau_blk(nat)
REAL(DP) bg_blk(3,3),tau(3,nat),tau_blk(3,nat_blk)
!
REAL(DP) r(3) ! work vectors
INTEGER i,na,na_blk
!
REAL(DP) small
PARAMETER ( small = 1.d-6 )
!
DO na=1,nat
IF (ionode) READ(5,*) (tau(i,na),i=1,3), ityp(na)
CALL mp_bcast(tau(:,na),ionode_id, world_comm)
CALL mp_bcast(ityp(na),ionode_id, world_comm)
IF (ityp(na).LE.0 .OR. ityp(na) .GT. ntyp) &
CALL errore('read_tau',' wrong atomic type', na)
DO na_blk=1,nat_blk
r(1) = tau(1,na) - tau_blk(1,na_blk)
r(2) = tau(2,na) - tau_blk(2,na_blk)
r(3) = tau(3,na) - tau_blk(3,na_blk)
CALL cryst_to_cart(1,r,bg_blk,-1)
IF (ABS( r(1)-NINT(r(1)) ) .LT. small .AND. &
ABS( r(2)-NINT(r(2)) ) .LT. small .AND. &
ABS( r(3)-NINT(r(3)) ) .LT. small ) THEN
itau_blk(na) = na_blk
go to 999
END IF
END DO
CALL errore ('read_tau',' wrong atomic position ', na)
999 CONTINUE
END DO
!
RETURN
END SUBROUTINE read_tau
!
!-----------------------------------------------------------------------
SUBROUTINE write_tau(fltau,nat,tau,ityp)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : ionode
!
IMPLICIT NONE
!
INTEGER nat, ityp(nat)
REAL(DP) tau(3,nat)
CHARACTER(LEN=*) fltau
!
INTEGER i,na
!
IF (.NOT.ionode) RETURN
OPEN (unit=4,file=fltau, status='new')
DO na=1,nat
WRITE(4,'(3(f12.6),i3)') (tau(i,na),i=1,3), ityp(na)
END DO
CLOSE (4)
!
RETURN
END SUBROUTINE write_tau
!
!-----------------------------------------------------------------------
SUBROUTINE gen_qpoints (ibrav, at_, bg_, nat, tau, ityp, nk1, nk2, nk3, &
nqx, nq, q, nosym, wk)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE cell_base, ONLY : at, bg
USE symm_base, ONLY : set_sym_bl, find_sym, s, irt, nsym, &
nrot, t_rev, time_reversal, sname
USE ktetra, ONLY : tetra_init
!
IMPLICIT NONE
! input
INTEGER :: ibrav, nat, nk1, nk2, nk3, ityp(*)
REAL(DP) :: at_(3,3), bg_(3,3), tau(3,nat)
LOGICAL :: nosym
! output
INTEGER :: nqx, nq
REAL(DP) :: q(3,nqx), wk(nqx)
! local
REAL(DP) :: xqq(3), mdum(3,nat)
LOGICAL :: magnetic_sym=.FALSE., skip_equivalence=.FALSE.
!
time_reversal = .true.
if (nosym) time_reversal = .false.
t_rev(:) = 0
xqq (:) =0.d0
at = at_
bg = bg_
CALL set_sym_bl ( )
!
if (nosym) then
nrot = 1
nsym = 1
endif
CALL kpoint_grid ( nrot, time_reversal, skip_equivalence, s, t_rev, bg, nqx, &
0,0,0, nk1,nk2,nk3, nq, q, wk)
!
CALL find_sym ( nat, tau, ityp, .not.time_reversal, mdum )
!
CALL irreducible_BZ (nrot, s, nsym, time_reversal, magnetic_sym, &
at, bg, nqx, nq, q, wk, t_rev)
!
CALL tetra_init (nsym, s, time_reversal, t_rev, at, bg, nqx, 0, 0, 0, &
nk1, nk2, nk3, nq, q)
!
RETURN
END SUBROUTINE gen_qpoints
!
!---------------------------------------------------------------------
SUBROUTINE a2Fdos &
(nat, nq, nr1, nr2, nr3, ibrav, at, bg, tau, alat, &
nsc, nat_blk, at_blk, bg_blk, itau_blk, omega_blk, rws, nrws, &
dos, Emin, DeltaE, ndos, asr, q, freq, fd, wq, huang)
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : ionode, ionode_id
USE mp, ONLY : mp_bcast
USE mp_world, ONLY : world_comm
USE mp_images, ONLY : intra_image_comm
USE ifconstants, ONLY : zeu, tau_blk, frc_lr
USE constants, ONLY : pi, RY_TO_THZ
USE constants, ONLY : K_BOLTZMANN_RY
USE el_phon, ONLY : el_ph_nsigma
!
IMPLICIT NONE
!
INTEGER, INTENT(in) :: nat, nq, nr1, nr2, nr3, ibrav, ndos
LOGICAL, INTENT(in) :: dos, fd, huang
CHARACTER(LEN=*), INTENT(IN) :: asr
REAL(DP), INTENT(in) :: freq(3*nat,nq), q(3,nq), wq(nq), at(3,3), bg(3,3), &
tau(3,nat), alat, Emin, DeltaE
!
INTEGER, INTENT(in) :: nsc, nat_blk, itau_blk(nat), nrws
REAL(DP), INTENT(in) :: rws(0:3,nrws), at_blk(3,3), bg_blk(3,3), omega_blk
!
REAL(DP), ALLOCATABLE :: gamma(:,:), frcg(:,:,:,:,:,:,:)
COMPLEX(DP), ALLOCATABLE :: gam(:,:,:,:), gam_blk(:,:,:,:), z(:,:)
real(DP) :: lambda, dos_a2F(3*nat), temp, dos_ee(el_ph_nsigma), dos_tot, &
deg(el_ph_nsigma), fermi(el_ph_nsigma), E
real(DP), parameter :: eps_w2 = 0.0000001d0
integer :: isig, ifn, n, m, na, nb, nc, nu, nmodes, &
i,j,k, ngauss, jsig, p1, p2, p3, filea2F, ios
character(len=256) :: name
real(DP), external :: dos_gam
CHARACTER(LEN=6) :: int_to_char
!
!
nmodes = 3*nat
do isig=1,el_ph_nsigma
filea2F = 60 + isig
name= 'elph_dir/a2Fmatdyn.' // TRIM(int_to_char(filea2F))
IF (ionode) open(unit=filea2F, file=TRIM(name), &
STATUS = 'unknown', IOSTAT=ios)
CALL mp_bcast(ios, ionode_id, intra_image_comm)
IF (ios /= 0) CALL errore('a2Fdos','problem opening file'//TRIM(name),1)
IF (ionode) &
READ(filea2F,*) deg(isig), fermi(isig), dos_ee(isig)
ENDDO
call mp_bcast(deg, ionode_id, intra_image_comm)
call mp_bcast(fermi, ionode_id, intra_image_comm)
call mp_bcast(dos_ee, ionode_id, intra_image_comm)
!
IF (ionode) THEN
IF(dos) then
open(unit=400,file='lambda',status='unknown')
write(400,*)
write(400,*) ' Electron-phonon coupling constant, lambda '
write(400,*)
ELSE
open (unit=20,file='gam.lines' ,status='unknown')
write(20,*)
write(20,*) ' Gamma lines for all modes [THz] '
write(20,*)
write(6,*)
write(6,*) ' Gamma lines for all modes [Rydberg] '
write(6,*)
ENDIF
ENDIF
!
ALLOCATE ( frcg(nr1,nr2,nr3,3,3,nat,nat) )
ALLOCATE ( gamma(3*nat,nq), gam(3,3,nat,nat), gam_blk(3,3,nat_blk,nat_blk) )
ALLOCATE ( z(3*nat,3*nat) )
!
frcg(:,:,:,:,:,:,:) = 0.d0
DO isig = 1, el_ph_nsigma
filea2F = 60 + isig
CALL readfg ( filea2F, nr1, nr2, nr3, nat, frcg )
!
if ( asr /= 'no') then
CALL set_asr (asr, nr1, nr2, nr3, frcg, frc_lr, zeu, nat_blk, ibrav, &
tau_blk, at_blk, huang)
endif
!
IF (ionode) open(unit=300,file='dyna2F',status='old')
!
do n = 1 ,nq
gam(:,:,:,:) = (0.d0, 0.d0)
IF (ionode) THEN
read(300,*)
do na=1,nmodes
read(300,*) (z(na,m),m=1,nmodes)
end do ! na
ENDIF
CALL mp_bcast(z, ionode_id, world_comm)
!
CALL setgam (q(1,n), gam, nat, at, bg, tau, itau_blk, nsc, alat, &
gam_blk, nat_blk, at_blk,bg_blk,tau_blk, omega_blk, &
frcg, nr1,nr2,nr3, rws, nrws, fd)
!
! here multiply dyn*gam*dyn for gamma and divide by w2 for lambda at given q
!
do nc = 1, nat
do k =1, 3
p1 = (nc-1)*3+k
nu = p1
gamma(nu,n) = 0.0d0
do i=1,3
do na=1,nat
p2 = (na-1)*3+i
do j=1,3
do nb=1,nat
p3 = (nb-1)*3+j
gamma(nu,n) = gamma(nu,n) + DBLE(conjg(z(p2,p1)) * &
gam(i,j,na,nb) * z(p3,p1))
enddo ! nb
enddo ! j
enddo ! na
enddo !i
gamma(nu,n) = gamma(nu,n) * pi / 2.0d0
enddo ! k
enddo !nc
!
!
EndDo !nq all points in BZ
IF (ionode) close(300) ! file with dyn vectors
!
! after we know gamma(q) and lambda(q) calculate DOS(omega) for spectrum a2F
!
if(dos.and.ionode) then
!
name='a2F.dos'//int_to_char(isig)
ifn = 200 + isig
open (ifn,file=TRIM(name),status='unknown',form='formatted')
write(ifn,*)
write(ifn,*) '# Eliashberg function a2F (per both spin)'
write(ifn,*) '# frequencies in Rydberg '
write(ifn,*) '# DOS normalized to E in Rydberg: a2F_total, a2F(mode) '
write(ifn,*)
!
! correction for small frequencies
!
do n = 1, nq
do i = 1, nmodes
if (freq(i,n).LE.eps_w2) then
gamma(i,n) = 0.0d0
endif
enddo
enddo
!
lambda = 0.0d0
do n= 1, ndos
!
E = Emin + (n-1)*DeltaE + 0.5d0*DeltaE
dos_tot = 0.0d0
do j=1,nmodes
!
dos_a2F(j) = dos_gam(nmodes, nq, j, gamma, freq, E)
dos_a2F(j) = dos_a2F(j) / dos_ee(isig) / 2.d0 / pi
dos_tot = dos_tot + dos_a2F(j)
!
enddo
lambda = lambda + 2.d0 * dos_tot/E * DeltaE
write (ifn, '(3X,1000E16.6)') E, dos_tot, dos_a2F(1:nmodes)
enddo !ndos
write(ifn,*) " lambda =",lambda,' Delta = ',DeltaE
close (ifn)
!
! lambda from alternative way, simple sum.
! Also Omega_ln is computed
!
lambda = 0.0_dp
E = 0.0_dp
do n = 1, nq
lambda = lambda &
& + sum(gamma(1:nmodes,n)/freq(1:nmodes,n)**2, &
& freq(1:nmodes,n) > 1.0e-5_dp) * wq(n)
E = E &
& + sum(log(freq(1:nmodes,n)) * gamma(1:nmodes,n)/freq(1:nmodes,n)**2, &
& freq(1:nmodes,n) > 1.0e-5_dp) * wq(n)
end do
E = exp(E / lambda) / K_BOLTZMANN_RY
lambda = lambda / (dos_ee(isig) * pi)
write(400,'(" Broadening ",F8.4," lambda ",F12.4," dos(Ef)",F8.4," omega_ln [K]",F12.4)') &
deg(isig),lambda, dos_ee(isig), E
!
endif !dos
!
! OUTPUT
!
if(.not.dos.and.ionode) then
write(20,'(" Broadening ",F8.4)') deg(isig)
write( 6,'(" Broadening ",F8.4)') deg(isig)
do n=1, nq
write(20,'(3x,i5)') n
write( 6,'(3x,i5)') n
write(20,'(9F8.4)') (gamma(i,n)*RY_TO_THZ,i=1,3*nat)
write( 6,'(6F12.9)') (gamma(i,n),i=1,3*nat)
!
! write also in a format that can be read by plotband
!
WRITE(200+isig, '(10x,3f10.6)') q(1,n), q(2,n), q(3,n)
!
! output in GHz
!
WRITE(200+isig, '(6f10.4)') (gamma(nu,n)*RY_TO_THZ*1000.0_DP, &
nu=1,3*nat)
end do
endif
!
ENDDO !isig
!
DEALLOCATE (z, frcg, gamma, gam, gam_blk )
!
IF (ionode) THEN
close(400) !lambda
close(20)
ENDIF
!
!
RETURN
END SUBROUTINE a2Fdos
!
!-----------------------------------------------------------------------
subroutine setgam (q, gam, nat, at,bg,tau,itau_blk,nsc,alat, &
& gam_blk, nat_blk, at_blk,bg_blk,tau_blk,omega_blk, &
& frcg, nr1,nr2,nr3, rws,nrws, fd)
!-----------------------------------------------------------------------
! compute the dynamical matrix (the analytic part only)
!
USE kinds, ONLY : DP
USE constants, ONLY : tpi
implicit none
!
! I/O variables
!
integer :: nr1, nr2, nr3, nat, nat_blk, &
nsc, nrws, itau_blk(nat)
real(DP) :: q(3), tau(3,nat), at(3,3), bg(3,3), alat, rws(0:3,nrws)
real(DP) :: tau_blk(3,nat_blk), at_blk(3,3), bg_blk(3,3), omega_blk, &
frcg(nr1,nr2,nr3,3,3,nat_blk,nat_blk)
COMPLEX(DP) :: gam_blk(3,3,nat_blk,nat_blk),f_of_q(3,3,nat,nat)
COMPLEX(DP) :: gam(3,3,nat,nat)
LOGICAL :: fd
!
! local variables
!
real(DP) :: arg
complex(DP) :: cfac(nat)
integer :: i,j,k, na,nb, na_blk, nb_blk, iq
real(DP) :: qp(3), qbid(3,nsc) ! automatic array
!
!
call q_gen(nsc,qbid,at_blk,bg_blk,at,bg)
!
f_of_q=(0.0_DP,0.0_DP)
do iq=1,nsc
!
do k=1,3
qp(k)= q(k) + qbid(k,iq)
end do
!
gam_blk(:,:,:,:) = (0.d0,0.d0)
CALL frc_blk (gam_blk,qp,tau_blk,nat_blk, &
nr1,nr2,nr3,frcg,at_blk,bg_blk,rws,nrws,f_of_q,fd)
!
do na=1,nat
na_blk = itau_blk(na)
do nb=1,nat
nb_blk = itau_blk(nb)
!
arg = tpi * ( qp(1) * ( (tau(1,na)-tau_blk(1,na_blk)) - &
(tau(1,nb)-tau_blk(1,nb_blk)) ) + &
qp(2) * ( (tau(2,na)-tau_blk(2,na_blk)) - &
(tau(2,nb)-tau_blk(2,nb_blk)) ) + &
qp(3) * ( (tau(3,na)-tau_blk(3,na_blk)) - &
(tau(3,nb)-tau_blk(3,nb_blk)) ) )
!
cfac(nb) = CMPLX(cos(arg),sin(arg), kind=dp)/nsc
!
end do ! nb
do nb=1,nat
do i=1,3
do j=1,3
nb_blk = itau_blk(nb)
gam(i,j,na,nb) = gam(i,j,na,nb) + cfac(nb) * &
gam_blk(i,j,na_blk,nb_blk)
end do ! j
end do ! i
end do ! nb
end do ! na
!
end do ! iq
!
return
end subroutine setgam
!
!--------------------------------------------------------------------
function dos_gam (nbndx, nq, jbnd, gamma, et, ef)
!--------------------------------------------------------------------
! calculates weights with the tetrahedron method (Bloechl version)
! this subroutine is based on tweights.f90 belonging to PW
! it calculates a2F on the surface of given frequency <=> histogram
! Band index means the frequency mode here
! and "et" means the frequency(mode,q-point)
!
USE kinds, ONLY: DP
USE parameters
USE ktetra, ONLY : ntetra, tetra
implicit none
!
integer :: nq, nbndx, jbnd
real(DP) :: et(nbndx,nq), gamma(nbndx,nq), func
real(DP) :: ef
real(DP) :: e1, e2, e3, e4, c1, c2, c3, c4, etetra(4)
integer :: ik, ibnd, nt, nk, ns, i, ik1, ik2, ik3, ik4, itetra(4)
real(DP) :: f12,f13,f14,f23,f24,f34, f21,f31,f41,f42,f32,f43
real(DP) :: P1,P2,P3,P4, G, o13, Y1,Y2,Y3,Y4, eps,vol, Tint
real(DP) :: dos_gam
Tint = 0.0d0
o13 = 1.0_dp/3.0_dp
eps = 1.0d-14
vol = 1.0d0/ntetra
P1 = 0.0_dp
P2 = 0.0_dp
P3 = 0.0_dp
P4 = 0.0_dp
do nt = 1, ntetra
ibnd = jbnd
!
! etetra are the energies at the vertexes of the nt-th tetrahedron
!
do i = 1, 4
etetra(i) = et(ibnd, tetra(i,nt))
enddo
itetra(1) = 0
call hpsort (4,etetra,itetra)
!
! ...sort in ascending order: e1 < e2 < e3 < e4
!
e1 = etetra (1)
e2 = etetra (2)
e3 = etetra (3)
e4 = etetra (4)
!
! kp1-kp4 are the irreducible k-points corresponding to e1-e4
!
ik1 = tetra(itetra(1),nt)
ik2 = tetra(itetra(2),nt)
ik3 = tetra(itetra(3),nt)
ik4 = tetra(itetra(4),nt)
Y1 = gamma(ibnd,ik1)/et(ibnd,ik1)
Y2 = gamma(ibnd,ik2)/et(ibnd,ik2)
Y3 = gamma(ibnd,ik3)/et(ibnd,ik3)
Y4 = gamma(ibnd,ik4)/et(ibnd,ik4)
IF ( e3 < ef .and. ef < e4) THEN
f14 = (ef-e4)/(e1-e4)
f24 = (ef-e4)/(e2-e4)
f34 = (ef-e4)/(e3-e4)
G = 3.0_dp * f14 * f24 * f34 / (e4-ef)
P1 = f14 * o13
P2 = f24 * o13
P3 = f34 * o13
P4 = (3.0_dp - f14 - f24 - f34 ) * o13
ELSE IF ( e2 < ef .and. ef < e3 ) THEN
f13 = (ef-e3)/(e1-e3)
f31 = 1.0_dp - f13
f14 = (ef-e4)/(e1-e4)
f41 = 1.0_dp-f14
f23 = (ef-e3)/(e2-e3)
f32 = 1.0_dp - f23
f24 = (ef-e4)/(e2-e4)
f42 = 1.0_dp - f24
G = 3.0_dp * (f23*f31 + f32*f24)
P1 = f14 * o13 + f13*f31*f23 / G
P2 = f23 * o13 + f24*f24*f32 / G
P3 = f32 * o13 + f31*f31*f23 / G
P4 = f41 * o13 + f42*f24*f32 / G
G = G / (e4-e1)
ELSE IF ( e1 < ef .and. ef < e2 ) THEN
f12 = (ef-e2)/(e1-e2)
f21 = 1.0_dp - f12
f13 = (ef-e3)/(e1-e3)
f31 = 1.0_dp - f13
f14 = (ef-e4)/(e1-e4)
f41 = 1.0_dp - f14
G = 3.0_dp * f21 * f31 * f41 / (ef-e1)
P1 = o13 * (f12 + f13 + f14)
P2 = o13 * f21
P3 = o13 * f31
P4 = o13 * f41
ELSE
G = 0.0_dp
END IF
Tint = Tint + G * (Y1*P1 + Y2*P2 + Y3*P3 + Y4*P4) * vol
enddo ! ntetra
dos_gam = Tint !2 because DOS_ee is per 1 spin
return
end function dos_gam
!
!
!------------------------------------------------------------------------------
function dos_broad(iatom, nbndx, nq, et, zq, wq, Ef, degauss)
!------------------------------------------------------------------------------
!
! Get atom projected ph DOS using Gaussian broadening. Inspired by
! thermo_pw/src/generalized_phdos.f90 (GPL)
!
USE kinds, ONLY : DP
!
IMPLICIT NONE
INTEGER, INTENT(IN) :: iatom, nq, nbndx
REAL(DP), INTENT(IN) :: et(nbndx, nq), zq(nq, nbndx, nbndx), wq(nq), Ef, degauss
REAL(DP) :: ufact, weight
INTEGER :: n, ik, ngauss, ipol, indi, jpol, indj
COMPLEX(DP) :: u1, u2
REAL(DP), EXTERNAL :: w0gauss
REAL(DP) :: dos_broad
!
dos_broad = 0.0_DP
!
ngauss = 0
!
DO ik = 1, nq
DO n = 1, nbndx
weight = w0gauss ( (Ef - et(n,ik) ) / degauss, ngauss)
!
DO ipol=1, 3
indi = 3 * (iatom - 1) + ipol
DO jpol = ipol, 3
indj = 3 * (iatom - 1) + jpol
u1=zq(ik, indi, n)
u2=zq(ik, indj, n)
ufact = DBLE(u1*CONJG(u2))
dos_broad = dos_broad + wq(ik) * ufact * weight
ENDDO
ENDDO
!
ENDDO
ENDDO
!
dos_broad = dos_broad / degauss
!
RETURN
end function dos_broad
!
!
!-----------------------------------------------------------------------
subroutine readfg ( ifn, nr1, nr2, nr3, nat, frcg )
!-----------------------------------------------------------------------
!
USE kinds, ONLY : DP
USE io_global, ONLY : ionode, ionode_id, stdout
USE mp, ONLY : mp_bcast
USE mp_world, ONLY : world_comm
implicit none
! I/O variable
integer, intent(in) :: nr1,nr2,nr3, nat
real(DP), intent(out) :: frcg(nr1,nr2,nr3,3,3,nat,nat)
! local variables
integer i, j, na, nb, m1,m2,m3, ifn
integer ibid, jbid, nabid, nbbid, m1bid,m2bid,m3bid
!
!
IF (ionode) READ (ifn,*) m1, m2, m3
CALL mp_bcast(m1, ionode_id, world_comm)
CALL mp_bcast(m2, ionode_id, world_comm)
CALL mp_bcast(m3, ionode_id, world_comm)
if ( m1 /= nr1 .or. m2 /= nr2 .or. m3 /= nr3) &
call errore('readfg','inconsistent nr1, nr2, nr3 read',1)
do i=1,3
do j=1,3
do na=1,nat
do nb=1,nat
IF (ionode) read (ifn,*) ibid, jbid, nabid, nbbid
CALL mp_bcast(ibid, ionode_id, world_comm)
CALL mp_bcast(jbid, ionode_id, world_comm)
CALL mp_bcast(nabid, ionode_id, world_comm)
CALL mp_bcast(nbbid, ionode_id, world_comm)
if(i.ne.ibid.or.j.ne.jbid.or.na.ne.nabid.or.nb.ne.nbbid) then
write(stdout,*) i,j,na,nb,' <> ', ibid, jbid, nabid, nbbid
call errore ('readfG','error in reading',1)
else
IF (ionode) read (ifn,*) (((m1bid, m2bid, m3bid, &
frcg(m1,m2,m3,i,j,na,nb), &
m1=1,nr1),m2=1,nr2),m3=1,nr3)
endif
CALL mp_bcast(frcg(:,:,:,i,j,na,nb), ionode_id, world_comm)
end do
end do
end do
end do
!
IF (ionode) close(ifn)
!
return
end subroutine readfg
!
!
SUBROUTINE find_representations_mode_q ( nat, ntyp, xq, w2, u, tau, ityp, &
amass, num_rap_mode, nspin_mag )
USE kinds, ONLY : DP
USE cell_base, ONLY : at, bg
USE symm_base, ONLY : s, sr, ft, irt, nsym, nrot, t_rev, time_reversal,&
sname, copy_sym, s_axis_to_cart
IMPLICIT NONE
INTEGER, INTENT(IN) :: nat, ntyp, nspin_mag
REAL(DP), INTENT(IN) :: xq(3), amass(ntyp), tau(3,nat)
REAL(DP), INTENT(IN) :: w2(3*nat)
INTEGER, INTENT(IN) :: ityp(nat)
COMPLEX(DP), INTENT(IN) :: u(3*nat,3*nat)
INTEGER, INTENT(OUT) :: num_rap_mode(3*nat)
REAL(DP) :: gi (3, 48), gimq (3), sr_is(3,3,48), rtau(3,48,nat)
INTEGER :: irotmq, nsymq, nsym_is, isym, i, ierr
LOGICAL :: minus_q, search_sym, sym(48), magnetic_sym
!
! find the small group of q
!
time_reversal=.TRUE.
IF (.NOT.time_reversal) minus_q=.FALSE.
sym(1:nsym)=.true.
call smallg_q (xq, 0, at, bg, nsym, s, sym, minus_q)
nsymq=copy_sym(nsym,sym )
call s_axis_to_cart ()
CALL set_giq (xq,s,nsymq,nsym,irotmq,minus_q,gi,gimq)
!
! if the small group of q is non symmorphic,
! search the symmetries only if there are no G such that Sq -> q+G
!
search_sym=.TRUE.
IF ( ANY ( ABS(ft(:,1:nsymq)) > 1.0d-8 ) ) THEN
DO isym=1,nsymq
search_sym=( search_sym.and.(abs(gi(1,isym))<1.d-8).and. &
(abs(gi(2,isym))<1.d-8).and. &
(abs(gi(3,isym))<1.d-8) )
END DO
END IF
!
! Set the representations tables of the small group of q and
! find the mode symmetry
!
IF (search_sym) THEN
magnetic_sym=(nspin_mag==4)
CALL prepare_sym_analysis(nsymq,sr,t_rev,magnetic_sym)
sym (1:nsym) = .TRUE.
CALL sgam_lr (at, bg, nsym, s, irt, tau, rtau, nat)
CALL find_mode_sym_new (u, w2, tau, nat, nsymq, s, sr, irt, xq, &
rtau, amass, ntyp, ityp, 1, .FALSE., .FALSE., num_rap_mode, ierr)
ENDIF
RETURN
END SUBROUTINE find_representations_mode_q