Line data Source code
1 : !!****m* ABINIT/m_iterators
2 : !! NAME
3 : !! m_iterators
4 : !!
5 : !! FUNCTION
6 : !! This module defines objects (iterators) that are used to facilitate the
7 : !! iteration over the elements of an ensemble e.g. set of transitions.
8 : !!
9 : !! COPYRIGHT
10 : !! Copyright (C) 2009-2026 ABINIT group (MG)
11 : !! This file is distributed under the terms of the
12 : !! GNU General Public License, see ~abinit/COPYING
13 : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : !!
15 : !! NOTES
16 : !! Iterators are used to obtain an indirect indexing that can be used to access array elements
17 : !! or array sections. An iterator is an object that contains the list of indices that should
18 : !! be treated. Each processor has its own local version initialized according the the distribution
19 : !! of the data across the nodes.
20 : !! Using iterators for looping facilitates the implementation of MPI algorithms since all the
21 : !! information on the distribution of the tasks is stored in the iterator itself
22 : !! For example an MPI loop over spins, k-points and bands can be written in terms of iterators using:
23 : !!
24 : !! do isp=1,iter_len(Iter_bks)
25 : !! spin = iter_yield(Iter_bks,idx3=isp)
26 : !!
27 : !! do ikp=1,iter_len(Iter_bks,idx3=isp)
28 : !! ik_ibz = iter_yield(Iter_bks,idx2=ikp,idx3=isp)
29 : !!
30 : !! do ibn=1,iter_len(Iter_bks,idx2=ikp,idx3=isp)
31 : !! band = iter_yield(Iter_bks,entry1=ibn,idx2=ikp,idx3=isp)
32 : !!
33 : !! iter_len gives the number of non-zero entries
34 : !! iter_yield returns the global indices used to access the data.
35 : !!
36 : !! The main advantage is seen in sections of code that are MPI parallelized because each node
37 : !! will have its own iterator (to be initialized by the programmer).
38 : !! Therefore it is very easy to distribute the workload among the nodes without having to
39 : !! to use "cycle" of "if then" instruction in the inners loops.
40 : !! Another important advantage is that the MPI implementation will continue to work even
41 : !! if the data distribution is changed, only the iterator has to be modified.
42 : !!
43 : !! SOURCE
44 :
45 : #if defined HAVE_CONFIG_H
46 : #include "config.h"
47 : #endif
48 :
49 : #include "abi_common.h"
50 :
51 : MODULE m_iterators
52 :
53 : use defs_basis
54 : use m_abicore
55 : use m_errors
56 :
57 : implicit none
58 :
59 : private
60 : !!***
61 :
62 : !----------------------------------------------------------------------
63 :
64 : !!****t* m_iterators/indices_t
65 : !! NAME
66 : !! indices_t
67 : !!
68 : !! FUNCTION
69 : !! A base datatype for constructing ragged arrays.
70 : !!
71 : !! SOURCE
72 :
73 : type,private :: indices_t
74 : integer :: leng
75 : integer, allocatable :: indx(:)
76 : ! indx(leng) The set of indices.
77 : end type indices_t
78 : !!***
79 :
80 : !----------------------------------------------------------------------
81 :
82 : !!****t* m_iterators/iter2_t
83 : !! NAME
84 : !! iter2_t
85 : !!
86 : !! FUNCTION
87 : !!
88 : !! SOURCE
89 :
90 : type,public :: iter2_t
91 : private
92 : integer :: sizes(2)
93 : integer :: starts(2)
94 : type(indices_t),allocatable :: slice(:,:)
95 : ! Temporary structure to store the indices in full storage mode.
96 :
97 : #if 0
98 : integer :: len3
99 : ! The number of non-zero entries in the last dimension.
100 :
101 : integer,allocatable :: map3(:)
102 : ! map3(len3)
103 : ! Indirect indexing packed --> full for the last dimension.
104 :
105 : integer,allocatable :: len2(:)
106 : ! len2(len3)
107 : ! Gives the number of non-zero entries along the second dimension for each non-null index along the 3-dimension.
108 :
109 : type(indices_t),allocatable :: map2(:)
110 : ! map2(len3)%indices
111 : ! Indirect indexing packed --> full for the second dimension.
112 :
113 : type(indices_t),allocatable :: len1(:,:)
114 : ! len1(MAX(len2),len3)
115 : ! Gives the number of non-zero entries along the first dimension.
116 :
117 : type(indices_t),allocatable :: map1(:)
118 : ! map1(MAX(len2),len3)%indices
119 : ! Indirect indexing packed --> full for the first dimension.
120 : #endif
121 :
122 : end type iter2_t
123 :
124 : public :: iter_alloc ! Allocate the iterator.
125 : public :: iter_push ! Copy a set of indices in the iterator
126 : public :: iter_free ! Deallocate the iterator.
127 : public :: OPERATOR(.LBOUND.) !
128 : public :: OPERATOR(.UBOUND.) !
129 : public :: OPERATOR(.SIZE.) !
130 : public :: iter_len ! The number of indices in a slice of the iterator
131 : public :: iter_yield ! Return the indices in of the slice of the iterator.
132 : public :: iter_print ! Printout of the iterator, just for debugging purposes.
133 : !!***
134 :
135 : interface iter_alloc
136 : module procedure iter2_alloc
137 : !module procedure iter3_alloc
138 : end interface iter_alloc
139 :
140 : interface iter_push
141 : module procedure iter2_push
142 : !module procedure iter3_push
143 : end interface iter_push
144 :
145 : interface iter_free
146 : module procedure iter2_free
147 : !module procedure iter3_free
148 : end interface iter_free
149 :
150 : interface operator(.lbound.)
151 : module procedure iter2_lbound
152 : !module procedure iter3_lbound
153 : end interface
154 :
155 : interface operator(.ubound.)
156 : module procedure iter2_ubound
157 : !module procedure iter3_ubound
158 : end interface
159 :
160 : interface operator(.size.)
161 : module procedure iter2_size
162 : !module procedure iter3_size
163 : end interface
164 :
165 : interface iter_len
166 : module procedure iter2_len
167 : !module procedure iter3_len
168 : end interface iter_len
169 :
170 : interface iter_yield
171 : module procedure iter2_yield
172 : !module procedure iter3_yield
173 : end interface iter_yield
174 :
175 : interface iter_print
176 : module procedure iter2_print
177 : !module procedure iter3_print
178 : end interface iter_print
179 :
180 : CONTAINS !===========================================================
181 : !!***
182 :
183 : !----------------------------------------------------------------------
184 :
185 : !!****f* m_iterators/indices_free
186 : !! NAME
187 : !! indices_free
188 : !!
189 : !! FUNCTION
190 : !!
191 : !! INPUTS
192 : !!
193 : !! OUTPUT
194 : !!
195 : !! SOURCE
196 :
197 3475 : subroutine indices_free(Ids)
198 :
199 : !Arguments ------------------------------------
200 : type(indices_t),intent(inout) :: Ids
201 :
202 : ! *************************************************************************
203 :
204 3475 : Ids%leng=0
205 3475 : ABI_SFREE(Ids%indx)
206 :
207 3475 : end subroutine indices_free
208 : !!***
209 :
210 : !----------------------------------------------------------------------
211 :
212 : !!****f* m_iterators/iter2_alloc
213 : !! NAME
214 : !! iter2_alloc
215 : !!
216 : !! FUNCTION
217 : !!
218 : !! INPUTS
219 : !!
220 : !! OUTPUT
221 : !!
222 : !! SOURCE
223 :
224 459 : subroutine iter2_alloc(Iter2,sizes,starts)
225 :
226 :
227 : !Arguments ------------------------------------
228 : !scalars
229 : type(iter2_t),intent(inout) :: Iter2
230 : !arrays
231 : integer,intent(in) :: sizes(2)
232 : integer,optional,intent(in) :: starts(2)
233 :
234 : !Local variables ------------------------------
235 : !scalars
236 : integer :: s1,s2,i1,i2
237 :
238 : !************************************************************************
239 459 : s1=1; s2=1
240 459 : if (PRESENT(starts)) then
241 0 : s1=starts(1)
242 0 : s2=starts(2)
243 : end if
244 :
245 1377 : Iter2%starts=(/s1,s2/)
246 1377 : Iter2%sizes =sizes
247 :
248 5779 : ABI_MALLOC( Iter2%slice,(s1:s1+sizes(1)-1, s2:s2+sizes(2)-1))
249 :
250 1845 : do i2=LBOUND(Iter2%slice,DIM=2),UBOUND(Iter2%slice,DIM=2)
251 5338 : do i1=LBOUND(Iter2%slice,DIM=1),UBOUND(Iter2%slice,DIM=1)
252 3943 : Iter2%slice(i1,i2)%leng=0
253 : end do
254 : end do
255 :
256 459 : end subroutine iter2_alloc
257 : !!***
258 :
259 : !----------------------------------------------------------------------
260 :
261 : !!****f* m_iterators/iter2_push
262 : !! NAME
263 : !! iter2_push
264 : !!
265 : !! FUNCTION
266 : !!
267 : !! INPUTS
268 : !!
269 : !! OUTPUT
270 : !!
271 : !! SOURCE
272 :
273 3475 : subroutine iter2_push(Iter2,i1,i2,list)
274 :
275 : !Arguments ------------------------------------
276 : !scalars
277 : integer,intent(in) :: i1,i2
278 : type(iter2_t),intent(inout) :: Iter2
279 : !arrays
280 : integer,intent(in) :: list(:)
281 :
282 : !Local variables ------------------------------
283 : !scalars
284 : integer :: leng
285 :
286 : !************************************************************************
287 :
288 3475 : leng = SIZE(list)
289 :
290 3475 : if (allocated( Iter2%slice(i1,i2)%indx) ) then
291 0 : ABI_ERROR("Iter2%slice already allocated")
292 : end if
293 :
294 3475 : Iter2%slice(i1,i2)%leng = leng
295 10425 : ABI_MALLOC(Iter2%slice(i1,i2)%indx,(leng))
296 15912 : Iter2%slice(i1,i2)%indx(:) = list
297 :
298 3475 : end subroutine iter2_push
299 : !!***
300 :
301 : !----------------------------------------------------------------------
302 :
303 : !!****f* m_iterators/iter2_free
304 : !! NAME
305 : !! iter2_free
306 : !!
307 : !! FUNCTION
308 : !!
309 : !! INPUTS
310 : !!
311 : !! OUTPUT
312 : !!
313 : !! SOURCE
314 :
315 459 : subroutine iter2_free(Iter2)
316 :
317 : !Arguments ------------------------------------
318 : !scalars
319 : type(iter2_t),intent(inout) :: Iter2
320 :
321 : !Local variables ------------------------------
322 : !scalars
323 : integer :: i1,i2
324 :
325 : !************************************************************************
326 :
327 1845 : do i2=LBOUND(Iter2%slice,DIM=2),UBOUND(Iter2%slice,DIM=2)
328 5338 : do i1=LBOUND(Iter2%slice,DIM=1),UBOUND(Iter2%slice,DIM=1)
329 3943 : call indices_free(Iter2%slice(i1,i2))
330 : end do
331 : end do
332 :
333 3934 : ABI_SFREE(Iter2%slice)
334 :
335 459 : end subroutine iter2_free
336 : !!***
337 :
338 : !----------------------------------------------------------------------
339 :
340 : !!****f* m_iterators/iter2_len
341 : !! NAME
342 : !! iter2_len
343 : !!
344 : !! FUNCTION
345 : !!
346 : !! INPUTS
347 : !!
348 : !! OUTPUT
349 : !!
350 : !! SOURCE
351 :
352 3475 : function iter2_len(Iter2,i1,i2)
353 :
354 : !Arguments ------------------------------------
355 : integer,intent(in) :: i1,i2
356 : integer :: iter2_len
357 : type(iter2_t),intent(in) :: Iter2
358 :
359 : ! *************************************************************************
360 :
361 3475 : iter2_len = Iter2%slice(i1,i2)%leng
362 :
363 3475 : end function iter2_len
364 : !!***
365 :
366 : !----------------------------------------------------------------------
367 :
368 : !!****f* m_iterators/iter2_lbound
369 : !! NAME
370 : !! iter2_lbound
371 : !!
372 : !! FUNCTION
373 : !!
374 : !! INPUTS
375 : !!
376 : !! OUTPUT
377 : !!
378 : !! SOURCE
379 :
380 0 : function iter2_lbound(Iter2,dim)
381 :
382 : !Arguments ------------------------------------
383 : !scalars
384 : integer,intent(in) :: dim
385 : integer :: iter2_lbound
386 : type(iter2_t),intent(in) :: Iter2
387 :
388 : !************************************************************************
389 :
390 0 : iter2_lbound = Iter2%starts(dim)
391 :
392 0 : end function iter2_lbound
393 : !!***
394 :
395 : !----------------------------------------------------------------------
396 :
397 : !!****f* m_iterators/iter2_ubound
398 : !! NAME
399 : !! iter2_ubound
400 : !!
401 : !! FUNCTION
402 : !!
403 : !! INPUTS
404 : !!
405 : !! OUTPUT
406 : !!
407 : !! SOURCE
408 :
409 0 : function iter2_ubound(Iter2,dim)
410 :
411 : !Arguments ------------------------------------
412 : !scalars
413 : integer,intent(in) :: dim
414 : integer :: iter2_ubound
415 : type(iter2_t),intent(in) :: Iter2
416 :
417 : !************************************************************************
418 :
419 0 : iter2_ubound = Iter2%starts(dim) + Iter2%sizes(dim) -1
420 :
421 0 : end function iter2_ubound
422 : !!***
423 :
424 : !----------------------------------------------------------------------
425 :
426 : !!****f* m_iterators/iter2_size
427 : !! NAME
428 : !! iter2_size
429 : !!
430 : !! FUNCTION
431 : !!
432 : !! INPUTS
433 : !!
434 : !! OUTPUT
435 : !!
436 : !! SOURCE
437 :
438 0 : function iter2_size(Iter2,dim)
439 :
440 : !Arguments ------------------------------------
441 : !scalars
442 : integer,intent(in) :: dim
443 : integer :: iter2_size
444 : type(iter2_t),intent(in) :: Iter2
445 :
446 : !************************************************************************
447 :
448 0 : iter2_size = iter2_ubound(Iter2,dim) - iter2_lbound(Iter2,dim) + 1
449 :
450 0 : end function iter2_size
451 : !!***
452 :
453 : !----------------------------------------------------------------------
454 :
455 : !!****f* m_iterators/iter2_yield
456 : !! NAME
457 : !! iter2_yield
458 : !!
459 : !! FUNCTION
460 : !!
461 : !! INPUTS
462 : !!
463 : !! OUTPUT
464 : !!
465 : !! SOURCE
466 :
467 12437 : function iter2_yield(Iter2,idx,i1,i2)
468 :
469 : !Arguments ------------------------------------
470 : integer,intent(in) :: idx,i1,i2
471 : integer :: iter2_yield
472 : type(iter2_t),intent(in) :: Iter2
473 :
474 : ! *************************************************************************
475 :
476 12437 : iter2_yield = Iter2%slice(i1,i2)%indx(idx)
477 :
478 12437 : end function iter2_yield
479 : !!***
480 :
481 : !----------------------------------------------------------------------
482 :
483 : !!****f* m_iterators/iter2_print
484 : !! NAME
485 : !! iter2_print
486 : !!
487 : !! FUNCTION
488 : !!
489 : !! INPUTS
490 : !!
491 : !! OUTPUT
492 : !!
493 : !! SOURCE
494 :
495 0 : subroutine iter2_print(Iter2,header,unit,mode_paral,prtvol)
496 :
497 : !Arguments ------------------------------------
498 : !scalars
499 : integer,optional,intent(in) :: unit,prtvol
500 : character(len=4),optional,intent(in) :: mode_paral
501 : character(len=*),optional,intent(in) :: header
502 : type(iter2_t),intent(in) :: Iter2
503 :
504 : !Local variables-------------------------------
505 : integer :: my_unt,my_prtvol,ntot,i1,i2,idx
506 : character(len=4) :: my_mode
507 : character(len=500) :: msg
508 : ! *********************************************************************
509 :
510 0 : my_unt =std_out; if (PRESENT(unit )) my_unt =unit
511 0 : my_prtvol=0 ; if (PRESENT(prtvol )) my_prtvol=prtvol
512 0 : my_mode ='COLL' ; if (PRESENT(mode_paral)) my_mode =mode_paral
513 :
514 0 : msg=' ==== Content of the iter2_t object ==== '
515 0 : if (PRESENT(header)) msg=' ==== '//TRIM(ADJUSTL(header))//' ==== '
516 0 : call wrtout(my_unt,msg,my_mode)
517 :
518 0 : ntot = PRODUCT(Iter2%sizes)
519 0 : write(std_out,*)"total number of elements:",ntot
520 0 : write(std_out,*)"list of indices: "
521 :
522 0 : do i2=iter2_lbound(Iter2,DIM=2),iter2_ubound(Iter2,DIM=2)
523 0 : do i1=iter2_lbound(Iter2,DIM=1),iter2_lbound(Iter2,DIM=1)
524 0 : write(std_out,*) (iter_yield(Iter2,idx,i1,i2), idx=1,iter_len(Iter2,i1,i2))
525 : end do
526 : end do
527 :
528 0 : end subroutine iter2_print
529 :
530 0 : END MODULE m_iterators
531 : !!***
|