Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
gpu_trans_map_amr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2024 Finnish Meteorological Institute and University of Helsinki
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "../grid.h"
24#include "../object_wrapper.h"
25#include "../memoryallocation.h"
26
28//#include "gpu_1d_ppm_nonuniform_conserving.hpp"
29
30#include "gpu_trans_map_amr.hpp"
31#include "cpu_trans_pencils.hpp"
32#include "../arch/gpu_base.hpp"
33
34#ifdef USE_WARPACCESSORS
35 #define USE_TRANS_WARPACCESSORS
36#endif
37
38// Skip remapping for this stencil, if no blocks exist
39__device__ inline bool check_skip_blocks(const Realf* __restrict__ const *pencilBlockData, const uint centerOffset) {
40 for (int index=-VLASOV_STENCIL_WIDTH; index<VLASOV_STENCIL_WIDTH+1; ++index) {
41 if (pencilBlockData[centerOffset + index] != NULL) {
42 return false;
43 }
44 }
45 return true;
46}
47
48/* Propagate a given velocity block in all spatial cells of a pencil by a time step dt using a PPM reconstruction.
49 Includes preparing intermediate buffers.
50 *
51 * @param dimension Cartesian direction of propagation
52 * @param dt Time step length
53 * @param pencilLengths pointer to buffer of lengths of all pencils to propagate
54 * @param pencilStarts pointer to buffer of indexes of first cells of pencils
55 * @param allBlocks pointer to list of all GIDs to propagate
56 * @param nAllBlocks how many blocks exist in total
57 * @param nPencils Number of total pencils (constant)
58 * @param sumOfLengths sum of all pencil lengths (constant)
59 * @param threshold sparsity threshold, used by slope limiters
60 * @param dev_allPencilsMeshes Pointer to buffer of pointers to velocity meshes
61 * @param dev_allPencilsContainers Pointer to buffer of pointers to BlockContainers
62 * @param pencilBlockData Pointer to buffer of pointers into cell block data, both written and read
63 * @param dev_blockDataOrdered Pointer to aligned buffer used as interim values
64 * @param pencilDZ Pointer into buffer of pencil cell sizes
65 * @param pencilRatios Pointer into buffer with pencil target ratios (due to AMR)
66 * @param pencilBlocksCount Pointer into buffer for storing how many non-empty blocks each pencil has for current GID
67 */
68
69// GPUTODO: The translation kernel may need splitting up into one read/prep kernel and another translate/write kernel,
70// so that pointers to each part can be declared const __restrict__ in turn. A quick attempt at this
71// was actually slower, and e.g. Realf** pencilBlockData could not be const __restrict__ anyway. Using
72// const_cast in some loops resulted in data corruption.
73
74//__launch_bounds__(maxThreadsPerBlock, minBlocksPerMultiprocessor, maxBlocksPerCluster)
75__global__ void __launch_bounds__(WID3) translation_kernel(
76 const uint dimension,
77 const Realf dt,
78 const uint* __restrict__ pencilLengths,
79 const uint* __restrict__ pencilStarts,
80 const vmesh::GlobalID* __restrict__ allBlocks, // List of all blocks
81 const uint nAllBlocks, // size of list of blocks which we won't exceed
82 const uint nPencils, // Number of total pencils (constant)
83 const uint sumOfLengths, // sum of all pencil lengths (constant)
84 const Realf threshold, // used by slope limiters
85 const vmesh::VelocityMesh* __restrict__ const *dev_allPencilsMeshes, // Pointers to velocity meshes
87 Realf** pencilBlockData, // pointers into cell block data, both written and read
88 Realf** dev_blockDataOrdered, // buffer of pointers to mapping input data
89 const Realf* __restrict__ pencilDZ,
90 const Realf* __restrict__ pencilRatios, // buffer holding target ratios
91 uint* pencilBlocksCount, // store how many non-empty blocks each pencil has for this GID
95 const uint numberOfBins
96 ) {
97 // This is launched with grid size (nGpuBlocks,nAllocations,1)
98 // where nGpuBlocks is the count of blocks which fit in the smallest temp buffer at once
99 // and nAllocations is the number of temp GPU buffers to use.
100 const uint startingBlockIndex = blockIdx.y*gridDim.x;
101 const uint blockIndexIncrement = gridDim.y*gridDim.x;
103
104 // This is launched with block size (WID,WID,WID)
105 const vmesh::LocalID ti = (threadIdx.z)*blockDim.x*blockDim.y + threadIdx.y*blockDim.x + threadIdx.x;
106
107 // Translation direction
109 switch (dimension) {
110 case 0:
111 vz_index = threadIdx.x;
112 break;
113 case 1:
114 vz_index = threadIdx.y;
115 break;
116 case 2:
117 vz_index = threadIdx.z;
118 break;
119 default:
120 printf(" Wrong dimension, abort\n");
121 break;
122 }
123
124 // offsets so this block of the kernel uses the correct part of temp arrays
125 const uint pencilBlockDataOffset = (blockIdx.x * sumOfLengths) + (blockIdx.y * sumOfLengths * gridDim.x);
126 const uint pencilOrderedSourceOffset = blockIdx.x * sumOfLengths * WID3;
127 const uint pencilBlocksCountOffset = (blockIdx.x * nPencils) + (blockIdx.y * nPencils * gridDim.x);
128 const vmesh::VelocityMesh* __restrict__ randovmesh = dev_allPencilsMeshes[0]; // just some vmesh
129 const Realf dvz = randovmesh->getCellSize()[dimension];
130 const Realf vz_min = randovmesh->getMeshMinLimits()[dimension];
131
132 // Acting on velocity block blockGID, now found from array
133 for (uint thisBlockIndex = startingBlockIndex + blockIdx.x; thisBlockIndex < nAllBlocks; thisBlockIndex += blockIndexIncrement) {
134
135 const uint blockGID = allBlocks[thisBlockIndex];
136 // First read data in
137 uint nBin = blockIdx.z;
138
139 for (uint pencilIndex = 0; pencilIndex < dev_binSize[nBin]; pencilIndex++) {
140 const uint pencili = dev_pencilsInBin[dev_binStart[nBin]+pencilIndex];
141 const uint lengthOfPencil = pencilLengths[pencili];
142 const uint start = pencilStarts[pencili];
143 // Get pointer to temprary buffer of VEC-ordered data for this kernel
144 Realf* thisPencilOrderedSource = pencilOrderedSource + pencilOrderedSourceOffset + start * WID3;
145 uint nonEmptyBlocks = 0;
146 // Go over pencil length, gather cellblock data into pencil source data
147 for (uint celli = 0; celli < lengthOfPencil; celli++) {
148 const vmesh::VelocityMesh* __restrict__ vmesh = dev_allPencilsMeshes[start + celli];
149 vmesh::VelocityBlockContainer* cellContainer = dev_allPencilsContainers[start + celli];
150 // Now using warp accessor.
151 #ifdef USE_TRANS_WARPACCESSORS
152 const vmesh::LocalID blockLID = vmesh->warpGetLocalID(blockGID,ti);
153 #else
154 const vmesh::LocalID blockLID = vmesh->getLocalID(blockGID);
155 #endif
156 // Store block data pointer for both loading of data and writing back to the cell
157 if (blockLID != vmesh->invalidLocalID()) {
158 #ifdef DEBUG_VLASIATOR
159 const vmesh::LocalID meshSize = vmesh->size();
160 const vmesh::LocalID VBCSize = cellContainer->size();
161 if ((blockLID>=meshSize) || (blockLID>=VBCSize)) {
162 if (ti==0) {
163 printf("Error in translation: trying to access LID %ul but sizes are vmesh %ul VBC %ul\n",blockLID,meshSize,VBCSize);
164 }
165 }
166 #endif
167 if (ti==0) {
168 pencilBlockData[pencilBlockDataOffset + start + celli] = cellContainer->getData(blockLID);
169 nonEmptyBlocks++;
170 }
171 // Valid block, store values in contiguous data
172 thisPencilOrderedSource[celli * WID3 + ti]
173 = (cellContainer->getData(blockLID))[ti];
174 } else {
175 if (ti==0) {
176 pencilBlockData[pencilBlockDataOffset + start + celli] = NULL;
177 }
178 // Non-existing block, push in zeroes
179 thisPencilOrderedSource[celli * WID3 + ti] = (Realf)(0.0);
180 }
182 } // End loop over this pencil
183 if (ti==0) {
184 pencilBlocksCount[pencilBlocksCountOffset + pencili] = nonEmptyBlocks;
185 }
187 } // end loop over pencils in this bin
188
190 // Now we reset target blocks
191 for (uint pencilIndex = 0; pencilIndex < dev_binSize[nBin]; pencilIndex++) {
192 const uint pencili = dev_pencilsInBin[dev_binStart[nBin]+pencilIndex];
193 const uint lengthOfPencil = pencilLengths[pencili];
194 const uint start = pencilStarts[pencili];
195 for (uint celli = 0; celli < lengthOfPencil; celli++) {
196 if (pencilRatios[start + celli] != 0) {
197 // Is a target cell, needs to be reset
198 if (pencilBlockData[pencilBlockDataOffset + start + celli]) {
199 (pencilBlockData[pencilBlockDataOffset + start + celli])[ti] = (Realf)(0.0);
200 }
201 }
202 } // end loop over this pencil
203 } // end loop over pencils in this bin
204
206
207 // Now we propagate the pencils and write data back to the block data containers
208 // Get velocity data from vmesh that we need later to calculate the translation
209
210 vmesh::LocalID blockIndicesD = 0;
211 if (dimension==0) {
212 randovmesh->getIndicesX(blockGID, blockIndicesD);
213 } else if (dimension==1) {
214 randovmesh->getIndicesY(blockGID, blockIndicesD);
215 } else if (dimension==2) {
216 randovmesh->getIndicesZ(blockGID, blockIndicesD);
217 }
218
219 // Assuming 1 neighbor in the target array because of the CFL condition
220 // In fact propagating to > 1 neighbor will give an error
221 // Also defined in the calling function for the allocation of targetValues
222 // const uint nTargetNeighborsPerPencil = 1;
223 for (uint pencilIndex = 0; pencilIndex < dev_binSize[nBin]; pencilIndex++) {
224 const uint pencili = dev_pencilsInBin[dev_binStart[nBin]+pencilIndex];
225 if (pencilBlocksCount[pencilBlocksCountOffset + pencili] == 0) {
226 continue;
227 }
228 const uint lengthOfPencil = pencilLengths[pencili];
229 const uint start = pencilStarts[pencili];
230 const Realf* __restrict__ thisPencilOrderedSource = pencilOrderedSource + pencilOrderedSourceOffset + start * WID3;
231
232 // Go over length of propagated cells
233 for (uint i = VLASOV_STENCIL_WIDTH; i < lengthOfPencil-VLASOV_STENCIL_WIDTH; i++){
234 // Get pointers to block data used for output.
235 Realf* block_data_m1 = pencilBlockData[pencilBlockDataOffset + start + i - 1];
236 Realf* block_data = pencilBlockData[pencilBlockDataOffset + start + i];
237 Realf* block_data_p1 = pencilBlockData[pencilBlockDataOffset + start + i + 1];
238
239 // Cells which shouldn't be written to (e.g. sysboundary cells) have a targetRatio of 0
240 // Also need to check if pointer is valid, because a cell can be missing an elsewhere propagated block
241 const Realf areaRatio_m1 = pencilRatios[start + i - 1];
242 const Realf areaRatio = pencilRatios[start + i];
243 const Realf areaRatio_p1 = pencilRatios[start + i + 1];
244
245 // (no longer loop over) planes (threadIdx.z) and vectors within planes (just 1 by construction)
246 const Realf cell_vz = (blockIndicesD * WID + vz_index + (Realf)(0.5)) * dvz + vz_min; //cell centered velocity
247 const Realf z_translation = cell_vz * dt / pencilDZ[start + i]; // how much it moved in time dt (reduced units)
248
249 // Determine direction of translation
250 // part of density goes here (cell index change along spatial direcion)
251 const bool positiveTranslationDirection = (z_translation > (Realf)(0.0));
252
253 // Calculate normalized coordinates in current cell.
254 // The coordinates (scaled units from 0 to 1) between which we will
255 // integrate to put mass in the target neighboring cell.
256 // Normalize the coordinates to the origin cell. Then we scale with the difference
257 // in volume between target and origin later when adding the integrated value.
258 Realf z_1,z_2;
259 z_1 = positiveTranslationDirection ? (Realf)(1.0) - z_translation : (Realf)(0.0);
260 z_2 = positiveTranslationDirection ? (Realf)(1.0) : - z_translation;
261
262 #ifdef DEBUG_VLASIATOR
263 if ( abs(z_1) > (Realf)(1.0) || abs(z_2) > (Realf)(1.0) ) {
264 assert( 0 && "Error in translation, CFL condition violated.");
265 }
266 #endif
267
268 // If no blocks exist for this mapping, skip forward.
270 // Compute polynomial coefficients
271 Realf a[3];
272 // Silly indexing into coefficient calculation necessary due to
273 // built-in assumptions of unsigned indexing.
274 compute_ppm_coeff_nonuniform(pencilDZ + start + i - VLASOV_STENCIL_WIDTH,
275 thisPencilOrderedSource + (i - VLASOV_STENCIL_WIDTH) * WID3,
276 h4, VLASOV_STENCIL_WIDTH, a, threshold, ti, WID3);
277 // Compute integral
278 const Realf ngbr_target_density =
279 z_2 * ( a[0] + z_2 * ( a[1] + z_2 * a[2] ) ) -
280 z_1 * ( a[0] + z_1 * ( a[1] + z_1 * a[2] ) );
281
282 // Store mapped density in two target cells
283 // in the current original cells we will put the rest of the original density
284 // Now because each GPU block handles all pencils for an unique GID, we shouldn't need atomic additions here.
285
286 // NOTE: not using atomic operations causes huge diffs (as if self contribution was neglected)! 11.01.2024 MB
287 if (areaRatio && block_data) {
288 const Realf selfContribution = (thisPencilOrderedSource[i * WID3 + ti] - ngbr_target_density) * areaRatio;
289 //atomicAdd(&block_data[ti],selfContribution);
290 block_data[ti] += selfContribution;
291 }
292 if (areaRatio_p1 && block_data_p1) {
293 const Realf p1Contribution = (positiveTranslationDirection ? ngbr_target_density
294 * pencilDZ[start + i] / pencilDZ[start + i + 1] : (Realf)(0.0)) * areaRatio_p1;
295 //atomicAdd(&block_data_p1[ti],p1Contribution);
296 block_data_p1[ti] += p1Contribution;
297 }
298 if (areaRatio_m1 && block_data_m1) {
299 const Realf m1Contribution = (!positiveTranslationDirection ? ngbr_target_density
300 * pencilDZ[start + i] / pencilDZ[start + i - 1] : (Realf)(0.0)) * areaRatio_m1;
301 //atomicAdd(&block_data_m1[ti],m1Contribution);
302 block_data_m1[ti] += m1Contribution;
303 }
304 } // Did not skip remapping
306 } // end loop over this pencil
307 } // end loop over pencils in this bin
309 } // end loop over blocks
310}
311
312/* Mini-kernel for looping over all available velocity meshes and gathering
313 * the union of all existing blocks.
314 *
315 * @param unionOfBlocksSet Hashmap, where keys are those blocks which are in the union of all blocks
316 * @param allVmeshPointer Buffer of pointers to velocitymeshes, used for gathering active blocks
317 * @param nAllCells count of cells to read from allVmeshPointer
318 */
319#ifdef USE_WARPACCESSORS
320__global__ void __launch_bounds__(GPUTHREADS*WARPSPERBLOCK) gather_union_of_blocks_kernel_WA(
321 Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID> *unionOfBlocksSet,
322 const vmesh::VelocityMesh* __restrict__ const *dev_vmeshes,
323 const uint nAllCells)
324{
325 const int ti = threadIdx.x; // [0,GPUTHREADS)
326 const int indexInBlock = threadIdx.y; // [0,WARPSPERBLOCK)
327 const uint cellIndex = blockIdx.x;
328 const uint blockIndexBase = blockIdx.y * WARPSPERBLOCK;
329 const vmesh::VelocityMesh* __restrict__ thisVmesh = dev_vmeshes[cellIndex];
330 const uint thisVmeshSize = thisVmesh->size();
331 const uint blockIndex = blockIndexBase + indexInBlock;
332 if (blockIndex < thisVmeshSize) {
333 // Now with warp accessors
334 const vmesh::GlobalID GID = thisVmesh->getGlobalID(blockIndex);
335 // warpInsert<true> only inserts if key does not yet exist
336 unionOfBlocksSet->warpInsert<true>(GID, (vmesh::LocalID)GID, ti);
337 }
338}
339#else
340__global__ void __launch_bounds__(GPUTHREADS*WARPSPERBLOCK) gather_union_of_blocks_kernel(
341 Hashinator::Hashmap<vmesh::GlobalID,vmesh::LocalID> *unionOfBlocksSet,
342 const vmesh::VelocityMesh* __restrict__ const *dev_vmeshes,
343 const uint nAllCells)
344{
345 const int indexInBlock = threadIdx.x; // [0,WARPSPERBLOCK*GPUTHREADS)
346 const uint cellIndex = blockIdx.x;
347 const uint blockIndexBase = blockIdx.y * WARPSPERBLOCK * GPUTHREADS;
348 const vmesh::VelocityMesh* __restrict__ thisVmesh = dev_vmeshes[cellIndex];
349 const uint thisVmeshSize = thisVmesh->size();
350 const uint blockIndex = blockIndexBase + indexInBlock;
351 if (blockIndex < thisVmeshSize) {
352 const vmesh::GlobalID GID = thisVmesh->getGlobalID(blockIndex);
353 // <true> only inserts if key does not yet exist
354 unionOfBlocksSet->set_element<true>(GID, (vmesh::LocalID)GID);
355 }
356}
357#endif
358
359/* Map velocity blocks in all local cells forward by one time step in one spatial dimension.
360 * This function uses 1-cell wide pencils to update cells in-place to avoid allocating large
361 * temporary buffers.
362 *
363 * @param [in] mpiGrid DCCRG grid object
364 * @param [in] localPropagatedCells List of local cells that get propagated
365 * ie. not boundary or DO_NOT_COMPUTE
366 * @param [in] remoteTargetCells List of non-local target cells
367 * @param [in] nPencilsLB vector where the number of active pencils for each cell can be stored, to be used by load balance
368 * @param [in] dimension Spatial dimension
369 * @param [in] dt Time step
370 * @param [in] popId Particle population ID
371 */
372bool trans_map_1d_amr(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
373 const vector<CellID>& localPropagatedCells,
374 const vector<CellID>& remoteTargetCells,
375 std::vector<uint>& nPencilsLB,
376 const uint dimension,
377 const Realf dt,
378 const uint popID) {
379
380 phiprof::Timer setupTimer {"trans-amr-setup"};
381
382 // return if there's no cells to propagate
383 if(localPropagatedCells.size() == 0) {
384 return false;
385 }
386 gpuStream_t bgStream = gpu_getStream(); // uses stream assigned to thread 0, not the blocking default stream
387
388 // Vector with all cell ids
389 vector<CellID> allCells(localPropagatedCells);
390 allCells.insert(allCells.end(), remoteTargetCells.begin(), remoteTargetCells.end());
391 const uint nAllCells = allCells.size();
392
393 phiprof::Timer allocateTimer {"trans-amr-allocs"};
394 // Ensure GPU data has sufficient allocations/sizes
395 const uint sumOfLengths = DimensionPencils[dimension].sumOfLengths;
397 // Ensure allocation for allPencilsMeshes, allPencilsContainers
398 gpuMemoryManager.startSession(0,0);
399
404
405 vmesh::VelocityMesh **host_allPencilsMeshes = GET_SESSION_HOST_POINTER(gpuMemoryManager, vmesh::VelocityMesh*, host_allPencilsMeshes);
406 vmesh::VelocityBlockContainer **host_allPencilsContainers = GET_SESSION_HOST_POINTER(gpuMemoryManager, vmesh::VelocityBlockContainer*, host_allPencilsContainers);
409
410 gpu_trans_allocate(nAllCells,0,0);
411 allocateTimer.stop();
412
413 // Find maximum mesh size.
414 phiprof::Timer maxMeshSizeTimer {"trans-amr-find-maxmesh"};
415 uint largestFoundMeshSize = 0;
416 int checkMeshId {phiprof::initializeTimer("trans-amr-checkMesh")};
417 #pragma omp parallel
418 {
419 uint thread_largestFoundMeshSize = 0;
420 #pragma omp for
421 for(uint celli = 0; celli < nAllCells; celli++){
422 (GET_POINTER(gpuMemoryManager, vmesh::VelocityMesh*, host_vmeshes))[celli] = mpiGrid[allCells[celli]]->dev_get_velocity_mesh(popID); // GPU-side vmesh
423 const uint thisMeshSize = mpiGrid[allCells[celli]]->get_velocity_mesh(popID)->size(); // get cached size from CPU side
424 thread_largestFoundMeshSize = thisMeshSize > thread_largestFoundMeshSize ? thisMeshSize : thread_largestFoundMeshSize;
425 #ifdef DEBUG_VLASIATOR
426 phiprof::Timer checkMeshTimer {checkMeshId};
427 if (!mpiGrid[allCells[celli]]->checkMesh(popID)) {
428 printf("GPU TRANS MAP AMR check of mesh for popID %d cell %lu failed!\n",popID,allCells[celli]);
429 }
430 #endif
431 }
432 #pragma omp critical
433 {
434 largestFoundMeshSize = largestFoundMeshSize > thread_largestFoundMeshSize ? largestFoundMeshSize : thread_largestFoundMeshSize;
435 }
436 }
437 maxMeshSizeTimer.stop();
438
439 // return if there's no blocks to propagate
440 if(largestFoundMeshSize == 0) {
441 return false;
442 }
443
444 allocateTimer.start();
445 // Copy vmesh pointers to GPU
447 // Reserve size for unionOfBlocksSet
448 gpu_trans_allocate(0,largestFoundMeshSize,0);
449 allocateTimer.stop();
450
451 // Gather cell weights for load balancing
452 phiprof::Timer pencilCountTimer {"trans-amr-count-pencils"};
454 for (uint i=0; i<localPropagatedCells.size(); i++) {
455 const uint myPencilCount = std::count(DimensionPencils[dimension].ids.begin(), DimensionPencils[dimension].ids.end(), localPropagatedCells[i]);
456 nPencilsLB[i] += myPencilCount;
457 nPencilsLB[nPencilsLB.size()-1] += myPencilCount;
458 }
459 }
460 pencilCountTimer.stop();
461
462 phiprof::Timer buildTimer {"trans-amr-buildBlockList"};
463 // Get a unique unsorted list of blockids that are in any of the
464 // propagated cells. We could do host-side pointer
465 // gathering in parallel with it, but that leads to potentially incorrect phiprof output..
466#ifdef USE_WARPACCESSORS
467 const uint maxBlocksPerCell = 1 + ((largestFoundMeshSize - 1) / WARPSPERBLOCK); // ceil int division
468 dim3 gatherdims_blocks(nAllCells,maxBlocksPerCell,1);
469 dim3 gatherdims_threads(GPUTHREADS,WARPSPERBLOCK,1);
470 gather_union_of_blocks_kernel_WA<<<gatherdims_blocks, gatherdims_threads, 0, bgStream>>> (
471#else
472 const uint maxBlocksPerCell = 1 + ((largestFoundMeshSize - 1) / (WARPSPERBLOCK*GPUTHREADS)); // ceil int division
473 dim3 gatherdims_blocks(nAllCells,maxBlocksPerCell,1);
474 dim3 gatherdims_threads(GPUTHREADS*WARPSPERBLOCK,1,1);
475 gather_union_of_blocks_kernel<<<gatherdims_blocks, gatherdims_threads, 0, bgStream>>> (
476#endif
479 nAllCells
480 );
482 CHK_ERR( gpuStreamSynchronize(bgStream) ); // So we get phiprof data of this gathering time
483 buildTimer.stop();
484
485 phiprof::Timer gatherPointerTimer {"trans-amr-gather-meshpointers"};
486 // For each cellid listed in the pencils for this dimension, store the pointer to the vmesh.
487 // At the same time, we could accumulate a list of unique cells included, but we already
488 // get these from vlasovmover. This has to be on the host, as SpatialCells reside in host memory.
489 const uint nPencils = DimensionPencils[dimension].N;
490 #pragma omp parallel for
491 for (uint pencili = 0; pencili < nPencils; ++pencili) {
492 int L = DimensionPencils[dimension].lengthOfPencils[pencili];
493 int start = DimensionPencils[dimension].idsStart[pencili];
494 // Loop over cells in pencil
495 for (int i = 0; i < L; i++) {
496 const CellID thisCell = DimensionPencils[dimension].ids[start+i];
497 host_allPencilsMeshes[start+i] = mpiGrid[thisCell]->dev_get_velocity_mesh(popID);
498 host_allPencilsContainers[start+i] = mpiGrid[thisCell]->dev_get_velocity_blocks(popID);
499 }
500 }
501 // Copy pencil meshes and VBCs to GPU
504
505 // Extract pointers to data in unified memory
506 uint* pencilLengths = gpuMemoryManager.getPointer<uint>(DimensionPencils[dimension].gpu_lengthOfPencils);
507 uint* pencilStarts = gpuMemoryManager.getPointer<uint>(DimensionPencils[dimension].gpu_idsStart);
508 Realf* pencilDZ = gpuMemoryManager.getPointer<Realf>(DimensionPencils[dimension].gpu_sourceDZ);
509 Realf* pencilRatios = gpuMemoryManager.getPointer<Realf>(DimensionPencils[dimension].gpu_targetRatios);
510 gatherPointerTimer.stop();
511
512 // Now we ensure the union of blocks gathering is complete and find the size of it. Use it to ensure allocations.
513 allocateTimer.start();
514 // Use non-pagefaulting fetching of metadata
515 Hashinator::Info mapInfo;
516 unionOfBlocksSet->copyMetadata(&mapInfo, bgStream);
517 CHK_ERR( gpuStreamSynchronize(bgStream) );
518 const vmesh::LocalID unionOfBlocksSetSize = mapInfo.fill;
519 gpu_trans_allocate(0,0,unionOfBlocksSetSize);
520 allocateTimer.stop();
521
522 phiprof::Timer buildTimer2 {"trans-amr-buildBlockList-2"};
523 // Extract the union of blocks into a vector
524 unionOfBlocksSet->extractAllKeysLoop(*dev_unionOfBlocks,bgStream);
525 split::SplitInfo unionInfo;
526 unionOfBlocks->copyMetadata(&unionInfo, bgStream);
527 CHK_ERR( gpuStreamSynchronize(bgStream) );
528 const uint nAllBlocks = unionInfo.size;
529 const uint numberOfBins = DimensionPencils[dimension].activeBins.size();
531 // This threshold value is used by slope limiters.
532 Realf threshold = mpiGrid[DimensionPencils[dimension].ids[VLASOV_STENCIL_WIDTH]]->getVelocityBlockMinValue(popID);
533 buildTimer2.stop();
534
535 // GPUTODO: Improve config parameter use for temp buffer allocation, consolidate buffers, etc.
536 // Current approach is not necessarily good if average block count vs grid size are mismatched.
537 // Best would be to have one large buffer from which sub-buffers are provided to the various Vlasov
538 // solvers as necessary.
539
540 // How many blocks worth of pre-allocated buffer do we have for each thread?
541 const uint currentAllocation = gpu_vlasov_getSmallestAllocation();
542 // How many block GIDs could each thread manage in parallel with this existing temp buffer? // floor int division
543 // Note: we no longer launch from several threads, but some buffers are still identified via threads.
544 const uint nBlocksPerAllocation = currentAllocation / sumOfLengths;
545 // And how many block GIDs will we actually manage at once?
546 const uint numAllocations = gpu_getAllocationCount();
547 const uint totalPerAllocation = 1 + ((nAllBlocks - 1) / numAllocations); // ceil int division
548 // no more than this per allocation
549 const uint nGpuBlocks = std::min(nBlocksPerAllocation,totalPerAllocation);
550 // Limit is either how many blocks exist, or how many fit in buffer.
551
552 phiprof::Timer bufferTimer {"trans-amr-buffers"};
553 // Two temporary buffers, used in-kernel for both reading and writing
554 // (dev_pencilBlockData and dev_pencilBlocksCount)
555 allocateTimer.start();
556
557 SESSION_ALLOCATE(gpuMemoryManager, Realf*, dev_pencilBlockData, sumOfLengths*nGpuBlocks*numAllocations * sizeof(Realf*));
558 SESSION_ALLOCATE(gpuMemoryManager, uint, dev_pencilBlocksCount, sumOfLengths*nGpuBlocks*numAllocations * sizeof(uint));
559
560 Realf **dev_pencilBlockData = GET_SESSION_POINTER(gpuMemoryManager, Realf*, dev_pencilBlockData); // Array of pointers into actual block data
561 uint *dev_pencilBlocksCount = GET_SESSION_POINTER(gpuMemoryManager, uint, dev_pencilBlocksCount);
562
563 allocateTimer.stop();
564 bufferTimer.stop();
565
566 /***********************/
567 setupTimer.stop();
568 /***********************/
569
570 // Loop over velocity space blocks
571 phiprof::Timer mappingTimer {"trans-amr-mapping"};
572 // Launch 2D grid: First dimension is how many blocks fit in one temp buffer, second one
573 // is which temp buffer allocation index to use. (GPUTODO: simplify together with buffer consolidation)
574 dim3 grid(nGpuBlocks,numAllocations,numberOfBins);
575 dim3 block(WID,WID,WID);
576 translation_kernel<<<grid, block, 0, bgStream>>> (
577 dimension,
578 dt,
581 allBlocks, // List of all block GIDs
582 nAllBlocks, // size of list of block GIDs which we won't exceed
583 nPencils, // Number of total pencils (constant)
584 sumOfLengths, // sum of all pencil lengths (constant)
585 threshold,
586 dev_allPencilsMeshes, // Pointers to velocity meshes
587 dev_allPencilsContainers, // pointers to BlockContainers
588 dev_pencilBlockData, // pointers into cell block data, both written and read
589 GET_POINTER(gpuMemoryManager, Realf*, dev_blockDataOrdered), // buffer of pointers to ordered buffer data
590 pencilDZ,
591 pencilRatios, // buffer tor holding target ratios
592 dev_pencilBlocksCount, // store how many non-empty blocks each pencil has for this GID
593 gpuMemoryManager.getPointer<uint>(DimensionPencils[dimension].dev_pencilsInBin),
594 gpuMemoryManager.getPointer<uint>(DimensionPencils[dimension].dev_binStart),
595 gpuMemoryManager.getPointer<uint>(DimensionPencils[dimension].dev_binSize),
597 );
599 CHK_ERR( gpuStreamSynchronize(bgStream) );
600 gpuMemoryManager.endSession();
601 mappingTimer.stop();
602
603 return true;
604}
605
606
607/* Get an index that identifies which cell in the list of sibling cells this cell is.
608 *
609 * @param mpiGrid DCCRG grid object
610 * @param cellid DCCRG id of this cell
611 */
612int get_sibling_index(dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid, const CellID& cellid) {
613
614 const int NO_SIBLINGS = 0;
615 if(mpiGrid.get_refinement_level(cellid) == 0) {
616 return NO_SIBLINGS;
617 }
618
619 //CellID parent = mpiGrid.mapping.get_parent(cellid);
620 CellID parent = mpiGrid.get_parent(cellid);
621
622 if (parent == INVALID_CELLID) {
623 std::cerr<<"Invalid parent id"<<std::endl;
624 abort();
625 }
626
627 // get_all_children returns an array instead of a vector now, need to map it to a vector for find and distance
628 // std::array<uint64_t, 8> siblingarr = mpiGrid.mapping.get_all_children(parent);
629 // vector<CellID> siblings(siblingarr.begin(), siblingarr.end());
630 vector<CellID> siblings = mpiGrid.get_all_children(parent);
631 auto location = std::find(siblings.begin(),siblings.end(),cellid);
632 auto index = std::distance(siblings.begin(), location);
633 if (index>7) {
634 std::cerr<<"Invalid parent id"<<std::endl;
635 abort();
636 }
637 return index;
638
639}
640
644__global__ static void remote_increment_kernel (
645 Realf* blockData,
646 Realf* neighborData,
647 vmesh::LocalID nBlocks
648 ) {
649 //const int gpuBlocks = gridDim.x;
650 const int blocki = blockIdx.x; // ==LID
651 const int i = threadIdx.x;
652 const int j = threadIdx.y;
653 const int k = threadIdx.z;
654 const uint ti = k*WID2 + j*WID + i;
655 // Increment value
656 // atomicAdd(&blockData[blocki * WID3 + ti],neighborData[blocki * WID3 + ti]);
657 // As each target block has its own GPU stream, we ensure that we don't write concurrently from
658 // several different threads or kernels, and thus don't need to use atomic operations.
659 blockData[blocki * WID3 + ti] += neighborData[blocki * WID3 + ti];
660}
661
662/* This function communicates the mapping on process boundaries, and then updates the data to their correct values.
663 * When sending data between neighbors of different refinement levels, special care has to be taken to ensure that
664 * The sending and receiving ranks allocate the correct size arrays for neighbor_block_data.
665 * This is partially due to DCCRG defining neighborhood size relative to the host cell. For details, see
666 * https://github.com/fmihpc/dccrg/issues/12
667 *
668 * @param mpiGrid DCCRG grid object
669 * @param dimension Spatial dimension
670 * @param direction Direction of communication (+ or -)
671 * @param popId Particle population ID
672 */
674 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
675 const uint dimension,
676 int direction,
677 const uint popID) {
678
679 // Fast return if no cells to process
680 int mpiProcs;
681 MPI_Comm_size(MPI_COMM_WORLD,&mpiProcs);
682 if (mpiProcs == 1) {
683 return;
684 }
685
694 int device = gpu_getDevice();
695
696 int neighborhood = 0;
697 //normalize and set neighborhoods
698 if(direction > 0) {
699 direction = 1;
700 switch (dimension) {
701 case 0:
702 neighborhood = Neighborhoods::SHIFT_P_X;
703 break;
704 case 1:
705 neighborhood = Neighborhoods::SHIFT_P_Y;
706 break;
707 case 2:
708 neighborhood = Neighborhoods::SHIFT_P_Z;
709 break;
710 }
711 }
712 if(direction < 0) {
713 direction = -1;
714 switch (dimension) {
715 case 0:
716 neighborhood = Neighborhoods::SHIFT_M_X;
717 break;
718 case 1:
719 neighborhood = Neighborhoods::SHIFT_M_Y;
720 break;
721 case 2:
722 neighborhood = Neighborhoods::SHIFT_M_Z;
723 break;
724 }
725 }
726
727 //const vector<CellID>& local_cells = getLocalCells();
728 const vector<CellID> local_cells = mpiGrid.get_local_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER);
729 const vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER);
730
731 vector<CellID> receive_cells;
732 set<CellID> send_cells;
733 vector<CellID> receive_origin_cells;
734 vector<uint> receive_origin_index;
735
736 phiprof::Timer updateRemoteTimerPre {"trans-amr-remotes-setup-getcells"};
737 // Initialize remote cells
738 #pragma omp parallel for
739 for (auto rc : remote_cells) {
740 SpatialCell *ccell = mpiGrid[rc];
741 // Initialize number of blocks to 0 and block data to a default value.
742 // We need the default for 1 to 1 communications
743 if(ccell) {
744 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
745 ccell->neighbor_block_data[i] = ccell->get_data(popID);
746 ccell->neighbor_number_of_blocks[i] = 0;
747 }
748 }
749 }
750
751 // Initialize local cells
752 #pragma omp parallel for
753 for (auto lc : local_cells) {
754 SpatialCell *ccell = mpiGrid[lc];
755 if(ccell) {
756 // Initialize number of blocks to 0 and neighbor block data pointer to the local block data pointer
757 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
758 ccell->neighbor_block_data[i] = ccell->get_data(popID);
759 ccell->neighbor_number_of_blocks[i] = 0;
760 }
761 }
762 }
763 updateRemoteTimerPre.stop();
764
765 vector<Realf*> receiveBuffers;
766 vector<Realf*> sendBuffers;
767
768 phiprof::Timer updateRemoteTimer0 {"trans-amr-remotes-setup-localcells"};
769 for (auto c : local_cells) {
770 SpatialCell *ccell = mpiGrid[c];
771 if (!ccell) {
772 continue;
773 }
774 vector<CellID> p_nbrs;
775 vector<CellID> n_nbrs;
776 for (const auto& [neighbor, dir] : mpiGrid.get_face_neighbors_of(c)) {
777 if(dir == ((int)dimension + 1) * direction) {
778 p_nbrs.push_back(neighbor);
779 }
780 if(dir == -1 * ((int)dimension + 1) * direction) {
781 n_nbrs.push_back(neighbor);
782 }
783 }
784
785 uint sendIndex = 0;
786 uint recvIndex = 0;
787 int mySiblingIndex = get_sibling_index(mpiGrid,c);
788 // Set up sends if any neighbor cells in p_nbrs are non-local.
789 if (!all_of(p_nbrs.begin(), p_nbrs.end(), [&mpiGrid](CellID i){return mpiGrid.is_local(i);})) {
790 phiprof::Timer updateRemoteTimer1 {"trans-amr-remotes-setup-sends"};
791 // ccell adds a neighbor_block_data block for each neighbor in the positive direction to its local data
792 for (const auto nbr : p_nbrs) {
793 //Send data in nbr target array that we just mapped to, if
794 // 1) it is a valid target,
795 // 2) the source cell in center was translated,
796 // 3) Cell is remote.
797 if(nbr != INVALID_CELLID && do_translate_cell(ccell) && !mpiGrid.is_local(nbr)) {
798 /*
799 Select the index to the neighbor_block_data and neighbor_number_of_blocks arrays
800 1) Ref_c == Ref_nbr == 0, index = 0
801 2) Ref_c == Ref_nbr != 0, index = c sibling index
802 3) Ref_c > Ref_nbr , index = c sibling index
803 4) Ref_c < Ref_nbr , index = nbr sibling index
804 */
805 if(mpiGrid.get_refinement_level(c) >= mpiGrid.get_refinement_level(nbr)) {
806 sendIndex = mySiblingIndex;
807 } else {
808 sendIndex = get_sibling_index(mpiGrid,nbr);
809 }
810 SpatialCell *pcell = mpiGrid[nbr];
811 // 4) it exists and is not a boundary cell,
813
814 ccell->neighbor_number_of_blocks.at(sendIndex) = pcell->get_number_of_velocity_blocks(popID);
815
816 if(send_cells.find(nbr) == send_cells.end()) {
817 // 5 We have not already sent data from this rank to this cell.
818 ccell->neighbor_block_data.at(sendIndex) = pcell->get_data(popID);
819 send_cells.insert(nbr);
820 } else {
821 // The receiving cell can't know which cell is sending the data from this rank.
822 // Therefore, we have to send 0's from other cells in the case where multiple cells
823 // from one rank are sending to the same remote cell so that all sent cells can be
824 // summed for the correct result.
825
826 if (ccell->neighbor_number_of_blocks.at(sendIndex) == 0) {
827 ccell->neighbor_block_data.at(sendIndex) = 0;
828 sendBuffers.push_back(0);
829 } else {
830 // GPUTODO: This is now unified memory. With GPU-aware MPI it could be on-device.
831 CHK_ERR( gpuMallocManaged((void**)&ccell->neighbor_block_data.at(sendIndex), ccell->neighbor_number_of_blocks.at(sendIndex) * WID3 * sizeof(Realf)) );
832 // CHK_ERR( gpuMemPrefetchAsync(ccell->neighbor_block_data.at(sendIndex),ccell->neighbor_number_of_blocks.at(sendIndex) * WID3 * sizeof(Realf),device,0) );
833 CHK_ERR( gpuMemset(ccell->neighbor_block_data.at(sendIndex), 0, ccell->neighbor_number_of_blocks.at(sendIndex) * WID3 * sizeof(Realf)) );
834 sendBuffers.push_back(ccell->neighbor_block_data.at(sendIndex));
835 }
836 } // closes if(send_cells.find(nbr) == send_cells.end())
837 } // closes if(pcell && pcell->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY)
838 } // closes if(nbr != INVALID_CELLID && do_translate_cell(ccell) && !mpiGrid.is_local(nbr))
839 } // closes for(uint i_nbr = 0; i_nbr < nbrs_to.size(); ++i_nbr)
840 } // closes if(!all_of(nbrs_to.begin(), nbrs_to.end(),[&mpiGrid](CellID i){return mpiGrid.is_local(i);}))
841
842 // Set up receives if any neighbor cells in n_nbrs are non-local.
843 if (!all_of(n_nbrs.begin(), n_nbrs.end(), [&mpiGrid](CellID i){return mpiGrid.is_local(i);})) {
844 phiprof::Timer updateRemoteTimer2 {"trans-amr-remotes-setup-receives"};
845 // ccell adds a neighbor_block_data block for each neighbor in the positive direction to its local data
846 for (const auto nbr : n_nbrs) {
847 if (nbr != INVALID_CELLID && !mpiGrid.is_local(nbr) &&
849 //Receive data that ncell mapped to this local cell data array,
850 //if 1) ncell is a valid source cell, 2) center cell is to be updated (normal cell) 3) ncell is remote
851 SpatialCell *ncell = mpiGrid[nbr];
852 // Check for null pointer
853 if(!ncell) {
854 continue;
855 }
856 /*
857 Select the index to the neighbor_block_data and neighbor_number_of_blocks arrays
858 1) Ref_nbr == Ref_c == 0, index = 0
859 2) Ref_nbr == Ref_c != 0, index = nbr sibling index
860 3) Ref_nbr > Ref_c , index = nbr sibling index
861 4) Ref_nbr < Ref_c , index = c sibling index
862 */
863 if(mpiGrid.get_refinement_level(nbr) >= mpiGrid.get_refinement_level(c)) {
864 // Allocate memory for one sibling at recvIndex.
865 recvIndex = get_sibling_index(mpiGrid,nbr);
866 ncell->neighbor_number_of_blocks.at(recvIndex) = ccell->get_number_of_velocity_blocks(popID);
867 if (ncell->neighbor_number_of_blocks.at(recvIndex) == 0) {
868 receiveBuffers.push_back(0);
869 } else {
870 // GPUTODO: This is now unified memory. With GPU-aware MPI it could be on-device.
871 CHK_ERR( gpuMallocManaged((void**)&ncell->neighbor_block_data.at(recvIndex), ncell->neighbor_number_of_blocks.at(recvIndex) * WID3 * sizeof(Realf)) );
872 CHK_ERR( gpuMemPrefetchAsync(ncell->neighbor_block_data.at(recvIndex), ncell->neighbor_number_of_blocks.at(recvIndex) * WID3 * sizeof(Realf), device,0) );
873 receiveBuffers.push_back(ncell->neighbor_block_data.at(recvIndex));
874 }
875 } else {
876 recvIndex = mySiblingIndex;
877 // std::array<uint64_t, 8> siblingarr = mpiGrid.mapping.get_all_children(mpiGrid.mapping.get_parent(c));
878 // vector<CellID> mySiblings(siblingarr.begin(), siblingarr.end());
879 auto mySiblings = mpiGrid.get_all_children(mpiGrid.get_parent(c));
880 auto myIndices = mpiGrid.mapping.get_indices(c);
881
882 // Allocate memory for each sibling to receive all the data sent by coarser ncell.
883 // only allocate blocks for face neighbors.
884 for (uint i_sib = 0; i_sib < MAX_NEIGHBORS_PER_DIM; ++i_sib) {
885 auto sibling = mySiblings.at(i_sib);
886 auto sibIndices = mpiGrid.mapping.get_indices(sibling);
887 auto* scell = mpiGrid[sibling];
888 // Only allocate siblings that are remote face neighbors to ncell
889 // Also take care to have these consistent with the sending process neighbor checks!
890 if(sibling != INVALID_CELLID
891 && scell
892 && mpiGrid.get_process(sibling) != mpiGrid.get_process(nbr)
893 && myIndices.at(dimension) == sibIndices.at(dimension)
894 && ncell->neighbor_number_of_blocks.at(i_sib) != scell->get_number_of_velocity_blocks(popID)
895 && scell->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
896
897 ncell->neighbor_number_of_blocks.at(i_sib) = scell->get_number_of_velocity_blocks(popID);
898 if (ncell->neighbor_number_of_blocks.at(i_sib) == 0) {
899 receiveBuffers.push_back(0);
900 } else {
901 // GPUTODO: This is now unified memory. With GPU-aware MPI it could be on-device.
902 CHK_ERR( gpuMallocManaged((void**)&ncell->neighbor_block_data.at(i_sib), ncell->neighbor_number_of_blocks.at(i_sib) * WID3 * sizeof(Realf)) );
903 CHK_ERR( gpuMemPrefetchAsync(ncell->neighbor_block_data.at(i_sib), ncell->neighbor_number_of_blocks.at(i_sib) * WID3 * sizeof(Realf), device,0) );
904 receiveBuffers.push_back(ncell->neighbor_block_data.at(i_sib));
905 }
906 }
907 }
908 }
909 receive_cells.push_back(c);
910 receive_origin_cells.push_back(nbr);
911 receive_origin_index.push_back(recvIndex);
912 } // closes (nbr != INVALID_CELLID && !mpiGrid.is_local(nbr) && ...)
913 } // closes for(uint i_nbr = 0; i_nbr < nbrs_of.size(); ++i_nbr)
914 } // closes if(!all_of(nbrs_of.begin(), nbrs_of.end(),[&mpiGrid](CellID i){return mpiGrid.is_local(i);}))
915 } // closes for (auto c : local_cells) {
916 updateRemoteTimer0.stop();
917
918 MPI_Barrier(MPI_COMM_WORLD);
919 phiprof::Timer updateRemoteTimer3 {"trans-amr-remotes-MPI"};
920
921 // Do communication
924 mpiGrid.update_copies_of_remote_neighbors(neighborhood);
925 updateRemoteTimer3.stop();
926
927 MPI_Barrier(MPI_COMM_WORLD);
928
929 // Reduce data: sum received data in the data array to
930 // the target grid in the temporary block container
931 if (receive_cells.size() != 0) {
932 phiprof::Timer updateRemoteTimerIncrement {"trans-amr-remotes-increment"};
933 for (size_t c = 0; c < receive_cells.size(); ++c) {
934 SpatialCell* receive_cell = mpiGrid[receive_cells[c]];
935 SpatialCell* origin_cell = mpiGrid[receive_origin_cells[c]];
936 if (!receive_cell || !origin_cell) {
937 continue;
938 }
939
940 Realf *blockData = receive_cell->get_data(popID);
941 Realf *neighborData = origin_cell->neighbor_block_data[receive_origin_index[c]];
942 vmesh::LocalID nBlocks = receive_cell->get_number_of_velocity_blocks(popID);
943 const uint maxThreads = gpu_getMaxThreads();
944 // Increment needs to be parallel-safe, so use modulo of cellid as stream number
945 gpuStream_t cellStream = gpuStreamList[receive_cells[c] % maxThreads];
946 if (nBlocks>0) {
947 dim3 block(WID,WID,WID);
949 blockData,
950 neighborData,
951 nBlocks
952 );
954 //CHK_ERR( gpuStreamSynchronize(cellStream) );
955 }
956 }
957 // Since all increment kernel streams were launched from outside an openmp region, use device sync here.
959
960 // send cell data is set to zero. This is to avoid double copy if
961 // one cell is the neighbor on both + and - side to the same process
962 vector<CellID> send_cells_vector(send_cells.begin(), send_cells.end());
963 for (uint c = 0; c < send_cells_vector.size(); c++) {
964 SpatialCell* send_cell = mpiGrid[send_cells_vector[c]];
965 gpuStream_t stream = gpu_getStream();
966 Realf* blockData = send_cell->get_data(popID);
967 CHK_ERR( gpuMemsetAsync(blockData, 0, WID3*send_cell->get_number_of_velocity_blocks(popID)*sizeof(Realf),stream) );
968 }
970 }
971
972 phiprof::Timer updateRemoteTimerFree {"trans-amr-remotes-free"};
973 for (auto p : receiveBuffers) {
974 CHK_ERR( gpuFree(p) );
975 }
976 for (auto p : sendBuffers) {
977 CHK_ERR( gpuFree(p) );
978 }
979 updateRemoteTimerFree.stop();
980}
for i
Definition Dispersion.m:24
dt
Definition Dispersion.m:39
set(gca, 'YDir', 'normal')
Constants c
Definition Dispersion.m:45
#define gpuPeekAtLastError
#define WARPSPERBLOCK
#define gpuStream_t
cudaStream_t gpuStreamList[]
Definition gpu_base.cpp:51
#define gpuStreamSynchronize
#define gpuMemcpyHostToDevice
#define CHK_ERR(err)
#define gpuMemcpy
#define gpuMallocManaged
#define gpuMemPrefetchAsync
#define gpuFree
#define gpuMemset
#define gpuDeviceSynchronize
#define gpuMemsetAsync
#define GPUTHREADS
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
std::array< Realf *, MAX_NEIGHBORS_PER_DIM > neighbor_block_data
static bool setCommunicatedSpecies(const uint popID)
static void set_mpi_transfer_type(const uint64_t type, bool atSysBoundaries=false)
std::array< vmesh::LocalID, MAX_NEIGHBORS_PER_DIM > neighbor_number_of_blocks
Realf * get_data(const uint popID)
ARCH_HOSTDEV vmesh::LocalID size() const
#define WID
Definition common.h:514
const int WID3
Definition common.h:517
const int WID2
Definition common.h:516
void compute_ppm_coeff_nonuniform(const Realf *const dv, const Vec *const values, const face_estimate_order order, const uint k, Vec a[3], const Realf threshold)
std::array< setOfPencils, 3 > DimensionPencils
bool do_translate_cell(const SpatialCell *const SC)
#define MAX_NEIGHBORS_PER_DIM
Definition definitions.h:93
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
const uint ti
GPUMemoryManager gpuMemoryManager
Definition gpu_base.cpp:64
split::SplitVector< vmesh::GlobalID > * dev_unionOfBlocks
Definition gpu_base.cpp:60
__host__ int gpu_getDevice()
Definition gpu_base.cpp:253
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * dev_unionOfBlocksSet
Definition gpu_base.cpp:61
split::SplitVector< vmesh::GlobalID > * unionOfBlocks
Definition gpu_base.cpp:60
__host__ void gpu_trans_allocate(cuint nAllCells, cuint largestVmesh, cuint unionSetSize)
Definition gpu_base.cpp:607
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * unionOfBlocksSet
Definition gpu_base.cpp:61
__host__ gpuStream_t gpu_getStream()
Definition gpu_base.cpp:244
__host__ uint gpu_vlasov_getSmallestAllocation()
Definition gpu_base.cpp:410
__host__ uint gpu_getMaxThreads()
Definition gpu_base.cpp:84
__host__ uint gpu_getAllocationCount()
Definition gpu_base.cpp:259
__host__ void gpu_vlasov_allocate(const uint maxBlockCount)
Definition gpu_base.cpp:335
#define SESSION_HOST_ALLOCATE(object, type, member, bytes)
Definition gpu_base.hpp:600
#define SESSION_ALLOCATE(object, type, member, bytes)
Definition gpu_base.hpp:557
#define GET_SESSION_POINTER(object, type, member)
Definition gpu_base.hpp:833
#define GET_SESSION_HOST_POINTER(object, type, member)
Definition gpu_base.hpp:853
#define GET_POINTER(object, type, member)
Definition gpu_base.hpp:809
const int j
__syncthreads()
const int k
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const * dev_allPencilsMeshes
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf threshold
const vmesh::VelocityMesh *__restrict__ randovmesh
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ pencilStarts
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint nPencils
const Realf dvz
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ uint uint uint uint const uint numberOfBins
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ pencilRatios
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ uint uint uint * dev_binStart
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ allBlocks
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint nAllBlocks
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ uint * pencilBlocksCount
static __global__ void remote_increment_kernel(Realf *blockData, Realf *neighborData, vmesh::LocalID nBlocks)
__global__ void const Realf const uint *__restrict__ pencilLengths
const Realf vz_min
const uint pencilBlocksCountOffset
Realf * pencilOrderedSource
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer ** dev_allPencilsContainers
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint sumOfLengths
const uint pencilOrderedSourceOffset
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ pencilDZ
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf ** pencilBlockData
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ uint uint uint uint * dev_binSize
int get_sibling_index(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellid)
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf const Realf *__restrict__ const Realf *__restrict__ uint uint * dev_pencilsInBin
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf const vmesh::VelocityMesh *__restrict__ const vmesh::VelocityBlockContainer Realf Realf ** dev_blockDataOrdered
bool trans_map_1d_amr(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &localPropagatedCells, const vector< CellID > &remoteTargetCells, std::vector< uint > &nPencilsLB, const uint dimension, const Realf dt, const uint popID)
uint vz_index
void update_remote_mapping_contribution_amr(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint dimension, int direction, const uint popID)
__device__ bool check_skip_blocks(const Realf *__restrict__ const *pencilBlockData, const uint centerOffset)
const uint blockIndexIncrement
const uint pencilBlockDataOffset
#define index(i, j, k)
@ VLASOV_SOLVER
Definition common.h:77
uint32_t uint
static const uint64_t NEIGHBOR_VEL_BLOCK_DATA
static __global__ void __launch_bounds__(WID3, 4) population_scale_kernel(vmesh
uint32_t LocalID
Definition definitions.h:60
uint32_t GlobalID
Definition definitions.h:59
const uint64_t INVALID_CELLID
Definition parameters.h:35
static bool prepareForRebalance
Definition parameters.h:167
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)