convert_brd_to_csr Subroutine

private subroutine convert_brd_to_csr(brd_mat, csr_mat)

Convert a block-row distributed DBCSR matrix to a CSR matrix The DBCSR matrix must have a block structure consistent with the CSR matrix.

Arguments

Type IntentOptional Attributes Name
type(dbcsr_type), intent(in) :: brd_mat

block-row distributed DBCSR matrix

type(csr_type), intent(inout) :: csr_mat

CSR matrix


Source Code

   SUBROUTINE convert_brd_to_csr(brd_mat, csr_mat)
      !! Convert a block-row distributed DBCSR matrix to a CSR matrix
      !! The DBCSR matrix must have a block structure consistent with the CSR matrix.

      TYPE(dbcsr_type), INTENT(IN)                       :: brd_mat
         !! block-row distributed DBCSR matrix
      TYPE(csr_type), INTENT(INOUT)                      :: csr_mat
         !! CSR matrix

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

      INTEGER :: blk, blkcol, blkrow, col_blk_offset, col_blk_size, csr_ind, data_type, dbcsr_ind, &
                 el_sum, handle, ind_blk_data, k, local_row_ind, m, n, nblkrows_total, node_row_offset, &
                 prev_blkrow, prev_row_blk_size, row_blk_offset, row_blk_size
      INTEGER, ALLOCATABLE, DIMENSION(:)                 :: nfullcol_blkrow
      INTEGER, DIMENSION(:), POINTER                     :: colind, csr_index, dbcsr_index, nzerow, &
                                                            rowptr
      LOGICAL                                            :: new_ind, tr
      TYPE(dbcsr_data_obj)                               :: block
      TYPE(dbcsr_iterator)                               :: iter

      CALL timeset(routineN, handle)
      local_row_ind = 0
      dbcsr_ind = 0
      node_row_offset = 0
      NULLIFY (rowptr, colind, dbcsr_index, csr_index)

      dbcsr_index => csr_mat%dbcsr_mapping%csr_to_brd_ind
      csr_index => csr_mat%dbcsr_mapping%brd_to_csr_ind

      ! CSR indices are not recalculated if indices are already defined
      new_ind = .NOT. (csr_mat%has_indices)

      IF (.NOT. csr_mat%has_mapping) &
         DBCSR_ABORT("DBCSR mapping of CSR matrix must be defined")

      ! Calculate mapping between CSR matrix and DBCSR matrix if not yet defined
      !IF (.NOT. csr_mat%has_mapping ) THEN
      !  CALL csr_get_dbcsr_mapping (brd_mat, dbcsr_index, csr_index, nze)
      !ENDIF

      CALL dbcsr_get_info(brd_mat, nblkrows_total=nblkrows_total)
      ALLOCATE (nfullcol_blkrow(nblkrows_total))

      ! iteration over blocks without touching data,
      ! in order to get number of non-zero full columns in each block row
      CALL dbcsr_iterator_start(iter, brd_mat, read_only=.TRUE.)
      blkrow = 0
      nfullcol_blkrow = 0 ! number of non-zero full columns in each block row
      data_type = dbcsr_get_data_type(brd_mat)

      DO WHILE (dbcsr_iterator_blocks_left(iter))
         CALL dbcsr_iterator_next_block(iter, blkrow, blkcol, blk, col_size=col_blk_size, &
                                        row_offset=row_blk_offset)
         nfullcol_blkrow(blkrow) = nfullcol_blkrow(blkrow) + col_blk_size
         IF (blk .EQ. 1) THEN
            node_row_offset = row_blk_offset
         END IF
      END DO

      CALL dbcsr_iterator_stop(iter)

      ! Copy data from BRD matrix to CSR matrix and calculate CSR indices
      prev_blkrow = 0
      prev_row_blk_size = 0
      el_sum = 0 ! number of elements above current block row
      colind => csr_mat%colind_local
      rowptr => csr_mat%rowptr_local
      nzerow => csr_mat%nzerow_local
      CALL dbcsr_data_init(block)
      CALL dbcsr_data_new(block, data_type)

      CALL dbcsr_iterator_start(iter, brd_mat, read_only=.TRUE.)

      IF (new_ind) rowptr(:) = 0 ! initialize to 0 in order to check which rows are 0 at a later time
      DO WHILE (dbcsr_iterator_blocks_left(iter))
         CALL dbcsr_iterator_next_block(iter, blkrow, blkcol, block, tr, &
                                        col_size=col_blk_size, row_size=row_blk_size, row_offset=row_blk_offset, &
                                        col_offset=col_blk_offset)

         IF (tr) &
            DBCSR_ABORT("DBCSR block data must not be transposed")

         IF (blkrow > prev_blkrow) THEN ! new block row
            local_row_ind = row_blk_offset - node_row_offset ! actually: local row index - 1
            IF (prev_blkrow .GT. 0) THEN
               el_sum = el_sum + nfullcol_blkrow(prev_blkrow)*prev_row_blk_size
            END IF
            dbcsr_ind = el_sum
         END IF
         DO n = 1, col_blk_size !nr of columns
            DO m = 1, row_blk_size !nr of rows
               dbcsr_ind = dbcsr_ind + 1
               csr_ind = csr_index(dbcsr_ind) ! get CSR index for current element
               IF (csr_ind .GT. 0) THEN ! is non-zero element if csr_ind > 0
                  IF (new_ind) THEN
                     ! Calculate CSR column index
                     colind(csr_ind) = col_blk_offset + n - 1
                     ! Calculate CSR row pointer
                     ! (not accounting for zero elements inside non-zero blocks)
                     IF (rowptr(local_row_ind + m) .LE. 0) rowptr(local_row_ind + m) = &
                        rowptr(local_row_ind + m) + el_sum + 1 + nfullcol_blkrow(blkrow)*(m - 1)
                  END IF
                  ind_blk_data = (m + row_blk_size*(n - 1)) ! index of data inside DBCSR blocks
                  SELECT CASE (csr_mat%nzval_local%data_type)
                  CASE (dbcsr_type_real_4)
                     csr_mat%nzval_local%r_sp(csr_ind) = block%d%r_sp(ind_blk_data)
                  CASE (dbcsr_type_real_8)
                     csr_mat%nzval_local%r_dp(csr_ind) = block%d%r_dp(ind_blk_data)
                  CASE (dbcsr_type_complex_4)
                     csr_mat%nzval_local%c_sp(csr_ind) = block%d%c_sp(ind_blk_data)
                  CASE (dbcsr_type_complex_8)
                     csr_mat%nzval_local%c_dp(csr_ind) = block%d%c_dp(ind_blk_data)
                  END SELECT
               ELSE ! is zero element if ind = -1
                  ! CSR row pointer has to be corrected if element is zero
                  ! (subtract 1 from all subsequent row pointers)
                  IF (new_ind) rowptr(local_row_ind + m + 1:) = rowptr(local_row_ind + m + 1:) - 1
               END IF
            END DO
         END DO
         prev_blkrow = blkrow
         prev_row_blk_size = row_blk_size
      END DO

      IF (new_ind) THEN
         ! Repeat previous row pointer for row pointers to zero rows
         IF (csr_mat%nrows_local .GT. 0) rowptr(1) = 1
         DO k = 1, csr_mat%nrows_local
            IF (rowptr(k) .LE. 0) rowptr(k) = rowptr(k - 1)
         END DO

         rowptr(csr_mat%nrows_local + 1) = csr_mat%nze_local + 1
      END IF

      CALL csr_create_nzerow(csr_mat, nzerow)

      CALL dbcsr_iterator_stop(iter)
      CALL dbcsr_data_clear_pointer(block)
      CALL dbcsr_data_release(block)

      IF (new_ind) csr_mat%has_indices = .TRUE.

      CALL timestop(handle)
   END SUBROUTINE convert_brd_to_csr