LCOV - code coverage report
Current view: top level - src/dbt - dbt_array_list_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:85b8a9b) Lines: 96.4 % 83 80
Test Date: 2026-06-14 06:48:14 Functions: 87.5 % 16 14

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 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              : ! **************************************************************************************************
      14              : MODULE dbt_array_list_methods
      15              : 
      16              :    #:include "dbt_macros.fypp"
      17              :    #:set maxdim = maxrank
      18              :    #:set ndims = range(2,maxdim+1)
      19              : 
      20              :    USE dbt_index, ONLY: dbt_inverse_order
      21              :    USE dbt_allocate_wrap, ONLY: allocate_any
      22              : 
      23              : #include "../base/base_uses.f90"
      24              : #if defined(__LIBXS)
      25              :    USE libxs, ONLY: libxs_diff
      26              : #  define PURE_ARRAY_EQ
      27              : #else
      28              : #  define PURE_ARRAY_EQ PURE
      29              : #endif
      30              : 
      31              :    IMPLICIT NONE
      32              :    PRIVATE
      33              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dbt_array_list_methods'
      34              : 
      35              :    PUBLIC  :: &
      36              :       array_eq_i, &
      37              :       array_list, &
      38              :       array_offsets, &
      39              :       array_sublist, &
      40              :       create_array_list, &
      41              :       destroy_array_list, &
      42              :       get_array_elements, &
      43              :       get_arrays, &
      44              :       get_ith_array, &
      45              :       number_of_arrays, &
      46              :       reorder_arrays, &
      47              :       sizes_of_arrays, &
      48              :       sum_of_arrays, &
      49              :       check_equal
      50              : 
      51              :    TYPE array_list
      52              :       INTEGER, DIMENSION(:), ALLOCATABLE :: col_data
      53              :       INTEGER, DIMENSION(:), ALLOCATABLE :: ptr
      54              :    END TYPE
      55              : 
      56              :    INTERFACE get_ith_array
      57              :       MODULE PROCEDURE allocate_and_get_ith_array
      58              :       MODULE PROCEDURE get_ith_array
      59              :    END INTERFACE
      60              : 
      61              : CONTAINS
      62              : 
      63              : ! **************************************************************************************************
      64              : !> \brief number of arrays stored in list
      65              : !> \author Patrick Seewald
      66              : ! **************************************************************************************************
      67    192251578 :    PURE FUNCTION number_of_arrays(list)
      68              :       TYPE(array_list), INTENT(IN) :: list
      69              :       INTEGER                      :: number_of_arrays
      70              : 
      71    192251578 :       number_of_arrays = SIZE(list%ptr) - 1
      72              : 
      73    192251578 :    END FUNCTION number_of_arrays
      74              : 
      75              : ! **************************************************************************************************
      76              : !> \brief Get an element for each array.
      77              : !> \param indices element index for each array
      78              : !> \author Patrick Seewald
      79              : ! **************************************************************************************************
      80    162748089 :    PURE FUNCTION get_array_elements(list, indices)
      81              :       TYPE(array_list), INTENT(IN)                           :: list
      82              :       INTEGER, DIMENSION(number_of_arrays(list)), INTENT(IN) :: indices
      83              :       INTEGER, DIMENSION(number_of_arrays(list))             :: get_array_elements
      84              : 
      85              :       INTEGER                                                :: i, ind
      86              : 
      87    513283717 :       DO i = 1, SIZE(indices)
      88    350535628 :          ind = indices(i) + list%ptr(i) - 1
      89    513283717 :          get_array_elements(i) = list%col_data(ind)
      90              :       END DO
      91              : 
      92              :    END FUNCTION get_array_elements
      93              : 
      94              : ! **************************************************************************************************
      95              : !> \brief collects any number of arrays of different sizes into a single array (list%col_data),
      96              : !>        storing the indices that start a new array (list%ptr).
      97              : !> \param list list of arrays
      98              : !> \param ndata number of arrays
      99              : !> \param data arrays 1 and 2
     100              : !> \author Patrick Seewald
     101              : ! **************************************************************************************************
     102      7432938 :    SUBROUTINE create_array_list(list, ndata, ${varlist("data")}$)
     103              :       TYPE(array_list), INTENT(OUT)               :: list
     104              :       INTEGER, INTENT(IN)                         :: ndata
     105              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: ${varlist("data")}$
     106              :       INTEGER                                     :: ptr, size_all
     107              : 
     108      7432938 :       size_all = 0
     109              : 
     110              :       #:for dim in range(1, maxdim+1)
     111     23675017 :          IF (ndata >= ${dim}$) THEN
     112     16243935 :             CPASSERT(PRESENT(data_${dim}$))
     113     16243935 :             size_all = size_all + SIZE(data_${dim}$)
     114              :          END IF
     115              :       #:endfor
     116              : 
     117     22298814 :       ALLOCATE (list%ptr(ndata + 1))
     118     22162705 :       ALLOCATE (list%col_data(size_all))
     119              : 
     120      7432938 :       ptr = 1
     121      7432938 :       list%ptr(1) = ptr
     122              : 
     123              :       #:for dim in range(1, maxdim+1)
     124     23675017 :          IF (ndata >= ${dim}$) THEN
     125    163383184 :             list%col_data(ptr:ptr + SIZE(data_${dim}$) - 1) = data_${dim}$ (:)
     126     16243935 :             ptr = ptr + SIZE(data_${dim}$)
     127     16243935 :             list%ptr(${dim+1}$) = ptr
     128              :          END IF
     129              :       #:endfor
     130              : 
     131      7432938 :    END SUBROUTINE
     132              : 
     133              : ! **************************************************************************************************
     134              : !> \brief extract a subset of arrays
     135              : !> \param list list of arrays
     136              : !> \param i_selected array numbers to retrieve
     137              : !> \author Patrick Seewald
     138              : ! **************************************************************************************************
     139      2967396 :    FUNCTION array_sublist(list, i_selected)
     140              :       TYPE(array_list), INTENT(IN)                           :: list
     141              :       INTEGER, DIMENSION(:), INTENT(IN)                      :: i_selected
     142              :       TYPE(array_list)                                       :: array_sublist
     143              :       INTEGER :: ndata
     144      1483698 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: ${varlist("data")}$
     145              : 
     146      1483698 :       ndata = SIZE(i_selected)
     147              : 
     148              :       #:for dim in range(1, maxdim+1)
     149      2967396 :          IF (ndata == ${dim}$) THEN
     150      1483698 :             CALL get_arrays(list, ${varlist("data", nmax=dim)}$, i_selected=i_selected)
     151      1483698 :             CALL create_array_list(array_sublist, ndata, ${varlist("data", nmax=dim)}$)
     152              :          END IF
     153              :       #:endfor
     154      2967396 :    END FUNCTION
     155              : 
     156              : ! **************************************************************************************************
     157              : !> \brief destroy array list.
     158              : !> \author Patrick Seewald
     159              : ! **************************************************************************************************
     160      5817460 :    SUBROUTINE destroy_array_list(list)
     161              :       TYPE(array_list), INTENT(INOUT) :: list
     162              : 
     163      5817460 :       DEALLOCATE (list%ptr, list%col_data)
     164      5817460 :    END SUBROUTINE
     165              : 
     166              : ! **************************************************************************************************
     167              : !> \brief Get all arrays contained in list
     168              : !> \param data arrays 1 and 2
     169              : !> \param i_selected array numbers to retrieve (if not present, all arrays are returned)
     170              : !> \author Patrick Seewald
     171              : ! **************************************************************************************************
     172      6113401 :    SUBROUTINE get_arrays(list, ${varlist("data")}$, i_selected)
     173              :       !! Get all arrays contained in list
     174              :       TYPE(array_list), INTENT(IN)                       :: list
     175              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT), &
     176              :          OPTIONAL                                        :: ${varlist("data")}$
     177              :       INTEGER, DIMENSION(:), INTENT(IN), &
     178              :          OPTIONAL                                        :: i_selected
     179              :       INTEGER                                            :: i, ndata
     180      6113401 :       INTEGER, DIMENSION(number_of_arrays(list))         :: o
     181              : 
     182     20882660 :       o(:) = 0
     183      6113401 :       IF (PRESENT(i_selected)) THEN
     184      4559148 :          ndata = SIZE(i_selected)
     185     14686691 :          o(1:ndata) = i_selected(:)
     186              :       ELSE
     187      1554253 :          ndata = number_of_arrays(list)
     188      7088699 :          o(1:ndata) = (/(i, i=1, ndata)/)
     189              :       END IF
     190              : 
     191              :       ASSOCIATE (ptr => list%ptr, col_data => list%col_data)
     192              :          #:for dim in range(1, maxdim+1)
     193     19007507 :             IF (ndata > ${dim-1}$) THEN
     194    136597056 :                ALLOCATE (data_${dim}$, source=col_data(ptr(o(${dim}$)):ptr(o(${dim}$) + 1) - 1))
     195              :             END IF
     196              :          #:endfor
     197              :       END ASSOCIATE
     198              : 
     199      6113401 :    END SUBROUTINE get_arrays
     200              : 
     201              : ! **************************************************************************************************
     202              : !> \brief get ith array
     203              : !> \author Patrick Seewald
     204              : ! **************************************************************************************************
     205      1291598 :    SUBROUTINE get_ith_array(list, i, array_size, array)
     206              :       TYPE(array_list), INTENT(IN)                    :: list
     207              :       INTEGER, INTENT(IN)                             :: i
     208              :       INTEGER, INTENT(IN)                             :: array_size
     209              :       INTEGER, DIMENSION(array_size), INTENT(OUT)     :: array
     210              : 
     211              :       ASSOCIATE (ptr => list%ptr, col_data => list%col_data)
     212            0 :          CPASSERT(i <= number_of_arrays(list))
     213              : 
     214      7071989 :          array(:) = col_data(ptr(i):ptr(i + 1) - 1)
     215              : 
     216              :       END ASSOCIATE
     217              : 
     218      1291598 :    END SUBROUTINE
     219              : 
     220              : ! **************************************************************************************************
     221              : !> \brief get ith array
     222              : !> \author Patrick Seewald
     223              : ! **************************************************************************************************
     224      1678818 :    SUBROUTINE allocate_and_get_ith_array(list, i, array)
     225              :       TYPE(array_list), INTENT(IN)                    :: list
     226              :       INTEGER, INTENT(IN)                             :: i
     227              :       INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: array
     228              : 
     229              :       ASSOCIATE (ptr => list%ptr, col_data => list%col_data)
     230            0 :          CPASSERT(i <= number_of_arrays(list))
     231              : 
     232     18514366 :          ALLOCATE (array, source=col_data(ptr(i):ptr(i + 1) - 1))
     233              :       END ASSOCIATE
     234      1678818 :    END SUBROUTINE
     235              : 
     236              : ! **************************************************************************************************
     237              : !> \brief sizes of arrays stored in list
     238              : !> \author Patrick Seewald
     239              : ! **************************************************************************************************
     240      5016594 :    FUNCTION sizes_of_arrays(list)
     241              :       TYPE(array_list), INTENT(IN)       :: list
     242              :       INTEGER, ALLOCATABLE, DIMENSION(:) :: sizes_of_arrays
     243              : 
     244              :       INTEGER                            :: i_data, num_data
     245              : 
     246      2508297 :       num_data = number_of_arrays(list)
     247      7524891 :       ALLOCATE (sizes_of_arrays(num_data))
     248      7721118 :       DO i_data = 1, num_data
     249      7721118 :          sizes_of_arrays(i_data) = list%ptr(i_data + 1) - list%ptr(i_data)
     250              :       END DO
     251              :    END FUNCTION sizes_of_arrays
     252              : 
     253              : ! **************************************************************************************************
     254              : !> \brief sum of all elements for each array stored in list
     255              : !> \author Patrick Seewald
     256              : ! **************************************************************************************************
     257      1469808 :    FUNCTION sum_of_arrays(list)
     258              :       TYPE(array_list), INTENT(IN)       :: list
     259              :       INTEGER, ALLOCATABLE, DIMENSION(:) :: sum_of_arrays
     260              : 
     261              :       INTEGER                            :: i_data, num_data
     262              : 
     263       734904 :       num_data = number_of_arrays(list)
     264      2204712 :       ALLOCATE (sum_of_arrays(num_data))
     265      1975646 :       DO i_data = 1, num_data
     266     12482350 :          sum_of_arrays(i_data) = SUM(list%col_data(list%ptr(i_data):list%ptr(i_data + 1) - 1))
     267              :       END DO
     268              : 
     269              :    END FUNCTION sum_of_arrays
     270              : 
     271              : ! **************************************************************************************************
     272              : !> \brief partial sums of array elements.
     273              : !> \author Patrick Seewald
     274              : ! **************************************************************************************************
     275       244968 :    SUBROUTINE array_offsets(list_in, list_out)
     276              :       TYPE(array_list), INTENT(IN)  :: list_in
     277              :       TYPE(array_list), INTENT(OUT) :: list_out
     278              : 
     279              :       INTEGER                       :: i_data, i_ptr, num_data, partial_sum
     280              : 
     281       244968 :       num_data = number_of_arrays(list_in)
     282      1600243 :       ALLOCATE (list_out%ptr, source=list_in%ptr)
     283       734904 :       ALLOCATE (list_out%col_data(SIZE(list_in%col_data)))
     284       865339 :       DO i_data = 1, num_data
     285       620371 :          partial_sum = 1
     286      6118691 :          DO i_ptr = list_out%ptr(i_data), list_out%ptr(i_data + 1) - 1
     287      5253352 :             list_out%col_data(i_ptr) = partial_sum
     288      5873723 :             partial_sum = partial_sum + list_in%col_data(i_ptr)
     289              :          END DO
     290              :       END DO
     291       244968 :    END SUBROUTINE
     292              : 
     293              : ! **************************************************************************************************
     294              : !> \brief reorder array list.
     295              : !> \author Patrick Seewald
     296              : ! **************************************************************************************************
     297      3075450 :    SUBROUTINE reorder_arrays(list_in, list_out, order)
     298              :       TYPE(array_list), INTENT(IN)                     :: list_in
     299              :       TYPE(array_list), INTENT(OUT)                    :: list_out
     300      3075450 :       INTEGER, ALLOCATABLE, DIMENSION(:)               :: ${varlist("data")}$
     301              :       INTEGER, DIMENSION(number_of_arrays(list_in)), &
     302              :          INTENT(IN)                                    :: order
     303              : 
     304              :       #:for ndim in ndims
     305      6150852 :          IF (number_of_arrays(list_in) == ${ndim}$) THEN
     306      3075450 :             CALL get_arrays(list_in, ${varlist("data", nmax=ndim)}$, i_selected=dbt_inverse_order(order))
     307              :             CALL create_array_list(list_out, number_of_arrays(list_in), &
     308      3075450 :                                    ${varlist("data", nmax=ndim)}$)
     309              :          END IF
     310              :       #:endfor
     311              : 
     312      3075450 :    END SUBROUTINE
     313              : 
     314              : ! **************************************************************************************************
     315              : !> \brief check whether two array lists are equal
     316              : !> \author Patrick Seewald
     317              : ! **************************************************************************************************
     318       915034 :    FUNCTION check_equal(list1, list2)
     319              :       TYPE(array_list), INTENT(IN)  :: list1, list2
     320              :       LOGICAL :: check_equal
     321              : 
     322       915034 :       check_equal = array_eq_i(list1%col_data, list2%col_data) .AND. array_eq_i(list1%ptr, list2%ptr)
     323       915034 :    END FUNCTION
     324              : 
     325              : ! **************************************************************************************************
     326              : !> \brief check whether two arrays are equal
     327              : !> \author Patrick Seewald
     328              : ! **************************************************************************************************
     329      4457341 :    PURE_ARRAY_EQ FUNCTION array_eq_i(arr1, arr2)
     330              :       INTEGER, INTENT(IN), DIMENSION(:) :: arr1
     331              :       INTEGER, INTENT(IN), DIMENSION(:) :: arr2
     332              :       LOGICAL                           :: array_eq_i
     333              : 
     334              : #if defined(__LIBXS)
     335      4457341 :       array_eq_i = .NOT. libxs_diff(arr1, arr2)
     336              : #else
     337              :       array_eq_i = .FALSE.
     338              :       IF (SIZE(arr1) == SIZE(arr2)) array_eq_i = ALL(arr1 == arr2)
     339              : #endif
     340      4457341 :    END FUNCTION
     341              : 
     342            0 : END MODULE dbt_array_list_methods
        

Generated by: LCOV version 2.0-1