Inserts block reservations into a matrix, avoiding the work matrix.
Data No data can be specified; instead, space is reserved and zeroed. To add data, call dbcsr_put_block afterwards.
Reserving existing blocks Duplicates are not added, but allocations may be greater than the minimum necessary.
blk_pointers When blk_pointers is passed, the newly added blocks use these pointers. No data is cleared in this case
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
type(dbcsr_type), | intent(inout) | :: | matrix |
Matrix into which blocks should be added. |
||
integer, | intent(in), | DIMENSION(:) | :: | rows |
Rows of the blocks to add Columns of the blocks to add |
|
integer, | intent(in), | DIMENSION(:) | :: | columns |
Rows of the blocks to add Columns of the blocks to add |
|
integer, | intent(in), | optional, | DIMENSION(:) | :: | blk_pointers |
block pointers to use for new blocks |
SUBROUTINE dbcsr_reserve_blocks(matrix, rows, columns, blk_pointers)
!! Inserts block reservations into a matrix, avoiding the work matrix.
!!
!! Data
!! No data can be specified; instead, space is reserved and zeroed. To
!! add data, call dbcsr_put_block afterwards.
!!
!! Reserving existing blocks
!! Duplicates are not added, but allocations may be greater than
!! the minimum necessary.
!!
!! blk_pointers
!! When blk_pointers is passed, the newly added blocks use these pointers.
!! No data is cleared in this case
TYPE(dbcsr_type), INTENT(INOUT) :: matrix
!! Matrix into which blocks should be added.
INTEGER, DIMENSION(:), INTENT(IN) :: rows, columns
!! Rows of the blocks to add
!! Columns of the blocks to add
INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: blk_pointers
!! block pointers to use for new blocks
CHARACTER(len=*), PARAMETER :: routineN = 'dbcsr_reserve_blocks'
INTEGER :: blk, blk_p, data_size_new, data_size_old, handle, nblkrows, nblks_actual_added, &
nblks_added, nblks_new, nblks_old, new_data_sizes, nze
INTEGER, ALLOCATABLE, DIMENSION(:) :: add_blkp, add_cols, add_rows, &
added_sizes, new_blk_p, new_col_i, &
new_row_i, old_row_i
INTEGER, ALLOCATABLE, DIMENSION(:, :) :: added_blk_info
! ---------------------------------------------------------------------------
CALL timeset(routineN, handle)
IF (SIZE(rows) /= SIZE(columns)) &
DBCSR_ABORT("Size of rows and columns array must match.")
IF (PRESENT(blk_pointers)) THEN
IF (SIZE(rows) /= SIZE(blk_pointers)) &
DBCSR_ABORT("Size of rows and block pointecs arrays must match.")
data_size_old = 0
ELSE
! Get current data size
data_size_old = dbcsr_data_get_size_referenced(matrix%data_area)
END IF
! Ensures that the rows and columns are sorted.
nblks_added = SIZE(rows)
ALLOCATE (add_rows(nblks_added))
add_rows(:) = rows(:)
ALLOCATE (add_cols(nblks_added))
add_cols(:) = columns(:)
IF (PRESENT(blk_pointers)) THEN
ALLOCATE (add_blkp(nblks_added))
add_blkp(:) = blk_pointers(:)
CALL dbcsr_sort_indices(nblks_added, add_rows, add_cols, &
blk_p=add_blkp)
ELSE
CALL dbcsr_sort_indices(nblks_added, add_rows, add_cols)
END IF
nblks_old = dbcsr_get_num_blocks(matrix)
nblkrows = dbcsr_nblkrows_total(matrix)
IF (SIZE(rows) .GT. 0 .AND. nblkrows .LE. 0) &
DBCSR_ABORT("Can not add blocks to matrix with no rows.")
! Adjust the index.
! Get the old row indices
ALLOCATE (old_row_i(nblks_old))
CALL dbcsr_expand_row_index(matrix%row_p, old_row_i, &
nblkrows, nblks_old)
! Calculate new block pointers. Possibly high estimates.
new_data_sizes = 0
blk_p = data_size_old + 1 ! New blocks start at the end of the old
ALLOCATE (added_blk_info(3, nblks_added))
ALLOCATE (added_sizes(nblks_added))
DO blk = 1, nblks_added
IF (PRESENT(blk_pointers)) THEN
blk_p = add_blkp(blk)
END IF
added_blk_info(1:3, blk) = (/add_rows(blk), add_cols(blk), blk_p/)
nze = dbcsr_blk_row_size(matrix, add_rows(blk)) &
*dbcsr_blk_column_size(matrix, add_cols(blk))
added_sizes(blk) = nze
blk_p = blk_p + nze
END DO
DEALLOCATE (add_rows)
DEALLOCATE (add_cols)
IF (PRESENT(blk_pointers)) DEALLOCATE (add_blkp)
!
nblks_new = nblks_old + nblks_added ! Possibly high estimate
ALLOCATE (new_row_i(nblks_new))
ALLOCATE (new_col_i(nblks_new))
ALLOCATE (new_blk_p(nblks_new))
! Merge the two indices
IF (PRESENT(blk_pointers)) THEN
CALL merge_index_arrays(new_row_i, new_col_i, new_blk_p, nblks_new, &
old_row_i, matrix%col_i, matrix%blk_p, nblks_old, &
added_blk_info, nblks_added, added_nblks=nblks_actual_added)
data_size_new = 0
ELSE
CALL merge_index_arrays(new_row_i, new_col_i, new_blk_p, nblks_new, &
old_row_i, matrix%col_i, matrix%blk_p, nblks_old, &
added_blk_info, nblks_added, added_nblks=nblks_actual_added, &
added_sizes=added_sizes, added_size_offset=data_size_old + 1, &
added_size=data_size_new)
END IF
nblks_new = nblks_actual_added + nblks_old
! Free some memory
DEALLOCATE (added_blk_info)
DEALLOCATE (added_sizes)
DEALLOCATE (old_row_i)
! We can skip this if no block was actually added.
IF (nblks_actual_added .GT. 0) THEN
! Write the new index
matrix%nblks = nblks_new
matrix%nze = matrix%nze + data_size_new
matrix%index(dbcsr_slot_nblks) = matrix%nblks
matrix%index(dbcsr_slot_nze) = matrix%index(dbcsr_slot_nze)
CALL dbcsr_clearfrom_index_array(matrix, dbcsr_slot_col_i)
CALL dbcsr_clearfrom_index_array(matrix, dbcsr_slot_blk_p)
CALL dbcsr_addto_index_array(matrix, dbcsr_slot_col_i, &
new_col_i(1:nblks_new), &
extra=nblks_new)
CALL dbcsr_addto_index_array(matrix, dbcsr_slot_blk_p, &
new_blk_p(1:nblks_new))
CALL dbcsr_make_dbcsr_index(matrix%row_p, new_row_i(1:nblks_new), &
nblkrows, nblks_new)
IF (.NOT. PRESENT(blk_pointers)) THEN
! Resize data area to fit the new blocks.
CALL dbcsr_data_ensure_size(matrix%data_area, &
data_size=matrix%nze)
! Zero the new data blocks.
CALL dbcsr_data_clear(matrix%data_area, &
lb=data_size_old + 1, ub=matrix%nze)
END IF
END IF
CALL timestop(handle)
END SUBROUTINE dbcsr_reserve_blocks