15 USE omp_lib,
ONLY: omp_get_num_threads, omp_get_thread_num
30#include "../base/base_uses.f90"
34 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'dbt_reshape_ops'
39 TYPE tensor_source_type
40 TYPE(dbt_type),
POINTER :: tensor => null()
41 INTEGER :: stack_offset = 0
42 END TYPE tensor_source_type
50 TYPE(matrix_buffer_type),
SAVE :: buffer_send, buffer_recv
68 SUBROUTINE dbt_reshape(tensor_in, tensor_out, summation, move_data, bounds, index_map, group_mask, group_dim)
70 TYPE(
dbt_type),
TARGET,
INTENT(INOUT) :: tensor_in
71 TYPE(
dbt_type),
INTENT(INOUT) :: tensor_out
72 LOGICAL,
INTENT(IN),
OPTIONAL :: summation, move_data
73 INTEGER,
INTENT(IN),
OPTIONAL :: bounds(:, :), index_map(:, :), group_dim
74 LOGICAL,
INTENT(IN),
OPTIONAL :: group_mask(:, :)
76 TYPE(tensor_source_type) :: sources(1)
78 sources(1)%tensor => tensor_in
79 CALL dbt_reshape_sources(sources, tensor_out, tensor_in%pgrid%mp_comm_2d, summation, move_data, bounds, &
80 index_map=index_map, group_mask=group_mask, group_dim=group_dim)
94 SUBROUTINE dbt_gather(tensor_in, tensor_out, images, index_map, stack_dim)
95 TYPE(
dbt_type),
TARGET,
INTENT(INOUT) :: tensor_in(:)
96 TYPE(
dbt_type),
INTENT(INOUT) :: tensor_out
97 INTEGER,
INTENT(IN) :: images(:), index_map(:, :), stack_dim
99 INTEGER :: i, nblks(SIZE(index_map, 2))
100 TYPE(tensor_source_type) :: sources(SIZE(images))
102 cpassert(
SIZE(tensor_in) > 0)
103 cpassert(
SIZE(index_map, 2) ==
ndims_tensor(tensor_out))
104 cpassert(stack_dim >= 1 .AND. stack_dim <=
SIZE(nblks))
106 cpassert(
SIZE(index_map, 1) >= maxval(nblks))
107 cpassert(all(index_map(:nblks(stack_dim), stack_dim) <= nblks(stack_dim)))
108 DO i = 1,
SIZE(images)
109 cpassert(images(i) >= 0 .AND. images(i) <=
SIZE(tensor_in))
110 IF (images(i) == 0) cycle
111 sources(i)%tensor => tensor_in(images(i))
112 sources(i)%stack_offset = (i - 1)*nblks(stack_dim)
114 CALL dbt_reshape_sources(sources, tensor_out, tensor_in(1)%pgrid%mp_comm_2d, &
115 index_map=index_map, stack_dim=stack_dim)
116 END SUBROUTINE dbt_gather
123 SUBROUTINE dbt_reshape_sources(sources, tensor_out, comm, summation, move_data, bounds, &
124 index_map, stack_dim, group_mask, group_dim)
126 TYPE(tensor_source_type),
INTENT(IN) :: sources(:)
127 TYPE(
dbt_type),
INTENT(INOUT) :: tensor_out
129 LOGICAL,
INTENT(IN),
OPTIONAL :: summation
130 LOGICAL,
INTENT(IN),
OPTIONAL :: move_data
131 INTEGER,
INTENT(IN),
OPTIONAL :: bounds(:, :), index_map(:, :), stack_dim, group_dim
132 LOGICAL,
INTENT(IN),
OPTIONAL :: group_mask(:, :)
134 CHARACTER(LEN=*),
PARAMETER :: routineN =
'dbt_reshape'
136 INTEGER :: iproc, numnodes, nindex, &
137 handle, handle2, iblk, offset, ndata, &
138 isource, d, igroup, ngroups, group_size, peer, first_offset
139 INTEGER,
DIMENSION(2) :: block_range
141 CHARACTER(LEN=32) :: name_pack, name_unpack
142 INTEGER,
DIMENSION(ndims_tensor(tensor_out)) :: blk_size, blk_offset, ind_nd, dest, dest_size
143 INTEGER,
DIMENSION(2, ndims_tensor(tensor_out)) :: bounds_prv
144 LOGICAL :: found, summation_prv, move_prv, do_bounds, overlap, inside
145 TYPE(
dbt_type),
POINTER :: tensor_in
146 INTEGER :: source_shape(ndims_tensor(tensor_out))
148 INTEGER,
ALLOCATABLE :: counts_send(:, :), counts_recv(:, :)
149 INTEGER,
ALLOCATABLE :: nblks_send_mythread(:), ndata_send_mythread(:)
151 CALL timeset(routinen, handle)
153 IF (
PRESENT(summation))
THEN
154 summation_prv = summation
156 summation_prv = .false.
159 IF (
PRESENT(move_data))
THEN
165 do_bounds =
PRESENT(bounds)
167 bounds_prv(:, :) = bounds(:, :)
172 cpassert(tensor_out%valid)
173 group_size = tensor_out%pgrid%mp_comm_2d%num_pe
174 cpassert(mod(comm%num_pe, group_size) == 0)
175 cpassert(mod(comm%mepos, group_size) == tensor_out%pgrid%mp_comm_2d%mepos)
176 ngroups = comm%num_pe/group_size
177 cpassert(
PRESENT(group_mask) .EQV.
PRESENT(group_dim))
178 IF (
PRESENT(group_mask))
THEN
179 cpassert(
SIZE(group_mask, 1) == ngroups)
180 cpassert(group_dim >= 1 .AND. group_dim <=
SIZE(ind_nd))
182 IF (
PRESENT(index_map))
THEN
183 cpassert(
SIZE(index_map, 2) ==
SIZE(ind_nd))
184 cpassert(all(index_map >= 0))
187 IF (.NOT. summation_prv)
THEN
188 CALL timeset(routinen//
"_clear", handle2)
190 CALL timestop(handle2)
193 numnodes = comm%num_pe
194 nindex = ndims_tensor(tensor_out) + 1
196 name_pack = routinen//
"_pack"
197 DO isource = 1,
SIZE(sources)
198 IF (.NOT.
ASSOCIATED(sources(isource)%tensor)) cycle
199 CALL dbt_get_info(sources(isource)%tensor, nblks_total=source_shape)
200 IF (
PRESENT(index_map))
THEN
201 cpassert(
SIZE(index_map, 1) >= maxval(source_shape))
203 IF (
PRESENT(group_mask))
THEN
204 cpassert(
SIZE(group_mask, 2) == source_shape(group_dim))
206 IF (permuted(sources(isource)%tensor)) name_pack = routinen//
"_pack_perm"
208 name_unpack = routinen//
"_unpack"
209 IF (permuted(tensor_out)) name_unpack = routinen//
"_unpack_perm"
210 ALLOCATE (counts_send(2, 0:numnodes - 1), counts_recv(2, 0:numnodes - 1), source=0)
220 CALL timeset(routinen//
"_count", handle2)
221 ALLOCATE (nblks_send_mythread(0:numnodes - 1), ndata_send_mythread(0:numnodes - 1), source=0)
223 DO isource = 1,
SIZE(sources)
224 tensor_in => sources(isource)%tensor
225 IF (.NOT.
ASSOCIATED(tensor_in)) cycle
230 CALL block_bounds(bounds_prv, blk_offset, blk_size, overlap, inside)
231 IF (.NOT. overlap) cycle
234 IF (
PRESENT(index_map))
THEN
236 dest(d) = index_map(ind_nd(d), d)
238 IF (any(dest == 0)) cycle
240 IF (
PRESENT(stack_dim)) dest(stack_dim) = dest(stack_dim) + sources(isource)%stack_offset
241 IF (
PRESENT(index_map))
THEN
243 cpassert(all(dest_size == blk_size))
246 DO igroup = 1, ngroups
247 IF (
PRESENT(group_mask))
THEN
248 IF (.NOT. group_mask(igroup, ind_nd(group_dim))) cycle
250 peer = (igroup - 1)*group_size + iproc
251 nblks_send_mythread(peer) = nblks_send_mythread(peer) + 1
252 ndata_send_mythread(peer) = ndata_send_mythread(peer) + product(blk_size)
258 counts_send(1, :) = counts_send(1, :) + ndata_send_mythread(:)
259 counts_send(2, :) = counts_send(2, :) + nblks_send_mythread(:)
260 ndata_send_mythread(:) = counts_send(1, :)
261 nblks_send_mythread(:) = counts_send(2, :)
266 CALL comm%alltoall(counts_send, counts_recv, 2)
269 CALL timestop(handle2)
271 CALL timeset(trim(name_pack), handle2)
273 CALL grow_buffer(buffer_send, counts_send(1, :), counts_send(2, :), nindex)
274 CALL grow_buffer(buffer_recv, counts_recv(1, :), counts_recv(2, :), nindex)
278 DO isource = 1,
SIZE(sources)
279 tensor_in => sources(isource)%tensor
280 IF (.NOT.
ASSOCIATED(tensor_in)) cycle
286 CALL block_bounds(bounds_prv, blk_offset, blk_size, overlap, inside)
287 IF (.NOT. overlap) cycle
290 IF (
PRESENT(index_map))
THEN
292 dest(d) = index_map(ind_nd(d), d)
294 IF (any(dest == 0)) cycle
296 IF (
PRESENT(stack_dim)) dest(stack_dim) = dest(stack_dim) + sources(isource)%stack_offset
299 DO igroup = 1, ngroups
300 IF (
PRESENT(group_mask))
THEN
301 IF (.NOT. group_mask(igroup, ind_nd(group_dim))) cycle
303 peer = (igroup - 1)*group_size + iproc
305 ndata = product(blk_size)
306 ndata_send_mythread(peer) = ndata_send_mythread(peer) - ndata
307 offset = buffer_send%msg_offset(peer) + ndata_send_mythread(peer)
308 IF (first_offset < 0)
THEN
309 CALL dbt_get_block_data(tensor_in, ind_nd, blk_size, buffer_send%msg(offset + 1:offset + ndata), found)
311 IF (.NOT. inside)
THEN
312 CALL block_crop(bounds_prv, blk_offset, blk_size, buffer_send%msg(offset + 1:offset + ndata))
314 first_offset = offset
316 buffer_send%msg(offset + 1:offset + ndata) = buffer_send%msg(first_offset + 1:first_offset + ndata)
319 nblks_send_mythread(peer) = nblks_send_mythread(peer) - 1
320 iblk = buffer_send%indx_offset(peer) + nblks_send_mythread(peer) + 1
321 buffer_send%indx(2:, iblk) = dest(:)
322 buffer_send%indx(1, iblk) = ndata_send_mythread(peer)
327 DEALLOCATE (nblks_send_mythread, ndata_send_mythread)
329 CALL timestop(handle2)
332 IF (numnodes > 1)
THEN
336 CALL swap_buffers(buffer_send, buffer_recv)
341 CALL timeset(routinen//
"_reserve", handle2)
342 block_range =
get_limit(buffer_recv%indx_offset(numnodes), omp_get_num_threads(), omp_get_thread_num())
343 CALL dbt_reserve_blocks(tensor_out, transpose(buffer_recv%indx(2:, block_range(1):block_range(2))))
345 CALL timestop(handle2)
347 CALL timeset(trim(name_unpack), handle2)
348 DO iproc = 0, numnodes - 1
350 DO iblk = buffer_recv%indx_offset(iproc) + 1, buffer_recv%indx_offset(iproc + 1)
351 ind_nd(:) = buffer_recv%indx(2:, iblk)
353 offset = buffer_recv%msg_offset(iproc) + buffer_recv%indx(1, iblk)
354 ndata = product(blk_size)
355 CALL dbt_put_block_data(tensor_out, ind_nd, blk_size, buffer_recv%msg(offset + 1:offset + ndata), &
360 CALL timestop(handle2)
363 DEALLOCATE (counts_send, counts_recv)
366 CALL timeset(routinen//
"_clear", handle2)
367 DO isource = 1,
SIZE(sources)
368 IF (
ASSOCIATED(sources(isource)%tensor))
CALL dbt_clear(sources(isource)%tensor)
370 CALL timestop(handle2)
373 CALL timestop(handle)
374 END SUBROUTINE dbt_reshape_sources
381 CALL release_buffer(buffer_send)
382 CALL release_buffer(buffer_recv)
389 FUNCTION permuted(tensor)
395 associate(map1_2d =>
tensor%nd_index_blk%map1_2d, map2_2d =>
tensor%nd_index_blk%map2_2d)
396 permuted = .NOT. all([map1_2d, map2_2d] == [(i, i=1,
SIZE(map1_2d) +
SIZE(map2_2d))])
398 END FUNCTION permuted
405 PURE SUBROUTINE block_bounds(bounds, blk_offset, blk_size, overlap, inside)
406 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: bounds
407 INTEGER,
DIMENSION(:),
INTENT(IN) :: blk_offset, blk_size
408 LOGICAL,
INTENT(OUT) :: overlap, inside
410 overlap = all(blk_offset <= bounds(2, :) .AND. bounds(1, :) <= blk_offset + blk_size - 1)
411 inside = all(bounds(1, :) <= blk_offset .AND. blk_offset + blk_size - 1 <= bounds(2, :))
412 END SUBROUTINE block_bounds
418 PURE SUBROUTINE block_crop(bounds, blk_offset, blk_size, data)
419 INTEGER,
DIMENSION(:, :),
INTENT(IN) :: bounds
420 INTEGER,
DIMENSION(:),
INTENT(IN) :: blk_offset, blk_size
421 REAL(dp),
DIMENSION(:),
INTENT(INOUT) :: data
424 INTEGER,
DIMENSION(SIZE(blk_size)) :: hi,
idx, lo
426 lo(:) = max(bounds(1, :) - blk_offset + 1, 1)
427 hi(:) = min(bounds(2, :) - blk_offset + 1, blk_size)
430 IF (any(
idx < lo .OR. hi <
idx))
data(i) = 0.0_dp
433 IF (
idx(d) <= blk_size(d))
EXIT
437 END SUBROUTINE block_crop
444 SUBROUTINE grow_buffer(buffer, ndata, nblks, nindex)
445 TYPE(matrix_buffer_type),
INTENT(INOUT) :: buffer
446 INTEGER,
DIMENSION(0:),
INTENT(IN) :: ndata, nblks
447 INTEGER,
INTENT(IN) :: nindex
449 INTEGER :: iproc, nprocs
452 IF (
ALLOCATED(buffer%msg_offset))
THEN
453 IF (
SIZE(buffer%msg_offset) /= nprocs + 1)
DEALLOCATE (buffer%msg_offset, buffer%indx_offset)
455 IF (.NOT.
ALLOCATED(buffer%msg_offset))
ALLOCATE (buffer%msg_offset(0:nprocs), buffer%indx_offset(0:nprocs))
456 buffer%msg_offset(0) = 0
457 buffer%indx_offset(0) = 0
458 DO iproc = 0, nprocs - 1
459 buffer%msg_offset(iproc + 1) = buffer%msg_offset(iproc) + ndata(iproc)
460 buffer%indx_offset(iproc + 1) = buffer%indx_offset(iproc) + nblks(iproc)
463 IF (
ALLOCATED(buffer%msg))
THEN
464 IF (
SIZE(buffer%msg) < buffer%msg_offset(nprocs))
DEALLOCATE (buffer%msg)
466 IF (.NOT.
ALLOCATED(buffer%msg))
THEN
467 ALLOCATE (buffer%msg(max(buffer%msg_offset(nprocs) + buffer%msg_offset(nprocs)/4, 1)))
470 IF (
ALLOCATED(buffer%indx))
THEN
471 IF (
SIZE(buffer%indx, 1) /= nindex .OR.
SIZE(buffer%indx, 2) < buffer%indx_offset(nprocs))
THEN
472 DEALLOCATE (buffer%indx)
475 IF (.NOT.
ALLOCATED(buffer%indx))
THEN
476 ALLOCATE (buffer%indx(nindex, max(buffer%indx_offset(nprocs) + buffer%indx_offset(nprocs)/4, 1)))
478 END SUBROUTINE grow_buffer
484 SUBROUTINE swap_buffers(a, b)
485 TYPE(matrix_buffer_type),
INTENT(INOUT) :: a, b
487 TYPE(matrix_buffer_type) :: t
489 CALL move_alloc(a%msg, t%msg)
490 CALL move_alloc(b%msg, a%msg)
491 CALL move_alloc(t%msg, b%msg)
492 CALL move_alloc(a%indx, t%indx)
493 CALL move_alloc(b%indx, a%indx)
494 CALL move_alloc(t%indx, b%indx)
495 CALL move_alloc(a%msg_offset, t%msg_offset)
496 CALL move_alloc(b%msg_offset, a%msg_offset)
497 CALL move_alloc(t%msg_offset, b%msg_offset)
498 CALL move_alloc(a%indx_offset, t%indx_offset)
499 CALL move_alloc(b%indx_offset, a%indx_offset)
500 CALL move_alloc(t%indx_offset, b%indx_offset)
501 END SUBROUTINE swap_buffers
507 SUBROUTINE release_buffer(buffer)
508 TYPE(matrix_buffer_type),
INTENT(INOUT) :: buffer
510 IF (
ALLOCATED(buffer%msg))
DEALLOCATE (buffer%msg)
511 IF (
ALLOCATED(buffer%indx))
DEALLOCATE (buffer%indx)
512 IF (
ALLOCATED(buffer%msg_offset))
DEALLOCATE (buffer%msg_offset)
513 IF (
ALLOCATED(buffer%indx_offset))
DEALLOCATE (buffer%indx_offset)
514 END SUBROUTINE release_buffer
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
Methods to operate on n-dimensional tensor blocks.
logical function, public dbt_iterator_blocks_left(iterator)
Generalization of block_iterator_blocks_left for tensors.
subroutine, public dbt_get_block_data(tensor, ind, sizes, data, found)
Get a block into the given contiguous data (arbitrary tensor rank), without allocating any intermedia...
subroutine, public dbt_iterator_stop(iterator)
Generalization of block_iterator_stop for tensors.
subroutine, public dbt_iterator_start(iterator, tensor)
Generalization of block_iterator_start for tensors.
subroutine, public dbt_put_block_data(tensor, ind, sizes, data, summation)
Put a block from the given contiguous data (arbitrary tensor rank), without allocating any intermedia...
subroutine, public dbt_iterator_next_block(iterator, ind_nd, blk_size, blk_offset)
iterate over nd blocks of an nd rank tensor, index only (blocks must be retrieved by calling dbt_get_...
Routines to reshape / redistribute tensors.
subroutine, public dbt_reshape_release()
Release the communication buffers that persist across calls of dbt_reshape.
subroutine, public dbt_reshape(tensor_in, tensor_out, summation, move_data, bounds, index_map, group_mask, group_dim)
copy data (involves reshape) tensor_out = tensor_out + tensor_in move_data memory optimization: trans...
DBT tensor framework for block-sparse tensor contraction: Types and create/destroy routines.
subroutine, public dbt_blk_sizes(tensor, ind, blk_size)
Size of tensor block.
subroutine, public dbt_get_info(tensor, nblks_total, nfull_total, nblks_local, nfull_local, pdims, my_ploc, blks_local_1, blks_local_2, blks_local_3, blks_local_4, proc_dist_1, proc_dist_2, proc_dist_3, proc_dist_4, blk_size_1, blk_size_2, blk_size_3, blk_size_4, blk_offset_1, blk_offset_2, blk_offset_3, blk_offset_4, distribution, name)
As block_get_info but for tensors.
pure integer function, public ndims_tensor(tensor)
tensor rank
subroutine, public dbt_clear(tensor)
Clear tensor (s.t. it does not contain any blocks).
subroutine, public dbt_get_stored_coordinates(tensor, ind_nd, processor)
Generalization of block_get_stored_coordinates for tensors.
Defines the basic variable types.
integer, parameter, public dp
Exchange numerical matrix payloads and integer metadata between MPI ranks.
subroutine, public exchange_matrix_buffers(comm, buffer_rec, buffer_send, do_indx, do_msg)
Synchronously exchange flat matrix buffers with nonempty peers.
Interface to the message passing library MPI.
All kind of helpful little routines.
pure integer function, dimension(2), public get_limit(m, n, me)
divide m entries into n parts, return size of part me