dbcsr_binary_read Subroutine

public subroutine dbcsr_binary_read(filepath, distribution, matrix_new)

Reads a DBCSR matrix from a file

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: filepath

path to the file

type(dbcsr_distribution_obj), intent(in) :: distribution

row and column distribution

type(dbcsr_type), intent(inout) :: matrix_new

DBCSR matrix


Source Code

   SUBROUTINE dbcsr_binary_read(filepath, distribution, matrix_new)
      !! Reads a DBCSR matrix from a file

      IMPLICIT NONE

      CHARACTER(len=*), INTENT(IN)                :: filepath
         !! path to the file
      TYPE(dbcsr_distribution_obj), INTENT(IN)     :: distribution
         !! row and column distribution
      TYPE(dbcsr_type), INTENT(INOUT)               :: matrix_new
         !! DBCSR matrix

      CHARACTER(LEN=*), PARAMETER :: routineN = 'dbcsr_binary_read'

      INTEGER                               :: nblkrows_total, nblkcols_total, &
                                               nblks, darea_size, data_type, type_size, &
                                               globalinfo_size, &
                                               size_of_pgrid, &
                                               i, j, &
                                               nblocks, &
                                               share_size, order, cur_blks, &
                                               job_count, start_index, end_index, &
                                               localinfo_length, blockdata_length, &
                                               worker_id, group_list_size, handle, linfo_length
      CHARACTER                             :: matrix_type
      CHARACTER(LEN=default_string_length)  :: matrix_name
      INTEGER, PARAMETER                    :: version_len = 10
      CHARACTER(LEN=version_len)            :: version
      CHARACTER(LEN=80)                     :: matrix_name_v_1_0
      CHARACTER(LEN=version_len), PARAMETER :: version_v_1_0 = "DBCSRv_1.0"
      TYPE(mp_comm_type)                    :: group_id
      TYPE(mp_file_type)                    :: thefile

      INTEGER, DIMENSION(:), POINTER        :: row_p, col_i, blk_p, &
                                               proc_nblks, proc_darea_sizes
      INTEGER, DIMENSION(4)                 :: values
      INTEGER, ALLOCATABLE, DIMENSION(:)    :: linfo_lens, bdata_lens
      INTEGER, ALLOCATABLE, DIMENSION(:), TARGET     :: ginfo_vec, linfo_vec, &
                                                        rowp, coli, blkp
      INTEGER, ALLOCATABLE, DIMENSION(:, :), TARGET   :: val_data
      INTEGER, DIMENSION(:), POINTER, CONTIGUOUS     :: row_blk_size, col_blk_size
      TYPE(dbcsr_mp_obj)                             :: mp_env
      TYPE(dbcsr_data_obj)                           :: dblk
      REAL(sp)                                       :: rsp_dummy(1)
      REAL(dp)                                       :: rdp_dummy(1)
      COMPLEX(sp)                                    :: csp_dummy(1)
      COMPLEX(dp)                                    :: cdp_dummy(1)
      REAL(sp), ALLOCATABLE, DIMENSION(:), TARGET     :: rsp
      REAL(dp), ALLOCATABLE, DIMENSION(:), TARGET     :: rdp
      COMPLEX(sp), ALLOCATABLE, DIMENSION(:), TARGET  :: csp
      COMPLEX(dp), ALLOCATABLE, DIMENSION(:), TARGET  :: cdp
      INTEGER(kind=file_offset), ALLOCATABLE, DIMENSION(:)   :: subh2_offsets, &
                                                                subh3_disps, subh3_offsets, &
                                                                bdata_disps, bdata_offsets
      INTEGER(kind=file_offset), PARAMETER    :: BOF = 0
      INTEGER(kind=file_offset)               :: offset, subh2_start, subh3_start, bdata_start, file_size, &
                                                 localinfo_offset, blockdata_offset, sum_nblks, subh3_length, data_area_size
      INTEGER, PARAMETER                      :: char_count = 1 + version_len + default_string_length

      CALL timeset(routineN, handle)

      mp_env = dbcsr_distribution_mp(distribution)
      group_id = dbcsr_mp_group(mp_env)

      CALL mp_environ(group_list_size, worker_id, group_id)
      CALL mp_file_open(group_id, thefile, filepath, file_amode_rdonly)

