17#ifndef CD_DISCHARGEINCEPTIONSTEPPERIMPLEM_H
18#define CD_DISCHARGEINCEPTIONSTEPPERIMPLEM_H
34#include <CD_NamespaceHeader.H>
36using namespace Physics::DischargeInception;
38template <
typename P,
typename F,
typename C>
41 CH_TIME(
"DischargeInceptionStepper::DischargeInceptionStepper");
42 if (m_verbosity > 5) {
43 pout() <<
"DischargeInceptionStepper::DischargeInceptionStepper" << endl;
50 m_mode = Mode::Stationary;
51 m_transportAlgorithm = TransportAlgorithm::ImExCTU;
52 m_timeStepRestriction = TimeStepRestriction::Unknown;
55 m_fullIntegration =
false;
56 m_evaluateTownsend =
false;
57 m_relativeDeltaU = 1 + 0.05;
63 m_rho = [](
const RealVect x) -> Real {
67 m_sigma = [](
const RealVect x) -> Real {
71 m_alpha = [](
const Real E,
const RealVect x) -> Real {
75 m_eta = [](
const Real E,
const RealVect x) -> Real {
79 m_voltageCurve = [](
const Real a_time) -> Real {
83 m_backgroundRate = [](
const Real E,
const RealVect x) -> Real {
87 m_detachmentRate = [](
const Real E,
const RealVect x) -> Real {
91 m_fieldEmission = [](
const Real E,
const RealVect x) -> Real {
95 m_secondaryEmission = [](
const Real E,
const RealVect x) -> Real {
99 m_initialIonDensity = [](
const RealVect x) -> Real {
103 m_ionMobility = [](
const Real E) -> Real {
107 m_ionDiffusion = [](
const Real E) -> Real {
112template <
typename P,
typename F,
typename C>
115 CH_TIME(
"DischargeInceptionStepper::~DischargeInceptionStepper");
116 if (m_verbosity > 5) {
117 pout() <<
"DischargeInceptionStepper::~DischargeInceptionStepper" << endl;
121template <
typename P,
typename F,
typename C>
125 CH_TIME(
"DischargeInceptionStepper::setupSolvers");
126 if (m_verbosity > 5) {
127 pout() <<
"DischargeInceptionStepper::setupSolvers" << endl;
131 auto voltage = [](
const Real a_time) -> Real {
136 m_fieldSolver = RefCountedPtr<FieldSolver>(
new F());
137 m_fieldSolver->setVerbosity(m_verbosity);
138 m_fieldSolver->parseOptions();
139 m_fieldSolver->setAmr(m_amr);
140 m_fieldSolver->setComputationalGeometry(m_computationalGeometry);
141 m_fieldSolver->setVoltage(voltage);
142 m_fieldSolver->setRealm(m_realm);
143 m_fieldSolver->setTime(0, 0.0, 0.0);
147 m_tracerParticleSolver->parseOptions();
148 m_tracerParticleSolver->setAmr(m_amr);
149 m_tracerParticleSolver->setComputationalGeometry(m_computationalGeometry);
150 m_tracerParticleSolver->setRealm(m_realm);
151 m_tracerParticleSolver->setPhase(m_phase);
152 m_tracerParticleSolver->setTime(0, 0.0, 0.0);
153 m_tracerParticleSolver->setName(
"Tracer particle solver");
154 m_tracerParticleSolver->setVolumeScale(
true);
155 m_tracerParticleSolver->setDeposition(DepositionType::NGP);
158 m_ionSolver = RefCountedPtr<CdrSolver>(
new C());
160 m_ionSolver->parseOptions();
161 m_ionSolver->setPhase(m_phase);
162 m_ionSolver->setAmr(m_amr);
163 m_ionSolver->setComputationalGeometry(m_computationalGeometry);
164 m_ionSolver->setRealm(m_realm);
168 m_ionSolver->setSpecies(species);
171template <
typename P,
typename F,
typename C>
175 CH_TIME(
"DischargeInceptionStepper::allocate");
176 if (m_verbosity > 5) {
177 pout() <<
"DischargeInceptionStepper::allocate" << endl;
180 m_fieldSolver->allocate();
181 m_tracerParticleSolver->allocate();
182 m_ionSolver->allocate();
185 m_amr->allocate(m_potential, m_realm, 1);
186 m_amr->allocate(m_potentialHomo, m_realm, 1);
187 m_amr->allocate(m_potentialInho, m_realm, 1);
189 m_amr->allocate(m_electricField, m_realm, SpaceDim);
190 m_amr->allocate(m_electricFieldHomo, m_realm, SpaceDim);
191 m_amr->allocate(m_electricFieldInho, m_realm, SpaceDim);
193 m_amr->allocate(m_gradAlpha, m_realm, m_phase, SpaceDim);
199 case Mode::Stationary: {
200 m_amr->allocate(m_inceptionVoltagePlus, m_realm, m_phase, 1);
201 m_amr->allocate(m_inceptionVoltageMinu, m_realm, m_phase, 1);
202 m_amr->allocate(m_streamerInceptionVoltagePlus, m_realm, m_phase, 1);
203 m_amr->allocate(m_streamerInceptionVoltageMinu, m_realm, m_phase, 1);
204 m_amr->allocate(m_townsendInceptionVoltagePlus, m_realm, m_phase, 1);
205 m_amr->allocate(m_townsendInceptionVoltageMinu, m_realm, m_phase, 1);
216 case Mode::Transient: {
217 m_amr->allocate(m_inceptionIntegral, m_realm, m_phase, 1);
218 m_amr->allocate(m_townsendCriterion, m_realm, m_phase, 1);
219 m_amr->allocate(m_emissionRate, m_realm, m_phase, 1);
220 m_amr->allocate(m_backgroundIonization, m_realm, m_phase, 1);
221 m_amr->allocate(m_detachment, m_realm, m_phase, 1);
237template <
typename P,
typename F,
typename C>
241 CH_TIME(
"DischargeInceptionStepper::initialData");
242 if (m_verbosity > 5) {
243 pout() <<
"DischargeInceptionStepper::initialData" << endl;
246 this->solvePoisson();
249template <
typename P,
typename F,
typename C>
253 CH_TIME(
"DischargeInceptionStepper::solvePoisson");
254 if (m_verbosity > 5) {
255 pout() <<
"DischargeInceptionStepper::solvePoisson" << endl;
259 m_fieldSolver->setRho(m_rho);
260 m_fieldSolver->setSigma(m_sigma);
261 m_fieldSolver->setVoltage([](
const Real& a_time) {
266 DataOps::copy(m_fieldSolver->getPotential(), m_potentialInho);
267 const bool convergedInho = m_fieldSolver->solve(m_fieldSolver->getPotential(),
268 m_fieldSolver->getRho(),
269 m_fieldSolver->getSigma(),
272 if (!convergedInho) {
273 MayDay::Warning(
"DischargeInceptionStepper::solvePoisson -- could not solve the inhomogeneous Poisson equation. ");
276 DataOps::copy(m_potentialInho, m_fieldSolver->getPotential());
277 DataOps::copy(m_electricFieldInho, m_fieldSolver->getElectricField());
280 m_fieldSolver->setRho([](
const RealVect& a_pos) {
283 m_fieldSolver->setSigma([](
const RealVect& a_pos) {
286 m_fieldSolver->setVoltage([](
const Real& a_time) {
290 DataOps::copy(m_fieldSolver->getPotential(), m_potentialHomo);
291 const bool convergedHomo = m_fieldSolver->solve(m_fieldSolver->getPotential(),
292 m_fieldSolver->getRho(),
293 m_fieldSolver->getSigma(),
296 if (!convergedHomo) {
297 MayDay::Warning(
"DischargeInceptionStepper::solvePoisson -- could not solve the homogeneous Poisson equation. ");
300 DataOps::copy(m_potentialHomo, m_fieldSolver->getPotential());
301 DataOps::copy(m_electricFieldHomo, m_fieldSolver->getElectricField());
304 m_homogeneousFieldGas = m_amr->alias(
phase::gas, m_electricFieldHomo);
310 const Real testVoltage = 1.0;
311 const Real errorThresh = 1.E-6;
319 auto voltage = [V = testVoltage](
const Real& a_time) {
325 m_fieldSolver->setRho(m_rho);
326 m_fieldSolver->setSigma(m_sigma);
327 m_fieldSolver->setVoltage(voltage);
328 m_fieldSolver->solve(m_fieldSolver->getPotential(), m_fieldSolver->getRho(), m_fieldSolver->getSigma(),
false);
331 DataOps::incr(m_potential, m_fieldSolver->getPotential(), -1.0);
333 EBAMRCellData phiGas = m_amr->alias(
phase::gas, m_potential);
338 DataOps::getMaxMin(max, min, phiGas, 0, m_amr->getMultiCutVofIterator(m_realm, m_phase));
340 if (std::max(std::abs(max), std::abs(min)) > errorThresh * testVoltage) {
341 MayDay::Error(
"DischargeInceptionStepper::solvePoisson - debug test failed. Check your BCs!");
346template <
typename P,
typename F,
typename C>
350 CH_TIME(
"DischargeInceptionStepper::registerRealms");
351 if (m_verbosity > 5) {
352 pout() <<
"DischargeInceptionStepper::registerRealms" << endl;
355 m_amr->registerRealm(m_realm);
358template <
typename P,
typename F,
typename C>
362 CH_TIME(
"DischargeInceptionStepper::registerOperators");
363 if (m_verbosity > 5) {
364 pout() <<
"DischargeInceptionStepper::registerOperators" << endl;
367 m_fieldSolver->registerOperators();
368 m_tracerParticleSolver->registerOperators();
369 m_ionSolver->registerOperators();
372template <
typename P,
typename F,
typename C>
376 CH_TIME(
"DischargeInceptionStepper::parseOptions");
378 this->parseVerbosity();
380 this->parseVoltages();
382 this->parsePlotVariables();
383 this->parseInceptionAlgorithm();
384 this->parseTransportAlgorithm();
387template <
typename P,
typename F,
typename C>
391 CH_TIME(
"DischargeInceptionStepper::parseRuntimeOptions");
392 if (m_verbosity > 5) {
393 pout() <<
"DischargeInceptionStepper::parseRuntimeOptions" << endl;
396 this->parseVerbosity();
397 this->parsePlotVariables();
398 this->parseInceptionAlgorithm();
399 this->parseTransportAlgorithm();
402template <
typename P,
typename F,
typename C>
406 CH_TIME(
"DischargeInceptionStepper::parseVerbosity");
407 if (m_verbosity > 5) {
408 pout() <<
"DischargeInceptionStepper::parseVerbosity" << endl;
411 ParmParse pp(
"DischargeInceptionStepper");
412 pp.get(
"verbosity", m_verbosity);
413 pp.get(
"profile", m_profile);
414 pp.query(
"debug", m_debug);
417template <
typename P,
typename F,
typename C>
421 CH_TIME(
"DischargeInceptionStepper::parseMode");
422 if (m_verbosity > 5) {
423 pout() <<
"DischargeInceptionStepper::parseMode" << endl;
426 ParmParse pp(
"DischargeInceptionStepper");
431 if (str ==
"stationary") {
432 m_mode = Mode::Stationary;
434 else if (str ==
"transient") {
435 m_mode = Mode::Transient;
438 MayDay::Error(
"Expected 'none', 'stationary', or 'transient' for 'DischargeInceptionStepper.mode'");
442template <
typename P,
typename F,
typename C>
446 CH_TIME(
"DischargeInceptionStepper::parseVoltages");
447 if (m_verbosity > 5) {
448 pout() <<
"DischargeInceptionStepper::parseVoltages" << endl;
451 ParmParse pp(
"DischargeInceptionStepper");
453 pp.get(
"rel_step_dU", m_relativeDeltaU);
454 pp.get(
"step_dK", m_deltaK);
455 pp.get(
"limit_max_K", m_maxKLimit);
456 pp.get(
"K_inception", m_inceptionK);
457 pp.get(
"eval_townsend", m_evaluateTownsend);
459 m_relativeDeltaU = 1.0 + m_relativeDeltaU;
462template <
typename P,
typename F,
typename C>
466 CH_TIME(
"DischargeInceptionStepper::parseOutput");
467 if (m_verbosity > 5) {
468 pout() <<
"DischargeInceptionStepper::parseOutput" << endl;
471 ParmParse pp(
"DischargeInceptionStepper");
473 pp.get(
"output_file", m_outputFile);
476template <
typename P,
typename F,
typename C>
480 CH_TIME(
"DischargeInceptionStepper::parseInceptionAlgorithm");
481 if (m_verbosity > 5) {
482 pout() <<
"DischargeInceptionStepper::parseInceptionAlgorithm" << endl;
485 ParmParse pp(
"DischargeInceptionStepper");
490 pp.get(
"full_integration", m_fullIntegration);
491 pp.get(
"inception_alg", str);
492 if (str ==
"euler") {
493 m_inceptionAlgorithm = IntegrationAlgorithm::Euler;
495 else if (str ==
"trapz") {
496 m_inceptionAlgorithm = IntegrationAlgorithm::Trapezoidal;
499 MayDay::Error(
"Expected 'euler' or 'trapz' for 'DischargeInceptionStepper.inception_alg'");
502 pp.get(
"min_phys_dx", m_minPhysDx);
503 pp.get(
"max_phys_dx", m_maxPhysDx);
504 pp.get(
"min_grid_dx", m_minGridDx);
505 pp.get(
"max_grid_dx", m_maxGridDx);
506 pp.get(
"alpha_dx", m_alphaDx);
507 pp.get(
"grad_alpha_dx", m_gradAlphaDx);
508 pp.get(
"townsend_grid_dx", m_townsendGridDx);
510 if (m_minPhysDx <= 0.0) {
511 MayDay::Abort(
"DischargeInceptionStepper.min_phys_dx must be > 0.0");
513 if (m_maxPhysDx <= 0.0) {
514 MayDay::Abort(
"DischargeInceptionStepper.max_phys_dx must be > 0.0");
516 if (m_minGridDx <= 0.0) {
517 MayDay::Abort(
"DischargeInceptionStepper.min_grid_dx must be > 0.0");
519 if (m_maxGridDx <= 0.0) {
520 MayDay::Abort(
"DischargeInceptionStepper.max_grid_dx must be > 0.0");
522 if (m_alphaDx <= 0.0) {
523 MayDay::Abort(
"DischargeInceptionStepper.alpha_dx must be > 0.0");
525 if (m_gradAlphaDx <= 0.0) {
526 MayDay::Abort(
"DischargeInceptionStepper.grad_alpha_dx must be > 0.0");
528 if (m_townsendGridDx <= 0.0) {
529 MayDay::Abort(
"DischargeInceptionStepper.townsend_grid_dx must be > 0.0");
533template <
typename P,
typename F,
typename C>
537 CH_TIME(
"DischargeInceptionStepper::parseTransportAlgorithm");
538 if (m_verbosity > 5) {
539 pout() <<
"DischargeInceptionStepper::parseTransportAlgorithm" << endl;
542 ParmParse pp(
"DischargeInceptionStepper");
546 pp.get(
"transport_alg", str);
547 pp.get(
"ion_transport", m_ionTransport);
548 pp.get(
"cfl", m_cfl);
549 pp.get(
"first_dt", m_firstDt);
550 pp.get(
"min_dt", m_minDt);
551 pp.get(
"max_dt", m_maxDt);
552 pp.get(
"max_dt_growth", m_maxDtGrowth);
553 pp.get(
"voltage_eps", m_epsVoltage);
555 CH_assert(m_minDt >= 0.0);
556 CH_assert(m_maxDt >= 0.0);
557 CH_assert(m_firstDt > 0.0);
559 if (str ==
"euler") {
560 m_transportAlgorithm = TransportAlgorithm::Euler;
562 else if (str ==
"heun") {
563 m_transportAlgorithm = TransportAlgorithm::Heun;
565 else if (str ==
"imex") {
566 m_transportAlgorithm = TransportAlgorithm::ImExCTU;
569 MayDay::Error(
"Expected 'euler', 'heun', or 'imex' for 'DischargeInceptionStepper.transport_alg'");
573template <
typename P,
typename F,
typename C>
577 CH_TIME(
"DischargeInceptionStepper::parsePlotVariables");
578 if (m_verbosity > 5) {
579 pout() <<
"DischargeInceptionStepper::parsePlotVariables" << endl;
583 m_plotPoisson =
false;
584 m_plotTracer =
false;
585 m_plotNegativeIons =
false;
586 m_plotInceptionIntegral =
false;
587 m_plotInceptionVoltage =
false;
588 m_plotBackgroundIonization =
false;
589 m_plotDetachment =
false;
590 m_plotFieldEmission =
false;
593 m_plotTownsend =
false;
595 ParmParse pp(
"DischargeInceptionStepper");
598 const int num = pp.countval(
"plt_vars");
600 Vector<std::string> plotVars(num);
601 pp.getarr(
"plt_vars", plotVars, 0, num);
603 for (
int i = 0; i < num; i++) {
604 if (plotVars[i] ==
"field") {
607 else if (plotVars[i] ==
"poisson") {
608 m_plotPoisson =
true;
610 else if (plotVars[i] ==
"tracer") {
613 else if (plotVars[i] ==
"ions") {
614 m_plotNegativeIons =
true;
616 else if (plotVars[i] ==
"K") {
617 m_plotInceptionIntegral =
true;
619 else if (plotVars[i] ==
"Uinc") {
620 m_plotInceptionVoltage =
true;
622 else if (plotVars[i] ==
"bg_rate") {
623 m_plotBackgroundIonization =
true;
625 else if (plotVars[i] ==
"detachment") {
626 m_plotDetachment =
true;
628 else if (plotVars[i] ==
"emission") {
629 m_plotFieldEmission =
true;
631 else if (plotVars[i] ==
"alpha") {
634 else if (plotVars[i] ==
"eta") {
637 else if (plotVars[i] ==
"T") {
638 m_plotTownsend =
true;
645template <
typename P,
typename F,
typename C>
649 CH_TIME(
"DischargeInceptionStepper::writeCheckpointData");
650 if (m_verbosity > 5) {
651 pout() <<
"DischargeInceptionStepper::writeCheckpointData" << endl;
657template <
typename P,
typename F,
typename C>
661 CH_TIME(
"DischargeInceptionStepper::readCheckpointData");
662 if (m_verbosity > 5) {
663 pout() <<
"DischargeInceptionStepper::readCheckpointData" << endl;
666 MayDay::Error(
"DischargeInceptionStepper::readCheckpointData -- restart not supported. Use Driver.restart=0");
670template <
typename P,
typename F,
typename C>
674 CH_TIME(
"DischargeInceptionStepper::getNumberOfPlotVariables");
675 if (m_verbosity > 5) {
676 pout() <<
"DischargeInceptionStepper::getNumberOfPlotVariables" << endl;
682 ncomp += m_fieldSolver->getNumberOfPlotVariables();
685 ncomp += m_tracerParticleSolver->getNumberOfPlotVariables();
687 if (m_plotNegativeIons) {
688 ncomp += m_ionSolver->getNumberOfPlotVariables();
692 case Mode::Stationary: {
696 ncomp += 2 * m_voltageSweeps.size();
699 ncomp += 2 * m_voltageSweeps.size();
702 ncomp += 2 * SpaceDim * m_voltageSweeps.size();
709 if (m_plotInceptionIntegral) {
710 ncomp += 2 * m_voltageSweeps.size();
714 if (m_plotInceptionVoltage) {
719 if (m_plotBackgroundIonization) {
720 ncomp += m_voltageSweeps.size();
724 if (m_plotDetachment) {
725 ncomp += m_voltageSweeps.size();
729 if (m_plotFieldEmission) {
730 ncomp += 2 * m_voltageSweeps.size();
735 ncomp += m_voltageSweeps.size();
740 ncomp += m_voltageSweeps.size();
744 if (m_plotAlpha && m_plotEta) {
745 ncomp += m_voltageSweeps.size();
749 if (m_plotTownsend) {
750 ncomp += 2 * m_voltageSweeps.size();
755 case Mode::Transient: {
772 if (m_plotInceptionIntegral) {
775 if (m_plotTownsend) {
778 if (m_plotBackgroundIonization) {
781 if (m_plotDetachment) {
784 if (m_plotFieldEmission) {
793 if (m_plotAlpha && m_plotEta) {
807template <
typename P,
typename F,
typename C>
811 CH_TIME(
"DischargeInceptionStepper::getPlotVariableNames");
812 if (m_verbosity > 5) {
813 pout() <<
"DischargeInceptionStepper::getPlotVariableNames" << endl;
816 Vector<std::string> plotVars;
819 Vector<std::string> poissonVars = m_fieldSolver->getPlotVariableNames();
820 for (
int i = 0; i < poissonVars.size(); i++) {
821 poissonVars[i] =
"Poisson/" + poissonVars[i];
823 plotVars.append(poissonVars);
827 Vector<std::string> tracerVars = m_tracerParticleSolver->getPlotVariableNames();
828 for (
int i = 0; i < tracerVars.size(); i++) {
829 tracerVars[i] =
"Tracer/" + tracerVars[i];
831 plotVars.append(tracerVars);
834 if (m_plotNegativeIons) {
835 Vector<std::string> cdrVars = m_ionSolver->getPlotVariableNames();
836 for (
int i = 0; i < cdrVars.size(); i++) {
837 cdrVars[i] =
"CDR/" + cdrVars[i];
839 plotVars.append(cdrVars);
843 case Mode::Stationary: {
844 plotVars.append(this->getStationaryPlotVariableNames());
848 case Mode::Transient: {
849 plotVars.append(this->getTransientPlotVariableNames());
854 MayDay::Error(
"DischargeInceptionStepper::getPlotVariableNames - logic bust");
863template <
typename P,
typename F,
typename C>
867 CH_TIME(
"DischargeInceptionStepper::getStationaryPlotVariableNames");
868 if (m_verbosity > 5) {
869 pout() <<
"DischargeInceptionStepper::getStationaryPlotVariableNames" << endl;
872 Vector<std::string> plotVars;
874 const std::string prefix =
"DischargeInceptionStepper/";
878 for (
const Real& V : m_voltageSweeps) {
879 plotVars.push_back(prefix +
"Potential/+/ V = +" + std::to_string(V));
880 plotVars.push_back(prefix +
"Potential/-/ V = -" + std::to_string(V));
883 for (
const Real& V : m_voltageSweeps) {
884 plotVars.push_back(prefix +
"E/+/ V = +" + std::to_string(V));
885 plotVars.push_back(prefix +
"x-E/+/ V= +" + std::to_string(V));
886 plotVars.push_back(prefix +
"y-E/+/ V= +" + std::to_string(V));
888 plotVars.push_back(prefix +
"z-E/+/ V= +" + std::to_string(V));
891 plotVars.push_back(prefix +
"E/-/ V = -" + std::to_string(V));
892 plotVars.push_back(prefix +
"x-E/-/ V = -" + std::to_string(V));
893 plotVars.push_back(prefix +
"y-E/-/ V = -" + std::to_string(V));
895 plotVars.push_back(prefix +
"z-E/-/ V= -" + std::to_string(V));
900 plotVars.push_back(prefix +
"Space charge density");
901 plotVars.push_back(prefix +
"Surface charge density");
904 if (m_plotInceptionVoltage) {
905 plotVars.push_back(prefix +
"Minimum inception voltage +");
906 plotVars.push_back(prefix +
"Minimum inception voltage -");
907 plotVars.push_back(prefix +
"Streamer inception voltage +");
908 plotVars.push_back(prefix +
"Streamer inception voltage -");
909 plotVars.push_back(prefix +
"Townsend inception voltage +");
910 plotVars.push_back(prefix +
"Townsend inception voltage -");
913 if (m_plotInceptionIntegral) {
916 for (
const Real& V : m_voltageSweeps) {
917 varName = prefix +
"K-value/+/ V = +" + std::to_string(V);
918 plotVars.push_back(varName);
921 for (
const Real& V : m_voltageSweeps) {
922 varName = prefix +
"K-value/-/ V = -" + std::to_string(V);
923 plotVars.push_back(varName);
928 if (m_plotTownsend) {
929 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
930 const std::string varName = prefix +
"T-value/+/ V = +" + std::to_string(m_voltageSweeps[i]);
932 plotVars.push_back(varName);
935 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
936 const std::string varName = prefix +
"T-value/-/ V = -" + std::to_string(m_voltageSweeps[i]);
938 plotVars.push_back(varName);
943 if (m_plotBackgroundIonization) {
946 for (
const Real& V : m_voltageSweeps) {
947 varName = prefix +
"Background ionization rate/ V = " + std::to_string(V);
948 plotVars.push_back(varName);
953 if (m_plotDetachment) {
956 for (
const Real& V : m_voltageSweeps) {
957 varName = prefix +
"Detachment rate/ V = " + std::to_string(V);
958 plotVars.push_back(varName);
963 if (m_plotFieldEmission) {
966 for (
const Real& V : m_voltageSweeps) {
967 varName = prefix +
"Field emission rate/+/ V = +" + std::to_string(V);
968 plotVars.push_back(varName);
971 for (
const Real& V : m_voltageSweeps) {
972 varName = prefix +
"Field emission rate/-/ V = -" + std::to_string(V);
973 plotVars.push_back(varName);
979 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
981 const std::string varName = prefix +
"Alpha coefficient/ V = " + std::to_string(m_voltageSweeps[i]);
983 plotVars.push_back(varName);
989 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
990 const std::string varName = prefix +
"Eta coefficient/ V = " + std::to_string(m_voltageSweeps[i]);
992 plotVars.push_back(varName);
997 if (m_plotAlpha && m_plotEta) {
998 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
999 const std::string varName = prefix +
"Alpha_eff/ V = " + std::to_string(m_voltageSweeps[i]);
1001 plotVars.push_back(varName);
1008template <
typename P,
typename F,
typename C>
1012 CH_TIME(
"DischargeInceptionStepper::getTransientPlotVariableNames");
1013 if (m_verbosity > 5) {
1014 pout() <<
"DischargeInceptionStepper::getTransientPlotVariableNames" << endl;
1017 Vector<std::string> plotVars;
1021 plotVars.push_back(
"Electric potential");
1022 plotVars.push_back(
"E");
1023 plotVars.push_back(
"x-E");
1024 plotVars.push_back(
"y-E");
1025 if (SpaceDim == 3) {
1026 plotVars.push_back(
"z-E");
1030 plotVars.push_back(
"Space charge density");
1031 plotVars.push_back(
"Surface charge density");
1034 if (m_plotInceptionIntegral) {
1035 plotVars.push_back(
"Inception integral");
1038 if (m_plotTownsend) {
1039 plotVars.push_back(
"Townsend criterion");
1042 if (m_plotBackgroundIonization) {
1043 plotVars.push_back(
"Background rate");
1046 if (m_plotDetachment) {
1047 plotVars.push_back(
"Detachment rate");
1050 if (m_plotFieldEmission) {
1051 plotVars.push_back(
"Field emission");
1055 plotVars.push_back(
"Townsend alpha coefficient");
1059 plotVars.push_back(
"Townsend eta coefficient");
1062 if (m_plotAlpha && m_plotEta) {
1063 plotVars.push_back(
"Effective Townsend coefficient");
1066 for (
int i = 0; i < plotVars.size(); i++) {
1067 plotVars[i] =
"DischargeInceptionStepper/" + plotVars[i];
1073template <
typename P,
typename F,
typename C>
1077 const std::string& a_outputRealm,
1078 const int a_level)
const
1080 CH_TIME(
"DischargeInceptionStepper::writePlotData");
1081 if (m_verbosity > 5) {
1082 pout() <<
"DischargeInceptionStepper::writePlotData" << endl;
1085 if (m_plotPoisson) {
1086 m_fieldSolver->writePlotData(a_output, a_icomp, a_outputRealm, a_level);
1090 m_tracerParticleSolver->writePlotData(a_output, a_icomp, a_outputRealm, a_level);
1093 if (m_plotNegativeIons) {
1094 m_ionSolver->writePlotData(a_output, a_icomp, a_outputRealm, a_level);
1099 case Mode::Stationary: {
1100 this->writePlotDataStationary(a_output, a_icomp, a_outputRealm, a_level);
1104 case Mode::Transient:
1105 this->writePlotDataTransient(a_output, a_icomp, a_outputRealm, a_level);
1109 MayDay::Error(
"DischargeInceptionStepper::writePlotData - logic bust");
1116template <
typename P,
typename F,
typename C>
1120 const std::string& a_outputRealm,
1121 const int a_level)
const noexcept
1123 CH_TIME(
"DischargeInceptionStepper::writePlotDataStationary");
1124 if (m_verbosity > 5) {
1125 pout() <<
"DischargeInceptionStepper::writePlotDataStationary" << endl;
1128 const std::string prefix =
"DischargeInceptionStepper/";
1131 MFAMRCellData scratch;
1132 EBAMRIVData scratchSurf;
1134 m_amr->allocate(scratch, m_realm, 1);
1135 m_amr->allocate(scratchSurf, m_realm,
phase::gas, 1);
1137 for (
const auto& V : m_voltageSweeps) {
1143 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_potential,
phase::gas, a_outputRealm, a_level,
true);
1149 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_potential,
phase::gas, a_outputRealm, a_level,
true);
1152 for (
const auto& V : m_voltageSweeps) {
1155 DataOps::incr(m_electricField, m_electricFieldHomo, Real(V));
1159 m_amr->getMultiCutVofIterator(m_realm,
phase::gas),
1161 m_fieldSolver->writeMultifluidData(a_output, a_icomp, scratch,
phase::gas, a_outputRealm, a_level,
true);
1162 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_electricField,
phase::gas, a_outputRealm, a_level,
true);
1166 DataOps::incr(m_electricField, m_electricFieldHomo, -Real(V));
1170 m_amr->getMultiCutVofIterator(m_realm,
phase::gas),
1172 m_fieldSolver->writeMultifluidData(a_output, a_icomp, scratch,
phase::gas, a_outputRealm, a_level,
true);
1173 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_electricField,
phase::gas, a_outputRealm, a_level,
true);
1184 m_amr->arithmeticAverage(scratch, m_realm);
1185 m_amr->interpGhostPwl(scratch, m_realm);
1186 m_fieldSolver->writeMultifluidData(a_output, a_icomp, scratch,
phase::gas, a_outputRealm, a_level,
true);
1194 m_fieldSolver->writeSurfaceData(a_output, a_icomp, *scratchSurf[a_level], a_outputRealm, a_level);
1197 if (m_plotInceptionVoltage) {
1198 this->writeData(a_output, a_icomp, m_inceptionVoltagePlus, a_outputRealm, a_level,
false,
true);
1199 this->writeData(a_output, a_icomp, m_inceptionVoltageMinu, a_outputRealm, a_level,
false,
true);
1200 this->writeData(a_output, a_icomp, m_streamerInceptionVoltagePlus, a_outputRealm, a_level,
false,
true);
1201 this->writeData(a_output, a_icomp, m_streamerInceptionVoltageMinu, a_outputRealm, a_level,
false,
true);
1202 this->writeData(a_output, a_icomp, m_townsendInceptionVoltagePlus, a_outputRealm, a_level,
false,
true);
1203 this->writeData(a_output, a_icomp, m_townsendInceptionVoltageMinu, a_outputRealm, a_level,
false,
true);
1206 const int numVoltages = m_voltageSweeps.size();
1208 if (m_plotInceptionIntegral) {
1209 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1210 this->writeData(a_output, a_icomp, m_inceptionIntegralPlus[i], a_outputRealm, a_level,
false,
true);
1212 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1213 this->writeData(a_output, a_icomp, m_inceptionIntegralMinu[i], a_outputRealm, a_level,
false,
true);
1217 if (m_plotTownsend) {
1218 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1219 this->writeData(a_output, a_icomp, m_townsendCriterionPlus[i], a_outputRealm, a_level,
false,
true);
1222 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1223 this->writeData(a_output, a_icomp, m_townsendCriterionMinu[i], a_outputRealm, a_level,
false,
true);
1227 if (m_plotBackgroundIonization) {
1228 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1229 this->writeData(a_output, a_icomp, m_backgroundIonizationStationary[i], a_outputRealm, a_level,
false,
true);
1233 if (m_plotDetachment) {
1234 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1235 this->writeData(a_output, a_icomp, m_detachmentStationary[i], a_outputRealm, a_level,
false,
true);
1239 if (m_plotFieldEmission) {
1240 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1241 this->writeData(a_output, a_icomp, m_emissionRatesPlus[i], a_outputRealm, a_level,
false,
true);
1243 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
1244 this->writeData(a_output, a_icomp, m_emissionRatesMinu[i], a_outputRealm, a_level,
false,
true);
1249 LevelData<EBCellFAB> alpha;
1250 LevelData<EBCellFAB> alphaCoar;
1252 m_amr->allocate(alpha, m_realm, m_phase, a_level, 1);
1254 m_amr->allocate(alphaCoar, m_realm, m_phase, a_level - 1, 1);
1257 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
1258 this->evaluateFunction(alpha, m_voltageSweeps[i], m_alpha, a_level);
1260 this->evaluateFunction(alphaCoar, m_voltageSweeps[i], m_alpha, a_level - 1);
1261 m_amr->interpGhost(alpha, alphaCoar, a_level, m_realm, m_phase);
1267 m_amr->copyData(a_output, alpha, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1274 LevelData<EBCellFAB> eta;
1275 LevelData<EBCellFAB> etaCoar;
1277 m_amr->allocate(eta, m_realm, m_phase, a_level, 1);
1279 m_amr->allocate(etaCoar, m_realm, m_phase, a_level - 1, 1);
1282 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
1283 this->evaluateFunction(eta, m_voltageSweeps[i], m_eta, a_level);
1285 this->evaluateFunction(etaCoar, m_voltageSweeps[i], m_eta, a_level - 1);
1286 m_amr->interpGhost(eta, etaCoar, a_level, m_realm, m_phase);
1292 m_amr->copyData(a_output, eta, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1298 if (m_plotAlpha && m_plotEta) {
1299 LevelData<EBCellFAB> alphaEff;
1300 LevelData<EBCellFAB> alphaEffCoar;
1302 m_amr->allocate(alphaEff, m_realm, m_phase, a_level, 1);
1304 m_amr->allocate(alphaEffCoar, m_realm, m_phase, a_level - 1, 1);
1307 auto alphaFunc = [alpha = this->m_alpha, eta = this->m_eta](
const Real E,
const RealVect x) -> Real {
1308 return alpha(E, x) - eta(E, x);
1311 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
1312 this->evaluateFunction(alphaEff, m_voltageSweeps[i], alphaFunc, a_level);
1314 this->evaluateFunction(alphaEffCoar, m_voltageSweeps[i], alphaFunc, a_level - 1);
1315 m_amr->interpGhost(alphaEff, alphaEffCoar, a_level, m_realm, m_phase);
1318 alphaEff.exchange();
1323 m_amr->copyData(a_output, alphaEff, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1330template <
typename P,
typename F,
typename C>
1334 const std::string& a_outputRealm,
1335 const int a_level)
const noexcept
1337 CH_TIME(
"DischargeInceptionStepper::writePlotDataTransient");
1338 if (m_verbosity > 5) {
1339 pout() <<
"DischargeInceptionStepper::writePlotDataTransient" << endl;
1342 CH_assert(a_level >= 0);
1343 CH_assert(a_level <= m_amr->getFinestLevel());
1349 MFAMRCellData scratch;
1350 EBAMRIVData scratchSurf;
1352 m_amr->allocate(scratch, m_realm, 1);
1353 m_amr->allocate(scratchSurf, m_realm,
phase::gas, 1);
1357 m_amr->getMultiCutVofIterator(m_realm,
phase::gas),
1359 m_amr->arithmeticAverage(scratch, m_realm);
1360 m_amr->interpGhostPwl(scratch, m_realm);
1362 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_potential,
phase::gas, a_outputRealm, a_level,
true);
1363 m_fieldSolver->writeMultifluidData(a_output, a_icomp, scratch,
phase::gas, a_outputRealm, a_level,
true);
1364 m_fieldSolver->writeMultifluidData(a_output, a_icomp, m_electricField,
phase::gas, a_outputRealm, a_level,
true);
1374 m_amr->arithmeticAverage(scratch, m_realm);
1375 m_amr->interpGhostPwl(scratch, m_realm);
1376 m_fieldSolver->writeMultifluidData(a_output, a_icomp, scratch,
phase::gas, a_outputRealm, a_level,
true);
1384 m_fieldSolver->writeSurfaceData(a_output, a_icomp, *scratchSurf[a_level], a_outputRealm, a_level);
1387 if (m_plotInceptionIntegral) {
1388 this->writeData(a_output, a_icomp, m_inceptionIntegral, a_outputRealm, a_level,
false,
true);
1391 if (m_plotTownsend) {
1392 this->writeData(a_output, a_icomp, m_townsendCriterion, a_outputRealm, a_level,
false,
true);
1395 if (m_plotBackgroundIonization) {
1396 LevelData<EBCellFAB> bgIonization;
1397 m_amr->allocate(bgIonization, m_realm, m_phase, a_level, 1);
1399 this->evaluateFunction(bgIonization, m_voltageCurve(m_time), m_backgroundRate, a_level);
1404 ->copyData(a_output, bgIonization, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1409 if (m_plotDetachment) {
1410 LevelData<EBCellFAB> detachRate;
1411 LevelData<EBCellFAB> detachRateCoar;
1413 m_amr->allocate(detachRate, m_realm, m_phase, a_level, 1);
1415 m_amr->allocate(detachRateCoar, m_realm, m_phase, a_level - 1, 1);
1418 this->evaluateFunction(detachRate, m_voltageCurve(m_time), m_detachmentRate, a_level);
1420 this->evaluateFunction(detachRateCoar, m_voltageCurve(m_time), m_detachmentRate, a_level - 1);
1421 m_amr->interpGhost(detachRate, detachRateCoar, a_level, m_realm, m_phase);
1424 m_amr->copyData(a_output, detachRate, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1429 if (m_plotFieldEmission) {
1430 this->writeData(a_output, a_icomp, m_emissionRate, a_outputRealm, a_level,
false,
false);
1434 LevelData<EBCellFAB> alpha;
1435 LevelData<EBCellFAB> alphaCoar;
1437 m_amr->allocate(alpha, m_realm, m_phase, a_level, 1);
1439 m_amr->allocate(alphaCoar, m_realm, m_phase, a_level - 1, 1);
1442 this->evaluateFunction(alpha, m_voltageCurve(m_time), m_alpha, a_level);
1444 this->evaluateFunction(alphaCoar, m_voltageCurve(m_time), m_alpha, a_level - 1);
1445 m_amr->interpGhost(alpha, alphaCoar, a_level, m_realm, m_phase);
1453 m_amr->copyData(a_output, alpha, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1459 LevelData<EBCellFAB> eta;
1460 LevelData<EBCellFAB> etaCoar;
1462 m_amr->allocate(eta, m_realm, m_phase, a_level, 1);
1464 m_amr->allocate(etaCoar, m_realm, m_phase, a_level - 1, 1);
1467 this->evaluateFunction(eta, m_voltageCurve(m_time), m_eta, a_level);
1469 this->evaluateFunction(etaCoar, m_voltageCurve(m_time), m_eta, a_level - 1);
1470 m_amr->interpGhost(eta, etaCoar, a_level, m_realm, m_phase);
1478 m_amr->copyData(a_output, eta, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1483 if (m_plotAlpha && m_plotEta) {
1484 LevelData<EBCellFAB> alphaEff;
1485 LevelData<EBCellFAB> alphaEffCoar;
1487 m_amr->allocate(alphaEff, m_realm, m_phase, a_level, 1);
1489 m_amr->allocate(alphaEffCoar, m_realm, m_phase, a_level - 1, 1);
1492 auto alphaFunc = [alpha = this->m_alpha, eta = this->m_eta](
const Real E,
const RealVect x) -> Real {
1493 return alpha(E, x) - eta(E, x);
1496 this->evaluateFunction(alphaEff, m_voltageCurve(m_time), alphaFunc, a_level);
1498 this->evaluateFunction(alphaEffCoar, m_voltageCurve(m_time), alphaFunc, a_level - 1);
1499 m_amr->interpGhost(alphaEff, alphaEffCoar, a_level, m_realm, m_phase);
1502 alphaEff.exchange();
1507 m_amr->copyData(a_output, alphaEff, a_level, a_outputRealm, m_realm, Interval(a_icomp, a_icomp), Interval(0, 0));
1513template <
typename P,
typename F,
typename C>
1517 CH_TIME(
"DischargeInceptionStepper::computeDt");
1518 if (m_verbosity > 5) {
1519 pout() <<
"DischargeInceptionStepper::computeDt" << endl;
1522 Real dt = std::numeric_limits<Real>::max();
1524 if (m_mode == Mode::Transient) {
1527 m_timeStepRestriction = TimeStepRestriction::Unknown;
1530 if (m_ionTransport) {
1531 Real ionDt = std::numeric_limits<Real>::infinity();
1532 switch (m_transportAlgorithm) {
1533 case TransportAlgorithm::Euler: {
1534 ionDt = m_cfl * m_ionSolver->computeAdvectionDiffusionDt();
1538 case TransportAlgorithm::Heun: {
1539 ionDt = m_cfl * m_ionSolver->computeAdvectionDiffusionDt();
1543 case TransportAlgorithm::ImExCTU: {
1544 ionDt = m_cfl * m_ionSolver->computeAdvectionDt();
1549 MayDay::Error(
"DischargeInceptionStepper::computDt -- logic bust");
1557 m_timeStepRestriction = TimeStepRestriction::CDR;
1562 Real curveDt = std::numeric_limits<Real>::max();
1563 if (m_timeStep == 0) {
1564 curveDt = m_firstDt;
1567 const Real preU = m_voltageCurve(m_time - m_dt);
1568 const Real curU = m_voltageCurve(m_time);
1569 const Real dVdt = std::abs(curU - preU) / dt;
1571 if (dVdt > std::numeric_limits<Real>::epsilon()) {
1572 curveDt = m_epsVoltage * std::abs(curU) / dVdt;
1576 curveDt = std::min(m_dt * (1.0 + m_maxDtGrowth), curveDt);
1577 curveDt = std::max(m_dt * (1.0 - m_maxDtGrowth), curveDt);
1582 m_timeStepRestriction = TimeStepRestriction::VoltageCurve;
1588 m_timeStepRestriction = TimeStepRestriction::MaxHardcap;
1593 m_timeStepRestriction = TimeStepRestriction::MinHardcap;
1600template <
typename P,
typename F,
typename C>
1604 CH_TIME(
"DischargeInceptionStepper::advance");
1605 if (m_verbosity > 5) {
1606 pout() <<
"DischargeInceptionStepper::advance" << endl;
1609 if (m_mode == Mode::Transient) {
1610 Timer timer(
"DischargeInceptionStepper::advance");
1612 const Real curTime = m_time + a_dt;
1613 const Real curVoltage = m_voltageCurve(curTime);
1620 m_amr->arithmeticAverage(m_potential, m_realm);
1621 m_amr->interpGhostPwl(m_potential, m_realm);
1624 DataOps::incr(m_electricField, m_electricFieldHomo, curVoltage);
1627 m_amr->arithmeticAverage(m_electricField, m_realm);
1628 m_amr->interpGhostPwl(m_electricField, m_realm);
1632 if (m_ionTransport) {
1633 this->computeIonVelocity(curVoltage);
1634 this->computeIonDiffusion(curVoltage);
1635 this->advanceIons(a_dt);
1641 this->seedIonizationParticles(curVoltage);
1642 this->computeInceptionIntegralTransient(curVoltage);
1645 if (m_evaluateTownsend) {
1647 this->seedIonizationParticles(curVoltage);
1648 this->computeTownsendCriterionTransient(curVoltage);
1654 const Real Vcr = this->computeCriticalVolumeTransient();
1655 const Real Acr = this->computeCriticalAreaTransient();
1656 const Real Vion = this->computeIonizationVolumeTransient(curVoltage);
1657 const Real Rdot = this->computeRdot(curVoltage);
1660 m_criticalVolume.emplace_back(curTime, Vcr);
1661 m_criticalArea.emplace_back(curTime, Acr);
1662 m_ionizationVolumeTransient.emplace_back(curTime, Vion);
1663 m_Rdot.emplace_back(curTime, Rdot);
1666 if (m_Rdot.size() >= 2) {
1669 for (
size_t i = 0; i < m_Rdot.size() - 1; i++) {
1670 const Real dt = m_Rdot[i + 1].first - m_Rdot[i].first;
1672 p += 0.5 * dt * (m_Rdot[i + 1].second + m_Rdot[i].second);
1675 m_inceptionProbability.emplace_back(curTime, 1.0 - exp(-p));
1680 Real maxK = -std::numeric_limits<Real>::max();
1681 Real minK = +std::numeric_limits<Real>::max();
1683 Real maxT = -std::numeric_limits<Real>::max();
1684 Real minT = +std::numeric_limits<Real>::max();
1686 DataOps::getMaxMin(maxK, minK, m_inceptionIntegral, 0, m_amr->getMultiCutVofIterator(m_realm, m_phase));
1687 DataOps::getMaxMin(maxT, minT, m_townsendCriterion, 0, m_amr->getMultiCutVofIterator(m_realm, m_phase));
1689 if (!m_fullIntegration) {
1690 maxK = std::min(maxK, m_inceptionK);
1691 maxT = std::min(maxT, 1.0);
1693 m_maxK.emplace_back(m_time + a_dt, maxK);
1694 m_maxT.emplace_back(m_time + a_dt, maxT);
1698 this->writeReportTransient();
1706 MayDay::Error(
"DischargeInceptionStepper::advance -- must have 'DischargeInceptionStepper.mode = transient'");
1712template <
typename P,
typename F,
typename C>
1716 CH_TIME(
"DischargeInceptionStepper::advanceIons");
1717 if (m_verbosity > 5) {
1718 pout() <<
"DischargeInceptionStepper::advanceIons" << endl;
1721 EBAMRCellData& phi = m_ionSolver->getPhi();
1726 EBAMRIVData& ebFlux = m_ionSolver->getEbFlux();
1727 m_ionSolver->extrapolateAdvectiveFluxToEB(ebFlux);
1728 DataOps::floor(ebFlux, 0.0, m_amr->getVofIterator(m_realm, m_phase));
1730 switch (m_transportAlgorithm) {
1731 case TransportAlgorithm::Euler: {
1733 m_amr->allocate(divJ, m_realm, m_phase, 1.0);
1735 m_ionSolver->computeDivJ(divJ, phi, 0.0,
false,
true,
false);
1741 case TransportAlgorithm::Heun: {
1747 m_amr->allocate(yp, m_realm, m_phase, 1);
1748 m_amr->allocate(k1, m_realm, m_phase, 1);
1749 m_amr->allocate(k2, m_realm, m_phase, 1);
1752 m_ionSolver->computeDivJ(k1, phi, 0.0,
false,
true,
false);
1757 m_ionSolver->computeDivJ(k2, yp, 0.0,
false,
true,
false);
1763 case TransportAlgorithm::ImExCTU: {
1764 const bool addEbFlux =
true;
1765 const bool addDomainFlux =
true;
1771 m_amr->allocate(k1, m_realm, m_phase, 1);
1772 m_amr->allocate(k2, m_realm, m_phase, 1);
1774 m_ionSolver->computeDivF(k1, phi, a_dt,
false,
true,
true);
1783 m_ionSolver->advanceCrankNicholson(phi, k2, k1, a_dt);
1788 MayDay::Error(
"DischargeInceptionStepper::advanceIons -- logic bust");
1792 DataOps::floor(phi, 0.0, m_amr->getVofIterator(m_realm, m_phase));
1794 m_amr->average(phi, m_realm, m_phase, Average::Conservative);
1795 m_amr->interpGhost(phi, m_realm, m_phase);
1798template <
typename P,
typename F,
typename C>
1802 CH_TIME(
"DischargeInceptionStepper::synchronizeSolverTimes");
1803 if (m_verbosity > 5) {
1804 pout() <<
"DischargeInceptionStepper::synchronizeSolverTimes" << endl;
1807 m_timeStep = a_step;
1811 m_fieldSolver->setTime(a_step, a_time, a_dt);
1812 m_tracerParticleSolver->setTime(a_step, a_time, a_dt);
1813 m_ionSolver->setTime(a_step, a_time, a_dt);
1816template <
typename P,
typename F,
typename C>
1820 CH_TIME(
"DischargeInceptionStepper::printStepReport");
1822 if (m_verbosity > 5) {
1823 pout() <<
"DischargeInceptionStepper::printStepReport" << endl;
1827 std::string timeStepMessage;
1828 switch (m_timeStepRestriction) {
1829 case TimeStepRestriction::Unknown: {
1830 timeStepMessage =
"Unknown";
1834 case TimeStepRestriction::CDR: {
1835 timeStepMessage =
"CFL";
1839 case TimeStepRestriction::VoltageCurve: {
1840 timeStepMessage =
"Voltage curve";
1844 case TimeStepRestriction::MinHardcap: {
1845 timeStepMessage =
"Min hardcap";
1849 case TimeStepRestriction::MaxHardcap: {
1850 timeStepMessage =
"Max hardcap";
1855 MayDay::Warning(
"DischargeInceptionStepper::printStepReport - logic bust");
1862 pout() <<
" ** Voltage = " << m_voltageCurve(m_time) << endl;
1863 pout() <<
" ** Crit. volume = " << m_criticalVolume.back().second << endl;
1864 pout() <<
" ** Inception probability = " << m_inceptionProbability.back().second << endl;
1865 pout() <<
" ** Time step restriction = " <<
"'" << timeStepMessage <<
"'" << endl;
1869template <
typename P,
typename F,
typename C>
1873 CH_TIME(
"DischargeInceptionStepper::preRegrid");
1874 if (m_verbosity > 5) {
1875 pout() <<
"DischargeInceptionStepper::preRegrid" << endl;
1878 m_fieldSolver->preRegrid(a_lmin, a_oldFinestLevel);
1879 m_tracerParticleSolver->preRegrid(a_lmin, a_oldFinestLevel);
1880 m_ionSolver->preRegrid(a_lmin, a_oldFinestLevel);
1882 m_amr->allocate(m_scratchHomo, m_realm, 1);
1883 m_amr->allocate(m_scratchInho, m_realm, 1);
1885 m_amr->copyData(m_scratchHomo, m_potentialHomo);
1886 m_amr->copyData(m_scratchInho, m_potentialInho);
1889template <
typename P,
typename F,
typename C>
1893 CH_TIME(
"DischargeInceptionStepper::regrid");
1894 if (m_verbosity > 5) {
1895 pout() <<
"DischargeInceptionStepper::regrid" << endl;
1899 m_fieldSolver->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
1900 m_tracerParticleSolver->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
1901 m_ionSolver->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
1904 m_amr->reallocate(m_potential, a_lmin);
1905 m_amr->reallocate(m_potentialHomo, a_lmin);
1906 m_amr->reallocate(m_potentialInho, a_lmin);
1908 m_amr->reallocate(m_electricField, a_lmin);
1909 m_amr->reallocate(m_electricFieldHomo, a_lmin);
1910 m_amr->reallocate(m_electricFieldInho, a_lmin);
1912 m_amr->reallocate(m_gradAlpha, m_phase, a_lmin);
1916 m_amr->interpToNewGrids(m_potentialHomo, m_scratchHomo, a_lmin, a_oldFinestLevel, a_newFinestLevel, interpType);
1917 m_amr->interpToNewGrids(m_potentialInho, m_scratchInho, a_lmin, a_oldFinestLevel, a_newFinestLevel, interpType);
1920 case Mode::Stationary: {
1921 m_amr->reallocate(m_inceptionVoltagePlus, m_phase, a_lmin);
1922 m_amr->reallocate(m_inceptionVoltageMinu, m_phase, a_lmin);
1923 m_amr->reallocate(m_streamerInceptionVoltagePlus, m_phase, a_lmin);
1924 m_amr->reallocate(m_streamerInceptionVoltageMinu, m_phase, a_lmin);
1925 m_amr->reallocate(m_townsendInceptionVoltagePlus, m_phase, a_lmin);
1926 m_amr->reallocate(m_townsendInceptionVoltageMinu, m_phase, a_lmin);
1930 case Mode::Transient: {
1931 m_amr->reallocate(m_inceptionIntegral, m_phase, a_lmin);
1932 m_amr->reallocate(m_townsendCriterion, m_phase, a_lmin);
1933 m_amr->reallocate(m_emissionRate, m_phase, a_lmin);
1934 m_amr->reallocate(m_backgroundIonization, m_phase, a_lmin);
1935 m_amr->reallocate(m_detachment, m_phase, a_lmin);
1945 this->solvePoisson();
1948 this->computeIonVelocity(m_voltageCurve(m_time));
1949 this->computeIonDiffusion(m_voltageCurve(m_time));
1952template <
typename P,
typename F,
typename C>
1956 CH_TIME(
"DischargeInceptionStepper::postRegrid");
1957 if (m_verbosity > 5) {
1958 pout() <<
"DischargeInceptionStepper::postRegrid" << endl;
1961 m_scratchHomo.clear();
1962 m_scratchInho.clear();
1965template <
typename P,
typename F,
typename C>
1969 CH_TIME(
"DischargeInceptionStepper::setVoltageCurve");
1970 if (m_verbosity > 5) {
1971 pout() <<
"DischargeInceptionStepper::setVoltageCurve" << endl;
1974 m_voltageCurve = a_voltageCurve;
1977template <
typename P,
typename F,
typename C>
1981 CH_TIME(
"DischargeInceptionStepper::setRho");
1982 if (m_verbosity > 5) {
1983 pout() <<
"DischargeInceptionStepper::setRho" << endl;
1989template <
typename P,
typename F,
typename C>
1993 CH_TIME(
"DischargeInceptionStepper::setSigma");
1994 if (m_verbosity > 5) {
1995 pout() <<
"DischargeInceptionStepper::setSigma" << endl;
2001template <
typename P,
typename F,
typename C>
2005 CH_TIME(
"DischargeInceptionStepper::setIonDensity");
2006 if (m_verbosity > 5) {
2007 pout() <<
"DischargeInceptionStepper::setIonDensity" << endl;
2010 m_initialIonDensity = a_density;
2013template <
typename P,
typename F,
typename C>
2017 CH_TIME(
"DischargeInceptionStepper::setIonMobility");
2018 if (m_verbosity > 5) {
2019 pout() <<
"DischargeInceptionStepper::setIonMobility" << endl;
2022 m_ionMobility = a_mobility;
2025template <
typename P,
typename F,
typename C>
2029 CH_TIME(
"DischargeInceptionStepper::setIonDiffusion");
2030 if (m_verbosity > 5) {
2031 pout() <<
"DischargeInceptionStepper::setIonDiffusion" << endl;
2034 m_ionDiffusion = a_diffCo;
2037template <
typename P,
typename F,
typename C>
2040 const std::function<Real(
const Real& E,
const RealVect& x)>& a_alpha)
noexcept
2042 CH_TIME(
"DischargeInceptionStepper::setAlpha");
2043 if (m_verbosity > 5) {
2044 pout() <<
"DischargeInceptionStepper::setAlpha" << endl;
2050template <
typename P,
typename F,
typename C>
2054 CH_TIME(
"DischargeInceptionStepper::setEta");
2055 if (m_verbosity > 5) {
2056 pout() <<
"DischargeInceptionStepper::setEta" << endl;
2062template <
typename P,
typename F,
typename C>
2063const std::function<Real(
const Real& E,
const RealVect& x)>&
2069template <
typename P,
typename F,
typename C>
2070const std::function<Real(
const Real& E,
const RealVect& x)>&
2076template <
typename P,
typename F,
typename C>
2079 const std::function<Real(
const Real& E,
const RealVect& x)>& a_backgroundRate)
noexcept
2081 CH_TIME(
"DischargeInceptionStepper::setBackgroundRate");
2082 if (m_verbosity > 5) {
2083 pout() <<
"DischargeInceptionStepper::setBackgroundRate" << endl;
2086 m_backgroundRate = a_backgroundRate;
2089template <
typename P,
typename F,
typename C>
2092 const std::function<Real(
const Real& E,
const RealVect& x)>& a_detachmentRate)
noexcept
2094 CH_TIME(
"DischargeInceptionStepper::setDetachmentRate");
2095 if (m_verbosity > 5) {
2096 pout() <<
"DischargeInceptionStepper::setDetachmentRate" << endl;
2099 m_detachmentRate = a_detachmentRate;
2102template <
typename P,
typename F,
typename C>
2105 const std::function<Real(
const Real& E,
const RealVect& x)>& a_currentDensity)
noexcept
2107 CH_TIME(
"DischargeInceptionStepper::setFieldEmission");
2108 if (m_verbosity > 5) {
2109 pout() <<
"DischargeInceptionStepper::setFieldEmission" << endl;
2112 m_fieldEmission = a_currentDensity;
2115template <
typename P,
typename F,
typename C>
2118 const std::function<Real(
const Real& E,
const RealVect& x)>& a_coefficient)
noexcept
2120 CH_TIME(
"DischargeInceptionStepper::setSecondaryEmission");
2121 if (m_verbosity > 5) {
2122 pout() <<
"DischargeInceptionStepper::setSecondaryEmission" << endl;
2125 m_secondaryEmission = a_coefficient;
2128template <
typename P,
typename F,
typename C>
2135template <
typename P,
typename F,
typename C>
2139 CH_TIME(
"DischargeInceptionStepper::seedUniformParticles");
2140 if (m_verbosity > 5) {
2141 pout() <<
"DischargeInceptionStepper::seedUniformParticles" << endl;
2147 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2148 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2149 const DataIterator& dit = dbl.dataIterator();
2150 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
2152 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
2154 const Real dx = m_amr->getDx()[lvl];
2156 auto& levelParticles = amrParticles[lvl];
2158 const int nbox = dit.size();
2160#pragma omp parallel for schedule(runtime)
2161 for (
int mybox = 0; mybox < nbox; mybox++) {
2162 const DataIndex& din = dit[mybox];
2164 const EBISBox& ebisbox = ebisl[din];
2165 const BaseFab<bool>& validCells = validCellsLD[din];
2169 auto regularKernel = [&](
const IntVect& iv) ->
void {
2170 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
2171 leaf.
append(m_amr->getProbLo() + (0.5 * RealVect::Unit + RealVect(iv)) * dx, 0.0);
2175 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
2176 if (validCells(vof.gridIndex())) {
2183 const Box cellBox = dbl[din];
2184 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
2186 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
2190 const double*
const pos[SpaceDim] = {
2192 double*
const x0[SpaceDim] = {
2193 D_DECL(leaf.template column<&P::x0_x>(), leaf.template column<&P::x0_y>(), leaf.template column<&P::x0_z>())};
2195 for (
int dir = 0; dir < SpaceDim; dir++) {
2196 x0[dir][i] = pos[dir][i];
2203 m_amr->removeCoveredParticlesIF(amrParticles, m_phase, 0.0);
2205 amrParticles.
remap();
2208template <
typename P,
typename F,
typename C>
2212 CH_TIME(
"DischargeInceptionStepper::seedIonizationParticles");
2213 if (m_verbosity > 5) {
2214 pout() <<
"DischargeInceptionStepper::seedIonizationParticles" << endl;
2221 EBAMRCellData scratch;
2222 EBAMRCellData alphaMesh;
2224 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
2225 m_amr->allocate(alphaMesh, m_realm, m_phase, 1);
2227 this->superposition(scratch, a_voltage);
2231 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2232 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2233 const DataIterator& dit = dbl.dataIterator();
2234 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
2236 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
2238 const Real dx = m_amr->getDx()[lvl];
2239 const RealVect probLo = m_amr->getProbLo();
2241 auto& levelParticles = amrParticles[lvl];
2243 const int nbox = dit.size();
2245#pragma omp parallel for schedule(runtime)
2246 for (
int mybox = 0; mybox < nbox; mybox++) {
2247 const DataIndex& din = dit[mybox];
2249 const EBISBox& ebisbox = ebisl[din];
2250 const BaseFab<bool>& validCells = validCellsLD[din];
2254 const EBCellFAB& electricField = (*scratch[lvl])[din];
2255 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
2257 EBCellFAB& alpha = (*alphaMesh[lvl])[din];
2258 FArrayBox& alphaReg = alpha.getFArrayBox();
2260 if (!ebisbox.isAllCovered()) {
2262 auto regularKernel = [&](
const IntVect& iv) ->
void {
2263 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
2265 const RealVect x = probLo + dx * (0.5 * RealVect::Unit + RealVect(iv));
2266 const RealVect EE = RealVect(
2267 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
2269 const Real E = EE.vectorLength();
2270 const Real curAlpha = m_alpha(E, x);
2271 const Real curEta = m_eta(E, x);
2273 if (curAlpha > curEta) {
2276 alphaReg(iv, 0) = curAlpha - curEta;
2281 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
2282 const IntVect iv = vof.gridIndex();
2284 if (validCells(iv, 0) && ebisbox.isIrregular(iv)) {
2285 const RealVect x = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
2286 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
2287 const Real E = EE.vectorLength();
2289 const Real curAlpha = m_alpha(E, x);
2290 const Real curEta = m_eta(E, x);
2292 if (curAlpha > curEta) {
2295 alpha(vof, 0) = curAlpha - curEta;
2302 const Box cellBox = dbl[din];
2303 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
2305 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
2311 const double*
const pos[SpaceDim] = {
2313 double*
const x0[SpaceDim] = {
2314 D_DECL(leaf.template column<&P::x0_x>(), leaf.template column<&P::x0_y>(), leaf.template column<&P::x0_z>())};
2316 for (
int dir = 0; dir < SpaceDim; dir++) {
2317 x0[dir][i] = pos[dir][i];
2324 m_amr->arithmeticAverage(alphaMesh, m_realm, m_phase);
2325 m_amr->interpGhost(alphaMesh, m_realm, m_phase);
2328 m_amr->computeGradient(m_gradAlpha, alphaMesh, m_realm, m_phase);
2331 m_amr->arithmeticAverage(m_gradAlpha, m_realm, m_phase);
2332 m_amr->interpGhost(m_gradAlpha, m_realm, m_phase);
2333 m_amr->interpToCentroids(m_gradAlpha, m_realm, m_phase);
2336template <
typename P,
typename F,
typename C>
2340 CH_TIME(
"DischargeInceptionStepper::postInitialize");
2341 if (m_verbosity > 5) {
2342 pout() <<
"DischargeInceptionStepper::postInitialize" << endl;
2346 m_ionSolver->initialData();
2347 this->computeIonVelocity(m_voltageCurve(m_time));
2348 this->computeIonDiffusion(m_voltageCurve(m_time));
2351 case Mode::Stationary: {
2352 this->computeInceptionIntegralStationary();
2353 this->computeTownsendCriterionStationary();
2354 this->computeCriticalVolumeStationary();
2355 this->computeCriticalAreaStationary();
2356 this->computeIonizationVolumeStationary();
2357 this->computeInceptionVoltageVolume();
2360 if (m_plotBackgroundIonization) {
2361 this->computeBackgroundIonizationStationary();
2364 if (m_plotDetachment) {
2365 this->computeDetachmentStationary();
2368 if (m_plotFieldEmission) {
2369 this->computeFieldEmissionStationary();
2372 this->writeReportStationary();
2376 case Mode::Transient: {
2379 this->seedIonizationParticles(m_voltageCurve(m_time));
2380 this->computeInceptionIntegralTransient(m_voltageCurve(m_time));
2383 if (m_evaluateTownsend) {
2384 this->seedIonizationParticles(m_voltageCurve(m_time));
2385 this->computeTownsendCriterionTransient(m_voltageCurve(m_time));
2389 Real maxK = -std::numeric_limits<Real>::max();
2390 Real minK = +std::numeric_limits<Real>::max();
2392 Real maxT = -std::numeric_limits<Real>::max();
2393 Real minT = +std::numeric_limits<Real>::max();
2395 DataOps::getMaxMin(maxK, minK, m_inceptionIntegral, 0, m_amr->getMultiCutVofIterator(m_realm, m_phase));
2396 DataOps::getMaxMin(maxT, minT, m_townsendCriterion, 0, m_amr->getMultiCutVofIterator(m_realm, m_phase));
2397 if (!m_fullIntegration) {
2398 maxK = std::min(maxK, m_inceptionK);
2399 maxT = std::min(maxT, 1.0);
2402 m_Rdot.emplace_back(m_time, this->computeRdot(m_voltageCurve(m_time)));
2403 m_criticalVolume.emplace_back(m_time, this->computeCriticalVolumeTransient());
2404 m_criticalArea.emplace_back(m_time, this->computeCriticalAreaTransient());
2405 m_ionizationVolumeTransient.emplace_back(m_time, this->computeIonizationVolumeTransient(m_voltageCurve(m_time)));
2406 m_inceptionProbability.emplace_back(m_time, 0.0);
2407 m_maxK.emplace_back(m_time, maxK);
2408 m_maxT.emplace_back(m_time, maxT);
2418template <
typename P,
typename F,
typename C>
2422 CH_TIME(
"DischargeInceptionStepper::interpolateGradAlphaToParticles");
2423 if (m_verbosity > 5) {
2424 pout() <<
"DischargeInceptionStepper::interpolateGradAlphaToParticles" << endl;
2428 m_amr->interpolateParticles<D_DECL(&P::ga_x, &P::ga_y, &P::ga_z)>(m_tracerParticleSolver->getParticles(),
2432 m_tracerParticleSolver->getInterpolationType(),
2436template <
typename P,
typename F,
typename C>
2439 const Real a_voltage)
noexcept
2441 CH_TIME(
"DischargeInceptionStepper::computeInceptionIntegral");
2442 if (m_verbosity > 5) {
2443 pout() <<
"DischargeInceptionStepper::computeInceptionIntegral" << endl;
2462 this->seedIonizationParticles(a_voltage);
2463 this->resetTracerParticles();
2466 switch (m_inceptionAlgorithm) {
2467 case IntegrationAlgorithm::Euler: {
2468 this->inceptionIntegrateEuler(a_voltage);
2472 case IntegrationAlgorithm::Trapezoidal: {
2473 this->inceptionIntegrateTrapezoidal(a_voltage);
2478 MayDay::Error(
"DischargeInceptionStepper::computeInceptionIntegral -- logic bust");
2485 m_tracerParticleSolver->deposit(a_inceptionIntegral);
2487 m_amr->conservativeAverage(a_inceptionIntegral, m_realm, m_phase);
2488 m_amr->interpGhost(a_inceptionIntegral, m_realm, m_phase);
2491template <
typename P,
typename F,
typename C>
2495 CH_TIME(
"DischargeInceptionStepper::computeInceptionIntegralStationary");
2496 if (m_verbosity > 5) {
2497 pout() <<
"DischargeInceptionStepper::computeInceptionIntegralStationary" << endl;
2500 constexpr int maxIter = 50;
2503 Real maxField = 0.0;
2504 Real minField = 0.0;
2506 EBAMRCellData gasField = m_amr->alias(
phase::gas, m_electricField);
2508 this->superposition(gasField, 1.0);
2513 const Real Ecrit = this->getCriticalField();
2515 Real curVoltage = m_relativeDeltaU * Ecrit / maxField;
2519 m_inceptionIntegralPlus.resize(0);
2520 m_inceptionIntegralMinu.resize(0);
2525 Real U1 = Ecrit / maxField;
2526 Real U2 = curVoltage;
2528 while (curMaxK < m_maxKLimit && curIter < maxIter) {
2529 EBAMRCellData Kplus;
2530 EBAMRCellData Kminu;
2532 m_amr->allocate(Kplus, m_realm, m_phase, 1);
2533 m_amr->allocate(Kminu, m_realm, m_phase, 1);
2538 m_inceptionIntegralPlus.push_back(Kplus);
2539 m_inceptionIntegralMinu.push_back(Kminu);
2541 this->computeInceptionIntegral(Kplus, +curVoltage);
2542 this->computeInceptionIntegral(Kminu, -curVoltage);
2545 Real maxKPlus = -std::numeric_limits<Real>::max();
2546 Real maxKMinu = -std::numeric_limits<Real>::max();
2548 RealVect maxKPlusPos = RealVect::Zero;
2549 RealVect maxKMinuPos = RealVect::Zero;
2551 this->getMaxValueAndLocation(maxKPlus, maxKPlusPos, Kplus);
2552 this->getMaxValueAndLocation(maxKMinu, maxKMinuPos, Kminu);
2555 m_KPlusValues.emplace_back(std::make_tuple(curVoltage, maxKPlus, maxKPlusPos));
2556 m_KMinuValues.emplace_back(std::make_tuple(curVoltage, maxKMinu, maxKMinuPos));
2558 curMaxK = std::max(maxKPlus, maxKMinu);
2566 const Real dKdU = (K2 - K1) / (U2 - U1);
2568 nextVoltage = U1 + ((K2 - K1) + m_deltaK) / dKdU;
2571 const Real dKdU = std::log(K2 / K1) / (U2 - U1);
2573 nextVoltage = U1 + std::log((K2 + m_deltaK) / K1) / dKdU;
2580 curVoltage = std::min(nextVoltage, curVoltage * m_relativeDeltaU);
2581 curIter = curIter + 1;
2583 if (!m_fullIntegration && (std::abs(curMaxK - m_inceptionK) <= 1E-3)) {
2589 m_voltageSweeps.resize(0);
2590 for (
int i = 0; i < m_KPlusValues.size(); i++) {
2591 m_voltageSweeps.push_back(std::get<0>(m_KPlusValues[i]));
2595template <
typename P,
typename F,
typename C>
2599 CH_TIME(
"DischargeInceptionStepper::computeInceptionIntegralTransient");
2600 if (m_verbosity > 5) {
2601 pout() <<
"DischargeInceptionStepper::computeInceptionIntegralTransient" << endl;
2605 switch (m_inceptionAlgorithm) {
2606 case IntegrationAlgorithm::Euler: {
2607 this->inceptionIntegrateEuler(a_voltage);
2611 case IntegrationAlgorithm::Trapezoidal: {
2612 this->inceptionIntegrateTrapezoidal(a_voltage);
2617 MayDay::Error(
"DischargeInceptionStepper::computeInceptionIntegralTransient - logic bust");
2624 m_tracerParticleSolver->deposit(m_inceptionIntegral);
2626 m_amr->conservativeAverage(m_inceptionIntegral, m_realm, m_phase);
2627 m_amr->interpGhost(m_inceptionIntegral, m_realm, m_phase);
2630template <
typename P,
typename F,
typename C>
2634 CH_TIME(
"DischargeInceptionStepper::inceptionIntegrateEuler");
2635 if (m_verbosity > 5) {
2636 pout() <<
"DischargeInceptionStepper::inceptionIntegrateEuler" << endl;
2639 const RealVect probLo = m_amr->getProbLo();
2640 const RealVect probHi = m_amr->getProbHi();
2646 m_amr->allocate(amrProcessedParticles, m_realm);
2650 m_tracerParticleSolver->remap();
2652 size_t particlesBefore = 0;
2659 EBAMRCellData scratch;
2660 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
2661 this->superposition(scratch, a_voltage);
2664 m_tracerParticleSolver->setVelocity(scratch);
2665 m_tracerParticleSolver->interpolateVelocities();
2669 this->interpolateGradAlphaToParticles();
2672 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2673 const Real dx = m_amr->getDx()[lvl];
2675 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2676 const DataIterator& dit = dbl.dataIterator();
2678 const int nbox = dit.size();
2680#pragma omp parallel for schedule(runtime)
2681 for (
int mybox = 0; mybox < nbox; mybox++) {
2682 const DataIndex& din = dit[mybox];
2690 double*
const pos[SpaceDim] = {
2692 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
2693 solverLeaf.template column<&P::v_y>(),
2694 solverLeaf.template column<&P::v_z>())};
2695 const ParticleReal*
const ga[SpaceDim] = {D_DECL(solverLeaf.template column<&P::ga_x>(),
2696 solverLeaf.template column<&P::ga_y>(),
2697 solverLeaf.template column<&P::ga_z>())};
2700 while (i < solverLeaf.
size()) {
2701 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
2702 const RealVect vec(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
2703 const Real v = vec.vectorLength();
2705 const Real alpha = m_alpha(E, x);
2706 const Real eta = m_eta(E, x);
2707 const Real alphaEff = alpha - eta;
2708 const Real tol = 1E-10;
2709 const Real gradAlpha = tol + RealVect(D_DECL(ga[0][i], ga[1][i], ga[2][i])).vectorLength();
2713 deltaX = std::min(m_alphaDx / (tol + std::abs(alphaEff)), m_gradAlphaDx * std::abs(alphaEff / gradAlpha));
2714 deltaX = std::max(deltaX, m_minGridDx * dx);
2715 deltaX = std::min(deltaX, m_maxGridDx * dx);
2716 deltaX = std::min(deltaX, m_maxPhysDx);
2717 deltaX = std::max(deltaX, m_minPhysDx);
2719 const Real dt = deltaX / v;
2720 const RealVect newPos = x + dt * vec;
2721 const Real delta = (newPos - x).vectorLength();
2723 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
2724 const bool insideEB = this->particleInsideEB(newPos);
2728 if (alphaEff < 0.0) {
2732 else if (insideEB) {
2734 const RefCountedPtr<BaseIF>& impFunc = m_amr->getBaseImplicitFunction(m_phase);
2737 w[i] = w[i] + s * delta * alphaEff;
2743 else if (outsideDomain) {
2745 w[i] = w[i] + s * delta * alphaEff;
2752 for (
int dir = 0; dir < SpaceDim; dir++) {
2753 pos[dir][i] = newPos[dir];
2755 w[i] = w[i] + deltaX * alphaEff;
2762 if (!m_fullIntegration) {
2764 while (j < solverLeaf.
size()) {
2765 if (w[j] >= m_inceptionK) {
2778 m_tracerParticleSolver->remap();
2779 m_tracerParticleSolver->interpolateVelocities();
2785 if (!m_fullIntegration) {
2786 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2787 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2788 const DataIterator& dit = dbl.dataIterator();
2790 const int nbox = dit.size();
2792#pragma omp parallel for schedule(runtime)
2793 for (
int mybox = 0; mybox < nbox; mybox++) {
2794 const DataIndex& din = dit[mybox];
2801 w[i] = std::min(m_inceptionK, w[i]);
2807 this->rewindTracerParticles();
2809 size_t particlesAfter = 0;
2815 if (particlesBefore != particlesAfter) {
2816 MayDay::Warning(
"DischargeInceptionStepper::inceptionIntegrateEuler - lost/gained particles!");
2820template <
typename P,
typename F,
typename C>
2824 CH_TIME(
"DischargeInceptionStepper::inceptionIntegrateTrapezoidal");
2825 if (m_verbosity > 5) {
2826 pout() <<
"DischargeInceptionStepper::inceptionIntegrateTrapezoidal" << endl;
2841 const RealVect probLo = m_amr->getProbLo();
2842 const RealVect probHi = m_amr->getProbHi();
2848 m_amr->allocate(amrProcessedParticles, m_realm);
2852 m_tracerParticleSolver->remap();
2854 size_t particlesBefore = 0;
2861 EBAMRCellData scratch;
2862 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
2863 this->superposition(scratch, a_voltage);
2866 m_tracerParticleSolver->setVelocity(scratch);
2867 m_tracerParticleSolver->interpolateVelocities();
2871 this->interpolateGradAlphaToParticles();
2874 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2875 const Real dx = m_amr->getDx()[lvl];
2877 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2878 const DataIterator& dit = dbl.dataIterator();
2880 const int nbox = dit.size();
2882#pragma omp parallel for schedule(runtime)
2883 for (
int mybox = 0; mybox < nbox; mybox++) {
2884 const DataIndex& din = dit[mybox];
2890 double*
const pos[SpaceDim] = {
2892 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
2893 solverLeaf.template column<&P::v_y>(),
2894 solverLeaf.template column<&P::v_z>())};
2895 const ParticleReal*
const ga[SpaceDim] = {D_DECL(solverLeaf.template column<&P::ga_x>(),
2896 solverLeaf.template column<&P::ga_y>(),
2897 solverLeaf.template column<&P::ga_z>())};
2898 ParticleReal*
const vk[SpaceDim] = {D_DECL(solverLeaf.template column<&P::vk_x>(),
2899 solverLeaf.template column<&P::vk_y>(),
2900 solverLeaf.template column<&P::vk_z>())};
2901 ParticleReal*
const alphaEffCol = solverLeaf.template column<&P::alphaEff>();
2902 ParticleReal*
const dtCol = solverLeaf.template column<&P::dtStep>();
2905 while (i < solverLeaf.
size()) {
2906 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
2907 const RealVect vec(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
2908 const Real v = vec.vectorLength();
2910 const Real alpha = m_alpha(E, x);
2911 const Real eta = m_eta(E, x);
2912 const Real alphaEff = alpha - eta;
2913 const Real tol = 1E-10;
2914 const Real gradAlpha = tol + RealVect(D_DECL(ga[0][i], ga[1][i], ga[2][i])).vectorLength();
2918 deltaX = std::min(m_alphaDx / (tol + std::abs(alphaEff)), m_gradAlphaDx * std::abs(alphaEff / gradAlpha));
2919 deltaX = std::max(deltaX, m_minGridDx * dx);
2920 deltaX = std::min(deltaX, m_maxGridDx * dx);
2921 deltaX = std::min(deltaX, m_maxPhysDx);
2922 deltaX = std::max(deltaX, m_minPhysDx);
2924 const Real dt = deltaX / v;
2925 const RealVect newPos = x + dt * vec;
2926 const Real delta = (newPos - x).vectorLength();
2928 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
2929 const bool insideEB = this->particleInsideEB(newPos);
2934 if (alphaEff < 0.0) {
2938 else if (insideEB) {
2939 const RefCountedPtr<BaseIF>& impFunc = m_amr->getBaseImplicitFunction(m_phase);
2942 w[i] = w[i] + s * delta * alphaEff;
2948 else if (outsideDomain) {
2950 w[i] = w[i] + s * delta * alphaEff;
2958 alphaEffCol[i] = alphaEff;
2960 for (
int dir = 0; dir < SpaceDim; dir++) {
2961 vk[dir][i] = vec[dir];
2962 pos[dir][i] = newPos[dir];
2972 m_tracerParticleSolver->remap();
2973 m_tracerParticleSolver->interpolateVelocities();
2976 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
2977 const Real dx = m_amr->getDx()[lvl];
2979 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
2980 const DataIterator& dit = dbl.dataIterator();
2982 const int nbox = dit.size();
2984#pragma omp parallel for schedule(runtime)
2985 for (
int mybox = 0; mybox < nbox; mybox++) {
2986 const DataIndex& din = dit[mybox];
2992 double*
const pos[SpaceDim] = {
2994 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
2995 solverLeaf.template column<&P::v_y>(),
2996 solverLeaf.template column<&P::v_z>())};
2997 const ParticleReal*
const vk[SpaceDim] = {D_DECL(solverLeaf.template column<&P::vk_x>(),
2998 solverLeaf.template column<&P::vk_y>(),
2999 solverLeaf.template column<&P::vk_z>())};
3000 const ParticleReal*
const alphaEffCol = solverLeaf.template column<&P::alphaEff>();
3001 const ParticleReal*
const dtCol = solverLeaf.template column<&P::dtStep>();
3004 while (i < solverLeaf.
size()) {
3005 const Real dt = dtCol[i];
3006 const RealVect vkv(D_DECL(vk[0][i], vk[1][i], vk[2][i]));
3007 const RealVect vk1(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
3008 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
3009 const Real E = vk1.vectorLength();
3012 const RealVect oldPos = x - dt * vkv;
3013 const RealVect newPos = oldPos + 0.5 * dt * (vkv + vk1);
3016 const Real alphak = alphaEffCol[i];
3017 const Real alphak1 = m_alpha(E, x) - m_eta(E, x);
3018 const Real delta = (newPos - oldPos).vectorLength();
3022 const bool negativeAlpha = (alphak + alphak1) < 0.0;
3023 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
3024 const bool insideEB = this->particleInsideEB(newPos);
3029 if (negativeAlpha) {
3033 else if (insideEB) {
3034 const RefCountedPtr<BaseIF>& impFunc = m_amr->getBaseImplicitFunction(m_phase);
3037 w[i] = w[i] + s * delta * alphak;
3043 else if (outsideDomain) {
3045 w[i] = w[i] + s * delta * alphak;
3052 for (
int dir = 0; dir < SpaceDim; dir++) {
3053 pos[dir][i] = newPos[dir];
3055 w[i] = w[i] + 0.5 * delta * (alphak + alphak1);
3062 if (!m_fullIntegration) {
3064 while (j < solverLeaf.
size()) {
3065 if (w[j] >= m_inceptionK) {
3078 m_tracerParticleSolver->remap();
3079 m_tracerParticleSolver->interpolateVelocities();
3086 if (!m_fullIntegration) {
3087 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3088 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3089 const DataIterator& dit = dbl.dataIterator();
3091 const int nbox = dit.size();
3093#pragma omp parallel for schedule(runtime)
3094 for (
int mybox = 0; mybox < nbox; mybox++) {
3095 const DataIndex& din = dit[mybox];
3102 w[i] = std::min(m_inceptionK, w[i]);
3108 this->rewindTracerParticles();
3111template <
typename P,
typename F,
typename C>
3115 CH_TIME(
"DischargeInceptionStepper::computeTownsendCriterionStationary");
3116 if (m_verbosity > 5) {
3117 pout() <<
"DischargeInceptionStepper::computeTownsendCriterionStationary" << endl;
3120 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
3122 m_townsendCriterionPlus.resize(0);
3123 m_townsendCriterionMinu.resize(0);
3125 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
3126 const Real voltage = m_voltageSweeps[i];
3128 const EBAMRCellData KPlus = m_inceptionIntegralPlus[i];
3129 const EBAMRCellData KMinu = m_inceptionIntegralMinu[i];
3131 EBAMRCellData townsendCriterionPlus;
3132 EBAMRCellData townsendCriterionMinu;
3134 EBAMRCellData expKPlus;
3135 EBAMRCellData expKMinu;
3137 m_amr->allocate(townsendCriterionPlus, m_realm, m_phase, 1);
3138 m_amr->allocate(townsendCriterionMinu, m_realm, m_phase, 1);
3140 m_amr->allocate(expKPlus, m_realm, m_phase, 1);
3141 m_amr->allocate(expKMinu, m_realm, m_phase, 1);
3149 Real maxTPlus = 0.0;
3150 Real maxTMinu = 0.0;
3152 RealVect maxTPlusPos = RealVect::Zero;
3153 RealVect maxTMinuPos = RealVect::Zero;
3155 if (m_evaluateTownsend) {
3158 this->resetTracerParticles();
3160 switch (m_inceptionAlgorithm) {
3161 case IntegrationAlgorithm::Euler: {
3162 this->townsendTrackEuler(voltage);
3166 case IntegrationAlgorithm::Trapezoidal: {
3167 this->townsendTrackTrapezoidal(voltage);
3172 MayDay::Error(
"DischargeInceptionStepper::computeTownsendCriterionStationary -- logic bust");
3178 m_tracerParticleSolver->deposit(townsendCriterionPlus);
3180 m_amr->conservativeAverage(townsendCriterionPlus, m_realm, m_phase);
3181 m_amr->interpGhost(townsendCriterionPlus, m_realm, m_phase);
3184 this->resetTracerParticles();
3186 switch (m_inceptionAlgorithm) {
3187 case IntegrationAlgorithm::Euler: {
3188 this->townsendTrackEuler(-voltage);
3192 case IntegrationAlgorithm::Trapezoidal: {
3193 this->townsendTrackTrapezoidal(-voltage);
3198 MayDay::Error(
"DischargeInceptionStepper::computeTownsendCriterionStationary -- logic bust");
3204 m_tracerParticleSolver->deposit(townsendCriterionMinu);
3206 m_amr->conservativeAverage(townsendCriterionMinu, m_realm, m_phase);
3207 m_amr->interpGhost(townsendCriterionMinu, m_realm, m_phase);
3210 auto exponentiate = [](
const Real x) -> Real {
3211 return x > 0.0 ? exp(x) - 1 : 0.0;
3217 DataOps::compute(expKPlus, exponentiate, m_amr->getMultiCutVofIterator(m_realm, m_phase));
3218 DataOps::compute(expKMinu, exponentiate, m_amr->getMultiCutVofIterator(m_realm, m_phase));
3223 this->getMaxValueAndLocation(maxTPlus, maxTPlusPos, townsendCriterionPlus);
3224 this->getMaxValueAndLocation(maxTMinu, maxTMinuPos, townsendCriterionMinu);
3227 if (!m_fullIntegration) {
3228 auto truncate = [](
const Real x) -> Real {
3229 return std::min(x, 1.0);
3232 DataOps::compute(townsendCriterionPlus, truncate, m_amr->getMultiCutVofIterator(m_realm, m_phase));
3233 DataOps::compute(townsendCriterionMinu, truncate, m_amr->getMultiCutVofIterator(m_realm, m_phase));
3237 m_townsendCriterionPlus.push_back(townsendCriterionPlus);
3238 m_townsendCriterionMinu.push_back(townsendCriterionMinu);
3240 m_TPlusValues.emplace_back(std::make_tuple(voltage, maxTPlus, maxTPlusPos));
3241 m_TMinuValues.emplace_back(std::make_tuple(voltage, maxTMinu, maxTMinuPos));
3245template <
typename P,
typename F,
typename C>
3249 CH_TIME(
"DischargeInceptionStepper::computeTownsendCriterionTransient");
3250 if (m_verbosity > 5) {
3251 pout() <<
"DischargeInceptionStepper::computeTownsendCriterionTransient" << endl;
3255 switch (m_inceptionAlgorithm) {
3256 case IntegrationAlgorithm::Euler: {
3257 this->townsendTrackEuler(a_voltage);
3261 case IntegrationAlgorithm::Trapezoidal: {
3262 this->townsendTrackTrapezoidal(a_voltage);
3267 MayDay::Error(
"DischargeInceptionStepper::computeTownsendCriterionTransient - logic bust");
3274 EBAMRCellData gamma;
3275 m_amr->allocate(gamma, m_realm, m_phase, 1);
3277 m_tracerParticleSolver->deposit(gamma);
3280 auto exponentiate = [](
const Real x) -> Real {
3281 return x > 0.0 ? exp(x) - 1 : 0.0;
3284 DataOps::compute(m_townsendCriterion, exponentiate, m_amr->getMultiCutVofIterator(m_realm, m_phase));
3288 if (!m_fullIntegration) {
3290 m_townsendCriterion,
3292 return std::min(x, 1.0);
3294 m_amr->getMultiCutVofIterator(m_realm, m_phase));
3297 m_amr->conservativeAverage(m_townsendCriterion, m_realm, m_phase);
3298 m_amr->interpGhost(m_townsendCriterion, m_realm, m_phase);
3301template <
typename P,
typename F,
typename C>
3305 CH_TIME(
"DischargeInceptionStepper::townsendTrackEuler");
3306 if (m_verbosity > 5) {
3307 pout() <<
"DischargeInceptionStepper::townsendTrackEuler" << endl;
3309 const RealVect probLo = m_amr->getProbLo();
3310 const RealVect probHi = m_amr->getProbHi();
3316 m_amr->allocate(amrProcessedParticles, m_realm);
3320 m_tracerParticleSolver->remap();
3322 size_t particlesBefore = 0;
3329 EBAMRCellData scratch;
3330 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
3331 this->superposition(scratch, a_voltage);
3333 m_tracerParticleSolver->setVelocity(scratch);
3334 m_tracerParticleSolver->interpolateVelocities();
3339 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3340 const Real dx = m_amr->getDx()[lvl];
3343 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3344 const DataIterator& dit = dbl.dataIterator();
3346 const int nbox = dit.size();
3348#pragma omp parallel for schedule(runtime)
3349 for (
int mybox = 0; mybox < nbox; mybox++) {
3350 const DataIndex& din = dit[mybox];
3356 double*
const pos[SpaceDim] = {
3358 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
3359 solverLeaf.template column<&P::v_y>(),
3360 solverLeaf.template column<&P::v_z>())};
3363 while (i < solverLeaf.
size()) {
3364 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
3365 const RealVect vec(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
3366 const Real v = vec.vectorLength();
3368 const Real deltaX = m_townsendGridDx * dx;
3369 const Real dt = deltaX / v;
3370 const RealVect newPos = x + dt * vec;
3372 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
3373 const bool insideEB = this->particleInsideEB(newPos);
3376 const Real alpha = m_alpha(E, x);
3377 const Real eta = m_eta(E, x);
3378 const Real alphaEff = alpha - eta;
3379 const bool negativeAlpha = alphaEff <= 0.0;
3384 w[i] = m_secondaryEmission(E, x);
3389 else if (outsideDomain || negativeAlpha) {
3394 for (
int dir = 0; dir < SpaceDim; dir++) {
3395 pos[dir][i] = newPos[dir];
3405 m_tracerParticleSolver->remap();
3406 m_tracerParticleSolver->interpolateVelocities();
3411 this->rewindTracerParticles();
3413 size_t particlesAfter = 0;
3419 if (particlesBefore != particlesAfter) {
3420 MayDay::Warning(
"DischargeInceptionStepper::townsendTrackEuler - lost/gained particles!");
3424template <
typename P,
typename F,
typename C>
3428 CH_TIME(
"DischargeInceptionStepper::townsendTrackTrapezoidal");
3429 if (m_verbosity > 5) {
3430 pout() <<
"DischargeInceptionStepper::townsendTrackTrapezoidal" << endl;
3439 const RealVect probLo = m_amr->getProbLo();
3440 const RealVect probHi = m_amr->getProbHi();
3446 m_amr->allocate(amrProcessedParticles, m_realm);
3450 m_tracerParticleSolver->remap();
3452 size_t particlesBefore = 0;
3459 EBAMRCellData scratch;
3460 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
3461 this->superposition(scratch, a_voltage);
3463 m_tracerParticleSolver->setVelocity(scratch);
3464 m_tracerParticleSolver->interpolateVelocities();
3469 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3470 const Real dx = m_amr->getDx()[lvl];
3473 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3474 const DataIterator& dit = dbl.dataIterator();
3476 const int nbox = dit.size();
3478#pragma omp parallel for schedule(runtime)
3479 for (
int mybox = 0; mybox < nbox; mybox++) {
3480 const DataIndex& din = dit[mybox];
3486 double*
const pos[SpaceDim] = {
3488 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
3489 solverLeaf.template column<&P::v_y>(),
3490 solverLeaf.template column<&P::v_z>())};
3491 ParticleReal*
const vk[SpaceDim] = {D_DECL(solverLeaf.template column<&P::vk_x>(),
3492 solverLeaf.template column<&P::vk_y>(),
3493 solverLeaf.template column<&P::vk_z>())};
3494 ParticleReal*
const alphaEffCol = solverLeaf.template column<&P::alphaEff>();
3495 ParticleReal*
const dtCol = solverLeaf.template column<&P::dtStep>();
3498 while (i < solverLeaf.
size()) {
3499 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
3500 const RealVect vec(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
3501 const Real v = vec.vectorLength();
3503 const Real alpha = m_alpha(E, x);
3504 const Real eta = m_eta(E, x);
3505 const Real alphaEff = alpha - eta;
3508 const Real deltaX = m_townsendGridDx * dx;
3509 const Real dt = deltaX / v;
3510 const RealVect newPos = x + vec * dt;
3512 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
3513 const bool insideEB = this->particleInsideEB(newPos);
3516 w[i] = m_secondaryEmission(E, x);
3521 else if (alphaEff < 0.0) {
3525 else if (outsideDomain) {
3531 alphaEffCol[i] = alphaEff;
3533 for (
int dir = 0; dir < SpaceDim; dir++) {
3534 vk[dir][i] = vec[dir];
3535 pos[dir][i] = newPos[dir];
3545 m_tracerParticleSolver->remap();
3546 m_tracerParticleSolver->interpolateVelocities();
3549 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3550 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3551 const DataIterator& dit = dbl.dataIterator();
3553 const int nbox = dit.size();
3555#pragma omp parallel for schedule(runtime)
3556 for (
int mybox = 0; mybox < nbox; mybox++) {
3557 const DataIndex& din = dit[mybox];
3563 double*
const pos[SpaceDim] = {
3565 const ParticleReal*
const vel[SpaceDim] = {D_DECL(solverLeaf.template column<&P::v_x>(),
3566 solverLeaf.template column<&P::v_y>(),
3567 solverLeaf.template column<&P::v_z>())};
3568 const ParticleReal*
const vk[SpaceDim] = {D_DECL(solverLeaf.template column<&P::vk_x>(),
3569 solverLeaf.template column<&P::vk_y>(),
3570 solverLeaf.template column<&P::vk_z>())};
3571 const ParticleReal*
const alphaEffCol = solverLeaf.template column<&P::alphaEff>();
3572 const ParticleReal*
const dtCol = solverLeaf.template column<&P::dtStep>();
3575 while (i < solverLeaf.
size()) {
3576 const Real dt = dtCol[i];
3577 const RealVect vkv(D_DECL(vk[0][i], vk[1][i], vk[2][i]));
3578 const RealVect vk1(D_DECL(vel[0][i], vel[1][i], vel[2][i]));
3579 const RealVect x(D_DECL(pos[0][i], pos[1][i], pos[2][i]));
3580 const Real E = vk1.vectorLength();
3583 const RealVect oldPos = x - dt * vkv;
3584 const RealVect newPos = x + 0.5 * dt * (vk1 - vkv);
3587 const Real alphak = alphaEffCol[i];
3588 const Real alphak1 = m_alpha(E, x) - m_eta(E, x);
3592 const bool negativeAlpha = (alphak + alphak1) < 0.0;
3593 const bool outsideDomain = this->particleOutsideGrid(newPos, probLo, probHi);
3594 const bool insideEB = this->particleInsideEB(newPos);
3597 (void)negativeAlpha;
3600 w[i] = m_secondaryEmission(E, oldPos);
3605 else if (outsideDomain) {
3610 for (
int dir = 0; dir < SpaceDim; dir++) {
3611 pos[dir][i] = newPos[dir];
3621 m_tracerParticleSolver->remap();
3622 m_tracerParticleSolver->interpolateVelocities();
3628 this->rewindTracerParticles();
3630 size_t particlesAfter = 0;
3636 if (particlesBefore != particlesAfter) {
3637 MayDay::Warning(
"DischargeInceptionStepper::townsendTrackTrapezoidal - lost/gained particles!");
3641template <
typename P,
typename F,
typename C>
3645 CH_TIME(
"DischargeInceptionStepper::computeRdot");
3646 if (m_verbosity > 5) {
3647 pout() <<
"DischargeInceptionStepper::computeRdot" << endl;
3654 const RealVect probLo = m_amr->getProbLo();
3657 EBAMRCellData scratch;
3658 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
3659 this->superposition(scratch, a_voltage);
3661 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3662 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3663 const DataIterator& dit = dbl.dataIterator();
3664 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
3665 const Real dx = m_amr->getDx()[lvl];
3667 const Real vol = std::pow(dx, SpaceDim);
3668 const Real area = std::pow(dx, SpaceDim - 1);
3670 const int nbox = dit.size();
3672#pragma omp parallel for schedule(runtime) reduction(+ : Rdot)
3673 for (
int mybox = 0; mybox < nbox; mybox++) {
3674 const DataIndex& din = dit[mybox];
3676 const EBISBox& ebisbox = ebisl[din];
3677 const BaseFab<bool>& validCells = (*m_amr->getValidCells(m_realm)[lvl])[din];
3679 const EBCellFAB& electricField = (*scratch[lvl])[din];
3680 const EBCellFAB& inceptionIntegral = (*m_inceptionIntegral[lvl])[din];
3681 const EBCellFAB& fieldEmission = (*m_emissionRate[lvl])[din];
3682 const EBCellFAB& ionDensity = (*m_ionSolver->getPhi()[lvl])[din];
3684 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
3685 const FArrayBox& inceptionIntegralReg = inceptionIntegral.getFArrayBox();
3686 const FArrayBox& ionDensityReg = ionDensity.getFArrayBox();
3689 auto regularKernel = [&](
const IntVect& iv) ->
void {
3690 if (ebisbox.isRegular(iv) && validCells(iv, 0)) {
3691 if (inceptionIntegralReg(iv, 0) >= m_inceptionK) {
3692 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv)) * dx;
3693 const RealVect EE = RealVect(
3694 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
3695 const Real E = EE.vectorLength();
3697 const Real alpha = m_alpha(E, pos);
3698 const Real eta = m_eta(E, pos);
3699 const Real k = m_detachmentRate(E, pos);
3700 const Real dndt = m_backgroundRate(E, pos) + k * ionDensityReg(iv, 0);
3702 CH_assert(alpha >= eta);
3704 Rdot += dndt * (1.0 - eta / alpha) * vol;
3710 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
3711 const IntVect iv = vof.gridIndex();
3712 if (ebisbox.isIrregular(iv) && validCells(iv, 0)) {
3713 if (inceptionIntegral(vof, 0) >= m_inceptionK) {
3714 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
3715 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
3716 const Real E = EE.vectorLength();
3718 const Real kappa = ebisbox.volFrac(vof);
3719 const Real areaFrac = ebisbox.bndryArea(vof);
3720 const Real alpha = m_alpha(E, pos);
3721 const Real eta = m_eta(E, pos);
3722 const Real k = m_detachmentRate(E, pos);
3723 const Real j = m_fieldEmission(E, pos);
3724 const Real dndt = m_backgroundRate(E, pos) + k * ionDensity(vof, 0);
3726 Rdot += dndt * (1.0 - eta / alpha) * kappa * vol;
3727 Rdot += j /
Units::Qe * areaFrac * area;
3734 Box cellBox = dbl[din];
3735 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
3737 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
3745template <
typename P,
typename F,
typename C>
3749 CH_TIME(
"DischargeInceptionStepper::rewindTracerParticles");
3750 if (m_verbosity > 5) {
3751 pout() <<
"DischargeInceptionStepper::rewindTracerParticles" << endl;
3756 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3757 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3758 const DataIterator& dit = dbl.dataIterator();
3760 const int nbox = dit.size();
3762#pragma omp parallel for schedule(runtime)
3763 for (
int mybox = 0; mybox < nbox; mybox++) {
3764 const DataIndex& din = dit[mybox];
3769 const double*
const x0[SpaceDim] = {
3770 D_DECL(leaf.template column<&P::x0_x>(), leaf.template column<&P::x0_y>(), leaf.template column<&P::x0_z>())};
3773 for (
int dir = 0; dir < SpaceDim; dir++) {
3774 pos[dir][i] = x0[dir][i];
3780 amrParticles.
remap();
3783template <
typename P,
typename F,
typename C>
3787 CH_TIME(
"DischargeInceptionStepper::resetTracerParticles");
3788 if (m_verbosity > 5) {
3789 pout() <<
"DischargeInceptionStepper::resetTracerParticles" << endl;
3794 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3795 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3796 const DataIterator& dit = dbl.dataIterator();
3798 const int nbox = dit.size();
3800#pragma omp parallel for schedule(runtime)
3801 for (
int mybox = 0; mybox < nbox; mybox++) {
3802 const DataIndex& din = dit[mybox];
3815template <
typename P,
typename F,
typename C>
3819 CH_TIME(
"DischargeInceptionStepper::computeBackgroundIonizationStationary");
3820 if (m_verbosity > 5) {
3821 pout() <<
"DischargeInceptionStepper::computeBackgroundIonizationStationary" << endl;
3824 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
3825 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
3826 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
3828 m_backgroundIonizationStationary.resize(0);
3831 EBAMRCellData scratch;
3832 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
3835 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
3836 const Real voltage = m_voltageSweeps[i];
3839 this->superposition(scratch, voltage);
3841 EBAMRCellData backgroundRate;
3843 m_amr->allocate(backgroundRate, m_realm, m_phase, 1);
3845 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3846 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3847 const DataIterator& dit = dbl.dataIterator();
3848 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
3849 const Real dx = m_amr->getDx()[lvl];
3850 const RealVect probLo = m_amr->getProbLo();
3852 const int nbox = dit.size();
3854#pragma omp parallel for schedule(runtime)
3855 for (
int mybox = 0; mybox < nbox; mybox++) {
3856 const DataIndex& din = dit[mybox];
3858 const EBISBox& ebisbox = ebisl[din];
3860 EBCellFAB& bgIonization = (*backgroundRate[lvl])[din];
3861 FArrayBox& bgIonizationReg = bgIonization.getFArrayBox();
3863 const EBCellFAB& electricField = (*scratch[lvl])[din];
3864 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
3866 auto regularKernel = [&](
const IntVect& iv) ->
void {
3867 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv)) * dx;
3868 const RealVect EE = RealVect(
3869 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
3870 const Real E = EE.vectorLength();
3872 bgIonizationReg(iv, 0) = m_backgroundRate(E, pos);
3875 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
3876 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
3877 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
3878 const Real E = EE.vectorLength();
3880 bgIonization(vof, 0) = m_backgroundRate(E, pos);
3886 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
3888 BoxLoops::loop<D_DECL(1, 1, 1)>(dbl[din], regularKernel);
3893 m_backgroundIonizationStationary.push_back(backgroundRate);
3897template <
typename P,
typename F,
typename C>
3901 CH_TIME(
"DischargeInceptionStepper::computeDetachmentStationary");
3902 if (m_verbosity > 5) {
3903 pout() <<
"DischargeInceptionStepper::computeDetachmentStationary" << endl;
3906 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
3907 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
3908 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
3910 m_detachmentStationary.resize(0);
3913 EBAMRCellData scratch;
3914 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
3917 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
3918 const Real voltage = m_voltageSweeps[i];
3921 this->superposition(scratch, voltage);
3923 EBAMRCellData detachmentRate;
3925 m_amr->allocate(detachmentRate, m_realm, m_phase, 1);
3927 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
3928 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
3929 const DataIterator& dit = dbl.dataIterator();
3930 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
3931 const Real dx = m_amr->getDx()[lvl];
3932 const RealVect probLo = m_amr->getProbLo();
3934 const int nbox = dit.size();
3936#pragma omp parallel for schedule(runtime)
3937 for (
int mybox = 0; mybox < nbox; mybox++) {
3938 const DataIndex& din = dit[mybox];
3940 const EBISBox& ebisbox = ebisl[din];
3942 EBCellFAB& detachment = (*detachmentRate[lvl])[din];
3943 FArrayBox& detachmentReg = detachment.getFArrayBox();
3945 const EBCellFAB& ionDensity = (*m_ionSolver->getPhi()[lvl])[din];
3946 const EBCellFAB& electricField = (*scratch[lvl])[din];
3948 const FArrayBox& ionDensityReg = ionDensity.getFArrayBox();
3949 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
3951 auto regularKernel = [&](
const IntVect& iv) ->
void {
3952 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv)) * dx;
3953 const RealVect EE = RealVect(
3954 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
3955 const Real E = EE.vectorLength();
3956 const Real phi = ionDensityReg(iv, 0);
3958 detachmentReg(iv, 0) = m_detachmentRate(E, pos) * phi;
3961 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
3962 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
3963 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
3964 const Real E = EE.vectorLength();
3965 const Real phi = ionDensity(vof, 0);
3967 detachment(vof, 0) = m_detachmentRate(E, pos) * phi;
3971 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
3973 BoxLoops::loop<D_DECL(1, 1, 1)>(dbl[din], regularKernel);
3978 m_amr->conservativeAverage(detachmentRate, m_realm, m_phase);
3979 m_amr->interpGhost(detachmentRate, m_realm, m_phase);
3981 m_detachmentStationary.push_back(detachmentRate);
3985template <
typename P,
typename F,
typename C>
3989 CH_TIME(
"DischargeInceptionStepper::computeFieldEmissionStationary");
3990 if (m_verbosity > 5) {
3991 pout() <<
"DischargeInceptionStepper::computeFieldEmissionStationary" << endl;
3994 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
3995 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
3996 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
3998 m_emissionRatesPlus.resize(0);
3999 m_emissionRatesMinu.resize(0);
4001 const int numVoltages = m_inceptionIntegralPlus.size();
4004 EBAMRCellData scratchPlus;
4005 EBAMRCellData scratchMinu;
4007 m_amr->allocate(scratchPlus, m_realm, m_phase, SpaceDim);
4008 m_amr->allocate(scratchMinu, m_realm, m_phase, SpaceDim);
4010 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
4011 const Real voltage = m_voltageSweeps[i];
4014 this->superposition(scratchPlus, +voltage);
4015 this->superposition(scratchMinu, -voltage);
4017 EBAMRCellData emissionRatesPlus;
4018 EBAMRCellData emissionRatesMinu;
4020 m_amr->allocate(emissionRatesPlus, m_realm, m_phase, 1);
4021 m_amr->allocate(emissionRatesMinu, m_realm, m_phase, 1);
4026 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
4027 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4028 const DataIterator& dit = dbl.dataIterator();
4029 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4030 const Real& dx = m_amr->getDx()[lvl];
4031 const RealVect probLo = m_amr->getProbLo();
4033 const int nbox = dit.size();
4035#pragma omp parallel for schedule(runtime)
4036 for (
int mybox = 0; mybox < nbox; mybox++) {
4037 const DataIndex& din = dit[mybox];
4039 const EBISBox& ebisbox = ebisl[din];
4043 EBCellFAB& emissionPlus = (*emissionRatesPlus[lvl])[din];
4044 EBCellFAB& emissionMinu = (*emissionRatesMinu[lvl])[din];
4046 emissionPlus.setVal(0.0);
4047 emissionMinu.setVal(0.0);
4049 const EBCellFAB& electricFieldPlus = (*scratchPlus[lvl])[din];
4050 const EBCellFAB& electricFieldMinu = (*scratchMinu[lvl])[din];
4052 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4053 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
4055 const RealVect Eplus = RealVect(
4056 D_DECL(electricFieldPlus(vof, 0), electricFieldPlus(vof, 1), electricFieldPlus(vof, 2)));
4057 const RealVect Eminu = RealVect(
4058 D_DECL(electricFieldMinu(vof, 0), electricFieldMinu(vof, 1), electricFieldMinu(vof, 2)));
4060 const Real normalEplus = Eplus.dotProduct(ebisbox.normal(vof));
4061 const Real normalEminu = Eminu.dotProduct(ebisbox.normal(vof));
4063 emissionPlus(vof, 0) = 0.0;
4064 emissionMinu(vof, 0) = 0.0;
4066 if (normalEplus < 0.0) {
4067 emissionPlus(vof, 0) = m_fieldEmission(Eplus.vectorLength(), pos);
4069 if (normalEminu < 0.0) {
4070 emissionMinu(vof, 0) = m_fieldEmission(Eminu.vectorLength(), pos);
4075 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4080 m_emissionRatesPlus.push_back(emissionRatesPlus);
4081 m_emissionRatesMinu.push_back(emissionRatesMinu);
4085template <
typename P,
typename F,
typename C>
4088 const Real& a_voltage)
const noexcept
4090 CH_TIME(
"DischargeInceptionStepper::computeFieldEmission");
4091 if (m_verbosity > 5) {
4092 pout() <<
"DischargeInceptionStepper::computeFieldEmission" << endl;
4095 CH_assert(a_emissionRate[0]->nComp() == 1);
4097 const RealVect probLo = m_amr->getProbLo();
4100 EBAMRCellData scratch;
4101 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
4102 this->superposition(scratch, a_voltage);
4104 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
4105 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4106 const DataIterator& dit = dbl.dataIterator();
4107 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4108 const Real dx = m_amr->getDx()[lvl];
4110 const int nbox = dit.size();
4112#pragma omp parallel for schedule(runtime)
4113 for (
int mybox = 0; mybox < nbox; mybox++) {
4114 const DataIndex& din = dit[mybox];
4116 const EBISBox& ebisbox = ebisl[din];
4120 EBCellFAB& emission = (*a_emissionRate[lvl])[din];
4122 emission.setVal(0.0);
4124 const EBCellFAB& electricField = (*scratch[lvl])[din];
4125 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
4127 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4128 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
4129 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
4130 const Real E = EE.vectorLength();
4132 if (EE.dotProduct(ebisbox.normal(vof)) > 0.0) {
4133 emission(vof, 0) = m_fieldEmission(E, pos);
4138 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4144template <
typename P,
typename F,
typename C>
4147 EBAMRCellData& a_data,
4148 const Real& a_voltage,
4149 const std::function<Real(
const Real E,
const RealVect x)>& a_func)
const noexcept
4151 CH_TIME(
"DischargeInceptionStepper::evaluateFunction");
4152 if (m_verbosity > 5) {
4153 pout() <<
"DischargeInceptionStepper::evaluateFunction" << endl;
4156 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
4157 this->evaluateFunction(*a_data[lvl], a_voltage, a_func, lvl);
4161template <
typename P,
typename F,
typename C>
4164 const Real& a_voltage,
4165 const std::function<Real(
const Real E,
const RealVect x)>& a_func,
4166 const int a_level)
const noexcept
4168 CH_TIME(
"DischargeInceptionStepper::evaluateFunction(level)");
4169 if (m_verbosity > 5) {
4170 pout() <<
"DischargeInceptionStepper::evaluateFunction(level)" << endl;
4173 CH_assert(a_level >= 0);
4174 CH_assert(a_level <= m_amr->getFinestLevel());
4177 EBAMRCellData scratch;
4178 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
4179 this->superposition(scratch, a_voltage);
4181 const RealVect probLo = m_amr->getProbLo();
4183 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[a_level];
4184 const DataIterator& dit = dbl.dataIterator();
4185 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[a_level];
4186 const Real dx = m_amr->getDx()[a_level];
4188 const int nbox = dit.size();
4190#pragma omp parallel for schedule(runtime)
4191 for (
int mybox = 0; mybox < nbox; mybox++) {
4192 const DataIndex& din = dit[mybox];
4194 const EBISBox& ebisbox = ebisl[din];
4198 EBCellFAB& data = a_data[din];
4199 FArrayBox& dataReg = data.getFArrayBox();
4203 const EBCellFAB& electricField = (*scratch[a_level])[din];
4204 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
4206 auto regularKernel = [&](
const IntVect& iv) ->
void {
4207 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv)) * dx;
4208 const RealVect EE = RealVect(D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
4209 const Real E = EE.vectorLength();
4211 dataReg(iv, 0) = a_func(E, pos);
4214 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4215 const RealVect pos = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
4216 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
4217 const Real E = EE.vectorLength();
4219 data(vof, 0) = a_func(E, pos);
4223 Box cellBox = dbl[din];
4224 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[a_level])[din];
4226 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4231template <
typename P,
typename F,
typename C>
4235 CH_TIME(
"DischargeInceptionStepper::computeInceptionVoltageVolume");
4236 if (m_verbosity > 5) {
4237 pout() <<
"DischargeInceptionStepper::computeInceptionVoltageVolume" << endl;
4243 CH_assert(m_mode == Mode::Stationary);
4245 if (m_inceptionIntegralPlus.size() < 2) {
4246 DataOps::setValue(m_inceptionVoltagePlus, std::numeric_limits<Real>::quiet_NaN());
4247 DataOps::setValue(m_inceptionVoltageMinu, std::numeric_limits<Real>::quiet_NaN());
4249 MayDay::Warning(
"DischargeInceptionStepper::computeInceptionVoltageVolume -- not enough voltages for estimating "
4250 "inception voltage");
4253 constexpr int comp = 0;
4256 auto calcUincInterp = [Kinc = this->m_inceptionK,
4257 &V = this->m_voltageSweeps](
const std::vector<Real>& K,
4258 const std::vector<Real>& T) -> std::array<Real, 3> {
4259 Real streamerInc = std::numeric_limits<Real>::quiet_NaN();
4260 Real townsendInc = std::numeric_limits<Real>::quiet_NaN();
4262 bool foundInception =
false;
4265 for (
size_t i = 0; i < K.size() - 1; i++) {
4266 if (K[i] <= Kinc && K[i + 1] > Kinc) {
4267 streamerInc = V[i] + (Kinc - K[i]) * (V[i + 1] - V[i]) / (K[i + 1] - K[i]);
4271 else if (K[i] == Kinc) {
4279 for (
size_t i = 0; i < T.size() - 1; i++) {
4280 if (T[i] <= 1.0 && T[i + 1] > 1) {
4281 townsendInc = V[i] + (1.0 - T[i]) * (V[i + 1] - V[i]) / (T[i + 1] - T[i]);
4285 else if (T[i] == 1.0) {
4294 if (std::isnan(streamerInc) && std::isnan(townsendInc)) {
4295 Uinc = std::numeric_limits<Real>::quiet_NaN();
4297 else if (std::isnan(streamerInc) && !std::isnan(townsendInc)) {
4300 else if (!std::isnan(streamerInc) && std::isnan(townsendInc)) {
4304 Uinc = std::min(streamerInc, townsendInc);
4307 return std::array<Real, 3>{Uinc, streamerInc, townsendInc};
4311 auto calcUincNoInterp = [Kinc = this->m_inceptionK,
4312 &V = this->m_voltageSweeps](
const std::vector<Real>& K,
4313 const std::vector<Real>& T) -> std::array<Real, 3> {
4314 Real streamerInc = std::numeric_limits<Real>::quiet_NaN();
4315 Real townsendInc = std::numeric_limits<Real>::quiet_NaN();
4318 for (
size_t i = 0; i < K.size() - 1; i++) {
4319 if (K[i] <= Kinc && K[i + 1] >= Kinc) {
4327 for (
size_t i = 0; i < T.size() - 1; i++) {
4328 if (T[i] <= 1.0 && T[i + 1] >= 1) {
4337 if (std::isnan(streamerInc) && std::isnan(townsendInc)) {
4338 Uinc = std::numeric_limits<Real>::quiet_NaN();
4340 else if (std::isnan(streamerInc) && !std::isnan(townsendInc)) {
4343 else if (!std::isnan(streamerInc) && std::isnan(townsendInc)) {
4347 Uinc = std::min(streamerInc, townsendInc);
4350 return std::array<Real, 3>{Uinc, streamerInc, townsendInc};
4354 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4355 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4356 const DataIterator& dit = dbl.dataIterator();
4358 const int nbox = dit.size();
4360#pragma omp parallel for schedule(runtime)
4361 for (
int mybox = 0; mybox < nbox; mybox++) {
4362 const DataIndex& din = dit[mybox];
4364 EBCellFAB& inceptionVoltagePlus = (*m_inceptionVoltagePlus[lvl])[din];
4365 EBCellFAB& inceptionVoltageMinu = (*m_inceptionVoltageMinu[lvl])[din];
4366 EBCellFAB& streamerInceptionVoltagePlus = (*m_streamerInceptionVoltagePlus[lvl])[din];
4367 EBCellFAB& streamerInceptionVoltageMinu = (*m_streamerInceptionVoltageMinu[lvl])[din];
4368 EBCellFAB& townsendInceptionVoltagePlus = (*m_townsendInceptionVoltagePlus[lvl])[din];
4369 EBCellFAB& townsendInceptionVoltageMinu = (*m_townsendInceptionVoltageMinu[lvl])[din];
4371 FArrayBox& inceptionVoltagePlusReg = inceptionVoltagePlus.getFArrayBox();
4372 FArrayBox& inceptionVoltageMinuReg = inceptionVoltageMinu.getFArrayBox();
4373 FArrayBox& streamerInceptionVoltagePlusReg = streamerInceptionVoltagePlus.getFArrayBox();
4374 FArrayBox& streamerInceptionVoltageMinuReg = streamerInceptionVoltageMinu.getFArrayBox();
4375 FArrayBox& townsendInceptionVoltagePlusReg = townsendInceptionVoltagePlus.getFArrayBox();
4376 FArrayBox& townsendInceptionVoltageMinuReg = townsendInceptionVoltageMinu.getFArrayBox();
4379 Vector<const EBCellFAB*> inceptionIntegralPlus;
4380 Vector<const EBCellFAB*> inceptionIntegralMinu;
4381 Vector<const EBCellFAB*> townsendCriterionPlus;
4382 Vector<const EBCellFAB*> townsendCriterionMinu;
4384 Vector<const FArrayBox*> inceptionIntegralPlusReg;
4385 Vector<const FArrayBox*> inceptionIntegralMinuReg;
4386 Vector<const FArrayBox*> townsendCriterionPlusReg;
4387 Vector<const FArrayBox*> townsendCriterionMinuReg;
4389 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
4390 inceptionIntegralPlus.push_back(&(*(m_inceptionIntegralPlus[i])[lvl])[din]);
4391 inceptionIntegralMinu.push_back(&(*(m_inceptionIntegralMinu[i])[lvl])[din]);
4392 townsendCriterionPlus.push_back(&(*(m_townsendCriterionPlus[i])[lvl])[din]);
4393 townsendCriterionMinu.push_back(&(*(m_townsendCriterionMinu[i])[lvl])[din]);
4395 inceptionIntegralPlusReg.push_back(&(inceptionIntegralPlus.back()->getFArrayBox()));
4396 inceptionIntegralMinuReg.push_back(&(inceptionIntegralMinu.back()->getFArrayBox()));
4397 townsendCriterionPlusReg.push_back(&(townsendCriterionPlus.back()->getFArrayBox()));
4398 townsendCriterionMinuReg.push_back(&(townsendCriterionMinu.back()->getFArrayBox()));
4402 auto regularKernel = [&](
const IntVect& iv) ->
void {
4403 std::vector<Real> Kplus;
4404 std::vector<Real> Kminu;
4406 std::vector<Real> Tplus;
4407 std::vector<Real> Tminu;
4409 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
4410 Kplus.emplace_back((*inceptionIntegralPlusReg[i])(iv, 0));
4411 Kminu.emplace_back((*inceptionIntegralMinuReg[i])(iv, 0));
4413 Tplus.emplace_back((*townsendCriterionPlusReg[i])(iv, 0));
4414 Tminu.emplace_back((*townsendCriterionMinuReg[i])(iv, 0));
4417 std::array<Real, 3> inceptionVoltagesPlus;
4418 std::array<Real, 3> inceptionVoltagesMinu;
4420 if (m_fullIntegration) {
4421 inceptionVoltagesPlus = calcUincInterp(Kplus, Tplus);
4422 inceptionVoltagesMinu = calcUincInterp(Kminu, Tminu);
4425 inceptionVoltagesPlus = calcUincNoInterp(Kplus, Tplus);
4426 inceptionVoltagesMinu = calcUincNoInterp(Kminu, Tminu);
4429 inceptionVoltagePlusReg(iv, comp) = std::get<0>(inceptionVoltagesPlus);
4430 inceptionVoltageMinuReg(iv, comp) = std::get<0>(inceptionVoltagesMinu);
4432 streamerInceptionVoltagePlusReg(iv, comp) = std::get<1>(inceptionVoltagesPlus);
4433 streamerInceptionVoltageMinuReg(iv, comp) = std::get<1>(inceptionVoltagesMinu);
4435 townsendInceptionVoltagePlusReg(iv, comp) = std::get<2>(inceptionVoltagesPlus);
4436 townsendInceptionVoltageMinuReg(iv, comp) = std::get<2>(inceptionVoltagesMinu);
4440 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4441 std::vector<Real> Kplus;
4442 std::vector<Real> Kminu;
4444 std::vector<Real> Tplus;
4445 std::vector<Real> Tminu;
4447 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
4448 Kplus.emplace_back((*inceptionIntegralPlus[i])(vof, 0));
4449 Kminu.emplace_back((*inceptionIntegralMinu[i])(vof, 0));
4451 Tplus.emplace_back((*townsendCriterionPlus[i])(vof, 0));
4452 Tminu.emplace_back((*townsendCriterionMinu[i])(vof, 0));
4455 std::array<Real, 3> inceptionVoltagesPlus;
4456 std::array<Real, 3> inceptionVoltagesMinu;
4458 if (m_fullIntegration) {
4459 inceptionVoltagesPlus = calcUincInterp(Kplus, Tplus);
4460 inceptionVoltagesMinu = calcUincInterp(Kminu, Tminu);
4463 inceptionVoltagesPlus = calcUincNoInterp(Kplus, Tplus);
4464 inceptionVoltagesMinu = calcUincNoInterp(Kminu, Tminu);
4467 inceptionVoltagePlus(vof, comp) = std::get<0>(inceptionVoltagesPlus);
4468 inceptionVoltageMinu(vof, comp) = std::get<0>(inceptionVoltagesMinu);
4470 streamerInceptionVoltagePlus(vof, comp) = std::get<1>(inceptionVoltagesPlus);
4471 streamerInceptionVoltageMinu(vof, comp) = std::get<1>(inceptionVoltagesMinu);
4473 townsendInceptionVoltagePlus(vof, comp) = std::get<2>(inceptionVoltagesPlus);
4474 townsendInceptionVoltageMinu(vof, comp) = std::get<2>(inceptionVoltagesMinu);
4478 const Box& cellBox = dbl[din];
4479 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4481 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4487 m_amr->conservativeAverage(m_inceptionVoltagePlus, m_realm, m_phase);
4488 m_amr->interpGhost(m_inceptionVoltageMinu, m_realm, m_phase);
4492template <
typename P,
typename F,
typename C>
4493std::pair<Real, RealVect>
4496 CH_TIME(
"DischargeInceptionStepper::computeMinimumInceptionVoltage");
4497 if (m_verbosity > 5) {
4498 pout() <<
"DischargeInceptionStepper::computeMinimumInceptionVoltage" << endl;
4501 const RealVect probLo = m_amr->getProbLo();
4503 std::pair<Real, RealVect> UxInc;
4505 UxInc.first = std::numeric_limits<Real>::max();
4506 UxInc.second = RealVect::Zero;
4508 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
4509 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4510 const DataIterator& dit = dbl.dataIterator();
4511 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4512 const Real& dx = m_amr->getDx()[lvl];
4514 const int nbox = dit.size();
4516#pragma omp parallel for schedule(runtime) reduction(pairmin : UxInc)
4517 for (
int mybox = 0; mybox < nbox; mybox++) {
4518 const DataIndex& din = dit[mybox];
4520 const BaseFab<bool>& validCells = (*m_amr->getValidCells(m_realm)[lvl])[din];
4521 const EBISBox& ebisBox = ebisl[din];
4523 const EBCellFAB& voltage = (*a_Uinc[lvl])[din];
4524 const FArrayBox& voltageReg = voltage.getFArrayBox();
4526 auto regularKernel = [&](
const IntVect& iv) ->
void {
4527 if (validCells(iv, 0) && ebisBox.isRegular(iv)) {
4528 const Real& U = voltageReg(iv, 0);
4529 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv)) * dx;
4531 if (!(std::isnan(U))) {
4532 if (std::abs(U) < UxInc.first) {
4533 UxInc.first = std::abs(U);
4540 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4541 const IntVect iv = vof.gridIndex();
4542 if (validCells(iv, 0) && ebisBox.isIrregular(iv)) {
4543 const Real& U = voltage(vof, 0);
4544 const RealVect centroid = ebisBox.centroid(vof);
4545 const RealVect pos = probLo + (0.5 * RealVect::Unit + RealVect(iv) + centroid) * dx;
4547 if (!(std::isnan(U))) {
4548 if (std::abs(U) < UxInc.first) {
4549 UxInc.first = std::abs(U);
4556 Box cellBox = dbl[din];
4557 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4559 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4567template <
typename P,
typename F,
typename C>
4571 CH_TIME(
"DischargeInceptionStepper::computeCriticalVolumeStationary");
4572 if (m_verbosity > 5) {
4573 pout() <<
"DischargeInceptionStepper::computeCriticalVolumeStationary" << endl;
4576 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
4577 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
4578 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
4580 m_criticalVolumePlus.resize(0);
4581 m_criticalVolumeMinu.resize(0);
4583 const int numVoltages = m_inceptionIntegralPlus.size();
4586 for (
size_t i = 0; i < numVoltages; i++) {
4587 Real criticalVolumePlus = 0.0;
4588 Real criticalVolumeMinu = 0.0;
4590 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4591 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4592 const DataIterator& dit = dbl.dataIterator();
4593 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4595 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4597 const Real dx = m_amr->getDx()[lvl];
4599 const int nbox = dit.size();
4601#pragma omp parallel for schedule(runtime) reduction(+ : criticalVolumePlus, criticalVolumeMinu)
4602 for (
int mybox = 0; mybox < nbox; mybox++) {
4603 const DataIndex& din = dit[mybox];
4605 const EBISBox& ebisbox = ebisl[din];
4606 const BaseFab<bool>& validCells = validCellsLD[din];
4608 const EBCellFAB& inceptionIntegralPlus = (*(m_inceptionIntegralPlus[i])[lvl])[din];
4609 const EBCellFAB& inceptionIntegralMinu = (*(m_inceptionIntegralMinu[i])[lvl])[din];
4611 const FArrayBox& inceptionIntegralPlusReg = inceptionIntegralPlus.getFArrayBox();
4612 const FArrayBox& inceptionIntegralMinuReg = inceptionIntegralMinu.getFArrayBox();
4614 const EBCellFAB& townsendCritPlus = (*(m_townsendCriterionPlus[i])[lvl])[din];
4615 const EBCellFAB& townsendCritMinu = (*(m_townsendCriterionMinu[i])[lvl])[din];
4617 const FArrayBox& townsendCritPlusReg = townsendCritPlus.getFArrayBox();
4618 const FArrayBox& townsendCritMinuReg = townsendCritMinu.getFArrayBox();
4620 auto regularKernel = [&](
const IntVect& iv) ->
void {
4621 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
4622 if (inceptionIntegralPlusReg(iv, 0) >= m_inceptionK || townsendCritPlusReg(iv, 0) >= 1.0) {
4623 criticalVolumePlus += std::pow(dx, SpaceDim);
4625 if (inceptionIntegralMinuReg(iv, 0) >= m_inceptionK || townsendCritMinuReg(iv, 0) >= 1.0) {
4626 criticalVolumeMinu += std::pow(dx, SpaceDim);
4631 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4632 if (validCells(vof.gridIndex())) {
4633 const Real kappa = ebisbox.volFrac(vof);
4635 if (inceptionIntegralPlus(vof, 0) >= m_inceptionK || townsendCritPlus(vof, 0) >= 1.0) {
4636 criticalVolumePlus += kappa * std::pow(dx, SpaceDim);
4638 if (inceptionIntegralMinu(vof, 0) >= m_inceptionK || townsendCritMinu(vof, 0) >= 1.0) {
4639 criticalVolumeMinu += kappa * std::pow(dx, SpaceDim);
4645 const Box cellBox = dbl[din];
4646 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4648 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4658template <
typename P,
typename F,
typename C>
4662 CH_TIME(
"DischargeInceptionStepper::computeCriticalVolumeTransient");
4663 if (m_verbosity > 5) {
4664 pout() <<
"DischargeInceptionStepper::computeCriticalVolumeTransient" << endl;
4669 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4670 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4671 const DataIterator& dit = dbl.dataIterator();
4672 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4674 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4676 const Real dx = m_amr->getDx()[lvl];
4677 const Real vol = std::pow(dx, SpaceDim);
4679 const int nbox = dit.size();
4681#pragma omp parallel for schedule(runtime) reduction(+ : Vcr)
4682 for (
int mybox = 0; mybox < nbox; mybox++) {
4683 const DataIndex& din = dit[mybox];
4685 const EBISBox& ebisbox = ebisl[din];
4686 const BaseFab<bool>& validCells = validCellsLD[din];
4688 const EBCellFAB& inceptionIntegral = (*m_inceptionIntegral[lvl])[din];
4689 const FArrayBox& inceptionIntegralReg = inceptionIntegral.getFArrayBox();
4691 const EBCellFAB& townsendCriterion = (*m_townsendCriterion[lvl])[din];
4692 const FArrayBox& townsendCriterionReg = townsendCriterion.getFArrayBox();
4694 auto regularKernel = [&](
const IntVect& iv) ->
void {
4695 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
4696 if (inceptionIntegralReg(iv, 0) >= m_inceptionK || townsendCriterionReg(iv, 0) >= 1.0) {
4702 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4703 if (validCells(vof.gridIndex())) {
4704 if (inceptionIntegral(vof, 0) >= m_inceptionK || townsendCriterion(vof, 0) >= 1.0) {
4705 Vcr += ebisbox.volFrac(vof) * vol;
4711 const Box cellBox = dbl[din];
4712 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4714 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4722template <
typename P,
typename F,
typename C>
4726 CH_TIME(
"DischargeInceptionStepper::computeCriticalAreaStationary");
4727 if (m_verbosity > 5) {
4728 pout() <<
"DischargeInceptionStepper::computeCriticalAreaStationary" << endl;
4731 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
4732 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
4733 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
4735 m_criticalAreaPlus.resize(0);
4736 m_criticalAreaMinu.resize(0);
4738 const int numVoltages = m_inceptionIntegralPlus.size();
4741 for (
size_t i = 0; i < numVoltages; i++) {
4742 Real criticalAreaPlus = 0.0;
4743 Real criticalAreaMinu = 0.0;
4745 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4746 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4747 const DataIterator& dit = dbl.dataIterator();
4748 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4750 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4752 const Real dx = m_amr->getDx()[lvl];
4754 const int nbox = dit.size();
4756#pragma omp parallel for schedule(runtime) reduction(+ : criticalAreaPlus, criticalAreaMinu)
4757 for (
int mybox = 0; mybox < nbox; mybox++) {
4758 const DataIndex& din = dit[mybox];
4760 const EBISBox& ebisbox = ebisl[din];
4761 const BaseFab<bool>& validCells = validCellsLD[din];
4763 const EBCellFAB& inceptionIntegralPlus = (*(m_inceptionIntegralPlus[i])[lvl])[din];
4764 const EBCellFAB& inceptionIntegralMinu = (*(m_inceptionIntegralMinu[i])[lvl])[din];
4766 const EBCellFAB& townsendCriterionPlus = (*(m_townsendCriterionPlus[i])[lvl])[din];
4767 const EBCellFAB& townsendCriterionMinu = (*(m_townsendCriterionMinu[i])[lvl])[din];
4769 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4770 if (validCells(vof.gridIndex())) {
4771 const Real boundaryArea = ebisbox.bndryArea(vof);
4773 if (inceptionIntegralPlus(vof, 0) >= m_inceptionK || townsendCriterionPlus(vof, 0) >= 1.0) {
4774 criticalAreaPlus += boundaryArea * std::pow(dx, SpaceDim - 1);
4776 if (inceptionIntegralMinu(vof, 0) >= m_inceptionK || townsendCriterionMinu(vof, 0) >= 1.0) {
4777 criticalAreaMinu += boundaryArea * std::pow(dx, SpaceDim - 1);
4783 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4794template <
typename P,
typename F,
typename C>
4798 CH_TIME(
"DischargeInceptionStepper::computeCriticalAreaTransient");
4799 if (m_verbosity > 5) {
4800 pout() <<
"DischargeInceptionStepper::computeCriticalAreaTransient" << endl;
4805 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4806 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4807 const DataIterator& dit = dbl.dataIterator();
4808 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4810 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4812 const Real dx = m_amr->getDx()[lvl];
4813 const Real area = std::pow(dx, SpaceDim - 1);
4815 const int nbox = dit.size();
4817#pragma omp parallel for schedule(runtime) reduction(+ : Acr)
4818 for (
int mybox = 0; mybox < nbox; mybox++) {
4819 const DataIndex& din = dit[mybox];
4821 const EBISBox& ebisbox = ebisl[din];
4822 const BaseFab<bool>& validCells = validCellsLD[din];
4824 const EBCellFAB& inceptionIntegral = (*m_inceptionIntegral[lvl])[din];
4825 const EBCellFAB& townsendCriterion = (*m_townsendCriterion[lvl])[din];
4827 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4828 if (validCells(vof.gridIndex())) {
4829 if (inceptionIntegral(vof, 0) >= m_inceptionK || townsendCriterion(vof, 0) >= 1.0) {
4830 Acr += ebisbox.bndryArea(vof) * area;
4836 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4845template <
typename P,
typename F,
typename C>
4849 CH_TIME(
"DischargeInceptionStepper::computeIonizationVolumeStationary");
4850 if (m_verbosity > 5) {
4851 pout() <<
"DischargeInceptionStepper::computeIonizationVolumeStationary" << endl;
4854 CH_assert(m_inceptionIntegralPlus.size() == m_inceptionIntegralMinu.size());
4855 CH_assert(m_inceptionIntegralPlus.size() == m_KPlusValues.size());
4856 CH_assert(m_inceptionIntegralMinu.size() == m_KMinuValues.size());
4858 m_ionizationVolume.resize(0);
4860 const int numVoltages = m_inceptionIntegralPlus.size();
4863 EBAMRCellData scratch;
4864 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
4867 for (
size_t i = 0; i < m_voltageSweeps.size(); i++) {
4868 const Real voltage = m_voltageSweeps[i];
4870 Real ionizationVolume = 0.0;
4872 this->superposition(scratch, voltage);
4874 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4875 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4876 const DataIterator& dit = dbl.dataIterator();
4877 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4879 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4881 const Real dx = m_amr->getDx()[lvl];
4882 const RealVect probLo = m_amr->getProbLo();
4884 const int nbox = dit.size();
4886#pragma omp parallel for schedule(runtime) reduction(+ : ionizationVolume)
4887 for (
int mybox = 0; mybox < nbox; mybox++) {
4888 const DataIndex& din = dit[mybox];
4890 const EBISBox& ebisbox = ebisl[din];
4891 const BaseFab<bool>& validCells = validCellsLD[din];
4893 const EBCellFAB& electricField = (*scratch[lvl])[din];
4894 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
4896 auto regularKernel = [&](
const IntVect& iv) ->
void {
4897 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
4898 const RealVect x = probLo + dx * (0.5 * RealVect::Unit + RealVect(iv));
4899 const RealVect EE = RealVect(
4900 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
4901 const Real E = EE.vectorLength();
4903 const Real alpha = m_alpha(E, x);
4904 const Real eta = m_eta(E, x);
4907 ionizationVolume += std::pow(dx, SpaceDim);
4912 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4913 if (validCells(vof.gridIndex())) {
4915 const RealVect x = probLo +
Location::position(Location::Cell::Center, vof, ebisbox, dx);
4916 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
4917 const Real E = EE.vectorLength();
4919 const Real alpha = m_alpha(E, x);
4920 const Real eta = m_eta(E, x);
4922 const Real kappa = ebisbox.volFrac(vof);
4925 ionizationVolume += kappa * std::pow(dx, SpaceDim);
4931 const Box cellBox = dbl[din];
4932 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
4934 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
4943template <
typename P,
typename F,
typename C>
4947 CH_TIME(
"DischargeInceptionStepper::computeIonizationVolumeTransient");
4948 if (m_verbosity > 5) {
4949 pout() <<
"DischargeInceptionStepper::computeIonizationVolumeTransient" << endl;
4955 EBAMRCellData scratch;
4956 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
4957 this->superposition(scratch, a_voltage);
4959 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); ++lvl) {
4960 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
4961 const DataIterator& dit = dbl.dataIterator();
4962 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
4964 const LevelData<BaseFab<bool>>& validCellsLD = *m_amr->getValidCells(m_realm)[lvl];
4966 const Real dx = m_amr->getDx()[lvl];
4967 const Real vol = std::pow(dx, SpaceDim);
4968 const RealVect probLo = m_amr->getProbLo();
4970 const int nbox = dit.size();
4972#pragma omp parallel for schedule(runtime) reduction(+ : Vion)
4973 for (
int mybox = 0; mybox < nbox; mybox++) {
4974 const DataIndex& din = dit[mybox];
4976 const EBISBox& ebisbox = ebisl[din];
4977 const BaseFab<bool>& validCells = validCellsLD[din];
4979 const EBCellFAB& electricField = (*scratch[lvl])[din];
4980 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
4982 auto regularKernel = [&](
const IntVect& iv) ->
void {
4983 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
4985 const RealVect x = probLo + dx * (0.5 * RealVect::Unit + RealVect(iv));
4986 const RealVect EE = RealVect(
4987 D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
4988 const Real E = EE.vectorLength();
4990 const Real alpha = m_alpha(E, x);
4991 const Real eta = m_eta(E, x);
4998 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
4999 if (validCells(vof.gridIndex())) {
5001 const RealVect x = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
5002 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
5003 const Real E = EE.vectorLength();
5005 const Real alpha = m_alpha(E, x);
5006 const Real eta = m_eta(E, x);
5008 Vion += ebisbox.volFrac(vof) * vol;
5014 const Box cellBox = dbl[din];
5015 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
5017 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
5025template <
typename P,
typename F,
typename C>
5029 CH_TIME(
"DischargeInceptionStepper::writeReportStationary");
5030 if (m_verbosity > 5) {
5031 pout() <<
"DischargeInceptionStepper::writeReportStationary" << endl;
5034 const auto UIncPlus = this->computeMinimumInceptionVoltage(m_inceptionVoltagePlus);
5035 const auto UIncMinu = this->computeMinimumInceptionVoltage(m_inceptionVoltageMinu);
5037 const auto streamerUIncPlus = this->computeMinimumInceptionVoltage(m_streamerInceptionVoltagePlus);
5038 const auto streamerUIncMinu = this->computeMinimumInceptionVoltage(m_streamerInceptionVoltageMinu);
5040 const auto townsendUIncPlus = this->computeMinimumInceptionVoltage(m_townsendInceptionVoltagePlus);
5041 const auto townsendUIncMinu = this->computeMinimumInceptionVoltage(m_townsendInceptionVoltageMinu);
5044 if (procID() == 0) {
5047 std::ofstream output(m_outputFile, std::ofstream::out);
5049 const int ww = (SpaceDim == 2) ? 24 : 36;
5051 const std::string lineBreak =
"# " + std::string(178 + 4 * ww,
'=');
5054 output << lineBreak <<
"\n";
5055 if (std::isnan(UIncPlus.first) || std::isnan(UIncMinu.first)) {
5056 output <<
"# Could not compute inception voltage\n";
5059 if(m_fullIntegration){
5060 output <<
"# Minimum inception voltage(+) = " << UIncPlus.first <<
",\t x = " << UIncPlus.second <<
"\n";
5061 output <<
"# Minimum inception voltage(-) = " << UIncMinu.first <<
",\t x = " << UIncMinu.second <<
"\n";
5063 output <<
"# Streamer inception voltage(+) = " << streamerUIncPlus.first <<
",\t x = " << streamerUIncPlus.second <<
"\n";
5064 output <<
"# Streamer inception voltage(-) = " << streamerUIncMinu.first <<
",\t x = " << streamerUIncMinu.second <<
"\n";
5066 output <<
"# Townsend inception voltage(+) = " << townsendUIncPlus.first <<
",\t x = " << townsendUIncPlus.second <<
"\n";
5067 output <<
"# Townsend inception voltage(-) = " << townsendUIncMinu.first <<
",\t x = " << townsendUIncMinu.second <<
"\n";
5070 output <<
"# Minimum inception voltage(+) >= " << UIncPlus.first <<
",\t x = " << UIncPlus.second <<
"\n";
5071 output <<
"# Minimum inception voltage(-) >= " << UIncMinu.first <<
",\t x = " << UIncMinu.second <<
"\n";
5073 output <<
"# Streamer inception voltage(+) >= " << streamerUIncPlus.first <<
",\t x = " << streamerUIncPlus.second <<
"\n";
5074 output <<
"# Streamer inception voltage(-) >= " << streamerUIncMinu.first <<
",\t x = " << streamerUIncMinu.second <<
"\n";
5076 output <<
"# Townsend inception voltage(+) >= " << townsendUIncPlus.first <<
",\t x = " << townsendUIncPlus.second <<
"\n";
5077 output <<
"# Townsend inception voltage(-) >= " << townsendUIncMinu.first <<
",\t x = " << townsendUIncMinu.second <<
"\n";
5081 output << lineBreak <<
"\n";
5082 output << left << setw(15) << setfill(
' ') <<
"# +/- Voltage";
5083 output << left << setw(15) << setfill(
' ') <<
"Max K(+)";
5084 output << left << setw(15) << setfill(
' ') <<
"Max K(-)";
5085 output << left << setw(ww) << setfill(
' ') <<
"Pos. max K(+)";
5086 output << left << setw(ww) << setfill(
' ') <<
"Pos. max K(-)";
5087 output << left << setw(20) << setfill(
' ') <<
"Max T(+)";
5088 output << left << setw(20) << setfill(
' ') <<
"Max T(-)";
5089 output << left << setw(ww) << setfill(
' ') <<
"Pos. max T(+)";
5090 output << left << setw(ww) << setfill(
' ') <<
"Pos. max T(-)";
5091 output << left << setw(20) << setfill(
' ') <<
"Crit. vol(+)";
5092 output << left << setw(20) << setfill(
' ') <<
"Crit. vol(-)";
5093 output << left << setw(20) << setfill(
' ') <<
"Crit. area(+)";
5094 output << left << setw(20) << setfill(
' ') <<
"Crit. area(-)";
5095 output << left << setw(20) << setfill(
' ') <<
"Ionization vol." <<
"\n";
5096 output << lineBreak <<
"\n";
5098 auto RealVectToString = [=](
const RealVect x) -> std::string {
5099 std::string ret =
"(";
5100 for (
int dir = 0; dir < SpaceDim; dir++) {
5101 ret += std::to_string(x[dir]);
5102 if(dir < SpaceDim -1) {
5112 for (
int i = 0; i < m_voltageSweeps.size(); i++) {
5113 output << left << setw(15) << setfill(
' ') << m_voltageSweeps[i];
5114 output << left << setw(15) << setfill(' ') << std::get<1>(m_KPlusValues[i]);
5115 output << left << setw(15) << setfill(' ') << std::get<1>(m_KMinuValues[i]);
5116 output << left << setw(ww) << setfill(' ') << RealVectToString(std::get<2>(m_KPlusValues[i]));
5117 output << left << setw(ww) << setfill(' ') << RealVectToString(std::get<2>(m_KMinuValues[i]));
5118 output << left << setw(20) << setfill(' ') << std::get<1>(m_TPlusValues[i]);
5119 output << left << setw(20) << setfill(' ') << std::get<1>(m_TMinuValues[i]);
5120 output << left << setw(ww) << setfill(' ') << RealVectToString(std::get<2>(m_TPlusValues[i]));
5121 output << left << setw(ww) << setfill(' ') << RealVectToString(std::get<2>(m_TMinuValues[i]));
5122 output << left << setw(20) << setfill(
' ') << m_criticalVolumePlus[i];
5123 output << left << setw(20) << setfill(
' ') << m_criticalVolumeMinu[i];
5124 output << left << setw(20) << setfill(
' ') << m_criticalAreaPlus[i];
5125 output << left << setw(20) << setfill(
' ') << m_criticalAreaMinu[i];
5126 output << left << setw(20) << setfill(
' ') << m_ionizationVolume[i];
5129 output << lineBreak <<
"\n";
5136template <
typename P,
typename F,
typename C>
5140 CH_TIME(
"DischargeInceptionStepper::writeReportTransient");
5141 if (m_verbosity > 5) {
5142 pout() <<
"DischargeInceptionStepper::writeReportTransient" << endl;
5146 if (procID() == 0) {
5148 std::ofstream output(m_outputFile, std::ofstream::out);
5150 output << std::left << std::setw(15) << setfill(
' ') <<
"# Time t";
5151 output << std::left << std::setw(15) << setfill(
' ') <<
"V(t)";
5152 output << std::left << std::setw(15) << setfill(
' ') <<
"max K(t)";
5153 output << std::left << std::setw(15) << setfill(
' ') <<
"max T(t)";
5154 output << std::left << std::setw(15) << setfill(
' ') <<
"Vcr(t)";
5155 output << std::left << std::setw(15) << setfill(
' ') <<
"Acr(t)";
5156 output << std::left << std::setw(15) << setfill(
' ') <<
"Vion(t)";
5157 output << std::left << std::setw(15) << setfill(
' ') <<
"lambda(t)";
5158 output << std::left << std::setw(15) << setfill(
' ') <<
"P(t)";
5159 output << std::left << std::setw(15) << setfill(
' ') <<
"dP(t, t+dt)";
5160 output << std::left << std::setw(15) << setfill(
' ') <<
"Time lag";
5164 std::vector<Real> dProb;
5165 for (
size_t i = 0; i < m_Rdot.size() - 1; i++) {
5166 const Real t = m_Rdot[i].first;
5167 const Real dt = m_Rdot[i + 1].first - m_Rdot[i].first;
5168 const Real prob = m_inceptionProbability[i].second;
5169 const Real Rdot = m_Rdot[i].second;
5171 dProb.emplace_back((1.0 - prob) * Rdot * dt);
5173 dProb.emplace_back(0.0);
5176 std::vector<Real> tau(m_Rdot.size(), 0.0);
5177 for (
size_t i = 0; i < m_Rdot.size() - 1; i++) {
5178 const Real t1 = m_Rdot[i].first;
5179 const Real t2 = m_Rdot[i + 1].first;
5180 const Real dt = t2 - t1;
5181 const Real prob = m_inceptionProbability[i].second;
5182 const Real lambda = m_Rdot[i].second;
5184 tau[i + 1] = tau[i] + t1 * (1 - prob) * lambda * dt;
5186 for (
int i = 0; i < tau.size(); i++) {
5187 const Real prob = m_inceptionProbability[i].second;
5189 tau[i] = prob > 0.0 ? tau[i] / prob : std::numeric_limits<Real>::infinity();
5192 for (
size_t i = 0; i < m_Rdot.size(); i++) {
5193 const Real time = m_Rdot[i].first;
5195 output << std::left << std::setw(15) << time;
5196 output << std::left << std::setw(15) << m_voltageCurve(time);
5197 output << std::left << std::setw(15) << m_maxK[i].second;
5198 output << std::left << std::setw(15) << m_maxT[i].second;
5199 output << std::left << std::setw(15) << m_criticalVolume[i].second;
5200 output << std::left << std::setw(15) << m_criticalArea[i].second;
5201 output << std::left << std::setw(15) << m_ionizationVolumeTransient[i].second;
5202 output << std::left << std::setw(15) << m_Rdot[i].second;
5203 output << std::left << std::setw(15) << m_inceptionProbability[i].second;
5204 output << std::left << std::setw(15) << dProb[i];
5205 output << std::left << std::setw(15) << tau[i];
5216template <
typename P,
typename F,
typename C>
5219 const RealVect& a_probLo,
5220 const RealVect& a_probHi)
const noexcept
5223 CH_TIME(
"DischargeInceptionStepper::particleOutsideGrid");
5224 if (m_verbosity > 5) {
5225 pout() <<
"DischargeInceptionStepper::particleOutsideGrid" << endl;
5229 bool isOutside =
false;
5231 for (
int dir = 0; dir < SpaceDim; dir++) {
5232 if (a_pos[dir] <= a_probLo[dir] || a_pos[dir] >= a_probHi[dir]) {
5240template <
typename P,
typename F,
typename C>
5245 CH_TIME(
"DischargeInceptionStepper::particleInsideEB");
5246 if (m_verbosity > 5) {
5247 pout() <<
"DischargeInceptionStepper::particleInsideEB" << endl;
5251 const RefCountedPtr<BaseIF>& implicitFunction = m_amr->getBaseImplicitFunction(m_phase);
5253 return (implicitFunction->value(a_pos) >= 0.0) ? true :
false;
5256template <
typename P,
typename F,
typename C>
5260 CH_TIME(
"DischargeInceptionStepper::computeIonVelocity");
5261 if (m_verbosity > 5) {
5262 pout() <<
"DischargeInceptionStepper::computeIonVelocity" << endl;
5265 CH_assert(!(m_ionSolver.isNull()));
5266 CH_assert(m_ionSolver->isMobile());
5268 EBAMRCellData& vel = m_ionSolver->getCellCenteredVelocity();
5271 this->superposition(vel, a_voltage);
5276 m_amr->allocate(mu, m_realm, m_phase, 1);
5278 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
5279 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
5280 const DataIterator& dit = dbl.dataIterator();
5282 const int nbox = dit.size();
5284#pragma omp parallel for schedule(runtime)
5285 for (
int mybox = 0; mybox < nbox; mybox++) {
5286 const DataIndex& din = dit[mybox];
5288 const EBCellFAB& v = (*vel[lvl])[din];
5289 const FArrayBox& vReg = v.getFArrayBox();
5291 EBCellFAB& MU = (*mu[lvl])[din];
5292 FArrayBox& MUREG = MU.getFArrayBox();
5294 auto regularKernel = [&](
const IntVect& iv) ->
void {
5295 const RealVect EE = RealVect(D_DECL(vReg(iv, 0), vReg(iv, 1), vReg(iv, 2)));
5296 const Real E = EE.vectorLength();
5298 MUREG(iv, 0) = m_ionMobility(E);
5301 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
5302 const RealVect EE = RealVect(D_DECL(v(vof, 0), v(vof, 1), v(vof, 2)));
5303 const Real E = EE.vectorLength();
5305 MU(vof, 0) = m_ionMobility(E);
5308 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
5309 Box cellBox = dbl[din];
5311 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
5318 m_amr->arithmeticAverage(vel, m_realm, m_phase);
5319 m_amr->interpGhostPwl(vel, m_realm, m_phase);
5322template <
typename P,
typename F,
typename C>
5326 CH_TIME(
"DischargeInceptionStepper::computeIonDiffusion");
5327 if (m_verbosity > 5) {
5328 pout() <<
"DischargeInceptionStepper::computeIonDiffusion" << endl;
5331 CH_assert(!(m_ionSolver.isNull()));
5332 CH_assert(m_ionSolver->isMobile());
5335 EBAMRCellData scratch;
5336 m_amr->allocate(scratch, m_realm, m_phase, SpaceDim);
5337 this->superposition(scratch, a_voltage);
5340 EBAMRCellData diffCoCell;
5341 m_amr->allocate(diffCoCell, m_realm, m_phase, 1);
5343 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
5344 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
5345 const DataIterator& dit = dbl.dataIterator();
5347 const int nbox = dit.size();
5349#pragma omp parallel for schedule(runtime)
5350 for (
int mybox = 0; mybox < nbox; mybox++) {
5351 const DataIndex& din = dit[mybox];
5353 const EBCellFAB& electricField = (*scratch[lvl])[din];
5354 const FArrayBox& electricFieldReg = electricField.getFArrayBox();
5356 EBCellFAB& dCo = (*diffCoCell[lvl])[din];
5357 FArrayBox& dCoReg = dCo.getFArrayBox();
5359 auto regularKernel = [&](
const IntVect& iv) ->
void {
5360 const RealVect EE = RealVect(D_DECL(electricFieldReg(iv, 0), electricFieldReg(iv, 1), electricFieldReg(iv, 2)));
5361 const Real E = EE.vectorLength();
5363 dCoReg(iv, 0) = m_ionDiffusion(E);
5366 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
5367 const RealVect EE = RealVect(D_DECL(electricField(vof, 0), electricField(vof, 1), electricField(vof, 2)));
5368 const Real E = EE.vectorLength();
5370 dCo(vof, 0) = m_ionDiffusion(E);
5373 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
5374 Box cellBox = dbl[din];
5376 BoxLoops::loop<D_DECL(1, 1, 1)>(cellBox, regularKernel);
5382 m_amr->arithmeticAverage(diffCoCell, m_realm, m_phase);
5383 m_amr->interpGhostPwl(diffCoCell, m_realm, m_phase);
5386 EBAMRFluxData& diffCoFace = m_ionSolver->getFaceCenteredDiffusionCoefficient();
5387 EBAMRIVData& diffCoEB = m_ionSolver->getEbCenteredDiffusionCoefficient();
5394 m_amr->getDomains(),
5398 Average::Arithmetic,
5399 m_amr->getFaceIteratorWithTangentialGhosts(m_realm, m_phase));
5402template <
typename P,
typename F,
typename C>
5405 const MFAMRCellData& a_inhomogeneousField,
5406 const MFAMRCellData& a_homogeneousField,
5407 const Real a_voltage)
const noexcept
5409 CH_TIME(
"DischargeInceptionStepper::superposition(full)");
5411 const EBAMRCellData homogeneousField = m_amr->alias(
phase::gas, a_homogeneousField);
5412 const EBAMRCellData inhomogeneousField = m_amr->alias(
phase::gas, a_inhomogeneousField);
5418 m_amr->arithmeticAverage(a_sumField, m_realm, m_phase);
5419 m_amr->interpGhostPwl(a_sumField, m_realm, m_phase);
5423template <
typename P,
typename F,
typename C>
5427 CH_TIME(
"DischargeInceptionStepper::superposition(short)");
5429 this->superposition(a_sumField, m_electricFieldInho, m_electricFieldHomo, a_voltage);
5432template <
typename P,
typename F,
typename C>
5436 const EBAMRCellData& a_data)
const noexcept
5438 CH_TIME(
"DischargeInceptionStepper::getMaxValueAndLocation");
5439 if (m_verbosity > 5) {
5440 pout() <<
"DischargeInceptionStepper::getMaxValueAndLocation" << endl;
5445 std::pair<Real, RealVect> maxValAndPos;
5446 maxValAndPos.first = -std::numeric_limits<Real>::max();
5447 maxValAndPos.second = RealVect::Zero;
5449 for (
int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
5450 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
5451 const DataIterator& dit = dbl.dataIterator();
5452 const EBISLayout& ebisl = m_amr->getEBISLayout(m_realm, m_phase)[lvl];
5453 const Real dx = m_amr->getDx()[lvl];
5454 const RealVect probLo = m_amr->getProbLo();
5456 const LevelData<BaseFab<bool>>& validCellsLD = (*m_amr->getValidCells(m_realm)[lvl]);
5458 const int nbox = dit.size();
5460#pragma omp parallel for schedule(runtime) reduction(pairmax : maxValAndPos)
5461 for (
int mybox = 0; mybox < nbox; mybox++) {
5462 const DataIndex& din = dit[mybox];
5463 const Box& cellbox = dbl[din];
5464 const EBISBox& ebisbox = ebisl[din];
5466 const EBCellFAB& data = (*a_data[lvl])[din];
5467 const FArrayBox& dataReg = data.getFArrayBox();
5468 const BaseFab<bool>& validCells = validCellsLD[din];
5470 CH_assert(data.nComp() == 1);
5473 auto regularKernel = [&](
const IntVect& iv) ->
void {
5474 if (validCells(iv, 0) && ebisbox.isRegular(iv)) {
5475 if (dataReg(iv, 0) > maxValAndPos.first) {
5476 maxValAndPos.first = dataReg(iv, 0);
5477 maxValAndPos.second = probLo + (RealVect(iv) + 0.5 * RealVect::Unit) * dx;
5482 auto irregularKernel = [&](
const VolIndex& vof) ->
void {
5483 if (validCells(vof.gridIndex(), 0) && ebisbox.isIrregular(vof.gridIndex())) {
5484 if (data(vof, 0) > maxValAndPos.first) {
5485 maxValAndPos.first = data(vof, 0);
5486 maxValAndPos.second = probLo +
Location::position(Location::Cell::Centroid, vof, ebisbox, dx);
5491 VoFIterator& vofit = (*m_amr->getVofIterator(m_realm, m_phase)[lvl])[din];
5493 BoxLoops::loop<D_DECL(1, 1, 1)>(cellbox, regularKernel);
5498 const std::pair<Real, RealVect> globalMaxValAndPos =
ParallelOps::max(maxValAndPos.first, maxValAndPos.second);
5500 a_maxVal = globalMaxValAndPos.first;
5501 a_maxPos = globalMaxValAndPos.second;
5504template <
typename P,
typename F,
typename C>
5508 const EBAMRCellData& a_data,
5509 const std::string a_outputRealm,
5511 const bool a_interpToCentroids,
5512 const bool a_interpGhost)
const noexcept
5514 CH_TIMERS(
"DischargeInceptionStepper::writeData");
5515 CH_TIMER(
"DischargeInceptionStepper::writeData::allocate", t1);
5516 CH_TIMER(
"DischargeInceptionStepper::writeData::local_copy", t2);
5517 CH_TIMER(
"DischargeInceptionStepper::writeData::interp_ghost", t3);
5518 CH_TIMER(
"DischargeInceptionStepper::writeData::interp_centroid", t4);
5519 CH_TIMER(
"DischargeInceptionStepper::writeData::final_copy", t5);
5520 if (m_verbosity > 5) {
5521 pout() <<
"DischargeInceptionStepper::writeData" << endl;
5525 const int numComp = a_data[a_level]->nComp();
5528 const Interval srcInterv(0, numComp - 1);
5529 const Interval dstInterv(a_comp, a_comp + numComp - 1);
5532 LevelData<EBCellFAB> scratch;
5533 m_amr->allocate(scratch, m_realm, m_phase, a_level, numComp);
5537 m_amr->copyData(scratch, *a_data[a_level], a_level, m_realm, m_realm);
5542 if (a_level > 0 && a_interpGhost) {
5543 m_amr->interpGhost(scratch, *a_data[a_level - 1], a_level, m_realm, m_phase);
5548 if (a_interpToCentroids) {
5549 m_amr->interpToCentroids(scratch, m_realm, m_phase, a_level);
5556 m_amr->copyData(a_output, scratch, a_level, a_outputRealm, m_realm, dstInterv, srcInterv);
5562template <
typename P,
typename F,
typename C>
5566 CH_TIMERS(
"DischargeInceptionStepper::getElectricField");
5568 return &m_homogeneousFieldGas;
5571template <
typename P,
typename F,
typename C>
5575 CH_TIME(
"DischargeInceptionStepper::getCriticalField");
5576 if (m_verbosity > 5) {
5577 pout() <<
"DischargeInceptionStepper::getCriticalField" << endl;
5584 auto alpha = [
this](
const Real E) -> Real {
5585 return m_alpha(std::pow(10.0, E), RealVect::Zero) - m_eta(std::pow(10.0, E), RealVect::Zero);
5590 return std::pow(10.0, p);
5593#include <CD_NamespaceFooter.H>
Declaration of the Physics::DischargeInception::DischargeInceptionSpecies CDR species.
Declaration of the Physics::DischargeInception::DischargeInceptionStepper TimeStepper.
Mode
Solver mode: stationary (voltage sweep) or transient (time-dependent).
Definition CD_DischargeInceptionStepper.H:56
Declaration of various useful OpenMP-related utilities.
Declaration of a namespace for SIMD-decorated loops over SoA particles.
CD_PARTICLE_REAL ParticleReal
Floating-point type a user may use for payload columns.
Definition CD_ParticleSoA.H:156
Agglomeration of some useful algebraic/polynomial routines.
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 getMaxMin(Real &max, Real &min, EBAMRCellData &a_data, const int a_comp, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Get maximum and minimum value of specified component.
Definition CD_DataOps.cpp:1711
static void getMaxMinNorm(Real &a_max, Real &a_min, EBAMRCellData &data, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter)
Get maximum and minimum value of normed data.
Definition CD_DataOps.cpp:1879
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 kappaScale(EBAMRCellData &a_data, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter) noexcept
Scale data by volume fraction.
Definition CD_DataOps.cpp:2142
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 dotProduct(MFAMRCellData &a_result, const MFAMRCellData &a_data1, const MFAMRCellData &a_data2)
Compote the cell-wise dot product between two data holders.
Definition CD_DataOps.cpp:537
static void squareRoot(EBAMRFluxData &a_lhs, Vector< RefCountedPtr< LayoutData< std::array< FaceIterator, SpaceDim > > > > &a_faceIter)
Compute the square root of the input data.
Definition CD_DataOps.cpp:3384
static void setCoveredValue(EBAMRCellData &a_lhs, const EBAMRCellData &a_coveredMask, const int a_comp, const Real a_value)
Set value in covered cells. Does specified component.
Definition CD_DataOps.cpp:2655
static void compute(EBAMRCellData &a_data, const std::function< Real(const Real a_cellValue)> &a_func, const Vector< RefCountedPtr< LayoutData< VoFIterator > > > &a_vofIter) noexcept
Compute a new value given the old cell value.
Definition CD_DataOps.cpp:482
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
static void multiplyScalar(EBAMRCellData &a_lhs, const EBAMRCellData &a_rhs)
Multiply data holder by another data holder.
Definition CD_DataOps.cpp:2341
Type
Type of interpolation methods supported. PWC = Piecewise constant, ignoring the embedded boundary....
Definition CD_EBCoarseToFineInterp.H:43
AMR-hierarchy container of computational particles, stored per patch in Struct-of-Arrays form.
Definition CD_ParticleContainer.H:123
void clearParticles()
Drop all valid particles on every level (keeps each leaf's arena capacity).
Definition CD_ParticleContainer.H:442
unsigned long long getNumberOfValidParticlesGlobal() const
Number of valid particles across all ranks.
Definition CD_ParticleContainer.H:543
void remap()
Redistribute every valid particle to the patch/level/rank that owns its cell.
Definition CD_ParticleContainerImplem.H:494
AMRParticlesSoA< P, Traits > & getParticles()
The valid particles on all levels.
Definition CD_ParticleContainer.H:317
static bool ebIntersectionBisect(const RefCountedPtr< BaseIF > &a_impFunc, const RealVect &a_oldPos, const RealVect &a_newPos, const Real &a_bisectStep, Real &a_s)
Compute the intersection point between a particle path and an implicit function using a bisection alg...
Definition CD_ParticleOpsImplem.H:175
static void copyDestructive(ParticleContainer< P, Traits > &a_dst, ParticleContainer< P, Traits > &a_src) noexcept
Move all particles from a_src into a_dst (per leaf), emptying a_src. SoA overload.
Definition CD_ParticleOpsImplem.H:278
static bool domainIntersection(const RealVect &a_oldPos, const RealVect &a_newPos, const RealVect &a_probLo, const RealVect &a_probHi, Real &a_s)
Compute the intersection point between a particle path and a domain side.
Definition CD_ParticleOpsImplem.H:126
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
void append(const RealVect &a_position, const double a_weight)
Append one particle with a default-constructed payload.
Definition CD_ParticleSoA.H:955
double * weightColumn() noexcept
Raw weight column (double*).
Definition CD_ParticleSoA.H:1160
std::size_t size() const noexcept
Number of particles currently stored.
Definition CD_ParticleSoA.H:882
double * positionColumn(const int a_dir) noexcept
Raw position component column dir (double*, for SIMD kernels).
Definition CD_ParticleSoA.H:1137
void remove(const std::size_t a_index) noexcept
Remove particle i using swap-and-pop (O(1), does NOT preserve order).
Definition CD_ParticleSoA.H:1033
void appendParticle(const ParticleSoA &a_src, const std::size_t a_index)
Append a single particle (all columns, incl. id/rank) copied from another container.
Definition CD_ParticleSoAImplem.H:172
CdrSpecies subclass for use with DischargeInceptionStepper.
Definition CD_DischargeInceptionSpecies.H:30
TimeStepper for evaluating the streamer inception criterion in static or transient electric fields.
Definition CD_DischargeInceptionStepper.H:95
virtual const std::function< Real(const Real &E, const RealVect &x)> & getAlpha() const noexcept
Get ionization coefficient.
Definition CD_DischargeInceptionStepperImplem.H:2064
void parseRuntimeOptions() override
Parse runtime options.
Definition CD_DischargeInceptionStepperImplem.H:389
virtual const EBAMRCellData * getElectricField() const noexcept
Get the electric field.
Definition CD_DischargeInceptionStepperImplem.H:5564
void parseMode() noexcept
Parse simulation mode.
Definition CD_DischargeInceptionStepperImplem.H:419
void computeIonVelocity(const Real &a_voltage) noexcept
Set the negative ion velocity. Note.
Definition CD_DischargeInceptionStepperImplem.H:5258
virtual void setIonMobility(const std::function< Real(const Real E)> &a_mobility) noexcept
Set the negative ion mobility (field-dependent)
Definition CD_DischargeInceptionStepperImplem.H:2015
virtual void writeReportStationary() const noexcept
Print report to the terminal.
Definition CD_DischargeInceptionStepperImplem.H:5027
virtual Real advance(const Real a_dt) override
Advancement method. Swaps between various kernels.
Definition CD_DischargeInceptionStepperImplem.H:1602
virtual void townsendTrackTrapezoidal(const Real &a_voltage) noexcept
Track particles (positive ions) using a trapezoidal rule and check if the collide with a cathode.
Definition CD_DischargeInceptionStepperImplem.H:3426
virtual void seedUniformParticles() noexcept
Distribute particles in every grid cell.
Definition CD_DischargeInceptionStepperImplem.H:2137
virtual void resetTracerParticles() noexcept
Reset particles.
Definition CD_DischargeInceptionStepperImplem.H:3785
virtual void setIonDensity(const std::function< Real(const RealVect x)> &a_density) noexcept
Set the negative ion density.
Definition CD_DischargeInceptionStepperImplem.H:2003
virtual void computeCriticalVolumeStationary() noexcept
Compute the critical volume of the K values for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4569
virtual void writePlotDataStationary(LevelData< EBCellFAB > &a_output, int &a_icomp, const std::string &a_outputRealm, const int a_level) const noexcept
Write plot data for the 'stationary' mode.
Definition CD_DischargeInceptionStepperImplem.H:1118
virtual void postRegrid() override
Perform post-regrid operations.
Definition CD_DischargeInceptionStepperImplem.H:1954
virtual void inceptionIntegrateTrapezoidal(const Real &a_voltage) noexcept
K integral: Add integration parts after particles move.
Definition CD_DischargeInceptionStepperImplem.H:2822
virtual void setBackgroundRate(const std::function< Real(const Real &E, const RealVect &x)> &a_backgroundRate) noexcept
Set the background ionization rate (e.g. from cosmic radiation etc).
Definition CD_DischargeInceptionStepperImplem.H:2078
void computeIonDiffusion(const Real &a_voltage) noexcept
Set the negative ion diffusion coefficient.
Definition CD_DischargeInceptionStepperImplem.H:5324
virtual std::pair< Real, RealVect > computeMinimumInceptionVoltage(const EBAMRCellData &a_Uinc) const noexcept
Compute the minimum inception voltage and the starting electron position.
Definition CD_DischargeInceptionStepperImplem.H:4494
virtual void computeTownsendCriterionStationary() noexcept
Solve for the Townsend criterion for each particle in each voltage.
Definition CD_DischargeInceptionStepperImplem.H:3113
virtual void synchronizeSolverTimes(const int a_step, const Real a_time, const Real a_dt) override
Synchronize solver times and time steps.
Definition CD_DischargeInceptionStepperImplem.H:1800
virtual void inceptionIntegrateEuler(const Real &a_voltage) noexcept
Integrate the inception integral using the Euler rule.
Definition CD_DischargeInceptionStepperImplem.H:2632
virtual void computeInceptionVoltageVolume() noexcept
Interpolate between K values to find voltage giving K_inception and store values in m_inceptionVoltag...
Definition CD_DischargeInceptionStepperImplem.H:4233
virtual Real computeIonizationVolumeTransient(const Real &a_voltage) const noexcept
Compute the ionization volume for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4945
virtual void computeFieldEmission(EBAMRCellData &a_emissionRate, const Real &a_voltage) const noexcept
Compute field emission rates.
Definition CD_DischargeInceptionStepperImplem.H:4087
virtual int getNumberOfPlotVariables() const override
Get the number of plot variables for this time stepper.
Definition CD_DischargeInceptionStepperImplem.H:672
virtual Real computeCriticalVolumeTransient() const noexcept
Compute the critical volume of the K values for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4660
void registerOperators() override
Register operators.
Definition CD_DischargeInceptionStepperImplem.H:360
virtual void getMaxValueAndLocation(Real &a_maxVal, RealVect &a_maxPos, const EBAMRCellData &a_data) const noexcept
Get the maximum value and location corresponding to the maximum value in the input data holder.
Definition CD_DischargeInceptionStepperImplem.H:5434
virtual void evaluateFunction(EBAMRCellData &a_data, const Real &a_voltage, const std::function< Real(const Real E, const RealVect x)> &a_func) const noexcept
Evaluate a function f = f(E, x) in a volume.
Definition CD_DischargeInceptionStepperImplem.H:4146
void allocate() override
Allocate storage for solvers and time stepper.
Definition CD_DischargeInceptionStepperImplem.H:173
virtual Vector< std::string > getTransientPlotVariableNames() const noexcept
Get plot variable names for transient mode.
Definition CD_DischargeInceptionStepperImplem.H:1010
virtual Mode getMode() const noexcept
Get the solver mode.
Definition CD_DischargeInceptionStepperImplem.H:2130
void parseInceptionAlgorithm() noexcept
Parse the inception algorithm.
Definition CD_DischargeInceptionStepperImplem.H:478
virtual ~DischargeInceptionStepper()
Destructor.
Definition CD_DischargeInceptionStepperImplem.H:113
void solvePoisson() noexcept
Solve the Poisson equation.
Definition CD_DischargeInceptionStepperImplem.H:251
virtual void setAlpha(const std::function< Real(const Real &E, const RealVect &x)> &a_alpha) noexcept
Set the ionization coefficient.
Definition CD_DischargeInceptionStepperImplem.H:2039
virtual void computeInceptionIntegral(EBAMRCellData &a_inceptionIntegral, const Real a_voltage) noexcept
Compute the inception integral for the input voltage.
Definition CD_DischargeInceptionStepperImplem.H:2438
virtual void regrid(const int a_lmin, const int a_oldFinestLevel, const int a_newFinestLevel) override
Time stepper regrid method.
Definition CD_DischargeInceptionStepperImplem.H:1891
bool particleOutsideGrid(const RealVect &a_pos, const RealVect &a_probLo, const RealVect &a_probHi) const noexcept
Check if particle is outside grid boundaries.
Definition CD_DischargeInceptionStepperImplem.H:5218
virtual void writeReportTransient() const noexcept
Print report to the terminal.
Definition CD_DischargeInceptionStepperImplem.H:5138
virtual void rewindTracerParticles() noexcept
Move particles back to their original position.
Definition CD_DischargeInceptionStepperImplem.H:3747
virtual void townsendTrackEuler(const Real &a_voltage) noexcept
Track particles (positive ions) using an Euler rule and check if the collide with a cathode.
Definition CD_DischargeInceptionStepperImplem.H:3303
void superposition(EBAMRCellData &a_sumField, const MFAMRCellData &a_inhomogeneousField, const MFAMRCellData &a_homogeneousField, const Real a_voltage) const noexcept
Calculate the total electric field = inhomogeneous + V * homogeneous.
Definition CD_DischargeInceptionStepperImplem.H:5404
void parseOptions()
Parse options.
Definition CD_DischargeInceptionStepperImplem.H:374
void setupSolvers() override
Instantiate the tracer particle solver.
Definition CD_DischargeInceptionStepperImplem.H:123
virtual void setEta(const std::function< Real(const Real &E, const RealVect &x)> &a_eta) noexcept
Set the attachment coefficient.
Definition CD_DischargeInceptionStepperImplem.H:2052
virtual Vector< std::string > getStationaryPlotVariableNames() const noexcept
Get plot variable names for stationary mode.
Definition CD_DischargeInceptionStepperImplem.H:865
virtual void setDetachmentRate(const std::function< Real(const Real &E, const RealVect &x)> &a_detachmentRate) noexcept
Set the detachment rate for negative ions.
Definition CD_DischargeInceptionStepperImplem.H:2091
virtual void computeTownsendCriterionTransient(const Real &a_voltage) noexcept
Solve for the Townsend criterion for each particle in each voltage.
Definition CD_DischargeInceptionStepperImplem.H:3247
virtual void computeIonizationVolumeStationary() noexcept
Compute the ionization volume for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4847
virtual void writePlotDataTransient(LevelData< EBCellFAB > &a_output, int &a_icomp, const std::string &a_outputRealm, const int a_level) const noexcept
Write plot data for the 'transient' mode.
Definition CD_DischargeInceptionStepperImplem.H:1332
virtual void computeFieldEmissionStationary() noexcept
Compute field emission rates.
Definition CD_DischargeInceptionStepperImplem.H:3987
void parseOutput() noexcept
Parse output settings.
Definition CD_DischargeInceptionStepperImplem.H:464
virtual void computeInceptionIntegralStationary() noexcept
Solve streamer inception integral for each particle in each voltage and store K values in m_inception...
Definition CD_DischargeInceptionStepperImplem.H:2493
virtual Real computeCriticalAreaTransient() const noexcept
Compute the critical area of the K values for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4796
virtual Real getCriticalField() const noexcept
Get the breakdown field.
Definition CD_DischargeInceptionStepperImplem.H:5573
virtual Vector< std::string > getPlotVariableNames() const override
Get plot variable names.
Definition CD_DischargeInceptionStepperImplem.H:809
virtual void computeDetachmentStationary() noexcept
Compute the detachment ionization rate for all voltages.
Definition CD_DischargeInceptionStepperImplem.H:3899
virtual void writeData(LevelData< EBCellFAB > &a_output, int &a_comp, const EBAMRCellData &a_data, const std::string a_outputRealm, const int a_level, const bool a_interpToCentroids, const bool a_interpGhost) const noexcept
Write data to output. Convenience function used for IO.
Definition CD_DischargeInceptionStepperImplem.H:5506
void parseVoltages() noexcept
Parse voltage levels.
Definition CD_DischargeInceptionStepperImplem.H:444
virtual void interpolateGradAlphaToParticles() noexcept
Interpolate alpha/|grad(alpha)| onto some scratch particle storage.
Definition CD_DischargeInceptionStepperImplem.H:2420
virtual void writePlotData(LevelData< EBCellFAB > &a_output, int &a_icomp, const std::string &a_outputRealm, const int a_level) const override
Write plot data to output holder.
Definition CD_DischargeInceptionStepperImplem.H:1075
virtual void setIonDiffusion(const std::function< Real(const Real E)> &a_diffCo) noexcept
Set the negative ion diffusion coefficient (field-dependent)
Definition CD_DischargeInceptionStepperImplem.H:2027
void postInitialize() override
Perform any post-initialization steps.
Definition CD_DischargeInceptionStepperImplem.H:2338
bool particleInsideEB(const RealVect &a_pos) const noexcept
Check if particle is inside electrode.
Definition CD_DischargeInceptionStepperImplem.H:5242
virtual void setSigma(const std::function< Real(const RealVect &x)> &a_sigma) noexcept
Set surface charge distribution.
Definition CD_DischargeInceptionStepperImplem.H:1991
void parseTransportAlgorithm() noexcept
Parse the transport algorithm.
Definition CD_DischargeInceptionStepperImplem.H:535
virtual void seedIonizationParticles(const Real a_voltage) noexcept
Add particles to every cell where alpha - eta > 0.0.
Definition CD_DischargeInceptionStepperImplem.H:2210
DischargeInceptionStepper()
Default constructor.
Definition CD_DischargeInceptionStepperImplem.H:39
void parsePlotVariables() noexcept
Parse plot variables.
Definition CD_DischargeInceptionStepperImplem.H:575
void initialData() override
Fill problem with initial data.
Definition CD_DischargeInceptionStepperImplem.H:239
virtual const std::function< Real(const Real &E, const RealVect &x)> & getEta() const noexcept
Get attachment coefficient.
Definition CD_DischargeInceptionStepperImplem.H:2071
virtual void setSecondaryEmission(const std::function< Real(const Real &E, const RealVect &x)> &a_coeff) noexcept
Set the secondary emission coefficient.
Definition CD_DischargeInceptionStepperImplem.H:2117
virtual Real computeDt() override
Compute a time step to be used by Driver.
Definition CD_DischargeInceptionStepperImplem.H:1515
virtual void preRegrid(const int a_lmin, const int a_oldFinestLevel) override
Perform pre-regrid operations.
Definition CD_DischargeInceptionStepperImplem.H:1871
virtual void printStepReport() override
Print a step report. Used in transient simulations.
Definition CD_DischargeInceptionStepperImplem.H:1818
virtual void setRho(const std::function< Real(const RealVect &x)> &a_rho) noexcept
Set space charge distribution.
Definition CD_DischargeInceptionStepperImplem.H:1979
void parseVerbosity() noexcept
Parse class verbosity.
Definition CD_DischargeInceptionStepperImplem.H:404
void registerRealms() override
Register realms. Primal is the only realm we need.
Definition CD_DischargeInceptionStepperImplem.H:348
virtual void computeBackgroundIonizationStationary() noexcept
Compute the background ionization rate for all voltages.
Definition CD_DischargeInceptionStepperImplem.H:3817
virtual void computeInceptionIntegralTransient(const Real &a_voltage) noexcept
Solve streamer inception integral.
Definition CD_DischargeInceptionStepperImplem.H:2597
virtual void setVoltageCurve(const std::function< Real(const Real &a_time)> &a_voltageCurve) noexcept
Set the voltage curve (used for transient mode)
Definition CD_DischargeInceptionStepperImplem.H:1967
virtual void computeCriticalAreaStationary() noexcept
Compute the critical area of the K values for each voltage.
Definition CD_DischargeInceptionStepperImplem.H:4724
virtual void advanceIons(const Real a_dt) noexcept
Advance negative ions.
Definition CD_DischargeInceptionStepperImplem.H:1714
virtual Real computeRdot(const Real &a_voltage) const noexcept
Compute integral_Vcr(done/dt * (1 - eta/alpha) dV)
Definition CD_DischargeInceptionStepperImplem.H:3643
virtual void setFieldEmission(const std::function< Real(const Real &E, const RealVect &x)> &a_currentDensity) noexcept
Set the field emission current.
Definition CD_DischargeInceptionStepperImplem.H:2104
static const std::string Primal
Identifier for perimal realm.
Definition CD_Realm.H:44
Class which is used for run-time monitoring of events.
Definition CD_Timer.H:32
void startEvent(const std::string &a_event) noexcept
Start an event.
Definition CD_TimerImplem.H:60
void eventReport(std::ostream &a_outputStream, const bool a_localReportOnly=false) const noexcept
Print all timed events to cout.
Definition CD_TimerImplem.H:170
void stopEvent(const std::string &a_event) noexcept
Stop an event.
Definition CD_TimerImplem.H:89
Base class for a tracer particle solver. This solver can advance particles in a pre-defined velocity ...
Definition CD_TracerParticleSolver.H:39
ALWAYS_INLINE void loop(const Box &a_computeBox, Functor &&kernel)
Launch a C++ kernel over a regular grid with compile-time per-dimension strides.
Definition CD_BoxLoopsImplem.H:39
RealVect position(Location::Cell a_location, const VolIndex &a_vof, const EBISBox &a_ebisbox, const Real &a_dx)
Compute the position (ignoring the "origin) of a Vof.
Definition CD_LocationImplem.H:21
Real max(const Real &a_input) noexcept
Get the maximum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition CD_ParallelOpsImplem.H:177
Real min(const Real &a_input) noexcept
Get the minimum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition CD_ParallelOpsImplem.H:59
Real sum(const Real &a_value) noexcept
Compute the sum across all MPI ranks.
Definition CD_ParallelOpsImplem.H:354
ALWAYS_INLINE void loop(const ParticleSoA< P, Traits > &a_soa, Functor &&a_kernel)
Launch a kernel over every particle in a ParticleSoA, decorating the loop with CD_PRAGMA_SIMD.
Definition CD_ParticleLoops.H:87
Real brentSolve(const Real a_point1, const Real a_point2, const std::function< Real(const Real x)> &a_func) noexcept
Compute the root of a function between two points. This is a 1D problem.
Definition CD_PolyUtils.cpp:169
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