Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
cpu_trans_map.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
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 <algorithm>
24#include <cmath>
25#include <utility>
26
27#ifdef _OPENMP
28#include <omp.h>
29#endif
30
31#include "../grid.h"
32#include "../object_wrapper.h"
33#include "vec.h"
34#include "cpu_1d_plm.hpp"
35#include "cpu_1d_ppm.hpp"
37#include "cpu_1d_pqm.hpp"
38#include "cpu_trans_map.hpp"
39#include "cpu_trans_pencils.hpp" // for do_translate_cell
40
41using namespace std;
42using namespace spatial_cell;
43
44// indices in padded source block, which is of type Vec with VECL
45// element sin each vector. b_k is the block index in z direction in
46// ordinary space [- VLASOV_STENCIL_WIDTH to VLASOV_STENCIL_WIDTH],
47// i,j,k are the cell ids inside on block (i in vector elements).
48// Vectors with same i,j,k coordinates, but in different spatial cells, are consequtive
49//#define i_trans_ps_blockv(j, k, b_k) ( (b_k + VLASOV_STENCIL_WIDTH ) + ( (((j) * WID + (k) * WID2)/VECL) * ( 1 + 2 * VLASOV_STENCIL_WIDTH) ) )
50#define i_trans_ps_blockv(planeVectorIndex, planeIndex, blockIndex) ( (blockIndex) + VLASOV_STENCIL_WIDTH + ( (planeVectorIndex) + (planeIndex) * VEC_PER_PLANE ) * ( 1 + 2 * VLASOV_STENCIL_WIDTH) )
51
52// indices in padded target block, which is of type Vec with VECL
53// element sin each vector. b_k is the block index in z direction in
54// ordinary space, i,j,k are the cell ids inside on block (i in vector
55// elements).
56//#define i_trans_pt_blockv(j, k, b_k) ( ( (j) * WID + (k) * WID2 + ((b_k) + 1 ) * WID3) / VECL )
57#define i_trans_pt_blockv(planeVectorIndex, planeIndex, blockIndex) ( planeVectorIndex + planeIndex * VEC_PER_PLANE + (blockIndex + 1) * VEC_PER_BLOCK)
58
59/*
60 * return INVALID_CELLID if the spatial neighbor does not exist, or if
61 * it is a cell that is not computed. If the
62 * include_first_boundary_layer flag is set, then also first boundary
63 * layer is inlcuded (does not return INVALID_CELLID).
64 * This does not use dccrg's get_neighbor_of function as it does not support computing neighbors for remote cells
65 */
66CellID get_spatial_neighbor(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
67 const CellID& cellID,
68 const bool include_first_boundary_layer,
69 const int spatial_di,
70 const int spatial_dj,
71 const int spatial_dk ) {
72 const dccrg::Types<3>::indices_t indices = mpiGrid.mapping.get_indices(cellID);
73
74 std::set<uint64_t> nbrIDs = mpiGrid.find_cells_at_offset(indices, cellID, 0, {spatial_di, spatial_dj, spatial_dk});
75
76 if(nbrIDs.size() != 1) {
77 std::cerr << "Error: Cell " << cellID << " has more than one neighbour (namely " << nbrIDs.size() << ":" << std::endl;
78 std::cerr << "[";
79 for(auto n : nbrIDs) {
80 std::cerr << n << ", ";
81 }
82 std::cerr << "]" << std::endl;
83
84 abort();
85 }
86
87 //get nbrID
88 CellID nbrID = *nbrIDs.begin();
89 if (nbrID == dccrg::error_cell ) {
90 return INVALID_CELLID;
91 }
92
93 // not existing cell or do not compute
94 if( mpiGrid[nbrID]->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE) {
95 return INVALID_CELLID;
96 }
97
98 //cell on boundary, but not first layer and we want to include
99 //first layer (e.g. when we compute source cells)
100 if( include_first_boundary_layer &&
101 mpiGrid[nbrID]->sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY &&
102 mpiGrid[nbrID]->sysBoundaryLayer != 1 ) {
103 return INVALID_CELLID;
104 }
105
106 //cell on boundary, and we want none of the layers,
107 //invalid.(e.g. when we compute targets)
108 if( !include_first_boundary_layer &&
109 mpiGrid[nbrID]->sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY){
110 return INVALID_CELLID;
111 }
112
113 return nbrID; //no AMR
114}
115
116
117/*
118 * return NULL if the spatial neighbor does not exist, or if
119 * it is a cell that is not computed. If the
120 * include_first_boundary_layer flag is set, then also first boundary
121 * layer is inlcuded (does not return INVALID_CELLID).
122 * This does not use dccrg's get_neighbor_of function as it does not support computing neighbors for remote cells
123
124
125 */
126
127SpatialCell* get_spatial_neighbor_pointer(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
128 const CellID& cellID,
129 const bool include_first_boundary_layer,
130 const int spatial_di,
131 const int spatial_dj,
132 const int spatial_dk ) {
133 CellID nbrID=get_spatial_neighbor(mpiGrid, cellID, include_first_boundary_layer, spatial_di, spatial_dj, spatial_dk);
134
135 if(nbrID!=INVALID_CELLID)
136 return mpiGrid[nbrID];
137 else
138 return NULL;
139}
140
141/*compute spatial neighbors for source stencil with a size of 2*
142 * VLASOV_STENCIL_WIDTH + 1, cellID at VLASOV_STENCIL_WIDTH. First
143 * bondary layer included. Invalid cells are replaced by closest good
144 * cells (i.e. boundary condition uses constant extrapolation for the
145 * stencil values at boundaries*/
146
147void compute_spatial_source_neighbors(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
148 const CellID& cellID,
149 const uint dimension,
150 SpatialCell **neighbors){
151 for(int i = -VLASOV_STENCIL_WIDTH; i <= VLASOV_STENCIL_WIDTH; i++){
152 switch (dimension){
153 case 0:
154 neighbors[i + VLASOV_STENCIL_WIDTH] = get_spatial_neighbor_pointer(mpiGrid, cellID, true, i, 0, 0);
155 break;
156 case 1:
157 neighbors[i + VLASOV_STENCIL_WIDTH] = get_spatial_neighbor_pointer(mpiGrid, cellID, true, 0, i, 0);
158 break;
159 case 2:
160 neighbors[i + VLASOV_STENCIL_WIDTH] = get_spatial_neighbor_pointer(mpiGrid, cellID, true, 0, 0, i);
161 break;
162 }
163 }
164
165 SpatialCell* last_good_cell = mpiGrid[cellID];
166 /*loop to neative side and replace all invalid cells with the closest good cell*/
167 for(int i = -1;i>=-VLASOV_STENCIL_WIDTH;i--){
168 if(neighbors[i + VLASOV_STENCIL_WIDTH] == NULL)
169 neighbors[i + VLASOV_STENCIL_WIDTH] = last_good_cell;
170 else
171 last_good_cell = neighbors[i + VLASOV_STENCIL_WIDTH];
172 }
173
174 last_good_cell = mpiGrid[cellID];
175 /*loop to positive side and replace all invalid cells with the closest good cell*/
176 for(int i = 1; i <= VLASOV_STENCIL_WIDTH; i++){
177 if(neighbors[i + VLASOV_STENCIL_WIDTH] == NULL)
178 neighbors[i + VLASOV_STENCIL_WIDTH] = last_good_cell;
179 else
180 last_good_cell = neighbors[i + VLASOV_STENCIL_WIDTH];
181 }
182}
183
184/*compute spatial target neighbors, stencil has a size of 3. No boundary cells are included*/
185void compute_spatial_target_neighbors(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
186 const CellID& cellID,
187 const uint dimension,
188 SpatialCell **neighbors){
189
190 for(int i = -1; i <= 1; i++){
191 switch (dimension){
192 case 0:
193 neighbors[i + 1] = get_spatial_neighbor_pointer(mpiGrid, cellID, false, i, 0, 0);
194 break;
195 case 1:
196 neighbors[i + 1] = get_spatial_neighbor_pointer(mpiGrid, cellID, false, 0, i, 0);
197 break;
198 case 2:
199 neighbors[i + 1] = get_spatial_neighbor_pointer(mpiGrid, cellID, false, 0, 0, i);
200 break;
201 }
202 }
203
204}
205
206/* Copy the data to the temporary values array, so that the
207 * dimensions are correctly swapped. Also, copy the same block for
208 * then neighboring spatial cells (in the dimension). neighbors
209 * generated with compute_spatial_neighbors_wboundcond).
210 *
211 * This function must be thread-safe.
212 *
213 * @param source_neighbors Array containing the VLASOV_STENCIL_WIDTH closest
214 * spatial neighbors of this cell in the propagated dimension.
215 * @param blockGID Global ID of the velocity block.
216 * @param values Vector where loaded data is stored.
217 * @param cellid_transpose
218 * @param popID ID of the particle species.
219 */
221 const SpatialCell* const* source_neighbors,
222 const vmesh::GlobalID blockGID,
223 Vec* values,
224 const unsigned char* const cellid_transpose,
225 const uint popID) {
226
227 /*load pointers to blocks and prefetch them to L1*/
228 Realf* blockDatas[VLASOV_STENCIL_WIDTH * 2 + 1];
229 for (int b = -VLASOV_STENCIL_WIDTH; b <= VLASOV_STENCIL_WIDTH; ++b) {
230 const SpatialCell* srcCell = source_neighbors[b + VLASOV_STENCIL_WIDTH];
231 const vmesh::LocalID blockLID = srcCell->get_velocity_block_local_id(blockGID,popID);
232 if (blockLID != srcCell->invalid_local_id()) {
233 blockDatas[b + VLASOV_STENCIL_WIDTH] = srcCell->get_data(blockLID,popID);
234 //prefetch storage pointers to L1
235 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]), _MM_HINT_T0);
236 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 64, _MM_HINT_T0);
237 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 128, _MM_HINT_T0);
238 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 192, _MM_HINT_T0);
239 if(VPREC == 8) {
240 //prefetch storage pointers to L1
241 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 256, _MM_HINT_T0);
242 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 320, _MM_HINT_T0);
243 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 384, _MM_HINT_T0);
244 _mm_prefetch((char *)(blockDatas[b + VLASOV_STENCIL_WIDTH]) + 448, _MM_HINT_T0);
245 }
246 }
247 else{
248 blockDatas[b + VLASOV_STENCIL_WIDTH] = NULL;
249 }
250 }
251
252 // Copy volume averages of this block from all spatial cells:
253 for (int b = -VLASOV_STENCIL_WIDTH; b <= VLASOV_STENCIL_WIDTH; ++b) {
254 if(blockDatas[b + VLASOV_STENCIL_WIDTH] != NULL) {
255 Realv blockValues[WID3];
256 const Realf* block_data = blockDatas[b + VLASOV_STENCIL_WIDTH];
257 // Copy data to a temporary array and transpose values so that mapping is along k direction.
258 // spatial source_neighbors already taken care of when
259 // creating source_neighbors table. If a normal spatial cell does not
260 // simply have the block, its value will be its null_block which
261 // is fine. This null_block has a value of zero in data, and that
262 // is thus the velocity space boundary
263 for (uint i=0; i<WID3; ++i) {
264 blockValues[i] = block_data[cellid_transpose[i]];
265 }
266
267 // now load values into the actual values table..
268 uint offset =0;
269 for (uint k=0; k<WID; ++k) {
270 for(uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++){
271 // store data, when reading data from data we swap dimensions
272 // using precomputed plane_index_to_id and cell_indices_to_id
273 values[i_trans_ps_blockv(planeVector, k, b)].load(blockValues + offset);
274 offset += VECL;
275 }
276 }
277 } else {
278 for (uint k=0; k<WID; ++k) {
279 for(uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++) {
280 values[i_trans_ps_blockv(planeVector, k, b)] = Vec(0);
281 }
282 }
283 }
284 }
285}
286
287/*
288 Here we map from the current time step grid, to a target grid which
289 is the lagrangian departure grid (so th grid at timestep +dt,
290 tracked backwards by -dt). This is done in ordinary space in the translation step
291
292 This function can, and should be, safely called in a parallel
293 OpenMP region (as long as it does only one dimension per parallel
294 refion). It is safe as each thread only computes certain blocks (blockID%tnum_threads = thread_num */
295
296bool trans_map_1d(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
297 const vector<CellID>& localPropagatedCells,
298 const vector<CellID>& remoteTargetCells,
299 const uint dimension,
300 const Realv dt,
301 const uint popID) {
302 // values used with an stencil in 1 dimension, initialized to 0.
303 // Contains a block, and its spatial neighbours in one dimension.
304 Realv dz,dvz,vz_min;
305 uint cell_indices_to_id[3]; /*< used when computing id of target cell in block*/
306 unsigned char cellid_transpose[WID3]; /*< defines the transpose for the solver internal (transposed) id: i + j*WID + k*WID2 to actual one*/
307
308 if(localPropagatedCells.size() == 0)
309 return true;
310 //vector with all cells
311 vector<CellID> allCells(localPropagatedCells);
312 allCells.insert(allCells.end(), remoteTargetCells.begin(), remoteTargetCells.end());
313
314 const uint nSourceNeighborsPerCell = 1 + 2 * VLASOV_STENCIL_WIDTH;
315 std::vector<SpatialCell*> allCellsPointer(allCells.size());
316 std::vector<SpatialCell*> sourceNeighbors(localPropagatedCells.size() * nSourceNeighborsPerCell);
317 std::vector<SpatialCell*> targetNeighbors(3 * localPropagatedCells.size() );
318
319 #pragma omp parallel for
320 for(uint celli = 0; celli < allCells.size(); celli++){
321 allCellsPointer[celli] = mpiGrid[allCells[celli]];
322 }
323
324
325 #pragma omp parallel for
326 for(uint celli = 0; celli < localPropagatedCells.size(); celli++){
327 // compute spatial neighbors, separately for targets and source. In
328 // source cells we have a wider stencil and take into account
329 // boundaries. For targets we only have actual cells as we do not
330 // want to propagate boundary cells (array may contain
331 // INVALID_CELLIDs at boundaries).
332 compute_spatial_source_neighbors(mpiGrid, localPropagatedCells[celli], dimension, sourceNeighbors.data() + celli * nSourceNeighborsPerCell);
333 compute_spatial_target_neighbors(mpiGrid, localPropagatedCells[celli], dimension, targetNeighbors.data() + celli * 3);
334 }
335
336
337 //Get a unique sorted list of blockids that are in any of the
338 // propagated cells. First use set for this, then add to vector (may not
339 // be the most nice way to do this and in any case we could do it along
340 // dimension for data locality reasons => copy acc map column code, TODO: FIXME
341 std::unordered_set<vmesh::GlobalID> unionOfBlocksSet;
342
343
344
345 for(uint celli = 0; celli < allCellsPointer.size(); celli++) {
346 vmesh::VelocityMesh<vmesh::GlobalID,vmesh::LocalID>& vmesh = allCellsPointer[celli]->get_velocity_mesh(popID);
347 for (vmesh::LocalID block_i=0; block_i< vmesh.size(); ++block_i) {
348 unionOfBlocksSet.insert(vmesh.getGlobalID(block_i));
349 }
350 }
351
352 std::vector<vmesh::GlobalID> unionOfBlocks;
353 unionOfBlocks.reserve(unionOfBlocksSet.size());
354 for(const auto blockGID: unionOfBlocksSet) {
355 unionOfBlocks.push_back(blockGID);
356 }
357
358
359
360
361 const uint8_t REFLEVEL=0;
362 const vmesh::VelocityMesh<vmesh::GlobalID,vmesh::LocalID>& vmesh = allCellsPointer[0]->get_velocity_mesh(popID);
363 // set cell size in dimension direction
364 dvz = vmesh.getCellSize(REFLEVEL)[dimension];
365 vz_min = vmesh.getMeshMinLimits()[dimension];
366 switch (dimension) {
367 case 0:
368 dz = P::dx_ini;
369 // set values in array that is used to convert block indices
370 // to global ID using a dot product.
371 cell_indices_to_id[0]=WID2;
372 cell_indices_to_id[1]=WID;
373 cell_indices_to_id[2]=1;
374 break;
375 case 1:
376 dz = P::dy_ini;
377 // set values in array that is used to convert block indices
378 // to global ID using a dot product
379 cell_indices_to_id[0]=1;
380 cell_indices_to_id[1]=WID2;
381 cell_indices_to_id[2]=WID;
382 break;
383 case 2:
384 dz = P::dz_ini;
385 // set values in array that is used to convert block indices
386 // to global id using a dot product.
387 cell_indices_to_id[0]=1;
388 cell_indices_to_id[1]=WID;
389 cell_indices_to_id[2]=WID2;
390 break;
391 default:
392 cerr << __FILE__ << ":"<< __LINE__ << " Wrong dimension, abort"<<endl;
393 abort();
394 break;
395 }
396
397 // init plane_index_to_id
398 for (uint k=0; k<WID; ++k) {
399 for (uint j=0; j<WID; ++j) {
400 for (uint i=0; i<WID; ++i) {
401 const uint cell =
402 i * cell_indices_to_id[0] +
403 j * cell_indices_to_id[1] +
404 k * cell_indices_to_id[2];
405 cellid_transpose[ i + j * WID + k * WID2] = cell;
406 }
407 }
408 }
409
410 const Realv i_dz=1.0/dz;
411
412 int mapping_id {phiprof::initializeTimer("mapping")};
413 int store_id {phiprof::initializeTimer("store")};
414
415 #pragma omp parallel
416 {
417 std::vector<Realf> targetBlockData(3 * localPropagatedCells.size() * WID3);
418 std::vector<bool> targetsValid(localPropagatedCells.size());
419 std::vector<vmesh::LocalID> allCellsBlockLocalID(allCells.size());
420
421
422
423 #pragma omp for schedule(guided)
424 for(uint blocki = 0; blocki < unionOfBlocks.size(); blocki++){
425 vmesh::GlobalID blockGID = unionOfBlocks[blocki];
426 phiprof::Timer mappingTimer {mapping_id};
427
428 for(uint celli = 0; celli < allCellsPointer.size(); celli++){
429 allCellsBlockLocalID[celli] = allCellsPointer[celli]->get_velocity_block_local_id(blockGID, popID);
430 }
431
432
433 for(uint celli = 0; celli < localPropagatedCells.size(); celli++){
434 SpatialCell *spatial_cell = allCellsPointer[celli];
435 const CellID cellID = localPropagatedCells[celli];
436 const vmesh::LocalID blockLID = allCellsBlockLocalID[celli];
437
438 //Reset list of valid targets, will be set to true later for those
439 //that are valid
440 targetsValid[celli] = false;
441
443 get_spatial_neighbor(mpiGrid, cellID, true, 0, 0, 0) == INVALID_CELLID) {
444 //do nothing if it is not a normal cell, or a cell that is in the
445 //first boundary layer, or the block does not exist in this
446 //spatial cell
447 continue;
448 }
449
450
451 // Vector buffer where we write data, initialized to 0*/
452 Vec targetVecValues[3 * WID3 / VECL];
453 // init target_values
454 for (uint i = 0; i< 3 * WID3 / VECL; ++i) {
455 targetVecValues[i] = Vec(0.0);
456 }
457
458 // buffer where we read in source data. i index vectorized
459 Vec values[(1 + 2 * VLASOV_STENCIL_WIDTH) * WID3 / VECL];
460 copy_trans_block_data(sourceNeighbors.data() + celli * nSourceNeighborsPerCell, blockGID, values, cellid_transpose, popID);
461 velocity_block_indices_t block_indices;
462 uint8_t refLevel;
463 vmesh.getIndices(blockGID,refLevel, block_indices[0], block_indices[1], block_indices[2]);
464
465 //i,j,k are now relative to the order in which we copied data to the values array.
466 //After this point in the k,j,i loops there should be no branches based on dimensions
467 //
468 //Note that the i dimension is vectorized, and thus there are no loops over i
469 for (uint k=0; k<WID; ++k) {
470 const Realv cell_vz = (block_indices[dimension] * WID + k + 0.5) * dvz + vz_min; //cell centered velocity
471 const Realv z_translation = cell_vz * dt * i_dz; // how much it moved in time dt (reduced units)
472 const int target_scell_index = (z_translation > 0) ? 1: -1; //part of density goes here (cell index change along spatial direcion)
473
474 //the coordinates (scaled units from 0 to 1) between which we will
475 //integrate to put mass in the target neighboring cell.
476 //As we are below CFL<1, we know
477 //that mass will go to two cells: current and the new one.
478 Realv z_1,z_2;
479 if ( z_translation < 0 ) {
480 z_1 = 0;
481 z_2 = -z_translation;
482 } else {
483 z_1 = 1.0 - z_translation;
484 z_2 = 1.0;
485 }
486
487 for (uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++) {
488 //compute reconstruction
489#ifdef TRANS_SEMILAG_PLM
490 Vec a[3];
491 compute_plm_coeff(values + i_trans_ps_blockv(planeVector, k, -VLASOV_STENCIL_WIDTH), VLASOV_STENCIL_WIDTH, a, spatial_cell->getVelocityBlockMinValue(popID));
492#endif
493#ifdef TRANS_SEMILAG_PPM
494 Vec a[3];
495 //Check that stencil width VLASOV_STENCIL_WIDTH in grid.h corresponds to order of face estimates (h4 & h5 =2, H6=3, h8=4)
496 compute_ppm_coeff(values + i_trans_ps_blockv(planeVector, k, -VLASOV_STENCIL_WIDTH), h4, VLASOV_STENCIL_WIDTH, a, spatial_cell->getVelocityBlockMinValue(popID));
497#endif
498#ifdef TRANS_SEMILAG_PQM
499 Vec a[5];
500 //Check that stencil width VLASOV_STENCIL_WIDTH in grid.h corresponds to order of face estimates (h4 & h5 =2, H6=3, h8=4)
501 compute_pqm_coeff(values + i_trans_ps_blockv(planeVector, k, -VLASOV_STENCIL_WIDTH), h6, VLASOV_STENCIL_WIDTH, a, spatial_cell->getVelocityBlockMinValue(popID));
502#endif
503
504#ifdef TRANS_SEMILAG_PLM
505 const Vec ngbr_target_density =
506 z_2 * ( a[0] + z_2 * a[1] ) -
507 z_1 * ( a[0] + z_1 * a[1] );
508#endif
509#ifdef TRANS_SEMILAG_PPM
510 const Vec ngbr_target_density =
511 z_2 * ( a[0] + z_2 * ( a[1] + z_2 * a[2] ) ) -
512 z_1 * ( a[0] + z_1 * ( a[1] + z_1 * a[2] ) );
513#endif
514#ifdef TRANS_SEMILAG_PQM
515 const Vec ngbr_target_density =
516 z_2 * ( a[0] + z_2 * ( a[1] + z_2 * ( a[2] + z_2 * ( a[3] + z_2 * a[4] ) ) ) ) -
517 z_1 * ( a[0] + z_1 * ( a[1] + z_1 * ( a[2] + z_1 * ( a[3] + z_1 * a[4] ) ) ) );
518#endif
519 targetVecValues[i_trans_pt_blockv(planeVector, k, target_scell_index)] += ngbr_target_density; //in the current original cells we will put this density
520 targetVecValues[i_trans_pt_blockv(planeVector, k, 0)] += values[i_trans_ps_blockv(planeVector, k, 0)] - ngbr_target_density; //in the current original cells we will put the rest of the original density
521 }
522 }
523
524 //Store final vector data in temporary data for all target blocks,
525 //and mark that this celli produced valid targets
526
527 targetsValid[celli] = true;
528 for (int b = -1; b< 2 ; ++b) {
529 Realv vector[VECL];
530 for (uint k=0; k<WID; ++k) {
531 for(uint planeVector = 0; planeVector < VEC_PER_PLANE; planeVector++){
532 targetVecValues[i_trans_pt_blockv(planeVector, k, b)].store(vector);
533 #pragma omp simd
534 for(uint i = 0; i< VECL; i++){
535 // store data, when reading data from data we swap
536 // dimensions
537 // using precomputed plane_index_to_id and
538 // cell_indices_to_id
539 targetBlockData[(celli * 3 + b + 1) * WID3 + cellid_transpose[i + planeVector * VECL + k * WID2]] =
540 vector[i];
541 }
542 }
543 }
544 }
545 }
546
547 mappingTimer.stop();
548 phiprof::Timer storeTimer {store_id};
549
550 //reset blocks in all non-sysboundary spatial cells for this block id
551 for(uint celli = 0; celli < allCellsPointer.size(); celli++){
552 SpatialCell* spatial_cell = allCellsPointer[celli];
553 if(spatial_cell->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
554 const vmesh::LocalID blockLID = allCellsBlockLocalID[celli];
556 Realf* blockData = spatial_cell->get_data(blockLID, popID);
557 for(int i = 0; i < WID3; i++) {
558 blockData[i] = 0.0;
559 }
560 }
561 }
562 }
563
564 //store values from target_values array to the actual blocks
565 for(uint celli = 0; celli < localPropagatedCells.size(); celli++){
566 if(targetsValid[celli]) {
567 for(uint ti = 0; ti < 3; ti++) {
568 SpatialCell* spatial_cell = targetNeighbors[celli * 3 + ti];
569 if(spatial_cell ==NULL) {
570 //invalid target spatial cell
571 continue;
572 }
573
574 const vmesh::LocalID blockLID = spatial_cell->get_velocity_block_local_id(blockGID, popID);
576 // block does not exist. If so, we do not create it and add stuff to it here.
577 // We have already created blocks around blocks with content in
578 // spatial sense, so we have no need to create even more blocks here
579 // TODO add loss counter
580 continue;
581 }
582 Realf* blockData = spatial_cell->get_data(blockLID, popID);
583 for(int i = 0; i < WID3 ; i++) {
584 blockData[i] += targetBlockData[(celli * 3 + ti) * WID3 + i];
585 }
586 }
587 }
588
589 }
590 storeTimer.stop();
591
592
593 } //loop over set of blocks on process
594 }
595
596
597 return true;
598}
599
608
610 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
611 const uint dimension,
612 int direction,
613 const uint popID) {
614
615 const vector<CellID>& local_cells = getLocalCells();
616 const vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER);
617 vector<CellID> receive_cells;
618 vector<CellID> send_cells;
619 vector<Realf*> receiveBuffers;
620
621// int myRank;
622// MPI_Comm_rank(MPI_COMM_WORLD,&myRank);
623
624 // MPI_Barrier(MPI_COMM_WORLD);
625 // cout << "begin update_remote_mapping_contribution, dimension = " << dimension << ", direction = " << direction << endl;
626 // MPI_Barrier(MPI_COMM_WORLD);
627
628 //normalize
629 if(direction > 0) direction = 1;
630 if(direction < 0) direction = -1;
631 for (size_t c=0; c<remote_cells.size(); ++c) {
632 SpatialCell *ccell = mpiGrid[remote_cells[c]];
633 //default values, to avoid any extra sends and receives
634 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
635 if(i == 0) {
636 ccell->neighbor_block_data.at(i) = ccell->get_data(popID);
637 } else {
638 ccell->neighbor_block_data.at(i) = NULL;
639 }
640 ccell->neighbor_number_of_blocks.at(i) = 0;
641 }
642 }
643
644 //TODO: prepare arrays, make parallel by avoidin push_back and by checking also for other stuff
645 for (size_t c = 0; c < local_cells.size(); ++c) {
646
647 SpatialCell *ccell = mpiGrid[local_cells[c]];
648 //default values, to avoid any extra sends and receives
649 for (uint i = 0; i < MAX_NEIGHBORS_PER_DIM; ++i) {
650 if(i == 0) {
651 ccell->neighbor_block_data.at(i) = ccell->get_data(popID);
652 } else {
653 ccell->neighbor_block_data.at(i) = NULL;
654 }
655 ccell->neighbor_number_of_blocks.at(i) = 0;
656 }
657 CellID p_ngbr = INVALID_CELLID;
658 CellID m_ngbr = INVALID_CELLID;
659
660 for (const auto& [neighbor, dir] : mpiGrid.get_face_neighbors_of(local_cells[c])) {
661 if(dir == ((int)dimension + 1) * direction) {
662 p_ngbr = neighbor;
663 }
664 if(dir == -1 * ((int)dimension + 1) * direction) {
665 m_ngbr = neighbor;
666 }
667
668 }
669
670 //MPI_Barrier(MPI_COMM_WORLD);
671
672 //internal cell, not much to do
673 if (mpiGrid.is_local(p_ngbr) && mpiGrid.is_local(m_ngbr)) continue;
674
675 SpatialCell *pcell = NULL;
676 if (p_ngbr != INVALID_CELLID) {
677 pcell = mpiGrid[p_ngbr];
678 }
679 SpatialCell *mcell = NULL;
680 if (m_ngbr != INVALID_CELLID) {
681 mcell = mpiGrid[m_ngbr];
682 }
684 if (!mpiGrid.is_local(p_ngbr) && do_translate_cell(ccell)) {
685 //if (p_ngbr != INVALID_CELLID && !mpiGrid.is_local(p_ngbr) && do_translate_cell(ccell)) {
686 //Send data in p_ngbr target array that we just
687 //mapped to if 1) it is a valid target,
688 //2) is remote cell, 3) if the source cell in center was
689 //translated
690 ccell->neighbor_block_data[0] = pcell->get_data(popID);
691
692 #ifdef DDEBUG
693 for(unsigned int cell = 0; cell<VELOCITY_BLOCK_LENGTH * pcell->get_number_of_velocity_blocks(popID); ++cell) {
694 if(isnan( pcell->get_data(popID)[cell] ) || isinf( pcell->get_data(popID)[cell])) {
695 fprintf(stderr,"NaN sent at cell %li, vel cell %i",receive_cells[c], cell);
696 abort();
697 }
698 }
699 #endif
700
701
703 send_cells.push_back(p_ngbr);
704 }
705 if (m_ngbr != INVALID_CELLID &&
706 !mpiGrid.is_local(m_ngbr) &&
708
709 //Receive data that mcell mapped to ccell to this local cell
710 //data array, if 1) m is a valid source cell, 2) center cell is to be updated (normal cell) 3) m is remote
711 //we will here allocate a receive buffer, since we need to aggregate values
713 mcell->neighbor_block_data[0] = (Realf*) aligned_malloc(mcell->neighbor_number_of_blocks[0] * WID3 * sizeof(Realf), 64);
714
715 receive_cells.push_back(local_cells[c]);
716 receiveBuffers.push_back(mcell->neighbor_block_data[0]);
717 }
718 }
719
720 // Do communication
723 switch(dimension) {
724 case 0:
725 if(direction > 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_P_X);
726 if(direction < 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_M_X);
727 break;
728 case 1:
729 if(direction > 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_P_Y);
730 if(direction < 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_M_Y);
731 break;
732 case 2:
733 if(direction > 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_P_Z);
734 if(direction < 0) mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SHIFT_M_Z);
735 break;
736 }
737
738 #pragma omp parallel
739 {
740 //reduce data: sum received data in the data array to
741 // the target grid in the temporary block container
742 for (size_t c=0; c < receive_cells.size(); ++c) {
743 SpatialCell* spatial_cell = mpiGrid[receive_cells[c]];
744 Realf *blockData = spatial_cell->get_data(popID);
745
746 #pragma omp for
747 for(unsigned int cell = 0; cell<VELOCITY_BLOCK_LENGTH * spatial_cell->get_number_of_velocity_blocks(popID); ++cell) {
748 blockData[cell] += receiveBuffers[c][cell];
749 }
750 }
751
752 // send cell data is set to zero. This is to avoid double copy if
753 // one cell is the neighbor on bot + and - side to the same
754 // process
755 for (size_t c=0; c<send_cells.size(); ++c) {
756 SpatialCell* spatial_cell = mpiGrid[send_cells[c]];
757 Realf * blockData = spatial_cell->get_data(popID);
758
759 #pragma omp for nowait
760 for(unsigned int cell = 0; cell< VELOCITY_BLOCK_LENGTH * spatial_cell->get_number_of_velocity_blocks(popID); ++cell) {
761 // copy received target data to temporary array where target data is stored.
762 blockData[cell] = 0;
763 }
764 }
765 }
766
767 //and finally free temporary receive buffer
768 for (size_t c=0; c < receiveBuffers.size(); ++c) {
769 aligned_free(receiveBuffers[c]);
770 }
771
772 // MPI_Barrier(MPI_COMM_WORLD);
773 // cout << "end update_remote_mapping_contribution, dimension = " << dimension << ", direction = " << direction << endl;
774 // MPI_Barrier(MPI_COMM_WORLD);
775
776}
777
for i
Definition Dispersion.m:24
dt
Definition Dispersion.m:39
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()
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
#define WID
Definition common.h:514
const int WID3
Definition common.h:517
const int WID2
Definition common.h:516
static void compute_plm_coeff(const Vec *const values, const uint k, Vec a[2], const Realf threshold)
static void compute_ppm_coeff(const Vec *const values, const face_estimate_order order, const uint k, Vec a[3], const Realf threshold)
static void compute_pqm_coeff(const Vec *__restrict__ values, face_estimate_order order, uint k, Vec a[5], const Realf threshold)
SpatialCell * get_spatial_neighbor_pointer(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const bool include_first_boundary_layer, const int spatial_di, const int spatial_dj, const int spatial_dk)
#define i_trans_ps_blockv(planeVectorIndex, planeIndex, blockIndex)
void copy_trans_block_data(const SpatialCell *const *source_neighbors, const vmesh::GlobalID blockGID, Vec *values, const unsigned char *const cellid_transpose, const uint popID)
void compute_spatial_source_neighbors(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const uint dimension, SpatialCell **neighbors)
bool trans_map_1d(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &localPropagatedCells, const vector< CellID > &remoteTargetCells, const uint dimension, const Realv dt, const uint popID)
CellID get_spatial_neighbor(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const bool include_first_boundary_layer, const int spatial_di, const int spatial_dj, const int spatial_dk)
void update_remote_mapping_contribution(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint dimension, int direction, const uint popID)
void compute_spatial_target_neighbors(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const uint dimension, SpatialCell **neighbors)
#define i_trans_pt_blockv(planeVectorIndex, planeIndex, blockIndex)
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
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
const Realf dvz
const Realf vz_min
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 Real dz_ini
Definition parameters.h:46
static Real dx_ini
Definition parameters.h:44
static Real dy_ini
Definition parameters.h:45
An interface to a type with floating point values.
#define _mm_prefetch(addr, hint)