117 using std::make_shared;
119 auto channel = make_shared<PlasmaChannel1D>(opts.
cfg);
121 auto left = make_shared<Cantera::Empty1D>();
122 auto right = make_shared<Cantera::Empty1D>();
123 std::vector<std::shared_ptr<Cantera::Domain1D>> domains{left, channel, right};
127 const std::size_t n_species = channel->nSpecies();
128 const std::size_t n_points = channel->nPoints();
129 const std::size_t n_vars = 2 + n_species;
130 const std::size_t channel_offset =
133 std::vector<double> x(sim.
size(), 0.0), xnew(sim.
size());
139 for (std::size_t comp = 0; comp < n_vars; comp++) {
140 std::vector<double> vals = channel->values(channel->componentName(comp));
141 for (std::size_t j = 0; j < n_points; j++) {
142 x[channel_offset + n_vars * j + comp] = vals[j];
155 history.
npts = n_points;
156 history.
nsp = n_species;
157 for (std::size_t j = 0; j < n_points; j++) history.
r.push_back(channel->z(j));
158 for (std::size_t k = 0; k < n_species; k++) {
159 history.
species.push_back(channel->componentName(2 + k));
166 auto record = [&](
double t) {
167 history.
t.push_back(t);
168 for (std::size_t j = 0; j < n_points; j++) {
169 const double Tg = x[channel_offset + n_vars * j + 0];
170 const double Te = x[channel_offset + n_vars * j + 1];
171 history.
Tg.push_back(Tg);
172 history.
Te.push_back(Te);
173 history.
ne.push_back(
174 channel->electronDensity(Tg, Te, &x[channel_offset + n_vars * j + 2]));
175 for (std::size_t k = 0; k < n_species; k++) {
176 history.
Y.push_back(x[channel_offset + n_vars * j + 2 + k]);
187 auto fieldAt = [&](
double t) {
195 const double t_total =
196 opts.
dt *
static_cast<double>(opts.
n_steps);
197 const std::size_t n_intervals =
198 std::max<std::size_t>(
203 ChannelRHS rhs(channel.get(), &sim, x, n_vars, channel_offset, n_points,
207 const char* lin_solver_env = std::getenv(
"RIZER_LINSOL");
208 const std::string lin_solver_type =
209 lin_solver_env ? std::string(lin_solver_env) : std::string(
"BAND");
210 cvode->setLinearSolverType(lin_solver_type);
211 if (lin_solver_type ==
"BAND") {
213 const int bandwidth =
static_cast<int>(2 * n_vars);
214 cvode->setBandwidth(bandwidth, bandwidth);
226 std::vector<double> atol(x.size());
227 for (std::size_t j = 0; j < n_points; j++) {
228 atol[n_vars * j + 0] = 1.0e-3;
229 atol[n_vars * j + 1] = 1.0e-3;
230 for (std::size_t k = 0; k < n_species; k++) {
231 atol[n_vars * j + 2 + k] = 1.0e-9;
234 cvode->setTolerances(1.0e-7,
240 cvode->setMaxStepSize(opts.
dt);
244 cvode->setMaxSteps(500000);
245 cvode->initialize(0.0, rhs);
251 auto decodeError = [&](
const std::string& message) -> std::string {
254 double t_fail = -1.0;
256 std::size_t t_pos = message.find(
"At t = ");
257 if (t_pos != std::string::npos) {
258 try { t_fail = std::stod(message.substr(t_pos + 7)); }
catch (...) {}
260 std::ostringstream out;
261 out <<
"PlasmaChannel1D BDF solve failed to converge";
262 if (t_fail >= 0.0) out <<
" near t=" << t_fail <<
" s";
263 out <<
".\nThe implicit corrector could not resolve the local "
264 "dynamics and the step size hit its floor. The dominant "
265 "error contributions are:\n";
266 std::istringstream in(message);
268 bool in_error_block =
false, found_any =
false;
269 while (std::getline(in, line)) {
270 if (line.find(
"Components with largest") != std::string::npos) {
271 in_error_block =
true;
274 if (!in_error_block)
continue;
275 std::size_t colon = line.find(
':');
276 if (colon == std::string::npos)
continue;
277 long global_index;
double error_value;
279 global_index = std::stol(line.substr(0, colon));
280 error_value = std::stod(line.substr(colon + 1));
281 }
catch (...) {
continue; }
282 long local_index = global_index -
static_cast<long>(channel_offset);
283 if (local_index < 0)
continue;
284 std::size_t j =
static_cast<std::size_t
>(local_index) / n_vars;
285 std::size_t comp =
static_cast<std::size_t
>(local_index) % n_vars;
286 if (j >= n_points)
continue;
287 out <<
" node " << j <<
" (r=" << channel->z(j) <<
" m) "
288 << channel->componentName(comp)
289 <<
" (weighted error " << error_value <<
")\n";
292 if (!found_any) { out << message <<
"\n"; }
293 out <<
"Remedies: reduce dt, loosen tolerances, soften the initial "
294 "profiles or the field ramp, or verify the initial state is "
295 "physically consistent at the flagged nodes.";
308 for (
double t_warm : {1.0e-15, 1.0e-14, 1.0e-13, 1.0e-12, 1.0e-11, 1.0e-10}) {
309 if (t_warm >= t_total)
break;
311 cvode->integrate(t_warm);
314 "{}", decodeError(err.
what()));
318 for (std::size_t frame = 1; frame <= n_intervals; frame++) {
319 const double t_rec = t_total *
static_cast<double>(frame)
320 /
static_cast<double>(n_intervals);
324 cvode->integrate(t_rec);
326 decoded = decodeError(err.
what());
335 auto solution = cvode->solution();
336 std::copy(solution.begin(), solution.end(), x.begin());
339 std::fprintf(stderr,
"[bdf] frame %zu/%zu t=%.3e s\n",
340 frame, n_intervals, t_rec);
361 const double dt_min = 1.0e-16;
363 const long max_substeps = 2000000;
365 auto& newton = sim.
newton();
371 long total_substeps = 0;
373 for (std::size_t frame = 1; frame <= n_intervals; frame++) {
375 t_total *
static_cast<double>(frame) /
static_cast<double>(n_intervals);
376 while (t < t_rec - 1.0e-300) {
378 const double step_size = std::min(dt, t_rec - t);
379 channel->setElectricField(fieldAt(t));
381 const int status = newton.solve(x, xnew, sim, opts.
loglevel);
383 std::copy(xnew.begin(), xnew.end(), x.begin());
386 dt = std::min(dt * 1.5, opts.
dt);
397 "Backward-Euler Newton failed to converge; dt fell below "
398 "{:g} s near t={:g} s. The electron-impact chemistry is too "
399 "stiff for this step -- use integrator='bdf'.", dt_min, t);
402 if (++total_substeps > max_substeps) {
404 "Exceeded {} sub-steps; integration is not progressing.",
std::vector< double > ne
Electron number density [1/m^3], row-major [nframes, npts].
std::vector< std::string > species
Species names, length nsp (order matches the Y axis).
std::vector< double > Y
Species mass fractions [-], row-major [nframes, npts, nsp].
std::vector< double > Tg
Gas temperature [K], row-major [nframes, npts].
std::vector< double > Te
Electron temperature [K], row-major [nframes, npts].