LCOV - code coverage report
Current view: top level - src/41_geometry - m_supercell.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.2 % 225 194
Test Date: 2026-09-21 19:39:32 Functions: 81.2 % 16 13

            Line data    Source code
       1              : !!****m* ABINIT/m_supercell
       2              : !! NAME
       3              : !! m_supercell
       4              : !!
       5              : !! FUNCTION
       6              : !! Module for using a supercell, in particular for phonon displacement freezing.
       7              : !! Container type is defined, and destruction, print subroutines as well as the central supercell_init
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2010-2026 ABINIT group (MJV, DJA)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public Licence, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      15              : !!
      16              : !! SOURCE
      17              : 
      18              : #if defined HAVE_CONFIG_H
      19              : #include "config.h"
      20              : #endif
      21              : 
      22              : #include "abi_common.h"
      23              : 
      24              : module m_supercell
      25              : 
      26              :  use defs_basis
      27              :  use m_errors
      28              :  use m_abicore
      29              : 
      30              :  use m_matrix,        only : matr3inv
      31              :  use m_copy,          only : alloc_copy
      32              :  use m_io_tools,      only : open_file
      33              :  use m_fstrings,      only : int2char4, write_num, itoa, sjoin
      34              :  use m_numeric_tools, only : isdiagmat
      35              : 
      36              :  implicit none
      37              : 
      38              :  private
      39              : 
      40              : !!***
      41              : 
      42              : !!****t* m_supercell/supercell_type
      43              : !! NAME
      44              : !! supercell_type
      45              : !!
      46              : !! FUNCTION
      47              : !! structure for a supercell constructed from a basic rprimd and xcart, with indexing to original atoms
      48              : !! The supercell may not be oriented the same way as the original cell, if you can reduce it by symmetry
      49              : !!
      50              : !! SOURCE
      51              : 
      52              :  type, public :: supercell_type
      53              :    integer :: natom_primcell
      54              :      ! number of atoms in primitive cell
      55              :    integer :: natom
      56              :      ! number of atoms in supercell
      57              :    integer :: ntypat
      58              :      ! number of atom types
      59              :    integer :: ncells
      60              :      ! number of unit cells in supercell
      61              :    integer :: rlatt(3,3)
      62              :      ! matrix for multiplicity of supercell (for the time being must be diagonal)
      63              :    real(dp) :: rprimd(3,3)
      64              :      ! new lattice vectors for supercell
      65              :    real(dp) :: qphon(3)
      66              :      ! phonon q vector used to generate scell, if any
      67              :    character(len=3) :: xyz_order
      68              :      ! Order used to build the supercell.
      69              :    real(dp), allocatable :: xcart(:,:)
      70              :      ! (3, natom) Cartesian positions of atoms
      71              :    real(dp), allocatable :: xcart_ref(:,:)
      72              :      ! (3, natom) equilibrium Cartesian positions of atoms
      73              :    integer, allocatable :: atom_indexing(:)
      74              :      ! (natom) indexes original atom: 1..natom_primcell
      75              :    integer, allocatable :: uc_indexing(:,:)
      76              :      ! (3, natom) indexes unit cell atom is.
      77              :    integer, allocatable :: typat(:)
      78              :      ! (natom) type of each atom in the supercell.
      79              :    real(dp), allocatable :: znucl(:)
      80              :      ! (ntypat) nuclear charges of species
      81              :    integer, allocatable :: rvecs(:,:)
      82              :      ! supercell vectors
      83              : 
      84              :  contains
      85              :    procedure :: init_for_qpt => supercell_init_for_qpt
      86              :    procedure :: init => supercell_init
      87              :    procedure :: freeze_displ => supercell_freeze_displ
      88              :    procedure :: copy => supercell_copy
      89              :    procedure :: free => supercell_free
      90              :    procedure :: print_for_qpt => supercell_print_for_qpt
      91              :    procedure :: print_abinit => supercell_print_abinit
      92              :    procedure :: write_xsf => supercell_write_xsf
      93              :  end type supercell_type
      94              : 
      95              :  public :: distance_supercell
      96              :  public :: findBound_supercell
      97              :  public :: getPBCIndexes_supercell
      98              :  public :: mksupercell  !  computes atomic positons, magnetic ordering of supercell
      99              : !!***
     100              : 
     101              : CONTAINS  !===========================================================================================
     102              : 
     103              : !!****f* m_supercell/supercell_init_for_qpt
     104              : !!
     105              : !! NAME
     106              : !! supercell_init_for_qpt
     107              : !!
     108              : !! FUNCTION
     109              : !! Initialize scell structure, from unit cell vectors, and atoms, based on qpoint chosen
     110              : !!
     111              : !! INPUTS
     112              : !! natom_primcell = number of atoms in primitive cell
     113              : !! qphon(3) = phonon wavevector
     114              : !!      find smallest supercell which will accomodate phonon qphon = (1/2,1/2,1/2)
     115              : !! rprimd_primcell(3,3) = real space lattice vectors (bohr)
     116              : !! typat_primcell = types of atoms
     117              : !! xcart_primcell(3,natom) = cartesian positions of atoms in primitive cell
     118              : !! znucl = nuclear charges for all species
     119              : !! ordering = if true,  typat will be 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 ....
     120              : !!            if false, typat will be 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 ....
     121              : !!
     122              : !! OUTPUT
     123              : !! scell = supercell structure to be initialized
     124              : !!
     125              : !! SOURCE
     126              : 
     127            6 : subroutine supercell_init_for_qpt(scell, natom_primcell, qphon, rprimd_primcell, &
     128            6 :                                   typat_primcell, xcart_primcell, znucl, ordering)
     129              : 
     130              : !Arguments ------------------------------------
     131              : !scalars
     132              :  class(supercell_type), intent(out) :: scell
     133              :  integer, intent(in) :: natom_primcell
     134              :  logical,optional,intent(in) :: ordering
     135              : !arrays
     136              :  integer , intent(in) :: typat_primcell(natom_primcell)
     137              :  real(dp), intent(in) :: qphon(3)
     138              :  real(dp), intent(in) :: znucl(:)
     139              :  real(dp), intent(in) :: rprimd_primcell(3,3)
     140              :  real(dp), intent(in) :: xcart_primcell(3,natom_primcell)
     141              : 
     142              : !Local variables-------------------------------
     143              : !scalar
     144              :  integer :: ii, maxsc, iscmult
     145              :  real(dp) :: qbymult
     146              : !arrays
     147              :  integer :: rlatt(3,3) ! number of primitive cells in each direction for the supercell
     148              :  character(len=500) :: msg
     149              : ! *************************************************************************
     150              : 
     151              : ! maximum number of unit cells in a given direction
     152            6 :  maxsc = 10
     153              : 
     154              : ! find smallest supercell which will accomodate phonon.
     155              : ! FIXME: for the moment, just get smallest multiple along each direction, with an upper bound
     156            6 :  rlatt = 0
     157            6 :  rlatt(1,1) = -1
     158            6 :  rlatt(2,2) = -1
     159            6 :  rlatt(3,3) = -1
     160           24 :  do ii=1,3
     161           21 :    do iscmult=1,maxsc
     162           21 :      qbymult = qphon(ii)*iscmult
     163           21 :      if (abs(qbymult - int(qbymult)) < tol10) then
     164           18 :        rlatt(ii,ii) = iscmult
     165           18 :        exit
     166              :      end if
     167              :    end do
     168           24 :    if (rlatt(ii,ii) == -1) then
     169            0 :      write(msg,'(a,I0,a,I0,2a,3E20.10)')' No supercell found with less than ', &
     170            0 :            maxsc,' unit cells in direction ', ii, ch10, ' qphon = ', qphon
     171            0 :      ABI_ERROR(msg)
     172              :    end if
     173              :  end do
     174              : 
     175            6 :  if (present(ordering)) then
     176            0 :    call scell%init(natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl, ordering)
     177              :  else
     178            6 :    call scell%init(natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl)
     179              :  end if
     180              : 
     181           24 :  scell%qphon = qphon
     182              : 
     183            6 : end subroutine supercell_init_for_qpt
     184              : !!***
     185              : 
     186              : !!****f* m_supercell/supercell_init
     187              : !! NAME
     188              : !! supercell_init
     189              : !!
     190              : !! FUNCTION
     191              : !! Initialize scell structure, from unit cell vectors, and atoms, based on rlatt multiplicity matrix
     192              : !!
     193              : !! INPUTS
     194              : !! natom_primcell = number of atoms in primitive cell
     195              : !! rlatt(3,3) = multiplicity of primtive unit cells in supercell
     196              : !! rprimd_primcell(3,3) = real space lattice vectors (bohr)
     197              : !! typat_primcell(natom) = types of all atoms in primitive cell
     198              : !! xcart_primcell(3,natom) = cartesian positions of atoms in primitive cell
     199              : !! znucl = nuclear charges for all species
     200              : !! [ordering] = if true,  typat will be 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 ....
     201              : !!              if false, typat will be 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 ....
     202              : !! [xyz_order]= Order used to build the supercell.
     203              : !!  "zyx" if one should move along z first.
     204              : !!  "xyz" if one should move along x first. This value should be used for plotting purposes
     205              : !!
     206              : !! OUTPUT
     207              : !! scell = supercell structure to be initialized
     208              : !!
     209              : !! SOURCE
     210              : 
     211          212 : subroutine supercell_init(scell, natom_primcell, rlatt, rprimd_primcell, typat_primcell, xcart_primcell, znucl, &
     212              :                           ordering, xyz_order) ! optional
     213              : 
     214              : !Arguments ------------------------------------
     215              : !scalars
     216              :  class(supercell_type), intent(out) :: scell
     217              :  integer, intent(in) :: natom_primcell
     218              :  logical,optional,intent(in) :: ordering
     219              :  character(len=*),optional,intent(in) :: xyz_order
     220              : !arrays
     221              :  integer , intent(in) :: rlatt(3,3)
     222              :  integer , intent(in) :: typat_primcell(natom_primcell)
     223              :  real(dp), intent(in) :: znucl(:)
     224              :  real(dp), intent(in) :: rprimd_primcell(3,3)
     225              :  real(dp), intent(in) :: xcart_primcell(3,natom_primcell)
     226              : 
     227              : !Local variables-------------------------------
     228              : !scalars
     229              :  integer :: iatom_supercell, i1,i2,i3, iatom, icell
     230              : ! *************************************************************************
     231              : 
     232          212 :  if (.not. isdiagmat(rlatt)) then
     233            0 :    ABI_ERROR('rlatt is not diagonal.')
     234              :  end if
     235              : 
     236          212 :  scell%xyz_order = "zyx"; if (present(xyz_order)) scell%xyz_order = xyz_order(1:3)
     237              : 
     238          212 :  scell%natom_primcell = natom_primcell
     239         2756 :  scell%rlatt = rlatt
     240          212 :  scell%ncells = rlatt(1,1)*rlatt(2,2)*rlatt(3,3)
     241          848 :  scell%rprimd(:,1) = rprimd_primcell(:,1) * rlatt(1,1)
     242          848 :  scell%rprimd(:,2) = rprimd_primcell(:,2) * rlatt(2,2)
     243          848 :  scell%rprimd(:,3) = rprimd_primcell(:,3) * rlatt(3,3)
     244              : 
     245              :  !call metric(scell%gmet, scell%gprimd, -1, scell%rmet, scell%rprimd, scell%ucvol)
     246              : 
     247          212 :  scell%ntypat = size(znucl)
     248          636 :  ABI_MALLOC(scell%znucl,(scell%ntypat))
     249          751 :  scell%znucl(:) = znucl(:)
     250              : 
     251              :  ! number of atoms in full supercell
     252          212 :  scell%natom= natom_primcell*scell%ncells
     253          636 :  ABI_MALLOC(scell%xcart,(3,scell%natom))
     254          636 :  ABI_MALLOC(scell%xcart_ref,(3,scell%natom))
     255          636 :  ABI_MALLOC(scell%typat,(scell%natom))
     256          636 :  ABI_MALLOC(scell%atom_indexing,(scell%natom))
     257          636 :  ABI_MALLOC(scell%uc_indexing,(3,scell%natom))
     258          636 :  ABI_MALLOC(scell%rvecs, (3, scell%ncells))
     259              : 
     260          212 :  iatom_supercell = 0; icell =0
     261              : 
     262          199 :  select case (scell%xyz_order)
     263              :  case ("zyx")
     264              :    ! legacy mode.
     265          604 :    do i1 = 1, rlatt(1,1)
     266         1607 :      do i2 = 1, rlatt(2,2)
     267         3523 :        do i3 = 1, rlatt(3,3)
     268         3118 :          call build_()
     269              :        end do
     270              :      end do
     271              :    end do
     272              : 
     273              :  case ("xyz")
     274           90 :    do i3 = 1, rlatt(3,3)
     275          749 :      do i2 = 1, rlatt(2,2)
     276         7965 :        do i1 = 1, rlatt(1,1)
     277         7888 :          call build_()
     278              :        end do
     279              :      end do
     280              :    end do
     281              : 
     282              :  case default
     283          212 :    ABI_ERROR(sjoin("Invalid xyz_order", scell%xyz_order))
     284              :  end select
     285              : 
     286          212 :  ABI_CHECK_IEQ(iatom_supercell, scell%natom, "iatom_supercell /= scell%natom")
     287              : 
     288       107088 :  scell%xcart = scell%xcart_ref
     289          848 :  scell%qphon = zero
     290              : 
     291          212 :  if (present(ordering)) then
     292            0 :    if (ordering) call order_supercell_typat(scell)
     293              :  end if
     294              : 
     295              : contains
     296         9344 :  subroutine build_()
     297        37376 :   icell = icell+1; scell%rvecs(:,icell) = [i1-1, i2-1, i3-1]
     298        36010 :   do iatom = 1, natom_primcell
     299        26666 :     iatom_supercell = iatom_supercell + 1
     300       106664 :     scell%uc_indexing(:,iatom_supercell) = [i1-1, i2-1, i3-1]
     301              :     scell%xcart_ref(:,iatom_supercell) = xcart_primcell(:,iatom) &
     302       586652 :        + matmul(rprimd_primcell,scell%uc_indexing(:,iatom_supercell))
     303        26666 :     scell%atom_indexing(iatom_supercell) = iatom
     304        36010 :     scell%typat(iatom_supercell) = typat_primcell(iatom)
     305              :   end do
     306         9344 :  end subroutine build_
     307              : 
     308              : end subroutine supercell_init
     309              : !!***
     310              : 
     311              : !!****f* m_supercell/order_supercell_typat
     312              : !!
     313              : !! NAME
     314              : !! order_supercell_typat
     315              : !!
     316              : !! FUNCTION
     317              : !! Re-order atoms in place for types
     318              : !!
     319              : !! INPUTS
     320              : !! scell = supercell structure with reference atomic positions etc...
     321              : !!
     322              : !! OUTPUT
     323              : !! scell = supercell structure: typat, xcart and so on will be updated
     324              : !!
     325              : !! SOURCE
     326              : 
     327            0 : subroutine order_supercell_typat(scell)
     328              : 
     329              : !Arguments ------------------------------------
     330              : !scalars
     331              :  class(supercell_type), intent(inout) :: scell
     332              : 
     333              : !Local variables-------------------------------
     334              :  integer :: itypat, iatom_supercell, iatom
     335            0 :  type(supercell_type) :: scell_tmp
     336              : ! *************************************************************************
     337              : 
     338            0 :  call scell%copy(scell_tmp)
     339              : 
     340            0 :  iatom_supercell = 0
     341            0 :  do itypat = 1, scell%ntypat
     342            0 :    do iatom = 1, scell%natom
     343            0 :      if (scell_tmp%typat(iatom) /= itypat) cycle
     344            0 :      iatom_supercell = iatom_supercell + 1
     345            0 :      scell%xcart(:,iatom_supercell) = scell_tmp%xcart(:,iatom)
     346            0 :      scell%xcart_ref(:,iatom_supercell) = scell_tmp%xcart_ref(:,iatom)
     347            0 :      scell%atom_indexing(iatom_supercell) = scell_tmp%atom_indexing(iatom)
     348            0 :      scell%uc_indexing(:,iatom_supercell) = scell_tmp%uc_indexing(:,iatom)
     349            0 :      scell%typat(iatom_supercell) = scell_tmp%typat(iatom)
     350              :    end do
     351              :  end do
     352              : 
     353            0 :  call scell_tmp%free()
     354              : 
     355            0 : end subroutine order_supercell_typat
     356              : !!***
     357              : 
     358              : 
     359              : !!****f* m_supercell/freeze_displ_supercell
     360              : !!
     361              : !! NAME
     362              : !! freeze_displ_supercell
     363              : !!
     364              : !! FUNCTION
     365              : !! Freeze a specific displacement phonon field into the supercell scell
     366              : !!
     367              : !! INPUTS
     368              : !! displ = phonon displacement vectors for this mode
     369              : !! freeze_displ = desired amplitude for phonon displacement along displ.
     370              : !!    for thermal displacement use sqrt[ (1/2 + bose_einstein(freq,T)) / freq ]
     371              : !! scell = supercell structure with reference atomic positions etc...
     372              : !!
     373              : !! OUTPUT
     374              : !! scell = supercell structure: xcart will be updated with phonon displacement
     375              : !!
     376              : !! SOURCE
     377              : 
     378         1446 : subroutine supercell_freeze_displ(scell, displ, freeze_displ)
     379              : 
     380              : !Arguments ------------------------------------
     381              : !scalars
     382              :  class(supercell_type), intent(inout) :: scell
     383              :  real(dp), intent(in) :: freeze_displ
     384              : !arrays
     385              :  real(dp), intent(in) :: displ(2,3*scell%natom_primcell)
     386              : 
     387              : !Local variables-------------------------------
     388              :  integer :: iatom, ipratom
     389              :  complex(dp) :: expqdotr, j=cmplx(zero,one)
     390              :  complex(dp) :: phase
     391         2892 :  complex(dp) :: zdispl(3,scell%natom_primcell)
     392              : ! *************************************************************************
     393              : 
     394              :  zdispl = (cmplx(reshape(displ(1,:), (/3,scell%natom_primcell/)),&
     395        41358 :                  reshape(displ(2,:), (/3,scell%natom_primcell/))))
     396              : 
     397              :  ! fix gauge by imposing real displacement for first atom in first direction
     398              :  ! multiply by normalized complex conjugate of first element
     399              :  ! NB 6 March 2018: this may be imposing a positive (not just real) displacement for 1st atom along x!!!
     400              :  ! That might be problematic below, though for the thermal displacement method freeze_displ swaps sign for each new mode
     401         1446 :  phase = cmplx(one,zero)
     402         1446 :  if (abs(zdispl(1,1)) > tol10) then
     403          697 :    phase = conjg(zdispl(1,1)) / abs(zdispl(1,1))
     404              :  end if
     405              : 
     406        69234 :  do iatom = 1, scell%natom
     407              :    expqdotr = exp(j*two_pi*(scell%qphon(1)*scell%uc_indexing(1,iatom) &
     408              :                            +scell%qphon(2)*scell%uc_indexing(2,iatom) &
     409        67788 :                            +scell%qphon(3)*scell%uc_indexing(3,iatom)))
     410              : 
     411              : ! this is offset in zdispl vector due to primitive cell atom position
     412        67788 :    ipratom = scell%atom_indexing(iatom)
     413              : 
     414              : !add real part of displacement times Bloch phase
     415              :    scell%xcart(:,iatom) = scell%xcart(:,iatom) &
     416       272598 : &        + freeze_displ * real(expqdotr * zdispl(:,ipratom) * phase)
     417              : 
     418              : !   scell%xcart(:,iatom) = scell%xcart(:,iatom) &
     419              : !&        + freeze_displ * cos(qdotr) * displ(1,ipratom+1:ipratom+3) &
     420              : !&        - freeze_displ * sin(qdotr) * displ(2,ipratom+1:ipratom+3)
     421              :  end do
     422              : 
     423         1446 : end subroutine supercell_freeze_displ
     424              : !!***
     425              : 
     426              : !****f* m_supercell/supercell_print_for_qpt
     427              : !!
     428              : !! NAME
     429              : !! supercell_print_for_qpt
     430              : !!
     431              : !! FUNCTION
     432              : !! output atomic positions, supercell vectors, etc... to a file. single qpoint and mode.
     433              : !!
     434              : !! INPUTS
     435              : !! freq = phonon frequency for mode jmode
     436              : !! jmode = mode which has been frozen into xcart contained in scell
     437              : !! outfile_radix = radix of file name to be written to
     438              : !!
     439              : !! OUTPUT
     440              : !! printing to file
     441              : !!
     442              : !! SOURCE
     443              : 
     444           36 : subroutine supercell_print_for_qpt(scell, freq, jmode, outfile_radix)
     445              : 
     446              : !Arguments ------------------------------------
     447              : !scalars
     448              :  class(supercell_type), intent(in) :: scell
     449              :  real(dp), intent(in) :: freq
     450              :  integer, intent(in) :: jmode
     451              :  character(len=*), intent(in) :: outfile_radix
     452              : 
     453              : !Local variables-------------------------------
     454              : !scalar
     455              :  character(len=fnlen) :: filename
     456              :  character(len=10) :: jmodestring
     457              :  character(len=80) :: title1, title2
     458              :  character(len=5) :: qphonstring1, qphonstring2, qphonstring3
     459              : ! *************************************************************************
     460              : 
     461              :  ! add suffix with mode and qpoint
     462           36 :  call int2char4(jmode, jmodestring)
     463           36 :  ABI_CHECK((jmodestring(1:1)/='#'),'Bug: string length too short!')
     464              : 
     465              :  ! qphonstring should be like 0.000_0.000_0.000
     466           36 :  call write_num(scell%qphon(1),qphonstring1,'(F5.3)')
     467           36 :  call write_num(scell%qphon(2),qphonstring2,'(F5.3)')
     468           36 :  call write_num(scell%qphon(3),qphonstring3,'(F5.3)')
     469              :  filename = trim(outfile_radix) // "_qpt_" // qphonstring1 // "_" // qphonstring2 // &
     470           36 :                  "_" // qphonstring3 // "_mode_" // trim(jmodestring)
     471              : 
     472           36 :  write (title1, '(a,3E20.10)') '# phonon q point : ', scell%qphon
     473           36 :  write (title2, '(a,I7,a,E20.10)') '# phonon mode number : ', jmode, ' frequency ', freq
     474              : 
     475           36 :  call scell%print_abinit(filename, title1, title2)
     476              : 
     477           36 : end subroutine supercell_print_for_qpt
     478              : !!***
     479              : 
     480              : !****f* m_supercell/supercell_print_abinit
     481              : !! NAME
     482              : !! supercell_print_abinit
     483              : !!
     484              : !! FUNCTION
     485              : !! output atomic positions, supercell vectors, etc... to a file
     486              : !! in Abinit input format.
     487              : !!
     488              : !! INPUTS
     489              : !! filename = filename
     490              : !! title1 = first line of description of contents
     491              : !! title2 = second line of description of contents
     492              : !! scell = supercell structure with data to be output
     493              : !!
     494              : !! OUTPUT
     495              : !! printing to file
     496              : !!
     497              : !! SOURCE
     498              : 
     499           46 : subroutine supercell_print_abinit(scell, filename, title1, title2)
     500              : 
     501              : !Arguments ------------------------------------
     502              : !scalars
     503              :  class(supercell_type), intent(in) :: scell
     504              :  character(len=fnlen), intent(in) :: filename
     505              :  character(len=80), intent(in) :: title1
     506              :  character(len=80), intent(in) :: title2
     507              : 
     508              : !Local variables-------------------------------
     509              : !scalar
     510              :  integer :: scunit, iatom
     511              :  character(len=500) :: msg
     512              :  real(dp) :: xred(3), gprimd(3,3)
     513              : ! *************************************************************************
     514              : 
     515           46 :  if (open_file(filename, msg, newunit=scunit, status="unknown", action="write") /= 0) then
     516            0 :    ABI_ERROR(msg)
     517              :  end if
     518              : 
     519              :  ! print header
     520           46 :  write (scunit, '(a)') '#'
     521           46 :  write (scunit, '(a)') '# anaddb file with frozen phonon mode in supercell'
     522           46 :  write (scunit, '(a)') '# !!!   Do not forget to adjust nband   !!! '
     523           46 :  write (scunit, '(a)') '#'
     524           46 :  write (scunit, '(a)') title1
     525           46 :  write (scunit, '(a)') title2
     526           46 :  write (scunit, '(a,3(3I7,2x))') '# supercell rlatt is ', scell%rlatt
     527           46 :  write (scunit, '(a,I7,a)') '# and has ', scell%ncells, ' primitive unit cells '
     528           46 :  write (scunit, '(a)') '#'
     529           46 :  write (scunit, '(a)') '# lattice vectors for supercell :'
     530           46 :  write (scunit, '(a,I7)') 'natom ', scell%natom
     531           46 :  write (scunit, *)
     532           46 :  write (scunit, '(a)') 'znucl '
     533          114 :  do iatom = 1, size(scell%znucl)
     534           68 :    write (scunit, '(I5)', ADVANCE="NO") int(scell%znucl(iatom))
     535          114 :    if (mod(iatom,6) == 0) write (scunit, *)
     536              :  end do
     537           46 :  write (scunit, *)
     538           46 :  write (scunit, *)
     539           46 :  write (scunit, '(a,I7)') 'ntypat', scell%ntypat
     540           46 :  write (scunit, '(a)') 'typat '
     541          634 :  do iatom = 1, scell%natom
     542          588 :    write (scunit, '(I5)', ADVANCE="NO") scell%typat(iatom)
     543          634 :    if (mod(iatom,6) == 0) write (scunit, *)
     544              :  end do
     545           46 :  write (scunit, *)
     546           46 :  write (scunit, '(a)') 'acell 1.0 1.0 1.0'
     547           46 :  write (scunit, '(a)') 'rprim'
     548           46 :  write (scunit, '(3E20.10)') scell%rprimd(:,1)
     549           46 :  write (scunit, '(3E20.10)') scell%rprimd(:,2)
     550           46 :  write (scunit, '(3E20.10)') scell%rprimd(:,3)
     551           46 :  write (scunit, *)
     552           46 :  write (scunit, '(a)') 'xcart'
     553          634 :  do iatom = 1, scell%natom
     554          634 :    write (scunit, '(3E20.10)') scell%xcart(:,iatom)
     555              :  end do
     556              :  ! for information, also print xred for atoms inside full supercell
     557           46 :  call matr3inv(scell%rprimd, gprimd)
     558              :  ! TODO: check this transpose is correct in some asymetric case
     559         1196 :  gprimd = transpose(gprimd)
     560           46 :  write (scunit, '(a)') '# for information, add xred as well'
     561           46 :  write (scunit, '(a)') '# xred'
     562          634 :  do iatom = 1, scell%natom
     563         7644 :    xred = matmul (gprimd, scell%xcart(:,iatom))
     564          634 :    write (scunit, '(a, 3E20.10)') '#  ', xred
     565              :  end do
     566              : 
     567              :  ! close file
     568           46 :  close(scunit)
     569              : 
     570           46 : end subroutine supercell_print_abinit
     571              : !!***
     572              : 
     573              : !****f* m_supercell/supercell_copy
     574              : !!
     575              : !! NAME
     576              : !! supercell_copy
     577              : !!
     578              : !! FUNCTION
     579              : !! copy supercell structure
     580              : !!
     581              : !! INPUTS
     582              : !! scell_in = supercell structure with data to copy
     583              : !!
     584              : !! OUTPUT
     585              : !! scell = supercell structure with data to be output
     586              : !!
     587              : !! SOURCE
     588              : 
     589          105 : subroutine supercell_copy(scell_in, scell_copy)
     590              : 
     591              : !Arguments ------------------------------------
     592              :  class(supercell_type), intent(in) :: scell_in
     593              :  class(supercell_type), intent(inout) :: scell_copy
     594              : ! *************************************************************************
     595              : 
     596          105 :  call scell_copy%free()
     597              : 
     598          105 :  scell_copy%natom_primcell = scell_in%natom_primcell
     599          105 :  scell_copy%natom = scell_in%natom
     600          105 :  scell_copy%ntypat = scell_in%ntypat
     601          105 :  scell_copy%ncells = scell_in%ncells
     602         1365 :  scell_copy%rlatt = scell_in%rlatt
     603         1365 :  scell_copy%rprimd = scell_in%rprimd
     604          420 :  scell_copy%qphon = scell_in%qphon
     605          105 :  call alloc_copy(scell_in%xcart        , scell_copy%xcart)
     606          105 :  call alloc_copy(scell_in%xcart_ref    , scell_copy%xcart_ref)
     607          105 :  call alloc_copy(scell_in%atom_indexing, scell_copy%atom_indexing)
     608          105 :  call alloc_copy(scell_in%uc_indexing  , scell_copy%uc_indexing)
     609          105 :  call alloc_copy(scell_in%typat        , scell_copy%typat)
     610          105 :  call alloc_copy(scell_in%znucl        , scell_copy%znucl)
     611              : 
     612          105 : end subroutine supercell_copy
     613              : !!***
     614              : 
     615              : !!****f* m_effective_potential/getPBCIndexes_supercell
     616              : !! NAME
     617              : !!
     618              : !! FUNCTION
     619              : !! Get the index of the cell by using PBC
     620              : !!
     621              : !! INPUTS
     622              : !! index  = index of the cell into the supercell
     623              : !! ncell = number of total cell
     624              : !!
     625              : !! OUTPUT
     626              : !! index  = index of the cell into the supercell with PBC
     627              : !!
     628              : !! SOURCE
     629              : 
     630   4411437984 : subroutine getPBCIndexes_supercell(index,ncell)
     631              : 
     632              : !Arguments ---------------------------------------------
     633              :   integer, intent(inout)  :: index(3)
     634              :   integer, intent(in) :: ncell(3)
     635              : 
     636              : !Local variables ---------------------------------------
     637              :   integer :: ii
     638              : ! *********************************************************************
     639              : 
     640  17645751936 :  do ii=1,3
     641  13848999534 :    do while (index(ii) > ncell(ii))
     642  13848999534 :      index(ii) = index(ii) - ncell(ii)
     643              :    end do
     644  18203804122 :    do while (index(ii) <= 0)
     645    558052186 :      index(ii) = index(ii) + ncell(ii)
     646              :    end do
     647              :  end do
     648              : 
     649   4411437984 : end subroutine getPBCIndexes_supercell
     650              : !!***
     651              : 
     652              : !****f* m_supercell/findBound_supercell
     653              : !! NAME
     654              : !!  findBound_supercell
     655              : !!
     656              : !! FUNCTION
     657              : !!  compute the bound of the supercell by considering the 0 0 0 (reference)
     658              : !!  in the center of the supercell.
     659              : !!  for example: (4 4 4) => min = -1 and max = 2
     660              : !!
     661              : !! INPUTS
     662              : !! ncell(3) = size of the supercell (for example 3 3 3)
     663              : !!
     664              : !! OUTPUT
     665              : !! min = minimun of the range
     666              : !! max = maximum of the range
     667              : !!
     668              : !! SOURCE
     669              : 
     670          204 : subroutine findBound_supercell(min, max, ncell)
     671              : 
     672              : !Arguments ---------------------------------------------
     673              :  integer, intent(inout) :: min,max
     674              :  integer, intent(in) :: ncell
     675              : 
     676              : ! *********************************************************************
     677          204 :  if(abs(max)>abs(min)) then
     678            0 :    max=(ncell)/2; min=-max;  if(mod(ncell,2)==0) max = max -1
     679              :  else
     680          204 :    min=-(ncell)/2; max=-min; if(mod(ncell,2)==0)  min= min +1
     681              :  end if
     682              : 
     683          204 : end subroutine findBound_supercell
     684              : !!***
     685              : 
     686              : !!****f* m_supercell/distance_supercell
     687              : !! NAME
     688              : !!
     689              : !! FUNCTION
     690              : !! compute the distance_supercell betwen 2 atoms in different cell
     691              : !!
     692              : !! INPUTS
     693              : !! xcart1(3) = cartesian coordinates of the first atom
     694              : !! xcart1(3) = cartesian coordinates of the second atom
     695              : !! rprimd(3,3) = primitive lattice vectors
     696              : !! cell1(3) = index of the cell of the first atom (for example -1 0 2)
     697              : !! cell2(3) = index of the cell of the second atom (for example  0 0 2)
     698              : !!
     699              : !! OUTPUT
     700              : !! distance_supercell = distance_supercell between the 2 atoms
     701              : !!
     702              : !! SOURCE
     703              : !!
     704              : 
     705            0 : pure real(dp) function distance_supercell(xcart1,xcart2,rprimd,cell1,cell2) result(dist)
     706              : 
     707              : !Arguments ------------------------------------
     708              :  real(dp),intent(in):: rprimd(3,3)
     709              :  real(dp),intent(in):: xcart1(3),xcart2(3)
     710              :  integer,intent(in) :: cell1(3),cell2(3)
     711              : 
     712              : !Local variables -------------------------------
     713              :  real(dp) :: rpt1(3),rpt2(3)
     714              :  integer  :: mu
     715              : ! *************************************************************************
     716              : 
     717            0 :  do mu=1,3
     718            0 :    rpt1(mu) = cell1(1)*rprimd(mu,1)+cell1(2)*rprimd(mu,2)+cell1(3)*rprimd(mu,3)
     719            0 :    rpt2(mu) = cell2(1)*rprimd(mu,1)+cell2(2)*rprimd(mu,2)+cell2(3)*rprimd(mu,3)
     720              :  end do
     721              : 
     722              :  dist = ((xcart2(1)+rpt2(1)-xcart1(1)-rpt1(1))**2+&
     723              :          (xcart2(2)+rpt2(2)-xcart1(2)-rpt1(2))**2+&
     724            0 :          (xcart2(3)+rpt2(3)-xcart1(3)-rpt1(3))**2)**0.5
     725              : 
     726            0 : end function distance_supercell
     727              : !!***
     728              : 
     729              : !****f* m_supercell/supercell_free
     730              : !!
     731              : !! NAME
     732              : !! supercell_free
     733              : !!
     734              : !! FUNCTION
     735              : !! deallocate all dynamic memory for this supercell structure
     736              : !!
     737              : !! SOURCE
     738              : 
     739          889 : subroutine supercell_free(scell)
     740              : 
     741              : !Arguments ------------------------------------
     742              :  class(supercell_type), intent(inout) :: scell
     743              : ! *************************************************************************
     744              : 
     745          889 :  ABI_SFREE(scell%xcart)
     746          889 :  ABI_SFREE(scell%xcart_ref)
     747          889 :  ABI_SFREE(scell%typat)
     748          889 :  ABI_SFREE(scell%atom_indexing)
     749          889 :  ABI_SFREE(scell%uc_indexing)
     750          889 :  ABI_SFREE(scell%znucl)
     751          889 :  ABI_SFREE(scell%rvecs)
     752              : 
     753          889 : end subroutine supercell_free
     754              : !!***
     755              : 
     756              : !!****f* m_supercell/mksupercell
     757              : !! NAME
     758              : !!  mksupercell
     759              : !!
     760              : !! FUNCTION
     761              : !!  computes atomic positons, magnetic ordering of supercell
     762              : !!
     763              : !! INPUTS
     764              : !!  magv_org (optional) magnetic ordering of atoms in primitive cell,
     765              : !!   ordering of atoms given als 1 and -1, if not given fm is assumed
     766              : !!  xred_org relative position of atoms in primitive cell
     767              : !!  rprimd_org unit cell dimensions of primitive cell
     768              : !!  natom=number of atoms in unit cell
     769              : !!  option= 1 output ion-ion distances / 2 output ordering of ion-ion distances / 3 output variables in varlist
     770              : !!           according to ion-ion distances * magnetic ordering
     771              : !!
     772              : !! OUTPUT
     773              : !!  magv_sc magnetic ordering of atoms in supercell
     774              : !!  xred_sc relative position of atoms in supercell
     775              : !!  rprimd_sc unit cell dimensions of supercell
     776              : !!
     777              : !! SOURCE
     778              : 
     779           45 : subroutine mksupercell(xred_org,magv_org,rprimd_org,nat_org,nat_sc,xred_sc,magv_sc,rprimd_sc,ext,prtvol)
     780              : 
     781              : !Arguments ------------------------------------
     782              : !scalars
     783              :  integer,intent(in)              :: nat_org,nat_sc
     784              :  integer,intent(in),optional     :: prtvol
     785              : !arrays
     786              :  real(dp),intent(in)             :: rprimd_org(3,3)
     787              :  integer,intent(in)              :: ext(3)
     788              :  real(dp),intent(in)             :: xred_org(3,nat_org)
     789              :  real(dp),intent(out)            :: xred_sc(3,nat_sc)
     790              :  real(dp),intent(out)            :: magv_sc(nat_sc)
     791              :  real(dp),intent(out)            :: rprimd_sc(3,3)
     792              :  integer,intent(in),optional     :: magv_org(nat_org)
     793              : 
     794              : !Local variables-------------------------------
     795              : !scalars
     796              :  integer :: prtvoll,ix,iy,iz,nprcl,iprcl,jdim,iatom
     797              : !arrays
     798           90 :  real(dp) :: magvv_org(nat_org)
     799           45 :  real(dp),allocatable :: transv(:,:,:)
     800              : ! *************************************************************************
     801              : 
     802           45 :  if (present(magv_org)) then
     803          110 :    magvv_org=magv_org
     804              :  else
     805            0 :    magvv_org=(/ (1, iatom=1,nat_org)  /)
     806              :  end if
     807              : 
     808              :  if (present(prtvol)) then
     809              :    prtvoll=prtvol
     810              :  else
     811              :    prtvoll=1
     812              :  end if
     813              : 
     814          990 :  rprimd_sc=reshape((/ (rprimd_org(ix,:)*ext(ix) ,ix=1,3) /),(/3,3 /))
     815          180 :  nprcl=product(ext)
     816          180 :  ABI_MALLOC(transv,(3,nat_org,nprcl))
     817              : 
     818        64355 :  transv=reshape((/ (((((/ ix,iy,iz /),iatom=1,nat_org),ix=0,ext(1)-1),iy=0,ext(2)-1),iz=0,ext(3)-1) /), (/ 3, nat_org,nprcl/) )
     819              : 
     820              :  !write(std_out,*)'mksupercell: xred_org ' ,xred_org
     821         3365 :  do iprcl=1,nprcl
     822        21080 :    xred_sc(:,1+(iprcl-1)*nat_org:iprcl*nat_org)=xred_org+transv(:,:,iprcl)
     823         7805 :    magv_sc(1+(iprcl-1)*nat_org:iprcl*nat_org)=magv_org
     824              :  end do
     825              : 
     826          180 :  do jdim=1,3
     827        13500 :    xred_sc(jdim,:)=xred_sc(jdim,:)/ext(jdim)
     828              :  end do
     829              : 
     830              :  !write(std_out,*)'mksupercell: xred_sc ', xred_sc
     831              :  !write(std_out,*)'mksupercell: magv_sc ', magv_sc
     832              : 
     833           45 :  ABI_FREE(transv)
     834              : 
     835           45 : end subroutine mksupercell
     836              : !!***
     837              : 
     838              : !****f* m_supercell/supercell_write_xsf
     839              : !! NAME
     840              : !! supercell_write_xsf
     841              : !!
     842              : !! FUNCTION
     843              : !! output atomic positions, supercell vectors, etc... to xsf_filenamt
     844              : !!
     845              : !! INPUTS
     846              : !! xsf_filename = filename
     847              : !!
     848              : !! OUTPUT
     849              : !! printing to file
     850              : !!
     851              : !! SOURCE
     852              : 
     853            4 : subroutine supercell_write_xsf(scell, xsf_filename)
     854              : 
     855              : !Arguments ------------------------------------
     856              : !scalars
     857              :  class(supercell_type), intent(in) :: scell
     858              :  character(len=*), intent(in) :: xsf_filename
     859              : 
     860              : !Local variables-------------------------------
     861              :  integer :: ount, ix, iy, iatom
     862              :  character(len=500) :: msg
     863              : ! *************************************************************************
     864              : 
     865            4 :  if (open_file(xsf_filename, msg, newunit=ount, status="unknown", action="write") /= 0) then
     866            0 :    ABI_ERROR(msg)
     867              :  end if
     868              : 
     869              :  ! Note: Don't put comments because Vesta on my Mac does not like them!
     870              :  !write (ount, '(a)')"#", trim(title)
     871              :  !write (ount, '(a,3(3I7,2x))') '# supercell rlatt is ', scell%rlatt
     872              :  !write (ount, '(a,I0,a)') '# and has ', scell%ncells, ' primitive unit cells '
     873              :  !write (ount, '(a)') '#'
     874              : 
     875            4 :  write(ount,'(1X,A)')  'DIM-GROUP'
     876            4 :  write(ount,*) '3  1'
     877            4 :  write(ount,'(1X,A)') 'PRIMVEC'
     878              :  !write(ount, "(a)")"# these are primitive lattice vectors (in Angstroms)"
     879           16 :  do iy = 1,3
     880           52 :    write(ount, '(3(ES17.10,2X))') (Bohr_Ang * scell%rprimd(ix,iy), ix=1,3)
     881              :  end do
     882            4 :  write(ount, "(1X, a)")"PRIMCOORD"
     883            4 :  write(ount, "(i0,1x,i0)") scell%natom, 1  ! # The second number is always 1 for PRIMCOORD coordinates.
     884              : 
     885         4560 :  do iatom=1,scell%natom
     886              :    write(ount, '(i9, 6(3X,ES17.10))') &
     887         4556 :      NINT(scell%znucl(scell%typat(iatom))), &  ! WARNING alchemy not supported by XCrysden
     888        36452 :      scell%xcart_ref(:,iatom) * Bohr_Ang, (scell%xcart(:,iatom) - scell%xcart_ref(:,iatom)) * Bohr_Ang
     889              :  end do
     890              : 
     891            4 :  close(ount)
     892              : 
     893            4 : end subroutine supercell_write_xsf
     894              : !!***
     895              : 
     896        27320 : end module m_supercell
     897              : !!***
        

Generated by: LCOV version 2.3-1