LCOV - code coverage report
Current view: top level - src/pw - realspace_grid_cube.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:7641cd9) Lines: 86.2 % 449 387
Test Date: 2026-05-25 07:16:39 Functions: 100.0 % 6 6

            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_cube
      12              :    USE cp_files,                        ONLY: close_file,&
      13              :                                               open_file
      14              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      15              :    USE kinds,                           ONLY: dp
      16              :    USE message_passing,                 ONLY: &
      17              :         file_amode_rdonly, file_offset, mp_comm_type, mp_file_descriptor_type, mp_file_type, &
      18              :         mp_file_type_free, mp_file_type_hindexed_make_chv, mp_file_type_set_view_chv, &
      19              :         mpi_character_size
      20              :    USE pw_grid_types,                   ONLY: PW_MODE_LOCAL
      21              :    USE pw_types,                        ONLY: pw_r3d_rs_type
      22              : #include "../base/base_uses.f90"
      23              : 
      24              :    IMPLICIT NONE
      25              : 
      26              :    PRIVATE
      27              : 
      28              :    PUBLIC :: cube_read_values, cube_value_format, cube_values_format, cube_to_pw, pw_to_cube, &
      29              :              pw_to_simple_volumetric
      30              : 
      31              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'realspace_grid_cube'
      32              :    INTEGER, PARAMETER, PRIVATE          :: cube_entry_len = 13, &
      33              :                                            cube_num_entries_line = 6
      34              :    INTEGER, PARAMETER, PRIVATE          :: cube_line_len = cube_entry_len*cube_num_entries_line
      35              :    CHARACTER(len=*), PARAMETER          :: cube_value_format = '(E13.5E3)', &
      36              :                                            cube_values_format = '(6E13.5E3)'
      37              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      38              : 
      39              : CONTAINS
      40              : 
      41              : ! **************************************************************************************************
      42              : !> \brief Read cube values from a character buffer.
      43              : !> \param values value buffer from one cube line or one z-slice
      44              : !> \param buffer parsed values
      45              : ! **************************************************************************************************
      46        29416 :    SUBROUTINE cube_read_values(values, buffer)
      47              :       CHARACTER(LEN=*), INTENT(IN)                       :: values
      48              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: buffer
      49              : 
      50              :       CHARACTER(LEN=cube_entry_len)                      :: value
      51              :       INTEGER                                            :: i, pos, readstat
      52              : 
      53        29416 :       READ (values, *, IOSTAT=readstat) buffer
      54        29416 :       IF (readstat == 0) RETURN
      55              : 
      56         2665 :       pos = 1
      57        95403 :       DO i = 1, SIZE(buffer)
      58        92738 :          IF (pos + cube_entry_len - 1 > LEN(values)) CPABORT("Unexpected end of cube data.")
      59        92738 :          value = values(pos:pos + cube_entry_len - 1)
      60        92738 :          READ (value, '(E13.5)', IOSTAT=readstat) buffer(i)
      61        92738 :          IF (readstat /= 0) CPABORT("Bad value while reading cube data.")
      62        92738 :          pos = pos + cube_entry_len
      63        95403 :          IF (MODULO(i, cube_num_entries_line) == 0) THEN
      64        14254 :             IF (pos <= LEN(values)) THEN
      65        14254 :                IF (values(pos:pos) == NEW_LINE('C')) pos = pos + 1
      66              :             END IF
      67              :          END IF
      68              :       END DO
      69              : 
      70              :    END SUBROUTINE cube_read_values
      71              : 
      72              : ! **************************************************************************************************
      73              : !> \brief ...
      74              : !> \param pw ...
      75              : !> \param unit_nr ...
      76              : !> \param title ...
      77              : !> \param particles_r ...
      78              : !> \param particles_z ...
      79              : !> \param particles_zeff ...
      80              : !> \param stride ...
      81              : !> \param max_file_size_mb ...
      82              : !> \param zero_tails ...
      83              : !> \param silent ...
      84              : !> \param mpi_io ...
      85              : ! **************************************************************************************************
      86         2088 :    SUBROUTINE pw_to_cube(pw, unit_nr, title, particles_r, particles_z, particles_zeff, &
      87              :                          stride, max_file_size_mb, zero_tails, silent, mpi_io)
      88              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw
      89              :       INTEGER, INTENT(IN)                                :: unit_nr
      90              :       CHARACTER(*), INTENT(IN), OPTIONAL                 :: title
      91              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
      92              :          OPTIONAL                                        :: particles_r
      93              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: particles_z
      94              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
      95              :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: stride
      96              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: max_file_size_mb
      97              :       LOGICAL, INTENT(IN), OPTIONAL                      :: zero_tails, silent, mpi_io
      98              : 
      99              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_to_cube'
     100              :       INTEGER, PARAMETER                                 :: entry_len = 13, num_entries_line = 6
     101              : 
     102              :       INTEGER :: checksum, dest, handle, i, I1, I2, I3, iat, ip, L1, L2, L3, msglen, my_rank, &
     103              :          my_stride(3), np, num_linebreak, num_pe, rank(2), size_of_z, source, tag, U1, U2, U3
     104              :       LOGICAL                                            :: be_silent, my_zero_tails, parallel_write
     105              :       REAL(KIND=dp)                                      :: compression_factor, my_max_file_size_mb
     106         2088 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: buf
     107              :       TYPE(mp_comm_type)                                 :: gid
     108              :       TYPE(mp_file_type)                                 :: mp_unit
     109              : 
     110         2088 :       CALL timeset(routineN, handle)
     111              : 
     112         2088 :       my_zero_tails = .FALSE.
     113         2088 :       be_silent = .FALSE.
     114         2088 :       parallel_write = .FALSE.
     115         2088 :       my_max_file_size_mb = 0.0_dp
     116         2088 :       IF (PRESENT(zero_tails)) my_zero_tails = zero_tails
     117         2088 :       IF (PRESENT(silent)) be_silent = silent
     118         2088 :       IF (PRESENT(mpi_io)) parallel_write = mpi_io
     119         2088 :       IF (PRESENT(max_file_size_mb)) my_max_file_size_mb = max_file_size_mb
     120          764 :       CPASSERT(my_max_file_size_mb >= 0)
     121              : 
     122         8352 :       my_stride = 1
     123         2088 :       IF (PRESENT(stride)) THEN
     124         2040 :          IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) &
     125              :             CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 "// &
     126         2040 :                           "(the same for X,Y,Z) or 3 values. Correct your input file.")
     127         2040 :          IF (SIZE(stride) == 1) THEN
     128          112 :             DO i = 1, 3
     129          112 :                my_stride(i) = stride(1)
     130              :             END DO
     131              :          ELSE
     132         8048 :             my_stride = stride(1:3)
     133              :          END IF
     134              :       END IF
     135              : 
     136         2088 :       IF (my_max_file_size_mb > 0) THEN
     137              :          ! A single grid point takes up 13 bytes, which is 1.3e-05 MB.
     138           40 :          compression_factor = 1.3e-05_dp*PRODUCT(REAL(pw%pw_grid%npts, dp))/max_file_size_mb
     139           40 :          my_stride(:) = INT(compression_factor**(1.0/3.0)) + 1
     140              :       END IF
     141              : 
     142         2088 :       CPASSERT(my_stride(1) > 0)
     143         2088 :       CPASSERT(my_stride(2) > 0)
     144         2088 :       CPASSERT(my_stride(3) > 0)
     145              : 
     146         2088 :       IF (.NOT. parallel_write) THEN
     147           76 :          IF (unit_nr > 0) THEN
     148              :             ! this format seems to work for e.g. molekel and gOpenmol
     149              :             ! latest version of VMD can read non orthorhombic cells
     150           38 :             WRITE (unit_nr, '(a11)') "-Quickstep-"
     151           38 :             IF (PRESENT(title)) THEN
     152           38 :                WRITE (unit_nr, *) TRIM(title)
     153              :             ELSE
     154            0 :                WRITE (unit_nr, *) "No Title"
     155              :             END IF
     156              : 
     157           38 :             CPASSERT(PRESENT(particles_z) .EQV. PRESENT(particles_r))
     158           38 :             np = 0
     159           38 :             IF (PRESENT(particles_z)) THEN
     160           38 :                CPASSERT(SIZE(particles_z) == SIZE(particles_r, dim=2))
     161              :                ! cube files can only be written for 99999 particles due to a format limitation (I5)
     162              :                ! so we limit the number of particles written.
     163           38 :                np = MIN(99999, SIZE(particles_z))
     164              :             END IF
     165              : 
     166           38 :             WRITE (unit_nr, '(I5,3f12.6)') np, 0.0_dp, 0._dp, 0._dp !start of cube
     167              : 
     168           38 :             WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(1) + my_stride(1) - 1)/my_stride(1), &
     169           38 :                pw%pw_grid%dh(1, 1)*REAL(my_stride(1), dp), pw%pw_grid%dh(2, 1)*REAL(my_stride(1), dp), &
     170           76 :                pw%pw_grid%dh(3, 1)*REAL(my_stride(1), dp)
     171           38 :             WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(2) + my_stride(2) - 1)/my_stride(2), &
     172           38 :                pw%pw_grid%dh(1, 2)*REAL(my_stride(2), dp), pw%pw_grid%dh(2, 2)*REAL(my_stride(2), dp), &
     173           76 :                pw%pw_grid%dh(3, 2)*REAL(my_stride(2), dp)
     174           38 :             WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(3) + my_stride(3) - 1)/my_stride(3), &
     175           38 :                pw%pw_grid%dh(1, 3)*REAL(my_stride(3), dp), pw%pw_grid%dh(2, 3)*REAL(my_stride(3), dp), &
     176           76 :                pw%pw_grid%dh(3, 3)*REAL(my_stride(3), dp)
     177              : 
     178           38 :             IF (PRESENT(particles_z)) THEN
     179           38 :                IF (PRESENT(particles_zeff)) THEN
     180            0 :                   DO iat = 1, np
     181            0 :                      WRITE (unit_nr, '(I5,4f12.6)') particles_z(iat), particles_zeff(iat), particles_r(:, iat)
     182              :                   END DO
     183              :                ELSE
     184          177 :                   DO iat = 1, np
     185          177 :                      WRITE (unit_nr, '(I5,4f12.6)') particles_z(iat), 0._dp, particles_r(:, iat)
     186              :                   END DO
     187              :                END IF
     188              :             END IF
     189              :          END IF
     190              : 
     191              :          ! shortcut
     192           76 :          L1 = pw%pw_grid%bounds(1, 1)
     193           76 :          L2 = pw%pw_grid%bounds(1, 2)
     194           76 :          L3 = pw%pw_grid%bounds(1, 3)
     195           76 :          U1 = pw%pw_grid%bounds(2, 1)
     196           76 :          U2 = pw%pw_grid%bounds(2, 2)
     197           76 :          U3 = pw%pw_grid%bounds(2, 3)
     198              : 
     199          228 :          ALLOCATE (buf(L3:U3))
     200              : 
     201           76 :          my_rank = pw%pw_grid%para%group%mepos
     202           76 :          gid = pw%pw_grid%para%group
     203           76 :          num_pe = pw%pw_grid%para%group%num_pe
     204           76 :          tag = 1
     205              : 
     206           76 :          rank (1) = unit_nr
     207           76 :          rank (2) = my_rank
     208           76 :          checksum = 0
     209           76 :          IF (unit_nr > 0) checksum = 1
     210              : 
     211           76 :          CALL gid%sum(checksum)
     212           76 :          CPASSERT(checksum == 1)
     213              : 
     214           76 :          CALL gid%maxloc(rank)
     215           76 :          CPASSERT(rank(1) > 0)
     216              : 
     217           76 :          dest = rank(2)
     218         2224 :          DO I1 = L1, U1, my_stride(1)
     219        68204 :             DO I2 = L2, U2, my_stride(2)
     220              : 
     221              :                ! cycling through the CPUs, check if the current ray (I1,I2) is local to that CPU
     222        65980 :                IF (pw%pw_grid%para%mode /= PW_MODE_LOCAL) THEN
     223       197940 :                   DO ip = 0, num_pe - 1
     224              :                      IF (pw%pw_grid%para%bo(1, 1, ip, 1) <= I1 - L1 + 1 .AND. pw%pw_grid%para%bo(2, 1, ip, 1) >= I1 - L1 + 1 .AND. &
     225       197940 :                          pw%pw_grid%para%bo(1, 2, ip, 1) <= I2 - L2 + 1 .AND. pw%pw_grid%para%bo(2, 2, ip, 1) >= I2 - L2 + 1) THEN
     226        65980 :                         source = ip
     227              :                      END IF
     228              :                   END DO
     229              :                ELSE
     230            0 :                   source = dest
     231              :                END IF
     232              : 
     233        65980 :                IF (source == dest) THEN
     234        33188 :                   IF (my_rank == source) THEN
     235       743889 :                      buf(:) = pw%array(I1, I2, :)
     236              :                   END IF
     237              :                ELSE
     238        32792 :                   IF (my_rank == source) THEN
     239       729966 :                      buf(:) = pw%array(I1, I2, :)
     240        16396 :                      CALL gid%send(buf, dest, tag)
     241              :                   END IF
     242        32792 :                   IF (my_rank == dest) THEN
     243        16396 :                      CALL gid%recv(buf, source, tag)
     244              :                   END IF
     245              :                END IF
     246              : 
     247        65980 :                IF (unit_nr > 0) THEN
     248        32990 :                   IF (my_zero_tails) THEN
     249            0 :                      DO I3 = L3, U3
     250            0 :                         IF (buf(I3) < 1.E-7_dp) buf(I3) = 0.0_dp
     251              :                      END DO
     252              :                   END IF
     253        32990 :                   WRITE (unit_nr, cube_values_format) (buf(I3), I3=L3, U3, my_stride(3))
     254              :                END IF
     255              : 
     256              :                ! this double loop generates so many messages that it can overload
     257              :                ! the message passing system, e.g. on XT3
     258              :                ! we therefore put a barrier here that limits the amount of message
     259              :                ! that flies around at any given time.
     260              :                ! if ever this routine becomes a bottleneck, we should go for a
     261              :                ! more complicated rewrite
     262        68128 :                CALL gid%sync()
     263              : 
     264              :             END DO
     265              :          END DO
     266              : 
     267           76 :          DEALLOCATE (buf)
     268              :       ELSE
     269         2012 :          size_of_z = CEILING(REAL(pw%pw_grid%bounds(2, 3) - pw%pw_grid%bounds(1, 3) + 1, dp)/REAL(my_stride(3), dp))
     270         2012 :          num_linebreak = size_of_z/num_entries_line
     271         2012 :          IF (MODULO(size_of_z, num_entries_line) /= 0) &
     272         1706 :             num_linebreak = num_linebreak + 1
     273         2012 :          msglen = (size_of_z*entry_len + num_linebreak)*mpi_character_size
     274         2012 :          CALL mp_unit%set_handle(unit_nr)
     275              :          CALL pw_to_cube_parallel(pw, mp_unit, title, particles_r, particles_z, particles_zeff, &
     276         3148 :                                   my_stride, my_zero_tails, msglen)
     277              :       END IF
     278              : 
     279         2088 :       CALL timestop(handle)
     280              : 
     281         4176 :    END SUBROUTINE pw_to_cube
     282              : 
     283              : ! **************************************************************************************************
     284              : !> \brief  Computes the external density on the grid
     285              : !>         hacked from external_read_density
     286              : !> \param grid     pw to read from cube file
     287              : !> \param filename name of cube file
     288              : !> \param scaling  scale values before storing
     289              : !> \param parallel_read ...
     290              : !> \param silent ...
     291              : !> \par History
     292              : !>      Created [M.Watkins] (01.2014)
     293              : !>      Use blocking, collective MPI read for parallel simulations [Nico Holmberg] (05.2017)
     294              : ! **************************************************************************************************
     295           38 :    SUBROUTINE cube_to_pw(grid, filename, scaling, parallel_read, silent)
     296              : 
     297              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: grid
     298              :       CHARACTER(len=*), INTENT(in)                       :: filename
     299              :       REAL(kind=dp), INTENT(in)                          :: scaling
     300              :       LOGICAL, INTENT(in)                                :: parallel_read
     301              :       LOGICAL, INTENT(in), OPTIONAL                      :: silent
     302              : 
     303              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cube_to_pw'
     304              :       INTEGER, PARAMETER                                 :: entry_len = 13, num_entries_line = 6
     305              : 
     306              :       CHARACTER(LEN=cube_line_len)                       :: value_line
     307              :       INTEGER                                            :: extunit, handle, i, j, k, last_z, &
     308              :                                                             msglen, my_rank, nat, ndum, &
     309              :                                                             num_linebreak, num_pe, output_unit, &
     310              :                                                             size_of_z, tag
     311              :       INTEGER, DIMENSION(3)                              :: lbounds, lbounds_local, npoints, &
     312              :                                                             npoints_local, ubounds, ubounds_local
     313              :       LOGICAL                                            :: be_silent
     314           38 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: buffer
     315              :       REAL(kind=dp), DIMENSION(3)                        :: dr, rdum
     316              :       TYPE(mp_comm_type)                                 :: gid
     317              : 
     318           76 :       output_unit = cp_logger_get_default_io_unit()
     319              : 
     320           38 :       CALL timeset(routineN, handle)
     321              : 
     322           38 :       be_silent = .FALSE.
     323           38 :       IF (PRESENT(silent)) THEN
     324            0 :          be_silent = silent
     325              :       END IF
     326              :       !get rs grids and parallel environment
     327           38 :       gid = grid%pw_grid%para%group
     328           38 :       my_rank = grid%pw_grid%para%group%mepos
     329           38 :       num_pe = grid%pw_grid%para%group%num_pe
     330           38 :       tag = 1
     331              : 
     332          152 :       lbounds_local = grid%pw_grid%bounds_local(1, :)
     333          152 :       ubounds_local = grid%pw_grid%bounds_local(2, :)
     334           38 :       size_of_z = ubounds_local(3) - lbounds_local(3) + 1
     335              : 
     336           38 :       IF (.NOT. parallel_read) THEN
     337            0 :          npoints = grid%pw_grid%npts
     338            0 :          lbounds = grid%pw_grid%bounds(1, :)
     339            0 :          ubounds = grid%pw_grid%bounds(2, :)
     340              : 
     341            0 :          DO i = 1, 3
     342            0 :             dr(i) = grid%pw_grid%dh(i, i)
     343              :          END DO
     344              : 
     345            0 :          npoints_local = grid%pw_grid%npts_local
     346              :          !pw grids at most pencils - all processors have a full set of z data for x,y
     347            0 :          ALLOCATE (buffer(lbounds(3):ubounds(3)))
     348              : 
     349            0 :          IF (my_rank == 0) THEN
     350            0 :             IF (output_unit > 0 .AND. .NOT. be_silent) THEN
     351            0 :                WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A,/)") "Reading the cube file:     ", TRIM(filename)
     352              :             END IF
     353              : 
     354              :             CALL open_file(file_name=filename, &
     355              :                            file_status="OLD", &
     356              :                            file_form="FORMATTED", &
     357              :                            file_action="READ", &
     358            0 :                            unit_number=extunit)
     359              : 
     360              :             !skip header comments
     361            0 :             DO i = 1, 2
     362            0 :                READ (extunit, *)
     363              :             END DO
     364            0 :             READ (extunit, *) nat, rdum
     365            0 :             DO i = 1, 3
     366            0 :                READ (extunit, *) ndum, rdum
     367            0 :                IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
     368            0 :                    output_unit > 0) THEN
     369            0 :                   WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
     370            0 :                   WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
     371            0 :                   WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
     372              :                END IF
     373              :             END DO
     374              :             !ignore atomic position data - read from coord or topology instead
     375            0 :             DO i = 1, nat
     376            0 :                READ (extunit, *)
     377              :             END DO
     378              :          END IF
     379              : 
     380              :          !master sends all data to everyone
     381            0 :          DO i = lbounds(1), ubounds(1)
     382            0 :             DO j = lbounds(2), ubounds(2)
     383            0 :                IF (my_rank == 0) THEN
     384            0 :                   DO k = lbounds(3), ubounds(3), cube_num_entries_line
     385            0 :                      last_z = MIN(k + cube_num_entries_line - 1, ubounds(3))
     386            0 :                      READ (extunit, '(A)') value_line
     387            0 :                      CALL cube_read_values(value_line, buffer(k:last_z))
     388              :                   END DO
     389              :                END IF
     390            0 :                CALL gid%bcast(buffer(lbounds(3):ubounds(3)), 0)
     391              : 
     392              :                !only use data that is local to me - i.e. in slice of pencil I own
     393              :                IF ((lbounds_local(1) <= i) .AND. (i <= ubounds_local(1)) .AND. (lbounds_local(2) <= j) &
     394            0 :                    .AND. (j <= ubounds_local(2))) THEN
     395              :                   !allow scaling of external potential values by factor 'scaling' (SCALING_FACTOR in input file)
     396            0 :                   grid%array(i, j, lbounds(3):ubounds(3)) = buffer(lbounds(3):ubounds(3))*scaling
     397              :                END IF
     398              : 
     399              :             END DO
     400              :          END DO
     401              : 
     402            0 :          IF (my_rank == 0) CALL close_file(unit_number=extunit)
     403              : 
     404            0 :          CALL gid%sync()
     405              :       ELSE
     406              :          ! Parallel routine needs as input the byte size of each grid z-slice
     407              :          ! This is a hack to prevent compilation errors with gcc -Wall (up to versions 6.3)
     408              :          ! related to allocatable-length string declaration CHARACTER(LEN=:), ALLOCATABLE, DIMENSION(:) :: string
     409              :          ! Each data line of a Gaussian cube contains max 6 entries with last line potentially containing less if nz % 6 /= 0
     410              :          ! Thus, this size is simply the number of entries multiplied by the entry size + the number of line breaks
     411           38 :          num_linebreak = size_of_z/num_entries_line
     412           38 :          IF (MODULO(size_of_z, num_entries_line) /= 0) &
     413           36 :             num_linebreak = num_linebreak + 1
     414           38 :          msglen = (size_of_z*entry_len + num_linebreak)*mpi_character_size
     415           38 :          CALL cube_to_pw_parallel(grid, filename, scaling, msglen, silent=silent)
     416              :       END IF
     417              : 
     418           38 :       CALL timestop(handle)
     419              : 
     420           76 :    END SUBROUTINE cube_to_pw
     421              : 
     422              : ! **************************************************************************************************
     423              : !> \brief Reads a realspace potential/density from a cube file using collective MPI I/O and
     424              : !>        stores it in grid.
     425              : !> \param grid     pw to read from cube file
     426              : !> \param filename name of cube file
     427              : !> \param scaling  scale values before storing
     428              : !> \param msglen   the size of each grid slice along z-axis in bytes
     429              : !> \param silent ...
     430              : !> \par History
     431              : !>      Created [Nico Holmberg] (05.2017)
     432              : ! **************************************************************************************************
     433           38 :    SUBROUTINE cube_to_pw_parallel(grid, filename, scaling, msglen, silent)
     434              : 
     435              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: grid
     436              :       CHARACTER(len=*), INTENT(in)                       :: filename
     437              :       REAL(kind=dp), INTENT(in)                          :: scaling
     438              :       INTEGER, INTENT(in)                                :: msglen
     439              :       LOGICAL, INTENT(in), OPTIONAL                      :: silent
     440              : 
     441              :       CHARACTER(LEN=cube_line_len)                       :: value_line
     442              :       INTEGER, DIMENSION(3)                              :: lbounds, lbounds_local, npoints, &
     443              :                                                             npoints_local, ubounds, ubounds_local
     444           38 :       INTEGER, ALLOCATABLE, DIMENSION(:), TARGET         :: blocklengths
     445              :       INTEGER(kind=file_offset), ALLOCATABLE, &
     446           38 :          DIMENSION(:), TARGET                            :: displacements
     447              :       INTEGER(kind=file_offset)                          :: BOF
     448              :       INTEGER                                            :: extunit_handle, i, islice, j, k, last_z, &
     449              :                                                             my_rank, nat, ndum, nslices, num_pe, &
     450              :                                                             offset_global, output_unit, size_of_z, &
     451              :                                                             tag
     452           38 :       CHARACTER(LEN=msglen), ALLOCATABLE, DIMENSION(:)   :: readbuffer
     453              :       LOGICAL                                            :: be_silent, should_read(2)
     454           38 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: buffer
     455              :       REAL(kind=dp), DIMENSION(3)                        :: dr, rdum
     456              :       TYPE(mp_comm_type)                                 :: gid
     457              :       TYPE(mp_file_descriptor_type)                      :: mp_file_desc
     458              :       TYPE(mp_file_type)                                 :: extunit
     459              : 
     460           76 :       output_unit = cp_logger_get_default_io_unit()
     461              : 
     462           38 :       be_silent = .FALSE.
     463           38 :       IF (PRESENT(silent)) THEN
     464            0 :          be_silent = silent
     465              :       END IF
     466              : 
     467              :       !get rs grids and parallel envnment
     468           38 :       gid = grid%pw_grid%para%group
     469           38 :       my_rank = grid%pw_grid%para%group%mepos
     470           38 :       num_pe = grid%pw_grid%para%group%num_pe
     471           38 :       tag = 1
     472              : 
     473          152 :       DO i = 1, 3
     474          152 :          dr(i) = grid%pw_grid%dh(i, i)
     475              :       END DO
     476              : 
     477          152 :       npoints = grid%pw_grid%npts
     478          152 :       lbounds = grid%pw_grid%bounds(1, :)
     479          152 :       ubounds = grid%pw_grid%bounds(2, :)
     480              : 
     481          152 :       npoints_local = grid%pw_grid%npts_local
     482          152 :       lbounds_local = grid%pw_grid%bounds_local(1, :)
     483          152 :       ubounds_local = grid%pw_grid%bounds_local(2, :)
     484           38 :       size_of_z = ubounds_local(3) - lbounds_local(3) + 1
     485           38 :       nslices = (ubounds_local(1) - lbounds_local(1) + 1)*(ubounds_local(2) - lbounds_local(2) + 1)
     486           38 :       islice = 1
     487              : 
     488              :       ! Read header information and determine byte offset of cube data on master process
     489           38 :       IF (my_rank == 0) THEN
     490           19 :          IF (output_unit > 0 .AND. .NOT. be_silent) THEN
     491           19 :             WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A,/)") "Reading the cube file:     ", TRIM(filename)
     492              :          END IF
     493              : 
     494              :          CALL open_file(file_name=filename, &
     495              :                         file_status="OLD", &
     496              :                         file_form="FORMATTED", &
     497              :                         file_action="READ", &
     498              :                         file_access="STREAM", &
     499           19 :                         unit_number=extunit_handle)
     500              : 
     501              :          !skip header comments
     502           57 :          DO i = 1, 2
     503           57 :             READ (extunit_handle, *)
     504              :          END DO
     505           19 :          READ (extunit_handle, *) nat, rdum
     506           76 :          DO i = 1, 3
     507           57 :             READ (extunit_handle, *) ndum, rdum
     508           57 :             IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
     509           19 :                 output_unit > 0) THEN
     510            0 :                WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
     511            0 :                WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
     512            0 :                WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
     513              :             END IF
     514              :          END DO
     515              :          !ignore atomic position data - read from coord or topology instead
     516           44 :          DO i = 1, nat
     517           44 :             READ (extunit_handle, *)
     518              :          END DO
     519              :          ! Get byte offset
     520           19 :          INQUIRE (extunit_handle, POS=offset_global)
     521           19 :          CALL close_file(unit_number=extunit_handle)
     522              :       END IF
     523              :       ! Sync offset and start parallel read
     524           38 :       CALL gid%bcast(offset_global, grid%pw_grid%para%group%source)
     525              :       ! INQUIRE(POS=...) returns a 1-based stream position, whereas MPI-IO
     526              :       ! file offsets are 0-based.
     527           38 :       BOF = offset_global - 1
     528           38 :       CALL extunit%open(groupid=gid, filepath=filename, amode_status=file_amode_rdonly)
     529              :       ! Determine byte offsets for each grid z-slice which are local to a process
     530          114 :       ALLOCATE (displacements(nslices))
     531           38 :       displacements = 0
     532         1151 :       DO i = lbounds(1), ubounds(1)
     533         3396 :          should_read(:) = .TRUE.
     534         1132 :          IF (i < lbounds_local(1)) THEN
     535          371 :             should_read(1) = .FALSE.
     536          761 :          ELSE IF (i > ubounds_local(1)) THEN
     537              :             EXIT
     538              :          END IF
     539        45269 :          DO j = lbounds(2), ubounds(2)
     540        44118 :             should_read(2) = .TRUE.
     541        44118 :             IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
     542            0 :                should_read(2) = .FALSE.
     543              :             END IF
     544       102942 :             IF (ALL(should_read .EQV. .TRUE.)) THEN
     545        29412 :                IF (islice > nslices) CPABORT("Index out of bounds.")
     546        29412 :                displacements(islice) = BOF
     547        29412 :                islice = islice + 1
     548              :             END IF
     549              :             ! Update global byte offset
     550        45231 :             BOF = BOF + msglen
     551              :          END DO
     552              :       END DO
     553              :       ! Size of each z-slice is msglen
     554          114 :       ALLOCATE (blocklengths(nslices))
     555        29450 :       blocklengths(:) = msglen
     556              :       ! Create indexed MPI type using calculated byte offsets as displacements and use it as a file view
     557           38 :       mp_file_desc = mp_file_type_hindexed_make_chv(nslices, blocklengths, displacements)
     558           38 :       BOF = 0
     559           38 :       CALL mp_file_type_set_view_chv(extunit, BOF, mp_file_desc)
     560              :       ! Collective read of cube
     561          114 :       ALLOCATE (readbuffer(nslices))
     562        29450 :       readbuffer(:) = ''
     563           38 :       CALL extunit%read_all(msglen, nslices, readbuffer, mp_file_desc)
     564           38 :       CALL mp_file_type_free(mp_file_desc)
     565           38 :       CALL extunit%close()
     566              :       ! Convert cube values string -> real
     567           38 :       i = lbounds_local(1)
     568           38 :       j = lbounds_local(2)
     569          114 :       ALLOCATE (buffer(lbounds(3):ubounds(3)))
     570           38 :       buffer = 0.0_dp
     571        29450 :       DO islice = 1, nslices
     572        29412 :          CALL cube_read_values(readbuffer(islice), buffer(lbounds(3):ubounds(3)))
     573              :          ! Optionally scale cube file values
     574      1213948 :          grid%array(i, j, lbounds(3):ubounds(3)) = scaling*buffer(lbounds(3):ubounds(3))
     575        29412 :          j = j + 1
     576        29450 :          IF (j > ubounds_local(2)) THEN
     577          742 :             j = lbounds_local(2)
     578          742 :             i = i + 1
     579              :          END IF
     580              :       END DO
     581           38 :       DEALLOCATE (readbuffer)
     582           38 :       DEALLOCATE (blocklengths, displacements)
     583              :       IF (debug_this_module) THEN
     584              :          ! Check that cube was correctly read using intrinsic read on master who sends data to everyone
     585              :          buffer = 0.0_dp
     586              :          IF (my_rank == 0) THEN
     587              :             IF (output_unit > 0 .AND. .NOT. be_silent) THEN
     588              :                WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A)") "Reading the cube file:     ", filename
     589              :             END IF
     590              : 
     591              :             CALL open_file(file_name=filename, &
     592              :                            file_status="OLD", &
     593              :                            file_form="FORMATTED", &
     594              :                            file_action="READ", &
     595              :                            unit_number=extunit_handle)
     596              : 
     597              :             !skip header comments
     598              :             DO i = 1, 2
     599              :                READ (extunit_handle, *)
     600              :             END DO
     601              :             READ (extunit_handle, *) nat, rdum
     602              :             DO i = 1, 3
     603              :                READ (extunit_handle, *) ndum, rdum
     604              :                IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
     605              :                    output_unit > 0) THEN
     606              :                   WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
     607              :                   WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
     608              :                   WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
     609              :                END IF
     610              :             END DO
     611              :             !ignore atomic position data - read from coord or topology instead
     612              :             DO i = 1, nat
     613              :                READ (extunit_handle, *)
     614              :             END DO
     615              :          END IF
     616              : 
     617              :          !master sends all data to everyone
     618              :          DO i = lbounds(1), ubounds(1)
     619              :             DO j = lbounds(2), ubounds(2)
     620              :                IF (my_rank == 0) THEN
     621              :                   DO k = lbounds(3), ubounds(3), cube_num_entries_line
     622              :                      last_z = MIN(k + cube_num_entries_line - 1, ubounds(3))
     623              :                      READ (extunit_handle, '(A)') value_line
     624              :                      CALL cube_read_values(value_line, buffer(k:last_z))
     625              :                   END DO
     626              :                END IF
     627              :                CALL gid%bcast(buffer(lbounds(3):ubounds(3)), 0)
     628              : 
     629              :                !only use data that is local to me - i.e. in slice of pencil I own
     630              :                IF ((lbounds_local(1) <= i) .AND. (i <= ubounds_local(1)) .AND. (lbounds_local(2) <= j) &
     631              :                    .AND. (j <= ubounds_local(2))) THEN
     632              :                   !allow scaling of external potential values by factor 'scaling' (SCALING_FACTOR in input file)
     633              :                   IF (ANY(grid%array(i, j, lbounds(3):ubounds(3)) /= buffer(lbounds(3):ubounds(3))*scaling)) &
     634              :                      CALL cp_abort(__LOCATION__, &
     635              :                                    "Error in parallel read of input cube file.")
     636              :                END IF
     637              : 
     638              :             END DO
     639              :          END DO
     640              : 
     641              :          IF (my_rank == 0) CALL close_file(unit_number=extunit_handle)
     642              : 
     643              :          CALL gid%sync()
     644              :       END IF
     645           38 :       DEALLOCATE (buffer)
     646              : 
     647           38 :    END SUBROUTINE cube_to_pw_parallel
     648              : 
     649              : ! **************************************************************************************************
     650              : !> \brief Writes a realspace potential to a cube file using collective MPI I/O.
     651              : !> \param grid        the pw to output to the cube file
     652              : !> \param unit_nr     the handle associated with the cube file
     653              : !> \param title       title of the cube file
     654              : !> \param particles_r Cartersian coordinates of the system
     655              : !> \param particles_z atomic masses of atoms in the system
     656              : !> \param particles_zeff effective atomic charges of atoms in the system
     657              : !> \param stride      every stride(i)th value of the potential is outputted (i=x,y,z)
     658              : !> \param zero_tails  flag that determines if small values of the potential should be zeroed
     659              : !> \param msglen      the size of each grid slice along z-axis in bytes
     660              : !> \par History
     661              : !>      Created [Nico Holmberg] (11.2017)
     662              : ! **************************************************************************************************
     663         2012 :    SUBROUTINE pw_to_cube_parallel(grid, unit_nr, title, particles_r, particles_z, particles_zeff, &
     664              :                                   stride, zero_tails, msglen)
     665              : 
     666              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: grid
     667              :       TYPE(mp_file_type), INTENT(IN)                     :: unit_nr
     668              :       CHARACTER(*), INTENT(IN), OPTIONAL                 :: title
     669              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
     670              :          OPTIONAL                                        :: particles_r
     671              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: particles_z
     672              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL  :: particles_zeff
     673              :       INTEGER, INTENT(IN)                                :: stride(3)
     674              :       LOGICAL, INTENT(IN)                                :: zero_tails
     675              :       INTEGER, INTENT(IN)                                :: msglen
     676              : 
     677              :       INTEGER, PARAMETER                                 :: entry_len = 13, header_len = 41, &
     678              :                                                             header_len_z = 53, num_entries_line = 6
     679              : 
     680              :       CHARACTER(LEN=entry_len)                           :: value
     681              :       CHARACTER(LEN=header_len)                          :: header
     682              :       CHARACTER(LEN=header_len_z)                        :: header_z
     683              :       INTEGER, DIMENSION(3)                              :: lbounds, lbounds_local, ubounds, &
     684              :                                                             ubounds_local
     685         2012 :       INTEGER, ALLOCATABLE, DIMENSION(:), TARGET         :: blocklengths
     686              :       INTEGER(kind=file_offset), ALLOCATABLE, &
     687         2012 :          DIMENSION(:), TARGET                            :: displacements
     688              :       INTEGER(kind=file_offset)                          :: BOF
     689              :       INTEGER                                            :: counter, i, islice, j, k, last_z, &
     690              :                                                             my_rank, np, nslices, size_of_z
     691         2012 :       CHARACTER(LEN=msglen), ALLOCATABLE, DIMENSION(:)   :: writebuffer
     692         2012 :       CHARACTER(LEN=msglen)                              :: tmp
     693              :       LOGICAL                                            :: should_write(2)
     694              :       TYPE(mp_comm_type)                                 :: gid
     695              :       TYPE(mp_file_descriptor_type)                      :: mp_desc
     696              : 
     697              :       !get rs grids and parallel envnment
     698         2012 :       gid = grid%pw_grid%para%group
     699         2012 :       my_rank = grid%pw_grid%para%group%mepos
     700              : 
     701              :       ! Shortcut
     702         8048 :       lbounds = grid%pw_grid%bounds(1, :)
     703         8048 :       ubounds = grid%pw_grid%bounds(2, :)
     704         8048 :       lbounds_local = grid%pw_grid%bounds_local(1, :)
     705         8048 :       ubounds_local = grid%pw_grid%bounds_local(2, :)
     706              :       ! Determine the total number of z-slices and the number of values per slice
     707         2012 :       size_of_z = CEILING(REAL(ubounds_local(3) - lbounds_local(3) + 1, dp)/REAL(stride(3), dp))
     708         2012 :       islice = 1
     709        29213 :       DO i = lbounds(1), ubounds(1), stride(1)
     710        84621 :          should_write(:) = .TRUE.
     711        28207 :          IF (i < lbounds_local(1)) THEN
     712         9208 :             should_write(1) = .FALSE.
     713        18999 :          ELSE IF (i > ubounds_local(1)) THEN
     714              :             EXIT
     715              :          END IF
     716       596184 :          DO j = lbounds(2), ubounds(2), stride(2)
     717       566971 :             should_write(2) = .TRUE.
     718       566971 :             IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
     719            0 :                should_write(2) = .FALSE.
     720              :             END IF
     721      1345832 :             IF (ALL(should_write .EQV. .TRUE.)) THEN
     722       375830 :                islice = islice + 1
     723              :             END IF
     724              :          END DO
     725              :       END DO
     726         2012 :       nslices = islice - 1
     727        38572 :       DO k = lbounds(3), ubounds(3), stride(3)
     728        38572 :          IF (k + stride(3) > ubounds(3)) last_z = k
     729              :       END DO
     730         2012 :       islice = 1
     731              :       ! Determine initial byte offset (0 or EOF if data is appended)
     732         2012 :       CALL unit_nr%get_position(BOF)
     733              :       ! Write header information on master process and update byte offset accordingly
     734         2012 :       IF (my_rank == 0) THEN
     735              :          ! this format seems to work for e.g. molekel and gOpenmol
     736              :          ! latest version of VMD can read non orthorhombic cells
     737         1006 :          CALL unit_nr%write_at(BOF, "-Quickstep-"//NEW_LINE("C"))
     738         1006 :          BOF = BOF + LEN("-Quickstep-"//NEW_LINE("C"))*mpi_character_size
     739         1006 :          IF (PRESENT(title)) THEN
     740         1006 :             CALL unit_nr%write_at(BOF, TRIM(title)//NEW_LINE("C"))
     741         1006 :             BOF = BOF + LEN(TRIM(title)//NEW_LINE("C"))*mpi_character_size
     742              :          ELSE
     743            0 :             CALL unit_nr%write_at(BOF, "No Title"//NEW_LINE("C"))
     744            0 :             BOF = BOF + LEN("No Title"//NEW_LINE("C"))*mpi_character_size
     745              :          END IF
     746              : 
     747         1006 :          CPASSERT(PRESENT(particles_z) .EQV. PRESENT(particles_r))
     748         1006 :          np = 0
     749         1006 :          IF (PRESENT(particles_z)) THEN
     750         1006 :             CPASSERT(SIZE(particles_z) == SIZE(particles_r, dim=2))
     751              :             ! cube files can only be written for 99999 particles due to a format limitation (I5)
     752              :             ! so we limit the number of particles written.
     753         1006 :             np = MIN(99999, SIZE(particles_z))
     754              :          END IF
     755              : 
     756         1006 :          WRITE (header, '(I5,3f12.6)') np, 0.0_dp, 0._dp, 0._dp !start of cube
     757         1006 :          CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
     758         1006 :          BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
     759              : 
     760         1006 :          WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(1) + stride(1) - 1)/stride(1), &
     761         1006 :             grid%pw_grid%dh(1, 1)*REAL(stride(1), dp), grid%pw_grid%dh(2, 1)*REAL(stride(1), dp), &
     762         2012 :             grid%pw_grid%dh(3, 1)*REAL(stride(1), dp)
     763         1006 :          CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
     764         1006 :          BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
     765              : 
     766         1006 :          WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(2) + stride(2) - 1)/stride(2), &
     767         1006 :             grid%pw_grid%dh(1, 2)*REAL(stride(2), dp), grid%pw_grid%dh(2, 2)*REAL(stride(2), dp), &
     768         2012 :             grid%pw_grid%dh(3, 2)*REAL(stride(2), dp)
     769         1006 :          CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
     770         1006 :          BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
     771              : 
     772         1006 :          WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(3) + stride(3) - 1)/stride(3), &
     773         1006 :             grid%pw_grid%dh(1, 3)*REAL(stride(3), dp), grid%pw_grid%dh(2, 3)*REAL(stride(3), dp), &
     774         2012 :             grid%pw_grid%dh(3, 3)*REAL(stride(3), dp)
     775         1006 :          CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
     776         1006 :          BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
     777              : 
     778         1006 :          IF (PRESENT(particles_z)) THEN
     779         1006 :             IF (PRESENT(particles_zeff)) THEN
     780         1980 :                DO i = 1, np
     781         1542 :                   WRITE (header_z, '(I5,4f12.6)') particles_z(i), particles_zeff(i), particles_r(:, i)
     782         1542 :                   CALL unit_nr%write_at(BOF, header_z//NEW_LINE("C"))
     783         1980 :                   BOF = BOF + LEN(header_z//NEW_LINE("C"))*mpi_character_size
     784              :                END DO
     785              :             ELSE
     786         2543 :                DO i = 1, np
     787         1975 :                   WRITE (header_z, '(I5,4f12.6)') particles_z(i), 0._dp, particles_r(:, i)
     788         1975 :                   CALL unit_nr%write_at(BOF, header_z//NEW_LINE("C"))
     789         2543 :                   BOF = BOF + LEN(header_z//NEW_LINE("C"))*mpi_character_size
     790              :                END DO
     791              :             END IF
     792              :          END IF
     793              :       END IF
     794              :       ! Sync offset
     795         2012 :       CALL gid%bcast(BOF, grid%pw_grid%para%group%source)
     796              :       ! Determine byte offsets for each grid z-slice which are local to a process
     797              :       ! and convert z-slices to cube format compatible strings
     798         6036 :       ALLOCATE (displacements(nslices))
     799         2012 :       displacements = 0
     800         6036 :       ALLOCATE (writebuffer(nslices))
     801       377842 :       writebuffer(:) = ''
     802        29213 :       DO i = lbounds(1), ubounds(1), stride(1)
     803        84621 :          should_write(:) = .TRUE.
     804        28207 :          IF (i < lbounds_local(1)) THEN
     805         9208 :             should_write(1) = .FALSE.
     806        18999 :          ELSE IF (i > ubounds_local(1)) THEN
     807              :             EXIT
     808              :          END IF
     809        29213 :          DO j = lbounds(2), ubounds(2), stride(2)
     810       566971 :             should_write(2) = .TRUE.
     811       566971 :             IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
     812            0 :                should_write(2) = .FALSE.
     813              :             END IF
     814      1318631 :             IF (ALL(should_write .EQV. .TRUE.)) THEN
     815       375830 :                IF (islice > nslices) CPABORT("Index out of bounds.")
     816       375830 :                displacements(islice) = BOF
     817       375830 :                tmp = ''
     818       375830 :                counter = 0
     819      9639869 :                DO k = lbounds(3), ubounds(3), stride(3)
     820      9264039 :                   IF (zero_tails .AND. grid%array(i, j, k) < 1.E-7_dp) THEN
     821        54882 :                      WRITE (value, cube_value_format) 0.0_dp
     822              :                   ELSE
     823      9209157 :                      WRITE (value, cube_value_format) grid%array(i, j, k)
     824              :                   END IF
     825      9264039 :                   tmp = TRIM(tmp)//TRIM(value)
     826      9264039 :                   counter = counter + 1
     827      9264039 :                   IF (MODULO(counter, num_entries_line) == 0 .OR. k == last_z) &
     828      2063081 :                      tmp = TRIM(tmp)//NEW_LINE('C')
     829              :                END DO
     830       375830 :                writebuffer(islice) = tmp
     831       375830 :                islice = islice + 1
     832              :             END IF
     833              :             ! Update global byte offset
     834       566971 :             BOF = BOF + msglen
     835              :          END DO
     836              :       END DO
     837              :       ! Create indexed MPI type using calculated byte offsets as displacements
     838              :       ! Size of each z-slice is msglen
     839         6036 :       ALLOCATE (blocklengths(nslices))
     840       377842 :       blocklengths(:) = msglen
     841         2012 :       mp_desc = mp_file_type_hindexed_make_chv(nslices, blocklengths, displacements)
     842              :       ! Use the created type as a file view
     843              :       ! NB. The vector 'displacements' contains the absolute offsets of each z-slice i.e.
     844              :       ! they are given relative to the beginning of the file. The global offset to
     845              :       ! set_view must therefore be set to 0
     846         2012 :       BOF = 0
     847         2012 :       CALL mp_file_type_set_view_chv(unit_nr, BOF, mp_desc)
     848              :       ! Collective write of cube
     849         2012 :       CALL unit_nr%write_all(msglen, nslices, writebuffer, mp_desc)
     850              :       ! Clean up
     851         2012 :       CALL mp_file_type_free(mp_desc)
     852         2012 :       DEALLOCATE (writebuffer)
     853         2012 :       DEALLOCATE (blocklengths, displacements)
     854              : 
     855         2012 :    END SUBROUTINE pw_to_cube_parallel
     856              : 
     857              : ! **************************************************************************************************
     858              : !> \brief Prints a simple grid file: X Y Z value
     859              : !> \param pw ...
     860              : !> \param unit_nr ...
     861              : !> \param stride ...
     862              : !> \param pw2 ...
     863              : !> \par History
     864              : !>      Created [Vladimir Rybkin] (08.2018)
     865              : !> \author Vladimir Rybkin
     866              : ! **************************************************************************************************
     867           16 :    SUBROUTINE pw_to_simple_volumetric(pw, unit_nr, stride, pw2)
     868              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: pw
     869              :       INTEGER, INTENT(IN)                                :: unit_nr
     870              :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: stride
     871              :       TYPE(pw_r3d_rs_type), INTENT(IN), OPTIONAL         :: pw2
     872              : 
     873              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_to_simple_volumetric'
     874              : 
     875              :       INTEGER                                            :: checksum, dest, handle, i, I1, I2, I3, &
     876              :                                                             ip, L1, L2, L3, my_rank, my_stride(3), &
     877              :                                                             ngrids, npoints, num_pe, rank(2), &
     878              :                                                             source, tag, U1, U2, U3
     879              :       LOGICAL                                            :: DOUBLE
     880              :       REAL(KIND=dp)                                      :: x, y, z
     881           16 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: buf, buf2
     882              :       TYPE(mp_comm_type)                                 :: gid
     883              : 
     884           16 :       CALL timeset(routineN, handle)
     885              : 
     886              :       ! Check if we write two grids
     887           16 :       DOUBLE = .FALSE.
     888           16 :       IF (PRESENT(pw2)) DOUBLE = .TRUE.
     889              : 
     890           64 :       my_stride = 1
     891           16 :       IF (PRESENT(stride)) THEN
     892           16 :          IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) &
     893              :             CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 "// &
     894           16 :                           "(the same for X,Y,Z) or 3 values. Correct your input file.")
     895           16 :          IF (SIZE(stride) == 1) THEN
     896            0 :             DO i = 1, 3
     897            0 :                my_stride(i) = stride(1)
     898              :             END DO
     899              :          ELSE
     900           64 :             my_stride = stride(1:3)
     901              :          END IF
     902           16 :          CPASSERT(my_stride(1) > 0)
     903           16 :          CPASSERT(my_stride(2) > 0)
     904           16 :          CPASSERT(my_stride(3) > 0)
     905              :       END IF
     906              : 
     907              :       ! shortcut
     908           16 :       L1 = pw%pw_grid%bounds(1, 1)
     909           16 :       L2 = pw%pw_grid%bounds(1, 2)
     910           16 :       L3 = pw%pw_grid%bounds(1, 3)
     911           16 :       U1 = pw%pw_grid%bounds(2, 1)
     912           16 :       U2 = pw%pw_grid%bounds(2, 2)
     913           16 :       U3 = pw%pw_grid%bounds(2, 3)
     914              : 
     915              :       ! Write the header: number of points and number of spins
     916           16 :       ngrids = 1
     917           16 :       IF (DOUBLE) ngrids = 2
     918              :       npoints = ((pw%pw_grid%npts(1) + my_stride(1) - 1)/my_stride(1))* &
     919              :                 ((pw%pw_grid%npts(2) + my_stride(2) - 1)/my_stride(1))* &
     920           16 :                 ((pw%pw_grid%npts(3) + my_stride(3) - 1)/my_stride(1))
     921           16 :       IF (unit_nr > 1) WRITE (unit_nr, '(I7,I5)') npoints, ngrids
     922              : 
     923           48 :       ALLOCATE (buf(L3:U3))
     924           16 :       IF (DOUBLE) ALLOCATE (buf2(L3:U3))
     925              : 
     926           16 :       my_rank = pw%pw_grid%para%group%mepos
     927           16 :       gid = pw%pw_grid%para%group
     928           16 :       num_pe = pw%pw_grid%para%group%num_pe
     929           16 :       tag = 1
     930              : 
     931           16 :       rank (1) = unit_nr
     932           16 :       rank (2) = my_rank
     933           16 :       checksum = 0
     934           16 :       IF (unit_nr > 0) checksum = 1
     935              : 
     936           16 :       CALL gid%sum(checksum)
     937           16 :       CPASSERT(checksum == 1)
     938              : 
     939           16 :       CALL gid%maxloc(rank)
     940           16 :       CPASSERT(rank(1) > 0)
     941              : 
     942           16 :       dest = rank(2)
     943          500 :       DO I1 = L1, U1, my_stride(1)
     944        15288 :          DO I2 = L2, U2, my_stride(2)
     945              : 
     946              :             ! cycling through the CPUs, check if the current ray (I1,I2) is local to that CPU
     947        14788 :             IF (pw%pw_grid%para%mode /= PW_MODE_LOCAL) THEN
     948        44364 :                DO ip = 0, num_pe - 1
     949              :                   IF (pw%pw_grid%para%bo(1, 1, ip, 1) <= I1 - L1 + 1 .AND. pw%pw_grid%para%bo(2, 1, ip, 1) >= I1 - L1 + 1 .AND. &
     950        44364 :                       pw%pw_grid%para%bo(1, 2, ip, 1) <= I2 - L2 + 1 .AND. pw%pw_grid%para%bo(2, 2, ip, 1) >= I2 - L2 + 1) THEN
     951        14788 :                      source = ip
     952              :                   END IF
     953              :                END DO
     954              :             ELSE
     955            0 :                source = dest
     956              :             END IF
     957              : 
     958        14788 :             IF (source == dest) THEN
     959         7444 :                IF (my_rank == source) THEN
     960       118276 :                   buf(:) = pw%array(I1, I2, :)
     961         3722 :                   IF (DOUBLE) buf2(:) = pw2%array(I1, I2, :)
     962              :                END IF
     963              :             ELSE
     964         7344 :                IF (my_rank == source) THEN
     965       116976 :                   buf(:) = pw%array(I1, I2, :)
     966         3672 :                   CALL gid%send(buf, dest, tag)
     967         3672 :                   IF (DOUBLE) THEN
     968            0 :                      buf2(:) = pw2%array(I1, I2, :)
     969            0 :                      CALL gid%send(buf2, dest, tag)
     970              :                   END IF
     971              :                END IF
     972         7344 :                IF (my_rank == dest) THEN
     973         3672 :                   CALL gid%recv(buf, source, tag)
     974         3672 :                   IF (DOUBLE) CALL gid%recv(buf2, source, tag)
     975              :                END IF
     976              :             END IF
     977              : 
     978         7394 :             IF (.NOT. DOUBLE) THEN
     979       470504 :                DO I3 = L3, U3, my_stride(3)
     980              :                   x = pw%pw_grid%dh(1, 1)*I1 + &
     981              :                       pw%pw_grid%dh(2, 1)*I2 + &
     982       455716 :                       pw%pw_grid%dh(3, 1)*I3
     983              : 
     984              :                   y = pw%pw_grid%dh(1, 2)*I1 + &
     985              :                       pw%pw_grid%dh(2, 2)*I2 + &
     986       455716 :                       pw%pw_grid%dh(3, 2)*I3
     987              : 
     988              :                   z = pw%pw_grid%dh(1, 3)*I1 + &
     989              :                       pw%pw_grid%dh(2, 3)*I2 + &
     990       455716 :                       pw%pw_grid%dh(3, 3)*I3
     991              : 
     992       470504 :                   IF (unit_nr > 0) THEN
     993       227858 :                      WRITE (unit_nr, '(6E13.5E3, 6E13.5E3, 6E13.5E3, 6E13.5E3)') x, y, z, buf(I3)
     994              :                   END IF
     995              :                END DO
     996              : 
     997              :             ELSE
     998              : 
     999            0 :                DO I3 = L3, U3, my_stride(3)
    1000              :                   x = pw%pw_grid%dh(1, 1)*I1 + &
    1001              :                       pw%pw_grid%dh(2, 1)*I2 + &
    1002            0 :                       pw%pw_grid%dh(3, 1)*I3
    1003              : 
    1004              :                   y = pw%pw_grid%dh(1, 2)*I1 + &
    1005              :                       pw%pw_grid%dh(2, 2)*I2 + &
    1006            0 :                       pw%pw_grid%dh(3, 2)*I3
    1007              : 
    1008              :                   z = pw%pw_grid%dh(1, 3)*I1 + &
    1009              :                       pw%pw_grid%dh(2, 3)*I2 + &
    1010            0 :                       pw%pw_grid%dh(3, 3)*I3
    1011              : 
    1012            0 :                   IF (unit_nr > 0) THEN
    1013            0 :                      WRITE (unit_nr, '(6E13.5E3, 6E13.5E3, 6E13.5E3, 6E13.5E3)') x, y, z, buf(I3), buf2(I3)
    1014              :                   END IF
    1015              :                END DO
    1016              : 
    1017              :             END IF ! Double
    1018              : 
    1019              :             ! this double loop generates so many messages that it can overload
    1020              :             ! the message passing system, e.g. on XT3
    1021              :             ! we therefore put a barrier here that limits the amount of message
    1022              :             ! that flies around at any given time.
    1023              :             ! if ever this routine becomes a bottleneck, we should go for a
    1024              :             ! more complicated rewrite
    1025        15272 :             CALL gid%sync()
    1026              : 
    1027              :          END DO
    1028              :       END DO
    1029              : 
    1030           16 :       DEALLOCATE (buf)
    1031           16 :       IF (DOUBLE) DEALLOCATE (buf2)
    1032              : 
    1033           16 :       CALL timestop(handle)
    1034              : 
    1035           32 :    END SUBROUTINE pw_to_simple_volumetric
    1036              : 
    1037              : END MODULE realspace_grid_cube
        

Generated by: LCOV version 2.0-1