Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
cpu_trans_map_amr.cpp
Go to the documentation of this file.
2//#include "cpu_1d_ppm_nonuniform_conserving.hpp"
3#include "vec.h"
4#include "../grid.h"
5#include "../object_wrapper.h"
9
10using namespace std;
11using namespace spatial_cell;
12
13// indices in padded source block, which is of type Vec with VECL
14// elements in each vector.
15
16#define i_trans_ps_blockv_pencil(planeVectorIndex, planeIndex, blockIndex, lengthOfPencil) ( (blockIndex) + ( (planeVectorIndex) + (planeIndex) * VEC_PER_PLANE ) * ( lengthOfPencil) )
17
18inline bool check_skip_remapping(const Vec* const values) {
19 for (int index=-VLASOV_STENCIL_WIDTH; index<VLASOV_STENCIL_WIDTH+1; ++index) {
20 if (horizontal_or(values[index] > Vec(0))) {
21 return false;
22 }
23 }
24 return true;
25}
26
27/* Propagate a given velocity block in all spatial cells of a pencil by a time step dt using a PPM reconstruction.
28 *
29 * @param dz Width of spatial cells in the direction of the pencil, vector datatype
30 * @param values Density values of the block, vector datatype
31 * @param dimension Satial dimension
32 * @param blockGID Global ID of the velocity block.
33 * @param dt Time step
34 * @param vmesh Velocity mesh object
35 * @param lengthOfPencil Number of cells in the pencil
36 */
38 const Realf* const dz,
39 const Vec* const values, // Vec-ordered block data values for pencils
40 const uint dimension,
41 const uint blockGID,
42 const Realf dt,
44 const int lengthOfPencil,
45 const Realf threshold,
46 Realf** blockDataPointer, // Spacing is for sources, but will be written into
47 const Realf* const targetRatios, // Vector holding target ratios
48 const unsigned int* const vcell_transpose
49) {
50 // Get velocity data from vmesh that we need later to calculate the translation
51 velocity_block_indices_t block_indices;
52 vmesh->getIndices(blockGID, block_indices[0], block_indices[1], block_indices[2]);
53 const Realf dvz = vmesh->getCellSize()[dimension];
54 const Realf vz_min = vmesh->getMeshMinLimits()[dimension];
55
56 // Assuming 1 neighbor in the target array because of the CFL condition
57 // In fact propagating to > 1 neighbor will give an error
58 // Also defined in the calling function for the allocation of targetValues
59
60 // Go over length of propagated cells
61 for (int i = VLASOV_STENCIL_WIDTH; i < (int)lengthOfPencil-VLASOV_STENCIL_WIDTH; i++){
62 // Get pointers to block data used for output.
63 Realf* block_data_m1 = blockDataPointer[i - 1];
64 Realf* block_data = blockDataPointer[i];
65 Realf* block_data_p1 = blockDataPointer[i + 1];
66 // Cells which shouldn't be written to (e.g. sysboundary cells) have a targetRatio of 0
67 // Also need to check if pointer is valid, because a cell can be missing an elsewhere propagated block
68 Realf areaRatio_m1 = targetRatios[i - 1];
69 Realf areaRatio = targetRatios[i];
70 Realf areaRatio_p1 = targetRatios[i + 1];
71
72 Realf vector[VECL];
73 // Loop over planes
74 for (uint k = 0; k < WID; ++k) {
75 const Realf cell_vz = (block_indices[dimension] * WID + k + 0.5) * dvz + vz_min; //cell centered velocity
76 const Vec z_translation = cell_vz * dt / dz[i]; // how much it moved in time dt (reduced units)
77
78 // Determine direction of translation
79 // part of density goes here (cell index change along spatial direcion)
80 Vecb positiveTranslationDirection = (z_translation > Vec(0.0));
81
82 // Calculate normalized coordinates in current cell.
83 // The coordinates (scaled units from 0 to 1) between which we will
84 // integrate to put mass in the target neighboring cell.
85 // Normalize the coordinates to the origin cell. Then we scale with the difference
86 // in volume between target and origin later when adding the integrated value.
87 Vec z_1,z_2;
88 z_1 = select(positiveTranslationDirection, 1.0 - z_translation, 0.0);
89 z_2 = select(positiveTranslationDirection, 1.0, - z_translation);
90
91 // if( horizontal_or(abs(z_1) > Vec(1.0)) || horizontal_or(abs(z_2) > Vec(1.0)) ) {
92 // std::cout << "Error, CFL condition violated\n";
93 // std::cout << "Exiting\n";
94 // std::exit(1);
95 // }
96
97 // Loop over Vec's in current plance
98 for (uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++) {
99 // Check if all values are 0:
100 if (check_skip_remapping(values + i_trans_ps_blockv_pencil(planeVector, k, i, lengthOfPencil))) {
101 continue;
102 }
103
104 // Compute polynomial coefficients
105 Vec a[3];
106 // Silly indexing into coefficient calculation necessary due to built-in assumptions of unsigned indexing.
107 compute_ppm_coeff_nonuniform(dz + i - VLASOV_STENCIL_WIDTH,
108 values + i_trans_ps_blockv_pencil(planeVector, k, i, lengthOfPencil) - VLASOV_STENCIL_WIDTH,
109 h4, VLASOV_STENCIL_WIDTH, a, threshold);
110
111 // Compute integral
112 const Vec ngbr_target_density =
113 z_2 * ( a[0] + z_2 * ( a[1] + z_2 * a[2] ) ) -
114 z_1 * ( a[0] + z_1 * ( a[1] + z_1 * a[2] ) );
115
116 // Store mapped density in two target cells
117 // in the current original cells we will put the rest of the original density
118 if (areaRatio && block_data) {
119 const Vec selfContribution = (values[i_trans_ps_blockv_pencil(planeVector, k, i, lengthOfPencil)] - ngbr_target_density) * areaRatio;
120 selfContribution.store(vector);
121 // Loop over 3rd (vectorized) vspace dimension
122 #pragma omp simd
123 for (uint iv = 0; iv < VECL; iv++) {
124 block_data[vcell_transpose[iv + planeVector * VECL + k * WID2]] += vector[iv];
125 }
126 }
127 if (areaRatio_p1 && block_data_p1) {
128 const Vec p1Contribution = select(positiveTranslationDirection, ngbr_target_density
129 * dz[i] / dz[i + 1], Vec(0.0)) * areaRatio_p1;
130 p1Contribution.store(vector);
131 // Loop over 3rd (vectorized) vspace dimension
132 #pragma omp simd
133 for (uint iv = 0; iv < VECL; iv++) {
134 block_data_p1[vcell_transpose[iv + planeVector * VECL + k * WID2]] += vector[iv];
135 }
136 }
137 if (areaRatio_m1 && block_data_m1) {
138 const Vec m1Contribution = select(!positiveTranslationDirection, ngbr_target_density
139 * dz[i] / dz[i - 1], Vec(0.0)) * areaRatio_m1;
140 m1Contribution.store(vector);
141 // Loop over 3rd (vectorized) vspace dimension
142 #pragma omp simd
143 for (uint iv = 0; iv < VECL; iv++) {
144 block_data_m1[vcell_transpose[iv + planeVector * VECL + k * WID2]] += vector[iv];
145 }
146 }
147 }
148 }
149 }
150}
151
152/* Copy the pencil source data to the temporary values array, so that the
153 * dimensions are correctly swapped.
154 *
155 * This function must be thread-safe.
156 *
157 * @param blockDataPointer Vector of pre-prepared pointers to input (cell) block data
158 * @param start Index from blockDataPointer to start at
159 * @param int lengthOfPencil Number of spatial cells in pencil (not inclusive 2*VLASOV_STENCIL_WIDTH
160 * @param values Vector into which the data should be loaded
161 * @param vcell_transpose
162 * @param popID ID of the particle species.
163 */
165 const Realf* const* pencilBlockData,
166 const int lengthOfPencil,
167 Vec* values,
168 const unsigned int* const vcell_transpose,
169 const uint popID) {
170
171 // Copy volume averages of this block from all spatial cells:
172 for (int b = 0; b < lengthOfPencil; b++) {
173 if(pencilBlockData[b] != NULL) {
174 Realf blockValues[WID3];
175 const Realf* block_data = pencilBlockData[b];
176 // Copy data to a temporary array and transpose values so that mapping is along k direction.
177 #pragma omp simd
178 for (uint i=0; i<WID3; ++i) {
179 blockValues[i] = block_data[vcell_transpose[i]];
180 }
181 // now load values into the actual values table..
182 uint offset =0;
183 for (uint k=0; k<WID; k++) {
184 for(uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++){
185 // store data, when reading data from data we swap dimensions
186 // using precomputed plane_index_to_id and cell_indices_to_id
187 values[i_trans_ps_blockv_pencil(planeVector, k, b, lengthOfPencil)].load(blockValues + offset);
188 offset += VECL;
189 }
190 }
191 } else {
192 for (uint k=0; k<WID; ++k) {
193 for(uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++) {
194 values[i_trans_ps_blockv_pencil(planeVector, k, b, lengthOfPencil)] = Vec(0);
195 }
196 }
197 }
198 }
199 return true;
200}
201
202/* Map velocity blocks in all local cells forward by one time step in one spatial dimension.
203 * This function uses 1-cell wide pencils to update cells in-place to avoid allocating large
204 * temporary buffers.
205 *
206 * @param [in] mpiGrid DCCRG grid object
207 * @param [in] localPropagatedCells List of local cells that get propagated
208 * ie. not boundary or DO_NOT_COMPUTE
209 * @param [in] remoteTargetCells List of non-local target cells
210 * @param [in] dimension Spatial dimension
211 * @param [in] dt Time step
212 * @param [in] popId Particle population ID
213 */
214bool trans_map_1d_amr(const dccrg::Dccrg<spatial_cell::SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
215 const vector<CellID>& localPropagatedCells,
216 const vector<CellID>& remoteTargetCells,
217 std::vector<uint>& nPencils,
218 const uint dimension,
219 const Realf dt,
220 const uint popID) {
221
222 /***********************/
223 phiprof::Timer setupTimer {"trans-amr-setup"};
224 /***********************/
225
226 // return if there's no cells to propagate
227 if(localPropagatedCells.size() == 0) {
228 return false;
229 }
230
231 uint cell_indices_to_id[3]; /*< used when computing id of target cell in block*/
232 unsigned int vcell_transpose[WID3]; /*< defines the transpose for the solver internal (transposed) id: i + j*WID + k*WID2 to actual one*/
233 // Fiddle indices x,y,z in VELOCITY SPACE
234 switch (dimension) {
235 case 0:
236 // set values in array that is used to convert block indices
237 // to global ID using a dot product.
238 cell_indices_to_id[0]=WID2;
239 cell_indices_to_id[1]=WID;
240 cell_indices_to_id[2]=1;
241 break;
242 case 1:
243 // set values in array that is used to convert block indices
244 // to global ID using a dot product
245 cell_indices_to_id[0]=1;
246 cell_indices_to_id[1]=WID2;
247 cell_indices_to_id[2]=WID;
248 break;
249 case 2:
250 // set values in array that is used to convert block indices
251 // to global id using a dot product.
252 cell_indices_to_id[0]=1;
253 cell_indices_to_id[1]=WID;
254 cell_indices_to_id[2]=WID2;
255 break;
256 default:
257 cerr << __FILE__ << ":"<< __LINE__ << " Wrong dimension, abort"<<endl;
258 abort();
259 break;
260 }
261
262 // Vector with all cell ids
263 vector<CellID> allCells(localPropagatedCells);
264 allCells.insert(allCells.end(), remoteTargetCells.begin(), remoteTargetCells.end());
265 const uint nAllCells = allCells.size();
266
267 // Vectors of pointers to the cell structs
268 std::vector<SpatialCell*> allCellsPointer(nAllCells);
269
270 // Initialize allCellsPointer
271 #pragma omp parallel for schedule(static)
272 for(uint celli = 0; celli < allCells.size(); celli++){
273 allCellsPointer[celli] = mpiGrid[allCells[celli]];
274 }
275 // init vcell_transpose (moved here to take advantage of the omp parallel region)
276 #pragma omp parallel for collapse(2) schedule(static)
277 for (uint k=0; k<WID; ++k) {
278 for (uint j=0; j<WID; ++j) {
279 for (uint i=0; i<WID; ++i) {
280 const uint cell =
281 i * cell_indices_to_id[0] +
282 j * cell_indices_to_id[1] +
283 k * cell_indices_to_id[2];
284 vcell_transpose[ i + j * WID + k * WID2] = cell;
285 }
286 }
287 }
288
289 // Only needed if pencil counts are used as weight multiplier in load balance
291 for (uint i=0; i<localPropagatedCells.size(); i++) {
292 for (uint ip=0; ip<DimensionPencils[dimension].N; ip++) {
293 // Read only central IDs for each pencil
294 const std::vector<CellID> centerIds = DimensionPencils[dimension].getIds(ip);
295 cuint myPencilCount = std::count(centerIds.begin(), centerIds.end(), localPropagatedCells[i]);
296 nPencils[i] += myPencilCount;
297 nPencils[nPencils.size()-1] += myPencilCount;
298 }
299 }
300 }
301
302 // Get a pointer to the velocity mesh of the first spatial cell
303 const vmesh::VelocityMesh* vmesh = allCellsPointer[0]->get_velocity_mesh(popID);
304
305 phiprof::Timer buildBlockListTimer {"trans-amr-buildBlockList"};
306 // Get a unique sorted list of blockids that are in any of the
307 // target cells (includes remote neighbour target cells)
308 std::vector<vmesh::GlobalID> unionOfBlocks;
309 std::unordered_set<vmesh::GlobalID> unionOfBlocksSet;
310 #pragma omp parallel
311 {
312 std::unordered_set<vmesh::GlobalID> thread_unionOfBlocksSet;
313 #pragma omp for schedule(dynamic)
314 for (unsigned int i=0; i<allCellsPointer.size(); i++) {
315 auto cell = &allCellsPointer[i];
316 const vmesh::VelocityMesh* cvmesh = (*cell)->get_velocity_mesh(popID);
317 for (vmesh::LocalID block_i=0; block_i< cvmesh->size(); ++block_i) {
318 thread_unionOfBlocksSet.insert(cvmesh->getGlobalID(block_i));
319 }
320 }
321 #pragma omp critical
322 {
323 unionOfBlocksSet.insert(thread_unionOfBlocksSet.begin(), thread_unionOfBlocksSet.end());
324 } // pragma omp critical
325 } // pragma omp parallel
326 unionOfBlocks.insert(unionOfBlocks.end(), unionOfBlocksSet.begin(), unionOfBlocksSet.end());
327 buildBlockListTimer.stop();
328 /***********************/
329 setupTimer.stop();
330 /***********************/
331
332 int mappingTimerId = phiprof::initializeTimer("trans-amr-mapping");
333 int loadTimerId = phiprof::initializeTimer("trans-amr-load source data");
334 int memsetTimerId = phiprof::initializeTimer("trans-amr-MemSet");
335 int propagateTimerId = phiprof::initializeTimer("trans-amr-propagatePencil");
336
337 const size_t blocksSize {unionOfBlocks.size()};
338 const size_t binsSize {DimensionPencils[dimension].activeBins.size()};
339
340 #pragma omp parallel
341 {
342 phiprof::Timer mappingTimer {mappingTimerId}; // mapping (top-level)
343
344 // Vector of pointers to cell block data, used for both reading and writing
345 std::vector<Vec> blockDataBuffer(DimensionPencils[dimension].sumOfLengths*WID3/VECL);
346 std::vector<Realf*> cellBlockData(DimensionPencils[dimension].sumOfLengths);
347 std::vector<uint> pencilBlocksCount(DimensionPencils[dimension].N);
348
349 // Loop over velocity space blocks (threaded).
350 // Get global id of the velocity block
351 // Load data for pencils.
352 #pragma omp for schedule(dynamic,1) collapse(2)
353 for(uint blocki = 0; blocki < blocksSize; blocki++) {
354 for (uint nBin = 0; nBin < binsSize; ++nBin) {
355 // For each block + bin we copy first copy each pencil's data into a buffer, clear the target blocks, and then sum the translated pencils in
356 const uint currentBin = DimensionPencils[dimension].activeBins[nBin];
357
358 phiprof::Timer loadTimer {loadTimerId};
359 vmesh::GlobalID blockGID = unionOfBlocks[blocki];
360 for (uint pencili : DimensionPencils[dimension].pencilsInBin[currentBin]) {
361 int nonEmptyBlocks = 0;
362 int L = DimensionPencils[dimension].lengthOfPencils[pencili];
363 int start = DimensionPencils[dimension].idsStart[pencili];
364 // Loop over cells in pencil
365 for (int b = 0; b < L; b++) {
366 // Get cell pointer and local block id
367 SpatialCell* srcCell = mpiGrid[DimensionPencils[dimension].ids[start + b]];
368 const vmesh::LocalID blockLID = srcCell->get_velocity_block_local_id(blockGID,popID);
369 // Store block data pointer for both loading of data and writing back to the cell
370 if (blockLID != srcCell->invalid_local_id()) {
371 // Get data pointer
372 cellBlockData[start + b] = srcCell->get_data(blockLID,popID);
373 nonEmptyBlocks++;
374 } else {
375 cellBlockData[start + b] = NULL;
376 }
377 }
378 if(nonEmptyBlocks == 0) {
379 continue;
380 }
381 pencilBlocksCount.at(pencili) = nonEmptyBlocks;
382 // Transpose and copy block data from cells to source buffer
383 Vec* blockDataSource = blockDataBuffer.data() + start*WID3/VECL;
384 Realf** pencilBlockData = cellBlockData.data() + start;
385 copy_trans_block_data_amr(pencilBlockData, L, blockDataSource, vcell_transpose, popID);
386 }
387 loadTimer.stop();
388
389 phiprof::Timer memsetTimer {memsetTimerId};
390 // reset blocks in all non-sysboundary neighbor spatial cells for this block id
391 for (CellID target_cell_id: DimensionPencils[dimension].targetCellsInBin[currentBin]) {
392 SpatialCell* target_cell = mpiGrid[target_cell_id];
393 if (target_cell) {
394 // Get local velocity block id
395 const vmesh::LocalID blockLID = target_cell->get_velocity_block_local_id(blockGID, popID);
396 // Check for invalid block id
397 if (blockLID != vmesh::VelocityMesh::invalidLocalID()) {
398 // Get a pointer to the block data
399 Realf* blockData = target_cell->get_data(blockLID, popID);
400 memset(blockData, 0, WID3*sizeof(Realf));
401 }
402 }
403 }
404 memsetTimer.stop();
405
406 phiprof::Timer propagateTimer {propagateTimerId};
407 for (uint pencili : DimensionPencils[dimension].pencilsInBin[currentBin]) {
408 // Skip pencils without blocks
409 if (pencilBlocksCount.at(pencili) == 0) {
410 continue;
411 }
412
413 // sourceVecData => targetBlockData[this pencil])
414 const int L = DimensionPencils[dimension].lengthOfPencils[pencili];
415 const int start = DimensionPencils[dimension].idsStart[pencili];
416 // Dz and sourceVecData are both padded by VLASOV_STENCIL_WIDTH
417 // Dz has 1 value/cell, sourceVecData has WID3 values/cell
418 // vmesh is required just for general indexes and accessors
419 const Realf scalingthreshold = mpiGrid[DimensionPencils[dimension].ids[start + VLASOV_STENCIL_WIDTH]]->getVelocityBlockMinValue(popID);
420 const Realf* pencilDZ = DimensionPencils[dimension].sourceDZ.data() + start;
421 const Realf* pencilRatios = DimensionPencils[dimension].targetRatios.data() + start;
422 Realf** pencilBlockData = cellBlockData.data() + start;
423 const Vec* blockDataSource = blockDataBuffer.data() +start*WID3/VECL;
425 blockDataSource,
426 dimension,
427 blockGID,
428 dt,
429 vmesh,
430 L,
431 scalingthreshold,
434 vcell_transpose
435 );
436 } // Loop over pencils
437 } // Loop over bins
438 } // Loop over blocks
439
440 } // closes pragma omp parallel
441
442 return true;
443}
444
445
446/* Get an index that identifies which cell in the list of sibling cells this cell is.
447 *
448 * @param mpiGrid DCCRG grid object
449 * @param cellid DCCRG id of this cell
450 */
451int get_sibling_index(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid, const CellID& cellid) {
452
453 const int NO_SIBLINGS = 0;
454 if(mpiGrid.get_refinement_level(cellid) == 0) {
455 return NO_SIBLINGS;
456 }
457
458 //CellID parent = mpiGrid.mapping.get_parent(cellid);
459 const CellID parent = mpiGrid.get_parent(cellid);
460
461 if (parent == INVALID_CELLID) {
462 std::cerr<<"Invalid parent id"<<std::endl;
463 abort();
464 }
465
466 // get_all_children returns an array instead of a vector now, need to map it to a vector for find and distance
467 // std::array<uint64_t, 8> siblingarr = mpiGrid.mapping.get_all_children(parent);
468 // vector<CellID> siblings(siblingarr.begin(), siblingarr.end());
469 const vector<CellID> siblings = mpiGrid.get_all_children(parent);
470 const auto location = std::find(siblings.begin(),siblings.end(),cellid);
471 auto index = std::distance(siblings.begin(), location);
472 if (index>7) {
473 std::cerr<<"Invalid parent id"<<std::endl;
474 abort();
475 }
476 return index;
477
478}
479
480/* This function communicates the mapping on process boundaries, and then updates the data to their correct values.
481 * When sending data between neighbors of different refinement levels, special care has to be taken to ensure that
482 * The sending and receiving ranks allocate the correct size arrays for neighbor_block_data.
483 * This is partially due to DCCRG defining neighborhood size relative to the host cell. For details, see
484 * https://github.com/fmihpc/dccrg/issues/12
485 *
486 * This function is not used if local ghost translation is active.
487 *
488 * @param mpiGrid DCCRG grid object
489 * @param dimension Spatial dimension
490 * @param direction Direction of communication (+ or -)
491 * @param popId Particle population ID
492 */
494 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
495 const uint dimension,
496 int direction,
497 const uint popID) {
498
499 const vector<CellID> local_cells = mpiGrid.get_local_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER);
500 const vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER);
501 vector<CellID> receive_cells;
502 set<CellID> send_cells;
503
504 vector<CellID> receive_origin_cells;
505 vector<uint> receive_origin_index;
506
507 int neighborhood = 0;
508
509 //normalize and set neighborhoods
510 if(direction > 0) {
511 direction = 1;
512 switch (dimension) {
513 case 0:
514 neighborhood = Neighborhoods::SHIFT_P_X;
515 break;
516 case 1:
517 neighborhood = Neighborhoods::SHIFT_P_Y;
518 break;
519 case 2:
520 neighborhood = Neighborhoods::SHIFT_P_Z;
521 break;
522 default:
523 cerr << __FILE__ << ":"<< __LINE__ << " Wrong dimension, abort"<<endl;
524 abort();
525 }
526 }
527 if(direction < 0) {
528 direction = -1;
529 switch (dimension) {
530 case 0:
531 neighborhood = Neighborhoods::SHIFT_M_X;
532 break;
533 case 1:
534 neighborhood = Neighborhoods::SHIFT_M_Y;
535 break;
536 case 2:
537 neighborhood = Neighborhoods::SHIFT_M_Z;
538 break;
539 default:
540 cerr << __FILE__ << ":"<< __LINE__ << " Wrong dimension, abort"<<endl;
541 abort();
542 }
543 }
544
545 // MPI_Barrier(MPI_COMM_WORLD);
546 // cout << "begin update_remote_mapping_contribution_amr, dimension = " << dimension << ", direction = " << direction << endl;
547 // MPI_Barrier(MPI_COMM_WORLD);
548
549 // Initialize remote cells
550 for (auto rc : remote_cells) {
551 SpatialCell *ccell = mpiGrid[rc];
552 // Initialize number of blocks to 0 and block data to a default value.
553 // We need the default for 1 to 1 communications
554 if(ccell) {
555 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
556 ccell->neighbor_block_data[i] = ccell->get_data(popID);
557 ccell->neighbor_number_of_blocks[i] = 0;
558 }
559 }
560 }
561
562 // Initialize local cells
563 for (auto lc : local_cells) {
564 SpatialCell *ccell = mpiGrid[lc];
565 if(ccell) {
566 // Initialize number of blocks to 0 and neighbor block data pointer to the local block data pointer
567 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
568 ccell->neighbor_block_data[i] = ccell->get_data(popID);
569 ccell->neighbor_number_of_blocks[i] = 0;
570 }
571 }
572 }
573
574 vector<Realf*> receiveBuffers;
575 vector<Realf*> sendBuffers;
576
577 for (auto c : local_cells) {
578
579 SpatialCell *ccell = mpiGrid[c];
580
581 if (!ccell) {
582 continue;
583 }
584
585 vector<CellID> p_nbrs;
586 vector<CellID> n_nbrs;
587
588 phiprof::Timer neighTimer {"get face neighbors"};
589 for (const auto& [neighbor, dir] : mpiGrid.get_face_neighbors_of(c)) {
590 if(dir == ((int)dimension + 1) * direction) {
591 p_nbrs.push_back(neighbor);
592 }
593
594 if(dir == -1 * ((int)dimension + 1) * direction) {
595 n_nbrs.push_back(neighbor);
596 }
597 }
598 neighTimer.stop();
599 uint sendIndex = 0;
600 uint recvIndex = 0;
601
602 int mySiblingIndex = get_sibling_index(mpiGrid,c);
603
604 // Set up sends if any neighbor cells in p_nbrs are non-local.
605 phiprof::Timer sendsTimer {"setup sends"};
606 if (!all_of(p_nbrs.begin(), p_nbrs.end(), [&mpiGrid](CellID i){return mpiGrid.is_local(i);})) {
607
608 // ccell adds a neighbor_block_data block for each neighbor in the positive direction to its local data
609 for (const auto& nbr : p_nbrs) {
610
611 //Send data in nbr target array that we just mapped to, if
612 // 1) it is a valid target,
613 // 2) the source cell in center was translated,
614 // 3) Cell is remote.
615 if(nbr != INVALID_CELLID && do_translate_cell(ccell) && !mpiGrid.is_local(nbr)) {
616
617 /*
618 Select the index to the neighbor_block_data and neighbor_number_of_blocks arrays
619 1) Ref_c == Ref_nbr == 0, index = 0
620 2) Ref_c == Ref_nbr != 0, index = c sibling index
621 3) Ref_c > Ref_nbr , index = c sibling index
622 4) Ref_c < Ref_nbr , index = nbr sibling index
623 */
624
625 if(mpiGrid.get_refinement_level(c) >= mpiGrid.get_refinement_level(nbr)) {
626 sendIndex = mySiblingIndex;
627 } else {
628 sendIndex = get_sibling_index(mpiGrid,nbr);
629 }
630
631 SpatialCell *pcell = mpiGrid[nbr];
632
633 // 4) it exists and is not a boundary cell,
635
636 ccell->neighbor_number_of_blocks.at(sendIndex) = pcell->get_number_of_velocity_blocks(popID);
637
638 if(send_cells.find(nbr) == send_cells.end()) {
639 // 5 We have not already sent data from this rank to this cell.
640
641 ccell->neighbor_block_data.at(sendIndex) = pcell->get_data(popID);
642 send_cells.insert(nbr);
643
644 } else {
645
646 // The receiving cell can't know which cell is sending the data from this rank.
647 // Therefore, we have to send 0's from other cells in the case where multiple cells
648 // from one rank are sending to the same remote cell so that all sent cells can be
649 // summed for the correct result.
650
651 ccell->neighbor_block_data.at(sendIndex) =
652 (Realf*) aligned_malloc(ccell->neighbor_number_of_blocks.at(sendIndex) * WID3 * sizeof(Realf), WID3);
653 sendBuffers.push_back(ccell->neighbor_block_data.at(sendIndex));
654 for (uint j = 0; j < ccell->neighbor_number_of_blocks.at(sendIndex) * WID3; ++j) {
655 ccell->neighbor_block_data.at(sendIndex)[j] = 0.0;
656
657 } // closes for(uint j = 0; j < ccell->neighbor_number_of_blocks.at(sendIndex) * WID3; ++j)
658
659 } // closes if(send_cells.find(nbr) == send_cells.end())
660
661 } // closes if(pcell && pcell->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY)
662
663 } // closes if(nbr != INVALID_CELLID && do_translate_cell(ccell) && !mpiGrid.is_local(nbr))
664
665 } // closes for(uint i_nbr = 0; i_nbr < nbrs_to.size(); ++i_nbr)
666
667 } // closes if(!all_of(nbrs_to.begin(), nbrs_to.end(),[&mpiGrid](CellID i){return mpiGrid.is_local(i);}))
668 sendsTimer.stop();
669 phiprof::Timer recvsTimer {"setup recvs"};
670 // Set up receives if any neighbor cells in n_nbrs are non-local.
671 if (!all_of(n_nbrs.begin(), n_nbrs.end(), [&mpiGrid](CellID i){return mpiGrid.is_local(i);})) {
672
673 // ccell adds a neighbor_block_data block for each neighbor in the positive direction to its local data
674 for (const auto& nbr : n_nbrs) {
675
676 if (nbr != INVALID_CELLID && !mpiGrid.is_local(nbr) &&
678 //Receive data that ncell mapped to this local cell data array,
679 //if 1) ncell is a valid source cell, 2) center cell is to be updated (normal cell) 3) ncell is remote
680
681 SpatialCell *ncell = mpiGrid[nbr];
682
683 // Check for null pointer
684 if(!ncell) {
685 continue;
686 }
687
688 /*
689 Select the index to the neighbor_block_data and neighbor_number_of_blocks arrays
690 1) Ref_nbr == Ref_c == 0, index = 0
691 2) Ref_nbr == Ref_c != 0, index = nbr sibling index
692 3) Ref_nbr > Ref_c , index = nbr sibling index
693 4) Ref_nbr < Ref_c , index = c sibling index
694 */
695
696 if(mpiGrid.get_refinement_level(nbr) >= mpiGrid.get_refinement_level(c)) {
697
698 // Allocate memory for one sibling at recvIndex.
699
700 recvIndex = get_sibling_index(mpiGrid,nbr);
701
702 ncell->neighbor_number_of_blocks.at(recvIndex) = ccell->get_number_of_velocity_blocks(popID);
703 ncell->neighbor_block_data.at(recvIndex) =
704 (Realf*) aligned_malloc(ncell->neighbor_number_of_blocks.at(recvIndex) * WID3 * sizeof(Realf), WID3);
705 receiveBuffers.push_back(ncell->neighbor_block_data.at(recvIndex));
706
707 } else {
708
709 recvIndex = mySiblingIndex;
710
711 // std::array<uint64_t, 8> siblingarr = mpiGrid.mapping.get_all_children(mpiGrid.mapping.get_parent(c));
712 // vector<CellID> mySiblings(siblingarr.begin(), siblingarr.end());
713 auto mySiblings = mpiGrid.get_all_children(mpiGrid.get_parent(c));
714 auto myIndices = mpiGrid.mapping.get_indices(c);
715
716 // Allocate memory for each sibling to receive all the data sent by coarser ncell.
717 // only allocate blocks for face neighbors.
718 for (uint i_sib = 0; i_sib < MAX_NEIGHBORS_PER_DIM; ++i_sib) {
719
720 auto sibling = mySiblings.at(i_sib);
721 auto sibIndices = mpiGrid.mapping.get_indices(sibling);
722 auto* scell = mpiGrid[sibling];
723
724
725 // Only allocate siblings that are remote face neighbors to ncell
726 // Also take care to have these consistent with the sending process neighbor checks!
727 if(sibling != INVALID_CELLID
728 && scell
729 && mpiGrid.get_process(sibling) != mpiGrid.get_process(nbr)
730 && myIndices.at(dimension) == sibIndices.at(dimension)
731 && ncell->neighbor_number_of_blocks.at(i_sib) != scell->get_number_of_velocity_blocks(popID)
732 && scell->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
733
734
735 ncell->neighbor_number_of_blocks.at(i_sib) = scell->get_number_of_velocity_blocks(popID);
736 ncell->neighbor_block_data.at(i_sib) =
737 (Realf*) aligned_malloc(ncell->neighbor_number_of_blocks.at(i_sib) * WID3 * sizeof(Realf), WID3);
738 receiveBuffers.push_back(ncell->neighbor_block_data.at(i_sib));
739 }
740 }
741 }
742
743 receive_cells.push_back(c);
744 receive_origin_cells.push_back(nbr);
745 receive_origin_index.push_back(recvIndex);
746
747 } // closes (nbr != INVALID_CELLID && !mpiGrid.is_local(nbr) && ...)
748
749 } // closes for(uint i_nbr = 0; i_nbr < nbrs_of.size(); ++i_nbr)
750
751 } // closes if(!all_of(nbrs_of.begin(), nbrs_of.end(),[&mpiGrid](CellID i){return mpiGrid.is_local(i);}))
752 } // closes for (auto c : local_cells) {
753
754 MPI_Barrier(MPI_COMM_WORLD);
755
756 // Do communication
757 phiprof::Timer commTimer {"update neighbour vel block data"};
760 mpiGrid.update_copies_of_remote_neighbors(neighborhood);
761 commTimer.stop();
762 MPI_Barrier(MPI_COMM_WORLD);
763
764 // Reduce data: sum received data in the data array to
765 // the target grid in the temporary block container
766 //#pragma omp parallel
767 phiprof::Timer reduceTimer {"merge retreived data"};
768 {
769 for (size_t c = 0; c < receive_cells.size(); ++c) {
770 SpatialCell* receive_cell = mpiGrid[receive_cells[c]];
771 SpatialCell* origin_cell = mpiGrid[receive_origin_cells[c]];
772
773 if(!receive_cell || !origin_cell) {
774 continue;
775 }
776
777 Realf *blockData = receive_cell->get_data(popID);
778 Realf *neighborData = origin_cell->neighbor_block_data[receive_origin_index[c]];
779
780 //#pragma omp for
781 for(uint vCell = 0; vCell < WID3 * receive_cell->get_number_of_velocity_blocks(popID); ++vCell) {
782 blockData[vCell] += neighborData[vCell];
783 }
784 }
785
786 // send cell data is set to zero. This is to avoid double copy if
787 // one cell is the neighbor on bot + and - side to the same process
788 for (auto c : send_cells) {
789 SpatialCell* spatial_cell = mpiGrid[c];
790 Realf * blockData = spatial_cell->get_data(popID);
791 //#pragma omp for nowait
792 for(unsigned int vCell = 0; vCell < WID3 * spatial_cell->get_number_of_velocity_blocks(popID); ++vCell) {
793 // copy received target data to temporary array where target data is stored.
794 blockData[vCell] = 0;
795 }
796 }
797 }
798 reduceTimer.stop();
799 for (auto p : receiveBuffers) {
800 aligned_free(p);
801 }
802 for (auto p : sendBuffers) {
803 aligned_free(p);
804 }
805
806 // MPI_Barrier(MPI_COMM_WORLD);
807 // cout << "end update_remote_mapping_contribution_amr, dimension = " << dimension << ", direction = " << direction << endl;
808 // MPI_Barrier(MPI_COMM_WORLD);
809
810}
for i
Definition Dispersion.m:24
dt
Definition Dispersion.m:39
set(gca, 'YDir', 'normal')
Constants c
Definition Dispersion.m:45
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
std::array< Realf *, MAX_NEIGHBORS_PER_DIM > neighbor_block_data
vmesh::LocalID get_velocity_block_local_id(const vmesh::GlobalID &blockGID, const uint popID) const
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)
static vmesh::LocalID invalid_local_id()
static vmesh::LocalID invalidLocalID()
vmesh::GlobalID getGlobalID(const vmesh::LocalID &localID) const
size_t size(bool dummy=0) 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)
void propagatePencil(const Realf *const dz, const Vec *const values, const uint dimension, const uint blockGID, const Realf dt, const vmesh::VelocityMesh *vmesh, const int lengthOfPencil, const Realf threshold, Realf **blockDataPointer, const Realf *const targetRatios, const unsigned int *const vcell_transpose)
bool trans_map_1d_amr(const dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &localPropagatedCells, const vector< CellID > &remoteTargetCells, std::vector< uint > &nPencils, const uint dimension, const Realf dt, const uint popID)
int get_sibling_index(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellid)
bool check_skip_remapping(const Vec *const values)
#define i_trans_ps_blockv_pencil(planeVectorIndex, planeIndex, blockIndex, lengthOfPencil)
void update_remote_mapping_contribution_amr(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint dimension, int direction, const uint popID)
bool copy_trans_block_data_amr(const Realf *const *pencilBlockData, const int lengthOfPencil, Vec *values, const unsigned int *const vcell_transpose, const uint popID)
std::array< setOfPencils, 3 > DimensionPencils
bool do_translate_cell(const SpatialCell *const SC)
const uint32_t cuint
Definition definitions.h:50
#define MAX_NEIGHBORS_PER_DIM
Definition definitions.h:93
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
split::SplitVector< vmesh::GlobalID > * unionOfBlocks
Definition gpu_base.cpp:60
Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > * unionOfBlocksSet
Definition gpu_base.cpp:61
const int j
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 threshold
__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__ 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 * pencilBlocksCount
const Realf vz_min
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint sumOfLengths
__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
#define index(i, j, k)
void * aligned_malloc(size_t size, std::size_t align)
void aligned_free(void *p)
@ VLASOV_SOLVER
Definition common.h:77
static const uint64_t NEIGHBOR_VEL_BLOCK_DATA
std::array< vmesh::LocalID, 3 > velocity_block_indices_t
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
An interface to a type with floating point values.
static ARCH_HOSTDEV bool horizontal_or(VecSimple< T > const &a)
static ARCH_HOSTDEV VecSimple< T > select(VecSimple< bool > const &a, VecSimple< T > const &b, VecSimple< T > const &c)