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