TABLE OF CONTENTS


ABINIT/m_ifc [ Modules ]

[ Top ] [ Modules ]

NAME

  m_ifc

FUNCTION

  This module contains the declaration of data types and methods
  used to handle interatomic force constant sets

COPYRIGHT

 Copyright (C) 2011-2024 ABINIT group (XG,MJV,EB,MG)
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .

SOURCE

17 #if defined HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "abi_common.h"
22 
23 MODULE m_ifc
24 
25  use defs_basis
26  use m_errors
27  use m_abicore
28  use m_xmpi
29  use m_sort
30  use m_cgtools
31  use m_nctk
32  use m_ddb
33  use m_ddb_hdr
34  use m_symkpt
35 #ifdef HAVE_NETCDF
36  use netcdf
37 #endif
38 
39  use m_io_tools,    only : open_file
40  use m_numeric_tools, only : arth
41  use m_fstrings,    only : ktoa, int2char4, sjoin, itoa, ltoa, ftoa
42  use m_symtk,       only : matr3inv
43  use m_special_funcs,  only : abi_derfc
44  use m_time,        only : cwtime, cwtime_report, timab
45  use m_copy,        only : alloc_copy
46  use m_pptools,     only : printbxsf
47  use m_lebedev,     only : lebedev_t, lebedev_ngrids
48  use m_ewald,       only : ewald9
49  use m_crystal,     only : crystal_t
50  use m_geometry,    only : phdispl_cart2red, normv, mkrdim
51  use m_kpts,        only : kpts_ibz_from_kptrlatt, smpbz
52  use m_dynmat,      only : canct9, dist9 , ifclo9, axial9, q0dy3_apply, q0dy3_calc, asrif9, dynmat_dq, &
53                            make_bigbox, canat9, chkrp9, ftifc_q2r, wght9, nanal9, gtdyn9, dymfz9, &
54                            massmult_and_breaksym, dfpt_phfrq, dfpt_prtph
55 
56  implicit none
57 
58  private

m_ifc/corsifc9 [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 corsifc9

FUNCTION

 Applies a cutoff on the ifc in real space

INPUTS

 acell(3)=length scales by which rprim is to be multiplied
 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)=canonical coordinates of the points in the BigBox.
 nsphere=number of atoms to be included in the cut-off sphere for interatomic
  force constant; if = 0 : maximum extent allowed by the grid.
 rifcsph=radius for cutoff of IFC
 wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector.

OUTPUT

 wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
  with the required cutoff applied.
 rcut_min=Effective cutoff. Defined by the minimum cutoff radius over the natom sites.

SOURCE

1548 subroutine corsifc9(acell,gprim,natom,nrpt,nsphere,rifcsph,rcan,rprim,rpt,rcut_min,wghatm)
1549 
1550 !Arguments -------------------------------
1551 !scalars
1552  integer,intent(in) :: natom,nrpt,nsphere
1553  real(dp),intent(in) :: rifcsph
1554  real(dp),intent(out) :: rcut_min
1555 !arrays
1556  real(dp),intent(in) :: acell(3)
1557  real(dp),intent(in) :: gprim(3,3),rcan(3,natom)
1558  real(dp),intent(in) :: rprim(3,3),rpt(3,nrpt)
1559  real(dp),intent(inout) :: wghatm(natom,natom,nrpt)
1560 
1561 !Local variables -------------------------
1562 !scalars
1563  integer :: ia,ib,ii,index,irpt
1564  real(dp) :: rmax,rsigma,r0
1565 !arrays
1566  integer,allocatable :: list(:)
1567  real(dp),allocatable :: dist(:,:,:),wkdist(:)
1568 
1569 ! *********************************************************************
1570 
1571  ! Compute the distances between atoms
1572  ! dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
1573  ABI_MALLOC(dist,(natom,natom,nrpt))
1574  call dist9(acell,dist,gprim,natom,nrpt,rcan,rprim,rpt)
1575 
1576  ABI_MALLOC(list,(natom*nrpt))
1577  ABI_MALLOC(wkdist,(natom*nrpt))
1578 
1579  ! loop on all generic atoms.
1580  rcut_min = huge(one)
1581  do ia=1,natom
1582 
1583    wkdist = reshape(dist(ia,:,:), [natom*nrpt])
1584    do ii=1,natom*nrpt
1585      list(ii)=ii
1586    end do
1587    ! This sorting algorithm is slow ...
1588    call sort_dp(natom*nrpt,wkdist,list,tol14)
1589    rmax = wkdist(natom*nrpt)
1590 
1591    ! zero the outside IFCs: act on wghatm
1592 
1593    ! fix number of spheres
1594    if(nsphere/=0.and.nsphere<natom*nrpt)then
1595      rcut_min = min(rcut_min, wkdist(nsphere+1))
1596      do ii=nsphere+1,natom*nrpt
1597        index=list(ii)
1598        irpt=(index-1)/natom+1
1599        ib=index-natom*(irpt-1)
1600        wghatm(ia,ib,irpt)=zero
1601      end do
1602    end if
1603 
1604    ! or fix radius of maximum ifc
1605    if(rifcsph>tol10)then
1606      do ii=nsphere+1,natom*nrpt
1607        index=list(ii)
1608        ! preserve weights for atoms inside sphere of radius rifcsph
1609        if (wkdist(ii) < rifcsph) cycle
1610        rcut_min = min(rcut_min, wkdist(ii))
1611        irpt=(index-1)/natom+1
1612        ib=index-natom*(irpt-1)
1613        wghatm(ia,ib,irpt)=zero
1614      end do
1615    end if
1616 
1617    ! filter smoothly to 0 at edge of WS cell
1618    if (rifcsph < -tol10) then
1619      ! Use different filter
1620      r0 = abs(rifcsph) * rmax; rsigma = half*(rmax-r0) !one
1621      rcut_min = r0 ! Set it to r0
1622      do ii=nsphere+1,natom*nrpt
1623        index=list(ii)
1624        irpt=(index-1)/natom+1
1625        ib=index-natom*(irpt-1)
1626        wghatm(ia,ib,irpt) = wghatm(ia,ib,irpt) * half * abi_derfc((wkdist(ii) - r0) / rsigma)
1627      end do
1628    end if
1629 
1630  end do
1631 
1632  ABI_FREE(dist)
1633  ABI_FREE(list)
1634  ABI_FREE(wkdist)
1635 
1636 end subroutine corsifc9

m_ifc/ifc_autocutoff [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_autocutoff

FUNCTION

 Find the value of nsphere that gives non-negative frequencies around Gamma
 in a small sphere of radius qrad.
 Use bisection to reduce the number of attemps although there's no guarantee
 that the number of negative frequencies is monotonic.

INPUTS

  crystal<crystal_t> = Information on the crystalline structure.
  comm=MPI communicator

SIDE EFFECTS

  ifc%wghatm(natom,natom,nrpt) = Weights associated to a pair of atoms and to a R vector
    with the last cutoff found by the bisection algorithm applied.
  ifc%atmfrc(2,3,natom,3,natom,nrpt)= ASR-imposed Interatomic Forces

SOURCE

1401 subroutine ifc_autocutoff(ifc, crystal, comm)
1402 
1403 !Arguments ------------------------------------
1404 !scalars
1405  class(ifc_type),intent(inout) :: ifc
1406  type(crystal_t),intent(in) :: crystal
1407  integer,intent(in) :: comm
1408 
1409 !Local variables-------------------------------
1410 !scalars
1411  integer,parameter :: master=0
1412  integer :: iq_ibz,ierr,my_rank,nprocs,ii,nsphere,num_negw,jl,ju,jm,natom,nrpt
1413  real(dp),parameter :: rifcsph0=zero
1414  real(dp) :: adiff,qrad,min_negw,xval,rcut_min
1415  type(lebedev_t) :: lgrid
1416 !arrays
1417  real(dp) :: displ_cart(2*3*ifc%natom*3*ifc%natom)
1418  real(dp) :: qred(3),qred_vers(3),phfrqs(3*ifc%natom) !,dwdq(3,3*ifc%natom)
1419  real(dp),allocatable :: ref_phfrq(:,:),cut_phfrq(:,:)
1420  real(dp),allocatable :: save_wghatm(:,:,:),save_atmfrc(:,:,:,:,:)
1421 
1422 ! *********************************************************************
1423 
1424  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
1425  natom = ifc%natom; nrpt = ifc%nrpt
1426 
1427  ! Compute frequencies on the ab-initio q-mesh without cutoff.
1428  ABI_CALLOC(ref_phfrq, (3*natom, ifc%nqibz))
1429  do iq_ibz=1,ifc%nqibz
1430    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
1431    call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), ref_phfrq(:,iq_ibz), displ_cart)
1432  end do
1433  call xmpi_sum(ref_phfrq, comm, ierr)
1434 
1435  ABI_MALLOC(save_wghatm, (natom,natom,nrpt))
1436  ABI_MALLOC(save_atmfrc, (3,natom,3,natom,ifc%nrpt))
1437  save_wghatm = ifc%wghatm; save_atmfrc = ifc%atmfrc
1438 
1439  ABI_MALLOC(cut_phfrq, (3*natom, ifc%nqibz))
1440  qrad = 0.01
1441  call lgrid%from_index(16)
1442 
1443  if (my_rank == master) then
1444    write(ab_out, "(a)")" Apply cutoff on IFCs. Using bisection algorithm to find initial guess for nsphere."
1445    write(ab_out, "(a,i0)")" Maximum nuber of atom-centered spheres: ",natom * nrpt
1446    write(ab_out, "(a,i0,a,f5.3)")" Using Lebedev-Laikov grid with npts: ",lgrid%npts, ", qrad: ",qrad
1447    write(ab_out, "(/,a)")" <adiff>: Average difference between ab-initio frequencies and frequencies with cutoff."
1448    write(ab_out, "(a)")" num_negw: Number of negative freqs detected in small sphere around Gamma."
1449    write(ab_out, "(a)")" min_negw: Min negative frequency on the small sphere."
1450    write(ab_out, "(a,/,/)")" rifcsph: Effective cutoff radius corresponding to nsphere."
1451    write(ab_out, "(a)")" nsphere   <adiff>[meV]   num_negw   min_negw[meV]   rifcsph"
1452  end if
1453 
1454  jl = 0; ju = natom * nrpt + 1 ! Initialize lower and upper limits.
1455  do
1456    if (ju - jl <= 1) then
1457      exit
1458    end if
1459    jm = (ju + jl) / 2  ! Compute a midpoint
1460    nsphere = jm
1461 
1462    ifc%wghatm = save_wghatm; ifc%atmfrc = save_atmfrc
1463    call corsifc9(ifc%acell,ifc%gprim, natom, nrpt,nsphere,rifcsph0,ifc%rcan,ifc%rprim,ifc%rpt,rcut_min,ifc%wghatm)
1464    if (ifc%asr > 0) call asrif9(ifc%asr,ifc%atmfrc,ifc%natom,ifc%nrpt,ifc%rpt,ifc%wghatm)
1465 
1466    cut_phfrq = zero
1467    do iq_ibz=1,ifc%nqibz
1468      if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
1469      call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), cut_phfrq(:,iq_ibz), displ_cart)
1470      !write(std_out,*)cut_phfrq(1,iq_ibz),ref_phfrq(1,iq_ibz)
1471    end do
1472    call xmpi_sum(cut_phfrq, comm, ierr)
1473 
1474    ! Test wether there are negative frequencies around gamma, including reciprocal lattice vectors.
1475    num_negw = 0; min_negw = zero
1476    do ii=1,lgrid%npts+3
1477      if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
1478      if (ii <= 3) then
1479        qred = zero; qred(ii) = one
1480      else
1481        qred = matmul(crystal%rprimd, lgrid%versors(:, ii-3))
1482      end if
1483      qred_vers = (qred / normv(qred, crystal%gmet, "G"))
1484      qred = qrad * qred_vers
1485      call ifc%fourq(crystal, qred, phfrqs, displ_cart) !, dwdq=dwdq)
1486      if (any(phfrqs < +tol8)) then
1487        num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs))
1488      end if
1489      !do jj=1,3
1490      !  xval = dot_product(dwdq(:,jj), matmul(crystal%gprimd, qred_vers))
1491      !  if (xval < zero) num_negw = num_negw + 1
1492      !end do
1493    end do
1494    call xmpi_sum(num_negw, comm, ierr)
1495    xval = min_negw; call xmpi_min(xval, min_negw, comm, ierr)
1496 
1497    adiff = sum(abs(cut_phfrq - ref_phfrq)) / (ifc%nqibz * 3 * natom)
1498    if (my_rank == master) then
1499      write(ab_out,"(a,i7,1x,es13.4,4x,i8,1x,es13.4,2x,es13.4)") &
1500        "-",nsphere, adiff * Ha_meV, num_negw, min_negw * Ha_meV, rcut_min
1501    end if
1502 
1503    if (num_negw == 0) then
1504      jl = jm ! Replace lower limit
1505    else
1506      ju = jm ! Replace upper limit
1507    end if
1508  end do
1509 
1510  ABI_FREE(ref_phfrq)
1511  ABI_FREE(cut_phfrq)
1512  ABI_FREE(save_wghatm)
1513  ABI_FREE(save_atmfrc)
1514  call lgrid%free()
1515 
1516 end subroutine ifc_autocutoff

