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