! read version, matrix name and matrix type
      CALL mp_file_read_at_all(thefile, BOF, version)

      IF (version /= version_v_1_0) &
         DBCSR_WARN("Trying to read an unknown version of the matrix data file. Good luck!")

      CALL mp_file_read_at_all(thefile, BOF + version_len*mpi_character_size, matrix_name_v_1_0)
      matrix_name = matrix_name_v_1_0

      CALL mp_file_read_at_all(thefile, BOF + (version_len + default_string_length)*mpi_character_size, matrix_type)
! read 4 integer values form sub-header1
      CALL mp_file_read_at_all(thefile, BOF + char_count*mpi_character_size, values)
      size_of_pgrid = values(1)
      data_type = values(2)
      nblkrows_total = values(3)
      nblkcols_total = values(4)
! read 2 vectors, row_blk_size and col_blk_size, from sub-header1
      globalinfo_size = nblkrows_total + nblkcols_total
      ALLOCATE (ginfo_vec(globalinfo_size))
      CALL mp_file_read_at_all(thefile, BOF + char_count*mpi_character_size + 4*mpi_integer_size, ginfo_vec)
      row_blk_size => ginfo_vec(1:nblkrows_total)
      col_blk_size => ginfo_vec(nblkrows_total + 1:globalinfo_size)

! compute the offsets where sub-header2 and sub-header3 start
      subh2_start = (4 + globalinfo_size)*mpi_integer_size + char_count*mpi_character_size
      subh3_start = subh2_start + 2*size_of_pgrid*mpi_integer_size

! compute the offsets in sub-header2 and read 2 integers nblocks, data_area_size
      ! number of data chunks from sub-header 2 and 3 to be read by every node rounded up
      ! to the next integer to make it even for all the nodes in the specified mpi group
      share_size = CEILING(REAL(size_of_pgrid, KIND=dp)/group_list_size)

      ALLOCATE (subh2_offsets(share_size))
      subh2_offsets = BOF
      DO i = 1, share_size
         offset = subh2_start + mpi_integer_size*2*(worker_id + (i - 1)*group_list_size)
         IF (offset .GE. subh3_start) EXIT
         subh2_offsets(i) = offset
      END DO

      ALLOCATE (val_data(3, share_size))
      val_data(:, :) = 0
      DO i = 1, share_size
         CALL mp_file_read_at_all(thefile, subh2_offsets(i), values, msglen=2)
         nblocks = values(1)
         data_area_size = values(2)
         IF (subh2_offsets(i) .EQ. 0) EXIT
         val_data(1, i) = nblocks
         IF (data_area_size >= HUGE(val_data(2, i))) &
            DBCSR_ABORT("Data area too large, fix code.")
         val_data(2, i) = INT(data_area_size)
         val_data(3, i) = worker_id + (i - 1)*group_list_size + 1 ! order
         ! order = indices of an array of length size_of_pgrid to be accessed by the current node
      END DO
      nblks = SUM(val_data(1, :))
      darea_size = SUM(val_data(2, :))
      proc_nblks => val_data(1, :) ! to be passed to dbcsr_datablock_redistribute
      proc_darea_sizes => val_data(2, :) ! to be passed to dbcsr_datablock_redistribute

