Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
cpu_trans_pencils.hpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2025 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#ifndef CPU_TRANS_PENCILS_H
23#define CPU_TRANS_PENCILS_H
24
25#include <vector>
26#include "vec.h"
27#include <unordered_set>
28#include <dccrg.hpp>
29#include <dccrg_cartesian_geometry.hpp>
30#include <string>
31#include "../common.h"
33
34struct setOfPencils {
35
36 uint N; // Number of pencils in the set
38 std::vector< uint > lengthOfPencils; // Lengths of pencils (including stencil cells)
39 std::vector< CellID > ids; // List of pencil cells (including stencil cells)
40 std::vector< uint > idsStart; // List of where a pencil's CellIDs start in the ids array
41 std::vector< Realf > sourceDZ; // Widths of source cells
42 std::vector< Realf > targetRatios; // Pencil to target cell area ratios of target cells
43 std::vector< Real > x,y; // x,y - position
44 std::vector< bool > periodic;
45 std::vector< std::vector<uint> > path; // Path taken through refinement levels
46
47 std::vector<uint> binOfPencil;
48 std::map<uint, std::vector<uint>> pencilsInBin;
49 std::map<uint, std::set<CellID>> targetCellsInBin;
50 std::vector<uint> activeBins;
51
52 //GPUTODO: move gpu buffers and their upload to separate gpu_trans_pencils .hpp and .cpp files
53#ifdef USE_GPU
54 // Pointers to GPU copies of vectors
55 size_t gpu_lengthOfPencils = 0;
56 size_t gpu_idsStart = 0;
57 size_t gpu_sourceDZ = 0;
58 size_t gpu_targetRatios = 0;
59 size_t dev_pencilsInBin = 0;
60 size_t host_binStart = 0;
61 size_t host_binSize = 0;
62 size_t dev_binStart = 0;
63 size_t dev_binSize = 0;
64
65#endif
66
68 N = 0;
69 sumOfLengths = 0;
70 }
71
73 N = 0;
74 sumOfLengths = 0;
75 lengthOfPencils.clear();
76 idsStart.clear();
77 ids.clear();
78 sourceDZ.clear();
79 targetRatios.clear();
80 x.clear();
81 y.clear();
82 periodic.clear();
83 path.clear();
84 binOfPencil.clear();
85 targetCellsInBin.clear();
86 pencilsInBin.clear();
87 activeBins.clear();
88 }
89
90 void addPencil(std::vector<CellID> idsIn, Real xIn, Real yIn, bool periodicIn, std::vector<uint> pathIn) {
91 N++;
92 // If necessary, add the zero cells to the beginning and end
93 if (idsIn.front() != 0) {
94 idsIn.insert(idsIn.begin(),VLASOV_STENCIL_WIDTH,0);
95 }
96 if (idsIn.back() != 0) {
97 for (int i = 0; i < VLASOV_STENCIL_WIDTH; i++)
98 {
99 idsIn.push_back(0);
100 }
101 }
102 sumOfLengths += idsIn.size();
103 lengthOfPencils.push_back(idsIn.size());
104 idsStart.push_back(ids.size());
105 ids.insert(ids.end(),idsIn.begin(),idsIn.end());
106 sourceDZ.resize(sumOfLengths);
108 x.push_back(xIn);
109 y.push_back(yIn);
110 periodic.push_back(periodicIn);
111 path.push_back(pathIn);
112 }
113
114 void binPencils() {
115 binOfPencil.resize(N);
116
117 // Consider only cells which _any_ pencil writes into for binning,
118 // since read-only cells aren't affected by race conditions
119 std::unordered_set<CellID> allTargetCells = {};
120 #pragma omp parallel for
121 for (uint i = 0; i < sumOfLengths; ++i) {
122 const CellID targ = ids[i];
123 const Realf ratio = targetRatios[i];
124 if (targ && (ratio > 0.0)) {
125 #pragma omp critical
126 allTargetCells.insert(targ);
127 }
128 }
129
130 // Loop over pencils to create initial bins containing all cells in the pencil that are a target cell for any pencil
131 // TODO could be paralellized as well
132 for (uint i = 0; i < N; ++i) {
133 binOfPencil[i] = i;
134 targetCellsInBin[i] = {};
135
136 for (auto id = ids.begin() + idsStart[i]; id < ids.begin() + idsStart[i] + lengthOfPencils[i]; ++id) {
137 // We don't need to consider source and target cells of the pencil separately
138 // as all pencils with source/target cell C must be in the same bin as all pencils with target C
139 if (*id && allTargetCells.contains(*id)) {
140 targetCellsInBin[i].insert(*id);
141 }
142 }
143 }
144
145 // Super ugly!
146 // TODO If anyone knows how to do this more efficiently feel free to fix it
147 std::set<uint> binsToDelete;
148 do {
149 binsToDelete.clear();
150 for (auto& [binIndex1, cellsInBin1] : targetCellsInBin) {
151 if (binsToDelete.contains(binIndex1)) {
152 continue;
153 }
154
155 for (auto& [binIndex2, cellsInBin2] : targetCellsInBin) {
156 if (binIndex1 == binIndex2 || binsToDelete.contains(binIndex2)) {
157 continue;
158 }
159
160 // Check for overlapping cells
161 for (auto cell : cellsInBin2) {
162 if (cellsInBin1.contains(cell)) {
163 binsToDelete.insert(binIndex2);
164
165 // Insert all cells from bin2 to bin1
166 cellsInBin1.insert(cellsInBin2.begin(), cellsInBin2.end());
167
168 // Replace bin2 with bin1 in bins
169 std::replace(binOfPencil.begin(), binOfPencil.end(), binIndex2, binIndex1);
170 break;
171 }
172 }
173 }
174 }
175
176 for (auto bin : binsToDelete) {
177 targetCellsInBin.erase(bin);
178 }
179 } while (!binsToDelete.empty());
180
181 // TODO do this "online" and make variable bins redundant
182 for (uint i = 0; i < N; ++i) {
183 pencilsInBin[binOfPencil[i]].push_back(i);
184 }
185
186 for (auto [bin, pencils] : pencilsInBin) {
187 activeBins.push_back(bin);
188 }
189
190 #ifdef USE_GPU
191 gpuBins();
192 #endif
193 }
194
195 #ifdef USE_GPU
196 void gpuBins(){
197 gpuMemoryManager.createPointer(dev_pencilsInBin);
198 gpuMemoryManager.createPointer(host_binStart);
199 gpuMemoryManager.createPointer(host_binSize);
200 gpuMemoryManager.createPointer(dev_binStart);
201 gpuMemoryManager.createPointer(dev_binSize);
202
203 gpuMemoryManager.allocate(dev_pencilsInBin, sumOfLengths*sizeof(uint));
204 gpuMemoryManager.hostAllocate(host_binStart, activeBins.size()*sizeof(uint));
205 gpuMemoryManager.hostAllocate(host_binSize, activeBins.size()*sizeof(uint));
206 gpuMemoryManager.allocate(dev_binStart, activeBins.size()*sizeof(uint));
207 gpuMemoryManager.allocate(dev_binSize, activeBins.size()*sizeof(uint));
208
209 uint *dev_pencilsInBinPointer = gpuMemoryManager.getPointer<uint>(dev_pencilsInBin);
210 uint *host_binStartPointer = gpuMemoryManager.getPointer<uint>(host_binStart);
211 uint *host_binSizePointer = gpuMemoryManager.getPointer<uint>(host_binSize);
212 uint *dev_binStartPointer = gpuMemoryManager.getPointer<uint>(dev_binStart);
213 uint *dev_binSizePointer = gpuMemoryManager.getPointer<uint>(dev_binSize);
214
215 int offset = 0;
216 for(size_t bin = 0; bin < activeBins.size(); bin++){
217 uint thisBin = activeBins[bin];
218 host_binStartPointer[bin] = offset;
219
220 uint binSize = pencilsInBin[thisBin].size();
221 host_binSizePointer[bin] = binSize;
222
223 CHK_ERR( gpuMemcpy(dev_pencilsInBinPointer + offset, pencilsInBin[thisBin].data(), binSize * sizeof(uint), gpuMemcpyHostToDevice) );
224
225 offset += binSize;
226 }
227
228 CHK_ERR( gpuMemcpy(dev_binStartPointer, host_binStartPointer, activeBins.size() * sizeof(uint), gpuMemcpyHostToDevice) );
229 CHK_ERR( gpuMemcpy(dev_binSizePointer, host_binSizePointer, activeBins.size() * sizeof(uint), gpuMemcpyHostToDevice) );
230 }
231 #endif
232
233 // Never called?
234 void removePencil(const uint pencilId) {
235 x.erase(x.begin() + pencilId);
236 y.erase(y.begin() + pencilId);
237 periodic.erase(periodic.begin() + pencilId);
238 path.erase(path.begin() + pencilId);
239
240 uint ibeg = idsStart[pencilId];
241 ids.erase(ids.begin() + ibeg, ids.begin() + ibeg + lengthOfPencils[pencilId] + 2*VLASOV_STENCIL_WIDTH);
242 targetRatios.erase(targetRatios.begin() + ibeg, targetRatios.begin() + ibeg + lengthOfPencils[pencilId] + 2*VLASOV_STENCIL_WIDTH);
243 sourceDZ.erase(sourceDZ.begin() + ibeg, sourceDZ.begin() + ibeg + lengthOfPencils[pencilId] + 2*VLASOV_STENCIL_WIDTH);
244 idsStart.erase(idsStart.begin() + pencilId);
245
246 N--;
247 sumOfLengths -= lengthOfPencils[pencilId];
248 lengthOfPencils.erase(lengthOfPencils.begin() + pencilId);
249 }
250
251 std::vector<CellID> getIds(const uint pencilId) const {
252 if (pencilId >= N) {
253 std::vector<CellID> idsEmpty;
254 return idsEmpty;
255 }
256 // Use vector range constructor. Only return actual pencil ids, not the stencils at the ends
257 std::vector<CellID>::const_iterator ibeg = ids.begin() + idsStart[pencilId] + VLASOV_STENCIL_WIDTH;
258 std::vector<CellID>::const_iterator iend = ibeg + lengthOfPencils[pencilId] - 2*VLASOV_STENCIL_WIDTH;
259 std::vector<CellID> idsOut(ibeg, iend);
260 return idsOut;
261 }
262
263 // Split one pencil into up to four pencils covering the same space.
264 // dx and dy are the dimensions of the original pencil.
265 void split(const uint myPencilId, const Real dx, const Real dy) {
266 auto myIds = this->getIds(myPencilId);
267
268 // Find paths that members of this pencil may have in other pencils (can happen)
269 // so that we don't add duplicates.
270 std::vector<int> existingSteps;
271
272 #pragma omp parallel for
273 for (uint theirPencilId = 0; theirPencilId < this->N; ++theirPencilId) {
274 if(theirPencilId == myPencilId) {
275 continue;
276 }
277 auto theirIds = this->getIds(theirPencilId);
278 for (auto theirId : theirIds) {
279 for (auto myId : myIds) {
280 if (myId == theirId) {
281 std::vector<uint> theirPath = this->path.at(theirPencilId);
282 std::vector<uint> myPath = this->path.at(myPencilId);
283 if(theirPath.size() > myPath.size()) {
284 bool samePath = true;
285 for (uint i = 0; i < myPath.size(); ++i) {
286 if(myPath.at(i) != theirPath.at(i)) {
287 samePath = false;
288 }
289 }
290
291 if(samePath) {
292 uint theirStep = theirPath.at(myPath.size());
293 #pragma omp critical
294 {
295 existingSteps.push_back(theirStep);
296 }
297 }
298 }
299 }
300 }
301 }
302 } // end parallel region
303
304 bool firstPencil = true;
305 const auto copy_of_path = path.at(myPencilId);
306 const auto copy_of_x = x.at(myPencilId);
307 const auto copy_of_y = y.at(myPencilId);
308
309 // Add those pencils whose steps dont already exist in the pencils struct
310 for (int step = 0; step < 4; ++step) {
311 if (std::any_of(existingSteps.begin(), existingSteps.end(), [step](int i){return step == i;})) {
312 continue;
313 }
314
315 Real signX = 1.0;
316 Real signY = 1.0;
317
318 if(step < 2) {
319 signY = -1.0;
320 }
321
322 if(step % 2 == 0) {
323 signX = -1.0;
324 }
325
326 auto myX = copy_of_x + signX * 0.25 * dx;
327 auto myY = copy_of_y + signY * 0.25 * dy;
328
329 if (firstPencil) {
330 //TODO: set x and y correctly. Right now they are not used anywhere.
331 path.at(myPencilId).push_back(step);
332 x.at(myPencilId) = myX;
333 y.at(myPencilId) = myY;
334 firstPencil = false;
335 } else {
336 auto myPath = copy_of_path;
337 myPath.push_back(step);
338 addPencil(myIds, myX, myY, periodic.at(myPencilId), myPath);
339 }
340 }
341 }
342};
343// Note: Splitting does not handle target or source cells, as those are computed after all pencil splitting has concluded.
344
345bool do_translate_cell(const spatial_cell::SpatialCell* const SC);
346
347// grid.cpp calls this function to both find seed cells and build pencils for all dimensions
348void prepareSeedIdsAndPencils(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid);
349// find seed cells and build pencils for one dimension
350void prepareSeedIdsAndPencils(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
351 const uint dimension);
352
353// pencils used for AMR translation
354extern std::array<setOfPencils,3> DimensionPencils;
355
356// Ghost translation cell lists (no interim comms)
357void prepareGhostTranslationCellLists(const dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
358 const std::vector<CellID>& localPropagatedCells);
359
360// defined in cpu_trans_map_amr.cpp
361extern std::unordered_set<CellID> ghostTranslate_sources_x;
362extern std::unordered_set<CellID> ghostTranslate_sources_y;
363extern std::unordered_set<CellID> ghostTranslate_sources_z;
364extern std::unordered_set<CellID> ghostTranslate_active_x;
365extern std::unordered_set<CellID> ghostTranslate_active_y;
366extern std::unordered_set<CellID> ghostTranslate_active_z;
367
368#endif
for i
Definition Dispersion.m:24
dx
Definition Dispersion.m:38
#define gpuMemcpyHostToDevice
#define CHK_ERR(err)
#define gpuMemcpy
std::unordered_set< CellID > ghostTranslate_sources_x
std::unordered_set< CellID > ghostTranslate_sources_z
std::unordered_set< CellID > ghostTranslate_active_z
std::array< setOfPencils, 3 > DimensionPencils
std::unordered_set< CellID > ghostTranslate_active_x
std::unordered_set< CellID > ghostTranslate_sources_y
std::unordered_set< CellID > ghostTranslate_active_y
void prepareSeedIdsAndPencils(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
void prepareGhostTranslationCellLists(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &localPropagatedCells)
bool do_translate_cell(const spatial_cell::SpatialCell *const SC)
float Real
Definition definitions.h:41
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
GPUMemoryManager gpuMemoryManager
Definition gpu_base.cpp:64
__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__ 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__ const Realf *__restrict__ uint uint uint uint * dev_binSize
__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
uint32_t uint
std::map< uint, std::vector< uint > > pencilsInBin
Vector of pencils in each bin.
std::vector< bool > periodic
void split(const uint myPencilId, const Real dx, const Real dy)
std::vector< Real > x
Definition grid_test.cpp:32
std::vector< uint > activeBins
set of keys in the above two maps
void removePencil(const uint pencilId)
std::vector< CellID > getIds(uint pencilId)
std::vector< uint > binOfPencil
Bin of each pencil.
std::vector< Real > y
Definition grid_test.cpp:32
std::vector< Realf > targetRatios
std::map< uint, std::set< CellID > > targetCellsInBin
Set of source and target cells in each bin which are a target cell of any pencil.
std::vector< Realf > sourceDZ
std::vector< CellID > ids
Definition grid_test.cpp:31
std::vector< uint > idsStart
std::vector< CellID > getIds(const uint pencilId) const
void addPencil(vector< CellID > idsIn, Real xIn, Real yIn)
Definition grid_test.cpp:38
void addPencil(std::vector< CellID > idsIn, Real xIn, Real yIn, bool periodicIn, std::vector< uint > pathIn)
std::vector< uint > lengthOfPencils
Definition grid_test.cpp:30
std::vector< std::vector< uint > > path
An interface to a type with floating point values.