m_ifc/ifc_calcnwrite_nana_terms [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_calcnwrite_nana_terms

FUNCTION

  Compute frequencies and phonon displacement for q-->0 in the presence of non-analytical behaviour.

INPUTS

  nph2l=Number of qpoints.
  qph2l(3,nph2l)=List of phonon wavevector directions along which the non-analytical correction
    to the Gamma-point phonon frequencies will be calculated
    The direction is in CARTESIAN COORDINATES
  qnrml2(nph2l)=Normalization factor.

OUTPUT

  (Optional)
  phfrq2l(3*crystal%natom,nph2l)=List of phonon frequencies
  polarity2l(3,3*crystal%natom,nph2l)=List of mode-polarities
     (see Eq.(41) of Veithen et al, PRB71, 125107 (2005) [[cite:Veithen2005]])

 NOTES:
  This routine should be called by master node and when ifcflag == 1.

SOURCE

2725 subroutine ifc_calcnwrite_nana_terms(ifc, crystal, nph2l, qph2l, &
2726                                      qnrml2, ncid, phfrq2l, polarity2l) ! optional arguments
2727 
2728 !Arguments ------------------------------------
2729  class(ifc_type),intent(in) :: ifc
2730  integer,intent(in) :: nph2l
2731  integer,optional,intent(in) :: ncid
2732  type(crystal_t),intent(in) :: crystal
2733 !arrays
2734  real(dp),intent(in) :: qph2l(3, nph2l)
2735  real(dp),optional,intent(in) :: qnrml2(nph2l)
2736  real(dp),optional,intent(out) :: phfrq2l(3*crystal%natom,nph2l), polarity2l(3,3*crystal%natom,nph2l)
2737 
2738 !Local variables-------------------------------
2739 !scalars
2740  integer :: iatom,idir,imode,iphl2
2741 #ifdef HAVE_NETCDF
2742  integer :: ncerr
2743 #endif
2744 !arrays
2745  real(dp) :: qphnrm(3),qphon(3,3)
2746  real(dp),allocatable :: displ_cart(:,:,:),phfrq(:),d2cart(:,:,:),eigvec(:,:,:),eigval(:)
2747 
2748 ! ************************************************************************
2749 
2750  if (nph2l == 0) return
2751 
2752  !Now treat the second list of vectors (only at the Gamma point, but can include non-analyticities)
2753  ABI_MALLOC(phfrq, (3*crystal%natom))
2754  ABI_MALLOC(displ_cart, (2, 3*crystal%natom, 3*crystal%natom))
2755  ABI_MALLOC(d2cart, (2, 3*ifc%mpert, 3*ifc%mpert))
2756  ABI_MALLOC(eigvec, (2, 3*crystal%natom, 3*crystal%natom))
2757  ABI_MALLOC(eigval, (3*crystal%natom))
2758 
2759  ! Before examining every direction or the dielectric tensor, generates the dynamical matrix at gamma
2760  qphon(:,1)=zero; qphnrm(1)=zero
2761 
2762  ! Generation of the dynamical matrix in cartesian coordinates
2763  ! Get d2cart using the interatomic forces and the
2764  ! long-range coulomb interaction through Ewald summation
2765  call gtdyn9(ifc%acell,ifc%atmfrc,ifc%dielt,ifc%dipdip, &
2766    ifc%dyewq0,d2cart,crystal%gmet,ifc%gprim,ifc%mpert,crystal%natom, &
2767    ifc%nrpt,qphnrm(1),qphon,crystal%rmet,ifc%rprim,ifc%rpt, &
2768    ifc%trans,crystal%ucvol,ifc%wghatm,crystal%xred,ifc%zeff,ifc%qdrp_cart,ifc%ewald_option,xmpi_comm_self)
2769 
2770 #ifdef HAVE_NETCDF
2771  if (present(ncid)) then
2772    iphl2 = 0
2773    call nctk_defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, "define")
2774    ! Add epsinf, Born effective charges and some useful metadata.
2775    ncerr = nctk_def_arrays(ncid, [ &
2776      nctkarr_t('emacro_cart', "dp", 'number_of_cartesian_directions, number_of_cartesian_directions'), &
2777      nctkarr_t('becs_cart', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, number_of_atoms")], &
2778      defmode=.True.)
2779    NCF_CHECK(ncerr)
2780    ! TODO chneut is missing
2781    ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
2782        "asr", "dipdip", "symdynmat"])
2783    NCF_CHECK(ncerr)
2784    NCF_CHECK(nctk_set_datamode(ncid))
2785    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'emacro_cart'), ifc%dielt))
2786    NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, 'becs_cart'), ifc%zeff))
2787    ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
2788      "asr", "dipdip", "symdynmat"], &
2789      [ifc%asr, ifc%dipdip, ifc%symdynmat])
2790    NCF_CHECK(ncerr)
2791  end if
2792 #endif
2793 
2794  ! Examine every wavevector of this list
2795  do iphl2=1,nph2l
2796    ! Initialisation of the phonon wavevector
2797    qphon(:,1) = qph2l(:,iphl2)
2798    qphnrm(1)=zero
2799    if(present(qnrml2)) qphnrm(1) = qnrml2(iphl2)
2800 
2801    ! Calculation of the eigenvectors and eigenvalues of the dynamical matrix
2802    call dfpt_phfrq(ifc%amu,displ_cart,d2cart,eigval,eigvec,crystal%indsym, &
2803       ifc%mpert,crystal%nsym,crystal%natom,crystal%nsym,crystal%ntypat,phfrq,qphnrm(1),qphon, &
2804       crystal%rprimd,ifc%symdynmat,crystal%symrel,crystal%symafm,crystal%typat,crystal%ucvol)
2805 
2806    ! Write the phonon frequencies
2807    !call dfpt_prtph(displ_cart,inp%eivec,inp%enunit,ab_out,natom,phfrq,qphnrm(1),qphon)
2808 
2809    if(present(phfrq2l)) phfrq2l(:,iphl2)=phfrq(:)
2810 
2811    if(present(polarity2l))then
2812      polarity2l(:,:,iphl2)=zero
2813      do imode=1,3*crystal%natom
2814        do iatom=1,crystal%natom
2815          do idir=1,3
2816            polarity2l(:,imode,iphl2)=polarity2l(:,imode,iphl2)+ifc%zeff(:,idir,iatom)*displ_cart(1,idir+(iatom-1)*3,imode)
2817          enddo
2818        enddo
2819      enddo
2820    endif
2821 
2822 #ifdef HAVE_NETCDF
2823    if(present(ncid))then
2824      ! Loop is not MPI-parallelized --> no need for MPI-IO API.
2825      call nctk_defwrite_nonana_terms(ncid, iphl2, nph2l, qph2l, crystal%natom, phfrq, displ_cart, "write")
2826    endif
2827 #endif
2828  end do ! iphl2
2829 
2830  ABI_FREE(phfrq)
2831  ABI_FREE(displ_cart)
2832  ABI_FREE(d2cart)
2833  ABI_FREE(eigvec)
2834  ABI_FREE(eigval)
2835 
2836 end subroutine ifc_calcnwrite_nana_terms

