(git:ccc2433)
dbt_array_list_methods.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
9 !> \brief Representation of arbitrary number of 1d integer arrays with arbitrary sizes.
10 !> This is needed for generic handling of dimension-specific tensor quantities
11 !> (such as block index).
12 !> \author Patrick Seewald
13 ! **************************************************************************************************
15 
16 
17 
18  USE dbt_index, ONLY: dbt_inverse_order
19  USE dbt_allocate_wrap, ONLY: allocate_any
20 
21 #include "../base/base_uses.f90"
22  IMPLICIT NONE
23  PRIVATE
24  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dbt_array_list_methods'
25 
26  PUBLIC :: &
27  array_eq_i, &
28  array_list, &
29  array_offsets, &
30  array_sublist, &
34  get_arrays, &
35  get_ith_array, &
39  sum_of_arrays, &
41 
42  TYPE array_list
43  INTEGER, DIMENSION(:), ALLOCATABLE :: col_data
44  INTEGER, DIMENSION(:), ALLOCATABLE :: ptr
45  END TYPE
46 
47  INTERFACE get_ith_array
48  MODULE PROCEDURE allocate_and_get_ith_array
49  MODULE PROCEDURE get_ith_array
50  END INTERFACE
51 
52 CONTAINS
53 
54 ! **************************************************************************************************
55 !> \brief number of arrays stored in list
56 !> \author Patrick Seewald
57 ! **************************************************************************************************
58  PURE FUNCTION number_of_arrays(list)
59  TYPE(array_list), INTENT(IN) :: list
60  INTEGER :: number_of_arrays
61 
62  number_of_arrays = SIZE(list%ptr) - 1
63 
64  END FUNCTION number_of_arrays
65 
66 ! **************************************************************************************************
67 !> \brief Get an element for each array.
68 !> \param indices element index for each array
69 !> \author Patrick Seewald
70 ! **************************************************************************************************
71  PURE FUNCTION get_array_elements(list, indices)
72  TYPE(array_list), INTENT(IN) :: list
73  INTEGER, DIMENSION(number_of_arrays(list)), INTENT(IN) :: indices
74  INTEGER, DIMENSION(number_of_arrays(list)) :: get_array_elements
75 
76  INTEGER :: i, ind
77 
78  DO i = 1, SIZE(indices)
79  ind = indices(i) + list%ptr(i) - 1
80  get_array_elements(i) = list%col_data(ind)
81  END DO
82 
83  END FUNCTION get_array_elements
84 
85 ! **************************************************************************************************
86 !> \brief collects any number of arrays of different sizes into a single array (list%col_data),
87 !> storing the indices that start a new array (list%ptr).
88 !> \param list list of arrays
89 !> \param ndata number of arrays
90 !> \param data arrays 1 and 2
91 !> \author Patrick Seewald
92 ! **************************************************************************************************
93  SUBROUTINE create_array_list(list, ndata, data_1, data_2, data_3, data_4)
94  TYPE(array_list), INTENT(OUT) :: list
95  INTEGER, INTENT(IN) :: ndata
96  INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: data_1, data_2, data_3, data_4
97  INTEGER :: ptr, size_all
98 
99  size_all = 0
100 
101  IF (ndata .GE. 1) THEN
102  cpassert(PRESENT(data_1))
103  size_all = size_all + SIZE(data_1)
104  END IF
105  IF (ndata .GE. 2) THEN
106  cpassert(PRESENT(data_2))
107  size_all = size_all + SIZE(data_2)
108  END IF
109  IF (ndata .GE. 3) THEN
110  cpassert(PRESENT(data_3))
111  size_all = size_all + SIZE(data_3)
112  END IF
113  IF (ndata .GE. 4) THEN
114  cpassert(PRESENT(data_4))
115  size_all = size_all + SIZE(data_4)
116  END IF
117 
118  ALLOCATE (list%ptr(ndata + 1))
119  ALLOCATE (list%col_data(size_all))
120 
121  ptr = 1
122  list%ptr(1) = ptr
123 
124  IF (ndata .GE. 1) THEN
125  list%col_data(ptr:ptr + SIZE(data_1) - 1) = data_1(:)
126  ptr = ptr + SIZE(data_1)
127  list%ptr(2) = ptr
128  END IF
129  IF (ndata .GE. 2) THEN
130  list%col_data(ptr:ptr + SIZE(data_2) - 1) = data_2(:)
131  ptr = ptr + SIZE(data_2)
132  list%ptr(3) = ptr
133  END IF
134  IF (ndata .GE. 3) THEN
135  list%col_data(ptr:ptr + SIZE(data_3) - 1) = data_3(:)
136  ptr = ptr + SIZE(data_3)
137  list%ptr(4) = ptr
138  END IF
139  IF (ndata .GE. 4) THEN
140  list%col_data(ptr:ptr + SIZE(data_4) - 1) = data_4(:)
141  ptr = ptr + SIZE(data_4)
142  list%ptr(5) = ptr
143  END IF
144 
145  END SUBROUTINE
146 
147 ! **************************************************************************************************
148 !> \brief extract a subset of arrays
149 !> \param list list of arrays
150 !> \param i_selected array numbers to retrieve
151 !> \author Patrick Seewald
152 ! **************************************************************************************************
153  FUNCTION array_sublist(list, i_selected)
154  TYPE(array_list), INTENT(IN) :: list
155  INTEGER, DIMENSION(:), INTENT(IN) :: i_selected
156  TYPE(array_list) :: array_sublist
157  INTEGER :: ndata
158  INTEGER, ALLOCATABLE, DIMENSION(:) :: data_1, data_2, data_3, data_4
159 
160  ndata = SIZE(i_selected)
161 
162  IF (ndata == 1) THEN
163  CALL get_arrays(list, data_1, i_selected=i_selected)
164  CALL create_array_list(array_sublist, ndata, data_1)
165  END IF
166  IF (ndata == 2) THEN
167  CALL get_arrays(list, data_1, data_2, i_selected=i_selected)
168  CALL create_array_list(array_sublist, ndata, data_1, data_2)
169  END IF
170  IF (ndata == 3) THEN
171  CALL get_arrays(list, data_1, data_2, data_3, i_selected=i_selected)
172  CALL create_array_list(array_sublist, ndata, data_1, data_2, data_3)
173  END IF
174  IF (ndata == 4) THEN
175  CALL get_arrays(list, data_1, data_2, data_3, data_4, i_selected=i_selected)
176  CALL create_array_list(array_sublist, ndata, data_1, data_2, data_3, data_4)
177  END IF
178  END FUNCTION
179 
180 ! **************************************************************************************************
181 !> \brief destroy array list.
182 !> \author Patrick Seewald
183 ! **************************************************************************************************
184  SUBROUTINE destroy_array_list(list)
185  TYPE(array_list), INTENT(INOUT) :: list
186 
187  DEALLOCATE (list%ptr, list%col_data)
188  END SUBROUTINE
189 
190 ! **************************************************************************************************
191 !> \brief Get all arrays contained in list
192 !> \param data arrays 1 and 2
193 !> \param i_selected array numbers to retrieve (if not present, all arrays are returned)
194 !> \author Patrick Seewald
195 ! **************************************************************************************************
196  SUBROUTINE get_arrays(list, data_1, data_2, data_3, data_4, i_selected)
197  !! Get all arrays contained in list
198  TYPE(array_list), INTENT(IN) :: list
199  INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT), &
200  OPTIONAL :: data_1, data_2, data_3, data_4
201  INTEGER, DIMENSION(:), INTENT(IN), &
202  OPTIONAL :: i_selected
203  INTEGER :: i, ndata
204  INTEGER, DIMENSION(number_of_arrays(list)) :: o
205 
206  o(:) = 0
207  IF (PRESENT(i_selected)) THEN
208  ndata = SIZE(i_selected)
209  o(1:ndata) = i_selected(:)
210  ELSE
211  ndata = number_of_arrays(list)
212  o(1:ndata) = (/(i, i=1, ndata)/)
213  END IF
214 
215  associate(ptr => list%ptr, col_data => list%col_data)
216  IF (ndata > 0) THEN
217  ALLOCATE (data_1, source=col_data(ptr(o(1)):ptr(o(1) + 1) - 1))
218  END IF
219  IF (ndata > 1) THEN
220  ALLOCATE (data_2, source=col_data(ptr(o(2)):ptr(o(2) + 1) - 1))
221  END IF
222  IF (ndata > 2) THEN
223  ALLOCATE (data_3, source=col_data(ptr(o(3)):ptr(o(3) + 1) - 1))
224  END IF
225  IF (ndata > 3) THEN
226  ALLOCATE (data_4, source=col_data(ptr(o(4)):ptr(o(4) + 1) - 1))
227  END IF
228  END associate
229 
230  END SUBROUTINE get_arrays
231 
232 ! **************************************************************************************************
233 !> \brief get ith array
234 !> \author Patrick Seewald
235 ! **************************************************************************************************
236  SUBROUTINE get_ith_array(list, i, array_size, array)
237  TYPE(array_list), INTENT(IN) :: list
238  INTEGER, INTENT(IN) :: i
239  INTEGER, INTENT(IN) :: array_size
240  INTEGER, DIMENSION(array_size), INTENT(OUT) :: array
241 
242  associate(ptr => list%ptr, col_data => list%col_data)
243  cpassert(i <= number_of_arrays(list))
244 
245  array(:) = col_data(ptr(i):ptr(i + 1) - 1)
246 
247  END associate
248 
249  END SUBROUTINE
250 
251 ! **************************************************************************************************
252 !> \brief get ith array
253 !> \author Patrick Seewald
254 ! **************************************************************************************************
255  SUBROUTINE allocate_and_get_ith_array(list, i, array)
256  TYPE(array_list), INTENT(IN) :: list
257  INTEGER, INTENT(IN) :: i
258  INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: array
259 
260  associate(ptr => list%ptr, col_data => list%col_data)
261  cpassert(i <= number_of_arrays(list))
262 
263  ALLOCATE (array, source=col_data(ptr(i):ptr(i + 1) - 1))
264  END associate
265  END SUBROUTINE
266 
267 ! **************************************************************************************************
268 !> \brief sizes of arrays stored in list
269 !> \author Patrick Seewald
270 ! **************************************************************************************************
271  FUNCTION sizes_of_arrays(list)
272  TYPE(array_list), INTENT(IN) :: list
273  INTEGER, ALLOCATABLE, DIMENSION(:) :: sizes_of_arrays
274 
275  INTEGER :: i_data, num_data
276 
277  num_data = number_of_arrays(list)
278  ALLOCATE (sizes_of_arrays(num_data))
279  DO i_data = 1, num_data
280  sizes_of_arrays(i_data) = list%ptr(i_data + 1) - list%ptr(i_data)
281  END DO
282  END FUNCTION sizes_of_arrays
283 
284 ! **************************************************************************************************
285 !> \brief sum of all elements for each array stored in list
286 !> \author Patrick Seewald
287 ! **************************************************************************************************
288  FUNCTION sum_of_arrays(list)
289  TYPE(array_list), INTENT(IN) :: list
290  INTEGER, ALLOCATABLE, DIMENSION(:) :: sum_of_arrays
291 
292  INTEGER :: i_data, num_data
293 
294  num_data = number_of_arrays(list)
295  ALLOCATE (sum_of_arrays(num_data))
296  DO i_data = 1, num_data
297  sum_of_arrays(i_data) = sum(list%col_data(list%ptr(i_data):list%ptr(i_data + 1) - 1))
298  END DO
299 
300  END FUNCTION sum_of_arrays
301 
302 ! **************************************************************************************************
303 !> \brief partial sums of array elements.
304 !> \author Patrick Seewald
305 ! **************************************************************************************************
306  SUBROUTINE array_offsets(list_in, list_out)
307  TYPE(array_list), INTENT(IN) :: list_in
308  TYPE(array_list), INTENT(OUT) :: list_out
309 
310  INTEGER :: i_data, i_ptr, num_data, partial_sum
311 
312  num_data = number_of_arrays(list_in)
313  ALLOCATE (list_out%ptr, source=list_in%ptr)
314  ALLOCATE (list_out%col_data(SIZE(list_in%col_data)))
315  DO i_data = 1, num_data
316  partial_sum = 1
317  DO i_ptr = list_out%ptr(i_data), list_out%ptr(i_data + 1) - 1
318  list_out%col_data(i_ptr) = partial_sum
319  partial_sum = partial_sum + list_in%col_data(i_ptr)
320  END DO
321  END DO
322  END SUBROUTINE
323 
324 ! **************************************************************************************************
325 !> \brief reorder array list.
326 !> \author Patrick Seewald
327 ! **************************************************************************************************
328  SUBROUTINE reorder_arrays(list_in, list_out, order)
329  TYPE(array_list), INTENT(IN) :: list_in
330  TYPE(array_list), INTENT(OUT) :: list_out
331  INTEGER, ALLOCATABLE, DIMENSION(:) :: data_1, data_2, data_3, data_4
332  INTEGER, DIMENSION(number_of_arrays(list_in)), &
333  INTENT(IN) :: order
334 
335  IF (number_of_arrays(list_in) == 2) THEN
336  CALL get_arrays(list_in, data_1, data_2, i_selected=dbt_inverse_order(order))
337  CALL create_array_list(list_out, number_of_arrays(list_in), &
338  data_1, data_2)
339  END IF
340  IF (number_of_arrays(list_in) == 3) THEN
341  CALL get_arrays(list_in, data_1, data_2, data_3, i_selected=dbt_inverse_order(order))
342  CALL create_array_list(list_out, number_of_arrays(list_in), &
343  data_1, data_2, data_3)
344  END IF
345  IF (number_of_arrays(list_in) == 4) THEN
346  CALL get_arrays(list_in, data_1, data_2, data_3, data_4, i_selected=dbt_inverse_order(order))
347  CALL create_array_list(list_out, number_of_arrays(list_in), &
348  data_1, data_2, data_3, data_4)
349  END IF
350 
351  END SUBROUTINE
352 
353 ! **************************************************************************************************
354 !> \brief check whether two array lists are equal
355 !> \author Patrick Seewald
356 ! **************************************************************************************************
357  FUNCTION check_equal(list1, list2)
358  TYPE(array_list), INTENT(IN) :: list1, list2
359  LOGICAL :: check_equal
360 
361  check_equal = array_eq_i(list1%col_data, list2%col_data) .AND. array_eq_i(list1%ptr, list2%ptr)
362  END FUNCTION
363 
364 ! **************************************************************************************************
365 !> \brief check whether two arrays are equal
366 !> \author Patrick Seewald
367 ! **************************************************************************************************
368  PURE FUNCTION array_eq_i(arr1, arr2)
369  INTEGER, INTENT(IN), DIMENSION(:) :: arr1
370  INTEGER, INTENT(IN), DIMENSION(:) :: arr2
371  LOGICAL :: array_eq_i
372 
373  array_eq_i = .false.
374  IF (SIZE(arr1) .EQ. SIZE(arr2)) array_eq_i = all(arr1 == arr2)
375 
376  END FUNCTION
377 
378 END MODULE dbt_array_list_methods
Wrapper for allocating, copying and reshaping arrays.
Representation of arbitrary number of 1d integer arrays with arbitrary sizes. This is needed for gene...
pure logical function, public array_eq_i(arr1, arr2)
check whether two arrays are equal
integer function, dimension(:), allocatable, public sum_of_arrays(list)
sum of all elements for each array stored in list
subroutine, public get_arrays(list, data_1, data_2, data_3, data_4, i_selected)
Get all arrays contained in list.
subroutine, public create_array_list(list, ndata, data_1, data_2, data_3, data_4)
collects any number of arrays of different sizes into a single array (listcol_data),...
subroutine, public destroy_array_list(list)
destroy array list.
integer function, dimension(:), allocatable, public sizes_of_arrays(list)
sizes of arrays stored in list
pure integer function, public number_of_arrays(list)
number of arrays stored in list
subroutine, public array_offsets(list_in, list_out)
partial sums of array elements.
pure integer function, dimension(number_of_arrays(list)), public get_array_elements(list, indices)
Get an element for each array.
subroutine, public get_ith_array(list, i, array_size, array)
get ith array
type(array_list) function, public array_sublist(list, i_selected)
extract a subset of arrays
subroutine, public reorder_arrays(list_in, list_out, order)
reorder array list.
logical function, public check_equal(list1, list2)
check whether two array lists are equal
tensor index and mapping to DBM index
Definition: dbt_index.F:12
pure integer function, dimension(size(order)), public dbt_inverse_order(order)
Invert order.
Definition: dbt_index.F:410
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
Definition: list.F:24