Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
arch_moments.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2024-2025 University of Helsinki, CSC
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 <phiprof.hpp>
24#include "arch_moments.h"
25#include "vlasovmover.h"
26#include "../object_wrapper.h"
27#include "../fieldsolver/fs_common.h" // divideIfNonZero()
28
29#ifdef USE_GPU
30#include "gpu_moments.h"
31#endif
32
33using namespace std;
34
42 const bool& computeSecond,
43 const bool& computePopulationMomentsOnly,
44 const bool& doNotSkip) {
45
46 // Called once per cell. If doNotSkip == true, then DO_NOT_COMPUTE cells aren't skipped.
47 if (!doNotSkip && cell->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE) {
48 return;
49 }
50
51 // Clear old moments to zero value
52 if (computePopulationMomentsOnly == false) {
53 cell->parameters[CellParams::RHOM ] = 0.0;
54 cell->parameters[CellParams::VX] = 0.0;
55 cell->parameters[CellParams::VY] = 0.0;
56 cell->parameters[CellParams::VZ] = 0.0;
57 cell->parameters[CellParams::RHOQ ] = 0.0;
58 cell->parameters[CellParams::P_11] = 0.0;
59 cell->parameters[CellParams::P_22] = 0.0;
60 cell->parameters[CellParams::P_33] = 0.0;
61 cell->parameters[CellParams::P_23] = 0.0;
62 cell->parameters[CellParams::P_13] = 0.0;
63 cell->parameters[CellParams::P_12] = 0.0;
64 }
65
66 // Loop over all particle species
67 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
68 #ifdef USE_GPU
70 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
71 #else
73 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
74 #endif
75 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
76 Population &pop = cell->get_population(popID);
77 if (nBlocks == 0) {
78 pop.RHO = 0;
79 for (int i=0; i<3; ++i) {
80 pop.V[i]=0;
81 }
82 for (int i=0; i<nMom2; ++i) {
83 pop.P[i]=0;
84 }
85 continue;
86 }
87
88 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
89 const Real charge = getObjectWrapper().particleSpecies[popID].charge;
90
91 // Temporary array for storing moments
92 Real array[nMom1] = {0};
93
94 // Calculate species' contribution to first velocity moments
95 blockVelocityFirstMoments(blockContainer,
96 array,
97 nBlocks);
98 pop.RHO = array[0];
99 pop.V[0] = divideIfNonZero(array[1], array[0]);
100 pop.V[1] = divideIfNonZero(array[2], array[0]);
101 pop.V[2] = divideIfNonZero(array[3], array[0]);
102
103 if (!computePopulationMomentsOnly) {
104 // Store species' contribution to bulk velocity moments
105 cell->parameters[CellParams::RHOM ] += array[0]*mass;
106 cell->parameters[CellParams::VX] += array[1]*mass;
107 cell->parameters[CellParams::VY] += array[2]*mass;
108 cell->parameters[CellParams::VZ] += array[3]*mass;
109 cell->parameters[CellParams::RHOQ ] += array[0]*charge;
110 }
111 } // for-loop over particle species
112
113 if(!computePopulationMomentsOnly) {
117 }
118
119 // Compute second moments only if requested
120 if (computeSecond == false) {
121 return;
122 }
123
124 // Loop over all particle species
125 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
126 #ifdef USE_GPU
128 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
129 #else
131 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
132 #endif
133 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
134 if (nBlocks == 0) {
135 continue;
136 }
137
138 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
139
140 // Temporary array for storing moments
141 Real array[nMom2] = {0};
142
143 // Calculate species' contribution to second velocity moments
144 blockVelocitySecondMoments(blockContainer,
148 array,
149 nBlocks);
150 // Store species' contribution to bulk velocity moments
151 Population &pop = cell->get_population(popID);
152 for (size_t i=0; i<nMom2; ++i) {
153 pop.P[i] = mass * array[i];
154 }
155
156 if (!computePopulationMomentsOnly) {
157 cell->parameters[CellParams::P_11] += pop.P[0];
158 cell->parameters[CellParams::P_22] += pop.P[1];
159 cell->parameters[CellParams::P_33] += pop.P[2];
160 cell->parameters[CellParams::P_23] += pop.P[3];
161 cell->parameters[CellParams::P_13] += pop.P[4];
162 cell->parameters[CellParams::P_12] += pop.P[5];
163 }
164 } // for-loop over particle species
165
166}
167
179 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
180 const std::vector<CellID>& cells,
181 const bool& computeSecond,
182 const bool initialCompute) {
183
184 // override with optimized GPU version to launch
185 // single kernel accessing all cells at once (10x faster)
186 #ifdef USE_GPU
187 gpu_calculateMoments_R(mpiGrid,cells,computeSecond,initialCompute);
188 return;
189 #endif
190
191 phiprof::Timer computeMomentsTimer {"Compute _R moments"};
192 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
193 #pragma omp parallel for schedule(dynamic,1)
194 for (size_t c=0; c<cells.size(); ++c) {
195 SpatialCell* cell = mpiGrid[cells[c]];
196
198 continue;
199 }
200 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
201 continue;
202 }
203 // Clear old moments to zero value
204 if (popID == 0) {
205 cell->parameters[CellParams::RHOM_R ] = 0.0;
206 cell->parameters[CellParams::VX_R] = 0.0;
207 cell->parameters[CellParams::VY_R] = 0.0;
208 cell->parameters[CellParams::VZ_R] = 0.0;
209 cell->parameters[CellParams::RHOQ_R ] = 0.0;
210 cell->parameters[CellParams::P_11_R] = 0.0;
211 cell->parameters[CellParams::P_22_R] = 0.0;
212 cell->parameters[CellParams::P_33_R] = 0.0;
213 cell->parameters[CellParams::P_23_R] = 0.0;
214 cell->parameters[CellParams::P_13_R] = 0.0;
215 cell->parameters[CellParams::P_12_R] = 0.0;
216 }
217
218 #ifdef USE_GPU
220 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
221 #else
223 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
224 #endif
225 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
226 Population &pop = cell->get_population(popID);
227 if (nBlocks == 0) {
228 pop.RHO_R = 0;
229 for (int i=0; i<3; ++i) {
230 pop.V_R[i]=0;
231 }
232 for (int i=0; i<nMom2; ++i) {
233 pop.P_R[i]=0;
234 }
235 continue;
236 }
237 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
238 const Real charge = getObjectWrapper().particleSpecies[popID].charge;
239
240 // Temporary array where the moments for this species are accumulated
241 Real array[nMom1] = {0};
242
243 // Calculate species' contribution to first velocity moments
244 blockVelocityFirstMoments(blockContainer,
245 array,
246 nBlocks);
247 // Store species' contribution to bulk velocity moments
248 pop.RHO_R = array[0];
249 pop.V_R[0] = divideIfNonZero(array[1], array[0]);
250 pop.V_R[1] = divideIfNonZero(array[2], array[0]);
251 pop.V_R[2] = divideIfNonZero(array[3], array[0]);
252
253 cell->parameters[CellParams::RHOM_R ] += array[0]*mass;
254 cell->parameters[CellParams::VX_R] += array[1]*mass;
255 cell->parameters[CellParams::VY_R] += array[2]*mass;
256 cell->parameters[CellParams::VZ_R] += array[3]*mass;
257 cell->parameters[CellParams::RHOQ_R ] += array[0]*charge;
258 } // for-loop over spatial cells
259 } // for-loop over particle species
260
261 #pragma omp parallel for schedule(static)
262 for (size_t c=0; c<cells.size(); ++c) {
263 SpatialCell* cell = mpiGrid[cells[c]];
265 continue;
266 }
267 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
268 continue;
269 }
273 }
274
275 // Compute second moments only if requested.
276 if (computeSecond == false) {
277 return;
278 }
279
280 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
281 #pragma omp parallel for schedule(dynamic,1)
282 for (size_t c=0; c<cells.size(); ++c) {
283 SpatialCell* cell = mpiGrid[cells[c]];
284
286 continue;
287 }
288 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
289 continue;
290 }
291
292 #ifdef USE_GPU
294 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
295 #else
297 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
298 #endif
299 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
300 if (nBlocks == 0) {
301 continue;
302 }
303 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
304
305 // Temporary array where species' contribution to 2nd moments is accumulated
306 Real array[nMom2] = {0};
307
308 // Calculate species' contribution to second velocity moments
309 blockVelocitySecondMoments(blockContainer,
313 array,
314 nBlocks);
315 // Store species' contribution to 2nd bulk velocity moments
316 Population &pop = cell->get_population(popID);
317 for (size_t i = 0; i < nMom2; ++i) {
318 pop.P_R[i] = mass * array[i];
319 }
320
321 cell->parameters[CellParams::P_11_R] += pop.P_R[0];
322 cell->parameters[CellParams::P_22_R] += pop.P_R[1];
323 cell->parameters[CellParams::P_33_R] += pop.P_R[2];
324 cell->parameters[CellParams::P_23_R] += pop.P_R[3];
325 cell->parameters[CellParams::P_13_R] += pop.P_R[4];
326 cell->parameters[CellParams::P_12_R] += pop.P_R[5];
327 } // for-loop over spatial cells
328 } // for-loop over particle species
329}
330
343 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
344 const std::vector<CellID>& cells,
345 const bool& computeSecond,
346 const bool initialCompute) {
347
348 // override with optimized GPU version to launch
349 // single kernel accessing all cells at once (10x faster)
350 #ifdef USE_GPU
351 gpu_calculateMoments_V(mpiGrid,cells,computeSecond,initialCompute);
352 return;
353 #endif
354
355 phiprof::Timer computeMomentsTimer {"Compute _V moments"};
356 // Loop over all particle species
357 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
358 #pragma omp parallel for schedule(dynamic,1)
359 for (size_t c=0; c<cells.size(); ++c) {
360 SpatialCell* cell = mpiGrid[cells[c]];
361
363 continue;
364 }
365 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
366 continue;
367 }
368
369 // Clear old moments to zero value
370 if (popID == 0) {
371 cell->parameters[CellParams::RHOM_V ] = 0.0;
372 cell->parameters[CellParams::VX_V] = 0.0;
373 cell->parameters[CellParams::VY_V] = 0.0;
374 cell->parameters[CellParams::VZ_V] = 0.0;
375 cell->parameters[CellParams::RHOQ_V ] = 0.0;
376 cell->parameters[CellParams::P_11_V] = 0.0;
377 cell->parameters[CellParams::P_22_V] = 0.0;
378 cell->parameters[CellParams::P_33_V] = 0.0;
379 cell->parameters[CellParams::P_23_V] = 0.0;
380 cell->parameters[CellParams::P_13_V] = 0.0;
381 cell->parameters[CellParams::P_12_V] = 0.0;
382 }
383
384 #ifdef USE_GPU
386 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
387 #else
389 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
390 #endif
391 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
392 Population &pop = cell->get_population(popID);
393 if (nBlocks == 0) {
394 pop.RHO_V = 0;
395 for (int i=0; i<3; ++i) {
396 pop.V_V[i]=0;
397 }
398 for (int i=0; i<nMom2; ++i) {
399 pop.P_V[i]=0;
400 }
401 continue;
402 }
403
404 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
405 const Real charge = getObjectWrapper().particleSpecies[popID].charge;
406
407 // Temporary array for storing moments
408 Real array[nMom1] = {0};
409
410 // Calculate species' contribution to first velocity moments
411 blockVelocityFirstMoments(blockContainer,
412 array,
413 nBlocks);
414 // Store species' contribution to bulk velocity moments
415 pop.RHO_V = array[0];
416 pop.V_V[0] = divideIfNonZero(array[1], array[0]);
417 pop.V_V[1] = divideIfNonZero(array[2], array[0]);
418 pop.V_V[2] = divideIfNonZero(array[3], array[0]);
419
420 cell->parameters[CellParams::RHOM_V ] += array[0]*mass;
421 cell->parameters[CellParams::VX_V] += array[1]*mass;
422 cell->parameters[CellParams::VY_V] += array[2]*mass;
423 cell->parameters[CellParams::VZ_V] += array[3]*mass;
424 cell->parameters[CellParams::RHOQ_V ] += array[0]*charge;
425
426 } // for-loop over spatial cells
427 } // for-loop over particle species
428
429 #pragma omp parallel for schedule(static)
430 for (size_t c=0; c<cells.size(); ++c) {
431 SpatialCell* cell = mpiGrid[cells[c]];
433 continue;
434 }
435 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
436 continue;
437 }
441 }
442
443 // Compute second moments only if requested
444 if (computeSecond == false) {
445 return;
446 }
447
448 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
449 #pragma omp parallel for schedule(dynamic,1)
450 for (size_t c=0; c<cells.size(); ++c) {
451 SpatialCell* cell = mpiGrid[cells[c]];
452
454 continue;
455 }
456 if (cell->sysBoundaryFlag == sysboundarytype::OUTFLOW && cell->sysBoundaryLayer != 1 && !initialCompute) { // these should have been handled by the boundary code
457 continue;
458 }
459
460 #ifdef USE_GPU
462 vmesh::VelocityBlockContainer* blockContainer = cell->dev_get_velocity_blocks(popID);
463 #else
465 vmesh::VelocityBlockContainer* blockContainer = cell->get_velocity_blocks(popID);
466 #endif
467 const uint nBlocks = cell->get_velocity_mesh(popID)->size();
468 if (nBlocks == 0) {
469 continue;
470 }
471
472 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
473 const Real charge = getObjectWrapper().particleSpecies[popID].charge;
474
475 // Temporary array where moments are stored
476 Real array[nMom2] = {0};
477
478 // Calculate species' contribution to second velocity moments
479 blockVelocitySecondMoments(blockContainer,
483 array,
484 nBlocks);
485 // Store species' contribution to 2nd bulk velocity moments
486 Population &pop = cell->get_population(popID);
487 for (size_t i = 0; i < nMom2; ++i) {
488 pop.P_V[i] = mass * array[i];
489 }
490
491 cell->parameters[CellParams::P_11_V] += pop.P_V[0];
492 cell->parameters[CellParams::P_22_V] += pop.P_V[1];
493 cell->parameters[CellParams::P_33_V] += pop.P_V[2];
494 cell->parameters[CellParams::P_23_V] += pop.P_V[3];
495 cell->parameters[CellParams::P_13_V] += pop.P_V[4];
496 cell->parameters[CellParams::P_12_V] += pop.P_V[5];
497 } // for-loop over spatial cells
498 } // for-loop over particle species
499}
for i
Definition Dispersion.m:24
Constants c
Definition Dispersion.m:45
void calculateCellMoments(spatial_cell::SpatialCell *cell, const bool &computeSecond, const bool &computePopulationMomentsOnly, const bool &doNotSkip)
void calculateMoments_R(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, const bool &computeSecond, const bool initialCompute)
void calculateMoments_V(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, const bool &computeSecond, const bool initialCompute)
void blockVelocitySecondMoments(vmesh::VelocityBlockContainer *blockContainer, const REAL averageVX, const REAL averageVY, const REAL averageVZ, REAL(&array)[SIZE], uint nBlocks)
#define nMom1
void blockVelocityFirstMoments(vmesh::VelocityBlockContainer *blockContainer, REAL(&array)[SIZE], uint nBlocks)
#define nMom2
vmesh::VelocityMesh * get_velocity_mesh(const size_t &popID)
vmesh::VelocityBlockContainer * get_velocity_blocks(const size_t &popID)
Population & get_population(const uint popID)
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
vmesh::VelocityBlockContainer * dev_get_velocity_blocks(const size_t &popID)
vmesh::VelocityMesh * dev_get_velocity_mesh(const size_t &popID)
size_t size(bool dummy=0) const
float Real
Definition definitions.h:41
Real divideIfNonZero(creal numerator, creal denominator)
Helper function.
Definition fs_common.cpp:33
void gpu_calculateMoments_V(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells_in, const bool computeSecond, const bool initialCompute)
void gpu_calculateMoments_R(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells_in, const bool computeSecond, const bool initialCompute)
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
std::vector< species::Species > particleSpecies