! compute the offsets in sub-header3 and read 3 vectors row_p, col_i, blk_p
      ! actual number of chunks to be read by the current node
      job_count = COUNT(val_data(3, :) .NE. 0)
      CALL mp_file_get_size(thefile, file_size)

      ALLOCATE (linfo_lens(size_of_pgrid))
      ALLOCATE (subh3_disps(size_of_pgrid))
      ALLOCATE (subh3_offsets(size_of_pgrid))
      linfo_lens = 0; subh3_disps = 0
      DO i = 1, size_of_pgrid
         DO j = 1, share_size
            order = val_data(3, j)
            IF (i .EQ. order) linfo_lens(order) = &
               1 + nblkrows_total + 2*val_data(1, j)
         END DO
      END DO
      CALL mp_sum(linfo_lens, group_id)
      CALL cumsum_l(INT(linfo_lens, kind=file_offset), subh3_disps)
      subh3_disps(:) = CSHIFT(subh3_disps, shift=-1)
      subh3_disps(1) = BOF
      subh3_offsets(:) = subh3_start + subh3_disps*mpi_integer_size

      sum_nblks = INT(nblks, kind=file_offset)
      CALL mp_sum(sum_nblks, group_id)
      subh3_length = size_of_pgrid*INT(1 + nblkrows_total, KIND=file_offset) + 2*sum_nblks

      linfo_length = nblkrows_total + 1 + 2*MAXVAL(val_data(1, :))

      ALLOCATE (linfo_vec(linfo_length))
      ALLOCATE (rowp((nblkrows_total + 1)*job_count))
      ALLOCATE (coli(nblks))
      ALLOCATE (blkp(nblks))
      DO i = 1, share_size
         order = val_data(3, i)
         cur_blks = val_data(1, i)
         IF (order .EQ. 0) THEN
            localinfo_offset = file_size
            localinfo_length = 0
         ELSE
            localinfo_offset = subh3_offsets(order)
            localinfo_length = linfo_lens(order)
         END IF
         CALL mp_file_read_at_all(thefile, localinfo_offset, linfo_vec, msglen=localinfo_length)
         IF (localinfo_length .EQ. 0) EXIT

         rowp((i - 1)*(nblkrows_total + 1) + 1:i*(nblkrows_total + 1)) = linfo_vec(1:nblkrows_total + 1)
         start_index = SUM(val_data(1, 1:i - 1)) + 1
         end_index = SUM(val_data(1, 1:i))
         coli(start_index:end_index) = &
            linfo_vec(nblkrows_total + 2:cur_blks + nblkrows_total + 1)
         blkp(start_index:end_index) = &
            linfo_vec(cur_blks + nblkrows_total + 2:2*cur_blks + nblkrows_total + 1)
      END DO
      row_p => rowp
      col_i => coli
      blk_p => blkp

