Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
datareductionoperator.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 <cstdlib>
24#include <mpi.h>
25#include <iostream>
26#include <limits>
27#include <algorithm>
28#include <array>
30#include "../object_wrapper.h"
31
32
33using namespace std;
34
35typedef Parameters P;
36
37namespace DRO {
38
39 // ************************************************************
40 // ***** DEFINITIONS FOR DATAREDUCTIONOPERATOR BASE CLASS *****
41 // ************************************************************
42
45
48
54 bool DataReductionOperator::reduceData(const SpatialCell* cell,char* buffer) {
55 cerr << "ERROR: DataReductionOperator::reduceData called instead of derived class function! (variable" <<
56 getName() << ")" << endl;
57 cerr << " Did you use a diagnostic reducer for writing bulk data?" << endl;
58 return false;
59 }
60
69 cerr << "ERROR: DataReductionOperator::reduceData called instead of derived class function! (variable " <<
70 getName() << ")" << endl;
71 cerr << " Did you use a bulk reducer for writing diagnostic data?" << endl;
72 return false;
73 }
74
75 DataReductionOperatorCellParams::DataReductionOperatorCellParams(const std::string& name,const unsigned int parameterIndex,const unsigned int _vectorSize) :
76 DataReductionOperator(), _parameterIndex {parameterIndex}, vectorSize {_vectorSize}, variableName {name} {}
78
79 bool DataReductionOperatorCellParams::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& _vectorSize) const {
80 dataType = "float";
81 dataSize = sizeof(Real);
82 _vectorSize = vectorSize;
83 return true;
84 }
85
87
89 const char* ptr = reinterpret_cast<const char*>(data);
90 for (uint i = 0; i < vectorSize*sizeof(Real); ++i){
91 buffer[i] = ptr[i];
92 }
93 return true;
94 }
95
97 //If vectorSize is >1 it still works, we just give the first value and no other ones..
98 *buffer=data[0];
99 return true;
100 }
102 for (uint i=0; i<vectorSize; i++) {
103 if(!std::isfinite(cell->parameters[_parameterIndex+i])) {
104 string message = "The DataReductionOperator " + this->getName() + " returned a nan or an inf in its " + std::to_string(i) + "-component.";
105 bailout(true, message, __FILE__, __LINE__);
106 }
107 }
108 data = &(cell->parameters[_parameterIndex]);
109 return true;
110 }
111
113 bool DataReductionOperatorFsGrid::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
114 // These are only set to dmmy values, as this reducer writes its own vlsv dataset anyway
115 dataType = "float";
116 dataSize = sizeof(double);
117 vectorSize = 1;
118 return true;
119 }
121 // This returns false, since it will handle writing itself in writeFsGridData below.
122 return false;
123 }
125 return false;
126 }
128 return true;
129 }
130
132 const std::string& meshName, vlsv::Writer& vlsvWriter,
133 const bool writeAsFloat) {
134 const std::map<std::string, std::string> attribs = {
135 {"mesh", meshName},
136 {"name", variableName},
137 {"unit", unit},
138 {"unitLaTeX", unitLaTeX},
139 {"unitConversion", unitConversion},
140 {"variableLaTeX", variableLaTeX},
141 };
142
143 std::vector<float> varBufferFloat;
144 const std::vector<double> varBuffer = lambda(fieldSolverData);
145 const auto* localSize = &fieldSolverData.fsgrid.getLocalSize()[0];
146 const auto totalSize = localSize[0] * localSize[1] * localSize[2];
147 const auto vectorSize = totalSize == 0 ? 0 : varBuffer.size() / totalSize;
148
149 auto writeArray = [&attribs, &totalSize, &vectorSize, &vlsvWriter](const auto& buf) -> bool {
150 return vlsvWriter.writeArray("VARIABLE", attribs, "float", totalSize, vectorSize, sizeof(buf[0]),
151 reinterpret_cast<const char*>(buf.data()));
152 };
153
154 if(writeAsFloat) {
155 // Convert down to 32bit floats to save output space
156 varBufferFloat.resize(varBuffer.size());
157 std::transform(varBuffer.cbegin(), varBuffer.cend(), varBufferFloat.begin(),
158 [](double v) { return static_cast<float>(v); });
159 }
160
161 const bool success = writeAsFloat ? writeArray(varBufferFloat) : writeArray(varBuffer);
162 if (!success) {
163 string message = "The DataReductionOperator " + this->getName() + " failed to write its data.";
164 bailout(true, message, __FILE__, __LINE__);
165 }
166
167 return true;
168 }
169
171 bool DataReductionOperatorIonosphereElement::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
172 dataType = "float";
173 dataSize = sizeof(double);
174 vectorSize = 1;
175 return true;
176 }
178 // This returns false, since it will handle writing itself in writeIonosphereGridData below.
179 return false;
180 }
182 return false;
183 }
185 return true;
186 }
188 grid, vlsv::Writer& vlsvWriter) {
189
190 // No point in trying to write anything if there is no ionosphere grid.
191 if(grid.elements.size() == 0) {
192 // Note this indicates success, since not writing an empty mesh is quite ok.
193 return true;
194 }
195
196 std::map<std::string,std::string> attribs;
197 attribs["mesh"]="ionosphere";
198 attribs["name"]=variableName;
199 attribs["unit"]=unit;
200 attribs["unitLaTeX"]=unitLaTeX;
201 attribs["unitConversion"]=unitConversion;
202 attribs["variableLaTeX"]=variableLaTeX;
203
204 // Only task 0 of the ionosphere communicator writes, but all other need to sync vectorSize
205 int rank = -1;
206 int worldRank = 0;
207 if(grid.isCouplingInwards || grid.isCouplingOutwards) {
208 MPI_Comm_rank(grid.communicator,&rank);
209 }
210 MPI_Comm_rank(MPI_COMM_WORLD,&worldRank);
211 int vectorSize = 0;
212 if(rank == 0) {
213 std::vector<Real> varBuffer = lambda(grid);
214
215 int vectorSize = varBuffer.size() / grid.elements.size();
216
217 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
218 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
219
220 if(vlsvWriter.writeArray("VARIABLE", attribs, "float", grid.elements.size(), vectorSize, sizeof(Real), reinterpret_cast<const char*>(varBuffer.data())) == false) {
221 string message = "The DataReductionOperator " + this->getName() + " failed to write its data.";
222 bailout(true, message, __FILE__, __LINE__);
223 }
224 } else {
225 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
226 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
227
228 // Dummy write
229 vlsvWriter.writeArray("VARIABLE", attribs, "float", 0, vectorSize, sizeof(Real), nullptr);
230 }
231
232 return true;
233 }
234
237 bool DataReductionOperatorIonosphereNode::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
238 dataType = "float";
239 dataSize = sizeof(double);
240 vectorSize = 1;
241 return true;
242 }
243 bool DataReductionOperatorIonosphereNodeInt::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
244 dataType = "int";
245 dataSize = sizeof(int);
246 vectorSize = 1;
247 return true;
248 }
250 // This returns false, since it will handle writing itself in writeIonosphereGridData below.
251 return false;
252 }
254 // This returns false, since it will handle writing itself in writeIonosphereGridData below.
255 return false;
256 }
258 return false;
259 }
261 return false;
262 }
264 return true;
265 }
267 return true;
268 }
270 grid, vlsv::Writer& vlsvWriter) {
271
272 // skip ionosphere for inital-grid as it breaks
273 if(P::systemWriteName[P::systemWriteName.size() - 1] == "initial-grid") {
274 return true;
275 }
276
277 // No point in trying to write anything if there is no ionosphere grid.
278 if(grid.nodes.size() == 0) {
279 // Note this indicates success, since not writing an empty mesh is quite ok.
280 return true;
281 }
282 std::map<std::string,std::string> attribs;
283 attribs["mesh"]="ionosphere";
284 attribs["name"]=variableName;
285 attribs["centering"]= "node"; // <-- this tells visit the variable is node-centered
286 attribs["unit"]=unit;
287 attribs["unitLaTeX"]=unitLaTeX;
288 attribs["unitConversion"]=unitConversion;
289 attribs["variableLaTeX"]=variableLaTeX;
290
291 // Only task 0 of the ionosphere communicator writes, but all others need to sync vectorSize
292 int rank = -1;
293 int worldRank = 0;
294 if(grid.isCouplingInwards || grid.isCouplingOutwards) {
295 MPI_Comm_rank(grid.communicator,&rank);
296 }
297 MPI_Comm_rank(MPI_COMM_WORLD,&worldRank);
298 int vectorSize = 0;
299 if(rank == 0) {
300 std::vector<Real> varBuffer = lambda(grid);
301
302 vectorSize = varBuffer.size() / grid.nodes.size();
303
304 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
305 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
306
307 if(vlsvWriter.writeArray("VARIABLE", attribs, "float", grid.nodes.size(), vectorSize, sizeof(Real), reinterpret_cast<const char*>(varBuffer.data())) == false) {
308 string message = "The DataReductionOperator " + this->getName() + " failed to write its data.";
309 bailout(true, message, __FILE__, __LINE__);
310 }
311 } else {
312 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
313 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
314
315 // Dummy write
316 vlsvWriter.writeArray("VARIABLE", attribs, "float", 0, vectorSize, sizeof(Real), nullptr);
317 }
318
319 return true;
320 }
321
323
324 // skip ionosphere for inital-grid as it breaks
325 if(P::systemWriteName[P::systemWriteName.size() - 1] == "initial-grid") {
326 return true;
327 }
328
329 // No point in trying to write anything if there is no ionosphere grid.
330 if(grid.nodes.size() == 0) {
331 // Note this indicates success, since not writing an empty mesh is quite ok.
332 return true;
333 }
334 std::map<std::string,std::string> attribs;
335 attribs["mesh"]="ionosphere";
336 attribs["name"]=variableName;
337 attribs["centering"]= "node"; // <-- this tells visit the variable is node-centered
338 attribs["unit"]=unit;
339 attribs["unitLaTeX"]=unitLaTeX;
340 attribs["unitConversion"]=unitConversion;
341 attribs["variableLaTeX"]=variableLaTeX;
342
343 // Only task 0 of the ionosphere communicator writes, but all others need to sync vectorSize
344 int rank = -1;
345 int worldRank = 0;
346 if(grid.isCouplingInwards || grid.isCouplingOutwards) {
347 MPI_Comm_rank(grid.communicator,&rank);
348 }
349 MPI_Comm_rank(MPI_COMM_WORLD,&worldRank);
350 int vectorSize = 0;
351 if(rank == 0) {
352 std::vector<int> varBuffer = lambda(grid);
353
354 vectorSize = varBuffer.size() / grid.nodes.size();
355
356 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
357 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
358
359 if(vlsvWriter.writeArray("VARIABLE", attribs, "int", grid.nodes.size(), vectorSize, sizeof(int), reinterpret_cast<const char*>(varBuffer.data())) == false) {
360 string message = "The DataReductionOperator " + this->getName() + " failed to write its data.";
361 bailout(true, message, __FILE__, __LINE__);
362 }
363 } else {
364 // We need to have vectorSize the same on all ranks, otherwise MPI_COMM_WORLD rank 0 writes a bogus value
365 MPI_Bcast(&vectorSize, 1, MPI_INT, grid.writingRank, MPI_COMM_WORLD);
366
367 // Dummy write
368 vlsvWriter.writeArray("VARIABLE", attribs, "int", 0, vectorSize, sizeof(int), nullptr);
369 }
370
371 return true;
372 }
373
375 bool DataReductionOperatorMPIGridCell::getDataVectorInfo(std::string& dataType, unsigned int& dataSize, unsigned int& vectorSize) const {
376 dataType = "float";
377 dataSize = sizeof(Real);
378 vectorSize = numFloats;
379 return true;
380 }
382 std::vector<Real> varBuffer = lambda(cell);
383
384 assert(varBuffer.size() == (unsigned int)numFloats);
385
386 for(int i=0; i<numFloats; i++) {
387 buffer[i] = varBuffer[i];
388 }
389
390 return true;
391 }
392
393 DataReductionOperatorBVOLDerivatives::DataReductionOperatorBVOLDerivatives(const std::string& name,const unsigned int parameterIndex,const unsigned int vectorSize):
394 DataReductionOperatorCellParams(name,parameterIndex,vectorSize) {
395
396 }
397 //a version with derivatives, this is the only function that is different
402
403
404
405 //------------------ total BVOL ---------------------------------------
408
409 bool VariableBVol::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
410 dataType = "float";
411 dataSize = sizeof(Real);
412 vectorSize = 3;
413 return true;
414 }
415
416 std::string VariableBVol::getName() const {return "vg_b_vol";}
417
418 bool VariableBVol::reduceData(const SpatialCell* cell,char* buffer) {
419 const char* ptr = reinterpret_cast<const char*>(B);
420 for (uint i = 0; i < 3*sizeof(Real); ++i) buffer[i] = ptr[i];
421 return true;
422 }
423
428 if(!(std::isfinite(B[0]) && std::isfinite(B[1]) && std::isfinite(B[2]))) {
429 string message = "The DataReductionOperator " + this->getName() + " returned a nan or an inf.";
430 bailout(true, message, __FILE__, __LINE__);
431 }
432 return true;
433 }
434
435 //MPI rank
438
439 bool MPIrank::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
440 dataType = "int";
441 dataSize = sizeof(int);
442 vectorSize = 1;
443 return true;
444 }
445
446 std::string MPIrank::getName() const {return "vg_rank";}
447
448 bool MPIrank::reduceData(const SpatialCell* cell,char* buffer) {
449 const char* ptr = reinterpret_cast<const char*>(&mpiRank);
450 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
451 return true;
452 }
453
455 int intRank;
456 MPI_Comm_rank(MPI_COMM_WORLD,&intRank);
457 rank = 1.0*intRank;
458 mpiRank = intRank;
459 return true;
460 }
461
462 // BoundaryType
465
466 bool BoundaryType::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
467 dataType = "int";
468 dataSize = sizeof(int);
469 vectorSize = 1;
470 return true;
471 }
472
473 std::string BoundaryType::getName() const {return "vg_boundarytype";}
474
475 bool BoundaryType::reduceData(const SpatialCell* cell,char* buffer) {
476 const char* ptr = reinterpret_cast<const char*>(&boundaryType);
477 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
478 return true;
479 }
480
482 boundaryType = (int)cell->sysBoundaryFlag;
483 return true;
484 }
485
486
487 // BoundaryLayer
490
491 bool BoundaryLayer::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
492 dataType = "int";
493 dataSize = sizeof(int);
494 vectorSize = 1;
495 return true;
496 }
497
498 std::string BoundaryLayer::getName() const {return "vg_boundarylayer";}
499
500 bool BoundaryLayer::reduceData(const SpatialCell* cell,char* buffer) {
501 const char* ptr = reinterpret_cast<const char*>(&boundaryLayer);
502 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
503 return true;
504 }
505
507 boundaryLayer = (int)cell->sysBoundaryLayer;
508 return true;
509 }
510
511 // MLPepochs
516
517 std::string MLPepochs::getName() const {return popName + "/mlp_epochs";}
518
519 bool MLPepochs::reduceData(const SpatialCell* cell,char* buffer) {
520 const char* ptr = reinterpret_cast<const char*>(&epochs);
521 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
522 return true;
523 }
524
525 bool MLPepochs::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
526 dataType = "uint";
527 dataSize = sizeof(uint32_t);
528 vectorSize = 1;
529 return true;
530 }
531
532 bool MLPepochs::reduceDiagnostic(const SpatialCell* cell,Real* buffer) {
533 *buffer = 1.0 * epochs;
534 return true;
535 }
536
539 return true;
540 }
541
542 // MLPerror
547
548 std::string MLPerror::getName() const {return popName + "/mlp_error";}
549
550 bool MLPerror::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
551 dataType = "float";
552 dataSize = sizeof(float);
553 vectorSize = 1;
554 return true;
555 }
556
557 bool MLPerror::reduceData(const SpatialCell* cell,char* buffer) {
558 const char* ptr = reinterpret_cast<const char*>(&error);
559 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
560 return true;
561 }
562
563 bool MLPerror::reduceDiagnostic(const SpatialCell* cell,Real* buffer) {
564 *buffer = 1.0 * error;
565 return true;
566 }
567
570 return true;
571 }
572
573 // Blocks
578
579 bool Blocks::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
580 dataType = "uint";
581 dataSize = sizeof(int);
582 vectorSize = 1;
583 return true;
584 }
585
586 std::string Blocks::getName() const {return popName + "/vg_blocks";}
587
588 bool Blocks::reduceData(const SpatialCell* cell,char* buffer) {
589 const char* ptr = reinterpret_cast<const char*>(&nBlocks);
590 for (uint i = 0; i < sizeof(int); ++i) buffer[i] = ptr[i];
591 return true;
592 }
593
594 bool Blocks::reduceDiagnostic(const SpatialCell* cell,Real* buffer) {
595 *buffer = 1.0 * nBlocks;
596 return true;
597 }
598
601 return true;
602 }
603
604 // Scalar pressure from the stored values which were calculated to be used by the solvers
607
608 std::string VariablePressureSolver::getName() const {return "vg_pressure";}
609
610 bool VariablePressureSolver::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
611 dataType = "float";
612 dataSize = sizeof(Real);
613 vectorSize = 1;
614 return true;
615 }
616
617 bool VariablePressureSolver::reduceData(const SpatialCell* cell,char* buffer) {
618 const char* ptr = reinterpret_cast<const char*>(&Pressure);
619 for (uint i = 0; i < sizeof(Real); ++i) buffer[i] = ptr[i];
620 return true;
621 }
622
625 return true;
626 }
627
628 // YK Adding pressure calculations to Vlasiator.
629 // p_ij = m/3 * integral((v - <V>)_i(v - <V>)_j * f(r,v) dV)
630
631 // Pressure tensor 6 components (11, 22, 33, 23, 13, 12) added by YK
632 // Split into VariablePTensorDiagonal (11, 22, 33)
633 // and VariablePTensorOffDiagonal (23, 13, 12)
638
639 std::string VariablePTensorDiagonal::getName() const {return popName + "/vg_ptensor_diagonal";}
640
641 bool VariablePTensorDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
642 dataType = "float";
643 dataSize = sizeof(Real);
644 vectorSize = 3;
645 return true;
646 }
647
648 bool VariablePTensorDiagonal::reduceData(const SpatialCell* cell,char* buffer) {
649
650 #ifdef USE_GPU
652 #else
654 #endif
655 const Real HALF = 0.5;
656 // ARCH interface includes OpenMP looping including critical regions for thread summation
657 {
658 Real sum[3] = {0.0, 0.0, 0.0};
659 Real averageVX = this->averageVX, averageVY = this->averageVY, averageVZ = this->averageVZ;
660
661 if (cell->get_number_of_velocity_blocks(popID) != 0)
663 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lsum ){
664
665 const Realf *block_data = VBC->getData(n);
666 const Real *block_parameters = VBC->getParameters(n);
667 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
668 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
669 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
670 const Real DV3 = block_parameters[BlockParams::DVX]
671 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
672
673 lsum[0] += block_data[cellIndex(i,j,k)] * (VX - averageVX) * (VX - averageVX) * DV3;
674 lsum[1] += block_data[cellIndex(i,j,k)] * (VY - averageVY) * (VY - averageVY) * DV3;
675 lsum[2] += block_data[cellIndex(i,j,k)] * (VZ - averageVZ) * (VZ - averageVZ) * DV3;
676 }, sum);
677
678 PTensor[0] = sum[0] * getObjectWrapper().particleSpecies[popID].mass;
679 PTensor[1] = sum[1] * getObjectWrapper().particleSpecies[popID].mass;
680 PTensor[2] = sum[2] * getObjectWrapper().particleSpecies[popID].mass;
681 }
682
683 const char* ptr = reinterpret_cast<const char*>(&PTensor);
684 for (uint i = 0; i < 3*sizeof(Real); ++i) buffer[i] = ptr[i];
685 return true;
686 }
687
689 averageVX = cell-> parameters[CellParams::VX];
690 averageVY = cell-> parameters[CellParams::VY];
691 averageVZ = cell-> parameters[CellParams::VZ];
692 for(int i = 0; i < 3; i++) {
693 PTensor[i] = 0.0;
694 }
695 return true;
696 }
697
702
703 std::string VariablePTensorOffDiagonal::getName() const {return popName + "/vg_ptensor_offdiagonal";}
704
705 bool VariablePTensorOffDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
706 dataType = "float";
707 dataSize = sizeof(Real);
708 vectorSize = 3;
709 return true;
710 }
711
713 #ifdef USE_GPU
715 #else
717 #endif
718 const Real HALF = 0.5;
719 // ARCH interface includes OpenMP looping including critical regions for thread summation
720 {
721 Real sum[3] = {0.0, 0.0, 0.0};
722 Real averageVX = this->averageVX, averageVY = this->averageVY, averageVZ = this->averageVZ;
723
724 if (cell->get_number_of_velocity_blocks(popID) != 0)
726 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
727
728 const Realf *block_data = VBC->getData(n);
729 const Real *block_parameters = VBC->getParameters(n);
730 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
731 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
732 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
733 const Real DV3 = block_parameters[BlockParams::DVX]
734 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
735
736 lsum[0] += block_data[cellIndex(i,j,k)] * (VX - averageVX) * (VY - averageVY) * DV3;
737 lsum[1] += block_data[cellIndex(i,j,k)] * (VZ - averageVZ) * (VX - averageVX) * DV3;
738 lsum[2] += block_data[cellIndex(i,j,k)] * (VY - averageVY) * (VZ - averageVZ) * DV3;
739 }, sum);
740
741 PTensor[0] = sum[0] * getObjectWrapper().particleSpecies[popID].mass;
742 PTensor[1] = sum[1] * getObjectWrapper().particleSpecies[popID].mass;
743 PTensor[2] = sum[2] * getObjectWrapper().particleSpecies[popID].mass;
744
745 }
746 const char* ptr = reinterpret_cast<const char*>(&PTensor);
747 for (uint i = 0; i < 3*sizeof(Real); ++i) buffer[i] = ptr[i];
748 return true;
749 }
750
752 averageVX = cell-> parameters[CellParams::VX];
753 averageVY = cell-> parameters[CellParams::VY];
754 averageVZ = cell-> parameters[CellParams::VZ];
755 for(int i = 0; i < 3; i++) {
756 PTensor[i] = 0.0;
757 }
758 return true;
759 }
760
761 /********
762 Next level of helper functions - these include threading and calculate zeroth or first velocity moments or the
763 diagonal / off-diagonal pressure tensor components for
764 thermal or non-thermal populations ********/
765
766 //Calculates rho thermal or rho non-thermal
767 static void rhoNonthermalCalculation( const SpatialCell * cell, const bool calculateNonthermal, cuint popID, Real & rho ) {
768 creal HALF = 0.5;
769 creal thermalRadius = getObjectWrapper().particleSpecies[popID].thermalRadius;
770 const std::array<Real, 3> thermalV = getObjectWrapper().particleSpecies[popID].thermalV;
771
772 #ifdef USE_GPU
774 #else
775 const vmesh::VelocityBlockContainer* VBC = cell->get_velocity_blocks(popID);
776 #endif
777
778 // ARCH interface includes OpenMP looping including critical regions for thread summation
779 {
780 Real thread_n_sum = 0.0;
781 Real thermalV0 = thermalV[0];
782 Real thermalV1 = thermalV[1];
783 Real thermalV2 = thermalV[2];
784
785 if (cell->get_number_of_velocity_blocks(popID) != 0)
787 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
788
789 const Realf *block_data = VBC->getData(n);
790 const Real *block_parameters = VBC->getParameters(n);
791 const Real DV3 = block_parameters[BlockParams::DVX] * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
792
793 // Go through every velocity cell (i, j, k are indices)
794 ARCH_INNER_BODY(i, j, k, n, lsum) {
795 // Get the vx, vy, vz coordinates of the velocity cell
796 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF) * block_parameters[BlockParams::DVX];
797 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF) * block_parameters[BlockParams::DVY];
798 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF) * block_parameters[BlockParams::DVZ];
799 // Compare the distance of the velocity cell from the center of the maxwellian distribution to the radius of the maxwellian distribution
800 if (((calculateNonthermal == true) &&
801 (( (thermalV0 - VX) * (thermalV0 - VX)
802 + (thermalV1 - VY) * (thermalV1 - VY)
803 + (thermalV2 - VZ) * (thermalV2 - VZ) )
804 > thermalRadius*thermalRadius))
805 ||
806 ((calculateNonthermal == false) &&
807 (( (thermalV0 - VX) * (thermalV0 - VX)
808 + (thermalV1 - VY) * (thermalV1 - VY)
809 + (thermalV2 - VZ) * (thermalV2 - VZ) )
810 <= thermalRadius*thermalRadius) )) {
811 //The velocity cell is a part of the nonthermal/thermal population:
812 lsum[0] += block_data[cellIndex(i,j,k)] * DV3;
813 }
814 };
815 }, thread_n_sum);
816 rho = thread_n_sum;
817 }
818 return;
819 }
820
821 static void VNonthermalCalculation( const SpatialCell * cell, const bool calculateNonthermal, cuint popID, Real * V ) {
822 creal HALF = 0.5;
823 const std::array<Real, 3> thermalV = getObjectWrapper().particleSpecies[popID].thermalV;
824 creal thermalRadius = getObjectWrapper().particleSpecies[popID].thermalRadius;
825
826 // Make sure the V is initialized
827 V[0] = 0;
828 V[1] = 0;
829 V[2] = 0;
830 Real n_sum = 0;
831
832 #ifdef USE_GPU
834 #else
835 const vmesh::VelocityBlockContainer* VBC = cell->get_velocity_blocks(popID);
836 #endif
837
838 // ARCH interface includes OpenMP looping including critical regions for thread summation
839 {
840
841 Real sum[4] = {0};
842 Real thermalV0 = thermalV[0];
843 Real thermalV1 = thermalV[1];
844 Real thermalV2 = thermalV[2];
845
846 if (cell->get_number_of_velocity_blocks(popID) != 0)
848 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
849
850 const Realf *block_data = VBC->getData(n);
851 const Real *block_parameters = VBC->getParameters(n);
852 // Get the volume of a velocity cell
853 const Real DV3 = block_parameters[BlockParams::DVX] * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
854
855 // Go through a block's every velocity cell
856 ARCH_INNER_BODY(i, j, k, n, lsum) {
857 // Get the coordinates of the velocity cell (e.g. VX = block_vx_min_coordinates + (velocity_cell_indice_x+0.5)*length_of_velocity_cell_in_x_direction
858 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF) * block_parameters[BlockParams::DVX];
859 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF) * block_parameters[BlockParams::DVY];
860 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF) * block_parameters[BlockParams::DVZ];
861 // Calculate the distance of the velocity cell from the center of the maxwellian distribution and compare it to the approximate radius of the maxwellian distribution
862 if (((calculateNonthermal == true) &&
863 (( (thermalV0 - VX) * (thermalV0 - VX)
864 + (thermalV1 - VY) * (thermalV1 - VY)
865 + (thermalV2 - VZ) * (thermalV2 - VZ) )
866 > thermalRadius*thermalRadius))
867 ||
868 ((calculateNonthermal == false) &&
869 (( (thermalV0 - VX) * (thermalV0 - VX)
870 + (thermalV1 - VY) * (thermalV1 - VY)
871 + (thermalV2 - VZ) * (thermalV2 - VZ) )
872 <= thermalRadius*thermalRadius) )) {
873 // Add the value of the coordinates and multiply by the AVGS value of the velocity cell and the volume of the velocity cell
874 lsum[0] += block_data[cellIndex(i,j,k)]*VX*DV3;
875 lsum[1] += block_data[cellIndex(i,j,k)]*VY*DV3;
876 lsum[2] += block_data[cellIndex(i,j,k)]*VZ*DV3;
877 lsum[3] += block_data[cellIndex(i,j,k)]*DV3;
878 }
879 };
880 }, sum);
881
882 V[0] = sum[0];
883 V[1] = sum[1];
884 V[2] = sum[2];
885 n_sum = sum[3];
886 }
887
888 // Finally, divide n_sum*V by V.
889 V[0]/=n_sum;
890 V[1]/=n_sum;
891 V[2]/=n_sum;
892
893 return;
894 }
895
897 const bool calculateNonthermal,
898 const Real averageVX,
899 const Real averageVY,
900 const Real averageVZ,
901 cuint popID,
902 Real * PTensor ) {
903 creal HALF = 0.5;
904 const std::array<Real, 3> thermalV = getObjectWrapper().particleSpecies[popID].thermalV;
905 creal thermalRadius = getObjectWrapper().particleSpecies[popID].thermalRadius;
906
907 #ifdef USE_GPU
909 #else
910 const vmesh::VelocityBlockContainer* VBC = cell->get_velocity_blocks(popID);
911 #endif
912
913 // ARCH interface includes OpenMP looping including critical regions for thread summation
914 {
915 Real sum[3] = {0};
916 Real thermalV0 = thermalV[0];
917 Real thermalV1 = thermalV[1];
918 Real thermalV2 = thermalV[2];
919
920 if (cell->get_number_of_velocity_blocks(popID) != 0)
922 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
923
924 const Realf *block_data = VBC->getData(n);
925 const Real *block_parameters = VBC->getParameters(n);
926 // Get the volume of a velocity cell
927 const Real DV3 = block_parameters[BlockParams::DVX] * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
928
929 ARCH_INNER_BODY(i, j, k, n, lsum) {
930 // Get the coordinates of the velocity cell (e.g. VX = block_vx_min_coordinates + (velocity_cell_indice_x+0.5)*length_of_velocity_cell_in_x_direction
931 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF) * block_parameters[BlockParams::DVX];
932 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF) * block_parameters[BlockParams::DVY];
933 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF) * block_parameters[BlockParams::DVZ];
934 // Calculate the distance of the velocity cell from the center of the maxwellian distribution and compare it to the approximate radius of the maxwellian distribution
935 if (((calculateNonthermal == true) &&
936 (( (thermalV0 - VX) * (thermalV0 - VX)
937 + (thermalV1 - VY) * (thermalV1 - VY)
938 + (thermalV2 - VZ) * (thermalV2 - VZ) )
939 > thermalRadius*thermalRadius))
940 ||
941 ((calculateNonthermal == false) &&
942 (( (thermalV0 - VX) * (thermalV0 - VX)
943 + (thermalV1 - VY) * (thermalV1 - VY)
944 + (thermalV2 - VZ) * (thermalV2 - VZ) )
945 <= thermalRadius*thermalRadius ))) {
946 lsum[0] += block_data[cellIndex(i,j,k)] * (VX - averageVX) * (VX - averageVX) * DV3;
947 lsum[1] += block_data[cellIndex(i,j,k)] * (VY - averageVY) * (VY - averageVY) * DV3;
948 lsum[2] += block_data[cellIndex(i,j,k)] * (VZ - averageVZ) * (VZ - averageVZ) * DV3;
949 }
950 };
951 }, sum);
952
953 PTensor[0] = sum[0] * getObjectWrapper().particleSpecies[popID].mass;
954 PTensor[1] = sum[1] * getObjectWrapper().particleSpecies[popID].mass;
955 PTensor[2] = sum[2] * getObjectWrapper().particleSpecies[popID].mass;
956
957 }
958 return;
959 }
960
962 const bool calculateNonthermal,
963 const Real averageVX,
964 const Real averageVY,
965 const Real averageVZ,
966 cuint popID,
967 Real * PTensor ) {
968 creal HALF = 0.5;
969 const std::array<Real, 3> thermalV = getObjectWrapper().particleSpecies[popID].thermalV;
970 creal thermalRadius = getObjectWrapper().particleSpecies[popID].thermalRadius;
971
972 #ifdef USE_GPU
974 #else
975 const vmesh::VelocityBlockContainer* VBC = cell->get_velocity_blocks(popID);
976 #endif
977
978 // ARCH interface includes OpenMP looping including critical regions for thread summation
979 {
980 Real sum[3] = {0};
981 Real thermalVX = thermalV[0];
982 Real thermalVY = thermalV[1];
983 Real thermalVZ = thermalV[2];
984
985 if (cell->get_number_of_velocity_blocks(popID) != 0)
987 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
988
989 const Realf *block_data = VBC->getData(n);
990 const Real *block_parameters = VBC->getParameters(n);
991 // Get the volume of a velocity cell
992 const Real DV3 = block_parameters[BlockParams::DVX] * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
993
994 ARCH_INNER_BODY(i, j, k, n, lsum) {
995 // Get the coordinates of the velocity cell (e.g. VX = block_vx_min_coordinates + (velocity_cell_indice_x+0.5)*length_of_velocity_cell_in_x_direction
996 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF) * block_parameters[BlockParams::DVX];
997 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF) * block_parameters[BlockParams::DVY];
998 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF) * block_parameters[BlockParams::DVZ];
999 // Calculate the distance of the velocity cell from the center of the maxwellian distribution and compare it to the approximate radius of the maxwellian distribution
1000 if (((calculateNonthermal == true) &&
1001 (( (thermalVX - VX) * (thermalVX - VX)
1002 + (thermalVY - VY) * (thermalVY - VY)
1003 + (thermalVZ - VZ) * (thermalVZ - VZ) )
1004 > thermalRadius*thermalRadius))
1005 ||
1006 ((calculateNonthermal == false) &&
1007 (( (thermalVX - VX) * (thermalVX - VX)
1008 + (thermalVY - VY) * (thermalVY - VY)
1009 + (thermalVZ - VZ) * (thermalVZ - VZ) )
1010 <= thermalRadius*thermalRadius ))) {
1011 lsum[0] += block_data[cellIndex(i,j,k)] * (VX - averageVX) * (VY - averageVY) * DV3;
1012 lsum[1] += block_data[cellIndex(i,j,k)] * (VZ - averageVZ) * (VX - averageVX) * DV3;
1013 lsum[2] += block_data[cellIndex(i,j,k)] * (VY - averageVY) * (VZ - averageVZ) * DV3;
1014 }
1015 };
1016 }, sum);
1017
1018 PTensor[0] = sum[0] * getObjectWrapper().particleSpecies[popID].mass;
1019 PTensor[1] = sum[1] * getObjectWrapper().particleSpecies[popID].mass;
1020 PTensor[2] = sum[2] * getObjectWrapper().particleSpecies[popID].mass;
1021
1022 }
1023 return;
1024 }
1025
1026 /*********
1027 End velocity moment / thermal/non-thermal helper functions
1028 *********/
1029
1030 // Rho nonthermal:
1036
1037 std::string VariableRhoNonthermal::getName() const {return popName + "/vg_rho_nonthermal";}
1038
1039 bool VariableRhoNonthermal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1040 dataType = "float";
1041 dataSize = sizeof(Real);
1042 vectorSize = (doSkip == true) ? 0 : 1;
1043 return true;
1044 }
1045
1046 bool VariableRhoNonthermal::reduceData(const SpatialCell* cell,char* buffer) {
1047 const bool calculateNonthermal = true;
1048 rhoNonthermalCalculation( cell, calculateNonthermal, popID, RhoNonthermal );
1049 const char* ptr = reinterpret_cast<const char*>(&RhoNonthermal);
1050 for (uint i = 0; i < sizeof(Real); ++i) buffer[i] = ptr[i];
1051 return true;
1052 }
1053
1055 RhoNonthermal = 0.0;
1056 return true;
1057 }
1058
1059 // Rho thermal:
1062 doSkip = (getObjectWrapper().particleSpecies[popID].thermalRadius == 0.0) ? true : false;
1063 }
1065
1066 std::string VariableRhoThermal::getName() const {return popName + "/vg_rho_thermal";}
1067
1068 bool VariableRhoThermal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1069 dataType = "float";
1070 dataSize = sizeof(Real);
1071 vectorSize = (doSkip == true) ? 0 : 1;
1072 return true;
1073 }
1074
1075 bool VariableRhoThermal::reduceData(const SpatialCell* cell,char* buffer) {
1076 const bool calculateNonthermal = false; //We don't want nonthermal
1077 rhoNonthermalCalculation( cell, calculateNonthermal, popID, RhoThermal );
1078 const char* ptr = reinterpret_cast<const char*>(&RhoThermal);
1079 for (uint i = 0; i < sizeof(Real); ++i) buffer[i] = ptr[i];
1080 return true;
1081 }
1082
1084 RhoThermal = 0.0;
1085 return true;
1086 }
1087
1088 // v nonthermal:
1094
1095 std::string VariableVNonthermal::getName() const {return popName + "/vg_v_nonthermal";}
1096
1097 bool VariableVNonthermal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1098 dataType = "float";
1099 dataSize = sizeof(Real);
1100 vectorSize = (doSkip == true) ? 0 : 3;
1101 return true;
1102 }
1103
1104 bool VariableVNonthermal::reduceData(const SpatialCell* cell,char* buffer) {
1105 const bool calculateNonthermal = true;
1106 //Calculate v nonthermal
1107 VNonthermalCalculation( cell, calculateNonthermal, popID, VNonthermal );
1108 const uint VNonthermalSize = 3;
1109 const char* ptr = reinterpret_cast<const char*>(&VNonthermal);
1110 for (uint i = 0; i < VNonthermalSize*sizeof(Real); ++i) buffer[i] = ptr[i];
1111 return true;
1112 }
1113
1115 // Initialize values
1116 for( uint i = 0; i < 3; ++i ) {
1117 VNonthermal[i] = 0.0;
1118 }
1119 return true;
1120 }
1121
1122 //v thermal:
1125 doSkip = (getObjectWrapper().particleSpecies[popID].thermalRadius == 0.0) ? true : false;
1126 }
1128
1129 std::string VariableVThermal::getName() const {return popName + "/vg_v_thermal";}
1130
1131 bool VariableVThermal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1132 dataType = "float";
1133 dataSize = sizeof(Real);
1134 vectorSize = (doSkip == true) ? 0 : 3;
1135 return true;
1136 }
1137
1138 bool VariableVThermal::reduceData(const SpatialCell* cell,char* buffer) {
1139 const bool calculateNonthermal = false;
1140 //Calculate v nonthermal
1141 VNonthermalCalculation( cell, calculateNonthermal, popID, VThermal );
1142 const uint vectorSize = 3;
1143 const char* ptr = reinterpret_cast<const char*>(&VThermal);
1144 for (uint i = 0; i < vectorSize*sizeof(Real); ++i) buffer[i] = ptr[i];
1145 return true;
1146 }
1147
1149 // Initialize values
1150 for( uint i = 0; i < 3; ++i ) {
1151 VThermal[i] = 0.0;
1152 }
1153 return true;
1154 }
1155
1156 // Adding pressure calculations for nonthermal population to Vlasiator.
1157 // p_ij = m/3 * integral((v - <V>)_i(v - <V>)_j * f(r,v) dV)
1158
1159 // Pressure tensor 6 components (11, 22, 33, 23, 13, 12) added by YK
1160 // Split into VariablePTensorNonthermalDiagonal (11, 22, 33)
1161 // and VariablePTensorNonthermalOffDiagonal (23, 13, 12)
1167
1168 std::string VariablePTensorNonthermalDiagonal::getName() const {return popName + "/vg_ptensor_nonthermal_diagonal";}
1169
1170 bool VariablePTensorNonthermalDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1171 dataType = "float";
1172 dataSize = sizeof(Real);
1173 vectorSize = (doSkip == true) ? 0 : 3;
1174 return true;
1175 }
1176
1178 const bool calculateNonthermal = true;
1179 //Calculate PTensor and save it in PTensorArray:
1181 const uint vectorSize = 3;
1182 //Save the data into buffer:
1183 const char* ptr = reinterpret_cast<const char*>(&PTensor);
1184 for (uint i = 0; i < vectorSize*sizeof(Real); ++i) buffer[i] = ptr[i];
1185 return true;
1186 }
1187
1189 //Get v of the nonthermal:
1190 Real V[3] = {0};
1191 const bool calculateNonthermal = true; //We are calculating nonthermal
1192 VNonthermalCalculation( cell, calculateNonthermal, popID, V );
1193 //Set the average velocities:
1194 averageVX = V[0];
1195 averageVY = V[1];
1196 averageVZ = V[2];
1197 const uint vectorSize = 3;
1198 for(uint i = 0; i < vectorSize; i++) {
1199 PTensor[i] = 0.0;
1200 }
1201 return true;
1202 }
1203
1204 // Adding pressure calculations for thermal population to Vlasiator.
1205 // p_ij = m/3 * integral((v - <V>)_i(v - <V>)_j * f(r,v) dV)
1206
1207 // Pressure tensor 6 components (11, 22, 33, 23, 13, 12) added by YK
1208 // Split into VariablePTensorThermalDiagonal (11, 22, 33)
1209 // and VariablePTensorThermalOffDiagonal (23, 13, 12)
1215
1216 std::string VariablePTensorThermalDiagonal::getName() const {return popName + "/vg_ptensor_thermal_diagonal";}
1217
1218 bool VariablePTensorThermalDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1219 dataType = "float";
1220 dataSize = sizeof(Real);
1221 vectorSize = (doSkip == true) ? 0 : 3;
1222 return true;
1223 }
1224
1226 const bool calculateNonthermal = false;
1227 //Calculate PTensor and save it in PTensorArray:
1229 const uint vectorSize = 3;
1230 //Save the data into buffer:
1231 const char* ptr = reinterpret_cast<const char*>(&PTensor);
1232 for (uint i = 0; i < vectorSize*sizeof(Real); ++i) buffer[i] = ptr[i];
1233 return true;
1234 }
1235
1237 //Get v of the thermal:
1238 Real V[3] = {0};
1239 const bool calculateNonthermal = false; //We are not calculating nonthermal
1240 VNonthermalCalculation( cell, calculateNonthermal, popID, V );
1241 //Set the average velocities:
1242 averageVX = V[0];
1243 averageVY = V[1];
1244 averageVZ = V[2];
1245 const uint vectorSize = 3;
1246 for(uint i = 0; i < vectorSize; i++) {
1247 PTensor[i] = 0.0;
1248 }
1249 return true;
1250 }
1251
1257
1258 std::string VariablePTensorNonthermalOffDiagonal::getName() const {return popName + "/vg_ptensor_nonthermal_offdiagonal";}
1259
1260 bool VariablePTensorNonthermalOffDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1261 dataType = "float";
1262 dataSize = sizeof(Real);
1263 vectorSize = (doSkip == true) ? 0 : 3;
1264 return true;
1265 }
1266
1268 //Calculate PTensor for PTensorArray:
1269 const bool calculateNonthermal = true;
1270 //Calculate and save:
1272 const uint vectorSize = 3;
1273 //Input data into buffer
1274 const char* ptr = reinterpret_cast<const char*>(&PTensor);
1275 for (uint i = 0; i < vectorSize*sizeof(Real); ++i) {
1276 buffer[i] = ptr[i];
1277 }
1278 return true;
1279 }
1280
1282 //Get v of the nonthermal:
1283 Real V[3] = {0};
1284 const bool calculateNonthermal = true; //We are calculating nonthermal
1285 VNonthermalCalculation( cell, calculateNonthermal, popID, V );
1286 //Set the average velocities:
1287 averageVX = V[0];
1288 averageVY = V[1];
1289 averageVZ = V[2];
1290 for(int i = 0; i < 3; i++) {
1291 PTensor[i] = 0.0;
1292 }
1293 return true;
1294 }
1295
1301
1302 std::string VariablePTensorThermalOffDiagonal::getName() const {return popName + "/vg_ptensor_thermal_offdiagonal";}
1303
1304 bool VariablePTensorThermalOffDiagonal::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1305 dataType = "float";
1306 dataSize = sizeof(Real);
1307 vectorSize = (doSkip == true) ? 0 : 3;
1308 return true;
1309 }
1310
1312 //Calculate PTensor for PTensorArray:
1313 const bool calculateNonthermal = false;
1314 //Calculate and save:
1316 const uint vectorSize = 3;
1317 //Input data into buffer
1318 const char* ptr = reinterpret_cast<const char*>(&PTensor);
1319 for (uint i = 0; i < vectorSize*sizeof(Real); ++i) {
1320 buffer[i] = ptr[i];
1321 }
1322 return true;
1323 }
1324
1326 //Get v of the nonthermal:
1327 Real V[3] = {0};
1328 const bool calculateNonthermal = false; //We are not calculating nonthermal
1329 VNonthermalCalculation( cell, calculateNonthermal, popID, V );
1330 //Set the average velocities:
1331 averageVX = V[0];
1332 averageVY = V[1];
1333 averageVZ = V[2];
1334 for(int i = 0; i < 3; i++) {
1335 PTensor[i] = 0.0;
1336 }
1337 return true;
1338 }
1339
1340
1345
1346 bool VariableEffectiveSparsityThreshold::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1347 dataType = "float";
1348 dataSize = sizeof(Real);
1349 vectorSize = 1;
1350 return true;
1351 }
1352
1353 std::string VariableEffectiveSparsityThreshold::getName() const {return popName + "/vg_effectivesparsitythreshold";}
1354
1356 Real dummy;
1357 reduceDiagnostic(cell,&dummy);
1358 const char* ptr = reinterpret_cast<const char*>(&dummy);
1359 for (uint i = 0; i < sizeof(Real); ++i) buffer[i] = ptr[i];
1360 return true;
1361 }
1362
1364 *result = cell->getVelocityBlockMinValue(popID);
1365 return true;
1366 }
1367
1371
1383 lossConeAngle = getObjectWrapper().particleSpecies[popID].precipitationLossConeAngle; // deg
1384 emin = getObjectWrapper().particleSpecies[popID].precipitationEmin; // already converted to SI
1385 emax = getObjectWrapper().particleSpecies[popID].precipitationEmax; // already converted to SI
1386 nChannels = getObjectWrapper().particleSpecies[popID].precipitationNChannels; // number of energy channels, logarithmically spaced between emin and emax
1387 for (int i=0; i<nChannels; i++){
1388 channels.push_back(emin * pow(emax/emin,(Real)i/(nChannels-1)));
1389 }
1390 }
1392
1393 std::string VariablePrecipitationDiffFlux::getName() const {return popName + "/vg_precipitationdifferentialflux";}
1394
1395 bool VariablePrecipitationDiffFlux::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1396 dataType = "float";
1397 dataSize = sizeof(Real);
1398 vectorSize = nChannels; //Number of energy channels
1399 return true;
1400 }
1401
1403
1404 dataDiffFlux.assign(nChannels,0.0);
1405
1406 std::vector<Real> sumWeights(nChannels,0.0);
1407
1408 std::array<Real,3> B;
1412
1413 Real cosAngle = cos(lossConeAngle*M_PI/180.0); // cosine of fixed loss cone angle
1414
1415 // Unit B-field direction
1416 creal normB = sqrt(B[0]*B[0] + B[1]*B[1] + B[2]*B[2]);
1417 for (uint i=0; i<3; i++){
1418 B[i] /= normB;
1419 }
1420
1421 // If southern hemisphere, loss cone is around -B
1422 if (cell->parameters[CellParams::ZCRD] + 0.5*cell->parameters[CellParams::DZ] < 0.0){
1423 for (uint i=0; i<3; i++){
1424 B[i] = -B[i];
1425 }
1426 }
1427
1428 #ifdef USE_GPU
1430 #else
1432 #endif
1433
1434 // ARCH interface includes OpenMP looping including critical regions for thread summation
1435 {
1436 std::vector<Real> sum(2 * nChannels,0.0);
1437 int nChannelsLocal = nChannels;
1438 Real B0 = B[0];
1439 Real B1 = B[1];
1440 Real B2 = B[2];
1441 Real emaxLocal = emax;
1442 Real eminLocal = emin;
1443
1444 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
1445 if (cell->get_number_of_velocity_blocks(popID) != 0)
1447 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum )-> void {
1448
1449 const Realf *block_data = VBC->getData(n);
1450 const Real *block_parameters = VBC->getParameters(n);
1451 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1452 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1453 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1454 const Real DV3 = block_parameters[BlockParams::DVX]
1455 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1456
1457 const Real normV = sqrt(VX*VX + VY*VY + VZ*VZ);
1458 const Real VdotB_norm = (B0*VX + B1*VY + B2*VZ)/normV;
1459 Real countAndGate = floor(VdotB_norm/cosAngle); // gate function: 0 outside loss cone, 1 inside
1460 countAndGate = max(0.,countAndGate);
1461 const Real energy = HALF * mass * normV*normV; // in SI
1462
1463 // Find the correct energy bin number to update
1464 int binNumber = round((log(energy) - log(eminLocal)) / log(emaxLocal/eminLocal) * (nChannelsLocal-1));
1465 binNumber = max(binNumber,0); // anything < emin goes to the lowest channel
1466 binNumber = min(binNumber,nChannelsLocal-1); // anything > emax goes to the highest channel
1467
1468 lsum[binNumber] += block_data[cellIndex(i,j,k)] * countAndGate * normV*normV * DV3;
1469 lsum[nChannelsLocal + binNumber] += countAndGate * DV3;
1470 }, sum);
1471
1472 // Place ARCH results in correct buffers
1473 for (int i=0; i<nChannels; i++) {
1474 dataDiffFlux[i] += sum[i];
1475 sumWeights[i] += sum[nChannels + i];
1476 }
1477 }
1478
1479 // Averaging within each bin and conversion to unit of part. cm-2 s-1 sr-1 ev-1
1480 for (int i=0; i<nChannels; i++) {
1481 if (sumWeights[i] != 0) {
1482 dataDiffFlux[i] *= 1.0 / (getObjectWrapper().particleSpecies[popID].mass * sumWeights[i]) * physicalconstants::CHARGE * 1.0e-4;
1483 }
1484 }
1485
1486 const char* ptr = reinterpret_cast<const char*>(dataDiffFlux.data());
1487 for (uint i = 0; i < nChannels*sizeof(Real); ++i) buffer[i] = ptr[i];
1488 return true;
1489 }
1490
1492 return true;
1493 }
1494
1495 bool VariablePrecipitationDiffFlux::writeParameters(vlsv::Writer& vlsvWriter) {
1496 for (int i=0; i<nChannels; i++) {
1497 const Real channelev = channels[i]/physicalconstants::CHARGE; // in eV
1498 if( vlsvWriter.writeParameter(popName+"_PrecipitationCentreEnergy"+std::to_string(i), &channelev) == false ) { return false; }
1499 }
1500 if( vlsvWriter.writeParameter(popName+"_LossConeAngle", &lossConeAngle) == false ) { return false; }
1501 return true;
1502 }
1503
1511
1512 std::string VariableMuSpace::getName() const {return popName + "/vg_1dmuspace";}
1513
1514 bool VariableMuSpace::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1515 dataType = "float";
1516 dataSize = sizeof(Real);
1517 vectorSize = nBins;
1518 return true;
1519 }
1520
1521 bool VariableMuSpace::reduceData(const SpatialCell* cell,char* buffer) {
1522
1523 const Realf dmubins = 2.0 / nBins;
1524 std::vector<Real> fmu(nBins,0.0);
1525
1526 #ifdef USE_GPU
1528 #else
1530 #endif
1531
1532 // ARCH interface includes OpenMP looping including critical regions for thread summation
1533 {
1534 const Real bulkVX = cell->parameters[CellParams::VX];
1535 const Real bulkVY = cell->parameters[CellParams::VY];
1536 const Real bulkVZ = cell->parameters[CellParams::VZ];
1537
1541 const Real Bnorm = sqrt(B0*B0 + B1*B1 + B2*B2);
1542 const Real b0 = B0/Bnorm;
1543 const Real b1 = B1/Bnorm;
1544 const Real b2 = B2/Bnorm;
1545 const int nBins_lambda = nBins; // so lambda does not need to capture *this
1546
1547 if (cell->get_number_of_velocity_blocks(popID) != 0)
1549 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum )-> void {
1550
1551 const Realf *block_data = VBC->getData(n);
1552 const Real *block_parameters = VBC->getParameters(n);
1553 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1554 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1555 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1556 const Real DV3 = block_parameters[BlockParams::DVX]
1557 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1558
1559 const Real VplasmaX = VX - bulkVX;
1560 const Real VplasmaY = VY - bulkVY;
1561 const Real VplasmaZ = VZ - bulkVZ;
1563
1564 const Real Vpara = VplasmaX*b0 + VplasmaY*b1 + VplasmaZ*b2;
1565 const Real mu = Vpara/(normV+std::numeric_limits<Realf>::min()); // + min value to avoid division by 0
1566 int muindex = floor((mu+1.0) / dmubins);
1567 muindex = std::max(0,std::min(muindex,nBins_lambda-1));
1568
1569 lsum[muindex] += block_data[cellIndex(i,j,k)] * DV3 / dmubins;
1570 }, fmu);
1571 }
1572
1573 const char* ptr = reinterpret_cast<const char*>(fmu.data());
1574 for (uint i = 0; i < nBins*sizeof(Real); ++i) buffer[i] = ptr[i];
1575 return true;
1576 }
1577
1579 return true;
1580 }
1581
1582 bool VariableMuSpace::writeParameters(vlsv::Writer& vlsvWriter) {
1583 return true;
1584 }
1585
1597 emin = getObjectWrapper().particleSpecies[popID].precipitationEmin; // already converted to SI
1598 emax = getObjectWrapper().particleSpecies[popID].precipitationEmax; // already converted to SI
1599 nChannels = getObjectWrapper().particleSpecies[popID].precipitationNChannels; // number of energy channels, logarithmically spaced between emin and emax
1600 for (int i=0; i<nChannels; i++){
1601 channels.push_back(emin * pow(emax/emin,(Real)i/(nChannels-1)));
1602 }
1603 }
1605
1606 std::string VariablePrecipitationLineDiffFlux::getName() const {return popName + "/vg_precipitationlinedifferentialflux";}
1607
1608 bool VariablePrecipitationLineDiffFlux::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1609 dataType = "float";
1610 dataSize = sizeof(Real);
1611 vectorSize = nChannels; //Number of energy channels
1612 return true;
1613 }
1614
1616
1617 dataLineDiffFlux.assign(nChannels,0.0);
1618
1619 std::vector<Real> sumWeights(nChannels,0.0);
1620
1621 std::array<Real,3> B;
1625
1626 // Unit B-field direction
1627 creal normB = sqrt(B[0]*B[0] + B[1]*B[1] + B[2]*B[2]);
1628 for (uint i=0; i<3; i++){
1629 B[i] /= normB;
1630 }
1631
1632 // If southern hemisphere, precipitation is along -B
1633 if (cell->parameters[CellParams::ZCRD] + HALF*cell->parameters[CellParams::DZ] < 0.0){
1634 for (uint i=0; i<3; i++){
1635 B[i] = -B[i];
1636 }
1637 }
1638
1639 // ARCH interface includes OpenMP looping including critical regions for thread summation
1640 {
1641 #ifdef USE_GPU
1643 #else
1645 #endif
1646
1647 std::vector<Real> sum(2 * nChannels,0.0);
1648 int nChannelsLocal = nChannels;
1649 Real B0 = B[0];
1650 Real B1 = B[1];
1651 Real B2 = B[2];
1652 Real emaxLocal = emax;
1653 Real eminLocal = emin;
1654 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
1655
1656 if (cell->get_number_of_velocity_blocks(popID) != 0)
1658 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lsum ){
1659 const Realf *block_data = VBC->getData(n);
1660 const Real *block_parameters = VBC->getParameters(n);
1661 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1662 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1663 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1664 const Real DV3 = block_parameters[BlockParams::DVX]
1665 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1666
1667 const Real normV = sqrt(VX*VX + VY*VY + VZ*VZ);
1668 Real BnormV[3];
1669 BnormV[0] = B0 * normV;
1670 BnormV[1] = B1 * normV;
1671 BnormV[2] = B2 * normV;
1672
1673 // We will use a gate function based on criteria that Vi-HALF*DVi <= BnormV[i] <= Vi+HALF*DVi (for i=x,y,z or 0,1,2)
1674 bool xGateCrit, yGateCrit, zGateCrit;
1675 const Real _DVX= block_parameters[BlockParams::DVX];
1676 const Real _DVY= block_parameters[BlockParams::DVY];
1677 const Real _DVZ= block_parameters[BlockParams::DVZ];
1678 xGateCrit = (BnormV[0] - (VX - HALF*_DVX)) * (BnormV[0] - (VX + HALF*_DVX)) <= 0;
1679 yGateCrit = (BnormV[1] - (VY - HALF*_DVY)) * (BnormV[1] - (VY + HALF*_DVY)) <= 0;
1680 zGateCrit = (BnormV[2] - (VZ - HALF*_DVZ)) * (BnormV[2] - (VZ + HALF*_DVZ)) <= 0;
1681 bool xyzGateCrit = xGateCrit && yGateCrit && zGateCrit; // gate function: 1 if the line goes through the v-cell, else 0.
1682 Real countAndGate = (Real) xyzGateCrit;
1683 const Real energy = HALF * mass * normV*normV; // in SI
1684
1685 // Find the correct energy bin number to update
1686 int binNumber = round((log(energy) - log(eminLocal)) / log(emaxLocal/eminLocal) * (nChannelsLocal-1));
1687 binNumber = max(binNumber,0); // anything < eminLocal goes to the lowest channel
1688 binNumber = min(binNumber,nChannelsLocal-1); // anything > emaxLocal goes to the highest channel
1689
1690 lsum[binNumber] += block_data[cellIndex(i,j,k)] * countAndGate * normV*normV * DV3;
1691 lsum[nChannelsLocal + binNumber] += countAndGate * DV3;
1692 }, sum);
1693
1694 // Place ARCH results in correct buffers
1695 for (int i=0; i<nChannels; i++) {
1696 dataLineDiffFlux[i] += sum[i];
1697 sumWeights[i] += sum[nChannels + i];
1698 }
1699 }
1700
1701 // Averaging within each bin and conversion to unit of part. cm-2 s-1 sr-1 ev-1
1702 for (int i=0; i<nChannels; i++) {
1703 if (sumWeights[i] != 0) {
1704 dataLineDiffFlux[i] *= 1.0 / (getObjectWrapper().particleSpecies[popID].mass * sumWeights[i]) * physicalconstants::CHARGE * 1.0e-4;
1705 }
1706 }
1707
1708 const char* ptr = reinterpret_cast<const char*>(dataLineDiffFlux.data());
1709 for (uint i = 0; i < nChannels*sizeof(Real); ++i) buffer[i] = ptr[i];
1710 return true;
1711 }
1712
1714 return true;
1715 }
1716
1718 for (int i=0; i<nChannels; i++) {
1719 const Real channelev = channels[i]/physicalconstants::CHARGE; // in eV
1720 if( vlsvWriter.writeParameter(popName+"_PrecipitationCentreEnergyLine"+std::to_string(i), &channelev) == false ) { return false; }
1721 }
1722 return true;
1723 }
1724
1746
1747 std::string VariableEnergyDensity::getName() const {return popName + "/vg_energydensity";}
1748
1749 bool VariableEnergyDensity::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1750 dataType = "float";
1751 dataSize = sizeof(Real);
1752 vectorSize = 3; // This is not components, but rather total energy density, density over E1, and density over E2
1753 return true;
1754 }
1755
1756 bool VariableEnergyDensity::reduceData(const SpatialCell* cell,char* buffer) {
1757 const Real HALF = 0.5;
1758 #ifdef USE_GPU
1760 #else
1762 #endif
1763
1764 // ARCH interface includes OpenMP looping including critical regions for thread summation
1765 {
1766 Real sum[3] = {0.0, 0.0, 0.0};
1767 Real E1limitLocal = E1limit;
1768 Real E2limitLocal = E2limit;
1769 const Real mass = getObjectWrapper().particleSpecies[popID].mass;
1770
1771 if (cell->get_number_of_velocity_blocks(popID) != 0)
1773 ARCH_LOOP_LAMBDA (const uint i, const uint j, const uint k, const uint n, Real *lsum ) {
1774
1775 const Realf *block_data = VBC->getData(n);
1776 const Real *block_parameters = VBC->getParameters(n);
1777 const Real DV3 = block_parameters[BlockParams::DVX]
1778 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1779
1780 ARCH_INNER_BODY(i, j, k, n, lsum) {
1781 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1782 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1783 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1784 const Real ENERGY = (VX*VX + VY*VY + VZ*VZ) * HALF * mass;
1785 lsum[0] += block_data[cellIndex(i,j,k)] * ENERGY * DV3;
1786 if (ENERGY > E1limitLocal) lsum[1] += block_data[cellIndex(i,j,k)] * ENERGY * DV3;
1787 if (ENERGY > E2limitLocal) lsum[2] += block_data[cellIndex(i,j,k)] * ENERGY * DV3;
1788 };
1789 }, sum);
1790
1791 EDensity[0] = sum[0];
1792 EDensity[1] = sum[1];
1793 EDensity[2] = sum[2];
1794
1795 }
1796
1797 // Output energy density in units eV/cm^3 instead of Joules per m^3
1798 EDensity[0] *= (1.0e-6)/physicalconstants::CHARGE;
1799 EDensity[1] *= (1.0e-6)/physicalconstants::CHARGE;
1800 EDensity[2] *= (1.0e-6)/physicalconstants::CHARGE;
1801
1802 const char* ptr = reinterpret_cast<const char*>(&EDensity);
1803 for (uint i = 0; i < 3*sizeof(Real); ++i) buffer[i] = ptr[i];
1804 return true;
1805 }
1806
1808 for(int i = 0; i < 3; i++) {
1809 EDensity[i] = 0.0;
1810 }
1811 return true;
1812 }
1813
1814 bool VariableEnergyDensity::writeParameters(vlsv::Writer& vlsvWriter) {
1815 // Output solar wind energy in eV
1817 // Output other bin limits as multipliers
1818 Real e1l = getObjectWrapper().particleSpecies[popID].EnergyDensityLimit1;
1819 Real e2l = getObjectWrapper().particleSpecies[popID].EnergyDensityLimit2;
1820
1821 if( vlsvWriter.writeParameter(popName+"_EnergyDensityESW", &swe) == false ) { return false; }
1822 if( vlsvWriter.writeParameter(popName+"_EnergyDensityELimit1", &e1l) == false ) { return false; }
1823 if( vlsvWriter.writeParameter(popName+"_EnergyDensityELimit2", &e2l) == false ) { return false; }
1824 return true;
1825 }
1826
1827 // Heat flux density vector
1828 // q_i = m/2 * integral((v - <V>)^2 (v - <V>)_i * f(r,v) dV)
1833
1834 std::string VariableHeatFluxVector::getName() const {return popName + "/vg_heatflux";}
1835
1836 bool VariableHeatFluxVector::getDataVectorInfo(std::string& dataType,unsigned int& dataSize,unsigned int& vectorSize) const {
1837 dataType = "float";
1838 dataSize = sizeof(Real);
1839 vectorSize = 3;
1840 return true;
1841 }
1842
1843 bool VariableHeatFluxVector::reduceData(const SpatialCell* cell,char* buffer) {
1844
1845 #ifdef USE_GPU
1847 #else
1849 #endif
1850
1851 const Real HALF = 0.5;
1852
1853 // ARCH interface includes OpenMP looping including critical regions for thread summation
1854 {
1855 Real sum[3] = {0.0, 0.0, 0.0};
1856 Real averageVX = this->averageVX, averageVY = this->averageVY, averageVZ = this->averageVZ;
1857 if (cell->get_number_of_velocity_blocks(popID) != 0)
1859 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lsum ){
1860 const Realf *block_data = VBC->getData(n);
1861 const Real *block_parameters = VBC->getParameters(n);
1862 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1863 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1864 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1865 const Real DV3 = block_parameters[BlockParams::DVX]
1866 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1867 const Real VSQ
1868 = (VX - averageVX) * (VX - averageVX)
1869 + (VY - averageVY) * (VY - averageVY)
1870 + (VZ - averageVZ) * (VZ - averageVZ);
1871
1872 lsum[0] += block_data[cellIndex(i,j,k)] * VSQ * (VX - averageVX) * DV3;
1873 lsum[1] += block_data[cellIndex(i,j,k)] * VSQ * (VY - averageVY) * DV3;
1874 lsum[2] += block_data[cellIndex(i,j,k)] * VSQ * (VZ - averageVZ) * DV3;
1875 }, sum);
1876
1877 HeatFlux[0] = sum[0] * HALF * getObjectWrapper().particleSpecies[popID].mass;
1878 HeatFlux[1] = sum[1] * HALF * getObjectWrapper().particleSpecies[popID].mass;
1879 HeatFlux[2] = sum[2] * HALF * getObjectWrapper().particleSpecies[popID].mass;
1880 }
1881 const char* ptr = reinterpret_cast<const char*>(&HeatFlux);
1882 for (uint i = 0; i < 3*sizeof(Real); ++i) buffer[i] = ptr[i];
1883 return true;
1884 }
1885
1887 averageVX = cell-> parameters[CellParams::VX];
1888 averageVY = cell-> parameters[CellParams::VY];
1889 averageVZ = cell-> parameters[CellParams::VZ];
1890 for(int i = 0; i < 3; i++) {
1891 HeatFlux[i] = 0.0;
1892 }
1893 return true;
1894 }
1895
1918
1919 std::string VariableNonMaxwellianity::getName() const { return popName + "/vg_nonmaxwellianity"; }
1920
1921 bool VariableNonMaxwellianity::getDataVectorInfo(std::string& dataType, unsigned int& dataSize,
1922 unsigned int& vectorSize) const {
1923 dataType = "float";
1924 dataSize = sizeof(Real);
1925 vectorSize = 1;
1926 return true;
1927 }
1928
1929 bool VariableNonMaxwellianity::reduceData(const SpatialCell* cell, char* buffer) {
1930 // calculate something for epsilon here
1931 const Real HALF = 0.5;
1932
1933 // thermal speed in parallel direction
1934 const Real V_par_th_sq = 2.0 * physicalconstants::K_B * T_par / getObjectWrapper().particleSpecies[popID].mass;
1935
1936 #ifdef USE_GPU
1938 #else
1940 #endif
1941
1942 // ARCH interface includes OpenMP looping including critical regions for thread summation
1943 {
1944 Real thread_epsilon_sum = 0.0;
1945
1946 Real rho_local = rho;
1947 Real VX0 = V0[0];
1948 Real VY0 = V0[1];
1949 Real VZ0 = V0[2];
1950 Real b_parX = b_par[0];
1951 Real b_parY = b_par[1];
1952 Real b_parZ = b_par[2];
1953 Real b_perp1X = b_perp1[0];
1954 Real b_perp1Y = b_perp1[1];
1955 Real b_perp1Z = b_perp1[2];
1956 Real b_perp2X = b_perp2[0];
1957 Real b_perp2Y = b_perp2[1];
1958 Real b_perp2Z = b_perp2[2];
1959 Real T_par_local = T_par;
1960 Real T_perp_local = T_perp;
1961
1962 if (cell->get_number_of_velocity_blocks(popID) != 0)
1964 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lthread_epsilon_sum ){
1965 const Realf *block_data = VBC->getData(n);
1966 const Real *block_parameters = VBC->getParameters(n);
1967 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
1968 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
1969 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
1970 const Real DV3 = block_parameters[BlockParams::DVX]
1971 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
1972
1973 const Real V_par = (VX - VX0) * b_parX + (VY - VY0) * b_parY + (VZ - VZ0) * b_parZ;
1974 const Real V_perp1 = (VX - VX0) * b_perp1X + (VY - VY0) * b_perp1Y + (VZ - VZ0) * b_perp1Z;
1975 const Real V_perp2 = (VX - VX0) * b_perp2X + (VY - VY0) * b_perp2Y + (VZ - VZ0) * b_perp2Z;
1976
1977 const Real bimaxwellian = rho_local / sqrt(M_PI * M_PI * M_PI * V_par_th_sq * V_par_th_sq * V_par_th_sq) *
1978 (T_par_local / T_perp_local) *
1979 exp(-(V_par * V_par) / V_par_th_sq -
1980 (V_perp1 * V_perp1 + V_perp2 * V_perp2) / (V_par_th_sq * T_perp_local / T_par_local));
1981
1982 lthread_epsilon_sum[0] +=
1983 (abs(block_data[cellIndex(i, j, k)] - bimaxwellian) - bimaxwellian) * DV3;
1984 }, thread_epsilon_sum);
1985
1986 // Epsilon is here the non-Maxwellianity
1987 epsilon = thread_epsilon_sum;
1988 }
1989
1990 epsilon *= HALF / rho;
1991 epsilon += HALF;
1992
1993 const char* ptr = reinterpret_cast<const char*>(&epsilon);
1994 for (uint i = 0; i < sizeof(Real); ++i)
1995 buffer[i] = ptr[i];
1996 return true;
1997 }
1998
2000 // calculate here parallel and perpendicular T for use in actual
2001 // non-Maxwellianity calculation
2002 // TODO: Consider if rotated saved moments would be enough? Data reductions take place
2003 // as first action of main loop, so moments_V are the most recent ones.
2004 epsilon = 0.0;
2005
2006 // get rho and bulk speed
2007 rho = cell->get_population(popID).RHO_V;
2008 V0[0] = cell->get_population(popID).V_V[0];
2009 V0[1] = cell->get_population(popID).V_V[1];
2010 V0[2] = cell->get_population(popID).V_V[2];
2011
2012 // calculate temperature from the pressure tensor
2013 Real PTensor[3] = {};
2014
2015 // parallel unit vector (B)
2019 Real norm_par = sqrt(BX * BX + BY * BY + BZ * BZ);
2020 b_par[0] = BX / norm_par;
2021 b_par[1] = BY / norm_par;
2022 b_par[2] = BZ / norm_par;
2023
2024 // perpendicular unit vector 1 (bulk velocity perpendicular to b)
2025 Real BV0 = sqrt(b_par[0] * V0[0] + b_par[1] * V0[1] + b_par[2] * V0[2]);
2026 b_perp1[0] = V0[0] - BV0 * b_par[0];
2027 b_perp1[1] = V0[1] - BV0 * b_par[1];
2028 b_perp1[2] = V0[2] - BV0 * b_par[2];
2029 Real norm_perp1 = sqrt(b_perp1[0] * b_perp1[0] + b_perp1[1] * b_perp1[1] + b_perp1[2] * b_perp1[2]);
2030 if (!(norm_perp1 > 0.0)) {
2031 // if V0 is aligned with b, take arbitrary perpendicular vector
2032 b_perp1[0] = +b_par[1] + b_par[2];
2033 b_perp1[1] = +b_par[2] - b_par[0];
2034 b_perp1[2] = -b_par[0] - b_par[1];
2035 norm_perp1 = sqrt(b_perp1[0] * b_perp1[0] + b_perp1[1] * b_perp1[1] + b_perp1[2] * b_perp1[2]);
2036 }
2037 b_perp1[0] /= norm_perp1;
2038 b_perp1[1] /= norm_perp1;
2039 b_perp1[2] /= norm_perp1;
2040
2041 // perpendicular unit vector 2 (b_par x b_perp1)
2042 b_perp2[0] = b_par[1] * b_perp1[2] - b_par[2] * b_perp1[1];
2043 b_perp2[1] = b_par[2] * b_perp1[0] - b_par[0] * b_perp1[2];
2044 b_perp2[2] = b_par[0] * b_perp1[1] - b_par[1] * b_perp1[0];
2045 Real norm_perp2 = sqrt(b_perp2[0] * b_perp2[0] + b_perp2[1] * b_perp2[1] + b_perp2[2] * b_perp2[2]);
2046 b_perp2[0] /= norm_perp2;
2047 b_perp2[1] /= norm_perp2;
2048 b_perp2[2] /= norm_perp2;
2049
2050 // below calculation is modified from VariablePTensorDiagonal
2051 const Real HALF = 0.5;
2052
2053 #ifdef USE_GPU
2055 #else
2057 #endif
2058
2059 // ARCH interface includes OpenMP looping including critical regions for thread summation
2060 {
2061 Real sum[3] = {0.0, 0.0, 0.0};
2062
2063 Real VX0 = V0[0];
2064 Real VY0 = V0[1];
2065 Real VZ0 = V0[2];
2066 Real b_parX = b_par[0];
2067 Real b_parY = b_par[1];
2068 Real b_parZ = b_par[2];
2069 Real b_perp1X = b_perp1[0];
2070 Real b_perp1Y = b_perp1[1];
2071 Real b_perp1Z = b_perp1[2];
2072 Real b_perp2X = b_perp2[0];
2073 Real b_perp2Y = b_perp2[1];
2074 Real b_perp2Z = b_perp2[2];
2075
2076 if (cell->get_number_of_velocity_blocks(popID) != 0)
2078 ARCH_LOOP_LAMBDA(const uint i, const uint j, const uint k, const uint n, Real *lsum ){
2079 const Realf *block_data = VBC->getData(n);
2080 const Real *block_parameters = VBC->getParameters(n);
2081 const Real VX = block_parameters[BlockParams::VXCRD] + (i + HALF)*block_parameters[BlockParams::DVX];
2082 const Real VY = block_parameters[BlockParams::VYCRD] + (j + HALF)*block_parameters[BlockParams::DVY];
2083 const Real VZ = block_parameters[BlockParams::VZCRD] + (k + HALF)*block_parameters[BlockParams::DVZ];
2084 const Real DV3 = block_parameters[BlockParams::DVX]
2085 * block_parameters[BlockParams::DVY] * block_parameters[BlockParams::DVZ];
2086
2087 const Real V_par = (VX - VX0) * b_parX + (VY - VY0) * b_parY + (VZ - VZ0) * b_parZ;
2088 const Real V_perp1 = (VX - VX0) * b_perp1X + (VY - VY0) * b_perp1Y + (VZ - VZ0) * b_perp1Z;
2089 const Real V_perp2 = (VX - VX0) * b_perp2X + (VY - VY0) * b_perp2Y + (VZ - VZ0) * b_perp2Z;
2090
2091 lsum[0] += block_data[cellIndex(i, j, k)] * V_par * V_par * DV3;
2092 lsum[1] += block_data[cellIndex(i, j, k)] * V_perp1 * V_perp1 * DV3;
2093 lsum[2] += block_data[cellIndex(i, j, k)] * V_perp2 * V_perp2 * DV3;
2094 }, sum);
2095
2096 PTensor[0] = sum[0] * getObjectWrapper().particleSpecies[popID].mass;
2097 PTensor[1] = sum[1] * getObjectWrapper().particleSpecies[popID].mass;
2098 PTensor[2] = sum[2] * getObjectWrapper().particleSpecies[popID].mass;
2099 }
2100 T_par = (PTensor[0]) / (rho * physicalconstants::K_B);
2101 T_perp = (PTensor[1] + PTensor[2]) / (2.0 * rho * physicalconstants::K_B);
2102
2103 return true;
2104 }
2105
2106} // namespace DRO
for i
Definition Dispersion.m:24
Numerical propagation V
Definition Dispersion.m:98
B0
Definition Dispersion.m:41
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
#define ARCH_INNER_BODY(...)
#define ARCH_LOOP_LAMBDA
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *buffer)
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual std::string getName() const
virtual bool setSpatialCell(const SpatialCell *cell)
DataReductionOperatorBVOLDerivatives(const std::string &name, const unsigned int parameterIndex, const unsigned int vectorSize)
virtual bool setSpatialCell(const SpatialCell *cell)
DataReductionOperatorCellParams(const std::string &name, const unsigned int parameterIndex, const unsigned int vectorSize)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool writeFsGridData(const FieldSolverData &fieldSolverData, const std::string &meshName, vlsv::Writer &vlsvWriter, const bool writeAsFloat=false)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual std::string getName() const =0
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool writeIonosphereData(SBC::SphericalTriGrid &grid, vlsv::Writer &vlsvWriter)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool writeIonosphereData(SBC::SphericalTriGrid &grid, vlsv::Writer &vlsvWriter)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *result)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool writeIonosphereData(SBC::SphericalTriGrid &grid, vlsv::Writer &vlsvWriter)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool reduceDiagnostic(const SpatialCell *cell, Real *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool reduceDiagnostic(const spatial_cell::SpatialCell *cell, Real *result)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual std::string getName() const
virtual bool writeParameters(vlsv::Writer &vlsvWriter)
virtual bool setSpatialCell(const SpatialCell *cell)
VariableEnergyDensity(cuint popID)
Energy density Calculates the energy density of particles in three bins: total energy density,...
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
VariableMuSpace(cuint popID)
V-space flatten into 1D mu distribution.
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool writeParameters(vlsv::Writer &vlsvWriter)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
VariableNonMaxwellianity(cuint popID)
Non-Maxwellianity Calculates for a population the dimensionless parameter defined by Graham et al....
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool writeParameters(vlsv::Writer &vlsvWriter)
virtual bool setSpatialCell(const SpatialCell *cell)
VariablePrecipitationDiffFlux(cuint popID)
Precipitation directional differential number flux (within loss cone) Evaluation of the precipitating...
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
VariablePrecipitationLineDiffFlux(cuint popID)
Precipitation directional differential number flux (along line) Evaluation of the precipitating diffe...
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool writeParameters(vlsv::Writer &vlsvWriter)
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool setSpatialCell(const SpatialCell *cell)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual std::string getName() const
virtual bool getDataVectorInfo(std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
virtual std::string getName() const
virtual bool reduceData(const SpatialCell *cell, char *buffer)
virtual bool setSpatialCell(const SpatialCell *cell)
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
vmesh::VelocityBlockContainer * get_velocity_blocks(const size_t &popID)
Real getVelocityBlockMinValue(const uint popID) const
std::array< Real, bvolderivatives::N_BVOL_DERIVATIVES > derivativesBVOL
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)
void bailout(const bool condition, const std::string &message, const char *const file, const int line)
A function to stop the simulation if the boolean condition is true. Raises a flag which gets MPI_Redu...
Definition common.cpp:36
#define WID
Definition common.h:514
Parameters P
const uint32_t cuint
Definition definitions.h:50
float Real
Definition definitions.h:41
float Realf
Definition definitions.h:33
const float creal
Definition definitions.h:42
const Real HALF
Definition fs_common.h:49
const Real VY
const Real VplasmaZ
const Real mu
const Real VplasmaY
__global__ void size_t const vmesh::VelocityBlockContainer *__restrict__ const Real Real Real Real Realf int Real const Real dmubins
const Real VplasmaX
const Real VZ
const int j
const Real Vpara
const Real VX
const int k
const Real normV
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
static void VNonthermalCalculation(const SpatialCell *cell, const bool calculateNonthermal, cuint popID, Real *V)
static void PTensorOffDiagonalNonthermalCalculations(const SpatialCell *cell, const bool calculateNonthermal, const Real averageVX, const Real averageVY, const Real averageVZ, cuint popID, Real *PTensor)
static void PTensorDiagonalNonthermalCalculations(const SpatialCell *cell, const bool calculateNonthermal, const Real averageVX, const Real averageVY, const Real averageVZ, cuint popID, Real *PTensor)
static void rhoNonthermalCalculation(const SpatialCell *cell, const bool calculateNonthermal, cuint popID, Real &rho)
static void parallel_reduce(const uint(&limits)[NDim], Lambda loop_body, T &sum)
const Real CHARGE
Definition common.h:572
const Real K_B
Definition common.h:571
FieldSolverGrid & fsgrid
Definition grid.h:36
std::vector< species::Species > particleSpecies
static int PADmubins
Definition parameters.h:241
static std::vector< std::string > systemWriteName
Definition parameters.h:82
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > max(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)
static ARCH_HOSTDEV VecSimple< T > floor(VecSimple< T > const &a)