chombo-discharge
Loading...
Searching...
No Matches
CD_ItoKMCGodunovStepperImplem.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_ITOKMCGODUNOVSTEPPERIMPLEM_H
14#define CD_ITOKMCGODUNOVSTEPPERIMPLEM_H
15
16// Chombo includes
17#include <ParmParse.H>
18
19// Our includes
21#include <CD_Timer.H>
22#include <CD_ParallelOps.H>
23#include <CD_DataOps.H>
24#include <CD_ParticleLoops.H>
25#include <CD_Units.H>
26#include <CD_Photon.H>
27#include <CD_DischargeIO.H>
28#include <CD_NamespaceHeader.H>
29
30using namespace Physics::ItoKMC;
31
32namespace {
33// Deposit an SoA point-particle container's weight onto a_phi through the Ito solver's own deposition routine, so
34// that the point particles land on the mesh in the same normalization as the solver's own particles. Going through
35// the solver -- rather than calling AmrMesh::depositWeight directly -- is what picks up the solver's cut-cell
36// deposition flag and its redistribution, and what guarantees the realm and phase are the solver's own.
37//
38// No coarsenAndFillGhosts() here: every caller sums these deposits into rho or the cell conductivity and then
39// coarsens and fills ghost cells on that sum, so doing it per species would only produce values that are
40// immediately overwritten.
41inline void
42depositPointParticlesLikeSolver(const RefCountedPtr<ItoSolver>& a_solver,
43 EBAMRCellData& a_phi,
44 const ParticleContainer<NoPayload>& a_particles) noexcept
45{
46 a_solver->depositWeight(a_phi, a_particles, a_solver->getDeposition(), a_solver->getCoarseFineDeposition());
47}
48
49} // namespace
50
51template <typename I, typename C, typename R, typename F>
52ItoKMCGodunovStepper<I, C, R, F>::ItoKMCGodunovStepper(RefCountedPtr<ItoKMCPhysics>& a_physics, bool a_parseOptions)
53 : ItoKMCStepper<I, C, R, F>(a_physics)
54{
55 CH_TIME("ItoKMCGodunovStepper::ItoKMCGodunovStepper");
57 this->m_name = "ItoKMCGodunovStepper";
58 this->m_prevDt = 0.0;
59 this->m_writeCheckpointParticles = false;
60 this->m_readCheckpointParticles = false;
61 this->m_extendConductivityEB = false;
62 this->m_canRegridOnRestart = true;
63 this->m_prevDt = 0.0;
64 this->m_maxFieldAbort = std::numeric_limits<Real>::max();
65
66 if (a_parseOptions) {
67 this->parseOptions();
68 }
69}
71template <typename I, typename C, typename R, typename F>
73{
74 CH_TIME("ItoKMCGodunovStepper::~ItoKMCGodunovStepper");
75 if (this->m_verbosity > 5) {
76 pout() << "ItoKMCGodunovStepper::~ItoKMCGodunovStepper" << endl;
77 }
78}
79
80template <typename I, typename C, typename R, typename F>
81void
83{
84 CH_TIME("ItoKMCGodunovStepper::registerOperators");
85 if (this->m_verbosity > 5) {
86 pout() << "ItoKMCGodunovStepper::registerOperators" << endl;
87 }
88
90
91 // Register this because we must be able to deposit particles inside dielectrics (due to particle diffusion across the
92 // EB).
93 (this->m_amr)->registerOperator(s_particle_mesh, this->m_particleRealm, phase::solid);
94}
95
96template <typename I, typename C, typename R, typename F>
97void
99{
100 CH_TIME("ItoKMCGodunovStepper::allocate");
101 if (this->m_verbosity > 5) {
102 pout() << "ItoKMCGodunovStepper::allocate" << endl;
103 }
104
106
107 // Now allocate for the conductivity particles and rho^dagger particles. This is only done in the 'allocate' routine
108 // and not in 'allocateInternals' because that would discard the particles during regrids. That has definitely never
109 // happen, and there's no way I've spent countless hours tracking down such a bug.
110 const int numItoSpecies = this->m_physics->getNumItoSpecies();
111
112 m_conductivityParticles.resize(numItoSpecies);
113 m_irregularParticles.resize(numItoSpecies);
114 m_rhoDaggerParticles.resize(numItoSpecies);
115
116 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
117 const int idx = solverIt.index();
118
119 m_conductivityParticles[idx] = RefCountedPtr<ParticleContainer<NoPayload>>(new ParticleContainer<NoPayload>());
120 m_irregularParticles[idx] = RefCountedPtr<ParticleContainer<NoPayload>>(new ParticleContainer<NoPayload>());
121 m_rhoDaggerParticles[idx] = RefCountedPtr<ParticleContainer<NoPayload>>(new ParticleContainer<NoPayload>());
122
123 (this->m_amr)->allocate(*m_conductivityParticles[idx], this->m_particleRealm);
124 (this->m_amr)->allocate(*m_irregularParticles[idx], this->m_particleRealm);
125 (this->m_amr)->allocate(*m_rhoDaggerParticles[idx], this->m_particleRealm);
126 }
127}
128
129template <typename I, typename C, typename R, typename F>
130void
132{
133 CH_TIME("ItoKMCGodunovStepper::allocateInternals");
134 if (this->m_verbosity > 5) {
135 pout() << this->m_name + "::allocateInternals" << endl;
136 }
137
139
140 const int numCdrSpecies = this->m_physics->getNumCdrSpecies();
141
142 m_cdrDivD.resize(numCdrSpecies);
143 for (int i = 0; i < numCdrSpecies; i++) {
144 this->m_amr->allocate(m_cdrDivD[i], this->m_fluidRealm, this->m_plasmaPhase, 1);
145 }
146
147 this->m_amr->allocate(m_semiImplicitRhoCDR, this->m_fluidRealm, this->m_plasmaPhase, 1);
148 this->m_amr->allocate(m_semiImplicitConductivityCDR, this->m_fluidRealm, this->m_plasmaPhase, 1);
149
150 // AmrMesh::allocate does not initialize. Both fields are consumed by regrid(), which may run before an
151 // advance has filled them, so give them a defined value here. Later regrids overwrite them through
152 // interpToNewGrids.
153 DataOps::setValue(m_semiImplicitRhoCDR, 0.0);
154 DataOps::setValue(m_semiImplicitConductivityCDR, 0.0);
155
156 // Holds the field the chemistry is evaluated at. This one needs no initialization -- advance() overwrites
157 // it from m_electricFieldFluid before anything reads it, and nothing else consumes it.
158 this->m_amr->allocate(m_reactiveElectricField, this->m_fluidRealm, this->m_plasmaPhase, SpaceDim);
159}
160
161template <typename I, typename C, typename R, typename F>
162void
164{
165 CH_TIME("ItoKMCGodunovStepper::barrier");
166 if (this->m_verbosity > 5) {
167 pout() << this->m_name + "::barrier" << endl;
168 }
169
170 if ((this->m_profile)) {
172 }
173}
174
175template <typename I, typename C, typename R, typename F>
176void
178{
179 CH_TIME("ItoKMCGodunovStepper::parseOptions");
180 if (this->m_verbosity > 5) {
181 pout() << this->m_name + "::parseOptions" << endl;
182 }
183
185
186 this->parseAlgorithm();
187 this->parseFiltering();
188 this->parseCheckpointParticles();
189 this->parseSecondaryEmissionSpecification();
190 this->parseReactiveFieldCentering();
191}
192
193template <typename I, typename C, typename R, typename F>
194void
196{
197 CH_TIME("ItoKMCGodunovStepper::parseRuntimeOptions");
198 if (this->m_verbosity > 5) {
199 pout() << this->m_name + "::parseRuntimeOptions" << endl;
200 }
201
203
204 this->parseAlgorithm();
205 this->parseFiltering();
206 this->parseCheckpointParticles();
207 this->parseSecondaryEmissionSpecification();
208 this->parseReactiveFieldCentering();
209}
210
211template <typename I, typename C, typename R, typename F>
212void
214{
215 CH_TIME("ItoKMCGodunovStepper::parseAlgorithm");
216 if (this->m_verbosity > 5) {
217 pout() << this->m_name + "::parseAlgorithm" << endl;
218 }
219
220 ParmParse pp(this->m_name.c_str());
221 std::string str;
222
223 pp.get("extend_conductivity", m_extendConductivityEB);
224 pp.get("algorithm", str);
225 pp.get("abort_max_field", m_maxFieldAbort);
226
227 // Get algorithm
228 if (str == "euler_maruyama") {
229 m_algorithm = WhichAlgorithm::EulerMaruyama;
230 }
231 else {
232 MayDay::Abort("ItoKMCGodunovStepper::parseAlgorithm - unknown algorithm requested");
233 }
234}
235
236template <typename I, typename C, typename R, typename F>
237void
239{
240 CH_TIME("ItoKMCGodunovStepper::parseFiltering");
241 if (this->m_verbosity > 5) {
242 pout() << this->m_name + "::parseFiltering" << endl;
243 }
244
245 ParmParse pp(this->m_name.c_str());
246 std::string str;
247
248 m_rhoFilterNum = -1;
249 m_rhoFilterMaxStride = 1;
250 m_rhoFilterAlpha = 0.5;
251
252 m_condFilterNum = -1;
253 m_condFilterMaxStride = 1;
254 m_condFilterAlpha = 0.5;
255
256 pp.get("rho_filter_num", m_rhoFilterNum);
257 pp.get("rho_filter_max_stride", m_rhoFilterMaxStride);
258 pp.get("rho_filter_alpha", m_rhoFilterAlpha);
259
260 pp.get("cond_filter_num", m_condFilterNum);
261 pp.get("cond_filter_max_stride", m_condFilterMaxStride);
262 pp.get("cond_filter_alpha", m_condFilterAlpha);
263
264 if (m_rhoFilterAlpha <= 0.0 || m_rhoFilterAlpha >= 1.0) {
265 MayDay::Abort("ItoKMCGodunovStepper::parseFiltering -- cannot have alpha <= 0 or alpha >= 1 for rho_filter");
266 }
267 if (m_condFilterAlpha <= 0.0 || m_condFilterAlpha >= 1.0) {
268 MayDay::Abort("ItoKMCGodunovStepper::parseFiltering -- cannot have alpha <= 0 or alpha >= 1 for cond_filter");
269 }
270}
271
272template <typename I, typename C, typename R, typename F>
273void
275{
276 CH_TIME("ItoKMCGodunovStepper::parseCheckpointParticles");
277 if (this->m_verbosity > 5) {
278 pout() << this->m_name + "::parseCheckpointParticles" << endl;
279 }
280
281 ParmParse pp(this->m_name.c_str());
282
283 pp.query("checkpoint_particles", m_writeCheckpointParticles);
284}
285
286template <typename I, typename C, typename R, typename F>
287void
289{
290 CH_TIME("ItoKMCGodunovStepper::parseSecondaryEmissionSpecifiation");
291 if (this->m_verbosity > 5) {
292 pout() << this->m_name + "::parseSecondaryEmissionSpecification" << endl;
293 }
294
295 ParmParse pp(this->m_name.c_str());
296
297 std::string str;
298
299 pp.query("secondary_emission", str);
300
301 if (str == "before_reactions") {
302 m_emitSecondaryParticlesBeforeReactions = true;
303 }
304 else if (str == "after_reactions") {
305 m_emitSecondaryParticlesBeforeReactions = false;
306 }
307 else {
308 std::string err;
309
310 err = "ItoKMCGodunovStepper::parseSecondaryEmissionSpecification - expected 'before_reactions' or 'after_reactions'";
311 err += "but got" + str;
312
313 MayDay::Abort(err.c_str());
314 }
315}
316
317template <typename I, typename C, typename R, typename F>
318void
320{
321 CH_TIME("ItoKMCGodunovStepper::parseReactiveFieldCentering");
322 if (this->m_verbosity > 5) {
323 pout() << this->m_name + "::parseReactiveFieldCentering" << endl;
324 }
326 ParmParse pp(this->m_name.c_str());
327
328 pp.get("reactive_E_centering", m_reactiveFieldCentering);
329
330 // Anything outside [0,1] extrapolates past the two fields that were actually solved for, which has no
331 // physical justification.
332 if (m_reactiveFieldCentering < 0.0 || m_reactiveFieldCentering > 1.0) {
333 MayDay::Abort("ItoKMCGodunovStepper::parseReactiveFieldCentering -- 'reactive_E_centering' must lie in [0,1]");
334 }
335}
336
337template <typename I, typename C, typename R, typename F>
338Real
340{
341 CH_TIME("ItoKMCGodunovStepper::computeDt");
342 if (this->m_verbosity > 5) {
343 pout() << this->m_name + "::computeDt" << endl;
344 }
347
348 if ((this->m_maxReducedField > m_maxFieldAbort) && (m_maxFieldAbort > 0.0)) {
349 pout() << this->m_name + " stopping because maximum field is too high (" << this->m_maxReducedField << ")" << endl;
350
351 this->m_keepGoing = false;
352 }
353
354 return dt;
355}
356
357template <typename I, typename C, typename R, typename F>
358Real
360{
361 CH_TIME("ItoKMCGodunovStepper::advance");
362 if (this->m_verbosity > 5) {
363 pout() << this->m_name + "::advance" << endl;
364 }
366 // Special flag for telling the class that we have the necessary things in place for doing a regrid. This is
367 // an if-but-maybe situation where the user chose not to checkpoint the particles we need for regrids, yet tries
368 // to restart a simulation and regrid without all the prerequisites being in place. This flag is set to true
369 // because these requirements are checked during the regrid routine.
370 m_canRegridOnRestart = true;
371
372 m_timer = Timer("ItoKMCGodunovStepper::advance");
373
374 // Previous time step is needed when regridding.
375 this->m_prevDt = a_dt;
376
377 // Done only so we can plot the absorbed photons (advanceReactionNetwork absorbs them)
378 m_timer.startEvent("Deposit photons");
379 for (auto solverIt = (this->m_rte)->iterator(); solverIt.ok(); ++solverIt) {
380 RefCountedPtr<McPhoto> solver = solverIt();
381
382 EBAMRCellData& phi = solver->getPhi();
383 ParticleContainer<Photon>& photons = solver->getBulkPhotons();
384
385 solver->depositPhotons(phi, photons, DepositionType::NGP);
386 }
387 m_timer.stopEvent("Deposit photons");
388
389 // Store E^k -- the field the step starts from. The chemistry is later evaluated at an interpolant between
390 // this field and the one that comes out of the semi-implicit transport step.
391 m_timer.startEvent("Store E^k");
392 DataOps::copy(m_reactiveElectricField, this->m_electricFieldFluid);
393 m_timer.stopEvent("Store E^k");
394
395 // ====== BEGIN TRANSPORT STEP ======
396 // Semi-implicitly advance the particles and the field.
397 switch (m_algorithm) {
398 case WhichAlgorithm::EulerMaruyama: {
399 this->advanceEulerMaruyama(a_dt);
400
401 break;
402 }
403 default: {
404 MayDay::Abort("ItoKMCGodunovStepper::advance - logic bust");
405
406 break;
407 }
408 }
409
410 // Do intersection test and remove particles that struck the EB or domain. Transfer them to appropriate containers.
411 // Then recompute the number of particles per cell.
412 this->barrier();
413 m_timer.startEvent("EB/Particle intersection");
414 if (m_extendConductivityEB) {
415
416 // clang-format off
417 // TLDR: This hook does a special intersection routine where instead of transferring the particles that were intersected, they
418 // are put in a separate data container. We want to do this in order to reduce artificial gradients in the particle
419 // densities near the EB. The way we do this is that we flag the particles during the intersection; particles that are flagged
420 // are transferred to a container which is added to the conductivity-related particles. The particles are later removed.
421 // clang-format on
422 const std::function<void(ParticleSoA<ItoParticle>&, std::size_t)> setFlag = [](ParticleSoA<ItoParticle>& leaf,
423 const std::size_t i) -> void {
424 leaf.template get<&ItoParticle::scratch>(i) = 1.0;
425 };
426 const std::function<void(ParticleSoA<ItoParticle>&, std::size_t)> nonDeletionModifier =
427 [](ParticleSoA<ItoParticle>& leaf, const std::size_t i) -> void {
428 leaf.template get<&ItoParticle::scratch>(i) = -1.0;
429 };
430
431 // Set flag for identifying which particles were intersected by not removed.
432 for (auto it = this->m_ito->iterator(); it.ok(); ++it) {
433 ParticleOps::setData(it()->getParticles(ItoSolver::WhichContainer::Bulk), setFlag);
434 }
435
436 // Intersect particles, but don't remove them.
437 const bool deleteParticles = false;
438 this->intersectParticles(SpeciesSubset::AllMobileOrDiffusive, deleteParticles, nonDeletionModifier);
439
440 // Particles that were not removed are copied to a separate data container.
441 for (auto it = this->m_ito->iterator(); it.ok(); ++it) {
442 const RefCountedPtr<ItoSolver>& solver = it();
443 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
444
445 const int idx = it.index();
446 const int Z = species->getChargeNumber();
447
448 ParticleContainer<NoPayload>& irregParticles = *m_irregularParticles[idx];
449 ParticleContainer<ItoParticle>& ebParticles = solver->getParticles(ItoSolver::WhichContainer::EB);
450 ParticleContainer<ItoParticle>& bulkParticles = it()->getParticles(ItoSolver::WhichContainer::Bulk);
451
452 irregParticles.clearParticles();
453
454 if (Z != 0 && solver->isMobile()) {
455 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
456 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
457 const DataIterator& dit = dbl.dataIterator();
458
459 const int nbox = dit.size();
461#pragma omp parallel for schedule(runtime)
462 for (int mybox = 0; mybox < nbox; mybox++) {
463 const DataIndex& din = dit[mybox];
464
465 ParticleSoA<NoPayload>& pointParticles = irregParticles[lvl][din];
466 const ParticleSoA<ItoParticle>& leaf = bulkParticles[lvl][din];
468 for (std::size_t i = 0; i < leaf.size(); i++) {
469 if (leaf.template get<&ItoParticle::scratch>(i) < 0.0) {
470 const RealVect pos = leaf.position(i);
471 const Real weight = leaf.weight(i);
472 const Real mobility = leaf.template get<&ItoParticle::mobility>(i);
473
474 pointParticles.append(pos, weight * mobility);
475 }
476 }
478 }
479 }
480 }
481
482 // Finally, delete the original particles that were flagged (scratch < 0) via swap-and-pop on the SoA leaves.
483 for (auto it = this->m_ito->iterator(); it.ok(); ++it) {
484 ParticleContainer<ItoParticle>& bulkParticles = it()->getParticles(ItoSolver::WhichContainer::Bulk);
485
486 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
487 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
488 const DataIterator& dit = dbl.dataIterator();
490 const int nbox = dit.size();
491
492#pragma omp parallel for schedule(runtime)
493 for (int mybox = 0; mybox < nbox; mybox++) {
494 const DataIndex& din = dit[mybox];
495
496 ParticleSoA<ItoParticle>& leaf = bulkParticles[lvl][din];
497
498 std::size_t i = 0;
499 while (i < leaf.size()) {
500 if (leaf.template get<&ItoParticle::scratch>(i) < 0.0) {
501 leaf.remove(i);
502 }
503 else {
504 i++;
505 }
507 }
508 }
509 }
510 }
511 else {
512 const bool deleteParticles = true;
513
514 this->intersectParticles(SpeciesSubset::AllMobileOrDiffusive, deleteParticles);
515 }
516
517 // The intersection tests above may not have caught all particles -- do a cleanup sweep where particles on the wrong
518 // side of the EB are put on the EB.
519 for (auto it = this->m_ito->iterator(); it.ok(); ++it) {
520 const RefCountedPtr<ItoSolver>& solver = it();
521
522 ParticleContainer<ItoParticle>& ebParticles = solver->getParticles(ItoSolver::WhichContainer::EB);
523 ParticleContainer<ItoParticle>& bulkParticles = solver->getParticles(ItoSolver::WhichContainer::Bulk);
524
525 this->m_amr->transferIrregularParticles(ebParticles, bulkParticles, this->m_plasmaPhase);
526 }
527 m_timer.stopEvent("EB/Particle intersection");
528 // ====== END TRANSPORT STEP ======
529
530 // Photon transport
531 this->barrier();
532 m_timer.startEvent("Photon transport");
533 this->advancePhotons(a_dt);
534 m_timer.stopEvent("Photon transport");
535
536 // Compute the gradients of the various species densities - this is used in the KMC kernels.
537 if ((this->m_physics)->needGradients()) {
538 m_timer.startEvent("Gradient calculation");
539 (this->m_ito)->depositParticles();
540 this->computeDensityGradients();
541 m_timer.stopEvent("Gradient calculation");
542 }
543
544 // Resolve secondary emission. We have filled the relevant particles in the transport step -- this can be done
545 // either before or after the reactions.
546 if (m_emitSecondaryParticlesBeforeReactions) {
547 this->barrier();
548 m_timer.startEvent("EB particle injection");
549 this->fillSecondaryEmissionEB(a_dt);
550 this->resolveSecondaryEmissionEB(a_dt);
551 m_timer.stopEvent("EB particle injection");
552 }
553
554 // Sort the particles and photons per cell so we can call reaction algorithms
555 this->barrier();
556 m_timer.startEvent("Sort by cell");
557 (this->m_ito)->organizeParticlesByCell(ItoSolver::WhichContainer::Bulk);
558 this->sortPhotonsByCell(McPhoto::WhichContainer::Bulk);
559 this->sortPhotonsByCell(McPhoto::WhichContainer::Source);
560 m_timer.stopEvent("Sort by cell");
561
562 // Run the Kinetic Monte Carlo reaction kernels. These are evaluated at (1-theta)*E^k + theta*E^(k+1) rather
563 // than at the end-of-step field: in the semi-implicit formulation E^(k+1) is the already-screened field, so
564 // evaluating the whole reactive substep there biases the rate coefficients low wherever the plasma screens
565 // the field. m_reactiveElectricField holds E^k, and m_electricFieldFluid holds E^(k+1) at this point.
566 //
567 // NOTE: This centering applies to the reactions only. The drift update must keep using E^(k+1) with the
568 // lagged mobility mu^k because that is the pairing the semi-implicit Poisson operator was built for.
569 this->barrier();
570 m_timer.startEvent("Reaction network");
571 DataOps::scale(m_reactiveElectricField, 1.0 - m_reactiveFieldCentering);
572 DataOps::incr(m_reactiveElectricField, this->m_electricFieldFluid, m_reactiveFieldCentering);
573 this->advanceReactionNetwork(m_reactiveElectricField, a_dt);
574 m_timer.stopEvent("Reaction network");
575
576 // Merge super-particles down to the target after the chemistry advance created/removed particles.
577 // Routed through the public ItoSolver::makeSuperparticles() so both per-cell and AMR-wide
578 // (nn_pair_tree/nn_pair_onecell/nn_pair_hash) merge algorithms run, chosen by ItoSolver.merge_algorithm.
579 // makeSuperparticles() cell-sorts internally as needed and returns the container patch-organized.
580 this->barrier();
581 m_timer.startEvent("Make superparticles");
582 if (this->m_mergeInterval > 0 && (this->m_timeStep + 1) % this->m_mergeInterval == 0) {
583 (this->m_ito)->makeSuperparticles(ItoSolver::WhichContainer::Bulk);
584 }
585 m_timer.stopEvent("Make superparticles");
586
587 // Sort particles per patch.
588 this->barrier();
589 m_timer.startEvent("Sort by patch");
590 (this->m_ito)->organizeParticlesByPatch(ItoSolver::WhichContainer::Bulk);
591 this->sortPhotonsByPatch(McPhoto::WhichContainer::Bulk);
592 this->sortPhotonsByPatch(McPhoto::WhichContainer::Source);
593 m_timer.stopEvent("Sort by patch");
594
595 // Resolve secondary emission. We have filled the relevant particles in the transport step -- this can be done
596 // either before or after the reactions.
597 if (!m_emitSecondaryParticlesBeforeReactions) {
598 this->barrier();
599 m_timer.startEvent("EB particle injection");
600 this->fillSecondaryEmissionEB(a_dt);
601 this->resolveSecondaryEmissionEB(a_dt);
602 m_timer.stopEvent("EB particle injection");
603 }
604
605 // Remove particles that are inside the EB -- this is not a part of the algorithm, just a safety measure to make sure
606 // we don't do things with particles that lie inside the EB.
607 this->barrier();
608 m_timer.startEvent("Remove covered");
609 this->removeCoveredParticles(SpeciesSubset::AllMobileOrDiffusive, EBRepresentation::Discrete, this->m_toleranceEB);
610 m_timer.stopEvent("Remove covered");
611
612 // Clear BC data holders.
613 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
614 solverIt()->clear(ItoSolver::WhichContainer::EB);
615 solverIt()->clear(ItoSolver::WhichContainer::Domain);
616 }
617
618 // Prepare for the next time step
619 this->barrier();
620 m_timer.startEvent("Post-compute v");
621 this->computeDriftVelocities();
622 m_timer.stopEvent("Post-compute v");
623
624 this->barrier();
625 m_timer.startEvent("Post-compute D");
626 this->computeDiffusionCoefficients();
627 m_timer.stopEvent("Post-compute D");
628
629 this->computePhysicsDt();
630
631 if ((this->m_profile)) {
632 m_timer.eventReport(pout(), false);
633 }
634
635 m_timer.clear();
636
637 // Compute the maximum field (in Townsend).
638 this->m_maxReducedField = this->computeMaxReducedElectricField(this->m_plasmaPhase);
639
640 return a_dt;
641}
642
643template <typename I, typename C, typename R, typename F>
644void
645ItoKMCGodunovStepper<I, C, R, F>::preRegrid(const int a_lmin, const int a_oldFinestLevel) noexcept
646{
647 CH_TIME("ItoKMCGodunovStepper::preRegrid");
648 if (this->m_verbosity > 5) {
649 pout() << "ItoKMCGodunovStepper::preRegrid" << endl;
650 }
651
652 const int numItoSpecies = (this->m_physics)->getNumItoSpecies();
653 const int numCdrSpecies = (this->m_physics)->getNumCdrSpecies();
654 const int numPlasmaSpecies = (this->m_physics)->getNumPlasmaSpecies();
655 const int numPhotonSpecies = (this->m_physics)->getNumPhotonSpecies();
656
657 ItoKMCStepper<I, C, R, F>::preRegrid(a_lmin, a_oldFinestLevel);
658
659 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
660 const int idx = solverIt.index();
661
662 m_conductivityParticles[idx]->preRegrid();
663 m_irregularParticles[idx]->preRegrid();
664 m_rhoDaggerParticles[idx]->preRegrid();
665 }
666
667 this->m_amr->allocate(m_scratchSemiImplicitRhoCDR, this->m_fluidRealm, this->m_plasmaPhase, 1);
668 this->m_amr->allocate(m_scratchSemiImplicitConductivityCDR, this->m_fluidRealm, this->m_plasmaPhase, 1);
669
670 DataOps::copy(m_scratchSemiImplicitRhoCDR, m_semiImplicitRhoCDR);
671 DataOps::copy(m_scratchSemiImplicitConductivityCDR, m_semiImplicitConductivityCDR);
672
673 // Release unnecessary storage.
674 for (int i = 0; i < numCdrSpecies; i++) {
675 m_cdrDivD[i].clear();
676 }
677
678 m_semiImplicitRhoCDR.clear();
679 m_semiImplicitConductivityCDR.clear();
680}
681
682template <typename I, typename C, typename R, typename F>
683void
685 const int a_oldFinestLevel,
686 const int a_newFinestLevel) noexcept
687{
688 CH_TIME("ItoKMCGodunovStepper::regrid");
689 if (this->m_verbosity > 5) {
690 pout() << "ItoKMCGodunovStepper::regrid" << endl;
691 }
692
693 m_timer = Timer("ItoKMCGodunovStepper::regrid");
694
695 // A special flag for aborting the simulation if the user did NOT put checkpoint particles in the checkpoint
696 // file but still try to regrid on restart.
697 if (!m_canRegridOnRestart) {
698 const std::string baseErr = "ItoKMCGodunovStepper::regrid -- can't regrid because";
699 const std::string err1 = "checkpoint file does not contain particles. Set Driver.initial_regrids=0";
700
701 pout() << baseErr + err1 << endl;
702
703 MayDay::Error((baseErr + err1).c_str());
704 }
705
706 // Regrid solvers
707 m_timer.startEvent("Regrid ItoSolver");
708 (this->m_ito)->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
709 if (this->m_timeStep == 0) {
710 // Necessary because first time step is not semi-implicit, so it will use the densities from the
711 // Ito and CDr solvers. However, ItoSolver does not re-deposit the particles during regrid, so we
712 // enforce it here.
713 (this->m_ito)->depositParticles();
714 }
715 m_timer.stopEvent("Regrid ItoSolver");
716
717 m_timer.startEvent("Regrid CdrSolver");
718 (this->m_cdr)->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
719 m_timer.stopEvent("Regrid CdrSolver");
720
721 m_timer.startEvent("Regrid FieldSolver");
722 (this->m_fieldSolver)->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
723 m_timer.stopEvent("Regrid FieldSolver");
724
725 m_timer.startEvent("Regrid RTE");
726 (this->m_rte)->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
727 m_timer.stopEvent("Regrid RTE");
728
729 m_timer.startEvent("Regrid SurfaceODESolver");
730 this->m_sigmaSolver->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
731 m_timer.stopEvent("Regrid SurfaceODESolver");
732
733 // Allocate internal memory for ItoKMCGodunovStepper now....
734 m_timer.startEvent("Allocate internals");
735 this->allocateInternals();
736 m_timer.stopEvent("Allocate internals");
737
738 // We need to remap/regrid the stored data required for the semi-implicit update as well.
739 m_timer.startEvent("Remap algorithm-particles");
740 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
741 const int idx = solverIt.index();
742 (this->m_amr)->remapToNewGrids(*m_rhoDaggerParticles[idx], a_lmin, a_newFinestLevel);
743 (this->m_amr)->remapToNewGrids(*m_conductivityParticles[idx], a_lmin, a_newFinestLevel);
744 (this->m_amr)->remapToNewGrids(*m_irregularParticles[idx], a_lmin, a_newFinestLevel);
745 }
746 m_timer.stopEvent("Remap algorithm-particles");
747
748 // Also regrid the space charge density contribution from the CDR equations
749 this->m_amr->interpToNewGrids(m_semiImplicitRhoCDR,
750 m_scratchSemiImplicitRhoCDR,
751 this->m_plasmaPhase,
752 a_lmin,
753 a_oldFinestLevel,
754 a_newFinestLevel,
755 EBCoarseToFineInterp::Type::ConservativeMinMod);
756
757 this->m_amr->interpToNewGrids(m_semiImplicitConductivityCDR,
758 m_scratchSemiImplicitConductivityCDR,
759 this->m_plasmaPhase,
760 a_lmin,
761 a_oldFinestLevel,
762 a_newFinestLevel,
763 EBCoarseToFineInterp::Type::ConservativeMinMod);
764
765 // Set up the field solver with standard coefficients or with
766 // modified coefficients if we are reusing data from the last time step.
767 m_timer.startEvent("Setup field solver");
768 (this->m_fieldSolver)->setupSolver();
769 this->computeConductivities(m_conductivityParticles, true);
770 this->setupSemiImplicitPoisson(this->m_prevDt);
771 m_timer.stopEvent("Setup field solver");
772
773 // Solve the Poisson equation.
774 m_timer.startEvent("Solve Poisson");
775 if (this->m_timeStep == 0) {
776 this->computeSpaceChargeDensity();
777 }
778 else {
779 this->depositPointParticles(m_rhoDaggerParticles, SpeciesSubset::All);
780 this->computeSemiImplicitRho();
781 }
782
783 const bool converged = this->solvePoisson();
784
785 if (!converged) {
786 const std::string errMsg = "ItoKMCGodunovStepper::regrid - Poisson solve did not converge after regrid";
787
788 pout() << errMsg << endl;
789
790 if (this->m_abortOnFailure) {
791 MayDay::Error(errMsg.c_str());
792 }
793 }
794 m_timer.stopEvent("Solve Poisson");
795
796 // The regrid super-particle merge now runs inside ItoSolver::regrid() -- above, in the "Regrid Ito
797 // solvers" event -- so that the de-refinement pile-up is merged while it is still held as the reduced
798 // 53 B particle rather than the full 149 B ItoParticle. Two consequences worth knowing:
799 //
800 // - This timer loses its "Make superparticles" line for the regrid. The advance() one stays, since
801 // merge_interval stays. Profile ItoSolver directly if the regrid merge needs attributing again;
802 // it keeps its own CH_TIME.
803 // - The merge now happens BEFORE the semi-implicit Poisson solve above rather than after it, which
804 // is what the base ItoKMCStepper::regrid() already did. Only observable at m_timeStep == 0, where
805 // computeSpaceChargeDensity() deposits the bulk particles; every later step solves from
806 // m_rhoDaggerParticles, and the conductivity comes from m_conductivityParticles. A merge
807 // conserves total weight, so the deposited density is preserved to the merge's spatial accuracy.
808
809 // Now let Ihe ito solver deposit its actual particles... In the above it deposit m_rhoDaggerParticles.
810 m_timer.startEvent("Deposit particles");
811 (this->m_ito)->depositParticles();
812 m_timer.stopEvent("Deposit particles");
813
814 // Recompute new velocities and diffusion coefficients
815 m_timer.startEvent("Prepare next step");
816 this->computeDiffusionCoefficients();
817 this->computeDriftVelocities();
818 m_timer.stopEvent("Prepare next step");
819
820 m_timer.eventReport(pout(), false);
821
822 // No reason to have these lying around.
823 m_scratchSemiImplicitRhoCDR.clear();
824 m_scratchSemiImplicitConductivityCDR.clear();
825
826 // Fill the neutral density on the mesh
827 this->fillNeutralDensity();
828}
829
830template <typename I, typename C, typename R, typename F>
831void
833{
834 CH_TIME("ItoKMCGodunovStepper::setOldPositions");
835 if (this->m_verbosity > 5) {
836 pout() << this->m_name + "::setOldPositions" << endl;
837 }
838
839 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
840 RefCountedPtr<ItoSolver>& solver = solverIt();
841
842 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
843 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
844 const DataIterator& dit = dbl.dataIterator();
845
846 auto& particles = solver->getParticles(ItoSolver::WhichContainer::Bulk)[lvl];
847
848 const int nbox = dit.size();
849
850#pragma omp parallel for schedule(runtime)
851 for (int mybox = 0; mybox < nbox; mybox++) {
852 const DataIndex& din = dit[mybox];
853
854 ParticleSoA<ItoParticle>& leaf = particles[din];
855
856 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
857 double* const oldPos[SpaceDim] = {D_DECL(leaf.template column<&ItoParticle::old_x>(),
858 leaf.template column<&ItoParticle::old_y>(),
859 leaf.template column<&ItoParticle::old_z>())};
860
861 ParticleLoops::loop(leaf, [&](const std::size_t i) {
862 D_DECL(oldPos[0][i] = pos[0][i], oldPos[1][i] = pos[1][i], oldPos[2][i] = pos[2][i]);
863 });
864 }
865 }
866 }
867}
868
869template <typename I, typename C, typename R, typename F>
870void
872 const SpeciesSubset a_subset) noexcept
873{
874 CH_TIME("ItoKMCGodunovStepper::remapPointParticles");
875 if (this->m_verbosity > 5) {
876 pout() << this->m_name + "::remapPointParticles" << endl;
877 }
878
879 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
880 RefCountedPtr<ItoSolver>& solver = solverIt();
881 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
882
883 const int idx = solverIt.index();
884
885 const bool mobile = solver->isMobile();
886 const bool diffusive = solver->isDiffusive();
887 const bool charged = species->getChargeNumber() != 0;
888
889 switch (a_subset) {
890 case SpeciesSubset::All: {
891 a_particles[idx]->remap();
892
893 break;
894 }
895 case SpeciesSubset::AllMobile: {
896 if (mobile) {
897 a_particles[idx]->remap();
898 }
899
900 break;
901 }
902 case SpeciesSubset::AllDiffusive: {
903 if (diffusive) {
904 a_particles[idx]->remap();
905 }
906
907 break;
908 }
909 case SpeciesSubset::AllMobileOrDiffusive: {
910 if (mobile || diffusive) {
911 a_particles[idx]->remap();
912 }
913
914 break;
915 }
916 case SpeciesSubset::AllMobileAndDiffusive: {
917 if (mobile && diffusive) {
918 a_particles[idx]->remap();
919 }
920
921 break;
922 }
923 case SpeciesSubset::Charged: {
924 if (charged) {
925 a_particles[idx]->remap();
926 }
927
928 break;
929 }
930 case SpeciesSubset::ChargedMobile: {
931 if (charged && mobile) {
932 a_particles[idx]->remap();
933 }
934
935 break;
936 }
937 case SpeciesSubset::ChargedDiffusive: {
938 if (charged && diffusive) {
939 a_particles[idx]->remap();
940 }
941
942 break;
943 }
944 case SpeciesSubset::ChargedMobileOrDiffusive: {
945 if (charged && (mobile || diffusive)) {
946 a_particles[idx]->remap();
947 }
948
949 break;
950 }
951 case SpeciesSubset::ChargedMobileAndDiffusive: {
952 if (charged && (mobile && diffusive)) {
953 a_particles[idx]->remap();
954 }
955
956 break;
957 }
958 case SpeciesSubset::Stationary: {
959 if (!mobile && !diffusive) {
960 a_particles[idx]->remap();
961 }
962
963 break;
964 }
965 default: {
966 MayDay::Abort("ItoKMCGodunovStepper::remapPointParticles - logic bust");
967
968 break;
969 }
970 }
971 }
972}
973
974template <typename I, typename C, typename R, typename F>
975void
977 const Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_particles,
978 const SpeciesSubset a_subset) noexcept
979{
980 CH_TIME("ItoKMCGodunovStepper::depositPointParticles");
981 if (this->m_verbosity > 5) {
982 pout() << this->m_name + "::depositPointParticles" << endl;
983 }
984
985 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
986 RefCountedPtr<ItoSolver>& solver = solverIt();
987 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
988
989 const int idx = solverIt.index();
990
991 const bool mobile = solver->isMobile();
992 const bool diffusive = solver->isDiffusive();
993 const bool charged = species->getChargeNumber() != 0;
994
995 switch (a_subset) {
996 case SpeciesSubset::All: {
997 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
998
999 break;
1000 }
1001 case SpeciesSubset::AllMobile: {
1002 if (mobile) {
1003 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1004 }
1005
1006 break;
1007 }
1008 case SpeciesSubset::AllDiffusive: {
1009 if (diffusive) {
1010 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1011 }
1012
1013 break;
1014 }
1015 case SpeciesSubset::AllMobileOrDiffusive: {
1016 if (mobile || diffusive) {
1017 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1018 }
1019 break;
1020 }
1021 case SpeciesSubset::AllMobileAndDiffusive: {
1022 if (mobile && diffusive) {
1023 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1024 }
1025 break;
1026 }
1027 case SpeciesSubset::Charged: {
1028 if (charged) {
1029 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1030 }
1031 break;
1032 }
1033 case SpeciesSubset::ChargedMobile: {
1034 if (charged && mobile) {
1035 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1036 }
1037 break;
1038 }
1039 case SpeciesSubset::ChargedDiffusive: {
1040 if (charged && diffusive) {
1041 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1042 }
1043
1044 break;
1045 }
1046 case SpeciesSubset::ChargedMobileOrDiffusive: {
1047 if (charged && (mobile || diffusive)) {
1048 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1049 }
1050
1051 break;
1052 }
1053 case SpeciesSubset::ChargedMobileAndDiffusive: {
1054 if (charged && (mobile && diffusive)) {
1055 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1056 }
1057
1058 break;
1059 }
1060 case SpeciesSubset::Stationary: {
1061 if (!mobile && !diffusive) {
1062 depositPointParticlesLikeSolver(solver, solver->getPhi(), *a_particles[idx]);
1063 }
1064
1065 break;
1066 }
1067 default: {
1068 MayDay::Abort("ItoKMCGodunovStepper::depositPointParticles - logic bust");
1069
1070 break;
1071 }
1072 }
1073 }
1074}
1075
1076template <typename I, typename C, typename R, typename F>
1077void
1079 const Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_particles,
1080 const SpeciesSubset a_subset) noexcept
1081{
1082 CH_TIME("ItoKMCGodunovStepper::clearPointParticles");
1083 if (this->m_verbosity > 5) {
1084 pout() << this->m_name + "::clearPointParticles" << endl;
1085 }
1086
1087 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1088 RefCountedPtr<ItoSolver>& solver = solverIt();
1089 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1090
1091 const int idx = solverIt.index();
1092
1093 const bool mobile = solver->isMobile();
1094 const bool diffusive = solver->isDiffusive();
1095 const bool charged = species->getChargeNumber() != 0;
1096
1097 switch (a_subset) {
1098 case SpeciesSubset::All: {
1099 a_particles[idx]->clearParticles();
1100
1101 break;
1102 }
1103 case SpeciesSubset::AllMobile: {
1104 if (mobile) {
1105 a_particles[idx]->clearParticles();
1106 }
1107
1108 break;
1109 }
1110 case SpeciesSubset::AllDiffusive: {
1111 if (diffusive) {
1112 a_particles[idx]->clearParticles();
1113 }
1114
1115 break;
1116 }
1117 case SpeciesSubset::AllMobileOrDiffusive: {
1118 if (mobile || diffusive) {
1119 a_particles[idx]->clearParticles();
1120 }
1121
1122 break;
1123 }
1124 case SpeciesSubset::AllMobileAndDiffusive: {
1125 if (mobile && diffusive) {
1126 a_particles[idx]->clearParticles();
1127 }
1128
1129 break;
1130 }
1131 case SpeciesSubset::Charged: {
1132 if (charged) {
1133 a_particles[idx]->clearParticles();
1134 }
1135
1136 break;
1137 }
1138 case SpeciesSubset::ChargedMobile: {
1139 if (charged && mobile) {
1140 a_particles[idx]->clearParticles();
1141 }
1142
1143 break;
1144 }
1145 case SpeciesSubset::ChargedDiffusive: {
1146 if (charged && diffusive) {
1147 a_particles[idx]->clearParticles();
1148 }
1149
1150 break;
1151 }
1152 case SpeciesSubset::ChargedMobileOrDiffusive: {
1153 if (charged && (mobile || diffusive)) {
1154 a_particles[idx]->clearParticles();
1155 }
1156
1157 break;
1158 }
1159 case SpeciesSubset::ChargedMobileAndDiffusive: {
1160 if (charged && (mobile && diffusive)) {
1161 a_particles[idx]->clearParticles();
1162 }
1163
1164 break;
1165 }
1166 case SpeciesSubset::Stationary: {
1167 if (!mobile && !diffusive) {
1168 a_particles[idx]->clearParticles();
1169 }
1170
1171 break;
1172 }
1173 default: {
1174 MayDay::Abort("ItoKMCGodunovStepper::clearPointParticles - logic bust");
1175
1176 break;
1177 }
1178 }
1179 }
1180}
1181
1182template <typename I, typename C, typename R, typename F>
1183void
1185{
1186 CH_TIME("ItoKMCGodunovStepper::computeCdrConductivity");
1187 if (this->m_verbosity > 5) {
1188 pout() << this->m_name + "::computeCdrConductivity" << endl;
1189 }
1190
1191 DataOps::setValue(m_semiImplicitConductivityCDR, 0.0);
1192
1193 for (auto solverIt = (this->m_cdr)->iterator(); solverIt.ok(); ++solverIt) {
1194 const RefCountedPtr<CdrSolver>& solver = solverIt();
1195 const RefCountedPtr<CdrSpecies>& species = solver->getSpecies();
1196
1197 const int index = solverIt.index();
1198 const int Z = species->getChargeNumber();
1199
1200 if (Z != 0 && solver->isMobile()) {
1201 const EBAMRCellData& phi = solver->getPhi();
1202 const EBAMRCellData& mu = this->m_cdrMobilities[index];
1203
1204 DataOps::copy(this->m_fluidScratch1, phi);
1205 DataOps::multiply(this->m_fluidScratch1, mu);
1206
1207 DataOps::incr(m_semiImplicitConductivityCDR, this->m_fluidScratch1, 1.0 * std::abs(Z));
1208 }
1209 }
1210}
1211
1212template <typename I, typename C, typename R, typename F>
1213void
1215 const Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_particles,
1216 const bool a_useStoredCdrConductivity) noexcept
1217{
1218 CH_TIME("ItoKMCGodunovStepper::computeConductivities");
1219 if (this->m_verbosity > 5) {
1220 pout() << this->m_name + "::computeConductivities" << endl;
1221 }
1222
1223 this->computeCellConductivity((this->m_conductivityCell), a_particles, a_useStoredCdrConductivity);
1224 this->computeFaceConductivity();
1225}
1226
1227template <typename I, typename C, typename R, typename F>
1228void
1230 EBAMRCellData& a_conductivityCell,
1231 const Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_particles,
1232 const bool a_useStoredCdrConductivity) noexcept
1233{
1234 CH_TIME("ItoKMCGodunovStepper::computeCellConductivity(EBAMRCellData, ParticleContainer)");
1235 if (this->m_verbosity > 5) {
1236 pout() << this->m_name + "::computeCellConductivity(EBAMRCellData, ParticleContainer)" << endl;
1237 }
1238
1239 DataOps::setValue(a_conductivityCell, 0.0);
1240
1241 // Contribution from Ito solvers.
1242 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1243 RefCountedPtr<ItoSolver>& solver = solverIt();
1244 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1245
1246 const int idx = solverIt.index();
1247 const int Z = species->getChargeNumber();
1248
1249 if (Z != 0 && solver->isMobile()) {
1250 // Deposit on the particle realm.
1251 DataOps::setValue(this->m_particleScratch1, 0.0);
1252 depositPointParticlesLikeSolver(solver, this->m_particleScratch1, *a_particles[idx]);
1253
1254 // Copy to fluid realm and add to total conductivity.
1255 (this->m_amr)->copyData(this->m_fluidScratch1, this->m_particleScratch1);
1256 DataOps::incr(a_conductivityCell, this->m_fluidScratch1, 1.0 * std::abs(Z));
1257 }
1258 }
1259
1260 // Contribution from the CDR solvers, always taken from m_semiImplicitConductivityCDR. The flag decides only
1261 // whether that buffer is refreshed from the solver states first, which it must not be inside regrid(), where
1262 // the mobilities it is built from are not valid for the current grids.
1263 if (!a_useStoredCdrConductivity) {
1264 this->computeCdrConductivity();
1265 }
1266
1267 DataOps::incr(a_conductivityCell, m_semiImplicitConductivityCDR, 1.0);
1268
1269 // Conductivity is mobility * weight * Q
1270 DataOps::scale(a_conductivityCell, Units::Qe);
1271
1272 // Coarsen, update ghost cells and interpolate to centroids. User can ask for bi/tri-linear filtering.
1273 (this->m_amr)->arithmeticAverage(a_conductivityCell, this->m_fluidRealm, (this->m_plasmaPhase));
1274 (this->m_amr)->interpGhostPwl(a_conductivityCell, this->m_fluidRealm, (this->m_plasmaPhase));
1275
1276 // User can choose to filter the conductivity. Need to sync after each smoothing.
1277 if (m_condFilterNum > 0 && m_condFilterMaxStride > 0) {
1278 for (int i = 0; i < m_condFilterNum; i++) {
1279 for (int curStride = 1; curStride <= m_condFilterMaxStride; curStride++) {
1280 DataOps::filterSmooth(a_conductivityCell, m_condFilterAlpha, curStride, true);
1281
1282 (this->m_amr)->arithmeticAverage(a_conductivityCell, this->m_fluidRealm, (this->m_plasmaPhase));
1283 (this->m_amr)->interpGhostPwl(a_conductivityCell, this->m_fluidRealm, (this->m_plasmaPhase));
1284 }
1285 }
1286 }
1287
1288 (this->m_amr)->interpToCentroids(a_conductivityCell, this->m_fluidRealm, (this->m_plasmaPhase));
1289
1290 // The sum itself is non-negative, but the CDR part is interpolated across regrids, filterSmooth may smooth
1291 // it, and interpToCentroids uses stencils with negative weights. Floor after the last of those so that the
1292 // bound holds where the data is consumed -- a negative conductivity enters the field solve as
1293 // eps + sigma*dt/eps0 < eps.
1294 DataOps::floor(a_conductivityCell, 0.0, (this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
1295}
1296
1297template <typename I, typename C, typename R, typename F>
1298void
1300{
1301 CH_TIME("ItoKMCGodunovStepper::computeFaceConductivity");
1302 if (this->m_verbosity > 5) {
1303 pout() << this->m_name + "::computeFaceConductivity" << endl;
1304 }
1305
1306 DataOps::setValue((this->m_conductivityFace), 0.0);
1307 DataOps::setValue((this->m_conductivityEB), 0.0);
1308
1309 // Average the cell-centered conductivity to faces. Note that this includes one "ghost face", which we need
1310 // because the multigrid solver will interpolate face-centered conductivities to face centroids.
1311 const Average average = Average::Arithmetic;
1312 const int tanGhost = 1;
1313 const Interval interv(0, 0);
1314
1316 (this->m_conductivityFace),
1317 (this->m_conductivityCell),
1318 (this->m_amr)->getDomains(),
1319 tanGhost,
1320 interv,
1321 interv,
1322 average,
1323 (this->m_amr)->getFaceIteratorWithTangentialGhosts(this->m_fluidRealm, this->m_plasmaPhase));
1324
1325 // Set the EB conductivity.
1326 DataOps::incr((this->m_conductivityEB),
1327 (this->m_conductivityCell),
1328 1.0,
1329 (this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
1330}
1331
1332template <typename I, typename C, typename R, typename F>
1333void
1335{
1336 CH_TIMERS("ItoKMCGodunovStepper::computeSemiImplicitRho");
1337 CH_TIMER("ItoKMCGodunovStepper::computeSemiImplicitRho::plasma_phase", t1);
1338 CH_TIMER("ItoKMCGodunovStepper::computeSemiImplicitRho::solid_phase", t2);
1339 CH_TIMER("ItoKMCGodunovStepper::computeSemiImplicitRho::filter", t3);
1340 if (this->m_verbosity > 5) {
1341 pout() << this->m_name + "::computeSemiImplicitRho" << endl;
1342 }
1343
1344 // Soft requirement?
1345 CH_assert(this->m_plasmaPhase == phase::gas);
1346
1347 const RefCountedPtr<MultiFluidIndexSpace>& mfis = (this->m_computationalGeometry)->getMfIndexSpace();
1348 const Vector<Dielectric>& dielectrics = (this->m_computationalGeometry)->getDielectrics();
1349
1350 const bool hasDielectrics = (mfis->numPhases() > 1) && (dielectrics.size() > 0);
1351
1352 MFAMRCellData& rho = this->m_fieldSolver->getRho();
1353 EBAMRCellData rhoGas = (this->m_amr)->alias(phase::gas, rho);
1354 EBAMRCellData rhoSolid;
1355
1356 if (hasDielectrics) {
1357 rhoSolid = (this->m_amr)->alias(phase::solid, rho);
1358 }
1359
1360 DataOps::setValue(rho, 0.0);
1361
1362 // Contribution from Ito solvers to the gas-side space charge density.
1363 CH_START(t1);
1364 for (auto solverIt = this->m_ito->iterator(); solverIt.ok(); ++solverIt) {
1365 const RefCountedPtr<ItoSolver>& solver = solverIt();
1366 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1367 const int Z = species->getChargeNumber();
1368
1369 if (Z != 0) {
1370 (this->m_amr)->copyData(this->m_fluidScratch1, solver->getPhi());
1371
1372 DataOps::incr(rhoGas, this->m_fluidScratch1, 1.0 * Z * Units::Qe);
1373 }
1374 }
1375
1376 // Contribution from CDR equations to the gas-side space charge density.
1377 DataOps::incr(rhoGas, m_semiImplicitRhoCDR, 1.0);
1378 CH_STOP(t1);
1379
1380 // Contribution from gas-side particles that diffused into EBs. This might be necessary near dielectric EBs as a
1381 // comparatively small correction in the space charge density. There should be no contribution from the CDR solvers
1382 // because the diffusion-only divergence term was computed using homogeneous Neumann boundary conditions.
1383 if (hasDielectrics) {
1384 CH_START(t2);
1385
1386 EBAMRCellData particleScratch;
1387 EBAMRCellData fluidScratch;
1388
1389 (this->m_amr)->allocate(particleScratch, this->m_particleRealm, phase::solid, 1);
1390 (this->m_amr)->allocate(fluidScratch, this->m_fluidRealm, phase::solid, 1);
1391
1392 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1393 const RefCountedPtr<ItoSolver>& solver = solverIt();
1394 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1395 const int Z = species->getChargeNumber();
1396
1397 if (Z != 0) {
1398 DataOps::setValue(particleScratch, 0.0);
1399 DataOps::setValue(fluidScratch, 0.0);
1400
1401 (this->m_amr)
1402 ->depositWeight(particleScratch,
1403 this->m_particleRealm,
1405 *m_rhoDaggerParticles[solverIt.index()],
1406 DepositionType::CIC,
1407 CoarseFineDeposition::Halo,
1408 true);
1409
1410 (this->m_amr)->copyData(fluidScratch, particleScratch);
1411
1412 DataOps::incr(rhoSolid, fluidScratch, 1.0 * Z * Units::Qe);
1413 }
1414 }
1415
1416 CH_STOP(t2);
1417 }
1418
1419 // Sync across levels
1420 this->m_amr->arithmeticAverage(rho, this->m_fluidRealm);
1421 this->m_amr->interpGhostPwl(rho, this->m_fluidRealm);
1422
1423 // User can choose to filter the space charge density. Need to sync after each smoothing.
1424 if (m_rhoFilterNum > 0 && m_rhoFilterMaxStride > 0) {
1425 CH_START(t3);
1426 for (int i = 0; i < m_rhoFilterNum; i++) {
1427 for (int curStride = 1; curStride <= m_rhoFilterMaxStride; curStride++) {
1428
1429 DataOps::filterSmooth(rhoGas, m_rhoFilterAlpha, curStride, true);
1430
1431 this->m_amr->arithmeticAverage(rhoGas, this->m_fluidRealm, this->m_plasmaPhase);
1432 this->m_amr->interpGhost(rhoGas, this->m_fluidRealm, this->m_plasmaPhase);
1433 }
1434 }
1435 CH_STOP(t3);
1436 }
1437
1438 // Put data on centroids.
1439 this->m_amr->interpToCentroids(rhoGas, this->m_fluidRealm, phase::gas);
1440 if (hasDielectrics) {
1441 this->m_amr->interpToCentroids(rhoSolid, this->m_fluidRealm, phase::solid);
1442 }
1443}
1444
1445template <typename I, typename C, typename R, typename F>
1446void
1448{
1449 CH_TIME("ItoKMCGodunovStepper::setupSemiImplicitPoisson");
1450 if (this->m_verbosity > 5) {
1451 pout() << this->m_name + "::setupSemiImplicitPoisson" << endl;
1452 }
1453
1454 // Set coefficients as usual
1455 (this->m_fieldSolver)->setPermittivities();
1456
1457 // Get the permittivities
1458 MFAMRCellData& permCell = (this->m_fieldSolver)->getPermittivityCell();
1459 MFAMRFluxData& permFace = (this->m_fieldSolver)->getPermittivityFace();
1460 MFAMRIVData& permEB = (this->m_fieldSolver)->getPermittivityEB();
1461
1462 // Get handles to the gas-phase permittivities.
1463 EBAMRFluxData permFaceGas = (this->m_amr)->alias((this->m_plasmaPhase), permFace);
1464 EBAMRIVData permEBGas = (this->m_amr)->alias((this->m_plasmaPhase), permEB);
1465
1466 // Increment the field solver permittivities by a_factor*sigma. After this, the "permittivities" are
1467 // given by epsr + a_factor*sigma
1468 DataOps::incr(permFaceGas, (this->m_conductivityFace), a_dt / Units::eps0);
1469 DataOps::incr(permEBGas,
1470 (this->m_conductivityEB),
1471 a_dt / Units::eps0,
1472 (this->m_amr)->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
1473
1474 // Coarsen coefficients.
1475 (this->m_amr)->arithmeticAverage(permFaceGas, this->m_fluidRealm, (this->m_plasmaPhase));
1476 (this->m_amr)->arithmeticAverage(permEBGas, this->m_fluidRealm, (this->m_plasmaPhase));
1477
1478 // Set up the solver with the "permittivities"
1479 (this->m_fieldSolver)->setSolverPermittivities(permCell, permFace, permEB);
1480}
1481
1482template <typename I, typename C, typename R, typename F>
1483void
1485 Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_particles,
1486 const EBRepresentation a_representation,
1487 const Real a_tolerance) const noexcept
1488{
1489 CH_TIME("ItoKMCGodunovStepper::removeCoveredPointParticles");
1490 if (this->m_verbosity > 5) {
1491 pout() << this->m_name + "::removeCoveredPointParticles" << endl;
1492 }
1493
1494 for (int i = 0; i < a_particles.size(); i++) {
1495 if (a_particles[i] != nullptr) {
1496 ParticleContainer<NoPayload>& particles = *a_particles[i];
1497
1498 switch (a_representation) {
1499 case EBRepresentation::Discrete: {
1500 (this->m_amr)->removeCoveredParticlesDiscrete(particles, (this->m_plasmaPhase), a_tolerance);
1501
1502 break;
1503 }
1504 case EBRepresentation::ImplicitFunction: {
1505 (this->m_amr)->removeCoveredParticlesIF(particles, (this->m_plasmaPhase), a_tolerance);
1506
1507 break;
1508 }
1509 case EBRepresentation::Voxel: {
1510 (this->m_amr)->removeCoveredParticlesVoxels(particles, (this->m_plasmaPhase));
1511
1512 break;
1513 }
1514 default: {
1515 MayDay::Error("ItoKMCGodunovStepper::removeCoveredParticles - logic bust");
1516 }
1517 }
1518 }
1519 }
1520}
1521
1522template <typename I, typename C, typename R, typename F>
1523void
1525 Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_conductivityParticles) noexcept
1526{
1527 CH_TIME("ItoKMCGodunovStepper::copyConductivityParticles");
1528 if (this->m_verbosity > 5) {
1529 pout() << this->m_name + "::copyConductivityParticles" << endl;
1530 }
1531
1532 // Clear particles first.
1533 this->clearPointParticles(a_conductivityParticles, SpeciesSubset::All);
1534
1535 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1536 const RefCountedPtr<ItoSolver>& solver = solverIt();
1537 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1538
1539 const int idx = solverIt.index();
1540 const int Z = species->getChargeNumber();
1541
1542 if (Z != 0 && solver->isMobile()) {
1543 const ParticleContainer<ItoParticle>& solverParticles = solver->getParticles(ItoSolver::WhichContainer::Bulk);
1544
1545 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
1546 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
1547 const DataIterator& dit = dbl.dataIterator();
1548
1549 const int nbox = dit.size();
1550
1551#pragma omp parallel for schedule(runtime)
1552 for (int mybox = 0; mybox < nbox; mybox++) {
1553 const DataIndex& din = dit[mybox];
1554
1555 const ParticleSoA<ItoParticle>& leaf = solverParticles[lvl][din];
1556
1557 ParticleSoA<NoPayload>& pointParticles = (*a_conductivityParticles[idx])[lvl][din];
1558 ParticleSoA<NoPayload>& irregParticles = (*m_irregularParticles[idx])[lvl][din];
1559
1560 for (std::size_t i = 0; i < leaf.size(); i++) {
1561 const RealVect pos = leaf.position(i);
1562 const Real weight = leaf.weight(i);
1563 const Real mobility = leaf.template get<&ItoParticle::mobility>(i);
1564
1565 pointParticles.append(pos, weight * mobility);
1566 }
1567
1568 pointParticles.catenate(irregParticles);
1569 }
1570 }
1571 }
1572 }
1573}
1574
1575template <typename I, typename C, typename R, typename F>
1576bool
1578{
1579 CH_TIME("ItoKMCGodunovStepper::solvePoisson()");
1580 if (this->m_verbosity > 5) {
1581 pout() << this->m_name + "::solvePoisson()" << endl;
1582 }
1583
1584 // Solve the Poisson equation and compute the cell-centered electric field.
1585 MFAMRCellData& phi = this->m_fieldSolver->getPotential();
1586 MFAMRCellData& rho = this->m_fieldSolver->getRho();
1587 EBAMRIVData& sigma = this->m_sigmaSolver->getPhi();
1588
1589 const bool converged = (this->m_fieldSolver)->solve(phi, rho, sigma, false);
1590
1591 (this->m_fieldSolver)->computeElectricField();
1592
1593 // Copy the electric field to appropriate data holders and perform center-to-centroid
1594 // interpolation.
1595 EBAMRCellData E;
1596 (this->m_amr)->allocatePointer(E, this->m_fluidRealm);
1597 (this->m_amr)->alias(E, this->m_plasmaPhase, (this->m_fieldSolver)->getElectricField());
1598
1599 // Fluid realm
1600 (this->m_amr)->copyData(this->m_electricFieldFluid, E);
1601 (this->m_amr)->conservativeAverage(this->m_electricFieldFluid, this->m_fluidRealm, this->m_plasmaPhase);
1602 (this->m_amr)->interpGhostPwl(this->m_electricFieldFluid, this->m_fluidRealm, this->m_plasmaPhase);
1603 (this->m_amr)->interpToCentroids(this->m_electricFieldFluid, this->m_fluidRealm, this->m_plasmaPhase);
1604
1605 // Particle realm
1606 (this->m_amr)->copyData(this->m_electricFieldParticle, E);
1607 (this->m_amr)->conservativeAverage(this->m_electricFieldParticle, this->m_particleRealm, this->m_plasmaPhase);
1608 (this->m_amr)->interpGhostPwl(this->m_electricFieldParticle, this->m_particleRealm, this->m_plasmaPhase);
1609 (this->m_amr)->interpToCentroids(this->m_electricFieldParticle, this->m_particleRealm, this->m_plasmaPhase);
1610
1611 return converged;
1612}
1613
1614template <typename I, typename C, typename R, typename F>
1615void
1617{
1618 CH_TIME("ItoKMCGodunovStepper::advanceEulerMaruyama");
1619 if (this->m_verbosity > 5) {
1620 pout() << this->m_name + "::advanceEulerMaruyama" << endl;
1621 }
1622
1623 // Store X^k positions.
1624 this->setOldPositions();
1625
1626 // Diffuse the particles. This copies onto m_rhoDaggerParticles and stores the hop on the full particles. We need
1627 // to remap the particles species that made a diffusion hop.
1628 this->barrier();
1629 m_timer.startEvent("Diffuse particles");
1630 this->diffuseParticlesEulerMaruyama(m_rhoDaggerParticles, a_dt);
1631 this->remapPointParticles(m_rhoDaggerParticles, SpeciesSubset::ChargedDiffusive);
1632 m_timer.stopEvent("Diffuse particles");
1633
1634 // Perform the diffusive CDR advance.
1635 this->barrier();
1636 m_timer.startEvent("Diffuse CDR");
1637 this->computeDiffusionTermCDR(m_semiImplicitRhoCDR, a_dt);
1638 m_timer.stopEvent("Diffuse CDR");
1639
1640 // Compute the conductivity on the mesh. This deposits q_e * Z * w * mu on the mesh.
1641 this->barrier();
1642 m_timer.startEvent("Compute conductivities");
1643 this->copyConductivityParticles(m_conductivityParticles);
1644 this->computeConductivities(m_conductivityParticles, false);
1645 m_timer.stopEvent("Compute conductivities");
1646
1647 // Set up the semi-implicit Poisson solver with the computed conductivities.
1648 this->barrier();
1649 m_timer.startEvent("Setup Poisson");
1650 this->setupSemiImplicitPoisson(a_dt);
1651 m_timer.stopEvent("Setup Poisson");
1652
1653 // Compute space charge density arising from the new particle positions X^k + sqrt(2*D*dt)*W. Only need to
1654 // do the diffusive and charged species.
1655 this->barrier();
1656 m_timer.startEvent("Deposit point particles");
1657 this->depositPointParticles(m_rhoDaggerParticles, SpeciesSubset::Charged);
1658 this->computeSemiImplicitRho();
1659 m_timer.stopEvent("Deposit point particles");
1660
1661 // Solve the semi-implicit Poisson equation.
1662 this->barrier();
1663 m_timer.startEvent("Solve Poisson");
1664 const bool converged = this->solvePoisson();
1665 if (!converged) {
1666 const std::string errMsg = "ItoKMCGodunovStepper::advanceEulerMaruyama - Poisson solve did not converge";
1667
1668 pout() << errMsg << endl;
1669
1670 if (this->m_abortOnFailure) {
1671 MayDay::Error(errMsg.c_str());
1672 }
1673 }
1674 m_timer.stopEvent("Solve Poisson");
1675
1676 // Recompute velocities with the new electric field. This interpolates the velocities to the current particle
1677 // positions, i.e. we compute V^(k+1)(X^k) = mu^k * E^(k+1)(X^k)
1678 this->barrier();
1679 m_timer.startEvent("Step-compute v");
1680#if 1 // This is what the algorithm says.
1681 this->setCdrVelocityFunctions();
1682 this->setItoVelocityFunctions();
1683 (this->m_ito)->interpolateVelocities();
1684 this->multiplyCdrVelocitiesByMobilities();
1685#else // Have to use this for LEA - need to debug.
1686 this->computeDriftVelocities();
1687#endif
1688 m_timer.stopEvent("Step-compute v");
1689
1690 // Finalize the Euler-Maruyama update.
1691 this->barrier();
1692 m_timer.startEvent("Euler-Maruyama step");
1693 this->stepEulerMaruyamaParticles(a_dt);
1694 this->remapParticles(SpeciesSubset::AllMobileOrDiffusive);
1695 this->stepEulerMaruyamaCDR(a_dt);
1696 m_timer.stopEvent("Euler-Maruyama step");
1697}
1698
1699template <typename I, typename C, typename R, typename F>
1700void
1702 Vector<RefCountedPtr<ParticleContainer<NoPayload>>>& a_rhoDaggerParticles,
1703 const Real a_dt) noexcept
1704{
1705 CH_TIME("ItoKMCGodunovStepper::diffuseParticlesEulerMaruyama");
1706 if (this->m_verbosity > 5) {
1707 pout() << this->m_name + "::diffuseParticlesEulerMaruyama" << endl;
1708 }
1709
1710 this->clearPointParticles(a_rhoDaggerParticles, SpeciesSubset::All);
1711
1712 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1713 RefCountedPtr<ItoSolver>& solver = solverIt();
1714 const RefCountedPtr<ItoSpecies>& species = solver->getSpecies();
1715
1716 const int idx = solverIt.index();
1717
1718 const bool mobile = solver->isMobile();
1719 const bool diffusive = solver->isDiffusive();
1720 const int Z = species->getChargeNumber();
1721
1722 const auto& diffusionFunction = (this->m_physics)->getItoDiffusionFunctions()[idx];
1723
1724 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
1725 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
1726 const DataIterator& dit = dbl.dataIterator();
1727
1728 auto& particles = solver->getParticles(ItoSolver::WhichContainer::Bulk)[lvl];
1729
1730 const int nbox = dit.size();
1731
1732#pragma omp parallel for schedule(runtime)
1733 for (int mybox = 0; mybox < nbox; mybox++) {
1734 const DataIndex& din = dit[mybox];
1735
1736 ParticleSoA<ItoParticle>& leaf = particles[din];
1737 ParticleSoA<NoPayload>& pointParticles = (*a_rhoDaggerParticles[idx])[lvl][din];
1738
1739 for (std::size_t i = 0; i < leaf.size(); i++) {
1740 const Real weight = leaf.weight(i);
1741 const RealVect pos = leaf.position(i);
1742
1743 // Compute a particle hop and store it on the run-time storage. The DiffusionFunction reads payload
1744 // columns (diffusion/velocity), so materialize the payload via gather().
1745 const ItoParticle p = leaf.gather(i);
1746 const RealVect hop = diffusive ? diffusionFunction(p, a_dt) : RealVect::Zero;
1747
1748 D_DECL(leaf.template get<&ItoParticle::scratch_x>(i) = static_cast<ParticleReal>(hop[0]),
1749 leaf.template get<&ItoParticle::scratch_y>(i) = static_cast<ParticleReal>(hop[1]),
1750 leaf.template get<&ItoParticle::scratch_z>(i) = static_cast<ParticleReal>(hop[2]));
1751
1752 if (Z != 0) {
1753 pointParticles.append(pos + hop, weight);
1754 }
1755 }
1756 }
1757 }
1758 }
1759}
1760
1761template <typename I, typename C, typename R, typename F>
1762void
1763ItoKMCGodunovStepper<I, C, R, F>::computeDiffusionTermCDR(EBAMRCellData& a_semiImplicitRhoCDR, const Real a_dt) noexcept
1764{
1765 CH_TIME("ItoKMCGodunovStepper::diffuseCDREulerMaruyama");
1766 if (this->m_verbosity > 5) {
1767 pout() << this->m_name + "::diffuseCDREulerMaruyama" << endl;
1768 }
1769
1770 DataOps::setValue(a_semiImplicitRhoCDR, 0.0);
1771
1772 for (auto solverIt = this->m_cdr->iterator(); solverIt.ok(); ++solverIt) {
1773 const RefCountedPtr<CdrSolver>& solver = solverIt();
1774 const RefCountedPtr<CdrSpecies>& species = solver->getSpecies();
1775
1776 const int index = solverIt.index();
1777 const int Z = species->getChargeNumber();
1778
1779 const EBAMRCellData& phi = solver->getPhi();
1780
1781 // Compute finite-volume approximation to div(D*grad(phi))
1782 if (solver->isDiffusive()) {
1783 solver->computeDivD(m_cdrDivD[index], solver->getPhi(), false, false, false);
1784 }
1785
1786 // Update the space charge density arising from the update phi^dagger = phi^k + dt * div(D*grad(phi^k))
1787 if (Z != 0) {
1788 DataOps::incr(a_semiImplicitRhoCDR, phi, 1.0 * Z);
1789 if (solver->isDiffusive()) {
1790 DataOps::incr(a_semiImplicitRhoCDR, m_cdrDivD[index], 1.0 * Z * a_dt);
1791 }
1792 }
1793 }
1794
1795 DataOps::scale(a_semiImplicitRhoCDR, Units::Qe);
1796
1797 this->m_amr->arithmeticAverage(a_semiImplicitRhoCDR, this->m_fluidRealm, this->m_plasmaPhase);
1798 this->m_amr->interpGhostPwl(a_semiImplicitRhoCDR, this->m_fluidRealm, this->m_plasmaPhase);
1799}
1800
1801template <typename I, typename C, typename R, typename F>
1802void
1804{
1805 CH_TIME("ItoKMCGodunovStepper::stepEulerMaruyamaParticles");
1806 if (this->m_verbosity > 5) {
1807 pout() << this->m_name + "::stepEulerMaruyamaParticles" << endl;
1808 }
1809
1810 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
1811 RefCountedPtr<ItoSolver>& solver = solverIt();
1812
1813 const bool mobile = solver->isMobile();
1814 const bool diffusive = solver->isDiffusive();
1815
1816 const Real f = mobile ? a_dt : 0.0;
1817 const Real g = diffusive ? 1.0 : 0.0;
1818
1819 if (mobile || diffusive) {
1820 for (int lvl = 0; lvl <= (this->m_amr)->getFinestLevel(); lvl++) {
1821 const DisjointBoxLayout& dbl = (this->m_amr)->getGrids((this->m_particleRealm))[lvl];
1822 const DataIterator& dit = dbl.dataIterator();
1823
1824 auto& particles = solver->getParticles(ItoSolver::WhichContainer::Bulk)[lvl];
1825
1826 const int nbox = dit.size();
1827
1828#pragma omp parallel for schedule(runtime)
1829 for (int mybox = 0; mybox < nbox; mybox++) {
1830 const DataIndex& din = dit[mybox];
1831
1832 ParticleSoA<ItoParticle>& leaf = particles[din];
1833
1834 double* const pos[SpaceDim] = {
1835 D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
1836 double* const oldPos[SpaceDim] = {D_DECL(leaf.template column<&ItoParticle::old_x>(),
1837 leaf.template column<&ItoParticle::old_y>(),
1838 leaf.template column<&ItoParticle::old_z>())};
1839 ParticleReal* const vel[SpaceDim] = {D_DECL(leaf.template column<&ItoParticle::vx>(),
1840 leaf.template column<&ItoParticle::vy>(),
1841 leaf.template column<&ItoParticle::vz>())};
1842 ParticleReal* const hop[SpaceDim] = {D_DECL(leaf.template column<&ItoParticle::scratch_x>(),
1843 leaf.template column<&ItoParticle::scratch_y>(),
1844 leaf.template column<&ItoParticle::scratch_z>())};
1845
1846 ParticleLoops::loop(leaf, [&](const std::size_t i) {
1847 // Add in the diffusion hop and advective contribution.
1848 for (int dir = 0; dir < SpaceDim; dir++) {
1849 pos[dir][i] = oldPos[dir][i] + f * vel[dir][i] + g * hop[dir][i];
1850 }
1851 });
1852 }
1853 }
1854 }
1855 }
1856}
1857
1858template <typename I, typename C, typename R, typename F>
1859void
1861{
1862 CH_TIME("ItoKMCGodunovStepper::stepEulerMaruyamaCDR");
1863 if (this->m_verbosity > 5) {
1864 pout() << this->m_name + "::stepEulerMaruyamaCDR" << endl;
1865 }
1866
1867 for (auto solverIt = (this->m_cdr)->iterator(); solverIt.ok(); ++solverIt) {
1868 RefCountedPtr<CdrSolver>& solver = solverIt();
1869
1870 const int index = solverIt.index();
1871
1872 EBAMRCellData& phi = solver->getPhi();
1873
1874 this->m_amr->conservativeAverage(phi, this->m_fluidRealm, this->m_plasmaPhase);
1875 this->m_amr->interpGhostPwl(phi, this->m_fluidRealm, this->m_plasmaPhase);
1876
1877 // Add in the advective term -- BC comes later.
1878 if (solver->isMobile()) {
1879 DataOps::setValue(solver->getEbFlux(), 0.0);
1880
1881 // Compute the FV approximation to the advective term and do the Euler advance. If the underlying
1882 // CDR solver is a CTU solver, we also add in the transverse terms.
1883 solver->computeDivF(this->m_fluidScratch1, phi, a_dt, false, true, true);
1884
1885 DataOps::incr(phi, this->m_fluidScratch1, -a_dt);
1886 }
1887
1888 // Add in the diffusion term.
1889 if (solver->isDiffusive()) {
1890 DataOps::incr(phi, this->m_cdrDivD[index], a_dt);
1891 }
1892
1893 DataOps::floor(phi, 0.0, this->m_amr->getVofIterator(this->m_fluidRealm, this->m_plasmaPhase));
1894 }
1895
1896 this->coarsenCDRSolvers();
1897}
1898
1899#ifdef CH_USE_HDF5
1900template <typename I, typename C, typename R, typename F>
1901void
1902ItoKMCGodunovStepper<I, C, R, F>::writeCheckpointHeader(HDF5HeaderData& a_header) const noexcept
1903{
1904 CH_TIME("ItoKMCGodunovStepper::writeCheckpointHeader");
1905 if (this->m_verbosity > 5) {
1906 pout() << this->m_name + "::writeCheckpointHeader" << endl;
1907 }
1908
1909 a_header.m_real["prev_dt"] = this->m_prevDt;
1910 a_header.m_real["physics_dt"] = this->m_physicsDt;
1911 a_header.m_int["checkpoint_particles"] = m_writeCheckpointParticles ? 1 : 0;
1912}
1913#endif
1914
1915#ifdef CH_USE_HDF5
1916template <typename I, typename C, typename R, typename F>
1917void
1918ItoKMCGodunovStepper<I, C, R, F>::readCheckpointHeader(HDF5HeaderData& a_header) noexcept
1919{
1920 CH_TIME("ItoKMCGodunovStepper::readCheckpointHeader");
1921 if (this->m_verbosity > 5) {
1922 pout() << this->m_name + "::readCheckpointHeader" << endl;
1923 }
1924
1925 this->m_prevDt = a_header.m_real["prev_dt"];
1926 this->m_physicsDt = a_header.m_real["physics_dt"];
1927
1928 m_readCheckpointParticles = (a_header.m_int["checkpoint_particles"] != 0) ? true : false;
1929 m_canRegridOnRestart = m_readCheckpointParticles;
1930}
1931#endif
1932
1933#ifdef CH_USE_HDF5
1934template <typename I, typename C, typename R, typename F>
1935void
1936ItoKMCGodunovStepper<I, C, R, F>::writeCheckpointData(HDF5Handle& a_handle, const int a_lvl) const noexcept
1937{
1938 CH_TIME("ItoKMCGodunovStepper::writeCheckpointData");
1939 if (this->m_verbosity > 5) {
1940 pout() << this->m_name + "::writeCheckpointData" << endl;
1941 }
1942
1944
1945 // Write the point-particles.
1946 if (m_writeCheckpointParticles) {
1947 for (int i = 0; i < (this->m_physics)->getNumItoSpecies(); i++) {
1948 const std::string identifierSigma = "ItoKMCGodunovStepper::conductivityParticles_" + std::to_string(i);
1949 const std::string identifierRho = "ItoKMCGodunovStepper::spaceChargeParticles_" + std::to_string(i);
1950
1951 const ParticleContainer<NoPayload>& conductivityParticles = *m_conductivityParticles[i];
1952 const ParticleContainer<NoPayload>& rhoDaggerParticles = *m_rhoDaggerParticles[i];
1953
1954 DischargeIO::writeCheckParticlesToHDF(a_handle, conductivityParticles[a_lvl], identifierSigma);
1955 DischargeIO::writeCheckParticlesToHDF(a_handle, rhoDaggerParticles[a_lvl], identifierRho);
1956 }
1957 }
1958
1959 // Write data required for the semi-implicit regrid.
1960 if (this->m_physics->getNumCdrSpecies() > 0) {
1961 write(a_handle, *m_semiImplicitRhoCDR[a_lvl], "ItoKMCGodunovStepper::semiImplicitRhoCDR");
1962 write(a_handle, *m_semiImplicitConductivityCDR[a_lvl], "ItoKMCGodunovStepper::semiImplicitConductivityCDR");
1963 }
1964}
1965#endif
1966
1967#ifdef CH_USE_HDF5
1968template <typename I, typename C, typename R, typename F>
1969void
1970ItoKMCGodunovStepper<I, C, R, F>::readCheckpointData(HDF5Handle& a_handle, const int a_lvl) noexcept
1971{
1972 CH_TIME("ItoKMCGodunovStepper::readCheckpointData");
1973 if (this->m_verbosity > 5) {
1974 pout() << this->m_name + "::readCheckpointData" << endl;
1975 }
1976
1978
1979 // Write the point-particles.
1980 if (m_readCheckpointParticles) {
1981 for (int i = 0; i < (this->m_physics)->getNumItoSpecies(); i++) {
1982 const std::string identifierSigma = "ItoKMCGodunovStepper::conductivityParticles_" + std::to_string(i);
1983 const std::string identifierRho = "ItoKMCGodunovStepper::spaceChargeParticles_" + std::to_string(i);
1984
1985 ParticleContainer<NoPayload>& conductivityParticles = *m_conductivityParticles[i];
1986 ParticleContainer<NoPayload>& rhoDaggerParticles = *m_rhoDaggerParticles[i];
1987
1988 DischargeIO::readCheckParticlesFromHDF(a_handle, conductivityParticles[a_lvl], identifierSigma);
1989 DischargeIO::readCheckParticlesFromHDF(a_handle, rhoDaggerParticles[a_lvl], identifierRho);
1990 }
1991 }
1992
1993 // Read in data that is required for the semi-implicit regrid.
1994 if (this->m_physics->getNumCdrSpecies() > 0) {
1995 const Interval interv(0, 0);
1996
1997 read<EBCellFAB>(a_handle,
1998 *m_semiImplicitRhoCDR[a_lvl],
1999 "ItoKMCGodunovStepper::semiImplicitRhoCDR",
2000 this->m_amr->getGrids(this->m_fluidRealm)[a_lvl],
2001 interv,
2002 false);
2003
2004 read<EBCellFAB>(a_handle,
2005 *m_semiImplicitConductivityCDR[a_lvl],
2006 "ItoKMCGodunovStepper::semiImplicitConductivityCDR",
2007 this->m_amr->getGrids(this->m_fluidRealm)[a_lvl],
2008 interv,
2009 false);
2010 }
2011}
2012#endif
2013
2014template <typename I, typename C, typename R, typename F>
2015void
2017{
2018 CH_TIME("ItoKMCGodunovStepper::postPlot");
2019 if (this->m_verbosity > 5) {
2020 pout() << this->m_name + "::postPlot" << endl;
2021 }
2022
2023 this->m_physicsPlotVariables.clear();
2024
2025 this->plotParticles();
2026}
2027
2028template <typename I, typename C, typename R, typename F>
2029void
2031{
2032 CH_TIME("ItoKMCGodunovStepper::plotParticles");
2033 if (this->m_verbosity > 2) {
2034 pout() << this->m_name + "::plotParticles" << endl;
2035 }
2036
2037 bool plotParticles = false;
2038
2039 ParmParse pp(this->m_name.c_str());
2040
2041 pp.query("plot_particles", plotParticles);
2042
2043 if (plotParticles) {
2044
2045 for (auto solverIt = (this->m_ito)->iterator(); solverIt.ok(); ++solverIt) {
2046 const RefCountedPtr<ItoSolver>& solver = solverIt();
2047 const ParticleContainer<ItoParticle>& particles = solver->getParticles(ItoSolver::WhichContainer::Bulk);
2048
2049 // Create the output folder
2050 std::string cmd = "mkdir -p particles/" + solver->getName();
2051 int success = 0;
2052 if (procID() == 0) {
2053 success = system(cmd.c_str());
2054 }
2055
2056 if (success != 0) {
2057 MayDay::Error("ItoKMCGodunovStepper::plotParticles - could not create 'particles' directory");
2058 }
2059
2060 // Set plot file name
2061 const std::string prefix = "./particles/" + solver->getName() + "/" + solver->getName();
2062 char fileChar[1000];
2063 sprintf(fileChar, "%s.step%07d.%dd.h5part", prefix.c_str(), this->m_timeStep, SpaceDim);
2064
2065 // Plot the particles directly from the live SoA container. The output datasets (id, position, weight
2066 // and the selected ItoParticle payload columns) are derived from ParticleTraits<ItoParticle>::h5PartColumns.
2067 DischargeIO::writeH5Part(std::string(fileChar), particles, this->m_amr->getProbLo(), this->m_time);
2068 }
2069 }
2070}
2071
2072#include <CD_NamespaceFooter.H>
2073
2074#endif
Average
Various averaging methods.
Definition CD_Average.H:25
Agglomeration of useful data operations.
Silly, but useful functions that override standard Chombo HDF5 IO.
EBRepresentation
Enum for putting some logic into how we think about EBs. This is just a simply supporting class for v...
Definition CD_EBRepresentation.H:23
Declaration of a class which uses a semi-implicit Godunov method for Ito plasma equations.
SpeciesSubset
Enum for selecting a subset of plasma species by mobility/diffusion/charge properties.
Definition CD_ItoKMCStepper.H:43
Agglomeration of basic MPI reductions.
Declaration of a namespace for SIMD-decorated loops over SoA particles.
CD_PARTICLE_REAL ParticleReal
Floating-point type a user may use for payload columns.
Definition CD_ParticleSoA.H:156
SoA payload for Monte Carlo radiative-transfer photons.
Implementation of CD_Timer.H.
Declaration of various useful units.
static void scale(MFAMRCellData &a_lhs, const Real &a_scale) noexcept
Scale data by factor.
Definition CD_DataOps.cpp:2503
static void floor(EBAMRCellData &a_lhs, const Real a_value, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Floor values in data holder. This sets all values below a_value to a_value.
Definition CD_DataOps.cpp:1465
static void filterSmooth(EBAMRCellData &a_data, const Real a_alpha, const int a_stride, const bool a_zeroEB) noexcept
Apply a convolved filter phi = alpha * phi_i + 0.5*(1-alpha) * [phi_(i+s) + phi_(i-s)] in each direct...
Definition CD_DataOps.cpp:679
static void multiply(EBAMRCellData &a_lhs, const EBAMRCellData &a_rhs)
Multiply data holder by another data holder.
Definition CD_DataOps.cpp:2246
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 copy(MFAMRCellData &a_dst, const MFAMRCellData &a_src)
Copy data from one data holder to another.
Definition CD_DataOps.cpp:1201
static void averageCellToFace(EBAMRFluxData &a_faceData, const EBAMRCellData &a_cellData, const Vector< ProblemDomain > &a_domains, Vector< RefCountedPtr< LayoutData< std::array< FaceIterator, SpaceDim > > > > &a_faceIter)
Average all components of the cell-centered data to faces (arithmetic, no tangential ghost faces).
Definition CD_DataOps.cpp:148
AMR-hierarchy container of computational particles, stored per patch in Struct-of-Arrays form.
Definition CD_ParticleContainer.H:123
void clearParticles()
Drop all valid particles on every level (keeps each leaf's arena capacity).
Definition CD_ParticleContainer.H:442
RealVect getProbLo() const
Lower-left corner of the physical domain.
Definition CD_ParticleContainer.H:280
AMRParticlesSoA< P, Traits > & getParticles()
The valid particles on all levels.
Definition CD_ParticleContainer.H:317
static void setData(ParticleContainer< P, Traits > &a_particles, const std::function< void(ParticleSoA< P, Traits > &, std::size_t)> &a_functor) noexcept
Set value function for SoA containers. Lets the user set particle parameters via a (leaf,...
Definition CD_ParticleOpsImplem.H:334
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
void append(const RealVect &a_position, const double a_weight)
Append one particle with a default-constructed payload.
Definition CD_ParticleSoA.H:955
RealVect position(const std::size_t a_index) const noexcept
Position of particle i as a RealVect (by value, assembled from the scalar columns).
Definition CD_ParticleSoA.H:1188
double & weight(const std::size_t a_index) noexcept
Weight of particle i.
Definition CD_ParticleSoA.H:1222
std::size_t size() const noexcept
Number of particles currently stored.
Definition CD_ParticleSoA.H:882
double * positionColumn(const int a_dir) noexcept
Raw position component column dir (double*, for SIMD kernels).
Definition CD_ParticleSoA.H:1137
P gather(const std::size_t a_index) const
Gather particle i's payload back into the AoS payload view.
Definition CD_ParticleSoA.H:1021
void catenate(ParticleSoA &a_other)
Move every particle of another container into this one, leaving a_other empty (catenate).
Definition CD_ParticleSoA.H:1002
void remove(const std::size_t a_index) noexcept
Remove particle i using swap-and-pop (O(1), does NOT preserve order).
Definition CD_ParticleSoA.H:1033
Implementation of ItoKMCStepper that uses a semi-implicit split-step formalism for advancing the Ito-...
Definition CD_ItoKMCGodunovStepper.H:31
virtual void setupSemiImplicitPoisson(const Real a_dt) noexcept
Set up the semi-implicit Poisson solver.
Definition CD_ItoKMCGodunovStepperImplem.H:1447
virtual void regrid(const int a_lmin, const int a_oldFinestLevel, const int a_newFinestLevel) noexcept override
Regrid methods – puts all data on the new mesh.
Definition CD_ItoKMCGodunovStepperImplem.H:684
virtual void computeDiffusionTermCDR(EBAMRCellData &m_semiImplicitRhoCDR, const Real a_dt) noexcept
Compute the diffusion term for the CDR equations as well as the resulting CDR-contributions to the sp...
Definition CD_ItoKMCGodunovStepperImplem.H:1763
virtual void allocate() noexcept override
Allocate storage required for advancing the equations.
Definition CD_ItoKMCGodunovStepperImplem.H:98
bool m_readCheckpointParticles
If true, then the HDF5 checkpoint file contained particles that we can read.
Definition CD_ItoKMCGodunovStepper.H:170
virtual Real advance(const Real a_dt) override
Advance the Ito-Poisson-KMC system over a_dt.
Definition CD_ItoKMCGodunovStepperImplem.H:359
virtual void allocateInternals() noexcept override
Allocate "internal" storage.
Definition CD_ItoKMCGodunovStepperImplem.H:131
Real m_maxFieldAbort
Limit for maximum field abort.
Definition CD_ItoKMCGodunovStepper.H:231
virtual void stepEulerMaruyamaCDR(const Real a_dt) noexcept
Step the CDR equations according to the regular Euler-Maruyama scheme.
Definition CD_ItoKMCGodunovStepperImplem.H:1860
virtual void computeConductivities(const Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const bool a_useStoredCdrConductivity) noexcept
Compute all conductivities (cell, face, and EB) from the input point particles.
Definition CD_ItoKMCGodunovStepperImplem.H:1214
virtual void parseAlgorithm() noexcept
Parse advancement algorithm.
Definition CD_ItoKMCGodunovStepperImplem.H:213
virtual void clearPointParticles(const Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const SpeciesSubset a_subset) noexcept
Clear the input particle data holders.
Definition CD_ItoKMCGodunovStepperImplem.H:1078
virtual void postPlot() noexcept override
Perform post-plot operations.
Definition CD_ItoKMCGodunovStepperImplem.H:2016
virtual Real computeDt() override
Compute a time step used for the advance method.
Definition CD_ItoKMCGodunovStepperImplem.H:339
virtual void diffuseParticlesEulerMaruyama(Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_rhoDaggerParticles, const Real a_dt) noexcept
Perform the diffusive Ito advance in the Euler-Maruyama step.
Definition CD_ItoKMCGodunovStepperImplem.H:1701
virtual void parseSecondaryEmissionSpecification() noexcept
Parse when secondary particles are emitted.
Definition CD_ItoKMCGodunovStepperImplem.H:288
virtual void parseFiltering() noexcept
Parse filter settings.
Definition CD_ItoKMCGodunovStepperImplem.H:238
virtual void parseRuntimeOptions() noexcept override
Parse run-time options.
Definition CD_ItoKMCGodunovStepperImplem.H:195
virtual void depositPointParticles(const Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const SpeciesSubset a_subset) noexcept
Deposit the input point particles on the mesh.
Definition CD_ItoKMCGodunovStepperImplem.H:976
virtual bool solvePoisson() noexcept override
Solve the electrostatic problem.
Definition CD_ItoKMCGodunovStepperImplem.H:1577
bool m_canRegridOnRestart
If true, then the class supports regrid-on-restart.
Definition CD_ItoKMCGodunovStepper.H:176
virtual void computeFaceConductivity() noexcept
Compute the cell-centered conductivity.
Definition CD_ItoKMCGodunovStepperImplem.H:1299
virtual void computeCellConductivity(EBAMRCellData &a_conductivityCell, const Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const bool a_useStoredCdrConductivity) noexcept
Compute the cell-centered conductivity.
Definition CD_ItoKMCGodunovStepperImplem.H:1229
virtual void removeCoveredPointParticles(Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const EBRepresentation a_representation, const Real a_tolerance) const noexcept
Remove covered particles.
Definition CD_ItoKMCGodunovStepperImplem.H:1484
virtual void remapPointParticles(Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_particles, const SpeciesSubset a_subset) noexcept
Remap the input point particles.
Definition CD_ItoKMCGodunovStepperImplem.H:871
virtual ~ItoKMCGodunovStepper()
Destructor. Does nothing.
Definition CD_ItoKMCGodunovStepperImplem.H:72
bool m_extendConductivityEB
For achieving a slightly smoother gradient in the conductivity near the EB.
Definition CD_ItoKMCGodunovStepper.H:181
virtual void setOldPositions() noexcept
Set the starting positions for the ItoSolver particles.
Definition CD_ItoKMCGodunovStepperImplem.H:832
bool m_writeCheckpointParticles
If true, then the particles are checkpointed so we can regrid on checkpoint-restart.
Definition CD_ItoKMCGodunovStepper.H:165
virtual void computeSemiImplicitRho() noexcept
Set up the space charge density for the regrid operation.
Definition CD_ItoKMCGodunovStepperImplem.H:1334
virtual void advanceEulerMaruyama(const Real a_dt) noexcept
Advance the particles using the Euler-Maruyama scheme.
Definition CD_ItoKMCGodunovStepperImplem.H:1616
virtual void preRegrid(const int a_lmin, const int a_oldFinestLevel) noexcept override
Perform pre-regrid operations.
Definition CD_ItoKMCGodunovStepperImplem.H:645
virtual void registerOperators() noexcept override
Register operators used for the simulation.
Definition CD_ItoKMCGodunovStepperImplem.H:82
virtual void plotParticles() const noexcept
Utility function for plotting the ItoSolver particles. These are written in a particles folder.
Definition CD_ItoKMCGodunovStepperImplem.H:2030
ItoKMCGodunovStepper()=delete
Disallowed default constructor. Use the full constructor.
virtual void parseReactiveFieldCentering() noexcept
Parse the time-centering of the electric field used for the reactive substep.
Definition CD_ItoKMCGodunovStepperImplem.H:319
virtual void parseCheckpointParticles() noexcept
Parse checkpoint-restart functionality.
Definition CD_ItoKMCGodunovStepperImplem.H:274
virtual void barrier() const noexcept
Set an MPI barrier if using debug mode.
Definition CD_ItoKMCGodunovStepperImplem.H:163
virtual void parseOptions() noexcept override
Parse options.
Definition CD_ItoKMCGodunovStepperImplem.H:177
virtual void computeCdrConductivity() noexcept
Compute the CDR contribution to the semi-implicit conductivity, i.e. sum(|Z| * phi * mu).
Definition CD_ItoKMCGodunovStepperImplem.H:1184
virtual void stepEulerMaruyamaParticles(const Real a_dt) noexcept
Step the particles according to the regular Euler-Maruyama scheme.
Definition CD_ItoKMCGodunovStepperImplem.H:1803
virtual void copyConductivityParticles(Vector< RefCountedPtr< ParticleContainer< NoPayload > > > &a_conductivityParticles) noexcept
Copy particles from the ItoSolver into PointParticles whose weight are ItoParticle::m_weight * ItoPar...
Definition CD_ItoKMCGodunovStepperImplem.H:1524
Abstract TimeStepper for the Ito-KMC-Poisson system of equations.
Definition CD_ItoKMCStepper.H:66
virtual void parseRuntimeOptions() noexcept override
Parse runtime configurable options.
Definition CD_ItoKMCStepperImplem.H:160
std::string m_name
Time stepper name.
Definition CD_ItoKMCStepper.H:380
virtual void registerOperators() noexcept override
Register operators used for the simulation.
Definition CD_ItoKMCStepperImplem.H:1597
virtual void parseOptions() noexcept
Parse options.
Definition CD_ItoKMCStepperImplem.H:140
virtual void preRegrid(const int a_lmin, const int a_oldFinestLevel) noexcept override
Perform pre-regrid operations - storing relevant data from the old grids.
Definition CD_ItoKMCStepperImplem.H:1649
Real m_prevDt
Previous time step.
Definition CD_ItoKMCStepper.H:509
virtual Real computeDt() override
Compute a time step used for the advance method.
Definition CD_ItoKMCStepperImplem.H:1468
virtual void allocateInternals() noexcept
Allocate "internal" storage.
Definition CD_ItoKMCStepperImplem.H:579
virtual void allocate() noexcept override
Allocate storage for solvers.
Definition CD_ItoKMCStepperImplem.H:561
Class which is used for run-time monitoring of events.
Definition CD_Timer.H:32
void writeH5Part(std::string a_filename, const ParticleContainer< P, Traits > &a_particles, RealVect a_shift, Real a_time) noexcept
Write an SoA particle container to an H5Part file (quick visualization).
Definition CD_DischargeIOImplem.H:201
void barrier() noexcept
MPI barrier.
Definition CD_ParallelOpsImplem.H:26
ALWAYS_INLINE void loop(const ParticleSoA< P, Traits > &a_soa, Functor &&a_kernel)
Launch a kernel over every particle in a ParticleSoA, decorating the loop with CD_PRAGMA_SIMD.
Definition CD_ParticleLoops.H:87
constexpr Real eps0
Permittivity of free space.
Definition CD_Units.H:30
constexpr Real Qe
Elementary charge.
Definition CD_Units.H:35
@ solid
Solid (dielectric) phase.
Definition CD_MultiFluidIndexSpace.H:40
@ gas
Gas phase.
Definition CD_MultiFluidIndexSpace.H:39
SoA payload for ItoSolver particles, i.e. drifting Brownian walkers.
Definition CD_ItoParticle.H:31