! compute the offsets and read block data
      ALLOCATE (bdata_lens(size_of_pgrid))
      ALLOCATE (bdata_disps(size_of_pgrid))
      ALLOCATE (bdata_offsets(size_of_pgrid))
      bdata_lens = 0
      DO i = 1, size_of_pgrid
         DO j = 1, share_size
            order = val_data(3, j)
            IF (i .EQ. order) bdata_lens(order) = val_data(2, j)
         END DO
      END DO
      CALL mp_sum(bdata_lens, group_id)
      CALL cumsum_l(INT(bdata_lens, kind=file_offset), bdata_disps)
      bdata_disps(:) = CSHIFT(bdata_disps, shift=-1)
      bdata_disps(1) = BOF

      bdata_start = subh3_start + subh3_length*mpi_integer_size
      SELECT CASE (data_type)
      CASE (dbcsr_type_real_4)
         type_size = real_4_size
      CASE (dbcsr_type_real_8)
         type_size = real_8_size
      CASE (dbcsr_type_complex_4)
         type_size = 2*real_4_size
      CASE (dbcsr_type_complex_8)
         type_size = 2*real_8_size
      END SELECT
      bdata_offsets(:) = bdata_start + bdata_disps*type_size

      SELECT CASE (data_type)
      CASE (dbcsr_type_real_4)
         ALLOCATE (rsp(darea_size))
         DO i = 1, share_size
            order = val_data(3, i)
            ! use dummy one-sized data array as buffer in place of empty array
            ! when nothing is supposed to be read (order = 0)
            IF (order .EQ. 0) THEN
               blockdata_offset = file_size
               CALL mp_file_read_at_all(thefile, blockdata_offset, rsp_dummy)
            ELSE
               start_index = SUM(val_data(2, 1:i - 1)) + 1
               end_index = SUM(val_data(2, 1:i))
               blockdata_length = bdata_lens(order)
               blockdata_offset = bdata_offsets(order)
               CALL mp_file_read_at_all(thefile, blockdata_offset, rsp(start_index:end_index), &
                                        msglen=blockdata_length)
            END IF
         END DO
      CASE (dbcsr_type_real_8)
         ALLOCATE (rdp(darea_size))
         DO i = 1, share_size
            order = val_data(3, i)
            IF (order .EQ. 0) THEN
               blockdata_offset = file_size
               CALL mp_file_read_at_all(thefile, blockdata_offset, rdp_dummy)
            ELSE
               start_index = SUM(val_data(2, 1:i - 1)) + 1
               end_index = SUM(val_data(2, 1:i))
               blockdata_length = bdata_lens(order)
               blockdata_offset = bdata_offsets(order)
               CALL mp_file_read_at_all(thefile, blockdata_offset, rdp(start_index:end_index), &
                                        msglen=blockdata_length)
            END IF
         END DO
      CASE (dbcsr_type_complex_4)
         ALLOCATE (csp(darea_size))
         DO i = 1, share_size
            order = val_data(3, i)
            IF (order .EQ. 0) THEN
               blockdata_offset = file_size
               CALL mp_file_read_at_all(thefile, blockdata_offset, csp_dummy)
            ELSE
               start_index = SUM(val_data(2, 1:i - 1)) + 1
               end_index = SUM(val_data(2, 1:i))
               blockdata_length = bdata_lens(order)
               blockdata_offset = bdata_offsets(order)
               CALL mp_file_read_at_all(thefile, blockdata_offset, csp(start_index:end_index), &
                                        msglen=blockdata_length)
            END IF
         END DO
      CASE (dbcsr_type_complex_8)
         ALLOCATE (cdp(darea_size))
         DO i = 1, share_size
            order = val_data(3, i)
            IF (order .EQ. 0) THEN
               blockdata_offset = file_size
               CALL mp_file_read_at_all(thefile, blockdata_offset, cdp_dummy)
            ELSE
               start_index = SUM(val_data(2, 1:i - 1)) + 1
               end_index = SUM(val_data(2, 1:i))
               blockdata_length = bdata_lens(order)
               blockdata_offset = bdata_offsets(order)
               CALL mp_file_read_at_all(thefile, blockdata_offset, cdp(start_index:end_index), &
                                        msglen=blockdata_length)
            END IF
         END DO
      END SELECT
      CALL dbcsr_data_init(dblk)
      CALL dbcsr_data_new(dblk, data_type)
      IF (ALLOCATED(rdp)) dblk%d%r_dp => rdp
      IF (ALLOCATED(rsp)) dblk%d%r_sp => rsp
      IF (ALLOCATED(cdp)) dblk%d%c_dp => cdp
      IF (ALLOCATED(csp)) dblk%d%c_sp => csp

      CALL mp_file_close(thefile)

      CALL dbcsr_create(matrix_new, matrix_name, distribution, matrix_type, &
                        row_blk_size, col_blk_size, nze=darea_size, &
                        data_type=data_type)
      CALL dbcsr_datablock_redistribute(dblk, row_p, col_i, blk_p, proc_nblks, proc_darea_sizes, matrix_new)

      DEALLOCATE (subh2_offsets, subh3_offsets, bdata_offsets)
      DEALLOCATE (subh3_disps, bdata_disps)
      DEALLOCATE (linfo_lens, bdata_lens)
      DEALLOCATE (val_data, ginfo_vec, linfo_vec)
      DEALLOCATE (rowp, coli, blkp)
      IF (ALLOCATED(rdp)) DEALLOCATE (rdp)
      IF (ALLOCATED(rsp)) DEALLOCATE (rsp)
      IF (ALLOCATED(cdp)) DEALLOCATE (cdp)
      IF (ALLOCATED(csp)) DEALLOCATE (csp)
      CALL dbcsr_data_clear_pointer(dblk)
      DEALLOCATE (dblk%d)

      CALL timestop(handle)
   CONTAINS
      SUBROUTINE cumsum_l(arr, cumsum)
         INTEGER(kind=file_offset), DIMENSION(:), &
            INTENT(IN)                                      :: arr
         INTEGER(kind=file_offset), DIMENSION(SIZE(arr)), &
            INTENT(OUT)                                     :: cumsum

         INTEGER                                            :: i

         cumsum(1) = arr(1)
         DO i = 2, SIZE(arr)
            cumsum(i) = cumsum(i - 1) + arr(i)
         END DO
      END SUBROUTINE cumsum_l

   END SUBROUTINE dbcsr_binary_read