m_ifc/ifc_fourq [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_fourq

FUNCTION

  Compute the phonon frequencies and the group velocities at the specified q-point by performing
  a Fourier transform on the IFCs matrix in real space.

INPUTS

  Ifc<type(ifc_type)>=Object containing the dynamical matrix and the IFCs.
  Crystal<type(crystal_t)> = Information on the crystalline structure.
  qpt(3)=q-point in reduced coordinates (unless nanaqdir is specified)
  [nanaqdir]=If present, the qpt will be treated as a vector specifying the
    direction in q-space along which the non-analytic behaviour of the dynamical
    matrix will be treated. Possible values:
       "cart" if qpt defines a direction in Cartesian coordinates
       "reduced" if qpt defines a direction in reduced coordinates
  [comm]: MPI communicator

OUTPUT

  phfrq(3*natom) = Phonon frequencies in Hartree
  displ_cart(2,3,natom,3*natom) = Phonon displacement in Cartesian coordinates
  [out_d2cart(2,3,3*natom,3,3*natom)] = The (interpolated) dynamical matrix for this q-point
  [out_eigvec(2*3*natom*3*natom) = The (interpolated) eigenvectors of the dynamical matrix in Cartesian coords.
  [out_displ_red(2*3*natom*3*natom) = The (interpolated) displacement in reduced coordinates.
  [dwdq(3,3*natom)] = Group velocities i.e. d(omega(q))/dq in Cartesian coordinates.

SOURCE

 923 subroutine ifc_fourq(ifc, crystal, qpt, phfrq, displ_cart, &
 924                      nanaqdir, comm, &                              ! Optional [in]
 925                      out_d2cart, out_eigvec, out_displ_red, dwdq)   ! Optional [out]
 926 
 927 !Arguments ------------------------------------
 928 !scalars
 929  class(ifc_type),intent(in) :: Ifc
 930  character(len=*),optional,intent(in) :: nanaqdir
 931  type(crystal_t),intent(in) :: Crystal
 932  integer,optional,intent(in) :: comm
 933 !arrays
 934  real(dp),intent(in) :: qpt(3)
 935  real(dp),intent(out) :: displ_cart(2,3,Crystal%natom,3*Crystal%natom)
 936  real(dp),intent(out) :: phfrq(3*Crystal%natom)
 937  real(dp),optional,intent(out) :: out_d2cart(2,3,Crystal%natom,3,Crystal%natom)
 938  real(dp),optional,intent(out) :: out_eigvec(2,3,Crystal%natom,3*Crystal%natom)
 939  real(dp),optional,intent(out) :: out_displ_red(2,3,Crystal%natom,3*Crystal%natom)
 940  real(dp),optional,intent(out) :: dwdq(3,3*crystal%natom)
 941 
 942 !Local variables-------------------------------
 943 !scalars
 944  integer :: natom, comm_
 945  real(dp) :: qphnrm
 946 !arrays
 947  real(dp) :: my_qpt(3),eigvec(2,3,Crystal%natom,3*Crystal%natom),eigval(3*Crystal%natom)
 948  real(dp) :: d2cart(2,3,Ifc%mpert,3,Ifc%mpert),tsec(2)
 949 
 950 ! ************************************************************************
 951 
 952  ! Keep track of total time spent.
 953  call timab(1748, 1, tsec)
 954 
 955  natom = Crystal%natom
 956  ! TODO: Rewrite and Parallelize ewald9 in gtdyn9
 957  comm_ = xmpi_comm_self; if (present(comm)) comm_ = comm
 958 
 959  ! Use my_qpt because dfpt_phfrq can change the q-point (very bad design)
 960  qphnrm = one; my_qpt = qpt
 961 
 962  if (present(nanaqdir)) then
 963    ! This will break backward compatibility because qpt is **always** in reduced coordinates.
 964    ! while dfpt_phfrq assume cartesian coordinates !!!!!!!!!!!
 965    ! It does not make sense to change API just to treat this particular case
 966    ! We should **alwayse use q-points in reduced coordinates.
 967    qphnrm = zero
 968    select case (nanaqdir)
 969    case ("reduced")
 970      ! Convert to Cartesian.
 971      my_qpt = matmul(Crystal%gprimd, qpt)
 972    case ("cart")
 973      continue
 974    case default
 975      ABI_ERROR(sjoin("Wrong value for nanaqdir:", nanaqdir))
 976    end select
 977  end if
 978 
 979  ! The dynamical matrix d2cart is calculated here:
 980  call gtdyn9(Ifc%acell,Ifc%atmfrc,Ifc%dielt,Ifc%dipdip,Ifc%dyewq0,d2cart,Crystal%gmet,Ifc%gprim,Ifc%mpert,natom,&
 981    Ifc%nrpt,qphnrm,my_qpt,Crystal%rmet,Ifc%rprim,Ifc%rpt,Ifc%trans,Crystal%ucvol,Ifc%wghatm,Crystal%xred,Ifc%zeff,&
 982    Ifc%qdrp_cart,Ifc%ewald_option,comm_,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
 983 
 984  ! Calculate the eigenvectors and eigenvalues of the dynamical matrix
 985  call dfpt_phfrq(Ifc%amu,displ_cart,d2cart,eigval,eigvec,Crystal%indsym,&
 986    Ifc%mpert,Crystal%nsym,natom,Crystal%nsym,Crystal%ntypat,phfrq,qphnrm,my_qpt,&
 987    Crystal%rprimd,Ifc%symdynmat,Crystal%symrel,Crystal%symafm,Crystal%typat,Crystal%ucvol)
 988 
 989  ! OmegaSRLR: Perform decomposition of dynamical matrix
 990  !if (srlr==1) call omega_decomp(amu,natom,ntypat,typat,dynmatfull,dynmatsr,dynmatlr,iqpt,nqpt,eigvec)
 991 
 992  ! Return the interpolated dynamical matrix and the eigenvector for this q-point
 993  if (present(out_d2cart)) out_d2cart = d2cart(:,:,:natom,:,:natom)
 994  if (present(out_eigvec)) out_eigvec = eigvec
 995 
 996  ! Return phonon displacement in reduced coordinates.
 997  if (present(out_displ_red)) call phdispl_cart2red(natom, crystal%gprimd, displ_cart, out_displ_red)
 998 
 999  ! Option to get vectors in reduced coordinates?
1000  !call phdispl_cart2red(natom, crystal%gprimd, out_eigvec, out_eigvec_red)
1001 
1002  ! Compute group velocities.
1003  if (present(dwdq)) call ifc%get_dwdq(crystal, my_qpt, phfrq, eigvec, dwdq, comm_)
1004 
1005  call timab(1748, 2, tsec)
1006 
1007 end subroutine ifc_fourq

m_ifc/ifc_free [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_free

FUNCTION

  Deallocate memory for the ifc_type structure

SOURCE

261 subroutine ifc_free(ifc)
262 
263 !Arguments ------------------------------------
264  class(ifc_type),intent(inout) :: ifc
265 
266 ! ************************************************************************
267 
268  ABI_SFREE(ifc%amu)
269  ABI_SFREE(ifc%atmfrc)
270  ABI_SFREE(ifc%cell)
271  ABI_SFREE(ifc%ewald_atmfrc)
272  ABI_SFREE(ifc%short_atmfrc)
273  ABI_SFREE(ifc%qshft)
274  ABI_SFREE(ifc%rpt)
275  ABI_SFREE(ifc%wghatm)
276  ABI_SFREE(ifc%rcan)
277  ABI_SFREE(ifc%trans)
278  ABI_SFREE(ifc%dyewq0)
279  ABI_SFREE(ifc%qibz)
280  ABI_SFREE(ifc%wtq)
281  ABI_SFREE(ifc%qbz)
282  ABI_SFREE(ifc%zeff)
283  ABI_SFREE(ifc%qdrp_cart)
284  ABI_SFREE(ifc%dynmat)
285  !ABI_SFREE(ifc%dynmat_lr)
286 
287 end subroutine ifc_free

m_ifc/ifc_from_file [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_from_file

FUNCTION

  Need to be updated

INPUTS

OUTPUT

SOURCE

742 subroutine ifc_from_file(ifc, dielt,filename,natom,ngqpt,nqshift,qshift,ucell_ddb,zeff,qdrp_cart,comm)
743 
744 !Arguments ------------------------------------
745 !scalars
746  class(ifc_type),intent(out) :: Ifc
747  integer,intent(in) :: nqshift,comm
748  integer,intent(inout) :: natom
749 !arrays
750  integer,intent(in) :: ngqpt(3)
751  real(dp),intent(in) :: qshift(3,nqshift)
752  character(len=*),intent(in) :: filename
753  real(dp),intent(inout) :: dielt(3,3)
754  real(dp),allocatable,intent(inout) :: zeff(:,:,:)
755  real(dp),allocatable,intent(inout) :: qdrp_cart(:,:,:,:)
756  type(crystal_t),intent(out) :: ucell_ddb
757 
758 !Local variables -------------------------
759 !scalars
760  integer :: dipdip,i,iblok,iblok_tmp
761  logical :: file_exists
762  character(len=500) :: msg
763  type(ddb_type) :: ddb
764  type(ddb_hdr_type) :: ddb_hdr
765 
766 !******************************************************************
767 
768  !check if ddb file exists
769  inquire(file=filename, exist=file_exists)
770 
771  if (file_exists .eqv. .true.)then
772 
773    !Reading the ddb
774    call ddb%from_file(filename, ddb_hdr, ucell_ddb, comm)
775    call ddb_hdr%free()
776 
777    natom = ddb%natom
778 
779  else
780    ABI_ERROR(sjoin("File:", filename, "is not present in the directory"))
781  end if
782 
783  ! Get Dielectric Tensor and Effective Charges
784  ! (initialized to one_3D and zero if the derivatives are not available in the DDB file)
785  ABI_MALLOC(zeff,(3,3,natom))
786  iblok = ddb%get_dielt_zeff(ucell_ddb,1,1,0,dielt,zeff)
787 
788  ! Try to get dielt, in case just the DDE are present
789  if (iblok == 0) then
790    iblok_tmp = ddb%get_dielt(1,dielt)
791  end if
792 
793  ABI_MALLOC(qdrp_cart,(3,3,3,natom))
794  iblok = ddb%get_quadrupoles(ddb_hdr%ddb_version,1,3,qdrp_cart)
795 
796  ! ifc to be calculated for interpolation
797  write(msg, '(a,a,(80a),a,a,a,a)' ) ch10,('=',i=1,80),ch10,ch10,' Calculation of the interatomic forces ',ch10
798  call wrtout(std_out,msg,'COLL')
799  call wrtout(ab_out,msg,'COLL')
800  if ((maxval(abs(zeff)) .lt. tol10) .OR. (maxval(dielt) .gt. 100000.0)) then
801    dipdip=0
802  else
803    dipdip=1
804  end if
805  call ifc%init(ucell_ddb,ddb,1,1,1,dipdip,1,ngqpt,nqshift,qshift,dielt,zeff,qdrp_cart,0,0.0_dp,0,1,comm)
806 
807  ! Free them all
808  call ddb%free()
809 
810 end subroutine ifc_from_file

m_ifc/ifc_get_dwdq [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_get_dwdq

FUNCTION

  Compute phonon group velocities at an arbitrary q-point.

INPUTS

  ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
  crystal<crystal_t> = Information on the crystalline structure.
  qpt(3)=q-point in reduced coordinates.
  eigvec(2*3*natom*3*natom) = The eigenvectors of the dynamical matrix.
  comm: MPI communicator

OUTPUT

  dwdq(3,3*natom) = Group velocities e.g. d(omega(q))/dq in Cartesian coordinates.

NOTES

  Using:

    D(q) u(q,nu) = w(q, nu)**2 and <u(q,nu) | u(q,nu')> = \delta_{nu, nu'}

  one can show, using the Hellman-Feynman theorem, that:

    \nabla_q w(q, nu) = 1/(2 w(q, nu))  <u(q, nu)| \nabla_q D(q) | u(q, nu)>

SOURCE

1038 subroutine ifc_get_dwdq(ifc, cryst, qpt, phfrq, eigvec, dwdq, comm)
1039 
1040 !Arguments ------------------------------------
1041 !scalars
1042  class(ifc_type),intent(in) :: ifc
1043  type(crystal_t),intent(in) :: cryst
1044  integer,intent(in) :: comm
1045 !arrays
1046  real(dp),intent(in) :: qpt(3)
1047  real(dp),intent(in) :: phfrq(3*cryst%natom)
1048  real(dp),intent(in) :: eigvec(2,3*cryst%natom,3*cryst%natom)
1049  real(dp),intent(out) :: dwdq(3,3*cryst%natom)
1050 
1051 !Local variables-------------------------------
1052 !scalars
1053  !integer,save :: enough=0
1054  integer,parameter :: nqpt1=1,option2=2,sumg0=0
1055  integer :: ii,nu,natom3,jj
1056  real(dp) :: hh
1057 !arrays
1058  real(dp) :: dddq(2,3*cryst%natom,3*cryst%natom,3),dot(2),qfd(3)
1059  real(dp) :: omat(2,3*cryst%natom,3*cryst%natom)
1060  real(dp) :: dyew(2,3*cryst%natom,3*cryst%natom)
1061 
1062 ! ************************************************************************
1063 
1064  ABI_UNUSED((/comm/))
1065 
1066  natom3 = cryst%natom * 3
1067 
1068  ! Generate the analytical part from the interatomic forces
1069  call dynmat_dq(qpt, cryst%natom, ifc%gprim, ifc%nrpt, ifc%rpt, ifc%atmfrc, ifc%wghatm, dddq)
1070 
1071  ! The analytical dynamical matrix dq has been generated
1072  ! in the normalized canonical coordinate system. Now, the
1073  ! phase is modified, in order to recover the usual (xred) coordinate of atoms.
1074  do ii=1,3
1075    call dymfz9(dddq(:,:,:,ii), cryst%natom, nqpt1, ifc%gprim, option2, qpt, ifc%trans)
1076    dddq(:,:,:,ii) = dddq(:,:,:,ii) * ifc%acell(ii)
1077  end do
1078 
1079  if (ifc%dipdip == 1.or.ifc%dipquad == 1.or.ifc%quadquad == 1) then
1080    ! Add the gradient of the non-analytical part.
1081    ! Note that dddq is in cartesian cordinates.
1082    ! For the time being, the gradient is computed with finite difference and step hh.
1083    ! TODO: should generalize ewald9 to compute dq.
1084    !enough = enough + 1
1085    !if (enough <= 5)  ABI_WARNING("phonon velocities with dipdip==1 not yet tested.")
1086    hh = 0.01_dp
1087    do ii=1,3
1088      do jj=-1,1,2
1089        ! qcart --> qred
1090        qfd = zero; qfd(ii) = jj
1091        qfd = matmul(cryst%rprimd, qfd); qfd = qfd / normv(qfd, cryst%gmet, "G")
1092        !write(std_out,*)"normv:",normv(qfd, cryst%gmet, "G")
1093        qfd = qpt + hh * qfd
1094 
1095        call ewald9(ifc%acell,ifc%dielt,dyew,cryst%gmet,ifc%gprim,cryst%natom,qfd,&
1096           cryst%rmet,ifc%rprim,sumg0,cryst%ucvol,cryst%xred,ifc%zeff,ifc%qdrp_cart,&
1097           ifc%ewald_option,dipquad=ifc%dipquad,quadquad=ifc%quadquad)
1098        call q0dy3_apply(cryst%natom,ifc%dyewq0,dyew)
1099        dddq(:,:,:,ii) = dddq(:,:,:,ii) + (jj * half / hh) * dyew
1100      end do
1101    end do
1102  end if
1103 
1104  do ii=1,3
1105    call massmult_and_breaksym(cryst%natom, cryst%ntypat, cryst%typat, ifc%amu, dddq(:,:,:,ii))
1106  end do
1107 
1108  ! Compute 1/(2w(q)) <u(q)|dD(q)/dq|u(q)>
1109  do ii=1,3
1110    call zgemm('N','N',natom3,natom3,natom3,cone,dddq(:,:,:,ii),natom3,eigvec,natom3,czero,omat,natom3)
1111    do nu=1,natom3
1112      if (abs(phfrq(nu)) > tol12) then
1113        dot = cg_zdotc(natom3, eigvec(1,1,nu), omat(1,1,nu))
1114        ! abs(w) is needed to get the correct derivative if we have a purely imaginary solution.
1115        dwdq(ii, nu) = dot(1) / (two * abs(phfrq(nu)))
1116      else
1117        dwdq(ii, nu) = zero
1118      end if
1119    end do
1120  end do
1121 
1122 end subroutine ifc_get_dwdq

m_ifc/ifc_get_phmesh [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_get_phmesh

FUNCTION

  Build linear mesh for phonons.

INPUTS

OUTPUT

SOURCE

1140 subroutine ifc_get_phmesh(ifc, ph_wstep, phmesh_size, phmesh)
1141 
1142 !Arguments ------------------------------------
1143 !scalars
1144  class(ifc_type),intent(in) :: ifc
1145  real(dp),intent(in) :: ph_wstep
1146  integer,intent(out) :: phmesh_size
1147 !arrays
1148  real(dp),allocatable,intent(out) :: phmesh(:)
1149 
1150 !******************************************************************
1151 
1152  phmesh_size = nint((ifc%omega_minmax(2) - ifc%omega_minmax(1) ) / ph_wstep) + 1
1153  ABI_MALLOC(phmesh, (phmesh_size))
1154  phmesh = arth(ifc%omega_minmax(1), ph_wstep, phmesh_size)
1155 
1156 end subroutine ifc_get_phmesh

m_ifc/ifc_getiaf [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_getiaf

FUNCTION

 Extracts the IFCs needed for the output for one atom in the
 unit cell. Accumulates the results for writing in the NetCDF file.
 Prints to the output file

INPUTS

 Ifc<type(ifc_type)>=Object containing the dynamical matrix and the IFCs.
 ifcana= 0 => no analysis of ifc ; 1 => full analysis
 ifcout= Number of interatomic force constants written in the output file
 iout=unit number for nice output
 zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
 ia=index of the atom in the unit cell for which the IFCs are being analyzed
 ra(3)=position of atom ia in cartesian coordinates
 list(ifcout)=index of permutation for distances from atom ia in ascending order
 dist(natom,natom,nrpt)=distance from atom ia to atom ib in unit cell irpt.
 invdlt(3,3)=inverse (transpose) of the dielectric tensor
 detdlt=determinant of the dielectric tensor

OUTPUT

 rsiaf(3,3,ifcout)=list of real space IFCs
 sriaf(3,3,ifcout)=list of the short range part of the real space IFCs
 vect(3,3,ifcout)=base vectors for local coordinates (longitudinal/transverse), if ifc_getiaf is able to find
   a third atom not aligned with the two atoms characterizing the IFC. If no, the second and third vectors are set to zero.
 indngb(ifcout)=indices in the unit cell of the neighbouring atoms
 posngb(3,ifcout)=position of the neighbouring atoms in cartesian coordinates
 output file

NOTES

 This routine should be executed by one processor only

SOURCE

2031 subroutine ifc_getiaf(Ifc,ifcana,ifcout,iout,zeff,ia,ra,list,&
2032 & dist,invdlt,detdlt,rsiaf,sriaf,vect,indngb,posngb)
2033 
2034 !Arguments -------------------------------
2035 !scalars
2036  class(ifc_type),intent(inout) :: Ifc
2037  integer,intent(in) :: ia,ifcana,ifcout,iout
2038  real(dp), intent(in) :: detdlt
2039 !arrays
2040  real(dp),intent(in) :: invdlt(3,3),ra(3)
2041  real(dp),intent(in) :: dist(Ifc%natom,Ifc%natom,Ifc%nrpt)
2042  real(dp),intent(in) :: zeff(3,3,Ifc%natom)
2043  integer,intent(in) :: list(Ifc%natom*Ifc%nrpt)
2044  integer,intent(out) :: indngb(ifcout)
2045  real(dp),intent(out) :: rsiaf(3,3,ifcout),sriaf(3,3,ifcout),vect(3,3,ifcout),posngb(3,ifcout)
2046 
2047 !Local variables -------------------------
2048 !scalars
2049  integer :: flag,ib,ii,index,jj,kk,mu,nu,irpt
2050  real(dp) :: ew1,rsq,scprod,trace1,trace2,trace3
2051  real(dp) :: yy,dist1
2052  character(len=500) :: message
2053 !arrays
2054  real(dp) :: ewiaf0(3,3),ewiaf1(3,3),ewloc(3,3),ifcloc(3,3)
2055  real(dp) :: rcart(3),rdiff(3),rsloc(3,3)
2056  real(dp) :: srloc(3,3),vect1(3),vect2(3),vect3(3),work(3),xx(3)
2057 
2058 ! *********************************************************************
2059 
2060  if(ifcana==1)then
2061    ! Generate the local coordinate system for the atom ia
2062    index=list(2)
2063    write(std_out,*)index
2064    call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
2065    vect2(1)=rcart(1)-ra(1)
2066    vect2(2)=rcart(2)-ra(2)
2067    vect2(3)=rcart(3)-ra(3)
2068    flag=0
2069    do ii=3,Ifc%natom*Ifc%nrpt
2070      index=list(ii)
2071      call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,rcart,Ifc%rprim,Ifc%rpt)
2072      vect1(1)=(rcart(1)-ra(1))-vect2(1)
2073      vect1(2)=(rcart(2)-ra(2))-vect2(2)
2074      vect1(3)=(rcart(3)-ra(3))-vect2(3)
2075      scprod=0.0_dp
2076      do jj=1,3
2077        scprod=scprod+vect1(jj)**2
2078      end do
2079      do jj=1,3
2080        vect1(jj)=vect1(jj)/scprod**0.5
2081      end do
2082      scprod=0.0_dp
2083      do jj=1,3
2084        scprod=scprod+vect2(jj)*vect1(jj)
2085      end do
2086      do jj=1,3
2087        work(jj)=vect2(jj)-vect1(jj)*scprod
2088      end do
2089      scprod=0.0_dp
2090      do jj=1,3
2091        scprod=scprod+work(jj)**2
2092      end do
2093      if(scprod>1.0d-10)then
2094        flag=1
2095      end if
2096      if(flag==1)exit
2097    end do
2098    if(flag==0)then
2099      write(message, '(3a)' )&
2100 &     'Unable to find a third atom not aligned with the two selected ones.',ch10,&
2101 &     'The local analysis (longitudinal/transverse) will not be done. The two transverse vectors are set to zero.'
2102      ABI_WARNING(message)
2103      vect2(:)=zero ; vect3(:)=zero
2104    else
2105      vect2(1)=work(1)/scprod**0.5
2106      vect2(2)=work(2)/scprod**0.5
2107      vect2(3)=work(3)/scprod**0.5
2108      vect3(1)=vect1(2)*vect2(3)-vect1(3)*vect2(2)
2109      vect3(2)=vect1(3)*vect2(1)-vect1(1)*vect2(3)
2110      vect3(3)=vect1(1)*vect2(2)-vect1(2)*vect2(1)
2111      if (iout > 0) then
2112        write(iout, '(a)' )' Third atom defining local coordinates : '
2113        write(iout, '(a,i4,a,i4)' )'     ib = ',ib,'   irpt = ',irpt
2114      end if
2115    endif
2116  end if
2117 
2118  ! Analysis and output of force constants, ordered with respect to the distance from atom ia
2119  do ii=1,ifcout
2120    index=list(ii)
2121    call canct9(Ifc%acell,Ifc%gprim,ib,index,irpt,Ifc%natom,Ifc%nrpt,Ifc%rcan,posngb(:,ii),Ifc%rprim,Ifc%rpt)
2122    indngb(ii)=ib
2123    dist1=dist(ia,ib,irpt)
2124    if (iout > 0) then
2125      write(iout, '(a)' )
2126      write(iout, '(i4,a,i6,a,i8)' )ii,' interaction with atom',ib,' cell',irpt
2127      write(iout, '(a,3es16.6)' )' with coordinates ',posngb(1:3,ii)*(one+tol8)
2128      write(iout, '(a,es16.6)' )' and distance ',dist1
2129    end if
2130 
2131    if(ifcana==1.and.ii/=1)then
2132      vect1(1)=(posngb(1,ii)-ra(1))/dist1
2133      vect1(2)=(posngb(2,ii)-ra(2))/dist1
2134      vect1(3)=(posngb(3,ii)-ra(3))/dist1
2135    end if
2136 
2137    if(Ifc%dipdip==0.or.Ifc%dipquad==1.or.Ifc%quadquad==1)then
2138      ! Get the "total" force constants (=real space FC)
2139      ! without taking into account the dipole-dipole interaction
2140      do mu=1,3
2141        do nu=1,3
2142          rsiaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt) * Ifc%wghatm(ia,ib,irpt)
2143        end do
2144      end do
2145      ! Output of the ifcs in cartesian coordinates
2146      if (iout > 0) then
2147        do nu=1,3
2148          write(iout, '(1x,3f9.5)' )(rsiaf(mu,nu,ii)+tol10,mu=1,3)
2149 !       transfer short range and long range
2150          do mu=1,3
2151            Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = rsiaf(mu,nu,ii) + tol10
2152          end do
2153 
2154        end do
2155      end if
2156 
2157      if(ifcana==1)then
2158        ! Further analysis
2159        trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
2160        if (iout > 0) then
2161          write(iout, '(a,f9.5)' ) '  Trace         ',trace1+tol10
2162        end if
2163        if(flag==1)then
2164          if(ii/=1)then
2165            call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
2166          end if
2167          if (iout > 0) then
2168            write(iout, '(a)' )' Transformation to local coordinates '
2169            write(iout, '(a,3f16.6)' ) ' First  local vector :',vect1
2170            write(iout, '(a,3f16.6)' ) ' Second local vector :',vect2
2171            write(iout, '(a,3f16.6)' ) ' Third  local vector :',vect3
2172          end if
2173          call ifclo9(rsiaf(:,:,ii),ifcloc,vect1,vect2,vect3)
2174          if (iout > 0) then
2175            do nu=1,3
2176              write(iout, '(1x,3f9.5)' )(ifcloc(mu,nu)+tol10,mu=1,3)
2177            end do
2178          end if
2179        endif ! flag==1
2180 
2181        vect(:,1,ii) = vect1
2182        vect(:,2,ii) = vect2
2183        vect(:,3,ii) = vect3
2184 
2185      end if ! Further analysis finished
2186 
2187    else if(Ifc%dipdip==1)then
2188 
2189      !write(iout,'(a)')
2190      !write(iout,'(a)')' Enter dipdip section, for debugging'
2191      !write(iout,'(a)')
2192 
2193      ! Get the Coulomb part
2194      do jj=1,3
2195        rdiff(jj)=ra(jj)-posngb(jj,ii)
2196      end do
2197      rsq=0.0_dp
2198      xx(1:3)=0.0_dp
2199      do jj=1,3
2200        do kk=1,3
2201          ewiaf0(jj,kk)=0.0_dp
2202          rsq=rsq+rdiff(jj)*invdlt(kk,jj)*rdiff(kk)
2203          xx(kk)=xx(kk)+invdlt(kk,jj)*rdiff(jj)
2204        end do
2205      end do
2206      yy=sqrt(rsq)
2207      !  Avoid zero denominators in term:
2208      if (sqrt(rsq)>=tol12) then
2209        do mu=1,3
2210          do nu=1,3
2211            ewiaf0(mu,nu)=(-3*xx(nu)*xx(mu)+invdlt(nu,mu)*yy**2)/yy**5/sqrt(detdlt)
2212          end do
2213        end do
2214      else
2215        if (ia/=ib)then
2216          write(message, '(a,a,a,a,a,i5,a,i5,a)' )&
2217 &         'The distance between two atoms vanishes.',ch10,&
2218 &         'This is not allowed.',ch10,&
2219 &         'Action: check the input for the atoms number',ia,' and',ib,'.'
2220          ABI_ERROR(message)
2221        end if
2222      end if
2223 
2224      ! Take into account the effective charge tensor
2225      do mu=1,3
2226        do nu=1,3
2227          ew1=zero
2228          if(ii==1)then
2229            ew1=-Ifc%dyewq0(mu,nu,ia)
2230          end if
2231          do jj=1,3
2232            do kk=1,3
2233              ew1=ew1+zeff(jj,mu,ia)*(zeff(kk,nu,ib)* ewiaf0(jj,kk))
2234            end do
2235          end do
2236          ewiaf1(mu,nu)=ew1
2237        end do
2238      end do
2239      ! Get the short-range force constants and the
2240      ! "total" force constants (=real space FC)
2241      do mu=1,3
2242        do nu=1,3
2243          sriaf(mu,nu,ii)=Ifc%atmfrc(mu,ia,nu,ib,irpt)* Ifc%wghatm(ia,ib,irpt)
2244          rsiaf(mu,nu,ii)=ewiaf1(mu,nu)+sriaf(mu,nu,ii)
2245        end do
2246      end do
2247 
2248      ! Output of the results
2249      if (iout > 0) then
2250        do nu=1,3
2251          write(iout, '(1x,3(3f9.5,1x))' )&
2252 &         (rsiaf(mu,nu,ii) +tol10,mu=1,3),&
2253 &         (ewiaf1(mu,nu)+tol10,mu=1,3),&
2254 &         (sriaf(mu,nu,ii) +tol10,mu=1,3)
2255 
2256 !       transfer short range and long range
2257          do mu=1,3
2258            Ifc%short_atmfrc(mu,ia,nu,ib,irpt) = sriaf(mu,nu,ii) + tol10
2259            Ifc%ewald_atmfrc(mu,ia,nu,ib,irpt) = ewiaf1(mu,nu) + tol10
2260          end do
2261        end do
2262      end if
2263 
2264      if(ifcana==1)then
2265        ! Further analysis
2266        if (iout > 0) then
2267          write(iout, '(a)' )' Traces (and ratios) :'
2268        end if
2269        trace1=rsiaf(1,1,ii)+rsiaf(2,2,ii)+rsiaf(3,3,ii)
2270        trace2=ewiaf1(1,1)+ewiaf1(2,2)+ewiaf1(3,3)
2271        trace3=sriaf(1,1,ii)+sriaf(2,2,ii)+sriaf(3,3,ii)
2272        if (iout > 0) then
2273          write(iout,'(3(f9.5,17x))')trace1+tol10,trace2+tol10,trace3+tol10
2274          write(iout,'(3(f9.5,17x))')1.0,(trace2+tol10)/(trace1+tol10),(trace3+tol10)/(trace1+tol10) !
2275        end if
2276 
2277        if(flag==1)then
2278          if(ii/=1)then
2279            call axial9(rsiaf(:,:,ii),vect1,vect2,vect3)
2280          end if
2281          if (iout > 0) then
2282            write(iout, '(a)' )' Transformation to local coordinates '
2283            write(iout, '(a,3f16.6)' )' First  local vector :',vect1
2284            write(iout, '(a,3f16.6)' )' Second local vector :',vect2
2285            write(iout, '(a,3f16.6)' )' Third  local vector :',vect3
2286          end if
2287          call ifclo9(rsiaf(:,:,ii),rsloc,vect1,vect2,vect3)
2288          call ifclo9(ewiaf1,ewloc,vect1,vect2,vect3)
2289          call ifclo9(sriaf(:,:,ii),srloc,vect1,vect2,vect3)
2290          if (iout > 0) then
2291            do nu=1,3
2292              write(iout, '(1x,3(3f9.5,1x))' )&
2293 &             (rsloc(mu,nu)+tol10,mu=1,3),&
2294 &             (ewloc(mu,nu)+tol10,mu=1,3),&
2295 &             (srloc(mu,nu)+tol10,mu=1,3)
2296            end do
2297            if(ii/=1)then
2298              write(iout, '(a)' )' Ratio with respect to the longitudinal ifc'
2299            else
2300              write(iout, '(a)' )' Ratio with respect to the (1,1) element'
2301            end if
2302            do nu=1,3
2303              write(iout, '(1x,3(3f9.5,1x))' )&
2304 &             (rsloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
2305 &             (ewloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3),&
2306 &             (srloc(mu,nu)/rsloc(1,1)+tol10,mu=1,3)
2307            end do
2308          end if
2309        endif ! flag==1
2310 
2311        vect(:,1,ii) = vect1
2312        vect(:,2,ii) = vect2
2313        vect(:,3,ii) = vect3
2314 
2315      end if ! Further analysis finished
2316    end if ! End the condition on dipdip
2317  end do ! End loop over all atoms in BigBox:
2318 
2319 end subroutine ifc_getiaf

m_ifc/ifc_init [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_init

FUNCTION

  Initialize the dynamical matrix as well as the IFCs.
  taking into account the dipole-dipole, dipole-quadrupole and quadrupole-quadrupole
  interaction.

INPUTS

 crystal<type(crystal_t)> = Information on the crystalline structure.
 ddb<type(ddb_type)> = Database with derivatives.
 brav=bravais lattice (1 or -1=simple lattice, 2=face centered lattice, 3=centered lattice, 4=hexagonal lattice)
 asr= Option for the imposition of the ASR
   0 => no ASR,
   1 => modify "asymmetrically" the diagonal element
   2 => modify "symmetrically" the diagonal element
 symdynmat=if 1, (re)symmetrize the dynamical matrix, except if Gamma wavevector with electric field added.
 dipdip=
   if 0, no dipole-dipole interaction was subtracted in atmfrc
   if 1, atmfrc has been build without dipole-dipole part
 rfmeth =
   1 if non-stationary block
   2 if stationary block
   3 if third order derivatives
 dielt(3,3)=dielectric tensor.
 zeff(3,3,natom)=effective charge on each atom, versus electric field and atomic displacement
 prtsrlr: TODO: TO BE REMOVED
 enunit: TODO: TO BE REMOVED
 dielt(3,3)=dielectric tensor
 ngqpt_in = input values of ngqpt
 nqshft=Number of shifths in q-grid.
 q1shft(3,nqshft)=Shifts for q-grid
 nsphere=number of atoms to be included in the cut-off sphere for interatomic force constant.
    0: maximum extent allowed by the grid.
  > 0: Apply cutoff
   -1: Analyze the effect of different nsphere values on the phonon spectrum, in particular the
       frequencies around gamma.
 rifcsph=radius for cutoff of IFC.
 comm=MPI communicator.
 [Ifc_coarse]=Optional.
 [dipquad] = if 1, atmfrc has been build without dipole-quadrupole part
 [quadquad] = if 1, atmfrc has been build without quadrupole-quadrupole part

OUTPUT

 Ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.

SOURCE

341 subroutine ifc_init(ifc,crystal,ddb,brav,asr,symdynmat,dipdip,&
342   rfmeth,ngqpt_in,nqshft,q1shft,dielt,zeff,qdrp_cart,nsphere,rifcsph,&
343   prtsrlr,enunit, & ! TODO: TO BE REMOVED
344   comm, &
345   Ifc_coarse,dipquad,quadquad) ! Optional
346 
347 !Arguments ------------------------------------
348  class(ifc_type),intent(inout) :: Ifc
349  integer,intent(in) :: asr,brav,dipdip,symdynmat,nqshft,rfmeth,nsphere,comm
350  real(dp),intent(in) :: rifcsph
351  type(crystal_t),intent(in) :: Crystal
352  type(ddb_type),intent(in) :: ddb
353  type(ifc_type),optional,intent(in) :: Ifc_coarse
354  integer,optional,intent(in) :: dipquad, quadquad
355 
356 !arrays
357  integer,intent(in) :: ngqpt_in(3)
358  real(dp),intent(in) :: q1shft(3,nqshft)
359  real(dp),intent(in) :: dielt(3,3),zeff(3,3,Crystal%natom)
360  real(dp),intent(in) :: qdrp_cart(3,3,3,Crystal%natom)
361 !anaddb variables (TO BE REMOVED)
362  integer,intent(in) :: prtsrlr,enunit
363 !end anaddb variables
364 
365 !Local variables -------------------------
366 !scalars
367  integer,parameter :: timrev1=1,iout0=0,chksymbreak0=0
368  integer :: mpert,iout,iqpt,mqpt,nsym,ntypat,iq_ibz,iq_bz,ii,natom
369  integer :: nqbz,option,plus,sumg0,irpt,irpt_new
370  integer :: nprocs,my_rank,my_ierr,ierr
371  real(dp),parameter :: qphnrm=one
372  real(dp) :: xval,cpu,wall,gflops,rcut_min
373  real(dp) :: r_inscribed_sphere,toldist
374  character(len=500*4) :: msg
375  type(ifc_type) :: ifc_tmp
376 !arrays
377  integer :: ngqpt(9),qptrlatt(3,3)
378  integer,allocatable :: qmissing(:),ibz2bz(:),bz2ibz_smap(:,:)
379  real(dp) :: gprim(3,3),rprim(3,3),qpt(3),rprimd(3,3), gprim_tmp(3,3), rprim_tmp(3,3)
380  real(dp):: rcan(3,Crystal%natom),trans(3,Crystal%natom),dyewq0(3,3,Crystal%natom)
381  real(dp) :: displ_cart(2*3*Crystal%natom*3*Crystal%natom)
382  real(dp) :: phfrq(3*Crystal%natom)
383  real(dp) :: eigvec(2,3,Crystal%natom,3,Crystal%natom)
384  real(dp),allocatable :: dyew(:,:,:,:,:),out_d2cart(:,:,:,:,:)
385  real(dp),allocatable :: dynmatfull(:,:,:,:,:,:),dynmat_sr(:,:,:,:,:,:),dynmat_lr(:,:,:,:,:,:) ! for OmegaSRLR
386  real(dp),allocatable :: wtq(:),wtq_folded(:),qbz(:,:)
387 
388 !******************************************************************
389 
390  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
391  call cwtime(cpu, wall, gflops, "start")
392 
393  mpert = ddb%mpert
394  iout = ab_out
395 
396  rprim = ddb%rprim; gprim = ddb%gprim
397 
398  nsym = Crystal%nsym
399  natom = Crystal%natom
400  ntypat = Crystal%ntypat
401  rprimd = Crystal%rprimd
402 
403  ngqpt=0; ngqpt(1:3)=ngqpt_in(1:3)
404 
405 ! Copy important parameters in Ifc
406  Ifc%natom = natom
407  Ifc%mpert = mpert
408  Ifc%asr = asr
409  Ifc%brav = brav
410  Ifc%dipdip = abs(dipdip)
411  Ifc%dipquad=0; if (present(dipquad)) Ifc%dipquad = dipquad
412  Ifc%quadquad=0; if (present(quadquad)) Ifc%quadquad = quadquad
413  Ifc%symdynmat = symdynmat
414  Ifc%nqshft = nqshft
415  call alloc_copy(q1shft(:,1:Ifc%nqshft),Ifc%qshft)
416  Ifc%ngqpt = ngqpt_in(1:3)
417  Ifc%rprim = ddb%rprim
418  Ifc%gprim = ddb%gprim
419  Ifc%acell = ddb%acell
420  Ifc%ewald_option = 0; if (dipdip < 0) Ifc%ewald_option = 1 !HM TODO: expose this in the init?
421 
422  ! Check if the rprim are coherent with the choice used in the interatomic forces generation
423  call chkrp9(Ifc%brav,rprim)
424 
425  ! Compute dyewq0, the correction to be applied to the Ewald, see Eq.(71) of PRB55, 10355 (1997).
426  dyewq0 = zero
427  if ((Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1).and. (Ifc%asr==1.or.Ifc%asr==2)) then
428    ! Calculation of the non-analytical part for q=0
429    sumg0=0
430    qpt(:)=zero
431    ABI_MALLOC(dyew,(2,3,natom,3,natom))
432    if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
433      call ewald9(ddb%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
434                  Crystal%xred,zeff,qdrp_cart,option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
435    else
436      call ewald9(ddb%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
437                  Crystal%xred,zeff,qdrp_cart,option=ifc%ewald_option)
438    end if
439 
440    call q0dy3_calc(natom,dyewq0,dyew,Ifc%asr)
441    ABI_FREE(dyew)
442  end if
443 
444  ! Sample the Brillouin zone
445  option=1
446  qptrlatt = 0; qptrlatt(1,1)=ngqpt(1); qptrlatt(2,2)=ngqpt(2); qptrlatt(3,3)=ngqpt(3)
447  mqpt=ngqpt(1)*ngqpt(2)*ngqpt(3)*nqshft
448  if (Ifc%brav==2) mqpt=mqpt/2
449  if (Ifc%brav==3) mqpt=mqpt/4
450 
451  ABI_MALLOC(qbz,(3,mqpt))
452  call smpbz(Ifc%brav,ab_out,qptrlatt,mqpt,nqbz,nqshft,option,q1shft,qbz)
453 
454  ! Find the irreducible zone (qibz)
455  ABI_MALLOC(ibz2bz, (nqbz))
456  ABI_MALLOC(wtq_folded, (nqbz))
457  ABI_MALLOC(wtq, (nqbz))
458  wtq = one / nqbz ! Weights sum up to one
459  ABI_MALLOC(bz2ibz_smap, (6, nqbz))
460 
461  ! FIXME: timrev1 should be set to 0 if TR cannot be used
462  call symkpt(chksymbreak0,crystal%gmet,ibz2bz,iout0,qbz,nqbz,ifc%nqibz,crystal%nsym,&
463    crystal%symrec,timrev1,wtq,wtq_folded, bz2ibz_smap, xmpi_comm_self)
464 
465  ABI_FREE(bz2ibz_smap)
466 
467  ABI_MALLOC(ifc%qibz, (3,ifc%nqibz))
468  ABI_MALLOC(ifc%wtq, (ifc%nqibz))
469  do iq_ibz=1,ifc%nqibz
470    ifc%qibz(:,iq_ibz) = qbz(:, ibz2bz(iq_ibz))
471    ifc%wtq(iq_ibz) = wtq_folded(ibz2bz(iq_ibz))
472  end do
473  ABI_FREE(ibz2bz)
474  ABI_FREE(wtq_folded)
475  ABI_FREE(wtq)
476 
477  ABI_MALLOC(Ifc%dynmat,(2,3,natom,3,natom,nqbz))
478 
479  ! This is needed to preserve the behavior of the old implementation with canonical coordinate.
480  if (Ifc%brav == 1) then
481    gprim_tmp = Crystal%gprimd
482    rprim_tmp = rprimd
483  else
484    gprim_tmp = gprim
485    rprim_tmp = rprim
486  endif
487 
488 ! Find symmetrical dynamical matrices
489  if (.not.present(Ifc_coarse)) then
490 
491    ! Each q-point in the BZ mush be the symmetrical of one of the qpts in the ddb file.
492    ! SP - gprimd and rprimd is required instead of gprim and rprim for non-diagonal supercells.
493    call symdm9(ddb, &
494      Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
495      Crystal%symrec, Crystal%symrel, comm)
496 
497  else
498    ! Symmetrize the qpts in the BZ using the q-points in the ddb.
499    ! Then use Ifc_coarse to fill the missing entries with Fourier interpolated matrices.
500    !
501    ! TODO: The previous version of refineblk was hacking the DDB database to add the q-points in the **IBZ**
502    ! Then D(q) was symmetrized in symdm9. This version avoids the symmetrization: the q-points
503    ! in the BZ that are not in the coarse q-mesh are obtained by an explicit FT.
504    ! This means that the final D(q) may break some symmetry in q-space if the FT does not preserve it.
505    ! The most elegant approach would be to get D(q_ibz) via FT if q_ibz is not in the coarse mesh and then
506    ! call symdm9 to get D(q) for each q point in the star of q_ibz.
507    call wrtout(std_out,"Will fill missing qpoints in the full BZ using the coarse q-mesh","COLL")
508 
509    call symdm9(ddb, &
510      Ifc%dynmat,gprim_tmp,Crystal%indsym,mpert,natom,nqbz,nsym,rfmeth,rprim_tmp,qbz,&
511      Crystal%symrec,Crystal%symrel,comm, qmissing=qmissing)
512 
513    ! Compute dynamical matrix with Fourier interpolation on the coarse q-mesh.
514    write(msg,"(a,i0,a)")"Will use Fourier interpolation to construct D(q) for ",size(qmissing)," q-points"
515    call wrtout(std_out,msg)
516 
517    ABI_MALLOC(out_d2cart, (2,3,natom,3,natom))
518    do ii=1,size(qmissing)
519      iq_bz = qmissing(ii)
520      qpt = qbz(:,iq_bz)
521      ! TODO: check dipdip option and phase, but I think this is correct!
522      call Ifc_coarse%fourq(Crystal,qpt,phfrq,displ_cart,out_d2cart=out_d2cart)
523      Ifc%dynmat(:,:,:,:,:,iq_bz) = out_d2cart
524    end do
525 
526    ABI_FREE(qmissing)
527    ABI_FREE(out_d2cart)
528  end if
529 
530  ! OmegaSRLR: Store full dynamical matrix for decomposition into short- and long-range parts
531  ABI_MALLOC(dynmatfull,(2,3,natom,3,natom,nqbz))
532  dynmatfull=Ifc%dynmat
533 
534  if (Ifc%dipdip==1.or.Ifc%dipquad==1.or.Ifc%quadquad==1) then
535    ! Take off the dipole-dipole part of the dynamical matrix
536    call wrtout(std_out, " Will extract the dipole-dipole part for every wavevector")
537    ABI_MALLOC(dyew,(2,3,natom,3,natom))
538 
539    do iqpt=1,nqbz
540      if (mod(iqpt, nprocs) /= my_rank) then ! mpi-parallelism
541        ifc%dynmat(:,:,:,:,:,iqpt) = zero; cycle
542      end if
543      qpt(:)=qbz(:,iqpt)
544      sumg0=0
545      if (Ifc%dipquad==1.or.Ifc%quadquad==1) then
546        call ewald9(ddb%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
547                  Crystal%xred,zeff,qdrp_cart,option=ifc%ewald_option,dipquad=Ifc%dipquad,quadquad=Ifc%quadquad)
548      else
549        call ewald9(ddb%acell,dielt,dyew,Crystal%gmet,gprim,natom,qpt,Crystal%rmet,rprim,sumg0,Crystal%ucvol,&
550                  Crystal%xred,zeff,qdrp_cart,option=ifc%ewald_option)
551      end if
552      call q0dy3_apply(natom,dyewq0,dyew)
553      plus=0
554      ! Implement Eq.(76) of Gonze&Lee PRB 55, 10355 (1997) [[cite:Gonze1997a]], possibly generalized for quadrupoles
555      call nanal9(dyew,Ifc%dynmat,iqpt,natom,nqbz,plus)
556    end do
557 
558    call xmpi_sum(ifc%dynmat, comm, ierr)
559    ABI_FREE(dyew)
560  end if
561 
562  ! OmegaSRLR: Store the short-range dynmat and compute long-range as difference
563  ABI_MALLOC(dynmat_sr,(2,3,natom,3,natom,nqbz))
564  ABI_MALLOC(dynmat_lr,(2,3,natom,3,natom,nqbz))
565  dynmat_sr=Ifc%dynmat
566  dynmat_lr=dynmatfull-dynmat_sr
567 
568  ! Now, take care of the remaining part of the dynamical matrix
569  ! Move to canonical normalized coordinates
570  call canat9(Ifc%brav,natom,rcan,rprim,trans,Crystal%xred)
571 
572  ! Multiply the dynamical matrix by a phase shift
573  option=1
574  call dymfz9(Ifc%dynmat,natom,nqbz,gprim,option,qbz,trans)
575 
576  ! Create the Big Box of R vectors in real space and compute the number of points (cells) in real space
577  call make_bigbox(Ifc%brav,ifc_tmp%cell,ngqpt,nqshft,rprim,ifc_tmp%nrpt,ifc_tmp%rpt)
578 
579  ! Weights associated to these R points and to atomic pairs
580  ABI_MALLOC(ifc_tmp%wghatm, (natom, natom, ifc_tmp%nrpt))
581 
582  ! HM: this tolerance is highly dependent on the compilation/architecture
583  !     numeric errors in the DDB text file. Try a few tolerances and check whether all the weights are found.
584  toldist = tol8
585  do while (toldist <= tol6)
586    ! Note ngqpt(9) with intent(inout)!
587    call wght9(Ifc%brav,gprim,natom,ngqpt,nqbz,nqshft,ifc_tmp%nrpt,q1shft,rcan,&
588               ifc_tmp%rpt,rprimd,toldist,r_inscribed_sphere,ifc_tmp%wghatm,my_ierr)
589    call xmpi_max(my_ierr, ierr, comm, ii)
590    if (ierr > 0) toldist = toldist * 10
591    if (ierr == 0) exit
592  end do
593 
594  if (ierr > 0) then
595    write(msg, '(3a,es14.4,2a,i0, 14a)' ) &
596     'The sum of the weight is not equal to nqpt.',ch10,&
597     'The sum of the weights is: ',sum(ifc_tmp%wghatm),ch10,&
598     'The number of q points is: ',nqbz, ch10, &
599     'This might have several sources.',ch10,&
600     'If toldist is larger than 1.0e-8, the atom positions might be loose.',ch10,&
601     'and the q point weights not computed properly.',ch10,&
602     'Action: make input atomic positions more symmetric.',ch10,&
603     'Otherwise, you might increase "buffer" in m_dynmat.F90 see bigbx9 subroutine and recompile.',ch10,&
604     'Actually, this can also happen when ngqpt is 0 0 0,',ch10,&
605     'if abs(brav) /= 1, in this case you should change brav to 1. If brav is already set to 1 (default) try -1.'
606    ABI_ERROR(msg)
607  end if
608 
609  ! Fourier transform of the dynamical matrices (q-->R)
610  ABI_MALLOC(ifc_tmp%atmfrc, (3,natom,3,natom,ifc_tmp%nrpt))
611  call ftifc_q2r(ifc_tmp%atmfrc,Ifc%dynmat,gprim,natom,nqbz,ifc_tmp%nrpt,ifc_tmp%rpt,qbz, comm)
612 
613  ! Eventually impose Acoustic Sum Rule on the interatomic forces
614  if (Ifc%asr > 0) call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
615 
616  ! The interatomic forces have been calculated
617  write(msg, '(2a)')ch10,' The interatomic forces have been obtained '
618  call wrtout([std_out, ab_out], msg,'COLL')
619  call cwtime_report(" ifc_init1", cpu, wall, gflops)
620 
621  ! Apply cutoff on ifc if needed
622  if (nsphere > 0 .or. abs(rifcsph) > tol10) then
623    call wrtout(std_out, ' Apply cutoff on IFCs.')
624    call wrtout(std_out, sjoin(" nsphere:", itoa(nsphere), ", rifcsph:", ftoa(rifcsph)))
625    call wrtout(std_out, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(r_inscribed_sphere)))
626    call corsifc9(ddb%acell,gprim,natom,ifc_tmp%nrpt,nsphere,rifcsph,rcan,rprim,ifc_tmp%rpt,rcut_min,ifc_tmp%wghatm)
627    if (Ifc%asr > 0) then
628      call wrtout(std_out, ' Enforcing ASR on cutoffed IFCs.')
629      call asrif9(Ifc%asr,ifc_tmp%atmfrc,natom,ifc_tmp%nrpt,ifc_tmp%rpt,ifc_tmp%wghatm)
630    end if
631  end if
632 
633  ! Only conserve the necessary points in rpt: in the FT algorithm the order of the points is unimportant
634  ! In the case of effective potential, we need to keep all the points
635  Ifc%nrpt = 0
636  do irpt=1,ifc_tmp%nrpt
637    if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) Ifc%nrpt = Ifc%nrpt + 1
638  end do
639 
640  ABI_CALLOC(Ifc%atmfrc,(3,natom,3,natom,Ifc%nrpt))
641  ABI_CALLOC(Ifc%rpt,(3,Ifc%nrpt))
642  ABI_CALLOC(Ifc%cell,(3,Ifc%nrpt))
643  ABI_CALLOC(Ifc%wghatm,(natom,natom,Ifc%nrpt))
644  ABI_CALLOC(Ifc%short_atmfrc,(3,natom,3,natom,Ifc%nrpt))
645  ABI_CALLOC(Ifc%ewald_atmfrc,(3,natom,3,natom,Ifc%nrpt))
646 
647  irpt_new = 1
648  do irpt = 1, ifc_tmp%nrpt
649    if (sum(ifc_tmp%wghatm(:,:,irpt)) /= 0) then
650      Ifc%atmfrc(:,:,:,:,irpt_new) = ifc_tmp%atmfrc(:,:,:,:,irpt)
651      Ifc%rpt(:,irpt_new) = ifc_tmp%rpt(:,irpt)
652      Ifc%wghatm(:,:,irpt_new) = ifc_tmp%wghatm(:,:,irpt)
653      Ifc%cell(:,irpt_new) = ifc_tmp%cell(:,irpt)
654      Ifc%r_inscribed_sphere = r_inscribed_sphere
655      irpt_new = irpt_new + 1
656    end if
657  end do
658 
659  !write(std_out,*)"nrpt before filter:", ifc_tmp%nrpt, ", after: ", ifc%nrpt
660  !do irpt=1,ifc%nrpt
661  !  write(std_out,*)ifc%rpt(:,irpt), (ifc%wghatm(ii,ii,irpt), ii=1,natom)
662  !end do
663 
664  ! Copy other useful arrays.
665  Ifc%dielt = dielt
666  Ifc%nqbz = nqbz
667 
668  call alloc_copy(rcan, Ifc%rcan)
669  call alloc_copy(trans, Ifc%trans)
670  call alloc_copy(dyewq0, Ifc%dyewq0)
671  call alloc_copy(qbz(:,1:nqbz), Ifc%qbz)
672  call alloc_copy(zeff, Ifc%zeff)
673  call alloc_copy(qdrp_cart, Ifc%qdrp_cart)
674  call alloc_copy(ddb%amu, Ifc%amu)
675 
676  call ifc_tmp%free()
677 
678  ! Compute min/max ph frequency with ab-initio q-mesh.
679  ifc%omega_minmax(1) = huge(one); ifc%omega_minmax(2) = -huge(one)
680  do iq_ibz=1,ifc%nqibz
681    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi-parallelism
682    call ifc%fourq(crystal, ifc%qibz(:,iq_ibz), phfrq, displ_cart)
683    ifc%omega_minmax(1) = min(ifc%omega_minmax(1), minval(phfrq))
684    ifc%omega_minmax(2) = max(ifc%omega_minmax(2), maxval(phfrq))
685  end do
686  xval = ifc%omega_minmax(1); call xmpi_min(xval, ifc%omega_minmax(1), comm, ierr)
687  xval = ifc%omega_minmax(2); call xmpi_max(xval, ifc%omega_minmax(2), comm, ierr)
688  ! Enlarge boundaries by 30 cm-1
689  ifc%omega_minmax(1) = ifc%omega_minmax(1) - 30.0_dp/Ha_cmm1
690  ifc%omega_minmax(2) = ifc%omega_minmax(2) + 30.0_dp/Ha_cmm1
691 
692  ! TODO (This is to be suppressed in a future version)
693  if (prtsrlr == 1) then
694    ! Check that the starting values are well reproduced.
695    write(msg, '(2a)' )' mkifc9 : now check that the starting values ',&
696      ' are reproduced after the use of interatomic forces '
697    call wrtout(std_out, msg)
698    do iqpt=1,nqbz
699      qpt(:)=Ifc%qbz(:,iqpt)
700      call ifc%fourq(Crystal,qpt,phfrq,displ_cart,out_eigvec=eigvec)
701 
702      ! OmegaSRLR: Perform decomposition of dynamical matrix
703      ! MG: FIXME I don't think the implementation is correct when q !=0
704      if (prtsrlr==1) then
705        call omega_decomp(ddb%amu,natom,ntypat,Crystal%typat,dynmatfull,dynmat_sr,dynmat_lr,iqpt,nqbz,eigvec)
706      end if
707 
708      ! Write the phonon frequencies (this is for checking purposes).
709      ! Note: these phonon frequencies are not written on unit iout, only on unit std_out.
710      call dfpt_prtph(displ_cart,0,enunit,-1,natom,phfrq,qphnrm,qpt)
711    end do
712  end if
713 
714  ! OmegaSRLR: deallocate memory used by dynmat decomposition
715  ABI_FREE(dynmatfull)
716  ABI_FREE(dynmat_sr)
717  ABI_FREE(dynmat_lr)
718  ABI_FREE(qbz)
719 
720  if (nsphere == -1) call ifc_autocutoff(ifc, crystal, comm)
721 
722  call cwtime_report(" ifc_init2", cpu, wall, gflops)
723 
724 end subroutine ifc_init

m_ifc/ifc_outphbtrap [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_outphbtrap

FUNCTION

  Print out phonon frequencies on regular grid for BoltzTrap
  Flag in input file is outboltztrap=1

INPUTS

  ifc<ifc_type>=Stores data related to interatomic force constants.
  Crystal<crystal_t>=Info on the crystal structure
  basename = file name for output to disk
  ngqpt(3)=Divisions of the q-mesh
  nqshft=Number of shifts
  qshft(3,nqshft)=Shifts of the q-mesh.

OUTPUT

  only write to file. This routine should be called by a single processor.

SOURCE

2532 subroutine ifc_outphbtrap(ifc, cryst, ngqpt, nqshft, qshft, basename)
2533 
2534 !Arguments -------------------------------
2535 !scalars
2536  class(ifc_type),intent(in) :: ifc
2537  integer,intent(in) :: nqshft
2538  character(len=*),intent(in) :: basename
2539  type(crystal_t),intent(in) :: cryst
2540 !arrays
2541  integer,intent(in) :: ngqpt(3)
2542  real(dp),intent(in) :: qshft(3,nqshft)
2543 
2544 !Local variables -------------------------
2545 !scalars
2546  integer,parameter :: qptopt1=1
2547  integer :: natom,imode,iq_ibz,nqbz,nqibz, nreals,unit_btrap,iatom,idir
2548  character(len=500) :: msg,format_nreals,format_line_btrap
2549  character(len=fnlen) :: outfile
2550 !arrays
2551  integer :: qptrlatt(3,3)
2552  real(dp) :: d2cart(2,3,cryst%natom,3,cryst%natom),displ(2*3*cryst%natom*3*cryst%natom)
2553  real(dp) :: phfrq(3*cryst%natom),qphon(3)
2554  real(dp),allocatable :: qbz(:,:),qibz(:,:),wtq(:)
2555 
2556 ! *********************************************************************
2557 
2558  DBG_ENTER("COLL")
2559 
2560  natom = cryst%natom
2561 
2562  ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
2563  qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
2564  call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
2565 
2566  outfile = trim(basename) // '_BTRAP'
2567  write(msg, '(3a)')ch10,' Will write phonon FREQS in BoltzTrap format to file ',trim(outfile)
2568  call wrtout([std_out, ab_out], msg)
2569 
2570  if (open_file(outfile,msg,newunit=unit_btrap,status="replace") /= 0) then
2571    ABI_ERROR(msg)
2572  end if
2573 
2574  write (unit_btrap,'(a)') '#'
2575  write (unit_btrap,'(a)') '# ABINIT package : Boltztrap phonon file. With old BT versions remove this header before feeding to BT'
2576  write (unit_btrap,'(a)') '#    for compatibility with PHON output the freq are in Ry (before the square)'
2577  write (unit_btrap,'(a)') '#'
2578  write (unit_btrap,'(a)') '#    nq, nband  '
2579  write (unit_btrap,'(a)') '#  qx, qy, qz   '
2580  write (unit_btrap,'(a)') '#  qpt weight   '
2581  write (unit_btrap,'(a)') '#  freq_1^2, dynmat column for mode 1 '
2582  write (unit_btrap,'(a)') '#  etc for mode 2,3,4... qpt 2,3,4... '
2583  write (unit_btrap,'(2I6)') nqibz, 3*natom
2584 
2585 ! Loop over irreducible q-points
2586  do iq_ibz=1,nqibz
2587    qphon(:)=qibz(:,iq_ibz)
2588 
2589    call ifc%fourq(cryst, qphon, phfrq, displ, out_d2cart=d2cart)
2590 
2591    write (unit_btrap,'(3E20.10)') qphon
2592    write (unit_btrap,'(E20.10)') wtq(iq_ibz)
2593    nreals=1+2*3*natom
2594    call appdig(nreals,'(',format_nreals)
2595    format_line_btrap=trim(format_nreals)//'E20.10)'
2596    do iatom = 1, natom
2597      do idir = 1, 3
2598        imode = idir + 3*(iatom-1)
2599        ! factor two for Ry output - this may change in definitive BT and abinit formats
2600        write (unit_btrap,trim(format_line_btrap))phfrq(imode)*two,d2cart(1:2,1:3,1:natom,idir,iatom)
2601      end do
2602    end do
2603 
2604  end do !irred q-points
2605  close (unit_btrap)
2606 
2607  ABI_FREE(qibz)
2608  ABI_FREE(qbz)
2609  ABI_FREE(wtq)
2610 
2611  DBG_EXIT("COLL")
2612 
2613 end subroutine ifc_outphbtrap

m_ifc/ifc_print [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  ifc_print

FUNCTION

  Print info on the object

INPUTS

  [unit]=Unit number for output. Defaults to std_out
  [prtvol]=Verbosity level.
  [header]=String to be printed as header for additional info.

OUTPUT

  Only printing

SOURCE

832 subroutine ifc_print(ifc, header, unit, prtvol)
833 
834 !Arguments ------------------------------------
835 !scalars
836  class(ifc_type),intent(in) :: ifc
837  integer,optional,intent(in) :: unit,prtvol
838  character(len=*),optional,intent(in) :: header
839 
840 !Local variables-------------------------------
841  integer :: unt,my_prtvol,iatom,ii,idir
842  character(len=500) :: msg
843 ! *********************************************************************
844 
845  unt = std_out; if (present(unit)) unt = unit
846  my_prtvol = 0; if (present(prtvol)) my_prtvol = prtvol
847 
848  msg = ' ==== Info on the interatomic force constants ==== '
849  if (present(header)) msg = ' ==== '//trim(adjustl(header))//' ==== '
850  call wrtout(unt, msg)
851 
852  call wrtout(unt,' Real(R)+Recip(G) space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):')
853  do ii=1,3
854    write(msg,'(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)')&
855     'R(',ii,')=',ifc%rprim(:,ii),'G(',ii,')=',ifc%gprim(:,ii)
856    call wrtout(unt,msg)
857  end do
858  call wrtout(unt, sjoin(" acell:", ltoa(ifc%acell)))
859  call wrtout(unt, sjoin(" Acoustic Sum Rule option (asr):", itoa(ifc%asr)))
860  call wrtout(unt, sjoin(" Option for the sampling of the BZ (brav):", itoa(ifc%brav)))
861  call wrtout(unt, sjoin(" Symmetrization flag (symdynmat):", itoa(ifc%symdynmat)))
862  call wrtout(unt, sjoin(" Dipole-dipole interaction flag (dipdip):", itoa(ifc%dipdip)))
863  call wrtout(unt, sjoin(" Dipole-quadrupole interaction flag (dipquad):", itoa(ifc%dipquad)))
864  call wrtout(unt, sjoin(" quadrupole-quadrupole interaction flag (quadquad):", itoa(ifc%quadquad)))
865  call wrtout(unt, sjoin(" Ewald option:", itoa(ifc%ewald_option)))
866  call wrtout(unt, sjoin(" Dielectric tensor: ", ch10, ltoa(reshape(ifc%dielt, [9]), fmt="f10.2")))
867  call wrtout(unt, " Effective charges:")
868  do iatom=1,ifc%natom
869    call wrtout(unt, ltoa(reshape(ifc%zeff(:,:,iatom), [3*3]), fmt="f10.2"))
870  end do
871  call wrtout(unt, " Quadrupolar terms:")
872  do iatom=1,ifc%natom
873    do idir=1,3
874      call wrtout(unt, ltoa(reshape(ifc%qdrp_cart(:,:,idir,iatom), [3*3]), fmt="f10.2"))
875    end do
876  end do
877 
878  call wrtout(unt, sjoin(" Mass of the atoms (atomic mass unit): ", ltoa(ifc%amu)))
879  call wrtout(unt, sjoin(" Number of real-space points for IFC(R): ", itoa(ifc%nrpt)))
880  call wrtout(std_out, sjoin(" Radius of biggest sphere inscribed in the WS supercell: ", ftoa(ifc%r_inscribed_sphere)))
881  call wrtout(unt, " ")
882 
883  call wrtout(unt, " Q-mesh:")
884  call wrtout(unt, sjoin(" ngqpt:", ltoa(ifc%ngqpt),", nqshft:", itoa(ifc%nqshft)))
885  do ii=1,ifc%nqshft
886    call wrtout(unt, sjoin("  ", ktoa(ifc%qshft(:,ii))))
887  end do
888 
889 end subroutine ifc_print

m_ifc/ifc_printbxsf [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_printbxsf

FUNCTION

  Output phonon isosurface in Xcrysden format.

INPUTS

  ifc<ifc_type>=Stores data related to interatomic force constants.
  crystal<crystal_t>=Info on the crystal structure
  ngqpt(3)=Divisions of the q-mesh
  nqshft=Number of shifts
  qshft(3,nqshft)=Shifts of the q-mesh.
  path=File name for output to disk
  comm=MPI communicator.

OUTPUT

  Only write to file

SOURCE

2639 subroutine ifc_printbxsf(ifc, cryst, ngqpt, nqshft, qshft, path, comm)
2640 
2641 !Arguments -------------------------------
2642 !scalars
2643  class(ifc_type),intent(in) :: ifc
2644  integer,intent(in) :: nqshft,comm
2645  character(len=*),intent(in) :: path
2646  type(crystal_t),intent(in) :: cryst
2647 !arrays
2648  integer,intent(in) :: ngqpt(3)
2649  real(dp),intent(in) :: qshft(3,nqshft)
2650 
2651 !Local variables -------------------------
2652 !scalars
2653  integer,parameter :: nsppol1=1,master=0,qptopt1=1
2654  integer :: my_rank,nprocs,iq_ibz,nqibz,nqbz,ierr
2655  character(len=500) :: msg
2656 !arrays
2657  integer :: qptrlatt(3,3),dummy_symafm(cryst%nsym)
2658  real(dp) :: displ_cart(2,3*cryst%natom,3*cryst%natom)
2659  real(dp),allocatable :: qibz(:,:),wtq(:),qbz(:,:),freqs_qibz(:,:)
2660 
2661 ! *********************************************************************
2662 
2663  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
2664 
2665  ! Setup IBZ, weights and BZ. Always use q --> -q symmetry for phonons even in systems wo inversion
2666  qptrlatt = 0; qptrlatt(1,1) = ngqpt(1); qptrlatt(2,2) = ngqpt(2); qptrlatt(3,3) = ngqpt(3)
2667  call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, nqshft, qshft, nqibz, qibz, wtq, nqbz, qbz)
2668  ABI_FREE(qbz)
2669  ABI_FREE(wtq)
2670 
2671  ! Compute phonon frequencies in the irreducible wedge.
2672  ABI_CALLOC(freqs_qibz, (3*cryst%natom, nqibz))
2673 
2674  do iq_ibz=1,nqibz
2675    if (mod(iq_ibz, nprocs) /= my_rank) cycle ! mpi parallelism.
2676    call ifc%fourq(cryst, qibz(:,iq_ibz), freqs_qibz(:,iq_ibz), displ_cart)
2677  end do
2678  call xmpi_sum(freqs_qibz, comm, ierr)
2679 
2680  ! Output phonon isosurface.
2681  if (my_rank == master) then
2682    dummy_symafm = 1
2683    call printbxsf(freqs_qibz, zero, zero, cryst%gprimd, qptrlatt, 3*cryst%natom,&
2684      nqibz, qibz, cryst%nsym, .False., cryst%symrec, dummy_symafm, .True., nsppol1, qshft, nqshft, path, ierr)
2685    if (ierr /=0) then
2686      msg = "Cannot produce BXSF file with phonon isosurface, see log file for more info"
2687      ABI_WARNING(msg)
2688      call wrtout(ab_out, msg, 'COLL')
2689    end if
2690  end if
2691 
2692  ABI_FREE(freqs_qibz)
2693  ABI_FREE(qibz)
2694 
2695 end subroutine ifc_printbxsf

m_ifc/ifc_speedofsound [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_speedofsound

FUNCTION

  Calculate the speed of sound by averaging the phonon group velocities of the
  three acoustic modes on a small sphere of radius qrad centered around Gamma.
  Perform spherical integration with Lebedev-Laikov grids

INPUTS

 ifc<ifc_type>=Object containing the dynamical matrix and the IFCs.
 crystal<crystal_t> = Information on the crystalline structure.
 qrad_tolkms(2):
   qrad=Radius of the sphere in reciprocal space
   atols_kms=Absolute tolerance in kilometer/second. The code generates spherical meshes
     until the results are converged twice within atols_kms.
 ncid=the id of the open NetCDF file. Use nctk_noid to disable netcdf output.
 comm=MPI communicator.

OUTPUT

SOURCE

1185 subroutine ifc_speedofsound(ifc, crystal, qrad_tolkms, ncid, comm)
1186 
1187 !Arguments -------------------------------
1188 !scalars
1189  class(ifc_type),intent(in) :: ifc
1190  integer,intent(in) :: comm,ncid
1191  type(crystal_t),intent(in) :: crystal
1192 !arrays
1193  real(dp),intent(in) :: qrad_tolkms(2)
1194 
1195 !Local variables -------------------------
1196 !scalars
1197  integer,parameter :: master=0
1198  integer :: ii,nu,igrid,my_rank,nprocs,ierr,converged,npts,num_negw,vs_ierr,ncerr
1199  integer :: iatom,iatref,num_acoustic,isacoustic
1200  real(dp) :: min_negw,cpu,wall,gflops
1201  real(dp) :: qrad,tolkms,diff
1202  character(len=500) :: msg
1203  type(lebedev_t) :: lgrid
1204 !arrays
1205  integer :: asnu(3)
1206  real(dp) :: qred(3),qvers_cart(3),qvers_red(3),quad(3),prev_quad(3),vs(7,3)
1207  real(dp) :: phfrqs(3*crystal%natom),dwdq(3,3*crystal%natom)
1208  real(dp) :: displ_cart(2,3*crystal%natom,3*crystal%natom),eigvec(2,3*crystal%natom,3*crystal%natom)
1209 
1210 ! *********************************************************************
1211 
1212  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
1213 
1214  if (ifc%asr == 0) ABI_WARNING("Computing speed of sound with asr == 0! Use asr > 0")
1215  qrad = qrad_tolkms(1); tolkms = qrad_tolkms(2)
1216  ABI_CHECK(qrad > zero, "vs_qrad <= 0")
1217  ABI_CHECK(tolkms > zero, "vs_tolkms <= 0")
1218 
1219  call cwtime(cpu, wall, gflops, "start")
1220 
1221  ! Find the index of the first acoustic modes (needed to handle systems with unstable branches at Gamma
1222  ! In this case, indeed, we end up computing derivatives for the wrong branches, the integration becomes
1223  ! unstable and difficult to converge.
1224  qred = zero
1225  call ifc%fourq(crystal, qred, phfrqs, displ_cart,out_eigvec=eigvec)
1226  !write(std_out,*)"omega(q==Gamma): ",phfrqs
1227 
1228  num_acoustic = 0
1229  do nu = 1, 3*crystal%natom
1230    ! Check if this mode is acoustic like: scalar product of all displacement vectors are collinear
1231    isacoustic = 1
1232    ! Find reference atom with non-zero displacement
1233    do iatom=1,crystal%natom
1234      if(sum(displ_cart(:,(iatom-1)*3+1:(iatom-1)*3+3,nu)**2) >tol16)iatref=iatom
1235    end do
1236    ! Now compute scalar product, and check they are all positive
1237    do iatom = 1, crystal%natom
1238      if (sum(eigvec(:,(iatom-1)*3+1:(iatom-1)*3+3, nu)*eigvec(:,(iatref-1)*3+1:(iatref-1)*3+3, nu)) < tol16 ) isacoustic = 0
1239    end do
1240    if (isacoustic == 1) then
1241      num_acoustic=num_acoustic+1
1242      asnu(num_acoustic)=nu
1243      if (num_acoustic==3) exit
1244    end if
1245  end do
1246 
1247  ABI_CHECK(num_acoustic == 3, sjoin("Wrong number of acoustic modes:", itoa(num_acoustic)))
1248 
1249  write(std_out,"(a,3i2,a)") "The bands with indices ",asnu(:)," will be used to calculate the sound velocities"
1250 
1251  ! Speed of sound along reduced directions.
1252  do ii=1,6
1253    qred = zero; qred(MOD(ii-1,3)+1) = one
1254    if (ii >= 4 .and. ii <= 6) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
1255    !if (ii >= 7 .and. ii <= 9) qred = matmul(crystal%rprimd, qred) ! Cartesian directions.
1256    qvers_red = (qred / normv(qred, crystal%gmet, "G"))
1257    qred = qrad * qvers_red
1258    !write(std_out,*)"dir",normv(qred, crystal%gmet, "G"), qrad
1259    call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
1260 
1261    do nu=1,3
1262      vs(ii, nu) = sqrt(sum(dwdq(1:3,asnu(nu)) ** 2)) * Bohr_meter * 0.001_dp / Time_Sec
1263    end do
1264    write(std_out,"(a,3es12.4,a)")" ||vs(nu)||:",vs(ii,:), " [km/s]"
1265 
1266    qvers_cart = matmul(crystal%gprimd, qvers_red) * two_pi
1267    do nu=1,3
1268      vs(ii, nu) = dot_product(dwdq(1:3,asnu(nu)), qvers_cart) * Bohr_meter * 0.001_dp / Time_Sec
1269    end do
1270    write(std_out,"(a,3es12.4,a)")" <q|vs(nu)>:",vs(ii,:), " [km/s]"
1271 
1272    !do nu=1,3
1273    !  write(std_out,"(a,3es12.4,a)")" vs(nu)_vect_red:",&
1274    !     matmul(crystal%gprimd, dwdq(1:3,asnu(nu))) * Bohr_meter * 0.001_dp / Time_Sec, " [km/s]"
1275    !end do
1276  end do
1277 
1278  ! Spherical average with Lebedev-Laikov grids.
1279  converged = 0
1280  do igrid=1,lebedev_ngrids
1281    call lgrid%from_index(igrid)
1282    npts = lgrid%npts; quad = zero; num_negw = 0; min_negw = zero
1283    do ii=1,npts
1284      if (mod(ii, nprocs) /= my_rank) cycle ! mpi-parallelism
1285 
1286      ! Build q-point on sphere of radius qrad. qcart --> qred
1287      qred = matmul(crystal%rprimd, lgrid%versors(:, ii))
1288      qred = qrad * (qred / normv(qred, crystal%gmet, "G"))
1289      !write(std_out,*)"lebe",normv(qred, crystal%gmet, "G"), qrad
1290      call ifc%fourq(crystal, qred, phfrqs, displ_cart, dwdq=dwdq)
1291      if (any(phfrqs(asnu) < -tol8)) then
1292        num_negw = num_negw + 1; min_negw = min(min_negw, minval(phfrqs(asnu)))
1293      end if
1294 
1295      do nu=1,3
1296        quad(nu) = quad(nu) + lgrid%weights(ii) * sqrt(sum(dwdq(1:3,asnu(nu)) ** 2))
1297        !quad(nu) = quad(nu) + lgrid%weights(ii) * abs(dot_product(lgrid%versors(:,ii), dwdq(:,asnu(nu))))
1298      end do
1299    end do
1300 
1301    ! Will use km/sec unit for echo purposes
1302    quad = quad * Bohr_meter * 0.001_dp / Time_Sec
1303    call xmpi_sum(quad, comm, ierr)
1304    call xmpi_sum(num_negw, comm, ierr)
1305    call lgrid%free()
1306 
1307    write(std_out,'(2(a,i6),a,3es12.4,a,es12.4)') &
1308      " Lebedev-Laikov grid: ",igrid,", npts: ", npts, " vs_sphavg(ac_modes): ",quad, " <vs>: ",sum(quad)/3
1309 
1310    if (igrid > 1) then
1311      diff = zero
1312      do nu=1,3
1313        diff = diff + abs(quad(nu) - prev_quad(nu)) / 3
1314      end do
1315      !if (abs(sum(quad - prev_quad)/3) < tolkms) then
1316      if (diff < tolkms) then
1317         converged = converged + 1
1318      else
1319         converged = 0
1320      end if
1321    end if
1322    prev_quad = quad
1323    vs(7, :) = quad
1324    if (converged == 2) exit
1325  end do ! igrid
1326 
1327  if (my_rank == master) then
1328    ! vs_err: 1 if not converged, < 0 if negative freqs, == 0 if success.
1329    vs_ierr = 0
1330    do ii=1,3
1331      write(ab_out,"(a,3es12.4,a,i1)")" Speed of sound:",vs(ii,:)," [km/s] along reduced direction: ",ii
1332    end do
1333    write(ab_out,'(2(a,es12.4),a,i0)') &
1334      " Lebedev-Laikov integration with qradius: ", qrad, " tolkms: ",tolkms, " [km/s], npts: ", npts
1335    write(ab_out,"(a,3es12.4,a,es12.4)")" Spherical average:",vs(7,:)," [km/s], ",sum(vs(7,:))/3
1336    if (converged /= 2) then
1337      vs_ierr = 1
1338      write(msg,'(a,es12.4,a)')" WARNING: Results are not converged within: ",tolkms, " [km/s]"
1339      call wrtout(ab_out, msg)
1340      ABI_WARNING(msg)
1341    end if
1342    if (num_negw > 0) then
1343      vs_ierr = -num_negw
1344      write(msg,'(a,i0,a,es12.4,3a)') &
1345        " WARNING: Detected ",num_negw, " negative frequencies. Minimum was: ",min_negw * Ha_meV, "[meV]",ch10,&
1346        " Speed of sound could be wrong"
1347      call wrtout(ab_out, msg)
1348      ABI_WARNING(msg)
1349    end if
1350 
1351    ! Dump results to netcdf file.
1352    if (ncid /= nctk_noid) then
1353 #ifdef HAVE_NETCDF
1354      ncerr = nctk_def_arrays(ncid, [nctkarr_t("vsound", "dp", "seven, three")], defmode=.True.)
1355      NCF_CHECK(ncerr)
1356      ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: "vsound_ierr"])
1357      NCF_CHECK(ncerr)
1358      ncerr = nctk_def_dpscalars(ncid, [character(len=nctk_slen) :: "vsound_qrad", "vsound_tolkms"])
1359      NCF_CHECK(ncerr)
1360      ncerr = nctk_def_arrays(ncid, [nctkarr_t("asnu", "i", "three")], defmode=.True.)
1361      NCF_CHECK(ncerr)
1362      ! Write data.
1363      NCF_CHECK(nctk_set_datamode(ncid))
1364      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_ierr"), vs_ierr))
1365      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_qrad"), qrad))
1366      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound_tolkms"), tolkms))
1367      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "vsound"), vs))
1368      NCF_CHECK(nf90_put_var(ncid, nctk_idname(ncid, "asnu"), asnu))
1369 #endif
1370    end if
1371  end if
1372 
1373  call cwtime_report(" ifc_speedofsound", cpu, wall, gflops)
1374 
1375 end subroutine ifc_speedofsound

m_ifc/ifc_type [ Types ]

[ Top ] [ m_ifc ] [ Types ]

NAME

 ifc_type

FUNCTION

  Contains the necessary data to interpolate the
  phonon bandstructure and eigenvectors in reciprocal space (ie.
  interatomic force constants and corresponding real space grid info).

SOURCE

 72  type,public :: ifc_type
 73 
 74    integer :: natom
 75      ! Number of atoms in the unit cell.
 76 
 77    integer :: mpert
 78      ! Maximum number of ipert.
 79 
 80    integer :: asr
 81      ! Option for the treatment of the Acoustic Sum Rule.
 82 
 83    integer :: brav
 84      ! Option for the sampling of the BZ (anaddb input variable)
 85 
 86    integer :: dipdip
 87      ! dipole dipole interaction flag.
 88 
 89    integer :: dipquad
 90      ! dipole quadrupole interaction flag.
 91 
 92    integer :: quadquad
 93      ! dipole quadrupole interaction flag.
 94 
 95    integer :: symdynmat
 96      ! If equal to 1, the dynamical matrix is symmetrized in dfpt_phfrq before the diagonalization.
 97 
 98    integer :: nqshft
 99      ! Number of shifts in the q-mesh (usually 1 since the mesh is gamma-centered!)
100 
101    integer :: nqibz
102      ! Number of points in the IBZ
103 
104    integer :: nqbz
105      ! Number of points in the full BZ
106 
107    integer :: nrpt
108      ! Number of real space points used to integrate IFC (for interpolation of dynamical matrices)
109 
110    integer :: ngqpt(3)
111     ! Number of division in the Q mesh.
112 
113    integer :: ewald_option
114     ! Option for the ewald sum
115 
116    real(dp) :: rprim(3,3),gprim(3,3),acell(3)
117      ! These values are used to call anaddb routines that don't use rprimd, gprimd
118 
119    real(dp) :: dielt(3,3)
120      ! Dielectric tensor (Cartesian coordinates)
121 
122    real(dp) :: omega_minmax(2)
123      ! Min and max frequency obtained on the initial ab-initio q-mesh (-+ 30 cmm1)
124      ! Used to generate frequency meshes for DOSes.
125 
126    real(dp) :: r_inscribed_sphere
127      ! radius of biggest sphere inscribed in the WS supercell
128 
129    real(dp),allocatable :: amu(:)
130      ! amu(ntypat)
131      ! mass of the atoms (atomic mass unit)
132 
133    real(dp),allocatable :: atmfrc(:,:,:,:,:)
134      ! atmfrc(3,natom,3,natom,nrpt)
135      ! Inter atomic forces in real space
136 
137    integer,allocatable :: cell(:,:)
138      ! cell(nrpt,3)
139      ! Give the index of the cell and irpt
140 
141    real(dp),allocatable :: ewald_atmfrc(:,:,:,:,:)
142      ! Ewald_atmfrc(3,natom,3,natom,nrpt)
143      ! Ewald Inter atomic forces in real space
144 
145    real(dp),allocatable :: short_atmfrc(:,:,:,:,:)
146      ! short_atmfrc(3,natom,3,natom,nrpt)
147      ! Short range part of Inter atomic forces in real space
148 
149    real(dp),allocatable :: qshft(:,:)
150     ! qshft(3,nqshft)
151     ! The shifts of the q-mesh
152 
153    real(dp), allocatable :: rpt(:,:)
154      ! rpt(3,nrpt)
155      ! Real space points in canonical type coordinates.
156 
157    real(dp),allocatable :: wghatm(:,:,:)
158      ! wghatm(natom,natom,nrpt)
159      ! Weights for each point and atom in the Wigner Seitz supercell in real space.
160 
161    real(dp),allocatable :: rcan(:,:)
162      ! rcan(3,natom)
163      ! Atomic position in canonical coordinates.
164 
165    real(dp),allocatable :: trans(:,:)
166      ! trans(3,natom)
167      ! Atomic translations: xred = rcan + trans
168 
169    real(dp),allocatable :: dyewq0(:,:,:)
170      ! dyewq0(3,3,natom)
171      ! Atomic self-interaction correction to the dynamical matrix (only when dipdip = 1).
172 
173    real(dp),allocatable :: zeff(:,:,:)
174      ! zeff(3,3,natom)
175      ! Effective charge on each atom, versus electric field and atomic displacement.
176      ! Cartesian coordinates
177 
178    real(dp),allocatable :: qdrp_cart(:,:,:,:)
179      ! qdrp_cart(3,3,3,natom)
180      ! Quadrupole tensor on each atom
181      ! Cartesian coordinates
182 
183    real(dp),allocatable :: qibz(:,:)
184      ! qibz(3,nqibz))
185      ! List of q-points in the IBZ
186 
187    real(dp),allocatable :: wtq(:)
188      ! wtq(nqibz))
189      ! q-point Weights.
190 
191    real(dp),allocatable :: qbz(:,:)
192      ! qbz(3,nqbz))
193      ! List of q-points in the full BZ
194 
195    real(dp),allocatable :: dynmat(:,:,:,:,:,:)
196      ! dynmat(2,3,natom,3,natom,nqbz))
197      ! dynamical matrices relative to the q points of the B.Z. sampling
198      ! Note that the long-range dip-dip part has been removed if dipdip = 1
199      ! Moreover the array is multiplied by a phase shift in mkifc9.
200 
201    !real(dp),allocatable :: dynmat_lr(:,:,:,:,:,:)
202     ! dynmat_lr(2,3,natom,3,natom,nqbz))
203     ! Long-range part of dynmat in q-space
204 
205  contains
206 
207     procedure :: free => ifc_free
208     ! Release memory
209 
210     procedure :: print => ifc_print
211      ! Print info on the object.
212 
213     procedure :: fourq => ifc_fourq
214      ! Use Fourier interpolation to compute interpolated frequencies w(q) and eigenvectors e(q)
215 
216     procedure :: get_dwdq => ifc_get_dwdq
217     !  Compute phonon group velocities at an arbitrary q-point.
218 
219     procedure :: get_phmesh => ifc_get_phmesh
220      ! Build linear mesh for phonons.
221 
222     procedure :: speedofsound => ifc_speedofsound
223      ! Compute the speed of sound by averaging phonon group velocities.
224 
225     procedure :: write => ifc_write
226      ! Print the ifc (output, netcdf and text file)
227 
228     procedure :: outphbtrap => ifc_outphbtrap
229      ! Print out phonon frequencies on regular grid for BoltzTrap code.
230 
231     procedure :: printbxsf => ifc_printbxsf
232      ! Output phonon isosurface in Xcrysden format.
233 
234     procedure :: calcnwrite_nana_terms => ifc_calcnwrite_nana_terms
235      ! Compute phonons for q--> 0 with LO-TO
236 
237     procedure :: init => ifc_init
238      ! Constructor from DDB datatype
239 
240     procedure :: from_file => ifc_from_file
241      ! Constructor from filename
242  end type ifc_type

m_ifc/ifc_write [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

 ifc_write

FUNCTION

 Adds the real-space interatomic force constants to:
  the output file,
  a NetCDF file which is already open on ncid
  if prt_ifc==1, to the ifcinfo.out file
  to a TDEP file named outfile.forceconstants_ABINIT

INPUTS

 Ifc<type(ifc_type)>=Object containing the dynamical matrix and the IFCs.
 ifcana= 0 => no analysis of ifc ; 1 => full analysis
 atifc(natom) =  atifc(ia) equals 1 if the analysis of ifc has to be done for atom ia; otherwise 0.
 ifcout= Number of interatomic force constants written in the output file
 prt_ifc = flag to print out ifc information for dynamical matrix (AI2PS)
 ncid=the id of the open NetCDF file. Set to nctk_noid if netcdf output is not wanted.

OUTPUT

   written in the output file and in the NetCDF file

NOTES

 This routine should be executed by one processor only

 TODO:
  1) ifc_write should not have side effects

  2) the code is unreadable and horrible - 3/4 different file formats for the
  same stuff. We should make different subroutines, even if it duplicates some code

SOURCE

1675 subroutine ifc_write(Ifc,ifcana,atifc,ifcout,prt_ifc,ncid, &
1676                                                     unit_out) ! optional arguments
1677 
1678 !Arguments -------------------------------
1679 !scalars
1680  class(ifc_type),intent(inout) :: Ifc
1681  integer,intent(in) :: ifcout,ifcana,prt_ifc,ncid
1682  integer,optional,intent(in) :: unit_out
1683 !arrays
1684  integer,intent(in) :: atifc(Ifc%natom)
1685 
1686 !Local variables -------------------------
1687 !scalars
1688  integer :: ia,ib,ii,ncerr,iatifc,ifcout1,mu,nu,iout, irpt
1689 ! unit number to print out ifc information for dynamical matrix (AI2PS)
1690  integer :: unit_ifc, unit_tdep
1691  real(dp) :: detdlt
1692  real(dp) :: maxdist_tdep
1693  character(len=500) :: message
1694  character(len=4) :: str1, str2
1695 !arrays
1696  integer,allocatable :: list(:),indngb(:)
1697  real(dp) :: invdlt(3,3),ra(3),xred(3),dielt(3,3)
1698  real(dp),allocatable :: dist(:,:,:),wkdist(:),rsiaf(:,:,:),sriaf(:,:,:),vect(:,:,:)
1699  real(dp),allocatable :: posngb(:,:),wghia(:)
1700  real(dp) :: gprimd(3,3),rprimd(3,3)
1701 
1702 ! *********************************************************************
1703 
1704  iout = ab_out
1705  if (present(unit_out)) then
1706    iout = unit_out
1707  end if
1708  dielt = ifc%dielt
1709 
1710  ! Compute the distances between atoms
1711  ABI_MALLOC(dist,(Ifc%natom,Ifc%natom,Ifc%nrpt))
1712  call dist9(Ifc%acell,dist,Ifc%gprim,Ifc%natom,Ifc%nrpt,Ifc%rcan,Ifc%rprim,Ifc%rpt)
1713  ! Now dist(ia,ib,irpt) contains the distance from atom ia to atom ib in unit cell irpt.
1714 
1715  ABI_MALLOC(list,(Ifc%natom*Ifc%nrpt))
1716  ABI_MALLOC(wkdist,(Ifc%natom*Ifc%nrpt))
1717 
1718  ! Calculating the inverse (transpose) of the dielectric tensor
1719  call matr3inv(dielt,invdlt)
1720 
1721  ! Calculating the determinant of the dielectric tensor
1722  detdlt=dielt(1,1)*dielt(2,2)*dielt(3,3)+dielt(1,3)*dielt(2,1)*&
1723 & dielt(3,2)+dielt(1,2)*dielt(2,3)*dielt(3,1)-dielt(1,3)*&
1724 & dielt(2,2)*dielt(3,1)-dielt(1,1)*dielt(2,3)*dielt(3,2)-&
1725 & dielt(1,2)*dielt(2,1)*dielt(3,3)
1726 
1727 ! echo to log file
1728  write(std_out,'(a)' )' ifc_write: analysis of interatomic force constants '
1729  call mkrdim(Ifc%acell,Ifc%rprim,rprimd)
1730  call matr3inv(rprimd,gprimd)
1731 
1732  if (iout > 0) then
1733    write(iout, '(/,a,/)' )' Analysis of interatomic force constants '
1734    if(Ifc%dipdip==1.and.Ifc%dipquad==0.and.Ifc%quadquad==0)then
1735      write(iout, '(a)' )' Are given : column(1-3), the total force constant'
1736      write(iout, '(a)' )'       then  column(4-6), the Ewald part'
1737      write(iout, '(a)' )'       then  column(7-9), the short-range part'
1738      write(iout, '(a)' )' Column 1, 4 and 7 are related to the displacement'
1739      write(iout, '(a)' )'       of the generic atom along x,               '
1740      write(iout, '(a)' )' column 2, 5 and 8 are related to the displacement'
1741      write(iout, '(a)' )'       of the generic atom along y,               '
1742      write(iout, '(a)' )' column 3, 6 and 9 are related to the displacement'
1743      write(iout, '(a)')'       of the generic atom along z.               '
1744    else if(Ifc%dipquad==1.or.Ifc%quadquad==1)then
1745      write(iout, '(a)' )' Are given : column(1-3), ONLY the short-range part!!!!'
1746      write(iout, '(a)' )' column 1 is related to the displacement'
1747      write(iout, '(a)' )'        of the generic atom along x,    '
1748      write(iout, '(a)' )' column 2 is related to the displacement'
1749      write(iout, '(a)' )'        of the generic atom along y,    '
1750      write(iout, '(a)' )' column 3 is related to the displacement'
1751      write(iout, '(a)' )'        of the generic atom along z,    '
1752    else if(Ifc%dipdip==0)then
1753      write(iout, '(a)' )' column 1 is related to the displacement'
1754      write(iout, '(a)' )'        of the generic atom along x,    '
1755      write(iout, '(a)' )' column 2 is related to the displacement'
1756      write(iout, '(a)' )'        of the generic atom along y,    '
1757      write(iout, '(a)' )' column 3 is related to the displacement'
1758      write(iout, '(a)' )'        of the generic atom along z,    '
1759    end if
1760  end if
1761 
1762  if (ifcout>Ifc%natom*Ifc%nrpt .or. ifcout == -1) then
1763    ifcout1=Ifc%natom*Ifc%nrpt
1764    write(message, '(3a,i0,a)' )&
1765 &   'The value of ifcout exceeds the number of atoms in the big box.', ch10, &
1766 &   'Output limited to ',Ifc%natom*Ifc%nrpt,' atoms.'
1767    ABI_WARNING(message)
1768  else
1769    ifcout1=ifcout
1770  end if
1771 
1772  ! set up file for real space ifc output, if required
1773  if (prt_ifc == 1) then
1774    if (open_file('ifcinfo.out', message, newunit=unit_ifc, status="replace") /= 0) then
1775      ABI_ERROR(message)
1776    end if
1777    write(iout, '(a,a)' )ch10,&
1778 &   '  NOTE: Open file ifcinfo.out, for the output of interatomic force constants. This is because prt_ifc==1. '
1779 
1780    if (open_file('outfile.forceconstants_ABINIT', message, newunit=unit_tdep, status="replace") /= 0) then
1781      ABI_ERROR(message)
1782    end if
1783    write(iout, '(a,a,a)' )ch10,&
1784 &   '  NOTE: Open file outfile.forceconstants_ABINIT, for the output of interatomic force',&
1785 &   ' constants in TDEP format. This is because prt_ifc==1. '
1786    ! Print necessary stuff for TDEP
1787    write(unit_tdep,"(1X,I10,15X,'How many atoms per unit cell')") Ifc%natom
1788 
1789    ! look at all pairs, find furthest one with weight 1
1790 !   do ia
1791 !Ifc%wghatm(ia,ib,irpt)
1792    maxdist_tdep = Ifc%r_inscribed_sphere !maxval(dist)*0.8_dp
1793    write(unit_tdep,"(1X,F20.15,5X,'Realspace cutoff (A)')") maxdist_tdep*Bohr_Ang
1794  end if
1795 
1796 #ifdef HAVE_NETCDF
1797  if (ncid /= nctk_noid) then
1798    ! initialize netcdf variables
1799    ncerr = nctk_def_dims(ncid, [nctkdim_t("natifc", SUM(atifc)), nctkdim_t("number_of_r_points_big_box", Ifc%nrpt), &
1800      nctkdim_t("number_of_atoms_big_box", Ifc%natom*Ifc%nrpt), nctkdim_t("ifcout", ifcout1)], defmode=.True.)
1801    NCF_CHECK(ncerr)
1802 
1803    ncerr = nctk_def_arrays(ncid, [&
1804      nctkarr_t('ifc_atoms_indices', "i", "natifc"),&
1805      nctkarr_t('ifc_neighbours_indices', "i", "ifcout, natifc"),&
1806      nctkarr_t('ifc_distances', "dp", "ifcout, natifc "),&
1807      nctkarr_t('ifc_matrix_cart_coord', "dp", "number_of_cartesian_directions,number_of_cartesian_directions, ifcout, natifc"),&
1808      nctkarr_t('ifc_atoms_cart_coord', "dp", "number_of_cartesian_directions,ifcout, natifc"),&
1809      nctkarr_t('ifc_weights', "dp", "ifcout, natifc")])
1810    NCF_CHECK(ncerr)
1811 
1812    if (Ifc%dipdip==1) then
1813      ncerr = nctk_def_arrays(ncid, [&
1814        nctkarr_t('ifc_matrix_cart_coord_short_range', "dp", &
1815        "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
1816      NCF_CHECK(ncerr)
1817    end if
1818 
1819    if (ifcana==1) then
1820      ncerr = nctk_def_arrays(ncid, [&
1821        nctkarr_t('ifc_local_vectors', "dp", "number_of_cartesian_directions, number_of_cartesian_directions, ifcout, natifc")])
1822      NCF_CHECK(ncerr)
1823    end if
1824 
1825    NCF_CHECK(nctk_set_datamode(ncid))
1826  end if
1827 #endif
1828 
1829  ABI_MALLOC(rsiaf,(3,3,ifcout1))
1830  ABI_MALLOC(sriaf,(3,3,ifcout1))
1831  ABI_MALLOC(vect,(3,3,ifcout1))
1832  ABI_MALLOC(indngb,(ifcout1))
1833  ABI_MALLOC(posngb,(3,ifcout1))
1834  ABI_MALLOC(wghia,(ifcout1))
1835 
1836  iatifc=0
1837 
1838  ! BIG loop on all generic atoms
1839  do ia=1,Ifc%natom
1840    if(atifc(ia)==1)then
1841 
1842      iatifc=iatifc+1
1843 
1844      ! First transform canonical coordinates to reduced coordinates
1845      do ii=1,3
1846        xred(ii)=Ifc%gprim(1,ii)*Ifc%rcan(1,ia)+Ifc%gprim(2,ii)*Ifc%rcan(2,ia)+Ifc%gprim(3,ii)*Ifc%rcan(3,ia)
1847      end do
1848 
1849      ! Then to cartesian coordinates
1850      ra(:)=xred(1)*Ifc%acell(1)*Ifc%rprim(:,1)+ xred(2)*Ifc%acell(2)*Ifc%rprim(:,2)+ xred(3)*Ifc%acell(3)*Ifc%rprim(:,3)
1851 
1852      ! This sorting algorithm is slow ...
1853      wkdist(:)=reshape(dist(ia,:,:),(/Ifc%natom*Ifc%nrpt/))
1854      do ii=1,Ifc%natom*Ifc%nrpt
1855        list(ii)=ii
1856      end do
1857      call sort_dp(Ifc%natom*Ifc%nrpt,wkdist,list,tol14)
1858 
1859      if (iout > 0) then
1860        write(iout, '(a)' )
1861        write(std_out,'(a,i4)' )' generic atom number',ia
1862        write(iout, '(a,i4)' )' generic atom number',ia
1863        write(std_out,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
1864        write(iout,'(a,3es16.8)' ) ' with cartesian coordinates',ra(1:3)
1865        write(iout, '(a)' )
1866      end if
1867 
1868      call ifc_getiaf(Ifc,ifcana,ifcout1,iout,ifc%zeff,ia,ra,list,dist,invdlt,&
1869                      detdlt,rsiaf,sriaf,vect,indngb,posngb)
1870 
1871      if (prt_ifc == 1) then
1872        do ii=1,ifcout1
1873          if (wkdist(ii) > maxdist_tdep) exit
1874        end do
1875        ii = ii - 1
1876        write(unit_tdep,"(1X,I10,15X,'How many neighbours does atom ',I3,' have')") ii, ia
1877 
1878        do ii=1,ifcout1
1879          ib = indngb(ii)
1880          irpt = (list(ii)-1)/Ifc%natom+1
1881          wghia(ii) = Ifc%wghatm(ia,ib,irpt)
1882          ! limit printing to maximum distance for tdep
1883          if (wkdist(ii) > maxdist_tdep) cycle
1884 
1885          !TDEP
1886          call int2char4(ii, str1)
1887          call int2char4(ia, str2)
1888          write(unit_tdep,"(1X,I10,15X,a,a,a,a)") ib, &
1889 &            'In the unit cell, what is the index of neighbour ', &
1890 &            trim(str1), " of atom ", trim(str2)
1891          ! The lattice vector needs to be in reduced coordinates?
1892          ! TODO: check whether this is correct for TDEP: might need just lattice
1893          ! vector part and not full vector, and could be in integers instead of
1894          ! cartesian vector...
1895          write (unit_tdep,'(3es28.16)') matmul(Ifc%rpt(1:3,irpt),Ifc%gprim)
1896 
1897          !AI2PS
1898          write(unit_ifc,'(i6,i6)') ia,ii
1899          write(unit_ifc,'(3es28.16)') posngb(1:3,ii)
1900          do nu=1,3
1901            !TDEp
1902            ! And the actual short ranged forceconstant: TODO: check if
1903            ! a transpose is needed or a swap between the nu and the mu
1904            !write(unit_tdep,'(3f28.16)') (sriaf(nu,mu,ii)*Ha_eV/amu_emass, mu=1, 3)
1905            write(unit_tdep,'(3f28.16)') (Ifc%short_atmfrc(mu,ia,nu,ib,irpt)*Ha_eV/Bohr_Ang**2, mu=1, 3)
1906 
1907            !AI2PS
1908            write(unit_ifc,'(3f28.16)')(rsiaf(nu,mu,ii),mu=1,3)
1909          end do
1910        end do
1911 
1912 #ifdef HAVE_NETCDF
1913        if (ncid /= nctk_noid) then
1914          NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_indices"), ia, start=[iatifc]))
1915          NCF_CHECK(nf90_put_var(ncid, vid("ifc_neighbours_indices"), indngb, start=[1,iatifc], count=[ifcout1,1]))
1916          NCF_CHECK(nf90_put_var(ncid, vid("ifc_distances"), wkdist(:ifcout1), start=[1,iatifc],count=[ifcout1,1]))
1917          ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord"), rsiaf, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
1918          NCF_CHECK(ncerr)
1919          NCF_CHECK(nf90_put_var(ncid, vid("ifc_atoms_cart_coord"), posngb, start=[1,1,iatifc], count=[3,ifcout1,1]))
1920          NCF_CHECK(nf90_put_var(ncid, vid("ifc_weights"), wghia, start=[1,iatifc], count=[ifcout1,1]))
1921 
1922          if (Ifc%dipdip==1) then
1923            ncerr = nf90_put_var(ncid, vid("ifc_matrix_cart_coord_short_range"), sriaf, &
1924              start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
1925            NCF_CHECK(ncerr)
1926          end if
1927          if (ifcana==1) then
1928            ncerr = nf90_put_var(ncid, vid("ifc_local_vectors"), vect, start=[1,1,1,iatifc], count=[3,3,ifcout1,1])
1929            NCF_CHECK(ncerr)
1930          end if
1931        end if
1932 #endif
1933      end if
1934    end if ! End the condition on atifc
1935  end do ! End Big loop on atoms in the unit cell, and corresponding test
1936 
1937 
1938 ! NB for future use: in TDEP the following can also be provided.
1939 !        ! Print some auxiliary information, if it is there. Such as norm of
1940 !        ! forceconstant per shell, which shells there are and so on.
1941 !        if ( fc%npairshells .gt. 0 .and. allocated(fc%pairshell) ) then
1942 !            write(u,"(1X,I10,15X,'Number of irreducible coordination shells')") fc%npairshells
1943 !            do i=1,fc%npairshells
1944 !                write(u,"(1X,I10,1X,F16.10,1X,F16.10,15X,'number atoms in shell, radius, norm of forceconstant',I0)") fc%pairshell(i)%n,fc%pairshell(i)%rad,fc%pairshell(i)%norm,i
1945 !            enddo
1946 !            do i=1,fc%npairshells
1947 !                do j=1,fc%pairshell(i)%n
1948 !                    write(u,"(1X,3(1X,F18.12),2(1X,I0))") lo_chop(matmul(p%inv_latticevectors,fc%pairshell(i)%vec(:,j)),lo_sqtol),fc%pairshell(i)%atind(j),fc%pairshell(i)%pairind(j)
1949 !                enddo
1950 !            enddo
1951 !        endif
1952 
1953  if (prt_ifc == 1) then
1954    close(unit_ifc)
1955    close(unit_tdep)
1956 
1957    if (open_file('infile.lotosplitting_ABINIT', message, newunit=unit_tdep, status="replace") /= 0) then
1958      ABI_ERROR(message)
1959    end if
1960    write(unit_tdep,'(3es28.16)') dielt(:,1)
1961    write(unit_tdep,'(3es28.16)') dielt(:,2)
1962    write(unit_tdep,'(3es28.16)') dielt(:,3)
1963    do ia = 1, Ifc%natom
1964      do ii = 1, 3
1965        write(unit_tdep,'(3es28.16)') ifc%zeff(:,ii,ia)
1966      end do
1967    end do
1968    close(unit_tdep)
1969  end if
1970 
1971  ABI_FREE(rsiaf)
1972  ABI_FREE(sriaf)
1973  ABI_FREE(vect)
1974  ABI_FREE(indngb)
1975  ABI_FREE(posngb)
1976  ABI_FREE(dist)
1977  ABI_FREE(list)
1978  ABI_FREE(wkdist)
1979  ABI_FREE(wghia)
1980 
1981 #ifdef HAVE_NETCDF
1982 contains
1983  integer function vid(vname)
1984    character(len=*),intent(in) :: vname
1985    vid = nctk_idname(ncid, vname)
1986  end function vid
1987 #endif
1988 
1989 end subroutine ifc_write

m_ifc/omega_decomp [ Functions ]

[ Top ] [ m_ifc ] [ Functions ]

NAME

  omega_decomp

FUNCTION

 Compute and return the eigenvalues (frequencies) of the short-range and
 long-range part of the dynamical matrix  See Europhys. Lett. 33 p.713 (1996) for details.
 (included by U. Aschauer and EB)

INPUTS

  argin(sizein)=description

OUTPUT

  argout(sizeout)=description

SIDE EFFECTS

SOURCE

2344 subroutine omega_decomp(amu,natom,ntypat,typat,dynmatfl,dynmatsr,dynmatlr,iqpt,nqpt,eigenvec)
2345 
2346 !Arguments -------------------------------
2347 !scalars
2348  integer,intent(in) :: natom,ntypat
2349  integer,intent(in) :: iqpt,nqpt
2350 !arrays
2351  integer,intent(in) :: typat(natom)
2352  real(dp),intent(in) :: amu(ntypat)
2353  real(dp),intent(inout) :: dynmatfl(2,3,natom,3,natom,nqpt)
2354  real(dp),intent(inout) :: dynmatsr(2,3,natom,3,natom,nqpt)
2355  real(dp),intent(inout) :: dynmatlr(2,3,natom,3,natom,nqpt)
2356  real(dp),intent(in)    :: eigenvec(2*3*natom*3*natom)
2357 
2358 !Local variables -------------------------
2359 !scalars
2360  integer :: i1,i2,idir1,idir2,imode,ipert1,ipert2,index1,index2
2361  real(dp),parameter :: break_symm=1.0d-12
2362  real(dp) :: fac
2363 !arrays
2364  real(dp) :: nearidentity(3,3)
2365  real(dp) :: omegafl, omegasr, omegalr
2366  real(dp) :: sumfl,sumlr,sumsr,asr
2367 ! *********************************************************************
2368 
2369 !write(ab_out,*)''
2370 !write(std_out,*) 'SR/LR decomposition: enter for wavevector number :',iqpt
2371 
2372 !apply asr (note the lr part is already asred by construction in mkifc9)
2373  do ipert1=1,natom
2374    do idir1=1,3
2375      do idir2=1,3
2376        asr=0.0d0
2377        do ipert2=1,natom
2378          asr=asr+dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)
2379        end do
2380        dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatfl(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
2381        dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)=dynmatsr(1,idir1,ipert1,idir2,ipert1,iqpt)-asr
2382      end do
2383    end do
2384  end do
2385 
2386 
2387 !This slight breaking of the symmetry allows the
2388 !results to be more portable between machines
2389  nearidentity(:,:)=1.0
2390  nearidentity(1,1)=1.0+break_symm
2391  nearidentity(3,3)=1.0-break_symm
2392 
2393 
2394 !Include Mass
2395  do ipert1=1,natom
2396    do ipert2=1,natom
2397 
2398      fac=1.0d0/sqrt(amu(typat(ipert1))*amu(typat(ipert2)))/amu_emass
2399 
2400      do idir1=1,3
2401        do idir2=1,3
2402 
2403          dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2404 &         dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2405 &         fac*nearidentity(idir1,idir2)
2406 
2407          dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2408 &         dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2409 &         fac*nearidentity(idir1,idir2)
2410 
2411          dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2412 &         dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)*&
2413 &         fac*nearidentity(idir1,idir2)
2414 
2415          ! This is to break slightly the translation invariance, and make
2416          ! the automatic tests more portable
2417          if(ipert1==ipert2 .and. idir1==idir2)then
2418            dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2419 &           dynmatfl(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2420 &           break_symm*natom/amu_emass/idir1*0.01d0
2421 
2422            dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2423 &           dynmatsr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2424 &           break_symm*natom/amu_emass/idir1*0.01d0
2425 
2426            dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)=&
2427 &           dynmatlr(1,idir1,ipert1,idir2,ipert2,iqpt)+&
2428 &           break_symm*natom/amu_emass/idir1*0.01d0
2429          end if
2430 
2431        end do
2432      end do
2433    end do
2434  end do
2435 
2436 !Calculation of <eigvec|Dyn_tot,Dyn_SR,Dyn_LR|eigenvec>=omega**2
2437 
2438 !write(ab_out,*)''
2439 !write(ab_out,*)'==============================================================================='
2440  write(ab_out,*)''
2441  write(ab_out,*) 'Long-Range/Short-Range decomposed phonon freq. (cm-1)**2'
2442  write(ab_out,*) 'at wavevector number:',iqpt
2443  write(ab_out,*)''
2444  write(ab_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
2445  write(std_out,'(a13,1x,a16,2x,a16,2x,a16)') ' Mode number.','tot**2','SR**2','LR**2'
2446 !write(ab_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
2447 !write(std_out,'(a12,2x,a10,2x,a10,2x,a10,2x,a16,2x,a16,2x,a16)') 'Mode number.','tot','SR','LR','tot**2','SR**2','LR**2'
2448 
2449  do imode=1,3*natom
2450    sumfl=zero; sumlr=zero; sumsr=zero
2451 
2452    do ipert1=1,natom
2453      do ipert2=1,natom
2454        do i1=1,3
2455          do i2=1,3
2456 
2457            index1=i1+(ipert1-1)*3+3*natom*(imode-1)
2458            index2=i2+(ipert2-1)*3+3*natom*(imode-1)
2459            ! MG FIXME: I don't think these expressions are correct when q != 0
2460            ! We should also include the imaginary part
2461 
2462            sumfl = sumfl + eigenvec(2*index1-1) * dynmatfl(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2463            sumlr = sumlr + eigenvec(2*index1-1) * dynmatlr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2464            sumsr = sumsr + eigenvec(2*index1-1) * dynmatsr(1,i1,ipert1,i2,ipert2,iqpt) * eigenvec(2*index2-1)
2465          end do
2466        end do
2467      end do
2468    end do
2469 
2470    sumfl = sumfl * Ha_cmm1 * Ha_cmm1
2471    sumsr = sumsr * Ha_cmm1 * Ha_cmm1
2472    sumlr = sumlr * Ha_cmm1 * Ha_cmm1
2473 
2474 !  Compute omega=sqrt(omega**2)
2475    if(sumfl>=1.0d-16)then
2476      omegafl=sqrt(sumfl)
2477    else if(sumfl>=-1.0d-16)then
2478      omegafl=zero
2479    else
2480      omegafl=-sqrt(-sumfl)
2481    end if
2482 
2483    if(sumsr>=1.0d-16)then
2484      omegasr=sqrt(sumsr)
2485    else if(sumsr>=-1.0d-16)then
2486      omegasr=zero
2487    else
2488      omegasr=-sqrt(-sumsr)
2489    end if
2490 
2491    if(sumlr>=1.0d-16)then
2492      omegalr=sqrt(sumlr)
2493    else if(sumlr>=-1.0d-16)then
2494      omegalr=zero
2495    else
2496      omegalr=-sqrt(-sumlr)
2497    end if
2498 
2499 !  Output
2500    write(ab_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr  !vz_d
2501    write(std_out,'(i4,10x,s,f16.4,2x,f16.4,2x,f16.4)') imode,sumfl,sumsr,sumlr  !vz_d
2502 !  write(ab_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
2503 !  write(std_out,'(i4,8x,f10.4,2x,f10.4,2x,f10.4,2x,s,f16.6,2x,f16.6,2x,f16.6)') imode,omegafl,omegasr,omegalr,sumfl,sumsr,sumlr
2504  end do
2505 
2506 end subroutine omega_decomp