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
|