LCOV - code coverage report
Current view: top level - src/pw - realspace_grid_openpmd.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 0.0 % 6 0
Test Date: 2026-10-16 00:55:08 Functions: 0.0 % 1 0

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Generate Gaussian cube files
      10              : ! **************************************************************************************************
      11              : MODULE realspace_grid_openpmd
      12              : 
      13              : #ifdef __OPENPMD
      14              :    USE cp_files, ONLY: close_file, &
      15              :                        open_file
      16              :    USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
      17              :    USE cp_output_handling_openpmd, ONLY: cp_openpmd_get_value_unit_nr, &
      18              :                                          cp_openpmd_per_call_value_type
      19              :    USE kinds, ONLY: default_string_length, &
      20              :                     dp
      21              :    USE message_passing, ONLY: &
      22              :       file_amode_rdonly, file_offset, mp_comm_type, mp_file_descriptor_type, mp_file_type, &
      23              :       mp_file_type_free, mp_file_type_hindexed_make_chv, mp_file_type_set_view_chv, &
      24              :       mpi_character_size
      25              :    USE physcon, ONLY: a_bohr, e_charge, seconds
      26              :    USE openpmd_api, ONLY: &
      27              :       openpmd_attributable_type, &
      28              :       openpmd_dynamic_memory_view_type_1d, &
      29              :       openpmd_dynamic_memory_view_type_3d, &
      30              :       openpmd_mesh_type, &
      31              :       openpmd_particle_species_type, &
      32              :       openpmd_record_component_type, &
      33              :       openpmd_record_type, openpmd_type_double, openpmd_type_int
      34              :    USE pw_grid_types, ONLY: PW_MODE_LOCAL
      35              :    USE pw_types, ONLY: pw_r3d_rs_type
      36              :    USE util, ONLY: sort_unique
      37              : 
      38              : #else
      39              : 
      40              :    USE pw_types, ONLY: pw_r3d_rs_type
      41              :    USE kinds, ONLY: dp
      42              : 
      43              : #endif
      44              : 
      45              : #include "../base/base_uses.f90"
      46              : 
      47              :    IMPLICIT NONE
      48              : 
      49              :    PRIVATE
      50              : 
      51              :    PUBLIC :: pw_to_openpmd
      52              : 
      53              : #ifdef __OPENPMD
      54              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'realspace_grid_openpmd'
      55              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      56              : 
      57              :    TYPE cp_openpmd_write_buffer_1d
      58              :       REAL(KIND=dp), DIMENSION(:), POINTER :: buffer => NULL()
      59              :    END TYPE cp_openpmd_write_buffer_1d
      60              : #endif
      61              : 
      62              : CONTAINS
      63              : 
      64              : #ifdef __OPENPMD
      65              : ! **************************************************************************************************
      66              : !> \brief ...
      67              : !> \param particles_z ...
      68              : !> \param res_atom_types ...
      69              : !> \param res_atom_counts ...
      70              : !> \param res_len ...
      71              : ! **************************************************************************************************
      72              :    SUBROUTINE pw_get_atom_types(particles_z, res_atom_types, res_atom_counts, res_len)
      73              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: particles_z
      74              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT)    :: res_atom_types, res_atom_counts
      75              :       INTEGER, INTENT(OUT)                               :: res_len
      76              : 
      77              :       INTEGER                                            :: current_atom_number, i
      78              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: particles_z_sorted
      79              :       LOGICAL                                            :: unique
      80              : 
      81              :       ALLOCATE (particles_z_sorted(SIZE(particles_z)))
      82              :       particles_z_sorted(:) = particles_z(:)
      83              :       CALL sort_unique(particles_z_sorted, unique)
      84              : 
      85              :       ALLOCATE (res_atom_types(MIN(118, SIZE(particles_z))))
      86              :       ALLOCATE (res_atom_counts(MIN(118, SIZE(particles_z))))
      87              :       current_atom_number = -1
      88              :       res_len = 0
      89              :       DO i = 1, SIZE(particles_z_sorted)
      90              :          IF (particles_z_sorted(i) /= current_atom_number) THEN
      91              :             res_len = res_len + 1
      92              :             current_atom_number = particles_z_sorted(i)
      93              :             res_atom_types(res_len) = current_atom_number
      94              :             res_atom_counts(res_len) = 1
      95              :          ELSE
      96              :             res_atom_counts(res_len) = res_atom_counts(res_len) + 1
      97              :          END IF
      98              :       END DO
      99              : 
     100              :    END SUBROUTINE pw_get_atom_types
     101              : 
     102              : ! **************************************************************************************************
     103              : !> \brief ...
     104              : !> \param particles_z ...
     105              : !> \param particles_r ...
     106              : !> \param particles_zeff ...
     107              : !> \param atom_type ...
     108              : !> \param atom_count ...
     109              : !> \param openpmd_data ...
     110              : !> \param do_write_data ...
     111              : ! **************************************************************************************************
     112              :    SUBROUTINE pw_write_particle_species( &
     113              :       particles_z, &
     114              :       particles_r, &
     115              :       particles_zeff, &
     116              :       atom_type, &
     117              :       atom_count, &
     118              :       openpmd_data, &
     119              :       do_write_data &
     120              :       )
     121              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: particles_z
     122              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: particles_r
     123              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
     124              :       INTEGER, INTENT(IN)                                :: atom_type, atom_count
     125              :       TYPE(cp_openpmd_per_call_value_type)               :: openpmd_data
     126              :       LOGICAL                                            :: do_write_data
     127              : 
     128              :       CHARACTER(len=1), DIMENSION(3), PARAMETER          :: dims = ["x", "y", "z"]
     129              : 
     130              :       CHARACTER(len=3)                                   :: atom_type_as_string
     131              :       CHARACTER(len=default_string_length)               :: species_name
     132              :       INTEGER                                            :: i, j, k
     133              :       INTEGER, DIMENSION(1)                              :: global_extent, global_offset, &
     134              :                                                             local_extent
     135              :       TYPE(cp_openpmd_write_buffer_1d)                   :: charge_write_buffer
     136              :       TYPE(cp_openpmd_write_buffer_1d), DIMENSION(3)     :: write_buffers
     137              :       TYPE(openpmd_attributable_type)                    :: attr
     138              :       TYPE(openpmd_dynamic_memory_view_type_1d)          :: unresolved_charge_write_buffer
     139              :       TYPE(openpmd_dynamic_memory_view_type_1d), &
     140              :          DIMENSION(3)                                    :: unresolved_write_buffers
     141              :       TYPE(openpmd_particle_species_type)                :: species
     142              :       TYPE(openpmd_record_component_type)                :: charge_component, position_component, &
     143              :                                                             position_offset_component
     144              :       TYPE(openpmd_record_type)                          :: charge, position, position_offset
     145              : 
     146              : ! TODO: The charge is probably constant per species?
     147              : ! If yes, we could use a constant component and save storage space
     148              : 
     149              :       global_extent(1) = atom_count
     150              :       IF (do_write_data) THEN
     151              :          global_offset(1) = 0
     152              :          local_extent(1) = atom_count
     153              :       ELSE
     154              :          global_offset(1) = 0
     155              :          local_extent(1) = 0
     156              :       END IF
     157              : 
     158              :       WRITE (atom_type_as_string, '(I3)') atom_type
     159              :       species_name = TRIM(openpmd_data%name_prefix)//"-"//ADJUSTL(atom_type_as_string)
     160              : 
     161              :       CALL openpmd_data%iteration%open()
     162              :       species = openpmd_data%iteration%get_particle_species(TRIM(species_name))
     163              : 
     164              :       position_offset = species%get_record("positionOffset")
     165              :       position = species%get_record("position")
     166              :       ! length
     167              :       CALL position%set_unit_dimension([1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp])
     168              :       DO k = 1, SIZE(dims)
     169              :          position_offset_component = position_offset%get_component(dims(k))
     170              :          CALL position_offset_component%make_constant_zero(openpmd_type_int, global_extent)
     171              :          CALL position_offset_component%set_unit_SI(a_bohr) ! doesnt really matter as it is zero
     172              :          position_component = position%get_component(dims(k))
     173              :          CALL position_component%reset_dataset(openpmd_type_double, global_extent)
     174              :          CALL position_component%set_unit_SI(a_bohr)
     175              :          unresolved_write_buffers(k) = &
     176              :             position_component%store_chunk_span_1d_double(global_offset, local_extent)
     177              :          write_buffers(k)%buffer => unresolved_write_buffers(k)%resolve_double(DEALLOCATE=.FALSE.)
     178              :       END DO
     179              : 
     180              :       IF (PRESENT(particles_zeff)) THEN
     181              :          charge = species%get_record("charge")
     182              :          charge_component = charge%as_record_component()
     183              :          ! charge ~ time x current
     184              :          CALL charge%set_unit_dimension([0.0_dp, 0.0_dp, 1.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp])
     185              :          CALL charge_component%reset_dataset(openpmd_type_double, global_extent)
     186              :          CALL charge_component%set_unit_SI(e_charge)
     187              :          unresolved_charge_write_buffer = charge_component%store_chunk_span_1d_double(global_offset, local_extent)
     188              :          charge_write_buffer%buffer => unresolved_charge_write_buffer%resolve_double(DEALLOCATE=.FALSE.)
     189              :       END IF
     190              : 
     191              :       ! Resolve Spans for a second time to allow for internal reallocations in BP4 engine of ADIOS2
     192              :       DO k = 1, SIZE(dims)
     193              :          write_buffers(k)%buffer = unresolved_write_buffers(k)%resolve_double(DEALLOCATE=.TRUE.)
     194              :       END DO
     195              :       IF (PRESENT(particles_zeff)) THEN
     196              :          charge_write_buffer%buffer = unresolved_charge_write_buffer%resolve_double(DEALLOCATE=.TRUE.)
     197              :       END IF
     198              :       IF (do_write_data) THEN
     199              :          j = 1
     200              :          DO i = 1, SIZE(particles_z)
     201              :             IF (particles_z(i) == atom_type) THEN
     202              :                DO k = 1, 3
     203              :                   write_buffers(k)%buffer(j) = particles_r(k, i)
     204              :                END DO
     205              :                IF (PRESENT(particles_zeff)) THEN
     206              :                   charge_write_buffer%buffer(j) = particles_zeff(i)
     207              :                END IF
     208              :                j = j + 1
     209              :             END IF
     210              :          END DO
     211              :       END IF
     212              :       attr = openpmd_data%iteration%as_attributable()
     213              :       CALL attr%series_flush("hdf5.independent_stores = true")
     214              :    END SUBROUTINE pw_write_particle_species
     215              : 
     216              : ! **************************************************************************************************
     217              : !> \brief ...
     218              : !> \param particles_z ...
     219              : !> \param particles_r ...
     220              : !> \param particles_zeff ...
     221              : !> \param atom_types ...
     222              : !> \param atom_counts ...
     223              : !> \param num_atom_types ...
     224              : !> \param openpmd_data ...
     225              : !> \param gid ...
     226              : ! **************************************************************************************************
     227              :    SUBROUTINE pw_write_particles( &
     228              :       particles_z, &
     229              :       particles_r, &
     230              :       particles_zeff, &
     231              :       atom_types, &
     232              :       atom_counts, &
     233              :       num_atom_types, &
     234              :       openpmd_data, &
     235              :       gid &
     236              :       )
     237              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: particles_z
     238              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: particles_r
     239              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
     240              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atom_types, atom_counts
     241              :       INTEGER, INTENT(IN), TARGET                        :: num_atom_types
     242              :       TYPE(cp_openpmd_per_call_value_type)               :: openpmd_data
     243              :       TYPE(mp_comm_type), OPTIONAL                       :: gid
     244              : 
     245              :       INTEGER                                            :: i, mpi_rank
     246              :       LOGICAL                                            :: do_write_data
     247              : 
     248              :       IF (PRESENT(gid)) THEN
     249              :          CALL gid%get_rank(mpi_rank)
     250              :          do_write_data = mpi_rank == 0
     251              :       ELSE
     252              :          do_write_data = .TRUE.
     253              :       END IF
     254              :       DO i = 1, num_atom_types
     255              :          CALL pw_write_particle_species( &
     256              :             particles_z, &
     257              :             particles_r, &
     258              :             particles_zeff, &
     259              :             atom_types(i), &
     260              :             atom_counts(i), &
     261              :             openpmd_data, &
     262              :             do_write_data &
     263              :             )
     264              :       END DO
     265              :    END SUBROUTINE pw_write_particles
     266              : 
     267              : ! **************************************************************************************************
     268              : !> \brief ...
     269              : !> \param pw ...
     270              : !> \param unit_nr ...
     271              : !> \param title ...
     272              : !> \param particles_r ...
     273              : !> \param particles_z ...
     274              : !> \param particles_zeff ...
     275              : !> \param stride ...
     276              : !> \param zero_tails ...
     277              : !> \param silent ...
     278              : !> \param mpi_io ...
     279              : ! **************************************************************************************************
     280              :    SUBROUTINE pw_to_openpmd( &
     281              :       pw, &
     282              :       unit_nr, &
     283              :       title, &
     284              :       particles_r, &
     285              :       particles_z, &
     286              :       particles_zeff, &
     287              :       stride, &
     288              :       zero_tails, &
     289              :       silent, &
     290              :       mpi_io &
     291              :       )
     292              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw
     293              :       INTEGER                                            :: unit_nr
     294              :       CHARACTER(*), INTENT(IN), OPTIONAL                 :: title
     295              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     296              :          OPTIONAL                                        :: particles_r
     297              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: particles_z
     298              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
     299              :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: stride
     300              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_tails, silent, mpi_io
     301              : 
     302              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_to_openpmd'
     303              : 
     304              :       CHARACTER(LEN=default_string_length)               :: my_title
     305              :       INTEGER                                            :: count1, count2, count3, handle, i, I1, &
     306              :                                                             I2, I3, iat, L1, L2, L3, my_rank, &
     307              :                                                             my_stride(3), np, num_atom_types, &
     308              :                                                             num_pe, U1, U2, U3
     309              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_counts, atom_types
     310              :       INTEGER, DIMENSION(3)                              :: global_extent, local_extent, offset
     311              :       LOGICAL                                            :: be_silent, my_zero_tails, parallel_write
     312              :       REAL(KIND=dp), DIMENSION(3)                        :: grid_spacing
     313              :       REAL(KIND=dp), POINTER                             :: write_buffer(:, :, :)
     314              :       TYPE(cp_openpmd_per_call_value_type)               :: openpmd_data
     315              :       TYPE(mp_comm_type)                                 :: gid
     316              :       TYPE(openpmd_attributable_type)                    :: attr
     317              :       TYPE(openpmd_dynamic_memory_view_type_3d)          :: unresolved_write_buffer
     318              :       TYPE(openpmd_mesh_type)                            :: mesh
     319              :       TYPE(openpmd_record_component_type)                :: scalar_mesh
     320              : 
     321              :       CALL timeset(routineN, handle)
     322              : 
     323              :       my_zero_tails = .FALSE.
     324              :       be_silent = .FALSE.
     325              :       parallel_write = .FALSE.
     326              :       gid = pw%pw_grid%para%group
     327              :       IF (PRESENT(title)) my_title = TRIM(title)
     328              :       IF (PRESENT(zero_tails)) my_zero_tails = zero_tails
     329              :       IF (PRESENT(silent)) be_silent = silent
     330              :       IF (PRESENT(mpi_io)) parallel_write = mpi_io
     331              :       my_stride = 1
     332              :       IF (PRESENT(stride)) THEN
     333              :          IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) THEN
     334              :             CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 "// &
     335              :                           "(the same for X,Y,Z) or 3 values. Correct your input file.")
     336              :          END IF
     337              :          IF (SIZE(stride) == 1) THEN
     338              :             DO i = 1, 3
     339              :                my_stride(i) = stride(1)
     340              :             END DO
     341              :          ELSE
     342              :             my_stride = stride(1:3)
     343              :          END IF
     344              :          CPASSERT(my_stride(1) > 0)
     345              :          CPASSERT(my_stride(2) > 0)
     346              :          CPASSERT(my_stride(3) > 0)
     347              :       END IF
     348              : 
     349              :       openpmd_data = cp_openpmd_get_value_unit_nr(unit_nr)
     350              : 
     351              :       CPASSERT(PRESENT(particles_z) .EQV. PRESENT(particles_r))
     352              :       np = 0
     353              :       IF (PRESENT(particles_z)) THEN
     354              :          CALL pw_get_atom_types(particles_z, atom_types, atom_counts, num_atom_types)
     355              :          CPASSERT(SIZE(particles_z) == SIZE(particles_r, dim=2))
     356              :          np = SIZE(particles_z)
     357              :       END IF
     358              : 
     359              :       DO i = 1, 3
     360              :          ! Notes:
     361              :          ! 1. This loses information on the rotation of the mesh, the mesh is stored
     362              :          !    without reference to a global coordinate system
     363              :          ! 2. This assumes that the coordinate system is not sheared
     364              :          grid_spacing(i) = SQRT(SUM(pw%pw_grid%dh(:, i)**2))*REAL(my_stride(i), dp)
     365              :       END DO
     366              : 
     367              :       IF (PRESENT(particles_z)) THEN
     368              :          IF (parallel_write) THEN
     369              :             CALL pw_write_particles( &
     370              :                particles_z, &
     371              :                particles_r, &
     372              :                particles_zeff, &
     373              :                atom_types, &
     374              :                atom_counts, &
     375              :                num_atom_types, &
     376              :                openpmd_data, &
     377              :                gid &
     378              :                )
     379              :          ELSE
     380              :             CALL pw_write_particles( &
     381              :                particles_z, &
     382              :                particles_r, &
     383              :                particles_zeff, &
     384              :                atom_types, &
     385              :                atom_counts, &
     386              :                num_atom_types, &
     387              :                openpmd_data &
     388              :                )
     389              :          END IF
     390              :       END IF
     391              : 
     392              :       DO iat = 1, 3
     393              :          global_extent(iat) = (pw%pw_grid%npts(iat) + my_stride(iat) - 1)/my_stride(iat)
     394              :          ! '- 1' for upper gaussian bracket
     395              :          offset(iat) = ((pw%pw_grid%bounds_local(1, iat) - pw%pw_grid%bounds(1, iat) + my_stride(iat) - 1)/my_stride(iat))
     396              :          ! '+ 1' because upper end is inclusive, '- 1' for upper gaussian bracket
     397              :          ! refer local_extent to the global offset first in order to have consistent rounding
     398              :          local_extent(iat) = ((pw%pw_grid%bounds_local(2, iat) + 1 - pw%pw_grid%bounds(1, iat) + my_stride(iat) - 1)/my_stride(iat))
     399              :       END DO
     400              :       local_extent = local_extent - offset
     401              : 
     402              :       mesh = openpmd_data%iteration%get_mesh(TRIM(openpmd_data%name_prefix))
     403              :       CALL mesh%set_axis_labels(["x", "y", "z"])
     404              :       CALL mesh%set_position([0.5_dp, 0.5_dp, 0.5_dp])
     405              :       CALL mesh%set_grid_global_offset([ &
     406              :                                        pw%pw_grid%bounds(1, 1)*grid_spacing(1), &
     407              :                                        pw%pw_grid%bounds(1, 2)*grid_spacing(2), &
     408              :                                        pw%pw_grid%bounds(1, 3)*grid_spacing(3)])
     409              :       CALL mesh%set_grid_spacing(grid_spacing)
     410              :       CALL mesh%set_grid_unit_SI(a_bohr)
     411              :       CALL mesh%set_unit_dimension(openpmd_data%unit_dimension)
     412              :       scalar_mesh = mesh%as_record_component()
     413              :       CALL scalar_mesh%set_unit_SI(openpmd_data%unit_si)
     414              :       CALL scalar_mesh%reset_dataset(openpmd_type_double, global_extent)
     415              : 
     416              :       ! shortcut
     417              :       ! need to adjust L1/U1 for uneven distributions across MPI ranks
     418              :       ! (when working with a stride, we might have to skip the first n values)
     419              :       ! so keep this consistent with the offset and local_extent computed above
     420              :       ! L1 = pw%pw_grid%bounds_local(1, 1)
     421              :       L1 = pw%pw_grid%bounds(1, 1) + offset(1)*my_stride(1)
     422              :       L2 = pw%pw_grid%bounds_local(1, 2)
     423              :       L3 = pw%pw_grid%bounds_local(1, 3)
     424              :       ! offset + local_extent is the start index for the next rank already
     425              :       ! since the indexes are inclusive, subtract 1 from the boundary index
     426              :       U1 = pw%pw_grid%bounds(1, 1) + (offset(1) + local_extent(1) - 1)*my_stride(1)
     427              :       U2 = pw%pw_grid%bounds_local(2, 2)
     428              :       U3 = pw%pw_grid%bounds_local(2, 3)
     429              : 
     430              :       my_rank = pw%pw_grid%para%group%mepos
     431              :       num_pe = pw%pw_grid%para%group%num_pe
     432              : 
     433              :       IF (ALL(my_stride == 1)) THEN
     434              :          CALL scalar_mesh%store_chunk(pw%array(L1:U1, L2:U2, L3:U3), offset)
     435              :          ! Are there some conditions under which we can skip this flush?
     436              :          attr = openpmd_data%iteration%as_attributable()
     437              :          CALL attr%series_flush("hdf5.independent_stores = false")
     438              :       ELSE
     439              :          count3 = 0
     440              :          DO I3 = L3, U3, my_stride(3)
     441              :             ! maybe add an overload to provide `buf` here for HDF5, might have better performance
     442              :             ! for intermittent flushing
     443              :             ! or just call the buffer in the outer function if memory is no problem...
     444              :             unresolved_write_buffer = scalar_mesh%store_chunk_span_3d_double( &
     445              :                                       [offset(1), offset(2), offset(3) + count3], &
     446              :                                       [local_extent(1), local_extent(2), 1])
     447              :             write_buffer => unresolved_write_buffer%resolve_double(DEALLOCATE=.TRUE.)
     448              : 
     449              :             ! Sanity checks: ensure buffer is associated and matches expected shape
     450              :             CPASSERT(ASSOCIATED(write_buffer))
     451              :             CPASSERT(SIZE(write_buffer, 1) == local_extent(1))
     452              :             CPASSERT(SIZE(write_buffer, 2) == local_extent(2))
     453              :             CPASSERT(SIZE(write_buffer, 3) == 1)
     454              : 
     455              :             count2 = 0
     456              :             DO I2 = L2, U2, my_stride(2)
     457              :                ! This loop deals with ray (:, count2, count3) of the local subspace
     458              :                ! The write buffer itself has been allocated for slice (:, :, count3)
     459              :                count1 = 0
     460              :                DO I1 = L1, U1, my_stride(1)
     461              :                   write_buffer(count1 + 1, count2 + 1, 1) = pw%array(I1, I2, I3)
     462              :                   ! Debug: print the target indices in write_buffer to the command line
     463              :                   ! WRITE(*,*) 'write_buffer index:', count1 + 1, ',', count2 + 1, ',', 1
     464              :                   count1 = count1 + 1
     465              :                END DO
     466              :                count2 = count2 + 1
     467              :             END DO
     468              :             count3 = count3 + 1
     469              :          END DO
     470              :       END IF
     471              : 
     472              :       CALL timestop(handle)
     473              : 
     474              :    END SUBROUTINE pw_to_openpmd
     475              : 
     476              : #else
     477              : 
     478              : ! **************************************************************************************************
     479              : !> \brief ...
     480              : !> \param pw ...
     481              : !> \param unit_nr ...
     482              : !> \param title ...
     483              : !> \param particles_r ...
     484              : !> \param particles_z ...
     485              : !> \param particles_zeff ...
     486              : !> \param stride ...
     487              : !> \param zero_tails ...
     488              : !> \param silent ...
     489              : !> \param mpi_io ...
     490              : ! **************************************************************************************************
     491            0 :    SUBROUTINE pw_to_openpmd( &
     492              :       pw, &
     493              :       unit_nr, &
     494              :       title, &
     495            0 :       particles_r, &
     496            0 :       particles_z, &
     497            0 :       particles_zeff, &
     498              :       stride, &
     499              :       zero_tails, &
     500              :       silent, &
     501              :       mpi_io &
     502              :       )
     503              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw
     504              :       INTEGER                                            :: unit_nr
     505              :       CHARACTER(*), INTENT(IN), OPTIONAL                 :: title
     506              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     507              :          OPTIONAL                                        :: particles_r
     508              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: particles_z
     509              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
     510              :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: stride
     511              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_tails, silent, mpi_io
     512              : 
     513              :       MARK_USED(pw)
     514              :       MARK_USED(unit_nr)
     515              :       MARK_USED(title)
     516              :       MARK_USED(particles_r)
     517              :       MARK_USED(particles_z)
     518              :       MARK_USED(particles_zeff)
     519              :       MARK_USED(stride)
     520              :       MARK_USED(zero_tails)
     521              :       MARK_USED(silent)
     522              :       MARK_USED(mpi_io)
     523            0 :       CPABORT("CP2K compiled without the openPMD-api")
     524              : 
     525            0 :    END SUBROUTINE pw_to_openpmd
     526              : 
     527              : #endif
     528              : 
     529              : END MODULE realspace_grid_openpmd
        

Generated by: LCOV version 2.0-1