chombo-discharge
Loading...
Searching...
No Matches
CD_ItoKMCBackgroundEvaluatorImplem.H
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021-2026 SINTEF Energy Research
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
13#ifndef CD_ITOKMCBACKGROUNDEVALUATORIMPLEM_H
14#define CD_ITOKMCBACKGROUNDEVALUATORIMPLEM_H
15
16// Our includes
18#include <CD_NamespaceHeader.H>
19
20using namespace Physics::ItoKMC;
21
22template <typename I, typename C, typename R, typename F>
25{
26 CH_TIME("ItoKMCBackgroundEvaluator::ItoKMCBackgroundEvaluator");
27
28 // Set default values
29 m_maxFieldExitCrit = std::numeric_limits<Real>::max();
30 m_relFieldExitCrit = std::numeric_limits<Real>::max();
31 m_maxFieldChange = -1.0;
32 m_relFieldChange = -1.0;
33 m_electrodeCharge = 0.0;
34 m_ohmicCharge = 0.0;
35 m_opticalSolver = "2PN2";
36 m_maxInitialTimeStep = 0.0;
37
38 // Override the name and re-parse ALL options (ItoKMCStepper + GodunovStepper) using the new prefix
39 this->m_name = "ItoKMCBackgroundEvaluator";
40 this->parseOptions();
41
42 // Parse BackgroundEvaluator-specific options
43 ParmParse pp(this->m_name.c_str());
44 pp.query("max_field_exit_crit", m_maxFieldExitCrit);
45 pp.query("rel_field_exit_crit", m_relFieldExitCrit);
46 pp.query("optical_solver", m_opticalSolver);
47 pp.query("max_initial_time_step", m_maxInitialTimeStep);
48}
49
50template <typename I, typename C, typename R, typename F>
51void
53{
54 CH_TIME("ItoKMCBackgroundEvaluator::postInitialize");
55 if (this->m_verbosity > 5) {
56 pout() << "ItoKMCBackgroundEvaluator::postInitialize" << endl;
57 }
58
60
61 this->computeBackgroundField();
62}
63
64template <typename I, typename C, typename R, typename F>
65void
67{
68 CH_TIME("ItoKMCBackgroundEvaluator::postRegrid");
69 if (this->m_verbosity > 5) {
70 pout() << "ItoKMCBackgroundEvaluator::postRegrid" << endl;
71 }
72
74
75 this->computeBackgroundField();
76}
77
78template <typename I, typename C, typename R, typename F>
79void
81{
82 CH_TIME("ItoKMCBackgroundEvaluator::postCheckpointSetup");
83 if (this->m_verbosity > 5) {
84 pout() << "ItoKMCBackgroundEvaluator::postCheckpointSetup" << endl;
85 }
86
88
89 this->computeBackgroundField();
90}
91
92template <typename I, typename C, typename R, typename F>
93Real
95{
96 CH_TIME("ItoKMCBackgroundEvaluator::advance");
97 if (this->m_verbosity > 5) {
98 pout() << "ItoKMCBackgroundEvaluator::advance" << endl;
99 }
100
102
103 const std::pair<Real, Real> fieldChange = this->evaluateSpaceChargeEffects();
104 const Real electrodeQ = this->integrateElectrodeSurfaceCharge();
105 const Real ohmicQ = this->integrateOhmicCharge();
106 const std::pair<Real, Real> opticalEmissions = this->integrateOpticalExcitations();
107
108 m_relFieldChange = fieldChange.first;
109 m_maxFieldChange = fieldChange.second;
110 m_electrodeCharge = electrodeQ;
111 m_ohmicCharge = ohmicQ;
112 m_sumOpticalPhi = opticalEmissions.first;
113 m_sumOpticalSrc = opticalEmissions.second;
114
115 bool abortCondition = false;
116 if ((m_maxFieldChange > m_maxFieldExitCrit) && (m_maxFieldExitCrit > 0.0)) {
117 pout() << "ItoKMCBackgroundEvaluator -- stopping because the max field (in any cell) "
118 << "changed by more than specified threshold (max_field_exit_crit)" << endl;
119 abortCondition = true;
120 }
121 if ((m_relFieldChange > m_relFieldExitCrit) && (m_relFieldExitCrit > 0.0)) {
122 pout() << "ItoKMCBackgroundEvaluator -- stopping because the relative field change in a cell "
123 << "is larger than specified threshold (rel_field_exit_crit)" << endl;
124 abortCondition = true;
125 }
126 if (abortCondition) {
127 this->m_keepGoing = false;
128 }
129
130 return actualDt;
131}
132
133template <typename I, typename C, typename R, typename F>
134Real
136{
137 CH_TIME("ItoKMCBackgroundEvaluator::computeDt");
138 if (this->m_verbosity > 5) {
139 pout() << "ItoKMCBackgroundEvaluator::computeDt" << endl;
140 }
141
143
144 if (this->m_timeStep == 0 && m_maxInitialTimeStep > 0.0 && newDt > m_maxInitialTimeStep)
145 newDt = m_maxInitialTimeStep;
146
147 return newDt;
148}
149
150template <typename I, typename C, typename R, typename F>
151void
153{
154 CH_TIME("ItoKMCBackgroundEvaluator::printStepReport");
155 if (this->m_verbosity > 5) {
156 pout() << "ItoKMCBackgroundEvaluator::printStepReport" << endl;
157 }
158
159 std::ios::fmtflags oldFlags = pout().flags();
160
162
163 // Append the step report.
164 const std::string whitespace = " ";
165 pout().precision(12);
166 pout() << whitespace + "Delta E(max) = " << 100.0 * m_maxFieldChange << " (%)" << endl;
167 pout() << whitespace + "Delta E(rel) = " << 100.0 * m_relFieldChange << " (%)" << endl;
168 pout() << whitespace + "Q (electrode) = " << std::scientific << m_electrodeCharge << " (C)" << endl;
169 pout() << whitespace + "Q (ohmic) = " << std::scientific << m_ohmicCharge << " (C)" << endl;
170 pout() << whitespace + "Sum (phi_optical) = " << std::scientific << m_sumOpticalPhi << endl;
171 pout() << whitespace + "Sum (src_optical) = " << std::scientific << m_sumOpticalSrc << " (1/s)" << endl;
172
173 pout().flags(oldFlags);
174}
175
176template <typename I, typename C, typename R, typename F>
177void
179{
180 CH_TIME("ItoKMCBackgroundEvaluator::computeBackgroundField");
181 if (this->m_verbosity > 5) {
182 pout() << "ItoKMCBackgroundEvaluator::computeBackgroundField" << endl;
183 }
184
185 // Allocate the background field, storage for the potential, storage for the space-charge, and storage for the
186 // surface charge.
190
191 (this->m_amr)->allocate(phi, this->m_fluidRealm, 1);
192 (this->m_amr)->allocate(rho, this->m_fluidRealm, 1);
193 (this->m_amr)->allocate(sigma, this->m_fluidRealm, this->m_plasmaPhase, 1);
194 (this->m_amr)->allocate(m_backgroundField, this->m_fluidRealm, SpaceDim);
195
196 // Copy the potential over from the field solver so we have a better initial guess for the potential. The
197 // space-charge and surface charge must be zero.
198 (this->m_amr)->copyData(phi, (this->m_fieldSolver)->getPotential());
199
202
203 // Reset the field solver permittivities. Note that this discards the semi-implicit coefficients for the field update,
204 // but these are refilled on the next solver time step anyways.
205 (this->m_fieldSolver)->setPermittivities();
206
207 const MFAMRCellData& permCell = (this->m_fieldSolver)->getPermittivityCell();
208 const MFAMRFluxData& permFace = (this->m_fieldSolver)->getPermittivityFace();
209 const MFAMRIVData& permEB = (this->m_fieldSolver)->getPermittivityEB();
210
211 (this->m_fieldSolver)->setSolverPermittivities(permCell, permFace, permEB);
212
213 // Solve the damn thing, and then compute the electric field onto m_backgroundField.
214 (this->m_fieldSolver)->solve(phi, rho, sigma, false);
215 (this->m_fieldSolver)->computeElectricField(m_backgroundField, phi);
216}
217
218template <typename I, typename C, typename R, typename F>
221{
222 CH_TIME("ItoKMCBackgroundEvaluator::evaluateSpaceChargeEffects");
223 if (this->m_verbosity > 5) {
224 pout() << "ItoKMCBackgroundEvaluator::evaluateSpaceChargeEffects" << endl;
225 }
226
232
233 (this->m_amr)->allocate(poissonNorm, this->m_fluidRealm, this->m_plasmaPhase, 1);
234 (this->m_amr)->allocate(laplaceNorm, this->m_fluidRealm, this->m_plasmaPhase, 1);
235 (this->m_amr)->allocate(poissonField, this->m_fluidRealm, this->m_plasmaPhase, SpaceDim);
236 (this->m_amr)->allocate(laplaceField, this->m_fluidRealm, this->m_plasmaPhase, SpaceDim);
237 (this->m_amr)->allocate(deltaE, this->m_fluidRealm, this->m_plasmaPhase, 1);
238
239 // Get the fields in the plasma phase -- the actual field and the background field.
240 const MFAMRCellData electricField = (this->m_fieldSolver)->getElectricField();
241
242 DataOps::copy(poissonField, (this->m_amr)->alias(this->m_plasmaPhase, electricField));
243 DataOps::copy(laplaceField, (this->m_amr)->alias(this->m_plasmaPhase, m_backgroundField));
244
245 (this->m_amr)->interpToCentroids(poissonField, this->m_fluidRealm, this->m_plasmaPhase);
246 (this->m_amr)->interpToCentroids(laplaceField, this->m_fluidRealm, this->m_plasmaPhase);
247
248 // Compute the field magnitude, and then the relative change in field magnitude.
251 (this->m_amr)->getNotCoveredCells(this->m_fluidRealm, this->m_plasmaPhase),
252 (this->m_amr)->getMultiCutVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
255 (this->m_amr)->getNotCoveredCells(this->m_fluidRealm, this->m_plasmaPhase),
256 (this->m_amr)->getMultiCutVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
257
262 0.0,
263 (this->m_amr)->getMultiCutVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
264
265 (this->m_amr)->arithmeticAverage(deltaE, this->m_fluidRealm, this->m_plasmaPhase);
266 (this->m_amr)->interpGhost(deltaE, this->m_fluidRealm, this->m_plasmaPhase);
267
268 // Iterate through the grid cells and figure out where the field change the most.
269 //
270 // PS: I'm doing this with a direct loop because DataOps::getMaxMin will do ALL cells, including ones that are
271 // covered by a finer level. But we only want to evaluate the valid region.
272 Real relChange = -1.0;
273 Real maxChange = -1.0;
274
279
283 0,
284 (this->m_amr)->getMultiCutVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
288 0,
289 (this->m_amr)->getMultiCutVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
290
291 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
292 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids(this->m_fluidRealm)[lvl];
293 const DataIterator& dit = dbl.dataIterator();
294 const EBISLayout& ebisl = (this->m_amr)->getEBISLayout(this->m_fluidRealm, this->m_plasmaPhase)[lvl];
295
296 const int nbox = dit.size();
297
298#pragma omp parallel for schedule(runtime) reduction(max : relChange)
299 for (int mybox = 0; mybox < nbox; mybox++) {
300 const DataIndex& din = dit[mybox];
301 const Box box = dbl[din];
302 const EBISBox& ebisbox = ebisl[din];
303 const BaseFab<bool>& validCells = (*(this->m_amr)->getValidCells(this->m_fluidRealm)[lvl])[din];
304
305 const EBCellFAB& data = (*deltaE[lvl])[din];
306 const FArrayBox& dataReg = data.getFArrayBox();
307
308 auto regularKernel = [&](const IntVect& iv) -> void {
309 if (validCells(iv) && ebisbox.isRegular(iv)) {
310 relChange = std::max(relChange, std::abs(dataReg(iv, 0)));
311 }
312 };
313
314 auto irregularKernel = [&](const VolIndex& vof) -> void {
315 if (validCells(vof.gridIndex()) && ebisbox.isIrregular(vof.gridIndex())) {
316 relChange = std::max(relChange, std::abs(data(vof, 0)));
317 }
318 };
319
320 VoFIterator& vofit = (*(this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase)[lvl])[din];
321
322 // Not vectorizable: max reduction (relChange) + out-of-line isRegular guard.
323 BoxLoops::loop<D_DECL(1, 1, 1)>(box, regularKernel);
325 }
326 }
327
330
332}
333
334template <typename I, typename C, typename R, typename F>
335Real
337{
338 CH_TIME("ItoKMCBackgroundEvaluator::integrateElectrodeSurfaceCharge");
339 if (this->m_verbosity > 5) {
340 pout() << "ItoKMCBackgroundEvaluator::integrateElectrodeSurfaceCharge" << endl;
341 }
342
343 Real Enorm = 0.0;
344
345 const Real eps = Units::eps0 * this->m_computationalGeometry->getGasPermittivity();
346
347 const MFAMRCellData& electricFieldCell = (this->m_fieldSolver)->getElectricField();
348 const MFAMRCellData& permittivityCell = (this->m_fieldSolver)->getPermittivityCell();
349 const EBAMRCellData permittivity = (this->m_amr)->alias(this->m_plasmaPhase, permittivityCell);
350
351 // Allocates data and computes the electric field on the cell centroid(s).
353 (this->m_amr)->allocate(electricField, this->m_fluidRealm, this->m_plasmaPhase, SpaceDim);
354 DataOps::copy(electricField, (this->m_amr)->alias(this->m_plasmaPhase, electricFieldCell));
355 (this->m_amr)->interpToCentroids(electricField, this->m_fluidRealm, this->m_plasmaPhase);
356
357 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
358 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids(this->m_fluidRealm)[lvl];
359 const EBISLayout& ebisl = (this->m_amr)->getEBISLayout(this->m_fluidRealm, this->m_plasmaPhase)[lvl];
360 const DataIterator& dit = dbl.dataIterator();
361 const Real dx = (this->m_amr)->getDx()[lvl];
362 const Real dA = std::pow(dx, SpaceDim - 1);
363
364 const int numBoxes = dit.size();
365
366#pragma omp parallel for schedule(runtime) reduction(+ : Enorm)
367 for (int mybox = 0; mybox < numBoxes; mybox++) {
368 const DataIndex& din = dit[mybox];
369 const EBISBox& ebisbox = ebisl[din];
370 const EBCellFAB& E = (*electricField[lvl])[din];
371 const EBCellFAB& eps = (*permittivity[lvl])[din];
372 const BaseFab<bool>& validCells = (*(this->m_amr)->getValidCells(this->m_fluidRealm)[lvl])[din];
373
374 auto kernel = [&](const VolIndex& vof) -> void {
375 if (ebisbox.isIrregular(vof.gridIndex()) && validCells(vof.gridIndex(), 0)) {
376 const RealVect normalVector = ebisbox.normal(vof);
377 const RealVect e = RealVect(D_DECL(E(vof, 0), E(vof, 1), E(vof, 2)));
378 const Real areaFrac = ebisbox.bndryArea(vof);
379
380 Enorm += eps(vof, 0) * e.dotProduct(normalVector) * areaFrac * dA;
381 }
382 };
383
384 VoFIterator& vofit = (*(this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase)[lvl])[din];
385
387 }
388 }
389
390 return eps * ParallelOps::sum(Enorm);
391}
392
393template <typename I, typename C, typename R, typename F>
394Real
396{
397 CH_TIME("ItoKMCBackgroundEvaluator::integrateOhmicCharge");
398 if (this->m_verbosity > 5) {
399 pout() << "ItoKMCBackgroundEvaluator::integrateOhmicCharge" << endl;
400 }
401
402 return 0.0;
403}
404
405template <typename I, typename C, typename R, typename F>
408{
409 CH_TIME("ItoKMCBackgroundEvaluator::integrateOpticalExcitations");
410 if (this->m_verbosity > 5) {
411 pout() << "ItoKMCBackgroundEvaluator::integrateOpticalExcitations" << endl;
412 }
413
414 Real sumPhi = 0.0;
415 Real sumSrc = 0.0;
416
417 for (CdrIterator<CdrSolver> solverIt = (this->m_cdr)->iterator(); solverIt.ok(); ++solverIt) {
419
420 if (solver->getName() == m_opticalSolver) {
421 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
422 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids(this->m_fluidRealm)[lvl];
423 const EBISLayout& ebisl = (this->m_amr)->getEBISLayout(this->m_fluidRealm, this->m_plasmaPhase)[lvl];
424 const DataIterator& dit = dbl.dataIterator();
425 const Real dx = (this->m_amr)->getDx()[lvl];
426 const Real dV = std::pow(dx, SpaceDim);
427
428 const int numBoxes = dit.size();
429
430#pragma omp parallel for schedule(runtime) reduction(+ : sumPhi, sumSrc)
431 for (int mybox = 0; mybox < numBoxes; mybox++) {
432 const DataIndex& din = dit[mybox];
433 const Box cellBox = dbl[din];
434 const EBISBox& ebisbox = ebisl[din];
435 const BaseFab<bool>& validCells = (*(this->m_amr)->getValidCells(this->m_fluidRealm)[lvl])[din];
436
437 const EBCellFAB& phi = (*(solver->getPhi()[lvl]))[din];
438 const EBCellFAB& src = (*(solver->getSource()[lvl]))[din];
439
440 const FArrayBox& phiReg = phi.getFArrayBox();
441 const FArrayBox& srcReg = src.getFArrayBox();
442
443 auto regularKernel = [&](const IntVect& iv) -> void {
444 if (ebisbox.isRegular(iv) && validCells(iv)) {
445 sumPhi += phiReg(iv, 0) * dV;
446 sumSrc += srcReg(iv, 0) * dV;
447 }
448 };
449
450 auto irregularKernel = [&](const VolIndex& vof) -> void {
451 if (ebisbox.isIrregular(vof.gridIndex()) && validCells(vof.gridIndex(), 0)) {
452 const Real kappa = ebisbox.volFrac(vof);
453
454 // Volume integral -- cut cells contribute their actual fluid volume kappa*dV (the regular kernel
455 // uses the full dV, kappa=1). kappa was previously computed here but not applied, over-counting
456 // cut cells by 1/kappa.
457 sumPhi += kappa * phi(vof, 0) * dV;
458 sumSrc += kappa * src(vof, 0) * dV;
459 }
460 };
461
462 VoFIterator& vofit = (*(this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase)[lvl])[din];
463
464 // Not vectorizable: FP sum reduction (sumPhi/sumSrc) + out-of-line isRegular guard.
465 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
467 }
468 }
469 }
470 }
471
474
476}
477
478#include <CD_NamespaceFooter.H>
479
480#endif
Declaration of the Physics::ItoKMC::ItoKMCBackgroundEvaluator TimeStepper.
static void getMaxMin(Real &max, Real &min, EBAMRCellData &a_data, const int a_comp, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Get maximum and minimum value of specified component.
Definition CD_DataOps.cpp:1711
static void vectorLength(EBAMRCellData &a_lhs, const EBAMRCellData &a_rhs, const EBAMRCellData &a_notCovered, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Compute the vector length of a data holder. Sets a_lhs = |a_rhs| where a_rhs contains SpaceDim compon...
Definition CD_DataOps.cpp:3500
static void incr(MFAMRCellData &a_lhs, const MFAMRCellData &a_rhs, const Real a_scale) noexcept
Function which increments data in the form a_lhs = a_lhs + a_rhs*a_scale for all components.
Definition CD_DataOps.cpp:820
static void setValue(LevelData< MFInterfaceFAB< T > > &a_lhs, const T &a_value)
Set value in an MFInterfaceFAB data holder.
Definition CD_DataOpsImplem.H:24
static void divideFallback(EBAMRCellData &a_numerator, const EBAMRCellData &a_denominator, const Real a_fallback, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Divide data. If the denominator is zero, set the value to a fallback option.
Definition CD_DataOps.cpp:1387
static void copy(MFAMRCellData &a_dst, const MFAMRCellData &a_src)
Copy data from one data holder to another.
Definition CD_DataOps.cpp:1201
virtual void postRegrid() noexcept override final
Post-regrid operations. Computes the background field.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:66
virtual Real integrateElectrodeSurfaceCharge() const noexcept
Compute total charge on electrode.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:336
virtual void computeBackgroundField() noexcept
Computes the background field. I.e., it allocates and fills m_backgroundField.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:178
virtual std::pair< Real, Real > evaluateSpaceChargeEffects() noexcept
Evaluate the maximum change in the background field.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:220
virtual void printStepReport() noexcept override final
Print a new step report. This is the old one plus the maximum field change.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:152
ItoKMCBackgroundEvaluator(RefCountedPtr< ItoKMCPhysics > &a_physics) noexcept
Constructor.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:23
virtual Real integrateOhmicCharge() const noexcept
Compute the total ohmic current through the electrode.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:395
virtual Real advance(const Real a_dt) override
Advance the system by a_dt, including background-field evaluation.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:94
virtual void postInitialize() noexcept override final
Post-initialization operations. Computes the background field.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:52
virtual void postCheckpointSetup() noexcept override final
Post-checkpoint operations. Computes the background field.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:80
virtual Real computeDt() override
Compute a time step for the advance method.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:135
virtual std::pair< Real, Real > integrateOpticalExcitations() const noexcept
Integrate the sum of the optical excitations.
Definition CD_ItoKMCBackgroundEvaluatorImplem.H:407
Implementation of ItoKMCStepper that uses a semi-implicit split-step formalism for advancing the Ito-...
Definition CD_ItoKMCGodunovStepper.H:30
virtual Real advance(const Real a_dt) override
Advance the Ito-Poisson-KMC system over a_dt.
Definition CD_ItoKMCGodunovStepperImplem.H:307
virtual Real computeDt() override
Compute a time step used for the advance method.
Definition CD_ItoKMCGodunovStepperImplem.H:287
Base class for a tracer particle solver. This solver can advance particles in a pre-defined velocity ...
Definition CD_TracerParticleSolver.H:38
TracerParticleSolver()
Default constructor.
Definition CD_TracerParticleSolverImplem.H:26
int m_verbosity
Verbosity level.
Definition CD_TracerParticleSolver.H:387
RefCountedPtr< AmrMesh > m_amr
Handle to AMR mesh.
Definition CD_TracerParticleSolver.H:327
RefCountedPtr< ComputationalGeometry > m_computationalGeometry
Handle to computational geometry.
Definition CD_TracerParticleSolver.H:332
virtual void allocate()
Allocate storage for this solver.
Definition CD_TracerParticleSolverImplem.H:195
int m_timeStep
Time step.
Definition CD_TracerParticleSolver.H:382
ALWAYS_INLINE void loop(const Box &a_computeBox, Functor &&kernel)
Launch a C++ kernel over a regular grid with compile-time per-dimension strides.
Definition CD_BoxLoopsImplem.H:39
Real max(const Real &a_input) noexcept
Get the maximum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition CD_ParallelOpsImplem.H:177
Real sum(const Real &a_value) noexcept
Compute the sum across all MPI ranks.
Definition CD_ParallelOpsImplem.H:354
constexpr Real eps0
Permittivity of free space.
Definition CD_Units.H:30