chombo-discharge
Loading...
Searching...
No Matches
CD_ItoKMCPhysicsImplem.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_ITOKMCPHYSICSIMPLEM_H
14#define CD_ITOKMCPHYSICSIMPLEM_H
15
16// Std includes
17#include <algorithm>
18
19// Chombo includes
20#include <ParmParse.H>
21
22// Our includes
23#include <CD_ItoKMCPhysics.H>
25#include <CD_Random.H>
26#include <CD_Units.H>
27#include <CD_DataOps.H>
28#include <CD_NamespaceHeader.H>
29
30using namespace Physics::ItoKMC;
31
33{
34 CH_TIME("ItoKMCPhysics::ItoKMCPhysics");
35
36 m_className = "ItoKMCPhysics";
37
38 m_kmcReactions.clear();
39 m_photoReactions.clear();
40
41 // Some default settings (mostly in case user forgets to call the parsing algorithms).
42 m_isDefined = false;
43 m_debug = true;
44 m_hasKMCSolver = false;
47 m_maxNewPhotons = 32;
48 m_Ncrit = 5;
49 m_eps = 2.0;
50 m_NSSA = 5;
51 m_maxIter = 10;
52 m_SSAlim = 5.0;
53 m_exitTol = 1.E-6;
56}
57
59{
60 CH_TIME("ItoKMCPhysics::~ItoKMCPhysics");
61}
62
63inline void
65{
66 CH_TIME("ItoKMCPhysics::define");
67
68 this->defineSpeciesMap();
69 this->definePhotoPathways();
70
71 // Safety hook -- make sure no one defines reactions using an out-of-range species index.
72#ifndef NDEBUG
73 for (const auto& R : m_kmcReactions) {
74 const auto& lhsReactants = R.getReactants();
75 const auto& rhsReactants = R.getReactiveProducts();
76 const auto& rhsPhotons = R.getNonReactiveProducts();
77
78 for (const auto& r : lhsReactants) {
79 CH_assert(r < m_itoSpecies.size() + m_cdrSpecies.size());
80 }
81 for (const auto& r : rhsReactants) {
82 CH_assert(r < m_itoSpecies.size() + m_cdrSpecies.size());
83 }
84 for (const auto& r : rhsPhotons) {
85 CH_assert(r < m_rtSpecies.size());
86 }
87 }
88#endif
89
90 m_isDefined = true;
91}
92
93inline void
95{
96 CH_TIME("ItoKMCPhysics::defineSpeciesMap");
97
98 const int numItoSpecies = this->getNumItoSpecies();
99 const int numCdrSpecies = this->getNumCdrSpecies();
100
101 int species = 0;
102 for (int i = 0; i < numItoSpecies; i++, species++) {
103 m_speciesMap.emplace(species, std::make_pair(SpeciesType::Ito, i));
104 }
105
106 for (int i = 0; i < numCdrSpecies; i++, species++) {
107 m_speciesMap.emplace(species, std::make_pair(SpeciesType::CDR, i));
108 }
109}
110
111inline bool
112ItoKMCPhysics::needGradient(const int a_plasmaIndex) const noexcept
113{
114 CH_assert(a_plasmaIndex >= 0);
115 CH_assert(a_plasmaIndex < m_itoSpecies.size() + m_cdrSpecies.size());
116
117 return this->needGradients();
118}
119
120inline void
122{
123 CH_TIME("ItoKMCPhysics::defineKMC");
124
125 CH_assert(!m_hasKMCSolver);
126
127 // Deep copy of reaction rates
129 for (const auto& r : m_kmcReactions) {
130 m_kmcReactionsThreadLocal.emplace_back(std::make_shared<const KMCReaction>(r));
131 }
132
135 m_kmcState.define(m_itoSpecies.size() + m_cdrSpecies.size(), m_rtSpecies.size());
137
139
140 // Compact the reactions that actually take part in the physics time step calculation. The dt probe at the
141 // end of advanceKMC scales every propensity by m_reactiveDtFactors, which the user sets to zero for every
142 // reaction excluded from that calculation -- so those propensities were evaluated and then multiplied away,
143 // and KMCSolver::computeDt still reduced over the whole reaction set. The probe's cost therefore grew with
144 // the size of the chemistry while only the included reactions could move the answer, and a chemistry that
145 // includes two reactions out of forty paid for all forty, per grid cell, twice per probe.
146 //
147 // The compaction is exact, not an approximation. An excluded reaction contributes muIJ * 0 to every
148 // reactant sum in computeDt, and a reactant whose accumulated mu is zero is skipped there by its own
149 // 'mu > numeric_limits<Real>::min()' guard -- so dropping the excluded reactions and the reactants only
150 // they reach leaves the returned time step bit-identical.
151 //
152 // A model that never sized m_reactiveDtFactors is read as "every reaction counts", matching the parser
153 // default for a reaction with no 'include_dt_calc' entry.
154 m_kmcReactionsDt.resize(0);
155 m_reactiveDtFactorsDt.resize(0);
156
157 for (size_t i = 0; i < m_kmcReactionsThreadLocal.size(); i++) {
158 const Real factor = (i < m_reactiveDtFactors.size()) ? m_reactiveDtFactors[i] : 1.0;
159
160 if (factor != 0.0) {
162 m_reactiveDtFactorsDt.emplace_back(factor);
163 }
164 }
165
167
168 m_hasKMCSolver = true;
169}
170
171inline void
173{
174 CH_TIME("ItoKMCPhysics::killKMC");
175
176 CH_assert(m_hasKMCSolver);
177
180 m_kmcState.define(0, 0);
182
183 m_kmcPropensityScratch.resize(0);
184
185 m_kmcReactionsDt.resize(0);
186 m_reactiveDtFactorsDt.resize(0);
187 m_kmcPropensityScratchDt.resize(0);
188
189 m_hasKMCSolver = false;
190}
191
192inline void
194{
195 CH_TIME("ItoKMCPhysics::definePhotoPathways");
196
197 // Build a temporary list of pathways. I.e. restructure the list of reactions
198 //
199 // Y1 -> A
200 // Y1 -> B
201 // Y2 -> C
202 // Y2 -> D
203 //
204 // into separate lists for Y1, Y2, ....
205 //
206 std::map<int, std::vector<std::pair<int, Real>>> pathways;
207
208 for (int i = 0; i < m_photoReactions.size(); i++) {
210
211 const size_t& src = r.getSourcePhoton();
212 const Real efficiency = r.getEfficiency();
213
214 pathways[src].emplace_back(std::make_pair(i, efficiency));
215 }
216
217 // Go through the temporary pathways list and compute the relative efficiencies of one of the
218 // photons triggering a reaction. The relative efficiencies are given by
219 //
220 // p(i) = R(i)/sum_j R(j).
221 //
222 for (const auto& p : pathways) {
223 const int photoSpecies = p.first;
224 const std::vector<std::pair<int, Real>> reactionsAndEfficiencies = p.second;
225
226 std::map<int, int> localToGlobalMap;
227 std::list<double> efficiencies;
228 double sumEfficiencies = 0.0;
229
230 for (int i = 0; i < reactionsAndEfficiencies.size(); i++) {
231 sumEfficiencies += (double)reactionsAndEfficiencies[i].second;
232 }
233
234 for (int i = 0; i < reactionsAndEfficiencies.size(); i++) {
235 localToGlobalMap.emplace(i, reactionsAndEfficiencies[i].first);
236 efficiencies.emplace_back((double)reactionsAndEfficiencies[i].second / sumEfficiencies);
237 }
238
239 std::discrete_distribution<int> distribution(efficiencies.begin(), efficiencies.end());
240
241 m_photoPathways.insert(std::make_pair((int)photoSpecies, std::make_pair(distribution, localToGlobalMap)));
242 }
243}
244
245inline const std::map<int, std::pair<SpeciesType, int>>&
247{
248 CH_TIME("ItoKMCPhysics::getSpeciesMap");
249
250 return m_speciesMap;
251}
252
253inline void
255{
256 CH_TIME("ItoKMCPhysics::parseRuntimeOptions");
257
258 this->parsePPC();
259 this->parseDebug();
260 this->parseAlgorithm();
261}
262
263inline void
265{
266 CH_TIME("ItoKMCPhysics::parsePPC");
267
268 ParmParse pp(m_className.c_str());
269
270 pp.get("max_new_particles", m_maxNewParticles);
271 pp.get("max_new_photons", m_maxNewPhotons);
272
273 if (m_maxNewParticles < 1) {
274 MayDay::Abort(("ItoKMCPhysics::parsePPC - '" + m_className + ".max_new_particles' must be >= 1").c_str());
275 }
276}
277
278inline void
280{
281 CH_TIME("ItoKMCPhysics::parseDebug");
282
283 ParmParse pp(m_className.c_str());
284
285 pp.get("debug", m_debug);
286}
287
288inline void
290{
291 CH_TIME("ItoKMCPhysics::parseAlgorithm");
292
293 ParmParse pp(m_className.c_str());
294
295 std::string str;
296
297 pp.get("algorithm", str);
298 pp.get("crit_num", m_Ncrit);
299 pp.get("SSA_num", m_NSSA);
300 pp.get("prop_eps", m_eps);
301 pp.get("SSA_lim", m_SSAlim);
302 pp.get("max_iter", m_maxIter);
303 pp.get("exit_tolerance", m_exitTol);
304
305 if (str == "ssa") {
307 }
308 else if (str == "explicit_euler") {
310 }
311 else if (str == "midpoint") {
313 }
314 else if (str == "prc") {
316 }
317 else if (str == "implicit_euler") {
319 }
320 else if (str == "hybrid_explicit_euler") {
322 }
323 else if (str == "hybrid_midpoint") {
325 }
326 else if (str == "hybrid_prc") {
328 }
329 else if (str == "hybrid_implicit_euler") {
331 }
332 else {
333 MayDay::Error("ItoKMCPhysics::parseAlgorithm - unknown algorithm requested");
334 }
335}
336
337inline const Vector<RefCountedPtr<ItoSpecies>>&
339{
340 return m_itoSpecies;
341}
342
343inline const Vector<RefCountedPtr<CdrSpecies>>&
345{
346 return m_cdrSpecies;
347}
348
349inline const Vector<RefCountedPtr<RtSpecies>>&
351{
352 return m_rtSpecies;
353}
354
355inline const Vector<DiffusionFunction>&
360
361inline int
363{
364 return m_itoSpecies.size();
365}
366
367inline int
369{
370 return m_cdrSpecies.size();
371}
372
373inline int
375{
376 return m_itoSpecies.size() + m_cdrSpecies.size();
377}
378
379inline int
381{
382 return m_rtSpecies.size();
383}
384
385inline Real
386ItoKMCPhysics::initialSigma(const Real a_time, const RealVect& a_pos) const
387{
388 return 0.0;
389}
390
391inline void
392ItoKMCPhysics::advanceKMC(Vector<FPR>& a_numParticles,
393 Vector<FPR>& a_numNewPhotons,
394 Real& a_physicsDt,
395 const Vector<Real>& a_phi,
396 const Vector<RealVect>& a_gradPhi,
397 const Real a_dt,
398 const RealVect a_E,
399 const RealVect a_pos,
400 const Real a_dx,
401 const Real a_kappa) const
402{
403 // Note: This is called PER GRID CELL, i.e. within OpenMP parallel regions. For this reason the KMC solver
404 // must be defined through defineKMC() (which must be later killed).
405 CH_assert(m_isDefined);
406 CH_assert(m_hasKMCSolver);
407
408 std::vector<FPR>& kmcParticles = m_kmcState.getReactiveState();
409 std::vector<FPR>& kmcPhotons = m_kmcState.getNonReactiveState();
410
411 for (size_t i = 0; i < a_numParticles.size(); i++) {
412 kmcParticles[i] = a_numParticles[i];
413 }
414
415 for (auto& p : kmcPhotons) {
416 p = 0LL;
417 }
418
419 // Lambda function used for computing charge before and after reactions. Used only in debug mode
420 // for ensuring that nothing goes wrong with charge conservation in the chemistry integration.
421 auto computeCharge = [&]() -> long long {
422 long long Q = 0.0;
423 for (int i = 0; i < kmcParticles.size(); i++) {
424 const SpeciesType& speciesType = m_speciesMap.at(i).first;
425 const int& speciesIndex = m_speciesMap.at(i).second;
426
427 int Z = 0;
428
429 switch (speciesType) {
430 case SpeciesType::Ito: {
431 Z = m_itoSpecies[speciesIndex]->getChargeNumber();
432
433 break;
434 }
435 case SpeciesType::CDR: {
436 Z = m_cdrSpecies[speciesIndex]->getChargeNumber();
437
438 break;
439 }
440 default: {
441 MayDay::Abort("ItoKMCPhysics::advanceKMC -- logic bust in computeCharge()");
442
443 break;
444 }
445 }
446
447 Q += llround(kmcParticles[i]) * Z;
448 }
449
450 return Q;
451 };
452
453 // In debug mode, compute the total charge.
454 const long long chargeBefore = m_debug ? computeCharge() : 0LL;
455
456 // Update the reaction rates to be used by the KMC solver.
457 this->updateReactionRates(m_kmcReactionsThreadLocal, a_E, a_pos, a_phi, a_gradPhi, a_dt, a_dx, a_kappa);
458
459 // Run the KMC solver.
460 switch (m_algorithm) {
461 case Algorithm::SSA: {
463
464 break;
465 }
468
469 break;
470 }
471 case Algorithm::Midpoint: {
473
474 break;
475 }
476 case Algorithm::PRC: {
478
479 break;
480 }
483
484 break;
485 }
488
489 break;
490 }
493
494 break;
495 }
498
499 break;
500 }
503
504 break;
505 }
506 default: {
507 MayDay::Error("ItoKMCPhysics::advanceKMC - logic bust");
508 }
509 }
510
511 // Put KMC back into ItoKMC
512 for (size_t i = 0; i < a_numParticles.size(); i++) {
513 a_numParticles[i] = (FPR)kmcParticles[i];
514 }
515 for (size_t i = 0; i < a_numNewPhotons.size(); i++) {
516 a_numNewPhotons[i] = (FPR)kmcPhotons[i];
517 }
518
519 const long long chargeAfter = m_debug ? computeCharge() : 0LL;
520
521 if (chargeAfter != chargeBefore) {
522 MayDay::Warning("ItoKMCPhysics::advanceKMC -- charge not conserved!");
523 }
524
525 // This loop is for isolating reactions that the user will explicitly ask to fire before computing the physics-based
526 // time step. It exists because if there are no electrons but lots of ions, one may get a time step that is too large
527 // because X/|sum mu| is zero for the electrons. Similarly, one may get a time step that is too small away from
528 // ionization regions because X/|sum mu| may be tiny if there is, say, 1 electron but lots of detachment.
529 //
530 // Everything below runs on the compacted reaction set built by defineKMC(), not on the full one: only the
531 // reactions the user included can move the answer, and the excluded ones cost a propensity evaluation and a
532 // reduction apiece, per probe, per grid cell. With nothing included there is nothing to limit, so the whole
533 // block drops out.
534 if (m_kmcReactionsDt.empty()) {
535 return;
536 }
537
538 // Fills the reusable propensity buffer rather than returning one, so that the probes below do not
539 // allocate once per reaction per grid cell.
540 auto fillPropensitiesDt = [&](const KMCState& a_state) -> void {
541 for (size_t i = 0; i < m_kmcReactionsDt.size(); i++) {
542 m_kmcPropensityScratchDt[i] = m_kmcReactionsDt[i]->propensity(a_state) * m_reactiveDtFactorsDt[i];
543 }
544 };
545
546 // Do a time step limitation on the complete state, using the user-specified reactions.
547 fillPropensitiesDt(m_kmcState);
548
549 a_physicsDt = std::min(a_physicsDt,
551
552 // Go through reactions that are potentially detaching species and do the calculation again. This probe walks
553 // the FULL reaction set even though the limit is evaluated on the compacted one: an excluded reaction can
554 // still deplete a species that an included reaction depends on, and that depletion is exactly what the probe
555 // is looking for.
556 for (const auto& reaction : m_kmcReactionsThreadLocal) {
557 const auto N = reaction->computeCriticalNumberOfReactions(m_kmcState);
558
559 // Trigger on both the reactions and the reactions with completely consumed reactants. The state
560 // is only copied inside the branch because that is the only place it is read -- copying it above
561 // the test meant paying for a copy per reaction per grid cell, including for the reactions that
562 // never enter here.
563 if (N < std::numeric_limits<FPR>::max()) {
565
566 reaction->advanceState(m_kmcStateScratch, N);
567
568 fillPropensitiesDt(m_kmcStateScratch);
569
570 a_physicsDt = std::min(a_physicsDt,
572 }
573 }
574}
575
576inline void
578 const Vector<FPR>& a_newNumParticles,
579 const Vector<FPR>& a_oldNumParticles,
580 const RealVect a_electricField,
581 const RealVect a_cellPos,
582 const RealVect a_centroidPos,
583 const RealVect a_lo,
584 const RealVect a_hi,
585 const RealVect a_bndryCentroid,
586 const RealVect a_bndryNormal,
587 const Real a_dx,
588 const Real a_kappa) const noexcept
589{
590 CH_assert(m_isDefined);
591 CH_assert(a_particles.size() == a_newNumParticles.size());
592 CH_assert(a_oldNumParticles.size() == a_newNumParticles.size());
593
594 if (m_debug) {
595 for (int i = 0; i < a_particles.size(); i++) {
596 const FPR& numNew = a_newNumParticles[i];
597 const FPR& numOld = a_oldNumParticles[i];
598
599 if (numNew < (FPR)0) {
600 MayDay::Warning("ItoKMCPhysics::reconcileParticles - new number of particles is < 0 (overflow issue?)");
601 }
602 else if (static_cast<long long>(numNew) < 0LL) {
603 MayDay::Warning("ItoKMCPhysics::reconcileParticles - integer overflow!");
604 }
605
606 if (numOld < 0) {
607 MayDay::Warning("ItoKMCPhysics::reconcileParticles - old number of particles is < 0");
608 }
609 else if (static_cast<long long>(numOld) < 0LL) {
610 MayDay::Warning("ItoKMCPhysics::reconcileParticles - integer overflow for old particles!");
611 }
612 }
613 }
614
615 // Compute the upstream position of the particles (which is usually the electrons).
616 bool hasDownstream = false;
617 RealVect upstreamPosition = RealVect::Zero;
618 RealVect upstreamLo = -0.5 * RealVect::Unit;
619 RealVect upstreamHi = +0.5 * RealVect::Unit;
620 RealVect v = RealVect::Zero;
621 int Z = 0;
622
623 if (m_particlePlacement == ParticlePlacement::Downstream) {
624 CH_assert(m_downstreamSpecies >= 0);
625
626 Z = m_itoSpecies[m_downstreamSpecies]->getChargeNumber();
627
628 if (Z != 0) {
629 v = Z * a_electricField;
630 v = v / v.vectorLength();
631 }
632
633 hasDownstream = this->computeUpstreamPosition(upstreamPosition,
634 upstreamLo,
635 upstreamHi,
636 Z,
637 *a_particles[m_downstreamSpecies],
638 a_electricField,
639 a_cellPos,
640 a_dx);
641 }
642
643 for (int i = 0; i < a_particles.size(); i++) {
644 const long long diff = static_cast<long long>(a_newNumParticles[i] - a_oldNumParticles[i]);
645
646 if (diff > 0LL) {
647 const long long numParticles = static_cast<long long>(a_particles[i]->size());
648
649 // Choose weights for the new particles and go with one of the placement algorithms.
650 ParticleManagement::partitionParticleWeights(m_weightScratch, diff, static_cast<long long>(m_maxNewParticles));
651
652 const std::vector<long long>& particleWeights = m_weightScratch;
653
654 if (m_particlePlacement == ParticlePlacement::Parent) {
655 this->buildParentWeights(m_parentWeightScratch, *a_particles[i], static_cast<std::size_t>(numParticles));
656 }
657
658 for (const auto& w : particleWeights) {
659 RealVect parentPos = RealVect::Zero;
660
661 const bool hasParent = (m_particlePlacement == ParticlePlacement::Parent) &&
662 this->sampleParentPosition(parentPos, *a_particles[i], m_parentWeightScratch);
663
664 const RealVect x = this->drawNewParticlePosition(hasParent,
665 hasDownstream,
666 parentPos,
667 upstreamPosition,
668 upstreamLo,
669 upstreamHi,
670 v,
671 a_cellPos,
672 a_centroidPos,
673 a_lo,
674 a_hi,
675 a_bndryCentroid,
676 a_bndryNormal,
677 a_dx,
678 a_kappa);
679
680 a_particles[i]->append(x, 1.0 * w, ItoParticle{});
681 }
682 }
683 else if (diff < 0LL) {
684 // Removing particles is a bit more difficult because we need to manipulate weights.
685 this->removeParticles(*a_particles[i], -diff);
686 }
687 }
688}
689
690inline RealVect
692 const bool a_hasDownstream,
693 const RealVect a_parentPos,
694 const RealVect a_upstreamPos,
695 const RealVect a_upstreamLo,
696 const RealVect a_upstreamHi,
697 const RealVect a_downstreamDirection,
698 const RealVect a_cellPos,
699 const RealVect a_centroidPos,
700 const RealVect a_lo,
701 const RealVect a_hi,
702 const RealVect a_bndryCentroid,
703 const RealVect a_bndryNormal,
704 const Real a_dx,
705 const Real a_kappa) const noexcept
706{
707 RealVect x = RealVect::Zero;
708
709 switch (m_particlePlacement) {
710 case ParticlePlacement::Centroid: {
711 x = a_cellPos + a_centroidPos * a_dx;
712
713 break;
714 }
715 case ParticlePlacement::Random: {
716 x = Random::randomPosition(a_cellPos, a_lo, a_hi, a_bndryCentroid, a_bndryNormal, a_dx, a_kappa);
717
718 break;
719 }
720 case ParticlePlacement::Parent: {
721 // Ionization happens at the electrons, so put the new particle on top of one of the particles that were
722 // already there, drawn with probability proportional to the parent weight. This is the placement that
723 // introduces no sub-grid transport of its own: it neither scatters the new weight across the cell (which
724 // acts as a numerical diffusion) nor pulls it towards the cell centre (which acts as a drag on the front).
725 // The inherited position is by construction on the fluid side of the EB, so no cut-cell test is needed.
726 //
727 // Falls back to a random position when there is nothing to inherit from, e.g. photoionization products
728 // landing in a cell that holds no particles of this species yet.
729 if (a_hasParent) {
730 x = a_parentPos;
731 }
732 else {
733 x = Random::randomPosition(a_cellPos, a_lo, a_hi, a_bndryCentroid, a_bndryNormal, a_dx, a_kappa);
734 }
735
736 break;
737 }
738 case ParticlePlacement::Downstream: {
739 if (a_hasDownstream) {
740 x = Random::randomPosition(a_upstreamLo, a_upstreamHi, a_upstreamPos, a_downstreamDirection);
741
742 if ((x - a_bndryCentroid).dotProduct(a_bndryNormal) < 0.0) {
743 x = a_upstreamPos;
744 }
745
746 x = a_cellPos + x * a_dx;
747 }
748 else {
749
750 x = Random::randomPosition(a_cellPos, a_lo, a_hi, a_bndryCentroid, a_bndryNormal, a_dx, a_kappa);
751 }
752
753 break;
754 }
755 default: {
756 MayDay::Error("ItoKMCPhysics::drawNewParticlePosition - logic bust");
757
758 break;
759 }
760 }
761
762 return x;
763}
764
765inline void
766ItoKMCPhysics::buildParentWeights(std::vector<Real>& a_cumulativeWeights,
767 const ParticleSoA<ItoParticle>& a_particles,
768 const std::size_t a_numEligible) const noexcept
769{
770 a_cumulativeWeights.clear();
771 a_cumulativeWeights.reserve(a_numEligible);
772
773 Real runningSum = 0.0;
774
775 for (std::size_t j = 0; j < a_numEligible; j++) {
776 runningSum += a_particles.weight(j);
777
778 a_cumulativeWeights.push_back(runningSum);
779 }
780}
781
782inline bool
784 const ParticleSoA<ItoParticle>& a_particles,
785 const std::vector<Real>& a_cumulativeWeights) const noexcept
786{
787 if (a_cumulativeWeights.empty() || a_cumulativeWeights.back() <= 0.0) {
788 return false;
789 }
790
791 const Real r = Random::getUniformReal01() * a_cumulativeWeights.back();
792
793 // First entry whose running sum reaches r. The end() case is round-off leaving the last sum a hair below r.
794 const auto it = std::lower_bound(a_cumulativeWeights.cbegin(), a_cumulativeWeights.cend(), r);
795
796 const std::size_t parent = (it == a_cumulativeWeights.cend())
797 ? a_cumulativeWeights.size() - 1
798 : static_cast<std::size_t>(it - a_cumulativeWeights.cbegin());
799
800 a_pos = a_particles.position(parent);
801
802 return true;
803}
804
805inline void
807 const Vector<ParticleSoA<ItoParticle>*>& a_itoParticles,
808 const Vector<long long>& a_numNewParticles,
809 const RealVect a_electricField,
810 const RealVect a_cellPos,
811 const RealVect a_centroidPos,
812 const RealVect a_lo,
813 const RealVect a_hi,
814 const RealVect a_bndryCentroid,
815 const RealVect a_bndryNormal,
816 const Real a_dx,
817 const Real a_kappa) const noexcept
818{
819 CH_assert(m_isDefined);
820 CH_assert(a_cdrParticles.size() == a_numNewParticles.size());
821 CH_assert(a_itoParticles.size() == m_itoSpecies.size());
822
823 // Most cells produce nothing for most species, and everything below is per-cell setup that such a cell must not
824 // pay for. Note that the productions are >= 0 by contract -- the caller has already split off the removal.
825 bool hasProduction = false;
826
827 for (int i = 0; i < a_numNewParticles.size(); i++) {
828 CH_assert(a_numNewParticles[i] >= 0LL);
829
830 hasProduction = hasProduction || (a_numNewParticles[i] > 0LL);
831 }
832
833 if (!hasProduction) {
834 return;
835 }
836
837 // Downstream placement needs the drift direction and the downstream region, exactly as in reconcileParticles.
838 bool hasDownstream = false;
839 RealVect upstreamPosition = RealVect::Zero;
840 RealVect upstreamLo = -0.5 * RealVect::Unit;
841 RealVect upstreamHi = +0.5 * RealVect::Unit;
842 RealVect v = RealVect::Zero;
843
844 if (m_particlePlacement == ParticlePlacement::Downstream) {
845 CH_assert(m_downstreamSpecies >= 0);
846
847 const int Z = m_itoSpecies[m_downstreamSpecies]->getChargeNumber();
848
849 if (Z != 0) {
850 v = Z * a_electricField;
851 v = v / v.vectorLength();
852 }
853
854 hasDownstream = this->computeUpstreamPosition(upstreamPosition,
855 upstreamLo,
856 upstreamHi,
857 Z,
858 *a_itoParticles[m_downstreamSpecies],
859 a_electricField,
860 a_cellPos,
861 a_dx);
862 }
863
864 // ParticlePlacement::Parent has no meaning here: a CDR product has no parents in the cell, its container holding
865 // only what the current step created. drawNewParticlePosition falls back to a uniformly random position.
866 constexpr bool hasParent = false;
867 const RealVect parentPos = RealVect::Zero;
868
869 for (int i = 0; i < a_cdrParticles.size(); i++) {
870 if (a_numNewParticles[i] > 0LL) {
871
872 // Same partition as the Ito products: at most m_maxNewParticles computational particles, each carrying an
873 // integer number of physical ones.
874 ParticleManagement::partitionParticleWeights(m_weightScratch,
875 a_numNewParticles[i],
876 static_cast<long long>(m_maxNewParticles));
877
878 for (const auto& w : m_weightScratch) {
879 const RealVect x = this->drawNewParticlePosition(hasParent,
880 hasDownstream,
881 parentPos,
882 upstreamPosition,
883 upstreamLo,
884 upstreamHi,
885 v,
886 a_cellPos,
887 a_centroidPos,
888 a_lo,
889 a_hi,
890 a_bndryCentroid,
891 a_bndryNormal,
892 a_dx,
893 a_kappa);
894
895 a_cdrParticles[i]->append(x, 1.0 * w);
896 }
897 }
898 }
899}
900
901inline bool
903 RealVect& a_lo,
904 RealVect& a_hi,
905 const int& a_Z,
906 const ParticleSoA<ItoParticle>& a_particles,
907 const RealVect& a_electricField,
908 const RealVect& a_cellPos,
909 const Real& a_dx) const noexcept
910{
911 CH_assert(a_dx > 0.0);
912
913 a_pos = RealVect::Zero;
914 a_lo = -0.5 * RealVect::Unit;
915 a_hi = +0.5 * RealVect::Unit;
916
917 const int Z = (a_Z > 0) ? 1 : (a_Z < 0) ? -1 : 0;
918 const RealVect E = a_electricField / a_electricField.vectorLength();
919 const RealVect v = Z * E;
920
921 // Upstream can only exist if there is a velocity direction and there are particles.
922 const bool hasDownstream = (a_particles.size() > 0) && (v.vectorLength() > 0.0);
923
924 if (hasDownstream) {
925
926 Real D = std::numeric_limits<Real>::max();
927
928 for (std::size_t i = 0; i < a_particles.size(); i++) {
929 const RealVect x = (a_particles.position(i) - a_cellPos) / a_dx;
930 const Real d = x.dotProduct(v);
931
932 if (d < D) {
933 D = d;
934 a_pos = x;
935 }
936 }
937
938 DataOps::computeMinValidBox(a_lo, a_hi, v, a_pos);
939 }
940
941 if (m_debug) {
942 for (int dir = 0; dir < SpaceDim; dir++) {
943 if (a_pos[dir] > 0.5 || a_pos[dir] < -0.5) {
944 MayDay::Abort("ItoKMCPhysics::computeUpstreamPosition - logic bust");
945 }
946 }
947 }
948
949 return hasDownstream;
950}
951
952inline void
953ItoKMCPhysics::removeParticles(ParticleSoA<ItoParticle>& a_particles, const long long a_numParticlesToRemove) const
954{
955 constexpr long long zero = 0LL;
956
957 CH_assert(m_isDefined);
958 CH_assert(a_numParticlesToRemove >= zero);
959
960 // Quick lambda for getting total particle weight. Used for debugging.
961 auto getTotalWeight = [&]() -> long long {
962 long long W = zero;
963
964 for (std::size_t i = 0; i < a_particles.size(); i++) {
965 W += llround(a_particles.weight(i));
966
967 if (a_particles.weight(i) < 1.0) {
968 MayDay::Error("ItoKMCPhysics::removeParticles -- bad particle mass!");
969 }
970 }
971
972 return W;
973 };
974
975 if (a_numParticlesToRemove > zero) {
976
977 // For debugging only.
978 long long totalWeightBefore = 0;
979 long long totalWeightAfter = 0;
980
981 // Debug hook, compute the total particle weight before we start removing weights.
982 if (m_debug) {
983 totalWeightBefore = getTotalWeight();
984
985 if (totalWeightBefore < a_numParticlesToRemove) {
986 MayDay::Error("ItoKMCPhysics::removeParticles: logic bust (trying to remove too many particles)");
987 }
988 }
989
990 // Remove physical particles.
991 ParticleManagement::removePhysicalParticles(a_particles, a_numParticlesToRemove);
992
993 // Remove particles with too low weight.
994 ParticleManagement::deleteParticles(a_particles, std::numeric_limits<Real>::min());
995
996 // Debug hook, make sure that particle weights are > 0 AND we've removed the desired
997 // particle weight.
998 if (m_debug) {
999 totalWeightAfter = getTotalWeight();
1000
1001 const long long errDiff = std::abs(totalWeightBefore - totalWeightAfter) - a_numParticlesToRemove;
1002 if (std::abs(errDiff) != zero) {
1003
1004 pout() << "ItoKMCPhysics::removeParticles: Total weight before = " << totalWeightBefore << endl;
1005 pout() << "ItoKMCPhysics::removeParticles: Total weight after = " << totalWeightAfter << endl;
1006 pout() << "ItoKMCPhysics::removeParticles: Should have removed = " << a_numParticlesToRemove << endl;
1007 pout() << "ItoKMCPhysics::removeParticles: Error = " << errDiff << endl;
1008
1009 MayDay::Abort("ItoKMCPhysics::removeParticles - incorrect mass removed");
1010 }
1011 }
1012 }
1013}
1014
1015inline void
1017 const Vector<FPR>& a_numNewPhotons,
1018 const RealVect a_cellPos,
1019 const RealVect a_centroidPos,
1020 const RealVect a_lo,
1021 const RealVect a_hi,
1022 const RealVect a_bndryCentroid,
1023 const RealVect a_bndryNormal,
1024 const Real a_dx,
1025 const Real a_kappa) const noexcept
1026{
1027 CH_assert(m_isDefined);
1028
1029 for (int i = 0; i < a_newPhotons.size(); i++) {
1030 if (a_numNewPhotons[i] > 0LL) {
1031
1032 ParticleManagement::partitionParticleWeights(m_weightScratch,
1033 static_cast<long long>(a_numNewPhotons[i]),
1034 static_cast<long long>(m_maxNewPhotons));
1035
1036 const std::vector<long long>& photonWeights = m_weightScratch;
1037
1038 for (const auto& w : photonWeights) {
1039 const RealVect x = Random::randomPosition(a_cellPos, a_lo, a_hi, a_bndryCentroid, a_bndryNormal, a_dx, a_kappa);
1040 const RealVect v = Units::c * Random::getDirection();
1041 const Real kappa = m_rtSpecies[i]->getAbsorptionCoefficient(x);
1042
1043 a_newPhotons[i]->append(
1044 x,
1045 1.0 * w,
1046 Photon{
1047 static_cast<ParticleReal>(kappa),
1048 D_DECL(static_cast<ParticleReal>(v[0]), static_cast<ParticleReal>(v[1]), static_cast<ParticleReal>(v[2]))});
1049 }
1050 }
1051 }
1052}
1053
1054inline void
1056 Vector<ParticleSoA<NoPayload>*>& a_cdrParticles,
1057 const Vector<ParticleSoA<Photon>*>& a_absorbedPhotons) const noexcept
1058{
1059 CH_assert(m_isDefined);
1060 CH_assert(a_itoParticles.size() == m_itoSpecies.size());
1061 CH_assert(a_cdrParticles.size() == m_cdrSpecies.size());
1062
1063 for (int i = 0; i < a_absorbedPhotons.size(); i++) {
1064 if (m_photoPathways.find(i) != m_photoPathways.end()) {
1065 std::discrete_distribution<int> d = m_photoPathways.at(i).first;
1066 const std::map<int, int>& localToGlobalMap = m_photoPathways.at(i).second;
1067
1068 const ParticleSoA<Photon>& absorbedPhotons = *a_absorbedPhotons[i];
1069
1070 for (std::size_t p = 0; p < absorbedPhotons.size(); p++) {
1071 const RealVect x = absorbedPhotons.position(p);
1072 const Real w = absorbedPhotons.weight(p);
1073
1074 // Determine the photo-reaction type.
1075 const int localReaction = Random::get(d);
1076 const int globalReaction = localToGlobalMap.at(localReaction);
1077
1078 const ItoKMCPhotoReaction& photoReaction = m_photoReactions[globalReaction];
1079 const std::list<size_t>& plasmaTargets = photoReaction.getTargetSpecies();
1080
1081 for (const auto& t : plasmaTargets) {
1082 const SpeciesType& type = m_speciesMap.at(t).first;
1083 const int& localIndex = m_speciesMap.at(t).second;
1084
1085 if (type == SpeciesType::Ito) {
1086 a_itoParticles[localIndex]->append(x, w, ItoParticle{});
1087 }
1088 else if (type == SpeciesType::CDR) {
1089 a_cdrParticles[localIndex]->append(x, w);
1090 }
1091 else {
1092 MayDay::Error("CD_ItoKMCPhysics.H - logic bust in reconcilePhotoionization");
1093 }
1094 }
1095 }
1096 }
1097 }
1098}
1099
1100inline RealVect
1101ItoKMCPhysics::noDiffusion(const ItoParticle& a_particle, const Real a_dt) const noexcept
1102{
1103 return RealVect::Zero;
1104}
1105
1106inline RealVect
1107ItoKMCPhysics::isotropicDiffusion(const ItoParticle& a_particle, const Real a_dt) const noexcept
1108{
1109 RealVect r = RealVect::Zero;
1110
1111 for (int dir = 0; dir < SpaceDim; dir++) {
1112 r[dir] = Random::getNormal01();
1113 }
1114
1115 return sqrt(2.0 * a_particle.diffusion * a_dt) * r;
1116}
1117
1118inline RealVect
1119ItoKMCPhysics::forwardIsotropicDiffusion(const ItoParticle& a_particle, const Real a_dt) const noexcept
1120{
1121 RealVect hop = this->isotropicDiffusion(a_particle, a_dt);
1122
1123 const RealVect v = RealVect(D_DECL(a_particle.vx, a_particle.vy, a_particle.vz));
1124
1125 if (v != RealVect::Zero) {
1126 const RealVect u = v / v.vectorLength();
1127 const Real d = u.dotProduct(hop);
1128
1129 hop -= std::min(d, 0.0) * u;
1130 }
1131
1132 return hop;
1133}
1134
1135#include <CD_NamespaceFooter.H>
1136
1137#endif
Agglomeration of useful data operations.
Declaration of the Physics::ItoKMC::ItoKMCPhysics abstract base class.
Real FPR
Floating-point type used to represent particle counts in the KMC state.
Definition CD_ItoKMCPhysics.H:45
SpeciesType
Tag for distinguishing species solved with an Ito diffusion or CDR fluid formalism.
Definition CD_ItoKMCPhysics.H:76
@ ImplicitEuler
Implicit Euler tau leaping.
@ Midpoint
Gillespie's midpoint method.
@ ExplicitEuler
Regular tau leaping.
@ PRC
Hu and Li's Poisson random correction method.
Namespace containing various particle management utilities.
CD_PARTICLE_REAL ParticleReal
Floating-point type a user may use for payload columns.
Definition CD_ParticleSoA.H:156
File containing some useful static methods related to random number generation.
Declaration of various useful units.
static void computeMinValidBox(RealVect &a_lo, RealVect &a_hi, const RealVect &a_normal, const RealVect &a_centroid)
Compute the tightest possible valid box around a cut-cell volume.
Definition CD_DataOps.cpp:3748
Declaration of a "dual state" for advancing with the Kinetic Monte Carlo module.
Definition CD_KMCDualState.H:32
State & getNonReactiveState() noexcept
Get modifiable non-reactive state.
Definition CD_KMCDualStateImplem.H:114
void define(const size_t a_numReactiveSpecies, const size_t a_numNonReactiveSpecies) noexcept
Define function.
Definition CD_KMCDualStateImplem.H:37
State & getReactiveState() noexcept
Get modifiable reactive state.
Definition CD_KMCDualStateImplem.H:100
void setSolverParameters(T a_numCrit, T a_numSSA, T a_maxIter, Real a_eps, Real a_SSAlim, Real a_exitTol) noexcept
Set solver parameters.
Definition CD_KMCSolverImplem.H:59
Real computeDt(const State &a_state, const ReactionList &a_reactions, const std::vector< Real > &a_propensities, Real a_epsilon) const noexcept
Compute a time step using the leap condition on the mean value.
Definition CD_KMCSolverImplem.H:399
void define(const ReactionList &a_reactions) noexcept
Define function. Sets the reactions.
Definition CD_KMCSolverImplem.H:49
void advanceSSA(State &a_state, Real a_dt) const noexcept
Advance with the SSA over the input time. This can end up using substepping.
Definition CD_KMCSolverImplem.H:526
void advanceHybrid(State &a_state, Real a_dt, const KMCLeapPropagator &a_leapPropagator=KMCLeapPropagator::ExplicitEuler) const noexcept
Advance using Cao et. al. hybrid algorithm over the input time. This can end up using substepping.
Definition CD_KMCSolverImplem.H:943
void advanceTau(State &a_state, const Real &a_dt, const KMCLeapPropagator &a_leapPropagator=KMCLeapPropagator::ExplicitEuler) const noexcept
Advance using a specified tau-leaping algorithm.
Definition CD_KMCSolverImplem.H:863
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
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:1195
double & weight(const std::size_t a_index) noexcept
Weight of particle i.
Definition CD_ParticleSoA.H:1229
std::size_t size() const noexcept
Number of particles currently stored.
Definition CD_ParticleSoA.H:882
Reaction class for describing photoionization in ItoKMCPhysics.
Definition CD_ItoKMCPhotoReaction.H:32
const Real & getEfficiency() const noexcept
Get the reaction efficiency.
Definition CD_ItoKMCPhotoReactionImplem.H:60
const size_t & getSourcePhoton() const noexcept
Get the source photon species index.
Definition CD_ItoKMCPhotoReactionImplem.H:48
const std::list< size_t > & getTargetSpecies() const noexcept
Get the plasma product species indices.
Definition CD_ItoKMCPhotoReactionImplem.H:54
int m_maxNewParticles
Maximum new number of particles generated by the chemistry advance.
Definition CD_ItoKMCPhysics.H:662
static thread_local std::vector< std::shared_ptr< const KMCReaction > > m_kmcReactionsDt
The subset of m_kmcReactionsThreadLocal that takes part in the physics time step calculation.
Definition CD_ItoKMCPhysics.H:592
int m_NSSA
Solver setting for the Cao et. al algorithm.
Definition CD_ItoKMCPhysics.H:680
Vector< RefCountedPtr< RtSpecies > > m_rtSpecies
List of solver-tracked photon species.
Definition CD_ItoKMCPhysics.H:650
int m_downstreamSpecies
An internal integer describing which species is the "ionizing" species.
Definition CD_ItoKMCPhysics.H:657
virtual void updateReactionRates(std::vector< std::shared_ptr< const KMCReaction > > &a_kmcReactions, const RealVect a_E, const RealVect a_pos, const Vector< Real > &a_phi, const Vector< RealVect > &a_gradPhi, const Real a_dt, const Real a_dx, const Real a_kappa) const noexcept=0
Update reaction rates.
RealVect forwardIsotropicDiffusion(const ItoParticle &a_particle, const Real a_dt) const noexcept
Quasi-isotropic diffusion function for a particle which does not permit backward diffusion.
Definition CD_ItoKMCPhysicsImplem.H:1119
Vector< DiffusionFunction > m_itoDiffusionFunctions
Diffusion functions for the various Ito species.
Definition CD_ItoKMCPhysics.H:635
Real m_eps
Solver setting for the Cao et. al. algorithm.
Definition CD_ItoKMCPhysics.H:697
bool m_debug
Turn on/off debugging.
Definition CD_ItoKMCPhysics.H:527
std::vector< Real > m_reactiveDtFactors
List of reactions that are a part of the time step limitation.
Definition CD_ItoKMCPhysics.H:617
int m_maxNewPhotons
Maximum new number of photons generated by the chemistry advance.
Definition CD_ItoKMCPhysics.H:667
void reconcilePhotons(Vector< ParticleSoA< Photon > * > &a_newPhotons, const Vector< FPR > &a_numNewPhotons, const RealVect a_cellPos, const RealVect a_centroidPos, const RealVect a_lo, const RealVect a_hi, const RealVect a_bndryCentroid, const RealVect a_bndryNormal, const Real a_dx, const Real a_kappa) const noexcept
Generate new photons.
Definition CD_ItoKMCPhysicsImplem.H:1016
void defineKMC() const noexcept
Define the KMC solver and state.
Definition CD_ItoKMCPhysicsImplem.H:121
RealVect isotropicDiffusion(const ItoParticle &a_particle, const Real a_dt) const noexcept
Isotropic diffusion function for a particle.
Definition CD_ItoKMCPhysicsImplem.H:1107
void advanceKMC(Vector< FPR > &a_numParticles, Vector< FPR > &a_numNewPhotons, Real &a_physicsDt, const Vector< Real > &a_phi, const Vector< RealVect > &a_gradPhi, const Real a_dt, const RealVect a_E, const RealVect a_pos, const Real a_dx, const Real a_kappa) const
Advance the reaction network using the KMC algorithm.
Definition CD_ItoKMCPhysicsImplem.H:392
std::string m_className
Class name. Used for options parsing.
Definition CD_ItoKMCPhysics.H:522
const Vector< DiffusionFunction > & getItoDiffusionFunctions() const noexcept
Get diffusion functions for all Ito species.
Definition CD_ItoKMCPhysicsImplem.H:356
std::vector< ItoKMCPhotoReaction > m_photoReactions
List of photoionization reactions.
Definition CD_ItoKMCPhysics.H:612
const Vector< RefCountedPtr< RtSpecies > > & getRtSpecies() const
Get all photon species.
Definition CD_ItoKMCPhysicsImplem.H:350
Vector< RefCountedPtr< ItoSpecies > > m_itoSpecies
List of solver-tracked particle drift-diffusion species.
Definition CD_ItoKMCPhysics.H:640
Vector< RefCountedPtr< CdrSpecies > > m_cdrSpecies
List of solver-tracked fluid drift-diffusion species.
Definition CD_ItoKMCPhysics.H:645
virtual Real initialSigma(const Real a_time, const RealVect &a_pos) const
Set initial surface charge. Default is 0, override if you want.
Definition CD_ItoKMCPhysicsImplem.H:386
Real m_exitTol
Exit tolerance for implicit KMC-leaping algorithms.
Definition CD_ItoKMCPhysics.H:702
static thread_local std::vector< Real > m_reactiveDtFactorsDt
Time-step scaling factors for m_kmcReactionsDt, parallel to it.
Definition CD_ItoKMCPhysics.H:597
virtual ~ItoKMCPhysics() noexcept
Destructor. Does nothing.
Definition CD_ItoKMCPhysicsImplem.H:58
static thread_local KMCState m_kmcStateScratch
Perturbed KMC state used by the time step tail of advanceKMC.
Definition CD_ItoKMCPhysics.H:555
static thread_local KMCSolverType m_kmcSolver
Kinetic Monte Carlo solver used in advanceReactionNetwork.
Definition CD_ItoKMCPhysics.H:542
void defineSpeciesMap() noexcept
Build internal representation of how we distinguish the Ito and CDR solvers.
Definition CD_ItoKMCPhysicsImplem.H:94
const Vector< RefCountedPtr< ItoSpecies > > & getItoSpecies() const
Get all particle drift-diffusion species.
Definition CD_ItoKMCPhysicsImplem.H:338
Real m_SSAlim
Solver setting for the Cao et. al. algorithm.
Definition CD_ItoKMCPhysics.H:691
void parseAlgorithm() noexcept
Parse reaction algorithm.
Definition CD_ItoKMCPhysicsImplem.H:289
void removeParticles(ParticleSoA< ItoParticle > &a_particles, const long long a_numToRemove) const
Remove particles from the input list.
Definition CD_ItoKMCPhysicsImplem.H:953
int m_maxIter
Maximum number of iterations for implicit KMC-leaping algorithms.
Definition CD_ItoKMCPhysics.H:685
int m_Ncrit
Solver setting for the Cao et. al algorithm.
Definition CD_ItoKMCPhysics.H:674
const std::map< int, std::pair< SpeciesType, int > > & getSpeciesMap() const noexcept
Get the internal mapping from plasma-species index to solver type and solver index.
Definition CD_ItoKMCPhysicsImplem.H:246
bool computeUpstreamPosition(RealVect &a_pos, RealVect &a_lo, RealVect &a_hi, const int &a_Z, const ParticleSoA< ItoParticle > &a_particles, const RealVect &a_electricField, const RealVect &a_cellPos, const Real &a_dx) const noexcept
Compute the upstream position in a grid cell. Returns false if an upstream position was undefinable.
Definition CD_ItoKMCPhysicsImplem.H:902
static thread_local std::vector< Real > m_kmcPropensityScratchDt
Propensity buffer for m_kmcReactionsDt, parallel to it.
Definition CD_ItoKMCPhysics.H:602
std::map< int, std::pair< std::discrete_distribution< int >, std::map< int, int > > > m_photoPathways
Random number generators for photoionization pathways.
Definition CD_ItoKMCPhysics.H:625
RealVect drawNewParticlePosition(const bool a_hasParent, const bool a_hasDownstream, const RealVect a_parentPos, const RealVect a_upstreamPos, const RealVect a_upstreamLo, const RealVect a_upstreamHi, const RealVect a_downstreamDirection, const RealVect a_cellPos, const RealVect a_centroidPos, const RealVect a_lo, const RealVect a_hi, const RealVect a_bndryCentroid, const RealVect a_bndryNormal, const Real a_dx, const Real a_kappa) const noexcept
Draw a position for a particle created by the reaction network in a grid cell.
Definition CD_ItoKMCPhysicsImplem.H:691
@ HybridMidpoint
Hybrid SSA / midpoint (Cao et al.).
@ ImplicitEuler
Implicit tau-leaping with Euler steps.
@ SSA
Gillespie's Stochastic Simulation Algorithm (exact).
@ Midpoint
Explicit tau-leaping with midpoint (second-order) steps.
@ ExplicitEuler
Explicit tau-leaping with Euler steps.
@ HybridImplicitEuler
Hybrid SSA / implicit Euler (Cao et al.).
@ HybridPRC
Hybrid SSA / PRC (Cao et al.).
@ HybridExplicitEuler
Hybrid SSA / explicit Euler (Cao et al.).
@ PRC
Partially-rejected corrections tau-leaping.
Algorithm m_algorithm
Algorithm to use for KMC advance.
Definition CD_ItoKMCPhysics.H:507
virtual void parseRuntimeOptions() noexcept
Parse run-time options.
Definition CD_ItoKMCPhysicsImplem.H:254
@ Random
Place particles at a uniformly random position within the cell.
void reconcileParticles(Vector< ParticleSoA< ItoParticle > * > &a_particles, const Vector< FPR > &a_newNumParticles, const Vector< FPR > &a_oldNumParticles, const RealVect a_electricField, const RealVect a_cellPos, const RealVect a_centroidPos, const RealVect a_lo, const RealVect a_hi, const RealVect a_bndryCentroid, const RealVect a_bndryNormal, const Real a_dx, const Real a_kappa) const noexcept
Reconcile the number of particles.
Definition CD_ItoKMCPhysicsImplem.H:577
const Vector< RefCountedPtr< CdrSpecies > > & getCdrSpecies() const
Get all fluid drift-diffusion species.
Definition CD_ItoKMCPhysicsImplem.H:344
static thread_local std::vector< std::shared_ptr< const KMCReaction > > m_kmcReactionsThreadLocal
Thread-local copies of KMC reactions used in advanceReactionNetwork.
Definition CD_ItoKMCPhysics.H:584
std::vector< KMCReaction > m_kmcReactions
List of reactions for the KMC solver.
Definition CD_ItoKMCPhysics.H:607
int getNumPhotonSpecies() const
Return number of RTE solvers.
Definition CD_ItoKMCPhysicsImplem.H:380
int getNumPlasmaSpecies() const
Return total number of plasma species.
Definition CD_ItoKMCPhysicsImplem.H:374
int getNumItoSpecies() const
Return number of Ito solvers.
Definition CD_ItoKMCPhysicsImplem.H:362
void define() noexcept
Define method – defines all the internal machinery.
Definition CD_ItoKMCPhysicsImplem.H:64
void buildParentWeights(std::vector< Real > &a_cumulativeWeights, const ParticleSoA< ItoParticle > &a_particles, const std::size_t a_numEligible) const noexcept
Build the running weight sum that sampleParentPosition() draws from.
Definition CD_ItoKMCPhysicsImplem.H:766
bool sampleParentPosition(RealVect &a_pos, const ParticleSoA< ItoParticle > &a_particles, const std::vector< Real > &a_cumulativeWeights) const noexcept
Draw the position of a parent particle, with probability proportional to particle weight.
Definition CD_ItoKMCPhysicsImplem.H:783
std::map< int, std::pair< SpeciesType, int > > m_speciesMap
Map for associating a plasma species with an Ito solver or CDR solver.
Definition CD_ItoKMCPhysics.H:517
RealVect noDiffusion(const ItoParticle &a_particle, const Real a_dt) const noexcept
No diffusion function for a particle.
Definition CD_ItoKMCPhysicsImplem.H:1101
void killKMC() const noexcept
Kill the KMC solver.
Definition CD_ItoKMCPhysicsImplem.H:172
void definePhotoPathways() noexcept
Define pathways for photo-reactions.
Definition CD_ItoKMCPhysicsImplem.H:193
void reconcilePhotoionization(Vector< ParticleSoA< ItoParticle > * > &a_itoParticles, Vector< ParticleSoA< NoPayload > * > &a_cdrParticles, const Vector< ParticleSoA< Photon > * > &a_absorbedPhotons) const noexcept
Reconcile photoionization reactions.
Definition CD_ItoKMCPhysicsImplem.H:1055
void parsePPC() noexcept
Parse the maximum number of particles generated per cell.
Definition CD_ItoKMCPhysicsImplem.H:264
void reconcileCdrParticles(Vector< ParticleSoA< NoPayload > * > &a_cdrParticles, const Vector< ParticleSoA< ItoParticle > * > &a_itoParticles, const Vector< long long > &a_numNewParticles, const RealVect a_electricField, const RealVect a_cellPos, const RealVect a_centroidPos, const RealVect a_lo, const RealVect a_hi, const RealVect a_bndryCentroid, const RealVect a_bndryNormal, const Real a_dx, const Real a_kappa) const noexcept
Turn the CDR mass created by the reaction network into particles.
Definition CD_ItoKMCPhysicsImplem.H:806
static thread_local bool m_hasKMCSolver
Is the KMC solver defined or not.
Definition CD_ItoKMCPhysics.H:537
int getNumCdrSpecies() const
Return number of CDR solvers.
Definition CD_ItoKMCPhysicsImplem.H:368
ParticlePlacement m_particlePlacement
Particle placement algorithm.
Definition CD_ItoKMCPhysics.H:512
void parseDebug() noexcept
Parse the maximum number of particles generated per cell.
Definition CD_ItoKMCPhysicsImplem.H:279
bool m_isDefined
Is defined or not.
Definition CD_ItoKMCPhysics.H:532
static thread_local std::vector< Real > m_kmcPropensityScratch
Propensity buffer used by the time step tail of advanceKMC.
Definition CD_ItoKMCPhysics.H:562
static thread_local KMCState m_kmcState
KMC state used in advanceReactionNetwork.
Definition CD_ItoKMCPhysics.H:547
virtual bool needGradient(const int a_plasmaIndex) const noexcept
Return true if the physics model reads the density gradient of one particular plasma species.
Definition CD_ItoKMCPhysicsImplem.H:112
ItoKMCPhysics() noexcept
Constructor. Does nothing.
Definition CD_ItoKMCPhysicsImplem.H:32
static Real get(T &a_distribution)
For getting a random number from a user-supplied distribution. T must be a distribution for which we ...
Definition CD_RandomImplem.H:219
static RealVect getDirection()
Get a random direction in space.
Definition CD_RandomImplem.H:182
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition CD_RandomImplem.H:158
static Real getNormal01()
Get a number from a normal distribution centered on zero and variance 1.
Definition CD_RandomImplem.H:174
static RealVect randomPosition(const RealVect &a_lo, const RealVect &a_hi) noexcept
Return a random position in the cube (a_lo, a_hi);.
Definition CD_RandomImplem.H:286
constexpr Real c
Speed of light.
Definition CD_Units.H:40
SoA payload for ItoSolver particles, i.e. drifting Brownian walkers.
Definition CD_ItoParticle.H:31
SoA payload for Monte Carlo radiative-transfer photons.
Definition CD_Photon.H:29