LCOV - code coverage report
Current view: top level - src/grid - grid_api.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:e7e05ae) Lines: 276 278 99.3 %
Date: 2024-04-18 06:59:28 Functions: 15 17 88.2 %

          Line data    Source code
       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: BSD-3-Clause                                                          !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Fortran API for the grid package, which is written in C.
      10             : !> \author Ole Schuett
      11             : ! **************************************************************************************************
      12             : MODULE grid_api
      13             :    USE ISO_C_BINDING,                   ONLY: &
      14             :         C_ASSOCIATED, C_BOOL, C_CHAR, C_DOUBLE, C_FUNLOC, C_FUNPTR, C_INT, C_LOC, C_LONG, &
      15             :         C_NULL_PTR, C_PTR
      16             :    USE kinds,                           ONLY: dp
      17             :    USE message_passing,                 ONLY: mp_comm_type
      18             :    USE offload_api,                     ONLY: offload_buffer_type
      19             :    USE realspace_grid_types,            ONLY: realspace_grid_type
      20             :    USE string_utilities,                ONLY: strlcpy_c2f
      21             : #include "../base/base_uses.f90"
      22             : 
      23             :    IMPLICIT NONE
      24             : 
      25             :    PRIVATE
      26             : 
      27             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'grid_api'
      28             : 
      29             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_AB = 100
      30             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DADB = 200
      31             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADBmDAB_X = 301
      32             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADBmDAB_Y = 302
      33             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADBmDAB_Z = 303
      34             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_XX = 411
      35             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_XY = 412
      36             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_XZ = 413
      37             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_YX = 421
      38             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_YY = 422
      39             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_YZ = 423
      40             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_ZX = 431
      41             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_ZY = 432
      42             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ARDBmDARB_ZZ = 433
      43             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DABpADB_X = 501
      44             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DABpADB_Y = 502
      45             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DABpADB_Z = 503
      46             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DX = 601
      47             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DY = 602
      48             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DZ = 603
      49             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DXDY = 701
      50             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DYDZ = 702
      51             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DZDX = 703
      52             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DXDX = 801
      53             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DYDY = 802
      54             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DZDZ = 803
      55             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DAB_X = 901
      56             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DAB_Y = 902
      57             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_DAB_Z = 903
      58             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADB_X = 904
      59             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADB_Y = 905
      60             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_ADB_Z = 906
      61             : 
      62             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_CORE_X = 1001
      63             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_CORE_Y = 1002
      64             :    INTEGER, PARAMETER, PUBLIC :: GRID_FUNC_CORE_Z = 1003
      65             : 
      66             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_AUTO = 10
      67             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_REF = 11
      68             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_CPU = 12
      69             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_DGEMM = 13
      70             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_GPU = 14
      71             :    INTEGER, PARAMETER, PUBLIC :: GRID_BACKEND_HIP = 15
      72             : 
      73             :    PUBLIC :: grid_library_init, grid_library_finalize
      74             :    PUBLIC :: grid_library_set_config, grid_library_print_stats
      75             :    PUBLIC :: collocate_pgf_product, integrate_pgf_product
      76             :    PUBLIC :: grid_basis_set_type, grid_create_basis_set, grid_free_basis_set
      77             :    PUBLIC :: grid_task_list_type, grid_create_task_list, grid_free_task_list
      78             :    PUBLIC :: grid_collocate_task_list, grid_integrate_task_list
      79             : 
      80             :    TYPE grid_basis_set_type
      81             :       PRIVATE
      82             :       TYPE(C_PTR) :: c_ptr = C_NULL_PTR
      83             :    END TYPE grid_basis_set_type
      84             : 
      85             :    TYPE grid_task_list_type
      86             :       PRIVATE
      87             :       TYPE(C_PTR) :: c_ptr = C_NULL_PTR
      88             :    END TYPE grid_task_list_type
      89             : 
      90             : CONTAINS
      91             : 
      92             : ! **************************************************************************************************
      93             : !> \brief low level collocation of primitive gaussian functions
      94             : !> \param la_max ...
      95             : !> \param zeta ...
      96             : !> \param la_min ...
      97             : !> \param lb_max ...
      98             : !> \param zetb ...
      99             : !> \param lb_min ...
     100             : !> \param ra ...
     101             : !> \param rab ...
     102             : !> \param scale ...
     103             : !> \param pab ...
     104             : !> \param o1 ...
     105             : !> \param o2 ...
     106             : !> \param rsgrid ...
     107             : !> \param ga_gb_function ...
     108             : !> \param radius ...
     109             : !> \param use_subpatch ...
     110             : !> \param subpatch_pattern ...
     111             : !> \author Ole Schuett
     112             : ! **************************************************************************************************
     113     1110568 :    SUBROUTINE collocate_pgf_product(la_max, zeta, la_min, &
     114             :                                     lb_max, zetb, lb_min, &
     115             :                                     ra, rab, scale, pab, o1, o2, &
     116             :                                     rsgrid, &
     117             :                                     ga_gb_function, radius, &
     118             :                                     use_subpatch, subpatch_pattern)
     119             : 
     120             :       INTEGER, INTENT(IN)                                :: la_max
     121             :       REAL(KIND=dp), INTENT(IN)                          :: zeta
     122             :       INTEGER, INTENT(IN)                                :: la_min, lb_max
     123             :       REAL(KIND=dp), INTENT(IN)                          :: zetb
     124             :       INTEGER, INTENT(IN)                                :: lb_min
     125             :       REAL(KIND=dp), DIMENSION(3), INTENT(IN), TARGET    :: ra, rab
     126             :       REAL(KIND=dp), INTENT(IN)                          :: scale
     127             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: pab
     128             :       INTEGER, INTENT(IN)                                :: o1, o2
     129             :       TYPE(realspace_grid_type)                          :: rsgrid
     130             :       INTEGER, INTENT(IN)                                :: ga_gb_function
     131             :       REAL(KIND=dp), INTENT(IN)                          :: radius
     132             :       LOGICAL, OPTIONAL                                  :: use_subpatch
     133             :       INTEGER, INTENT(IN), OPTIONAL                      :: subpatch_pattern
     134             : 
     135             :       INTEGER                                            :: border_mask
     136             :       INTEGER, DIMENSION(3), TARGET                      :: border_width, npts_global, npts_local, &
     137             :                                                             shift_local
     138             :       LOGICAL(KIND=C_BOOL)                               :: orthorhombic
     139     1110568 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: grid
     140             :       INTERFACE
     141             :          SUBROUTINE grid_cpu_collocate_pgf_product_c(orthorhombic, &
     142             :                                                      border_mask, func, &
     143             :                                                      la_max, la_min, lb_max, lb_min, &
     144             :                                                      zeta, zetb, rscale, dh, dh_inv, ra, rab, &
     145             :                                                      npts_global, npts_local, shift_local, border_width, &
     146             :                                                      radius, o1, o2, n1, n2, pab, &
     147             :                                                      grid) &
     148             :             BIND(C, name="grid_cpu_collocate_pgf_product")
     149             :             IMPORT :: C_PTR, C_INT, C_DOUBLE, C_BOOL
     150             :             LOGICAL(KIND=C_BOOL), VALUE               :: orthorhombic
     151             :             INTEGER(KIND=C_INT), VALUE                :: border_mask
     152             :             INTEGER(KIND=C_INT), VALUE                :: func
     153             :             INTEGER(KIND=C_INT), VALUE                :: la_max
     154             :             INTEGER(KIND=C_INT), VALUE                :: la_min
     155             :             INTEGER(KIND=C_INT), VALUE                :: lb_max
     156             :             INTEGER(KIND=C_INT), VALUE                :: lb_min
     157             :             REAL(KIND=C_DOUBLE), VALUE                :: zeta
     158             :             REAL(KIND=C_DOUBLE), VALUE                :: zetb
     159             :             REAL(KIND=C_DOUBLE), VALUE                :: rscale
     160             :             TYPE(C_PTR), VALUE                        :: dh
     161             :             TYPE(C_PTR), VALUE                        :: dh_inv
     162             :             TYPE(C_PTR), VALUE                        :: ra
     163             :             TYPE(C_PTR), VALUE                        :: rab
     164             :             TYPE(C_PTR), VALUE                        :: npts_global
     165             :             TYPE(C_PTR), VALUE                        :: npts_local
     166             :             TYPE(C_PTR), VALUE                        :: shift_local
     167             :             TYPE(C_PTR), VALUE                        :: border_width
     168             :             REAL(KIND=C_DOUBLE), VALUE                :: radius
     169             :             INTEGER(KIND=C_INT), VALUE                :: o1
     170             :             INTEGER(KIND=C_INT), VALUE                :: o2
     171             :             INTEGER(KIND=C_INT), VALUE                :: n1
     172             :             INTEGER(KIND=C_INT), VALUE                :: n2
     173             :             TYPE(C_PTR), VALUE                        :: pab
     174             :             TYPE(C_PTR), VALUE                        :: grid
     175             :          END SUBROUTINE grid_cpu_collocate_pgf_product_c
     176             :       END INTERFACE
     177             : 
     178     1110568 :       border_mask = 0
     179     1110568 :       IF (PRESENT(use_subpatch)) THEN
     180       61024 :          IF (use_subpatch) THEN
     181       54166 :             CPASSERT(PRESENT(subpatch_pattern))
     182       54166 :             border_mask = IAND(63, NOT(subpatch_pattern))  ! invert last 6 bits
     183             :          END IF
     184             :       END IF
     185             : 
     186     1110568 :       orthorhombic = LOGICAL(rsgrid%desc%orthorhombic, C_BOOL)
     187             : 
     188     1110568 :       CPASSERT(LBOUND(pab, 1) == 1)
     189     1110568 :       CPASSERT(LBOUND(pab, 2) == 1)
     190             : 
     191             :       CALL get_rsgrid_properties(rsgrid, npts_global=npts_global, &
     192             :                                  npts_local=npts_local, &
     193             :                                  shift_local=shift_local, &
     194     1110568 :                                  border_width=border_width)
     195             : 
     196     1110568 :       grid(1:, 1:, 1:) => rsgrid%r(:, :, :)  ! pointer assignment
     197             : 
     198             : #if __GNUC__ >= 9
     199             :       CPASSERT(IS_CONTIGUOUS(rsgrid%desc%dh))
     200             :       CPASSERT(IS_CONTIGUOUS(rsgrid%desc%dh_inv))
     201             :       CPASSERT(IS_CONTIGUOUS(ra))
     202             :       CPASSERT(IS_CONTIGUOUS(rab))
     203             :       CPASSERT(IS_CONTIGUOUS(npts_global))
     204             :       CPASSERT(IS_CONTIGUOUS(npts_local))
     205             :       CPASSERT(IS_CONTIGUOUS(shift_local))
     206             :       CPASSERT(IS_CONTIGUOUS(border_width))
     207     1110568 :       CPASSERT(IS_CONTIGUOUS(pab))
     208     1110568 :       CPASSERT(IS_CONTIGUOUS(grid))
     209             : #endif
     210             : 
     211             :       ! For collocating a single pgf product we use the optimized cpu backend.
     212             : 
     213             :       CALL grid_cpu_collocate_pgf_product_c(orthorhombic=orthorhombic, &
     214             :                                             border_mask=border_mask, &
     215             :                                             func=ga_gb_function, &
     216             :                                             la_max=la_max, &
     217             :                                             la_min=la_min, &
     218             :                                             lb_max=lb_max, &
     219             :                                             lb_min=lb_min, &
     220             :                                             zeta=zeta, &
     221             :                                             zetb=zetb, &
     222             :                                             rscale=scale, &
     223             :                                             dh=C_LOC(rsgrid%desc%dh(1, 1)), &
     224             :                                             dh_inv=C_LOC(rsgrid%desc%dh_inv(1, 1)), &
     225             :                                             ra=C_LOC(ra(1)), &
     226             :                                             rab=C_LOC(rab(1)), &
     227             :                                             npts_global=C_LOC(npts_global(1)), &
     228             :                                             npts_local=C_LOC(npts_local(1)), &
     229             :                                             shift_local=C_LOC(shift_local(1)), &
     230             :                                             border_width=C_LOC(border_width(1)), &
     231             :                                             radius=radius, &
     232             :                                             o1=o1, &
     233             :                                             o2=o2, &
     234             :                                             n1=SIZE(pab, 1), &
     235             :                                             n2=SIZE(pab, 2), &
     236             :                                             pab=C_LOC(pab(1, 1)), &
     237     1110568 :                                             grid=C_LOC(grid(1, 1, 1)))
     238             : 
     239     1110568 :    END SUBROUTINE collocate_pgf_product
     240             : 
     241             : ! **************************************************************************************************
     242             : !> \brief low level function to compute matrix elements of primitive gaussian functions
     243             : !> \param la_max ...
     244             : !> \param zeta ...
     245             : !> \param la_min ...
     246             : !> \param lb_max ...
     247             : !> \param zetb ...
     248             : !> \param lb_min ...
     249             : !> \param ra ...
     250             : !> \param rab ...
     251             : !> \param rsgrid ...
     252             : !> \param hab ...
     253             : !> \param pab ...
     254             : !> \param o1 ...
     255             : !> \param o2 ...
     256             : !> \param radius ...
     257             : !> \param calculate_forces ...
     258             : !> \param force_a ...
     259             : !> \param force_b ...
     260             : !> \param compute_tau ...
     261             : !> \param use_virial ...
     262             : !> \param my_virial_a ...
     263             : !> \param my_virial_b ...
     264             : !> \param hdab Derivative with respect to the primitive on the left.
     265             : !> \param hadb Derivative with respect to the primitive on the right.
     266             : !> \param a_hdab ...
     267             : !> \param use_subpatch ...
     268             : !> \param subpatch_pattern ...
     269             : ! **************************************************************************************************
     270      853640 :    SUBROUTINE integrate_pgf_product(la_max, zeta, la_min, &
     271             :                                     lb_max, zetb, lb_min, &
     272             :                                     ra, rab, rsgrid, &
     273             :                                     hab, pab, o1, o2, &
     274             :                                     radius, &
     275             :                                     calculate_forces, force_a, force_b, &
     276             :                                     compute_tau, &
     277             :                                     use_virial, my_virial_a, &
     278             :                                     my_virial_b, hdab, hadb, a_hdab, use_subpatch, subpatch_pattern)
     279             : 
     280             :       INTEGER, INTENT(IN)                                :: la_max
     281             :       REAL(KIND=dp), INTENT(IN)                          :: zeta
     282             :       INTEGER, INTENT(IN)                                :: la_min, lb_max
     283             :       REAL(KIND=dp), INTENT(IN)                          :: zetb
     284             :       INTEGER, INTENT(IN)                                :: lb_min
     285             :       REAL(KIND=dp), DIMENSION(3), INTENT(IN), TARGET    :: ra, rab
     286             :       TYPE(realspace_grid_type), INTENT(IN)              :: rsgrid
     287             :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: hab
     288             :       REAL(KIND=dp), DIMENSION(:, :), OPTIONAL, POINTER  :: pab
     289             :       INTEGER, INTENT(IN)                                :: o1, o2
     290             :       REAL(KIND=dp), INTENT(IN)                          :: radius
     291             :       LOGICAL, INTENT(IN)                                :: calculate_forces
     292             :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT), &
     293             :          OPTIONAL                                        :: force_a, force_b
     294             :       LOGICAL, INTENT(IN), OPTIONAL                      :: compute_tau, use_virial
     295             :       REAL(KIND=dp), DIMENSION(3, 3), OPTIONAL           :: my_virial_a, my_virial_b
     296             :       REAL(KIND=dp), DIMENSION(:, :, :), OPTIONAL, &
     297             :          POINTER                                         :: hdab, hadb
     298             :       REAL(KIND=dp), DIMENSION(:, :, :, :), OPTIONAL, &
     299             :          POINTER                                         :: a_hdab
     300             :       LOGICAL, OPTIONAL                                  :: use_subpatch
     301             :       INTEGER, INTENT(IN), OPTIONAL                      :: subpatch_pattern
     302             : 
     303             :       INTEGER                                            :: border_mask
     304             :       INTEGER, DIMENSION(3), TARGET                      :: border_width, npts_global, npts_local, &
     305             :                                                             shift_local
     306             :       LOGICAL                                            :: my_use_virial
     307             :       LOGICAL(KIND=C_BOOL)                               :: my_compute_tau, orthorhombic
     308             :       REAL(KIND=dp), DIMENSION(3, 2), TARGET             :: forces
     309             :       REAL(KIND=dp), DIMENSION(3, 3, 2), TARGET          :: virials
     310      853640 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: grid
     311             :       TYPE(C_PTR)                                        :: a_hdab_cptr, forces_cptr, hadb_cptr, &
     312             :                                                             hdab_cptr, pab_cptr, virials_cptr
     313             :       INTERFACE
     314             :          SUBROUTINE grid_cpu_integrate_pgf_product_c(orthorhombic, compute_tau, &
     315             :                                                      border_mask, &
     316             :                                                      la_max, la_min, lb_max, lb_min, &
     317             :                                                      zeta, zetb, dh, dh_inv, ra, rab, &
     318             :                                                      npts_global, npts_local, shift_local, border_width, &
     319             :                                                      radius, o1, o2, n1, n2, grid, hab, pab, &
     320             :                                                      forces, virials, hdab, hadb, a_hdab) &
     321             :             BIND(C, name="grid_cpu_integrate_pgf_product")
     322             :             IMPORT :: C_PTR, C_INT, C_DOUBLE, C_BOOL
     323             :             LOGICAL(KIND=C_BOOL), VALUE               :: orthorhombic
     324             :             LOGICAL(KIND=C_BOOL), VALUE               :: compute_tau
     325             :             INTEGER(KIND=C_INT), VALUE                :: border_mask
     326             :             INTEGER(KIND=C_INT), VALUE                :: la_max
     327             :             INTEGER(KIND=C_INT), VALUE                :: la_min
     328             :             INTEGER(KIND=C_INT), VALUE                :: lb_max
     329             :             INTEGER(KIND=C_INT), VALUE                :: lb_min
     330             :             REAL(KIND=C_DOUBLE), VALUE                :: zeta
     331             :             REAL(KIND=C_DOUBLE), VALUE                :: zetb
     332             :             TYPE(C_PTR), VALUE                        :: dh
     333             :             TYPE(C_PTR), VALUE                        :: dh_inv
     334             :             TYPE(C_PTR), VALUE                        :: ra
     335             :             TYPE(C_PTR), VALUE                        :: rab
     336             :             TYPE(C_PTR), VALUE                        :: npts_global
     337             :             TYPE(C_PTR), VALUE                        :: npts_local
     338             :             TYPE(C_PTR), VALUE                        :: shift_local
     339             :             TYPE(C_PTR), VALUE                        :: border_width
     340             :             REAL(KIND=C_DOUBLE), VALUE                :: radius
     341             :             INTEGER(KIND=C_INT), VALUE                :: o1
     342             :             INTEGER(KIND=C_INT), VALUE                :: o2
     343             :             INTEGER(KIND=C_INT), VALUE                :: n1
     344             :             INTEGER(KIND=C_INT), VALUE                :: n2
     345             :             TYPE(C_PTR), VALUE                        :: grid
     346             :             TYPE(C_PTR), VALUE                        :: hab
     347             :             TYPE(C_PTR), VALUE                        :: pab
     348             :             TYPE(C_PTR), VALUE                        :: forces
     349             :             TYPE(C_PTR), VALUE                        :: virials
     350             :             TYPE(C_PTR), VALUE                        :: hdab
     351             :             TYPE(C_PTR), VALUE                        :: hadb
     352             :             TYPE(C_PTR), VALUE                        :: a_hdab
     353             :          END SUBROUTINE grid_cpu_integrate_pgf_product_c
     354             :       END INTERFACE
     355             : 
     356      853640 :       IF (radius == 0.0_dp) THEN
     357           0 :          RETURN
     358             :       END IF
     359             : 
     360      853640 :       border_mask = 0
     361      853640 :       IF (PRESENT(use_subpatch)) THEN
     362      807386 :          IF (use_subpatch) THEN
     363       48235 :             CPASSERT(PRESENT(subpatch_pattern))
     364       48235 :             border_mask = IAND(63, NOT(subpatch_pattern))  ! invert last 6 bits
     365             :          END IF
     366             :       END IF
     367             : 
     368             :       ! When true then 0.5 * (nabla x_a).(v(r) nabla x_b) is computed.
     369      853640 :       IF (PRESENT(compute_tau)) THEN
     370        2286 :          my_compute_tau = LOGICAL(compute_tau, C_BOOL)
     371             :       ELSE
     372             :          my_compute_tau = .FALSE.
     373             :       END IF
     374             : 
     375      853640 :       IF (PRESENT(use_virial)) THEN
     376      380216 :          my_use_virial = use_virial
     377             :       ELSE
     378             :          my_use_virial = .FALSE.
     379             :       END IF
     380             : 
     381      853640 :       IF (calculate_forces) THEN
     382      347755 :          CPASSERT(PRESENT(pab))
     383      347755 :          pab_cptr = C_LOC(pab(1, 1))
     384      347755 :          forces(:, :) = 0.0_dp
     385      347755 :          forces_cptr = C_LOC(forces(1, 1))
     386             :       ELSE
     387             :          pab_cptr = C_NULL_PTR
     388             :          forces_cptr = C_NULL_PTR
     389             :       END IF
     390             : 
     391      853640 :       IF (calculate_forces .AND. my_use_virial) THEN
     392       74075 :          virials(:, :, :) = 0.0_dp
     393       74075 :          virials_cptr = C_LOC(virials(1, 1, 1))
     394             :       ELSE
     395             :          virials_cptr = C_NULL_PTR
     396             :       END IF
     397             : 
     398      853640 :       IF (calculate_forces .AND. PRESENT(hdab)) THEN
     399        2059 :          hdab_cptr = C_LOC(hdab(1, 1, 1))
     400             :       ELSE
     401             :          hdab_cptr = C_NULL_PTR
     402             :       END IF
     403             : 
     404      853640 :       IF (calculate_forces .AND. PRESENT(hadb)) THEN
     405        1143 :          hadb_cptr = C_LOC(hadb(1, 1, 1))
     406             :       ELSE
     407             :          hadb_cptr = C_NULL_PTR
     408             :       END IF
     409             : 
     410      853640 :       IF (calculate_forces .AND. my_use_virial .AND. PRESENT(a_hdab)) THEN
     411          36 :          a_hdab_cptr = C_LOC(a_hdab(1, 1, 1, 1))
     412             :       ELSE
     413             :          a_hdab_cptr = C_NULL_PTR
     414             :       END IF
     415             : 
     416      853640 :       orthorhombic = LOGICAL(rsgrid%desc%orthorhombic, C_BOOL)
     417             : 
     418             :       CALL get_rsgrid_properties(rsgrid, npts_global=npts_global, &
     419             :                                  npts_local=npts_local, &
     420             :                                  shift_local=shift_local, &
     421      853640 :                                  border_width=border_width)
     422             : 
     423      853640 :       grid(1:, 1:, 1:) => rsgrid%r(:, :, :) ! pointer assignment
     424             : 
     425             : #if __GNUC__ >= 9
     426             :       CPASSERT(IS_CONTIGUOUS(rsgrid%desc%dh))
     427             :       CPASSERT(IS_CONTIGUOUS(rsgrid%desc%dh_inv))
     428             :       CPASSERT(IS_CONTIGUOUS(ra))
     429             :       CPASSERT(IS_CONTIGUOUS(rab))
     430             :       CPASSERT(IS_CONTIGUOUS(npts_global))
     431             :       CPASSERT(IS_CONTIGUOUS(npts_local))
     432             :       CPASSERT(IS_CONTIGUOUS(shift_local))
     433             :       CPASSERT(IS_CONTIGUOUS(border_width))
     434      853640 :       CPASSERT(IS_CONTIGUOUS(grid))
     435      853640 :       CPASSERT(IS_CONTIGUOUS(hab))
     436             :       CPASSERT(IS_CONTIGUOUS(forces))
     437             :       CPASSERT(IS_CONTIGUOUS(virials))
     438      853640 :       IF (PRESENT(pab)) THEN
     439      382525 :          CPASSERT(IS_CONTIGUOUS(pab))
     440             :       END IF
     441      853640 :       IF (PRESENT(hdab)) THEN
     442       24066 :          CPASSERT(IS_CONTIGUOUS(hdab))
     443             :       END IF
     444      853640 :       IF (PRESENT(a_hdab)) THEN
     445       22923 :          CPASSERT(IS_CONTIGUOUS(a_hdab))
     446             :       END IF
     447             : #endif
     448             : 
     449             :       CALL grid_cpu_integrate_pgf_product_c(orthorhombic=orthorhombic, &
     450             :                                             compute_tau=my_compute_tau, &
     451             :                                             border_mask=border_mask, &
     452             :                                             la_max=la_max, &
     453             :                                             la_min=la_min, &
     454             :                                             lb_max=lb_max, &
     455             :                                             lb_min=lb_min, &
     456             :                                             zeta=zeta, &
     457             :                                             zetb=zetb, &
     458             :                                             dh=C_LOC(rsgrid%desc%dh(1, 1)), &
     459             :                                             dh_inv=C_LOC(rsgrid%desc%dh_inv(1, 1)), &
     460             :                                             ra=C_LOC(ra(1)), &
     461             :                                             rab=C_LOC(rab(1)), &
     462             :                                             npts_global=C_LOC(npts_global(1)), &
     463             :                                             npts_local=C_LOC(npts_local(1)), &
     464             :                                             shift_local=C_LOC(shift_local(1)), &
     465             :                                             border_width=C_LOC(border_width(1)), &
     466             :                                             radius=radius, &
     467             :                                             o1=o1, &
     468             :                                             o2=o2, &
     469             :                                             n1=SIZE(hab, 1), &
     470             :                                             n2=SIZE(hab, 2), &
     471             :                                             grid=C_LOC(grid(1, 1, 1)), &
     472             :                                             hab=C_LOC(hab(1, 1)), &
     473             :                                             pab=pab_cptr, &
     474             :                                             forces=forces_cptr, &
     475             :                                             virials=virials_cptr, &
     476             :                                             hdab=hdab_cptr, &
     477             :                                             hadb=hadb_cptr, &
     478      853640 :                                             a_hdab=a_hdab_cptr)
     479             : 
     480      853640 :       IF (PRESENT(force_a) .AND. C_ASSOCIATED(forces_cptr)) &
     481     1381292 :          force_a = force_a + forces(:, 1)
     482      853640 :       IF (PRESENT(force_b) .AND. C_ASSOCIATED(forces_cptr)) &
     483     1381292 :          force_b = force_b + forces(:, 2)
     484      853640 :       IF (PRESENT(my_virial_a) .AND. C_ASSOCIATED(virials_cptr)) &
     485      962975 :          my_virial_a = my_virial_a + virials(:, :, 1)
     486      853640 :       IF (PRESENT(my_virial_b) .AND. C_ASSOCIATED(virials_cptr)) &
     487      962975 :          my_virial_b = my_virial_b + virials(:, :, 2)
     488             : 
     489      853640 :    END SUBROUTINE integrate_pgf_product
     490             : 
     491             : ! **************************************************************************************************
     492             : !> \brief Helper routines for getting rsgrid properties and asserting underlying assumptions.
     493             : !> \param rsgrid ...
     494             : !> \param npts_global ...
     495             : !> \param npts_local ...
     496             : !> \param shift_local ...
     497             : !> \param border_width ...
     498             : !> \author Ole Schuett
     499             : ! **************************************************************************************************
     500     2016686 :    SUBROUTINE get_rsgrid_properties(rsgrid, npts_global, npts_local, shift_local, border_width)
     501             :       TYPE(realspace_grid_type), INTENT(IN)              :: rsgrid
     502             :       INTEGER, DIMENSION(:)                              :: npts_global, npts_local, shift_local, &
     503             :                                                             border_width
     504             : 
     505             :       INTEGER                                            :: i
     506             : 
     507             :       ! See rs_grid_create() in ./src/pw/realspace_grid_types.F.
     508     4033372 :       CPASSERT(LBOUND(rsgrid%r, 1) == rsgrid%lb_local(1))
     509     4033372 :       CPASSERT(UBOUND(rsgrid%r, 1) == rsgrid%ub_local(1))
     510     4033372 :       CPASSERT(LBOUND(rsgrid%r, 2) == rsgrid%lb_local(2))
     511     4033372 :       CPASSERT(UBOUND(rsgrid%r, 2) == rsgrid%ub_local(2))
     512     4033372 :       CPASSERT(LBOUND(rsgrid%r, 3) == rsgrid%lb_local(3))
     513     4033372 :       CPASSERT(UBOUND(rsgrid%r, 3) == rsgrid%ub_local(3))
     514             : 
     515             :       ! While the rsgrid code assumes that the grid starts at rsgrid%lb,
     516             :       ! the collocate code assumes that the grid starts at (1,1,1) in Fortran, or (0,0,0) in C.
     517             :       ! So, a point rp(:) gets the following grid coordinates MODULO(rp(:)/dr(:),npts_global(:))
     518             : 
     519             :       ! Number of global grid points in each direction.
     520     8066744 :       npts_global = rsgrid%desc%ub - rsgrid%desc%lb + 1
     521             : 
     522             :       ! Number of local grid points in each direction.
     523     8066744 :       npts_local = rsgrid%ub_local - rsgrid%lb_local + 1
     524             : 
     525             :       ! Number of points the local grid is shifted wrt global grid.
     526     8066744 :       shift_local = rsgrid%lb_local - rsgrid%desc%lb
     527             : 
     528             :       ! Convert rsgrid%desc%border and rsgrid%desc%perd into the more convenient border_width array.
     529     8066744 :       DO i = 1, 3
     530     8066744 :          IF (rsgrid%desc%perd(i) == 1) THEN
     531             :             ! Periodic meaning the grid in this direction is entriely present on every processor.
     532     6049622 :             CPASSERT(npts_local(i) == npts_global(i))
     533     6049622 :             CPASSERT(shift_local(i) == 0)
     534             :             ! No need for halo regions.
     535     6049622 :             border_width(i) = 0
     536             :          ELSE
     537             :             ! Not periodic meaning the grid in this direction is distributed among processors.
     538         436 :             CPASSERT(npts_local(i) <= npts_global(i))
     539             :             ! Check bounds of grid section that is owned by this processor.
     540         436 :             CPASSERT(rsgrid%lb_real(i) == rsgrid%lb_local(i) + rsgrid%desc%border)
     541         436 :             CPASSERT(rsgrid%ub_real(i) == rsgrid%ub_local(i) - rsgrid%desc%border)
     542             :             ! We have halo regions.
     543         436 :             border_width(i) = rsgrid%desc%border
     544             :          END IF
     545             :       END DO
     546     2016686 :    END SUBROUTINE get_rsgrid_properties
     547             : 
     548             : ! **************************************************************************************************
     549             : !> \brief Allocates a basis set which can be passed to grid_create_task_list.
     550             : !> \param nset ...
     551             : !> \param nsgf ...
     552             : !> \param maxco ...
     553             : !> \param maxpgf ...
     554             : !> \param lmin ...
     555             : !> \param lmax ...
     556             : !> \param npgf ...
     557             : !> \param nsgf_set ...
     558             : !> \param first_sgf ...
     559             : !> \param sphi ...
     560             : !> \param zet ...
     561             : !> \param basis_set ...
     562             : !> \author Ole Schuett
     563             : ! **************************************************************************************************
     564       14063 :    SUBROUTINE grid_create_basis_set(nset, nsgf, maxco, maxpgf, &
     565       14063 :                                     lmin, lmax, npgf, nsgf_set, first_sgf, sphi, zet, &
     566             :                                     basis_set)
     567             :       INTEGER, INTENT(IN)                                :: nset, nsgf, maxco, maxpgf
     568             :       INTEGER, DIMENSION(:), INTENT(IN), TARGET          :: lmin, lmax, npgf, nsgf_set
     569             :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: first_sgf
     570             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), TARGET :: sphi, zet
     571             :       TYPE(grid_basis_set_type), INTENT(INOUT)           :: basis_set
     572             : 
     573             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_create_basis_set'
     574             : 
     575             :       INTEGER                                            :: handle
     576       28126 :       INTEGER, DIMENSION(nset), TARGET                   :: my_first_sgf
     577             :       TYPE(C_PTR)                                        :: first_sgf_c, lmax_c, lmin_c, npgf_c, &
     578             :                                                             nsgf_set_c, sphi_c, zet_c
     579             :       INTERFACE
     580             :          SUBROUTINE grid_create_basis_set_c(nset, nsgf, maxco, maxpgf, &
     581             :                                             lmin, lmax, npgf, nsgf_set, first_sgf, sphi, zet, &
     582             :                                             basis_set) &
     583             :             BIND(C, name="grid_create_basis_set")
     584             :             IMPORT :: C_PTR, C_INT
     585             :             INTEGER(KIND=C_INT), VALUE                :: nset
     586             :             INTEGER(KIND=C_INT), VALUE                :: nsgf
     587             :             INTEGER(KIND=C_INT), VALUE                :: maxco
     588             :             INTEGER(KIND=C_INT), VALUE                :: maxpgf
     589             :             TYPE(C_PTR), VALUE                        :: lmin
     590             :             TYPE(C_PTR), VALUE                        :: lmax
     591             :             TYPE(C_PTR), VALUE                        :: npgf
     592             :             TYPE(C_PTR), VALUE                        :: nsgf_set
     593             :             TYPE(C_PTR), VALUE                        :: first_sgf
     594             :             TYPE(C_PTR), VALUE                        :: sphi
     595             :             TYPE(C_PTR), VALUE                        :: zet
     596             :             TYPE(C_PTR)                               :: basis_set
     597             :          END SUBROUTINE grid_create_basis_set_c
     598             :       END INTERFACE
     599             : 
     600       14063 :       CALL timeset(routineN, handle)
     601             : 
     602       14063 :       CPASSERT(SIZE(lmin) == nset)
     603       14063 :       CPASSERT(SIZE(lmin) == nset)
     604       14063 :       CPASSERT(SIZE(lmax) == nset)
     605       14063 :       CPASSERT(SIZE(npgf) == nset)
     606       14063 :       CPASSERT(SIZE(nsgf_set) == nset)
     607       14063 :       CPASSERT(SIZE(first_sgf, 2) == nset)
     608       14063 :       CPASSERT(SIZE(sphi, 1) == maxco .AND. SIZE(sphi, 2) == nsgf)
     609       14063 :       CPASSERT(SIZE(zet, 1) == maxpgf .AND. SIZE(zet, 2) == nset)
     610       14063 :       CPASSERT(.NOT. C_ASSOCIATED(basis_set%c_ptr))
     611             : 
     612             : #if __GNUC__ >= 9
     613       14063 :       CPASSERT(IS_CONTIGUOUS(lmin))
     614       14063 :       CPASSERT(IS_CONTIGUOUS(lmax))
     615       14063 :       CPASSERT(IS_CONTIGUOUS(npgf))
     616       14063 :       CPASSERT(IS_CONTIGUOUS(nsgf_set))
     617             :       CPASSERT(IS_CONTIGUOUS(my_first_sgf))
     618       14063 :       CPASSERT(IS_CONTIGUOUS(sphi))
     619       14063 :       CPASSERT(IS_CONTIGUOUS(zet))
     620             : #endif
     621             : 
     622       14063 :       lmin_c = C_NULL_PTR
     623       14063 :       lmax_c = C_NULL_PTR
     624       14063 :       npgf_c = C_NULL_PTR
     625       14063 :       nsgf_set_c = C_NULL_PTR
     626       14063 :       first_sgf_c = C_NULL_PTR
     627       14063 :       sphi_c = C_NULL_PTR
     628       14063 :       zet_c = C_NULL_PTR
     629             : 
     630             :       ! Basis sets arrays can be empty, need to check before accessing the first element.
     631       14063 :       IF (nset > 0) THEN
     632       14055 :          lmin_c = C_LOC(lmin(1))
     633       14055 :          lmax_c = C_LOC(lmax(1))
     634       14055 :          npgf_c = C_LOC(npgf(1))
     635       14055 :          nsgf_set_c = C_LOC(nsgf_set(1))
     636             :       END IF
     637       14063 :       IF (SIZE(first_sgf) > 0) THEN
     638       46312 :          my_first_sgf(:) = first_sgf(1, :)  ! make a contiguous copy
     639       14055 :          first_sgf_c = C_LOC(my_first_sgf(1))
     640             :       END IF
     641       14063 :       IF (SIZE(sphi) > 0) THEN
     642       14053 :          sphi_c = C_LOC(sphi(1, 1))
     643             :       END IF
     644       14063 :       IF (SIZE(zet) > 0) THEN
     645       14053 :          zet_c = C_LOC(zet(1, 1))
     646             :       END IF
     647             : 
     648             :       CALL grid_create_basis_set_c(nset=nset, &
     649             :                                    nsgf=nsgf, &
     650             :                                    maxco=maxco, &
     651             :                                    maxpgf=maxpgf, &
     652             :                                    lmin=lmin_c, &
     653             :                                    lmax=lmax_c, &
     654             :                                    npgf=npgf_c, &
     655             :                                    nsgf_set=nsgf_set_c, &
     656             :                                    first_sgf=first_sgf_c, &
     657             :                                    sphi=sphi_c, &
     658             :                                    zet=zet_c, &
     659       14063 :                                    basis_set=basis_set%c_ptr)
     660       14063 :       CPASSERT(C_ASSOCIATED(basis_set%c_ptr))
     661             : 
     662       14063 :       CALL timestop(handle)
     663       14063 :    END SUBROUTINE grid_create_basis_set
     664             : 
     665             : ! **************************************************************************************************
     666             : !> \brief Deallocates given basis set.
     667             : !> \param basis_set ...
     668             : !> \author Ole Schuett
     669             : ! **************************************************************************************************
     670       14063 :    SUBROUTINE grid_free_basis_set(basis_set)
     671             :       TYPE(grid_basis_set_type), INTENT(INOUT)           :: basis_set
     672             : 
     673             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_free_basis_set'
     674             : 
     675             :       INTEGER                                            :: handle
     676             :       INTERFACE
     677             :          SUBROUTINE grid_free_basis_set_c(basis_set) &
     678             :             BIND(C, name="grid_free_basis_set")
     679             :             IMPORT :: C_PTR
     680             :             TYPE(C_PTR), VALUE                        :: basis_set
     681             :          END SUBROUTINE grid_free_basis_set_c
     682             :       END INTERFACE
     683             : 
     684       14063 :       CALL timeset(routineN, handle)
     685             : 
     686       14063 :       CPASSERT(C_ASSOCIATED(basis_set%c_ptr))
     687             : 
     688       14063 :       CALL grid_free_basis_set_c(basis_set%c_ptr)
     689             : 
     690       14063 :       basis_set%c_ptr = C_NULL_PTR
     691             : 
     692       14063 :       CALL timestop(handle)
     693       14063 :    END SUBROUTINE grid_free_basis_set
     694             : 
     695             : ! **************************************************************************************************
     696             : !> \brief Allocates a task list which can be passed to grid_collocate_task_list.
     697             : !> \param ntasks ...
     698             : !> \param natoms ...
     699             : !> \param nkinds ...
     700             : !> \param nblocks ...
     701             : !> \param block_offsets ...
     702             : !> \param atom_positions ...
     703             : !> \param atom_kinds ...
     704             : !> \param basis_sets ...
     705             : !> \param level_list ...
     706             : !> \param iatom_list ...
     707             : !> \param jatom_list ...
     708             : !> \param iset_list ...
     709             : !> \param jset_list ...
     710             : !> \param ipgf_list ...
     711             : !> \param jpgf_list ...
     712             : !> \param border_mask_list ...
     713             : !> \param block_num_list ...
     714             : !> \param radius_list ...
     715             : !> \param rab_list ...
     716             : !> \param rs_grids ...
     717             : !> \param task_list ...
     718             : !> \author Ole Schuett
     719             : ! **************************************************************************************************
     720       13210 :    SUBROUTINE grid_create_task_list(ntasks, natoms, nkinds, nblocks, &
     721       13210 :                                     block_offsets, atom_positions, atom_kinds, basis_sets, &
     722       13210 :                                     level_list, iatom_list, jatom_list, &
     723       13210 :                                     iset_list, jset_list, ipgf_list, jpgf_list, &
     724       13210 :                                     border_mask_list, block_num_list, &
     725       13210 :                                     radius_list, rab_list, rs_grids, task_list)
     726             : 
     727             :       INTEGER, INTENT(IN)                                :: ntasks, natoms, nkinds, nblocks
     728             :       INTEGER, DIMENSION(:), INTENT(IN), TARGET          :: block_offsets
     729             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), TARGET :: atom_positions
     730             :       INTEGER, DIMENSION(:), INTENT(IN), TARGET          :: atom_kinds
     731             :       TYPE(grid_basis_set_type), DIMENSION(:), &
     732             :          INTENT(IN), TARGET                              :: basis_sets
     733             :       INTEGER, DIMENSION(:), INTENT(IN), TARGET          :: level_list, iatom_list, jatom_list, &
     734             :                                                             iset_list, jset_list, ipgf_list, &
     735             :                                                             jpgf_list, border_mask_list, &
     736             :                                                             block_num_list
     737             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), TARGET    :: radius_list
     738             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), TARGET :: rab_list
     739             :       TYPE(realspace_grid_type), DIMENSION(:), &
     740             :          INTENT(IN)                                      :: rs_grids
     741             :       TYPE(grid_task_list_type), INTENT(INOUT)           :: task_list
     742             : 
     743             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_create_task_list'
     744             : 
     745             :       INTEGER                                            :: handle, ikind, ilevel, nlevels
     746       13210 :       INTEGER, ALLOCATABLE, DIMENSION(:, :), TARGET      :: border_width, npts_global, npts_local, &
     747       13210 :                                                             shift_local
     748             :       LOGICAL(KIND=C_BOOL)                               :: orthorhombic
     749             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     750       13210 :          TARGET                                          :: dh, dh_inv
     751             :       TYPE(C_PTR) :: block_num_list_c, block_offsets_c, border_mask_list_c, iatom_list_c, &
     752             :          ipgf_list_c, iset_list_c, jatom_list_c, jpgf_list_c, jset_list_c, level_list_c, &
     753             :          rab_list_c, radius_list_c
     754       13210 :       TYPE(C_PTR), ALLOCATABLE, DIMENSION(:), TARGET     :: basis_sets_c
     755             :       INTERFACE
     756             :          SUBROUTINE grid_create_task_list_c(orthorhombic, &
     757             :                                             ntasks, nlevels, natoms, nkinds, nblocks, &
     758             :                                             block_offsets, atom_positions, atom_kinds, basis_sets, &
     759             :                                             level_list, iatom_list, jatom_list, &
     760             :                                             iset_list, jset_list, ipgf_list, jpgf_list, &
     761             :                                             border_mask_list, block_num_list, &
     762             :                                             radius_list, rab_list, &
     763             :                                             npts_global, npts_local, shift_local, &
     764             :                                             border_width, dh, dh_inv, task_list) &
     765             :             BIND(C, name="grid_create_task_list")
     766             :             IMPORT :: C_PTR, C_INT, C_BOOL
     767             :             LOGICAL(KIND=C_BOOL), VALUE               :: orthorhombic
     768             :             INTEGER(KIND=C_INT), VALUE                :: ntasks
     769             :             INTEGER(KIND=C_INT), VALUE                :: nlevels
     770             :             INTEGER(KIND=C_INT), VALUE                :: natoms
     771             :             INTEGER(KIND=C_INT), VALUE                :: nkinds
     772             :             INTEGER(KIND=C_INT), VALUE                :: nblocks
     773             :             TYPE(C_PTR), VALUE                        :: block_offsets
     774             :             TYPE(C_PTR), VALUE                        :: atom_positions
     775             :             TYPE(C_PTR), VALUE                        :: atom_kinds
     776             :             TYPE(C_PTR), VALUE                        :: basis_sets
     777             :             TYPE(C_PTR), VALUE                        :: level_list
     778             :             TYPE(C_PTR), VALUE                        :: iatom_list
     779             :             TYPE(C_PTR), VALUE                        :: jatom_list
     780             :             TYPE(C_PTR), VALUE                        :: iset_list
     781             :             TYPE(C_PTR), VALUE                        :: jset_list
     782             :             TYPE(C_PTR), VALUE                        :: ipgf_list
     783             :             TYPE(C_PTR), VALUE                        :: jpgf_list
     784             :             TYPE(C_PTR), VALUE                        :: border_mask_list
     785             :             TYPE(C_PTR), VALUE                        :: block_num_list
     786             :             TYPE(C_PTR), VALUE                        :: radius_list
     787             :             TYPE(C_PTR), VALUE                        :: rab_list
     788             :             TYPE(C_PTR), VALUE                        :: npts_global
     789             :             TYPE(C_PTR), VALUE                        :: npts_local
     790             :             TYPE(C_PTR), VALUE                        :: shift_local
     791             :             TYPE(C_PTR), VALUE                        :: border_width
     792             :             TYPE(C_PTR), VALUE                        :: dh
     793             :             TYPE(C_PTR), VALUE                        :: dh_inv
     794             :             TYPE(C_PTR)                               :: task_list
     795             :          END SUBROUTINE grid_create_task_list_c
     796             :       END INTERFACE
     797             : 
     798       13210 :       CALL timeset(routineN, handle)
     799             : 
     800       13210 :       CPASSERT(SIZE(block_offsets) == nblocks)
     801       13210 :       CPASSERT(SIZE(atom_positions, 1) == 3 .AND. SIZE(atom_positions, 2) == natoms)
     802       13210 :       CPASSERT(SIZE(atom_kinds) == natoms)
     803       13210 :       CPASSERT(SIZE(basis_sets) == nkinds)
     804       13210 :       CPASSERT(SIZE(level_list) == ntasks)
     805       13210 :       CPASSERT(SIZE(iatom_list) == ntasks)
     806       13210 :       CPASSERT(SIZE(jatom_list) == ntasks)
     807       13210 :       CPASSERT(SIZE(iset_list) == ntasks)
     808       13210 :       CPASSERT(SIZE(jset_list) == ntasks)
     809       13210 :       CPASSERT(SIZE(ipgf_list) == ntasks)
     810       13210 :       CPASSERT(SIZE(jpgf_list) == ntasks)
     811       13210 :       CPASSERT(SIZE(border_mask_list) == ntasks)
     812       13210 :       CPASSERT(SIZE(block_num_list) == ntasks)
     813       13210 :       CPASSERT(SIZE(radius_list) == ntasks)
     814       13210 :       CPASSERT(SIZE(rab_list, 1) == 3 .AND. SIZE(rab_list, 2) == ntasks)
     815             : 
     816       39630 :       ALLOCATE (basis_sets_c(nkinds))
     817       36877 :       DO ikind = 1, nkinds
     818       36877 :          basis_sets_c(ikind) = basis_sets(ikind)%c_ptr
     819             :       END DO
     820             : 
     821       13210 :       nlevels = SIZE(rs_grids)
     822       13210 :       CPASSERT(nlevels > 0)
     823       13210 :       orthorhombic = LOGICAL(rs_grids(1)%desc%orthorhombic, C_BOOL)
     824             : 
     825       66050 :       ALLOCATE (npts_global(3, nlevels), npts_local(3, nlevels))
     826       66050 :       ALLOCATE (shift_local(3, nlevels), border_width(3, nlevels))
     827       66050 :       ALLOCATE (dh(3, 3, nlevels), dh_inv(3, 3, nlevels))
     828       65688 :       DO ilevel = 1, nlevels
     829       13210 :          ASSOCIATE (rsgrid => rs_grids(ilevel))
     830             :             CALL get_rsgrid_properties(rsgrid=rsgrid, &
     831             :                                        npts_global=npts_global(:, ilevel), &
     832             :                                        npts_local=npts_local(:, ilevel), &
     833             :                                        shift_local=shift_local(:, ilevel), &
     834       52478 :                                        border_width=border_width(:, ilevel))
     835       52478 :             CPASSERT(rsgrid%desc%orthorhombic .EQV. orthorhombic)  ! should be the same for all levels
     836      682214 :             dh(:, :, ilevel) = rsgrid%desc%dh(:, :)
     837      734692 :             dh_inv(:, :, ilevel) = rsgrid%desc%dh_inv(:, :)
     838             :          END ASSOCIATE
     839             :       END DO
     840             : 
     841             : #if __GNUC__ >= 9
     842       13210 :       CPASSERT(IS_CONTIGUOUS(block_offsets))
     843       13210 :       CPASSERT(IS_CONTIGUOUS(atom_positions))
     844       13210 :       CPASSERT(IS_CONTIGUOUS(atom_kinds))
     845       13210 :       CPASSERT(IS_CONTIGUOUS(basis_sets))
     846       13210 :       CPASSERT(IS_CONTIGUOUS(level_list))
     847       13210 :       CPASSERT(IS_CONTIGUOUS(iatom_list))
     848       13210 :       CPASSERT(IS_CONTIGUOUS(jatom_list))
     849       13210 :       CPASSERT(IS_CONTIGUOUS(iset_list))
     850       13210 :       CPASSERT(IS_CONTIGUOUS(jset_list))
     851       13210 :       CPASSERT(IS_CONTIGUOUS(ipgf_list))
     852       13210 :       CPASSERT(IS_CONTIGUOUS(jpgf_list))
     853       13210 :       CPASSERT(IS_CONTIGUOUS(border_mask_list))
     854       13210 :       CPASSERT(IS_CONTIGUOUS(block_num_list))
     855       13210 :       CPASSERT(IS_CONTIGUOUS(radius_list))
     856       13210 :       CPASSERT(IS_CONTIGUOUS(rab_list))
     857             :       CPASSERT(IS_CONTIGUOUS(npts_global))
     858             :       CPASSERT(IS_CONTIGUOUS(npts_local))
     859             :       CPASSERT(IS_CONTIGUOUS(shift_local))
     860             :       CPASSERT(IS_CONTIGUOUS(border_width))
     861             :       CPASSERT(IS_CONTIGUOUS(dh))
     862             :       CPASSERT(IS_CONTIGUOUS(dh_inv))
     863             : #endif
     864             : 
     865       13210 :       IF (ntasks > 0) THEN
     866       12984 :          block_offsets_c = C_LOC(block_offsets(1))
     867       12984 :          level_list_c = C_LOC(level_list(1))
     868       12984 :          iatom_list_c = C_LOC(iatom_list(1))
     869       12984 :          jatom_list_c = C_LOC(jatom_list(1))
     870       12984 :          iset_list_c = C_LOC(iset_list(1))
     871       12984 :          jset_list_c = C_LOC(jset_list(1))
     872       12984 :          ipgf_list_c = C_LOC(ipgf_list(1))
     873       12984 :          jpgf_list_c = C_LOC(jpgf_list(1))
     874       12984 :          border_mask_list_c = C_LOC(border_mask_list(1))
     875       12984 :          block_num_list_c = C_LOC(block_num_list(1))
     876       12984 :          radius_list_c = C_LOC(radius_list(1))
     877       12984 :          rab_list_c = C_LOC(rab_list(1, 1))
     878             :       ELSE
     879             :          ! Without tasks the lists are empty and there is no first element to call C_LOC on.
     880             :          block_offsets_c = C_NULL_PTR
     881             :          level_list_c = C_NULL_PTR
     882             :          iatom_list_c = C_NULL_PTR
     883             :          jatom_list_c = C_NULL_PTR
     884             :          iset_list_c = C_NULL_PTR
     885             :          jset_list_c = C_NULL_PTR
     886             :          ipgf_list_c = C_NULL_PTR
     887             :          jpgf_list_c = C_NULL_PTR
     888             :          border_mask_list_c = C_NULL_PTR
     889             :          block_num_list_c = C_NULL_PTR
     890             :          radius_list_c = C_NULL_PTR
     891             :          rab_list_c = C_NULL_PTR
     892             :       END IF
     893             : 
     894             :       !If task_list%c_ptr is already allocated, then its memory will be reused or freed.
     895             :       CALL grid_create_task_list_c(orthorhombic=orthorhombic, &
     896             :                                    ntasks=ntasks, &
     897             :                                    nlevels=nlevels, &
     898             :                                    natoms=natoms, &
     899             :                                    nkinds=nkinds, &
     900             :                                    nblocks=nblocks, &
     901             :                                    block_offsets=block_offsets_c, &
     902             :                                    atom_positions=C_LOC(atom_positions(1, 1)), &
     903             :                                    atom_kinds=C_LOC(atom_kinds(1)), &
     904             :                                    basis_sets=C_LOC(basis_sets_c(1)), &
     905             :                                    level_list=level_list_c, &
     906             :                                    iatom_list=iatom_list_c, &
     907             :                                    jatom_list=jatom_list_c, &
     908             :                                    iset_list=iset_list_c, &
     909             :                                    jset_list=jset_list_c, &
     910             :                                    ipgf_list=ipgf_list_c, &
     911             :                                    jpgf_list=jpgf_list_c, &
     912             :                                    border_mask_list=border_mask_list_c, &
     913             :                                    block_num_list=block_num_list_c, &
     914             :                                    radius_list=radius_list_c, &
     915             :                                    rab_list=rab_list_c, &
     916             :                                    npts_global=C_LOC(npts_global(1, 1)), &
     917             :                                    npts_local=C_LOC(npts_local(1, 1)), &
     918             :                                    shift_local=C_LOC(shift_local(1, 1)), &
     919             :                                    border_width=C_LOC(border_width(1, 1)), &
     920             :                                    dh=C_LOC(dh(1, 1, 1)), &
     921             :                                    dh_inv=C_LOC(dh_inv(1, 1, 1)), &
     922       13210 :                                    task_list=task_list%c_ptr)
     923             : 
     924       13210 :       CPASSERT(C_ASSOCIATED(task_list%c_ptr))
     925             : 
     926       13210 :       CALL timestop(handle)
     927       26420 :    END SUBROUTINE grid_create_task_list
     928             : 
     929             : ! **************************************************************************************************
     930             : !> \brief Deallocates given task list, basis_sets have to be freed separately.
     931             : !> \param task_list ...
     932             : !> \author Ole Schuett
     933             : ! **************************************************************************************************
     934        7864 :    SUBROUTINE grid_free_task_list(task_list)
     935             :       TYPE(grid_task_list_type), INTENT(INOUT)           :: task_list
     936             : 
     937             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_free_task_list'
     938             : 
     939             :       INTEGER                                            :: handle
     940             :       INTERFACE
     941             :          SUBROUTINE grid_free_task_list_c(task_list) &
     942             :             BIND(C, name="grid_free_task_list")
     943             :             IMPORT :: C_PTR
     944             :             TYPE(C_PTR), VALUE                        :: task_list
     945             :          END SUBROUTINE grid_free_task_list_c
     946             :       END INTERFACE
     947             : 
     948        7864 :       CALL timeset(routineN, handle)
     949             : 
     950        7864 :       IF (C_ASSOCIATED(task_list%c_ptr)) THEN
     951        7864 :          CALL grid_free_task_list_c(task_list%c_ptr)
     952             :       END IF
     953             : 
     954        7864 :       task_list%c_ptr = C_NULL_PTR
     955             : 
     956        7864 :       CALL timestop(handle)
     957        7864 :    END SUBROUTINE grid_free_task_list
     958             : 
     959             : ! **************************************************************************************************
     960             : !> \brief Collocate all tasks of in given list onto given grids.
     961             : !> \param task_list ...
     962             : !> \param ga_gb_function ...
     963             : !> \param pab_blocks ...
     964             : !> \param rs_grids ...
     965             : !> \author Ole Schuett
     966             : ! **************************************************************************************************
     967      191279 :    SUBROUTINE grid_collocate_task_list(task_list, ga_gb_function, pab_blocks, rs_grids)
     968             :       TYPE(grid_task_list_type), INTENT(IN)              :: task_list
     969             :       INTEGER, INTENT(IN)                                :: ga_gb_function
     970             :       TYPE(offload_buffer_type), INTENT(IN)              :: pab_blocks
     971             :       TYPE(realspace_grid_type), DIMENSION(:), &
     972             :          INTENT(IN)                                      :: rs_grids
     973             : 
     974             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_collocate_task_list'
     975             : 
     976             :       INTEGER                                            :: handle, ilevel, nlevels
     977      191279 :       INTEGER, ALLOCATABLE, DIMENSION(:, :), TARGET      :: npts_local
     978      191279 :       TYPE(C_PTR), ALLOCATABLE, DIMENSION(:), TARGET     :: grids_c
     979             :       INTERFACE
     980             :          SUBROUTINE grid_collocate_task_list_c(task_list, func, nlevels, &
     981             :                                                npts_local, pab_blocks, grids) &
     982             :             BIND(C, name="grid_collocate_task_list")
     983             :             IMPORT :: C_PTR, C_INT, C_BOOL
     984             :             TYPE(C_PTR), VALUE                        :: task_list
     985             :             INTEGER(KIND=C_INT), VALUE                :: func
     986             :             INTEGER(KIND=C_INT), VALUE                :: nlevels
     987             :             TYPE(C_PTR), VALUE                        :: npts_local
     988             :             TYPE(C_PTR), VALUE                        :: pab_blocks
     989             :             TYPE(C_PTR), VALUE                        :: grids
     990             :          END SUBROUTINE grid_collocate_task_list_c
     991             :       END INTERFACE
     992             : 
     993      191279 :       CALL timeset(routineN, handle)
     994             : 
     995      191279 :       nlevels = SIZE(rs_grids)
     996      191279 :       CPASSERT(nlevels > 0)
     997             : 
     998      573837 :       ALLOCATE (grids_c(nlevels))
     999      573837 :       ALLOCATE (npts_local(3, nlevels))
    1000      951047 :       DO ilevel = 1, nlevels
    1001      191279 :          ASSOCIATE (rsgrid => rs_grids(ilevel))
    1002     3039072 :             npts_local(:, ilevel) = rsgrid%ub_local - rsgrid%lb_local + 1
    1003     1519536 :             grids_c(ilevel) = rsgrid%buffer%c_ptr
    1004             :          END ASSOCIATE
    1005             :       END DO
    1006             : 
    1007             : #if __GNUC__ >= 9
    1008             :       CPASSERT(IS_CONTIGUOUS(npts_local))
    1009             :       CPASSERT(IS_CONTIGUOUS(grids_c))
    1010             : #endif
    1011             : 
    1012      191279 :       CPASSERT(C_ASSOCIATED(task_list%c_ptr))
    1013      191279 :       CPASSERT(C_ASSOCIATED(pab_blocks%c_ptr))
    1014             : 
    1015             :       CALL grid_collocate_task_list_c(task_list=task_list%c_ptr, &
    1016             :                                       func=ga_gb_function, &
    1017             :                                       nlevels=nlevels, &
    1018             :                                       npts_local=C_LOC(npts_local(1, 1)), &
    1019             :                                       pab_blocks=pab_blocks%c_ptr, &
    1020      191279 :                                       grids=C_LOC(grids_c(1)))
    1021             : 
    1022      191279 :       CALL timestop(handle)
    1023      382558 :    END SUBROUTINE grid_collocate_task_list
    1024             : 
    1025             : ! **************************************************************************************************
    1026             : !> \brief Integrate all tasks of in given list from given grids.
    1027             : !> \param task_list ...
    1028             : !> \param compute_tau ...
    1029             : !> \param calculate_forces ...
    1030             : !> \param calculate_virial ...
    1031             : !> \param pab_blocks ...
    1032             : !> \param rs_grids ...
    1033             : !> \param hab_blocks ...
    1034             : !> \param forces ...
    1035             : !> \param virial ...
    1036             : !> \author Ole Schuett
    1037             : ! **************************************************************************************************
    1038      178779 :    SUBROUTINE grid_integrate_task_list(task_list, compute_tau, calculate_forces, calculate_virial, &
    1039      178779 :                                        pab_blocks, rs_grids, hab_blocks, forces, virial)
    1040             :       TYPE(grid_task_list_type), INTENT(IN)              :: task_list
    1041             :       LOGICAL, INTENT(IN)                                :: compute_tau, calculate_forces, &
    1042             :                                                             calculate_virial
    1043             :       TYPE(offload_buffer_type), INTENT(IN)              :: pab_blocks
    1044             :       TYPE(realspace_grid_type), DIMENSION(:), &
    1045             :          INTENT(IN)                                      :: rs_grids
    1046             :       TYPE(offload_buffer_type), INTENT(INOUT)           :: hab_blocks
    1047             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
    1048             :          TARGET                                          :: forces
    1049             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    1050             :          TARGET                                          :: virial
    1051             : 
    1052             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_integrate_task_list'
    1053             : 
    1054             :       INTEGER                                            :: handle, ilevel, nlevels
    1055      178779 :       INTEGER, ALLOCATABLE, DIMENSION(:, :), TARGET      :: npts_local
    1056             :       TYPE(C_PTR)                                        :: forces_c, virial_c
    1057      178779 :       TYPE(C_PTR), ALLOCATABLE, DIMENSION(:), TARGET     :: grids_c
    1058             :       INTERFACE
    1059             :          SUBROUTINE grid_integrate_task_list_c(task_list, compute_tau, natoms, &
    1060             :                                                nlevels, npts_local, &
    1061             :                                                pab_blocks, grids, hab_blocks, forces, virial) &
    1062             :             BIND(C, name="grid_integrate_task_list")
    1063             :             IMPORT :: C_PTR, C_INT, C_BOOL
    1064             :             TYPE(C_PTR), VALUE                        :: task_list
    1065             :             LOGICAL(KIND=C_BOOL), VALUE               :: compute_tau
    1066             :             INTEGER(KIND=C_INT), VALUE                :: natoms
    1067             :             INTEGER(KIND=C_INT), VALUE                :: nlevels
    1068             :             TYPE(C_PTR), VALUE                        :: npts_local
    1069             :             TYPE(C_PTR), VALUE                        :: pab_blocks
    1070             :             TYPE(C_PTR), VALUE                        :: grids
    1071             :             TYPE(C_PTR), VALUE                        :: hab_blocks
    1072             :             TYPE(C_PTR), VALUE                        :: forces
    1073             :             TYPE(C_PTR), VALUE                        :: virial
    1074             :          END SUBROUTINE grid_integrate_task_list_c
    1075             :       END INTERFACE
    1076             : 
    1077      178779 :       CALL timeset(routineN, handle)
    1078             : 
    1079      178779 :       nlevels = SIZE(rs_grids)
    1080      178779 :       CPASSERT(nlevels > 0)
    1081             : 
    1082      536337 :       ALLOCATE (grids_c(nlevels))
    1083      536337 :       ALLOCATE (npts_local(3, nlevels))
    1084      888179 :       DO ilevel = 1, nlevels
    1085      178779 :          ASSOCIATE (rsgrid => rs_grids(ilevel))
    1086     2837600 :             npts_local(:, ilevel) = rsgrid%ub_local - rsgrid%lb_local + 1
    1087     1418800 :             grids_c(ilevel) = rsgrid%buffer%c_ptr
    1088             :          END ASSOCIATE
    1089             :       END DO
    1090             : 
    1091      178779 :       IF (calculate_forces) THEN
    1092       22521 :          forces_c = C_LOC(forces(1, 1))
    1093             :       ELSE
    1094             :          forces_c = C_NULL_PTR
    1095             :       END IF
    1096             : 
    1097      178779 :       IF (calculate_virial) THEN
    1098        3377 :          virial_c = C_LOC(virial(1, 1))
    1099             :       ELSE
    1100             :          virial_c = C_NULL_PTR
    1101             :       END IF
    1102             : 
    1103             : #if __GNUC__ >= 9
    1104             :       CPASSERT(IS_CONTIGUOUS(npts_local))
    1105             :       CPASSERT(IS_CONTIGUOUS(grids_c))
    1106      178779 :       CPASSERT(IS_CONTIGUOUS(forces))
    1107             :       CPASSERT(IS_CONTIGUOUS(virial))
    1108             : #endif
    1109             : 
    1110      178779 :       CPASSERT(SIZE(forces, 1) == 3)
    1111      178779 :       CPASSERT(C_ASSOCIATED(task_list%c_ptr))
    1112      178779 :       CPASSERT(C_ASSOCIATED(hab_blocks%c_ptr))
    1113      178779 :       CPASSERT(C_ASSOCIATED(pab_blocks%c_ptr) .OR. .NOT. calculate_forces)
    1114      178779 :       CPASSERT(C_ASSOCIATED(pab_blocks%c_ptr) .OR. .NOT. calculate_virial)
    1115             : 
    1116             :       CALL grid_integrate_task_list_c(task_list=task_list%c_ptr, &
    1117             :                                       compute_tau=LOGICAL(compute_tau, C_BOOL), &
    1118             :                                       natoms=SIZE(forces, 2), &
    1119             :                                       nlevels=nlevels, &
    1120             :                                       npts_local=C_LOC(npts_local(1, 1)), &
    1121             :                                       pab_blocks=pab_blocks%c_ptr, &
    1122             :                                       grids=C_LOC(grids_c(1)), &
    1123             :                                       hab_blocks=hab_blocks%c_ptr, &
    1124             :                                       forces=forces_c, &
    1125      178779 :                                       virial=virial_c)
    1126             : 
    1127      178779 :       CALL timestop(handle)
    1128      357558 :    END SUBROUTINE grid_integrate_task_list
    1129             : 
    1130             : ! **************************************************************************************************
    1131             : !> \brief Initialize grid library
    1132             : !> \author Ole Schuett
    1133             : ! **************************************************************************************************
    1134        8392 :    SUBROUTINE grid_library_init()
    1135             :       INTERFACE
    1136             :          SUBROUTINE grid_library_init_c() BIND(C, name="grid_library_init")
    1137             :          END SUBROUTINE grid_library_init_c
    1138             :       END INTERFACE
    1139             : 
    1140        8392 :       CALL grid_library_init_c()
    1141             : 
    1142        8392 :    END SUBROUTINE grid_library_init
    1143             : 
    1144             : ! **************************************************************************************************
    1145             : !> \brief Finalize grid library
    1146             : !> \author Ole Schuett
    1147             : ! **************************************************************************************************
    1148        8392 :    SUBROUTINE grid_library_finalize()
    1149             :       INTERFACE
    1150             :          SUBROUTINE grid_library_finalize_c() BIND(C, name="grid_library_finalize")
    1151             :          END SUBROUTINE grid_library_finalize_c
    1152             :       END INTERFACE
    1153             : 
    1154        8392 :       CALL grid_library_finalize_c()
    1155             : 
    1156        8392 :    END SUBROUTINE grid_library_finalize
    1157             : 
    1158             : ! **************************************************************************************************
    1159             : !> \brief Configures the grid library
    1160             : !> \param backend : backend to be used for collocate/integrate, possible values are REF, CPU, GPU
    1161             : !> \param validate : if set to true, compare the results of all backend to the reference backend
    1162             : !> \param apply_cutoff : apply a spherical cutoff before collocating or integrating. Only relevant for CPU backend
    1163             : !> \author Ole Schuett
    1164             : ! **************************************************************************************************
    1165        8510 :    SUBROUTINE grid_library_set_config(backend, validate, apply_cutoff)
    1166             :       INTEGER, INTENT(IN)                                :: backend
    1167             :       LOGICAL, INTENT(IN)                                :: validate, apply_cutoff
    1168             : 
    1169             :       INTERFACE
    1170             :          SUBROUTINE grid_library_set_config_c(backend, validate, apply_cutoff) &
    1171             :             BIND(C, name="grid_library_set_config")
    1172             :             IMPORT :: C_INT, C_BOOL
    1173             :             INTEGER(KIND=C_INT), VALUE                :: backend
    1174             :             LOGICAL(KIND=C_BOOL), VALUE               :: validate
    1175             :             LOGICAL(KIND=C_BOOL), VALUE               :: apply_cutoff
    1176             :          END SUBROUTINE grid_library_set_config_c
    1177             :       END INTERFACE
    1178             : 
    1179             :       CALL grid_library_set_config_c(backend=backend, &
    1180             :                                      validate=LOGICAL(validate, C_BOOL), &
    1181        8510 :                                      apply_cutoff=LOGICAL(apply_cutoff, C_BOOL))
    1182             : 
    1183        8510 :    END SUBROUTINE grid_library_set_config
    1184             : 
    1185             : ! **************************************************************************************************
    1186             : !> \brief Print grid library statistics
    1187             : !> \param mpi_comm ...
    1188             : !> \param output_unit ...
    1189             : !> \author Ole Schuett
    1190             : ! **************************************************************************************************
    1191        8510 :    SUBROUTINE grid_library_print_stats(mpi_comm, output_unit)
    1192             :       TYPE(mp_comm_type)                                 :: mpi_comm
    1193             :       INTEGER, INTENT(IN)                                :: output_unit
    1194             : 
    1195             :       INTERFACE
    1196             :          SUBROUTINE grid_library_print_stats_c(mpi_sum_func, mpi_comm, print_func, output_unit) &
    1197             :             BIND(C, name="grid_library_print_stats")
    1198             :             IMPORT :: C_FUNPTR, C_INT
    1199             :             TYPE(C_FUNPTR), VALUE                     :: mpi_sum_func
    1200             :             INTEGER(KIND=C_INT), VALUE                :: mpi_comm
    1201             :             TYPE(C_FUNPTR), VALUE                     :: print_func
    1202             :             INTEGER(KIND=C_INT), VALUE                :: output_unit
    1203             :          END SUBROUTINE grid_library_print_stats_c
    1204             :       END INTERFACE
    1205             : 
    1206             :       ! Since Fortran units and mpi groups can't be used from C, we pass function pointers instead.
    1207             :       CALL grid_library_print_stats_c(mpi_sum_func=C_FUNLOC(mpi_sum_func), &
    1208             :                                       mpi_comm=mpi_comm%get_handle(), &
    1209             :                                       print_func=C_FUNLOC(print_func), &
    1210        8510 :                                       output_unit=output_unit)
    1211             : 
    1212        8510 :    END SUBROUTINE grid_library_print_stats
    1213             : 
    1214             : ! **************************************************************************************************
    1215             : !> \brief Callback to run mpi_sum on a Fortran MPI communicator.
    1216             : !> \param number ...
    1217             : !> \param mpi_comm ...
    1218             : !> \author Ole Schuett
    1219             : ! **************************************************************************************************
    1220     3404000 :    SUBROUTINE mpi_sum_func(number, mpi_comm) BIND(C, name="grid_api_mpi_sum_func")
    1221             :       INTEGER(KIND=C_LONG), INTENT(INOUT)                :: number
    1222             :       INTEGER(KIND=C_INT), INTENT(IN), VALUE             :: mpi_comm
    1223             : 
    1224             :       TYPE(mp_comm_type)                                 :: my_mpi_comm
    1225             : 
    1226             :       ! Convert the handle to the default integer kind and convert it to the communicator type
    1227     3404000 :       CALL my_mpi_comm%set_handle(INT(mpi_comm))
    1228             : 
    1229     3404000 :       CALL my_mpi_comm%sum(number)
    1230     3404000 :    END SUBROUTINE mpi_sum_func
    1231             : 
    1232             : ! **************************************************************************************************
    1233             : !> \brief Callback to write to a Fortran output unit.
    1234             : !> \param message ...
    1235             : !> \param output_unit ...
    1236             : !> \author Ole Schuett
    1237             : ! **************************************************************************************************
    1238      117074 :    SUBROUTINE print_func(message, output_unit) BIND(C, name="grid_api_print_func")
    1239             :       CHARACTER(LEN=1, KIND=C_CHAR), INTENT(IN)          :: message(*)
    1240             :       INTEGER(KIND=C_INT), INTENT(IN), VALUE             :: output_unit
    1241             : 
    1242             :       CHARACTER(LEN=1000)                                :: buffer
    1243             :       INTEGER                                            :: nchars
    1244             : 
    1245      117074 :       IF (output_unit <= 0) &
    1246       58313 :          RETURN
    1247             : 
    1248             :       ! Convert C char array into Fortran string.
    1249       58761 :       nchars = strlcpy_c2f(buffer, message)
    1250             : 
    1251             :       ! Print the message.
    1252       58761 :       WRITE (output_unit, FMT="(A)", ADVANCE="NO") buffer(1:nchars)
    1253             :    END SUBROUTINE print_func
    1254             : 
    1255           0 : END MODULE grid_api

Generated by: LCOV version 1.15