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

Generated by: LCOV version 2.0-1