LCOV - code coverage report
Current view: top level - src/78_effpot - m_supercell_maker.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 50.7 % 211 107
Test Date: 2026-09-19 15:24:51 Functions: 55.6 % 27 15

            Line data    Source code
       1              : !!****m* ABINIT/m_supercell_maker
       2              : !! NAME
       3              : !! m_supercell_maker
       4              : !!
       5              : !! FUNCTION
       6              : !! This module define the supercell_maker file, which provide functions to help build
       7              : !! potentials in supercell.
       8              : !! Note: This module works at lower level than m_supercell. The purpose is not to get
       9              : !! an supercell of crystal structure, but it provide the functions to help building such thing (but not limited to).
      10              : !!
      11              : !! TODO: update m_supercell based on this so that it can use non-diagonal supercell matrix.
      12              : !! Then this need to be moved to level same as m_supercell.
      13              : !!
      14              : !! Datatypes:
      15              : !!  supercell_maker_t
      16              : !!
      17              : !! Subroutines:
      18              : !!
      19              : !!
      20              : !! COPYRIGHT
      21              : !! Copyright (C) 2001-2026 ABINIT group (hexu)
      22              : !! This file is distributed under the terms of the
      23              : !! GNU General Public License, see ~abinit/COPYING
      24              : !! or http://www.gnu.org/copyleft/gpl.txt .
      25              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      26              : !!
      27              : !! SOURCE
      28              : 
      29              : 
      30              : #if defined HAVE_CONFIG_H
      31              : #include "config.h"
      32              : #endif
      33              : #include "abi_common.h"
      34              : 
      35              : module m_supercell_maker
      36              :   use defs_basis
      37              :   use m_abicore
      38              :   use m_errors
      39              :   use m_xmpi
      40              :   use m_mathfuncs,     only: binsearch_left_integerlist, rotate_by_angle_around_axis
      41              :   use m_matrix,        only: matr3inv, mat33det
      42              :   use m_mpi_scheduler, only: init_mpi_info
      43              :   use m_supercell
      44              :   implicit none
      45              :   private
      46              : !!***
      47              :   !-----------------------------------------------------------------------
      48              :   !> @brief A helper type to build supercell and potentials from primitive
      49              :   !> It keep the information of the supercell matrix, and the R-vectors (R1~Rn),
      50              :   !> so that the potentials in
      51              :   !> For a list of indices in primitive cell (e.g. (i, j, k)), it will become
      52              :   !> (i,R0), (j, R0), (k, R0), (i, R1), (i, R1), ... (i, Rn), (j,Rn), (k, Rn)
      53              :   !-----------------------------------------------------------------------
      54              :   type ,public :: supercell_maker_t
      55              :      integer :: scmat(3,3)  ! supercell matrix
      56              :      real(dp) :: inv_scmat(3,3) ! inverse of supercell matrix
      57              :      integer :: ncells         ! number of cells in supercell
      58              :      integer, allocatable :: rvecs(:,:) ! R vectors for cells in supercell. dim:(3, ncells)
      59              :    contains
      60              :      procedure :: initialize
      61              :      procedure :: finalize
      62              :      procedure :: to_red_sc
      63              :      procedure :: build_rvec
      64              :      procedure :: sc_cell
      65              :      procedure :: R_to_sc
      66              : 
      67              :      ! Translations: from one primitive cell element to ncell supercell elements
      68              :      ! with values unchanged (therefore just repeat ncells times)
      69              :      generic :: repeat => repeat_int1d, repeat_real1d, repeat_real2d, repeat_realmat
      70              :      procedure :: repeat_int1d
      71              :      procedure :: repeat_int1d_noalloc
      72              :      procedure :: repeat_real1d
      73              :      procedure :: repeat_real2d
      74              :      procedure :: repeat_realmat
      75              : 
      76              :      ! Translations: from one primitive cell element to ncell supercell elements
      77              :      ! with values changed (different from repeat)
      78              :      procedure :: trans_xred
      79              :      procedure :: trans_xcart
      80              :      procedure :: trans_i
      81              :      procedure :: trans_i_noalloc
      82              :      procedure :: trans_ilist
      83              :      procedure :: trans_j_and_Rj
      84              :      procedure :: trans_j_and_Rj_noalloc
      85              :      procedure :: trans_jlist_and_Rj
      86              :      procedure :: rvec_for_each
      87              : 
      88              :      ! Wave like quantities:
      89              :      procedure :: generate_wave_scalar   ! s=s0*e^{ikR}
      90              :      procedure :: generate_spin_wave_vectorlist  !vector with rotation angle= 2pi k * R
      91              :   end type supercell_maker_t
      92              : 
      93              :   public :: scmaker_unittest
      94              : contains
      95              : 
      96              :   !-----------------------------------------------------------------------
      97              :   !> @brief initialize
      98              :   !> @param [in] sc_matrix: the supercell matrix which maps the primitive cell to sc
      99              :   !>       it does not have to be diagonal.
     100              :   !-----------------------------------------------------------------------
     101            6 :   subroutine initialize(self, sc_matrix)
     102              :     class(supercell_maker_t), intent(inout) :: self
     103              :     integer, intent(in) :: sc_matrix(3, 3)
     104              :     real(dp) :: tmp(3,3)
     105              :     integer :: master, my_rank, comm, nproc, ierr
     106              :     logical :: iam_master
     107            6 :     call init_mpi_info(master, iam_master, my_rank, comm, nproc)
     108              : 
     109           78 :     self%scmat(:,:)=sc_matrix
     110            6 :     call xmpi_bcast(self%scmat, master, comm, ierr)
     111            6 :     self%ncells=abs(mat33det(self%scmat))
     112              :     ! call xmpi_bcast(self%ncells, master, comm, ierr)
     113           18 :     ABI_MALLOC(self%rvecs, (3, self%ncells))
     114              :     ! Why transpose?
     115           78 :     tmp(:,:)=transpose(self%scmat)
     116              : 
     117              :     ! save inverse of matrix so A^{-1} x can be easily calculated.
     118            6 :     call matr3inv(tmp, self%inv_scmat)
     119            6 :     call self%build_rvec()
     120              :     !call xmpi_bcast(self%inv_scmat, master, comm, ierr)
     121              :     !call xmpi_bcast(self%ncells, master, comm, ierr)
     122              :     !call xmpi_bcast(self%rvecs, master, comm, ierr)
     123            6 :   end subroutine initialize
     124              : 
     125              :   !-----------------------------------------------------------------------
     126              :   !> @brief Finalize
     127              :   !-----------------------------------------------------------------------
     128            6 :   subroutine finalize(self)
     129              :     class(supercell_maker_t), intent(inout) :: self
     130           78 :     self%scmat=0
     131            6 :     self%ncells=0
     132            6 :     if (allocated(self%rvecs)) then
     133            6 :        ABI_FREE(self%rvecs)
     134              :     end if
     135            6 :   end subroutine finalize
     136              : 
     137              :   !-----------------------------------------------------------------------
     138              :   !> @brief from reduced coordinate in primitive cell to that insupercell
     139              :   !>  This does not use translation symmetry, so it is a ONE to ONE convert.
     140              :   !> @param [in] pos (reduced position in primitive cell)
     141              :   !> @param [out] ret reduce position in supercell
     142              :   !-----------------------------------------------------------------------
     143      3619346 :   function to_red_sc(self, pos) result(ret)
     144              :     class(supercell_maker_t), intent(inout) :: self
     145              :     real(dp), intent(in) :: pos(3)
     146              :     real(dp) :: ret(3)
     147     61528882 :     ret(:)=matmul(pos, self%inv_scmat)
     148      3619346 :   end function to_red_sc
     149              : 
     150              :   !-----------------------------------------------------------------------
     151              :   !> @brief build R vectors for supercells.
     152              :   !-----------------------------------------------------------------------
     153            6 :   subroutine build_rvec(self)
     154              :     class(supercell_maker_t), intent(inout) :: self
     155              :     real(dp):: scorners_newcell(8,3), corners(8,3), x(3), tmp(3)
     156              :     integer :: minr(3), maxr(3), ix, iy, iz, counter
     157              :     real(dp) :: eps=1d-9
     158            6 :     counter=0
     159              :     ! cornors
     160              :     scorners_newcell=transpose(reshape([0., 0., 0., 0., 0., 1., 0., 1., 0., &
     161              :          0., 1., 1., 1., 0., 0., 1., 0., 1.,  &
     162            6 :          1., 1., 0., 1., 1., 1.],[3,8]))
     163          582 :     corners = matmul(scorners_newcell, self%scmat)
     164              :     !rep=ceiling(maxval(corners, dim=1) - minval(corners, dim=1))
     165           24 :     minr=floor(minval(corners, dim=1))
     166           24 :     maxr=ceiling(maxval(corners, dim=1))
     167              :     ! NOTE: DO NOT CHANGE THE ORDER. It is used in the binary search.
     168           48 :     do ix = minr(1), maxr(1)
     169          350 :        do iy = minr(2), maxr(2)
     170         2570 :           do iz = minr(3), maxr(3)
     171         8904 :              x(:)=[ix, iy, iz]
     172         8904 :              tmp=self%to_red_sc(x)
     173              :              if ( (.not. any(tmp<=-1.0*eps)) &
     174        14234 :                   .and. (.not. any(tmp>1.0-eps)) ) then
     175         1440 :                 counter=counter+1
     176         5760 :                 self%rvecs(:,counter)=nint(x)
     177              :              end if
     178              :           end do
     179              :        end do
     180              :     end do
     181            6 :     if (counter /= self%ncells ) then
     182            0 :        ABI_ERROR("Bug found. supercell_maker: Wrong number of supercell found in build_rvec. ")
     183              :     end if
     184            6 :   end subroutine build_rvec
     185              : 
     186              :   !-----------------------------------------------------------------------
     187              :   !> @brief cell parameters from unitcell to supercell
     188              :   !> @param [in] cell: cell parameter in primitive cell
     189              :   !> @param [out] sccell: supercell cell parameter
     190              :   !-----------------------------------------------------------------------
     191            8 :   function sc_cell(self, cell) result(sccell)
     192              :     class(supercell_maker_t), intent(inout) :: self
     193              :     real(dp), intent(in) :: cell(3,3)
     194              :     real(dp) :: sccell(3,3)
     195          528 :     sccell=matmul(self%scmat, cell)
     196            8 :   end function sc_cell
     197              : 
     198              :   !-----------------------------------------------------------------------
     199              :   !> @brief reduced position in primitive cell to supercell.
     200              :   !>    It use translation symmetry. so (3,n) -> (3, n*ncells)
     201              :   !> Note that allocation will be done if not already allocated.
     202              :   !> @param [in] xred: reduced coordinates in primitive cell
     203              :   !> @param [out] sccell: reduced coordinates in supercell
     204              :   !-----------------------------------------------------------------------
     205            0 :   subroutine trans_xred(self, xred, scxred)
     206              :     class(supercell_maker_t), intent(inout) :: self
     207              :     real(dp), intent(in) :: xred(:,:)
     208              :     real(dp), allocatable, intent(inout) :: scxred(:, :)
     209              :     integer :: npos, icell, ipos, counter=0
     210            0 :     npos=size(xred, dim=2)
     211            0 :     if (.not. allocated(scxred)) then
     212            0 :        ABI_MALLOC(scxred, (3,size(xred, dim=2)*self%ncells))
     213              :     end if
     214            0 :     do icell = 1, self%ncells
     215            0 :        do ipos=1 , npos
     216            0 :           counter=counter+1
     217            0 :           scxred(:, counter) = self%to_red_sc(xred(:, ipos)+ self%rvecs(:, icell))
     218              :        end do
     219              :     end do
     220            0 :   end subroutine trans_xred
     221              : 
     222              :   !-----------------------------------------------------------------------
     223              :   !> @brief cartesion position in primitive cell to supercell.
     224              :   !>    It use translation symmetry. so (3,n) -> (3, n*ncells)
     225              :   !> Note that allocation will be done if not already allocated.
     226              :   !> @param [in] primcell: cell parameter in primitive cell
     227              :   !> @param [in] xcart: cartesion coordinates in primitive cell
     228              :   !> @param [out] scxcart:cartesion coordinates in supercell
     229              :   !-----------------------------------------------------------------------
     230            8 :   subroutine trans_xcart(self, primcell, xcart, scxcart)
     231              :     class(supercell_maker_t), intent(inout) :: self
     232              :     real(dp), intent(in) :: xcart(:,:), primcell(3,3)
     233              :     real(dp), allocatable, intent(inout) :: scxcart(:,:)
     234              :     integer :: npos, icell, ipos, counter
     235            8 :     counter =0
     236            8 :     npos=size(xcart, dim=2)
     237            8 :     if (.not. allocated(scxcart)) then
     238           18 :        ABI_MALLOC(scxcart, (3,npos*self%ncells))
     239              :     end if
     240         1880 :     do icell = 1, self%ncells
     241        10024 :        do ipos=1 , npos
     242         8144 :           counter=counter+1
     243       189184 :           scxcart(:, counter) = matmul(self%rvecs(:, icell), primcell) + xcart(:,ipos)
     244              :        end do
     245              :     end do
     246            8 :   end subroutine trans_xcart
     247              : 
     248              : 
     249              :   !-----------------------------------------------------------------------
     250              :   !> @brief Find a R vector in primitive cell unit to a R vector in supercell unit
     251              :   !>  Here is an example:
     252              :   !>   A Rp for a 1*1*1 primitive cell. Rp=(0,0, 3)
     253              :   !>   For a supercell of 1*1*2, Rp = (0, 0, 1) * supercell + (0, 0, 1) * primcell
     254              :   !> @param [in] R index using primitive cell parameter
     255              :   !> @param [out] R index using supercell parameter
     256              :   !> @param [out] index of cell INSIDE supercell in primitive cell.
     257              :   !-----------------------------------------------------------------------
     258      3617120 :   subroutine R_to_sc(self, R, R_sc, ind_sc)
     259              :     class(supercell_maker_t), intent(inout) :: self
     260              :     integer, intent(in) :: R(3)
     261              :     integer, intent(inout) :: ind_sc, R_sc(3)
     262              :     integer :: rprim(3)
     263     25319840 :     R_sc=floor(self%to_red_sc(R*1.0d0)+1.0d-8)
     264     61491040 :     rprim(:)= R-matmul(R_sc, self%scmat)
     265      3617120 :     ind_sc=binsearch_left_integerlist(self%rvecs, rprim)
     266      3617120 :     if (ind_sc==0) then
     267              :        !print *, "R: " , R
     268              :        !print *, "Rredsc:", self%to_red_sc(R*1.0d0)
     269              :        !print *, "R_sc: " , R_sc
     270              :        !print *, "rprim", rprim
     271            0 :        ABI_ERROR("Bug found. supercell_maker%R_to_sc: Cannot find rprim")
     272              :     end if
     273      3617120 :   end subroutine R_to_sc
     274              : 
     275              : 
     276              : 
     277              :   !-----------------------------------------------------------------------
     278              :   !> @brief generate a wave like quantity. A_sc(R) = A(0)* exp(ikR)
     279              :   !>  The A_sc will be allocated. size : (ncells)
     280              :   !> @param [in] A: a scalar quantity.
     281              :   !> @param [in] kpoint: the wave vector
     282              :   !> @param [out] A_sc: indices in supercell.
     283              :   !-----------------------------------------------------------------------
     284            0 :   subroutine generate_wave_scalar(self, A, kpoint, A_sc)
     285              :     class(supercell_maker_t), intent(inout) :: self
     286              :     real(dp), intent(in) :: A
     287              :     real(dp), intent(in) ::  kpoint(3)
     288              :     real(dp), allocatable, intent(inout) :: A_sc(:)
     289              :     integer :: i
     290            0 :     if(.not. allocated(A_sc)) then
     291            0 :        ABI_MALLOC(A_sc, (self%ncells))
     292              :     end if
     293            0 :     do i=1, self%ncells
     294              :        A_sc(i) = real(A*exp(cmplx(0.0,two_pi, kind=dp) * &
     295            0 :             &dot_product(kpoint, self%rvecs(:, i))), kind=dp)
     296              :     end do
     297            0 :   end subroutine generate_wave_scalar
     298              : 
     299              :   !-----------------------------------------------------------------------
     300              :   !> @brief generate a wave like quantity. A_sc(R) = A(0)* exp(ikR)
     301              :   !>  The A_sc will be allocated. size : (nA*ncells)
     302              :   !> @param [in] A: a list scalar quantity in primitive cell.
     303              :   !> @param [in] kpoint: the wave vector
     304              :   !> @param [out] A_sc: indices in supercell.
     305              :   !-----------------------------------------------------------------------
     306              :   subroutine generate_wave_scalarlist(self, A, kpoint, A_sc)
     307              :     class(supercell_maker_t), intent(inout) :: self
     308              :     real(dp), intent(in) :: A(:)
     309              :     real(dp), intent(in) ::  kpoint(3)
     310              :     real(dp), allocatable, intent(inout) :: A_sc(:)
     311              :     integer :: icell, iA, nA, counter
     312              :     nA=size(A)
     313              :     if(.not. allocated(A_sc)) then
     314              :        ABI_MALLOC(A_sc, (nA*self%ncells))
     315              :     end if
     316              :     counter=0
     317              :     do icell = 1, self%ncells
     318              :        do iA=1 , nA
     319              :           counter=counter+1
     320              :           A_sc(counter) = real(A(iA)*exp(cmplx(0.0,two_pi, kind=dp) * &
     321              :                &dot_product(kpoint, self%rvecs(:, icell))), kind=dp)
     322              :        end do
     323              :     end do
     324              :   end subroutine generate_wave_scalarlist
     325              : 
     326              : 
     327              :   !-----------------------------------------------------------------------
     328              :   !> @brief generate a wave like quantity. A_sc(R) = A(0)* exp(ikR)
     329              :   !>  The A_sc will be allocated. size : (ndim, nA*ncells)
     330              :   !>   NOTE: This generate a density wave. For a spin wave,
     331              :   !>         use generate_spin_wave_vectorlist.
     332              :   !> @param [in] A: a vector quantity. dimension (xyz, iA)
     333              :   !> @param [in] kpoint: the wave vector
     334              :   !> @param [out] A_sc: indices in supercell.
     335              :   !-----------------------------------------------------------------------
     336              :   subroutine generate_wave_vectorlist(self, A, kpoint, A_sc)
     337              :     class(supercell_maker_t), intent(inout) :: self
     338              :     real(dp), intent(in) :: A(:, :)
     339              :     real(dp), intent(in) ::  kpoint(3)
     340              :     real(dp), allocatable, intent(inout) :: A_sc(:, :)
     341              :     integer :: icell, iA, nA, counter, ndim
     342              :     ndim=size(A, 1)
     343              :     nA=size(A,2)
     344              :     if(.not. allocated(A_sc)) then
     345              :        ABI_MALLOC(A_sc, (ndim, nA*self%ncells))
     346              :     end if
     347              :     counter=0
     348              :     do icell = 1, self%ncells
     349              :        do iA=1 , nA
     350              :           counter=counter+1
     351              :           A_sc(:,counter) = real(A(:,iA)*exp(cmplx(0.0,two_pi, kind=dp) * &
     352              :                &dot_product(kpoint, self%rvecs(:, icell))), kind=dp)
     353              :        end do
     354              :     end do
     355              :   end subroutine generate_wave_vectorlist
     356              : 
     357              : 
     358              :   !-----------------------------------------------------------------------
     359              :   !> @brief generate a spin wave  quantity.
     360              :   !>  rotate by theta(R) = 2pi * k.dot.R, around axis.
     361              :   !>  The A_sc will be allocated. size : (ndim, nA*ncells)
     362              :   !> @param [in] A: a vector quantity. dimension (xyz, iA)
     363              :   !> @param [in] kpoint: the wave vector
     364              :   !> @param [in] axis: the axis to rotate around
     365              :   !> @param [out] A_sc: indices in supercell.
     366              :   !-----------------------------------------------------------------------
     367            2 :   subroutine generate_spin_wave_vectorlist(self, A, kpoint, axis, A_sc)
     368              :     class(supercell_maker_t), intent(inout) :: self
     369              :     real(dp), intent(in) :: A(:, :) !(3, dimension of primitive cell)
     370              :     real(dp), intent(in) ::  kpoint(3)
     371              :     real(dp), intent(in) ::  axis(3)
     372              :     real(dp), allocatable, intent(inout) :: A_sc(:, :) !(3, dimension of supercell)
     373              :     integer :: icell, iA, nA, counter, ndim
     374              :     real(dp):: angle
     375            2 :     ndim=size(A, 1)
     376            2 :     nA=size(A,2)
     377            2 :     if(.not. allocated(A_sc)) then
     378            0 :        ABI_MALLOC(A_sc, (ndim, nA*self%ncells))
     379              :     end if
     380            2 :     counter=0
     381          434 :     do icell = 1, self%ncells
     382          866 :        do iA=1, nA
     383          432 :           counter=counter+1
     384         1728 :           angle=two_pi* DOT_PRODUCT(kpoint,  self%rvecs(:, icell))
     385         2160 :           A_sc(:,counter) = rotate_by_angle_around_axis(angle=angle, axis=axis, vec=A(:, iA))
     386              :        end do
     387              :     end do
     388            2 :   end subroutine generate_spin_wave_vectorlist
     389              : 
     390              : 
     391              :   !-----------------------------------------------------------------------
     392              :   !> @brief Get the indices of all the supercell repeat of an index in primitive cell
     393              :   !> @param [in] nbasis: total number of indices in the primitive cell (eg. natom in a cell)
     394              :   !>  Note that if the dimension xyz is also in the index, then use 3*natom.
     395              :   !>  i_sc array will be allocated if not already done
     396              :   !> This function is mostly useful for building supercell potential with such format H_ij(R_j)
     397              :   !> @param [in] i: index in primitive cell
     398              :   !> @param [out] i_sc: indices in supercell.
     399              :   !-----------------------------------------------------------------------
     400         8309 :   subroutine trans_i(self, nbasis, i, i_sc)
     401              :     class(supercell_maker_t), intent(inout) :: self
     402              :     integer, intent(in) :: i, nbasis
     403              :     integer, allocatable, intent(inout) :: i_sc(:)
     404         8309 :     if(.not. allocated(i_sc)) then
     405        16347 :        ABI_MALLOC(i_sc, (self%ncells))
     406              :     end if
     407         8309 :     call self%trans_i_noalloc(nbasis, i, i_sc)
     408         8309 :   end subroutine trans_i
     409              : 
     410              :   !-----------------------------------------------------------------------
     411              :   !> @brief Get the indices of all the supercell repeat of an index in primitive cell
     412              :   !> @param [in] nbasis: total number of indices in the primitive cell (eg. natom in a cell)
     413              :   !>  Note that if the dimension xyz is also in the index, then use 3*natom.
     414              :   !>  i_sc array will NOT be allocated.
     415              :   !> This function is mostly useful for building supercell potential with such format H_ij(R_j)
     416              :   !> @param [in] i: index in primitive cell
     417              :   !> @param [out] i_sc: indices in supercell.
     418              :   !-----------------------------------------------------------------------
     419         8309 :   subroutine trans_i_noalloc(self, nbasis, i, i_sc)
     420              :     class(supercell_maker_t), intent(inout) :: self
     421              :     integer, intent(in) :: i, nbasis
     422              :     integer, intent(inout) :: i_sc(:)
     423              :     integer :: icell
     424      1757397 :     do icell =1, self%ncells
     425      1757397 :        i_sc(icell)=nbasis*(icell-1)+i
     426              :     end do
     427         8309 :   end subroutine trans_i_noalloc
     428              : 
     429              : 
     430              :   !-----------------------------------------------------------------------
     431              :   !> @brief Get the indices of all the supercell repeat of an LIST of indices in primitive cell
     432              :   !> @param [in] nbasis: total number of indices in the primitive cell (eg. natom in a cell)
     433              :   !>  Note that if the dimension xyz is also in the index, then use 3*natom.
     434              :   !>  i_sc array will be allocated if not already done.
     435              :   !> This function is mostly useful for building supercell potential with such format H_ij(R_j)
     436              :   !> @param [in] ilist: list of indices in primitive cell
     437              :   !> @param [out] ilist_sc: list of indices in supercell.
     438              :   !-----------------------------------------------------------------------
     439            0 :   subroutine trans_ilist(self, nbasis, ilist, ilist_sc)
     440              :     class(supercell_maker_t), intent(inout) :: self
     441              :     integer, intent(in) :: ilist(:), nbasis
     442              :     integer, allocatable,  intent(inout) :: ilist_sc(:)
     443              :     integer :: i
     444            0 :     if(.not. allocated(ilist_sc)) then
     445            0 :        ABI_MALLOC(ilist_sc, (size(ilist)*self%ncells))
     446              :     end if
     447            0 :     do i =1, size(ilist)
     448            0 :        call trans_i_noalloc(self,nbasis, ilist(i), ilist_sc(self%ncells*(i-1)+1:self%ncells*i ))
     449              :     end do
     450            0 :   end subroutine trans_ilist
     451              : 
     452              :   !-----------------------------------------------------------------------
     453              :   !> @brief Get the indices and R vector for a index of j displaced by a R vector.
     454              :   !>  This is often used to represent a vector outside the primitive cell.
     455              :   !>      i.e. its position is (r_j + R_j) in primitive cell unit. Then it will have
     456              :   !>      periodical repeats, which has index of j_sc inside supercell, and a R_sc vector to shift it.
     457              :   !> @param [in] nbasis: total number of indices in the primitive cell (eg. natom in a cell)
     458              :   !>  Note that if the dimension xyz is also in the index, then use 3*natom.
     459              :   !>  i_sc array will be allocated if not already done.
     460              :   !> This function is mostly useful for building supercell potential with such format H_ij(R_j)
     461              :   !> @param [in] j: index in primitive cell
     462              :   !> @param [in] Rj: R vector in primitive cell unit
     463              :   !> @param [out] j_sc: index in supercell
     464              :   !> @param [out] Rj_sc: R' vector in supercell unit.
     465              :   !-----------------------------------------------------------------------
     466        15121 :   subroutine trans_j_and_Rj(self, nbasis, j, Rj, j_sc, Rj_sc)
     467              :     class(supercell_maker_t), intent(inout) :: self
     468              :     integer, intent(in) :: j, Rj(3), nbasis
     469              :     integer, allocatable , intent(inout) :: j_sc(:), Rj_sc(:, :)
     470        15121 :     if(.not. allocated(j_sc)) then
     471        36783 :        ABI_MALLOC(j_sc, (self%ncells))
     472              :     endif
     473        15121 :     if(.not. allocated(Rj_sc)) then
     474        36783 :        ABI_MALLOC(Rj_sc, (3, self%ncells))
     475              :     endif
     476        15121 :     call self%trans_j_and_Rj_noalloc(nbasis, j, Rj, j_sc, Rj_sc)
     477        15121 :   end subroutine trans_j_and_Rj
     478              : 
     479              :   !-----------------------------------------------------------------------
     480              :   !> @brief same as trans_j_and_Rj, but it does not allocate data.
     481              :   !-----------------------------------------------------------------------
     482        15121 :   subroutine trans_j_and_Rj_noalloc(self, nbasis, j, Rj, j_sc, Rj_sc)
     483              :     class(supercell_maker_t), intent(inout) :: self
     484              :     integer, intent(in) :: j, Rj(3), nbasis
     485              :     integer, intent(inout) :: j_sc(:), Rj_sc(:, :)
     486              :     integer :: i,jj
     487      3632241 :     do i =1, self%ncells
     488     14468480 :        call self%R_to_sc(Rj + self%rvecs(:,i), Rj_sc(:,i), jj)
     489      3632241 :        j_sc(i)=nbasis*(jj-1)+j
     490              :     end do
     491        15121 :   end subroutine trans_j_and_Rj_noalloc
     492              : 
     493              :   !-----------------------------------------------------------------------
     494              :   !> @brief same as trans_j_and_Rj, but it loop over a list of j with the
     495              :   !>    same Rj
     496              :   !-----------------------------------------------------------------------
     497            0 :   subroutine trans_jlist_and_Rj(self, nbasis, jlist, Rj, ind_sc, R_sc)
     498              :     class(supercell_maker_t), intent(inout) :: self
     499              :     integer, intent(in) :: jlist(:), Rj(3), nbasis
     500              :     integer, allocatable, intent(inout) :: ind_sc(:), R_sc(:,:)
     501              :     integer :: i,jj, counter, indj
     502            0 :     if (.not. allocated(ind_sc)) then
     503            0 :        ABI_MALLOC(ind_sc, (self%ncells*size(jlist)) )
     504              :     endif
     505            0 :     if (.not. allocated(R_sc)) then
     506            0 :        ABI_MALLOC(R_sc, (3, self%ncells))
     507              :     endif
     508            0 :     counter=0
     509            0 :     do i =1, self%ncells
     510            0 :        call self%R_to_sc(Rj + self%rvecs(:,i), R_sc(:,i), jj)
     511            0 :        do indj=1, size(jlist)
     512            0 :           counter=counter+1
     513            0 :           ind_sc(counter)=nbasis*(jj-1)+jlist(indj)
     514              :        end do
     515              :     end do
     516            0 :   end subroutine trans_jlist_and_Rj
     517              : 
     518              :   !-----------------------------------------------------------------------
     519              :   !> @brief same as trans_j_and_Rj, but it loop over a list of j with the
     520              :   !>    same Rj
     521              :   !-----------------------------------------------------------------------
     522              :   subroutine trans_jlist_and_Rj_noalloc(self, nbasis, jlist, Rj, ind_sc, R_sc)
     523              :     class(supercell_maker_t), intent(inout) :: self
     524              :     integer, optional, intent(in) :: jlist(:)
     525              :     integer, intent(in) :: Rj(3), nbasis
     526              :     integer, intent(inout) :: ind_sc(:), R_sc(:,:)
     527              :     integer :: i,jj, counter, indj, n
     528              :     counter=0
     529              :     if (present(jlist)) then
     530              :        n=size(jlist)
     531              :     else
     532              :        n=nbasis
     533              :     end if
     534              :     do i =1, self%ncells
     535              :        call self%R_to_sc(Rj + self%rvecs(:,i), R_sc(:,i), jj)
     536              :        do indj=1, n
     537              :           counter=counter+1
     538              :           ind_sc(counter)=nbasis*(jj-1)+jlist(indj)
     539              :        end do
     540              :     end do
     541              :   end subroutine trans_jlist_and_Rj_noalloc
     542              : 
     543              : 
     544              : 
     545              :   !-----------------------------------------------------------------------
     546              :   !> @brief same as trans_j_and_Rj, but it loop over a list of j with the
     547              :   !>    same Rj
     548              :   !-----------------------------------------------------------------------
     549              :   subroutine trans_ijR(self, nbasis_i, nbasis_j, ilist, jlist, Rj, i_sc, j_sc, R_sc)
     550              :     class(supercell_maker_t), intent(inout) :: self
     551              :     integer, intent(in) ::ilist(:), jlist(:), Rj(3), nbasis_i, nbasis_j
     552              :     integer, allocatable, intent(inout) :: i_sc(:), j_sc(:), R_sc(:,:)
     553              :     integer :: icell,jj, counter, indj
     554              :     if (.not. allocated(i_sc)) then
     555              :        ABI_MALLOC(i_sc, (self%ncells*size(jlist)) )
     556              :     endif
     557              :     if (.not. allocated(j_sc)) then
     558              :        ABI_MALLOC(j_sc, (self%ncells*size(jlist)) )
     559              :     endif
     560              :     if (.not. allocated(R_sc)) then
     561              :        ABI_MALLOC(R_sc, (3, self%ncells))
     562              :     endif
     563              :     counter=0
     564              :     do icell =1, self%ncells
     565              :        call self%R_to_sc(Rj + self%rvecs(:,icell), R_sc(:,icell), jj)
     566              :        do indj=1, size(jlist)
     567              :           counter=counter+1
     568              :           i_sc(counter)=nbasis_i*(icell-1)+ilist(indj)
     569              :           j_sc(counter)=nbasis_j*(jj-1)+jlist(indj)
     570              :        end do
     571              :     end do
     572              :   end subroutine trans_ijR
     573              : 
     574              : 
     575              : 
     576              :   !-----------------------------------------------------------------------
     577              :   !> @brief repeat a quantity (which is a scalar for each index)
     578              :   !>  memory will be allocated if not already done
     579              :   !> @param [in] a: the quantity to be repeated (loop over index i in primcell)
     580              :   !> @param [out] ret: the repeat. also a 1D matrix. (loop over index in supercell)
     581              :   !-----------------------------------------------------------------------
     582            9 :   subroutine repeat_int1d(self, a, ret)
     583              :     class(supercell_maker_t), intent(inout) :: self
     584              :     integer, intent(in) :: a(:)
     585              :     integer, allocatable :: ret(:)
     586              :     integer :: n, i
     587            9 :     n=size(a)
     588            9 :     if (.not. allocated(ret)) then
     589           21 :        ABI_MALLOC(ret, (n*self%ncells))
     590              :     end if
     591         2393 :     do i =1, self%ncells
     592        11561 :        ret((i-1)*n+1: i*n) = a(:)
     593              :     end do
     594            9 :   end subroutine repeat_int1d
     595              : 
     596              :   !-----------------------------------------------------------------------
     597              :   !> @brief repeat a quantity (which is a scalar for each index)
     598              :   !> memory will NOT be allocated.
     599              :   !> @param [in] a: the quantity to be repeated (loop over index i in primcell)
     600              :   !> @param [out] ret: the repeat. also a 1D matrix. (loop over index in supercell)
     601              :   !-----------------------------------------------------------------------
     602            0 :   subroutine repeat_int1d_noalloc(self, a, ret)
     603              :     class(supercell_maker_t), intent(inout) :: self
     604              :     integer, intent(in) :: a(:)
     605              :     integer :: ret(:)
     606              :     integer :: n, i
     607            0 :     n=size(a)
     608            0 :     do i =1, self%ncells
     609            0 :        ret((i-1)*n+1: i*n) = a(:)
     610              :     end do
     611            0 :   end subroutine repeat_int1d_noalloc
     612              : 
     613              :   !-----------------------------------------------------------------------
     614              :   !> @brief repeat a quantity (which is a 1D matrix for each index)
     615              :   !>  memory will be allocated if not already done
     616              :   !> @param [in] a: the quantity to be repeated (loop over index i in primcell)
     617              :   !> @param [out] ret: the repeat. also a 1D matrix. (loop over index in supercell)
     618              :   !-----------------------------------------------------------------------
     619           13 :   subroutine repeat_real1d(self, a, ret)
     620              :     class(supercell_maker_t), intent(inout) :: self
     621              :     real(dp), intent(in) :: a(:)
     622              :     real(dp), allocatable:: ret(:)
     623              :     integer :: n, i
     624           13 :     n=size(a)
     625           13 :     if (.not. allocated(ret)) then
     626           21 :        ABI_MALLOC(ret, (n*self%ncells))
     627              :     end if
     628         3261 :     do i =1, self%ncells
     629        13293 :        ret((i-1)*n+1: i*n) = a(:)
     630              :     end do
     631           13 :   end subroutine repeat_real1d
     632              : 
     633              :   !-----------------------------------------------------------------------
     634              :   !> @brief repeat a quantity (which is a 1D matrix for each index)
     635              :   !>  memory will be allocated if not already done
     636              :   !> @param [in] a: the quantity to be repeated ( 2nd dim loop over index i in primcell)
     637              :   !> @param [out] ret: the repeat. also a 2D matrix. (2nd dim loop over index in supercell)
     638              :   !-----------------------------------------------------------------------
     639            0 :   subroutine repeat_real2d(self, a, ret)
     640              :     class(supercell_maker_t), intent(inout) :: self
     641              :     real(dp), intent(in) :: a(:,:)
     642              :     real(dp), allocatable:: ret(:, :)
     643              :     integer :: n1, n2, i
     644            0 :     n1=size(a, dim=1)
     645            0 :     n2=size(a,dim=2)
     646            0 :     if (.not. allocated(ret)) then
     647            0 :        ABI_MALLOC(ret, (n1, n2*self%ncells))
     648              :     end if
     649            0 :     do i =1, self%ncells
     650            0 :        ret(:,(i-1)*n2+1: i*n2) = a(:,:)
     651              :     end do
     652            0 :   end subroutine repeat_real2d
     653              : 
     654              :   !-----------------------------------------------------------------------
     655              :   !> @brief repeat a quantity (which is a 2D matrix for each index)
     656              :   !>  memory will be allocated if not already done
     657              :   !> @param [in] a: the quantity to be repeated ( 3rd dim loop over index i in primcell)
     658              :   !> @param [out] ret: the repeat. also a 2D matrix. (3rd dim loop over index in supercell)
     659              :   !-----------------------------------------------------------------------
     660            0 :   subroutine repeat_realmat(self, a, ret)
     661              :     class(supercell_maker_t), intent(inout) :: self
     662              :     real(dp), intent(in) :: a(:,:,:)
     663              :     real(dp), allocatable, intent(inout) :: ret(:,:,:)
     664              :     integer :: n,  i
     665            0 :     n=size(a, 3)
     666            0 :     if (.not. allocated(ret)) then
     667            0 :        ABI_MALLOC(ret, (size(a, dim=1), size(a, dim=2), n*self%ncells))
     668              :     end if
     669            0 :     do i=1, self%ncells
     670            0 :        ret(:,:,(i-1)*n+1: i*n)=a(:, :, :)
     671              :     end do
     672            0 :   end subroutine repeat_realmat
     673              : 
     674              :   !-----------------------------------------------------------------------
     675              :   !> @brief  a list of R vectors for all the indices in supercell
     676              :   !> memory will be allocated if not already done.
     677              :   !> @param [in] nbasis: number of indices in primitivecell
     678              :   !> @param [ret]  A R vector for each index in supercell mat(3, nbasis*ncells)
     679              :   !-----------------------------------------------------------------------
     680            3 :   subroutine rvec_for_each(self, nbasis, ret)
     681              :     class(supercell_maker_t), intent(inout) :: self
     682              :     integer, intent(in) :: nbasis
     683              :     integer, allocatable, intent(inout) :: ret(:,:)
     684              :     integer :: icell, ibasis
     685            3 :     if (.not. allocated(ret)) then
     686            3 :        ABI_MALLOC(ret, (3, nbasis*self%ncells))
     687              :     end if
     688          947 :     do icell=1, self%ncells
     689         2403 :        do ibasis=1, nbasis
     690         6768 :           ret(:, (icell-1)*nbasis+ibasis)= self%rvecs(:, icell)
     691              :        end do
     692              :     end do
     693            3 :   end subroutine rvec_for_each
     694              : 
     695              :   !============================Unit test=====================================
     696              : 
     697            0 :   function test1() result(err)
     698            0 :     type(supercell_maker_t) :: maker
     699              :     integer :: err
     700              :     integer :: scmat(3,3)
     701            0 :     integer, allocatable :: ind_sc(:)
     702              :     integer :: R(3), R_sc(3), ind_sc2
     703            0 :     integer, allocatable ::  j_sc(:), R_sc3(:, :)
     704            0 :     scmat=reshape([2,0, 0, 0,2, 0, 0,0,2], [3,3])
     705            0 :     call maker%initialize(scmat)
     706            0 :     err=0
     707            0 :     call maker%trans_i(nbasis=3, i=1, i_sc=ind_sc)
     708            0 :     R=[0,0,0]
     709            0 :     call maker%R_to_sc(R, R_sc, ind_sc2)
     710            0 :     if (.not.( (all(R_sc==[0,0,0])) .and. (ind_sc2==1 )))  then
     711            0 :        ABI_ERROR("R_to_sc is wrong")
     712              :     end if
     713              : 
     714            0 :     R=[0,0,3]
     715            0 :     call maker%trans_j_and_Rj(nbasis=3, j=1, Rj=R, j_sc=j_sc, Rj_sc=R_sc3  )
     716            0 :     if (.not. (  all(j_sc(1:3)==[4,1,10]) &
     717              :          .and. all(R_sc3(:,1)==[0,0,1]) &
     718              :          .and. all(R_sc3(:,3)==[0,0,1]) ) ) then
     719            0 :        ABI_ERROR("Wrong trans_j_and_Rj")
     720            0 :        err=1
     721              :     end if
     722            0 :     ABI_FREE(ind_sc)
     723            0 :     ABI_FREE(j_sc)
     724            0 :     ABI_FREE(R_sc3)
     725            0 :   end function test1
     726              : 
     727            0 :   function test2() result(err)
     728            0 :     type(supercell_maker_t) :: maker
     729              :     integer :: err
     730              :     integer :: scmat(3,3)
     731              :     real(dp) :: sccell(3,3)
     732            0 :     real(dp), allocatable :: scxred(:, :)
     733            0 :     integer, allocatable :: rep1(:)
     734            0 :     real(dp), allocatable :: rep2(:)
     735            0 :     scmat=transpose(reshape([1,2, 3, 4,5,6,7,8,6], [3,3]))
     736              :     !scmat=reshape([1,2, 3, 4,5,6,7,8,6], [3,3])
     737            0 :     call maker%initialize(scmat)
     738              : 
     739            0 :     err=0
     740              : 
     741              :     ! test build_rvecs
     742            0 :     if (.not. all(maker%rvecs==reshape([0,  0,  0,  2,  3,  4,  3,  4,  4, &
     743              :          3,  4,  5,  4,  5,  5,  5,  6, 5, &
     744              :          5,  6,  6,  6,  7, 6,  8, 10, 10], [3, 8]))) then
     745            0 :        ABI_ERROR("Wrong Rvecs found !")
     746            0 :        err=1
     747              :     end if
     748              : 
     749              :     ! test sc_cell
     750            0 :     sccell(:,:)=maker%sc_cell(transpose(reshape([1.d0,2.d0,3.d0,4.d0,5.d0,6.d0,3.d0,2.d0,3.d0], [3,3])))
     751            0 :     if (.not. all(abs(sccell-transpose(reshape([18,18, 24, 42, 45, 60, 57, 66, 87], [3,3])))<1e-4)) then
     752            0 :        ABI_ERROR("Wrong cell paramter found !")
     753            0 :        err=1
     754              :     end if
     755              : 
     756              : 
     757              :     ! test trans_xred
     758            0 :     call maker%trans_xred(reshape([0.1d0, 0.2d0, 0.3d0, 0.1d0, 0.4d0, 0.6d0], [3, 2]), scxred)
     759            0 :     if (.not. all(abs(scxred(:,18)-[1.0666666666666684,0.53333333333333277,0.70000000000000040])<1e-4)) then
     760            0 :        ABI_ERROR("Wrong sc_xred !")
     761            0 :        err=1
     762              :     end if
     763              : 
     764              :     ! test repeat
     765            0 :     call maker%repeat([1,2], rep1)
     766              : 
     767            0 :     call maker%repeat([1.0d0,2.0d0], rep2)
     768              : 
     769            0 :   end function test2
     770              : 
     771            0 :   subroutine scmaker_unittest()
     772            0 :     if (test1()/=0) ABI_ERROR("Supercell maker: Test1 Failed")
     773            0 :     if (test2()/=0) ABI_ERROR("Supercell maker: Test2 Failed")
     774            0 :   end subroutine scmaker_unittest
     775              : 
     776              : 
     777              : !===================================================================================
     778              : ! The functions below are deprecated!!!
     779              : ! ! They are used with the m_supercell module.
     780              : !
     781              : !   ! R (in term of primitive cell) to R_sc(in term of supercell) + R_prim
     782              : !   subroutine find_R_PBC(scell, R, R_sc, R_prim)
     783              : !     type(supercell_type) , intent(in):: scell
     784              : !     integer, intent(in):: R(3)
     785              : !     integer, intent(out):: R_sc(3), R_prim(3)
     786              : !     real(dp) :: R_sc_d(3), sc_mat(3,3)
     787              : 
     788              : !     integer:: ipriv(3), info
     789              : !     !call dgesv( n, nrhs, a, lda, ipiv, b, ldb, info )
     790              : !     sc_mat(:,:)=scell%rlatt
     791              : !     R_sc_d(:)=R(:)
     792              : !     call dgesv(3, 1, sc_mat, 3, ipriv, R_sc_d, 3, info)
     793              : !     if ( info/=0 ) then
     794              : !        ABI_ERROR("Failed to find R_sc")
     795              : !     end if
     796              : 
     797              : !     ! if only diagonal of rlatt works.
     798              : !     !R_sc_d(1)= real(R(1))/real(scell%rlatt(1,1))
     799              : !     !R_sc_d(2)= real(R(2))/real(scell%rlatt(2,2))
     800              : !     !R_sc_d(3)= real(R(3))/real(scell%rlatt(3,3))
     801              : !     ! TODO hexu: R_prim should be non-negative, which is assumed in m_supercell.
     802              : !     ! But should we make it more general?
     803              : !     R_sc(1)=floor(R_sc_d(1))
     804              : !     R_sc(2)=floor(R_sc_d(2))
     805              : !     R_sc(3)=floor(R_sc_d(3))
     806              : !     R_prim(1)=(R(1)-R_sc(1)*scell%rlatt(1,1))
     807              : !     R_prim(2)=(R(2)-R_sc(2)*scell%rlatt(2,2))
     808              : !     R_prim(3)=(R(3)-R_sc(3)*scell%rlatt(3,3))
     809              : !   end subroutine find_R_PBC
     810              : 
     811              : !   ! TODO hexu: move this to m_supercell?
     812              : !   ! find the spercelll atom index from index of atom in primitive cell and R vector
     813              : !   function find_supercell_index(scell, iatom_prim, rvec) result(iatom_supercell)
     814              : !     type(supercell_type) , intent(in):: scell
     815              : !     integer, intent(in) :: iatom_prim, rvec(3)
     816              : !     integer  :: iatom_supercell
     817              : !     integer :: i
     818              : !     iatom_supercell=-1
     819              : !     do i=1, scell%natom, 1
     820              : !        if ( scell%atom_indexing(i) == iatom_prim .and. &
     821              : !             all(scell%uc_indexing(:,i)==rvec) ) then
     822              : !           iatom_supercell=i
     823              : !           return
     824              : !        end if
     825              : !     end do
     826              : !     ABI_ERROR("BUG found. supercell_maker%find_supercell_index cannot find iatom_prim, rvec pair in supercell")
     827              : !   end function find_supercell_index
     828              : 
     829              : !   !i0, j0+R0 shifted by R to i1=i0+0+R->periodic, j1=j0+R0+R->periodic
     830              : !   subroutine find_supercell_ijR(scell, i0, j0, R0, R, i1, j1, R1, R_sc)
     831              : 
     832              : !     type(supercell_type) , intent(in):: scell
     833              : !     integer, intent(in) :: i0, j0, R0(3), R(3)
     834              : !     integer, intent(out) :: i1, j1, R1(3), R_sc(3)
     835              : !     i1=find_supercell_index(scell,i0,R)
     836              : !     call find_R_PBC(scell,R0+R,R_sc,R1)
     837              : !     j1=find_supercell_index(scell, j0, R1)
     838              : !   end subroutine find_supercell_ijR
     839              : 
     840              : 
     841            0 :  end module m_supercell_maker
        

Generated by: LCOV version 2.3-1