(git:f824184)
Loading...
Searching...
No Matches
dbt_reshape_ops.F
Go to the documentation of this file.
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 Routines to reshape / redistribute tensors
10!> \author Patrick Seewald
11! **************************************************************************************************
13
14
15 USE omp_lib, ONLY: omp_get_num_threads, omp_get_thread_num
16 USE dbt_block, ONLY: &
19 USE dbt_types, ONLY: dbt_blk_sizes, &
20 dbt_type, &
25 USE kinds, ONLY: dp
28 USE util, ONLY: get_limit
29
30#include "../base/base_uses.f90"
31
32 IMPLICIT NONE
33 PRIVATE
34 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dbt_reshape_ops'
35
37
38 ! Non-owning references allow scalar copies and image gathers to share one transport.
39 TYPE tensor_source_type
40 TYPE(dbt_type), POINTER :: tensor => null()
41 INTEGER :: stack_offset = 0
42 END TYPE tensor_source_type
43
45 MODULE PROCEDURE dbt_reshape, dbt_gather
46 END INTERFACE dbt_copy_indexed
47
48 ! Communication buffers persist across calls such that pages are faulted in once rather than per
49 ! call; per block, the index holds the data offset (relative to the peer's data) and nd-index.
50 TYPE(matrix_buffer_type), SAVE :: buffer_send, buffer_recv
51
52CONTAINS
53
54! **************************************************************************************************
55!> \brief copy data (involves reshape)
56!> tensor_out = tensor_out + tensor_in move_data memory optimization:
57!> transfer data from tensor_in to tensor_out s.t. tensor_in is empty on return
58!> \param bounds crop tensor data while copying (as dbt_crop): start and end index per dimension
59!> \param tensor_in source tensor on the parent communicator
60!> \param tensor_out destination tensor; smaller communicators denote equal, contiguous subgroups
61!> \param summation add to destination instead of replacing it
62!> \param move_data clear the source after copying
63!> \param index_map optional source-to-destination block indices; zero skips a block
64!> \param group_mask optional subgroup selection by source block index
65!> \param group_dim source dimension indexing group_mask
66!> \author Ole Schuett
67! **************************************************************************************************
68 SUBROUTINE dbt_reshape(tensor_in, tensor_out, summation, move_data, bounds, index_map, group_mask, group_dim)
69
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(:, :)
75
76 TYPE(tensor_source_type) :: sources(1)
77
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)
81 END SUBROUTINE dbt_reshape
82
83! **************************************************************************************************
84!> \brief Gather whole blocks from selected tensors, optionally relabelling each block index.
85!> Zero images or mapped indices are skipped. Blocks retain their sizes. Each image occupies
86!> one source tensor extent along stack_dim, including skipped images. Retained index maps
87!> must be injective; the stack-dimension map stays within one source extent.
88!> \param tensor_in source tensors on one communicator, with identical shapes
89!> \param tensor_out destination tensor
90!> \param images source tensor indices; zero skips an image
91!> \param index_map source-to-destination block indices, padded to the largest source dimension
92!> \param stack_dim dimension along which images are stacked
93! **************************************************************************************************
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
98
99 INTEGER :: i, nblks(SIZE(index_map, 2))
100 TYPE(tensor_source_type) :: sources(SIZE(images))
101
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))
105 CALL dbt_get_info(tensor_in(1), nblks_total=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)
113 END DO
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
117
118! **************************************************************************************************
119!> \brief Shared block transport for copies, indexed gathers and subgroup replication.
120!> Subgroups have identical layouts and contiguous rank ranges in comm. group_mask selects
121!> replicas by a source block index; with no mask, every subgroup receives the block.
122! **************************************************************************************************
123 SUBROUTINE dbt_reshape_sources(sources, tensor_out, comm, summation, move_data, bounds, &
124 index_map, stack_dim, group_mask, group_dim)
125
126 TYPE(tensor_source_type), INTENT(IN) :: sources(:)
127 TYPE(dbt_type), INTENT(INOUT) :: tensor_out
128 CLASS(mp_comm_type), INTENT(IN) :: comm
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(:, :)
133
134 CHARACTER(LEN=*), PARAMETER :: routineN = 'dbt_reshape'
135
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
140 TYPE(dbt_iterator_type) :: iter
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))
147
148 INTEGER, ALLOCATABLE :: counts_send(:, :), counts_recv(:, :)
149 INTEGER, ALLOCATABLE :: nblks_send_mythread(:), ndata_send_mythread(:)
150
151 CALL timeset(routinen, handle)
152
153 IF (PRESENT(summation)) THEN
154 summation_prv = summation
155 ELSE
156 summation_prv = .false.
157 END IF
158
159 IF (PRESENT(move_data)) THEN
160 move_prv = move_data
161 ELSE
162 move_prv = .false.
163 END IF
164
165 do_bounds = PRESENT(bounds)
166 IF (do_bounds) THEN
167 bounds_prv(:, :) = bounds(:, :)
168 ELSE
169 bounds_prv(:, :) = 0
170 END IF
171
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))
181 END IF
182 IF (PRESENT(index_map)) THEN
183 cpassert(SIZE(index_map, 2) == SIZE(ind_nd))
184 cpassert(all(index_map >= 0))
185 END IF
186
187 IF (.NOT. summation_prv) THEN
188 CALL timeset(routinen//"_clear", handle2)
189 CALL dbt_clear(tensor_out)
190 CALL timestop(handle2)
191 END IF
192
193 numnodes = comm%num_pe
194 nindex = ndims_tensor(tensor_out) + 1
195 ! separate timers for blocks that need a reshape (index order differs from matrix layout)
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))
202 END IF
203 IF (PRESENT(group_mask)) THEN
204 cpassert(SIZE(group_mask, 2) == source_shape(group_dim))
205 END IF
206 IF (permuted(sources(isource)%tensor)) name_pack = routinen//"_pack_perm"
207 END DO
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)
211
212!$OMP PARALLEL DEFAULT(NONE) &
213!$OMP SHARED(sources,tensor_out,summation,comm,numnodes,nindex,name_pack,name_unpack) &
214!$OMP SHARED(index_map,stack_dim,group_mask,group_dim,group_size,ngroups) &
215!$OMP SHARED(do_bounds,bounds_prv,buffer_send,buffer_recv) &
216!$OMP SHARED(counts_send,counts_recv) &
217!$OMP PRIVATE(nblks_send_mythread,ndata_send_mythread) &
218!$OMP PRIVATE(iter,ind_nd,blk_size,blk_offset,found,overlap,inside,iproc,handle2) &
219!$OMP PRIVATE(block_range,offset,ndata,iblk,tensor_in,isource,d,dest,dest_size,igroup,peer,first_offset)
220 CALL timeset(routinen//"_count", handle2)
221 ALLOCATE (nblks_send_mythread(0:numnodes - 1), ndata_send_mythread(0:numnodes - 1), source=0)
222
223 DO isource = 1, SIZE(sources)
224 tensor_in => sources(isource)%tensor
225 IF (.NOT. ASSOCIATED(tensor_in)) cycle
226 CALL dbt_iterator_start(iter, tensor_in)
227 DO WHILE (dbt_iterator_blocks_left(iter))
228 CALL dbt_iterator_next_block(iter, ind_nd, blk_size=blk_size, blk_offset=blk_offset)
229 IF (do_bounds) THEN
230 CALL block_bounds(bounds_prv, blk_offset, blk_size, overlap, inside)
231 IF (.NOT. overlap) cycle
232 END IF
233 dest = ind_nd
234 IF (PRESENT(index_map)) THEN
235 DO d = 1, SIZE(dest)
236 dest(d) = index_map(ind_nd(d), d)
237 END DO
238 IF (any(dest == 0)) cycle
239 END IF
240 IF (PRESENT(stack_dim)) dest(stack_dim) = dest(stack_dim) + sources(isource)%stack_offset
241 IF (PRESENT(index_map)) THEN
242 CALL dbt_blk_sizes(tensor_out, dest, dest_size)
243 cpassert(all(dest_size == blk_size))
244 END IF
245 CALL dbt_get_stored_coordinates(tensor_out, dest, iproc)
246 DO igroup = 1, ngroups
247 IF (PRESENT(group_mask)) THEN
248 IF (.NOT. group_mask(igroup, ind_nd(group_dim))) cycle
249 END IF
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)
253 END DO
254 END DO
255 CALL dbt_iterator_stop(iter)
256 END DO
257!$OMP CRITICAL(omp_dbt_reshape)
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, :) ! current totals indicate slot for this thread
261 nblks_send_mythread(:) = counts_send(2, :)
262!$OMP END CRITICAL(omp_dbt_reshape)
263!$OMP BARRIER
264
265!$OMP MASTER
266 CALL comm%alltoall(counts_send, counts_recv, 2)
267!$OMP END MASTER
268!$OMP BARRIER
269 CALL timestop(handle2)
270
271 CALL timeset(trim(name_pack), handle2)
272!$OMP MASTER
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)
275!$OMP END MASTER
276!$OMP BARRIER
277
278 DO isource = 1, SIZE(sources)
279 tensor_in => sources(isource)%tensor
280 IF (.NOT. ASSOCIATED(tensor_in)) cycle
281 CALL dbt_iterator_start(iter, tensor_in)
282 DO WHILE (dbt_iterator_blocks_left(iter))
283 CALL dbt_iterator_next_block(iter, ind_nd, blk_size=blk_size, blk_offset=blk_offset)
284 inside = .true.
285 IF (do_bounds) THEN
286 CALL block_bounds(bounds_prv, blk_offset, blk_size, overlap, inside)
287 IF (.NOT. overlap) cycle
288 END IF
289 dest = ind_nd
290 IF (PRESENT(index_map)) THEN
291 DO d = 1, SIZE(dest)
292 dest(d) = index_map(ind_nd(d), d)
293 END DO
294 IF (any(dest == 0)) cycle
295 END IF
296 IF (PRESENT(stack_dim)) dest(stack_dim) = dest(stack_dim) + sources(isource)%stack_offset
297 CALL dbt_get_stored_coordinates(tensor_out, dest, iproc)
298 first_offset = -1
299 DO igroup = 1, ngroups
300 IF (PRESENT(group_mask)) THEN
301 IF (.NOT. group_mask(igroup, ind_nd(group_dim))) cycle
302 END IF
303 peer = (igroup - 1)*group_size + iproc
304 ! Insert block data, reading the source only once for all replicas.
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)
310 cpassert(found)
311 IF (.NOT. inside) THEN
312 CALL block_crop(bounds_prv, blk_offset, blk_size, buffer_send%msg(offset + 1:offset + ndata))
313 END IF
314 first_offset = offset
315 ELSE
316 buffer_send%msg(offset + 1:offset + ndata) = buffer_send%msg(first_offset + 1:first_offset + ndata)
317 END IF
318 ! Payload offsets in the metadata are relative to the peer's segment.
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)
323 END DO
324 END DO
325 CALL dbt_iterator_stop(iter)
326 END DO
327 DEALLOCATE (nblks_send_mythread, ndata_send_mythread)
328!$OMP BARRIER
329 CALL timestop(handle2)
330
331!$OMP MASTER
332 IF (numnodes > 1) THEN
333 CALL exchange_matrix_buffers(comm, buffer_recv, buffer_send)
334 ELSE
335 ! A single rank receives what it sends: the buffers trade places.
336 CALL swap_buffers(buffer_send, buffer_recv)
337 END IF
338!$OMP END MASTER
339!$OMP BARRIER
340
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))))
344!$OMP BARRIER
345 CALL timestop(handle2)
346
347 CALL timeset(trim(name_unpack), handle2)
348 DO iproc = 0, numnodes - 1
349!$OMP DO
350 DO iblk = buffer_recv%indx_offset(iproc) + 1, buffer_recv%indx_offset(iproc + 1)
351 ind_nd(:) = buffer_recv%indx(2:, iblk)
352 CALL dbt_blk_sizes(tensor_out, ind_nd, blk_size)
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), &
356 summation=summation)
357 END DO
358!$OMP END DO
359 END DO
360 CALL timestop(handle2)
361!$OMP END PARALLEL
362
363 DEALLOCATE (counts_send, counts_recv)
364
365 IF (move_prv) THEN
366 CALL timeset(routinen//"_clear", handle2)
367 DO isource = 1, SIZE(sources)
368 IF (ASSOCIATED(sources(isource)%tensor)) CALL dbt_clear(sources(isource)%tensor)
369 END DO
370 CALL timestop(handle2)
371 END IF
372
373 CALL timestop(handle)
374 END SUBROUTINE dbt_reshape_sources
375
376! **************************************************************************************************
377!> \brief Release the communication buffers that persist across calls of dbt_reshape.
378!> \author Hans Pabst
379! **************************************************************************************************
381 CALL release_buffer(buffer_send)
382 CALL release_buffer(buffer_recv)
383 END SUBROUTINE dbt_reshape_release
384
385! **************************************************************************************************
386!> \brief Whether the tensor's index order differs from its matrix layout (blocks need a reshape).
387!> \author Hans Pabst
388! **************************************************************************************************
389 FUNCTION permuted(tensor)
390 TYPE(dbt_type), INTENT(IN) :: tensor
391 LOGICAL :: permuted
392
393 INTEGER :: i
394
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))])
397 END associate
398 END FUNCTION permuted
399
400! **************************************************************************************************
401!> \brief Whether a block (element offset and size per dimension) overlaps the bounds, and whether
402!> it lies entirely inside them.
403!> \author Hans Pabst
404! **************************************************************************************************
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
409
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
413
414! **************************************************************************************************
415!> \brief Zero the elements of a block (column-major data) outside the bounds (as dbt_crop).
416!> \author Hans Pabst
417! **************************************************************************************************
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
422
423 INTEGER :: d, i
424 INTEGER, DIMENSION(SIZE(blk_size)) :: hi, idx, lo
425
426 lo(:) = max(bounds(1, :) - blk_offset + 1, 1)
427 hi(:) = min(bounds(2, :) - blk_offset + 1, blk_size)
428 idx(:) = 1
429 DO i = 1, SIZE(data)
430 IF (any(idx < lo .OR. hi < idx)) data(i) = 0.0_dp
431 DO d = 1, SIZE(idx) ! next column-major index
432 idx(d) = idx(d) + 1
433 IF (idx(d) <= blk_size(d)) EXIT
434 idx(d) = 1
435 END DO
436 END DO
437 END SUBROUTINE block_crop
438
439! **************************************************************************************************
440!> \brief Lay out a persistent buffer for the given per-peer counts (as allocate_matrix_buffers),
441!> growing its arrays only when they are too small.
442!> \author Hans Pabst
443! **************************************************************************************************
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
448
449 INTEGER :: iproc, nprocs
450
451 nprocs = SIZE(ndata)
452 IF (ALLOCATED(buffer%msg_offset)) THEN
453 IF (SIZE(buffer%msg_offset) /= nprocs + 1) DEALLOCATE (buffer%msg_offset, buffer%indx_offset)
454 END IF
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)
461 END DO
462
463 IF (ALLOCATED(buffer%msg)) THEN
464 IF (SIZE(buffer%msg) < buffer%msg_offset(nprocs)) DEALLOCATE (buffer%msg)
465 END IF
466 IF (.NOT. ALLOCATED(buffer%msg)) THEN
467 ALLOCATE (buffer%msg(max(buffer%msg_offset(nprocs) + buffer%msg_offset(nprocs)/4, 1)))
468 END IF
469 ! records are exchanged as whole columns: the leading dimension must match
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)
473 END IF
474 END IF
475 IF (.NOT. ALLOCATED(buffer%indx)) THEN
476 ALLOCATE (buffer%indx(nindex, max(buffer%indx_offset(nprocs) + buffer%indx_offset(nprocs)/4, 1)))
477 END IF
478 END SUBROUTINE grow_buffer
479
480! **************************************************************************************************
481!> \brief Exchange the contents of two buffers without copying.
482!> \author Hans Pabst
483! **************************************************************************************************
484 SUBROUTINE swap_buffers(a, b)
485 TYPE(matrix_buffer_type), INTENT(INOUT) :: a, b
486
487 TYPE(matrix_buffer_type) :: t
488
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
502
503! **************************************************************************************************
504!> \brief Deallocate the arrays of a buffer.
505!> \author Hans Pabst
506! **************************************************************************************************
507 SUBROUTINE release_buffer(buffer)
508 TYPE(matrix_buffer_type), INTENT(INOUT) :: buffer
509
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
515
516END MODULE dbt_reshape_ops
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
struct tensor_ tensor
Methods to operate on n-dimensional tensor blocks.
Definition dbt_block.F:12
logical function, public dbt_iterator_blocks_left(iterator)
Generalization of block_iterator_blocks_left for tensors.
Definition dbt_block.F:202
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...
Definition dbt_block.F:567
subroutine, public dbt_iterator_stop(iterator)
Generalization of block_iterator_stop for tensors.
Definition dbt_block.F:139
subroutine, public dbt_iterator_start(iterator, tensor)
Generalization of block_iterator_start for tensors.
Definition dbt_block.F:126
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...
Definition dbt_block.F:593
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_...
Definition dbt_block.F:166
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.
Definition dbt_types.F:12
subroutine, public dbt_blk_sizes(tensor, ind, blk_size)
Size of tensor block.
Definition dbt_types.F:1468
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.
Definition dbt_types.F:1645
pure integer function, public ndims_tensor(tensor)
tensor rank
Definition dbt_types.F:1216
subroutine, public dbt_clear(tensor)
Clear tensor (s.t. it does not contain any blocks).
Definition dbt_types.F:1768
subroutine, public dbt_get_stored_coordinates(tensor, ind_nd, processor)
Generalization of block_get_stored_coordinates for tensors.
Definition dbt_types.F:1499
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
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.
Definition util.F:14
pure integer function, dimension(2), public get_limit(m, n, me)
divide m entries into n parts, return size of part me
Definition util.F:333