Cantera  3.2.0b1
Loading...
Searching...
No Matches
Flow1D.cpp
Go to the documentation of this file.
1//! @file Flow1D.cpp
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
8#include "cantera/oneD/refine.h"
12#include "cantera/base/global.h"
13
14using namespace std;
15
16namespace Cantera
17{
18
19namespace { // restrict scope of auxiliary variables to local translation unit
20
21const map<string, size_t> componentMap = {
22 {"velocity", c_offset_U}, // axial velocity [m/s]
23 {"spreadRate", c_offset_V}, // strain rate
24 {"T", c_offset_T}, // temperature [kelvin]
25 {"Lambda", c_offset_L}, // (1/r)dP/dr
26 {"eField", c_offset_E}, // electric field
27 {"Uo", c_offset_Uo}, // oxidizer axial velocity [m/s]
28};
29
30} // end unnamed namespace
31
32Flow1D::Flow1D(ThermoPhase* ph, size_t nsp, size_t points) :
33 Domain1D(nsp+c_offset_Y, points),
34 m_nsp(nsp)
35{
36 warn_deprecated("Flow1D::Flow1D(ThermoPhase*, size_t, size_t)",
37 "To be removed after Cantera 3.2. Use constructor using Solution instead.");
38 _init(ph, nsp, points);
39}
40
41void Flow1D::_init(ThermoPhase* ph, size_t nsp, size_t points)
42{
43 m_points = points;
44
45 if (ph == 0) {
46 return; // used to create a dummy object
47 }
48 m_thermo = ph;
49
50 size_t nsp2 = m_thermo->nSpecies();
51 if (nsp2 != m_nsp) {
52 m_nsp = nsp2;
54 }
55
56 // make a local copy of the species molecular weight vector
58
59 // set pressure based on associated thermo object
61
62 // the species mass fractions are the last components in the solution
63 // vector, so the total number of components is the number of species
64 // plus the offset of the first mass fraction.
66
67 // Turn off the energy equation at all points
68 m_do_energy.resize(m_points,false);
69
70 m_diff.resize(m_nsp*m_points);
75 m_dhk_dz.resize(m_nsp, m_points - 1, 0.0);
76 m_ybar.resize(m_nsp);
77 m_qdotRadiation.resize(m_points, 0.0);
78
79 //-------------- default solution bounds --------------------
80 setBounds(c_offset_U, -1e20, 1e20); // no bounds on u
81 setBounds(c_offset_V, -1e20, 1e20); // no bounds on V
82 setBounds(c_offset_T, 200.0, 2*m_thermo->maxTemp()); // temperature bounds
83 setBounds(c_offset_L, -1e20, 1e20); // Lambda should be negative
84 setBounds(c_offset_E, -1e20, 1e20); // no bounds on electric field
85 setBounds(c_offset_Uo, -1e20, 1e20); // no bounds on Uo
86 // mass fraction bounds
87 for (size_t k = 0; k < m_nsp; k++) {
88 setBounds(c_offset_Y+k, -1.0e-7, 1.0e5);
89 }
90
91 //-------------------- grid refinement -------------------------
92 m_refiner->setActive(c_offset_U, false);
93 m_refiner->setActive(c_offset_V, false);
94 m_refiner->setActive(c_offset_T, false);
95 m_refiner->setActive(c_offset_L, false);
96 m_refiner->setActive(c_offset_Uo, false);
97
98 vector<double> gr;
99 for (size_t ng = 0; ng < m_points; ng++) {
100 gr.push_back(1.0*ng/m_points);
101 }
102 setupGrid(m_points, gr.data());
103
104 // Find indices for radiating species
105 m_kRadiating.resize(2, npos);
106 m_kRadiating[0] = m_thermo->speciesIndex("CO2", false);
107 m_kRadiating[1] = m_thermo->speciesIndex("H2O", false);
108}
109
110Flow1D::Flow1D(shared_ptr<ThermoPhase> th, size_t nsp, size_t points)
111 : Flow1D(th.get(), nsp, points)
112{
113 auto sol = Solution::create();
114 sol->setThermo(th);
115 setSolution(sol);
116}
117
118Flow1D::Flow1D(shared_ptr<Solution> phase, const string& id, size_t points)
119 : Domain1D(phase->thermo()->nSpecies()+c_offset_Y, points)
120 , m_nsp(phase->thermo()->nSpecies())
121{
122 _init(phase->thermo().get(), phase->thermo()->nSpecies(), points);
123
125 m_solution->thermo()->addSpeciesLock();
126 m_id = id;
127 m_kin = m_solution->kinetics().get();
128 m_trans = m_solution->transport().get();
129 if (m_trans->transportModel() == "none") {
130 throw CanteraError("Flow1D::Flow1D",
131 "An appropriate transport model\nshould be set when instantiating the "
132 "Solution ('gas') object.");
133 }
134 m_solution->registerChangedCallback(this, [this]() {
135 _setKinetics(m_solution->kinetics());
136 _setTransport(m_solution->transport());
137 });
138}
139
140Flow1D::~Flow1D()
141{
142 if (m_solution) {
143 m_solution->removeChangedCallback(this);
144 }
145}
146
147double Flow1D::lambda(const double* x, size_t j) const {
148 warn_deprecated("Flow1D::lambda",
149 "To be removed after Cantera 3.2. Component 'lambda' is renamed to 'Lambda'.");
150 return x[index(c_offset_L, j)];
151}
152
153string Flow1D::domainType() const {
154 if (m_isFree) {
155 return "free-flow";
156 }
157 if (m_usesLambda) {
158 return "axisymmetric-flow";
159 }
160 return "unstrained-flow";
161}
162
163void Flow1D::setKinetics(shared_ptr<Kinetics> kin)
164{
165 warn_deprecated("Flow1D::setKinetics",
166 "After Cantera 3.2, a change of domain contents after instantiation "
167 "will be disabled.");
168 _setKinetics(kin);
169}
170
171void Flow1D::_setKinetics(shared_ptr<Kinetics> kin)
172{
173 m_kin = kin.get();
174 m_solution->setKinetics(kin);
175}
176
177void Flow1D::setTransport(shared_ptr<Transport> trans)
178{
179 warn_deprecated("Flow1D::setTransport",
180 "After Cantera 3.2, a change of domain contents after instantiation "
181 "will be disabled.");
182 _setTransport(trans);
183}
184
185void Flow1D::_setTransport(shared_ptr<Transport> trans)
186{
187 if (!trans) {
188 throw CanteraError("Flow1D::_setTransport", "Unable to set empty transport.");
189 }
190 m_trans = trans.get();
191 if (m_trans->transportModel() == "none") {
192 throw CanteraError("Flow1D::_setTransport", "Invalid Transport model 'none'.");
193 }
194 m_do_multicomponent = (m_trans->transportModel() == "multicomponent" ||
195 m_trans->transportModel() == "multicomponent-CK");
196
197 m_diff.resize(m_nsp * m_points);
200 }
202 m_solution->setTransport(trans);
203}
204
205void Flow1D::resize(size_t ncomponents, size_t points)
206{
207 Domain1D::resize(ncomponents, points);
208 m_rho.resize(m_points, 0.0);
209 m_wtm.resize(m_points, 0.0);
210 m_cp.resize(m_points, 0.0);
211 m_visc.resize(m_points, 0.0);
212 m_tcon.resize(m_points, 0.0);
213
214 m_diff.resize(m_nsp*m_points);
217 }
221 m_hk.resize(m_nsp, m_points, 0.0);
222 m_dhk_dz.resize(m_nsp, m_points - 1, 0.0);
223 m_do_energy.resize(m_points,false);
224 m_qdotRadiation.resize(m_points, 0.0);
225 m_fixedtemp.resize(m_points);
226
227 m_dz.resize(m_points-1);
228 m_z.resize(m_points);
229}
230
231void Flow1D::setupGrid(size_t n, const double* z)
232{
233 resize(m_nv, n);
234
235 m_z[0] = z[0];
236 for (size_t j = 1; j < m_points; j++) {
237 if (z[j] <= z[j-1]) {
238 throw CanteraError("Flow1D::setupGrid",
239 "grid points must be monotonically increasing");
240 }
241 m_z[j] = z[j];
242 m_dz[j-1] = m_z[j] - m_z[j-1];
243 }
244}
245
247{
248 double* x = xg + loc();
249 for (size_t j = 0; j < m_points; j++) {
250 double* Y = x + m_nv*j + c_offset_Y;
253 }
254}
255
256void Flow1D::setTransportModel(const string& model)
257{
258 if (model == "none") {
259 throw CanteraError("Flow1D::setTransportModel",
260 "Invalid Transport model 'none'.");
261 }
262 m_solution->setTransportModel(model);
263 Flow1D::_setTransport(m_solution->transport());
264}
265
267 return m_trans->transportModel();
268}
269
272 if (transportModel() != "mixture-averaged-CK" &&
273 transportModel() != "mixture-averaged") {
274 warn_user("Flow1D::setFluxGradientBasis",
275 "Setting fluxGradientBasis only affects "
276 "the mixture-averaged diffusion model.");
277 }
278}
279
281{
282 for (size_t j = 0; j < m_points; j++) {
283 T(x,j) = m_thermo->temperature();
284 m_thermo->getMassFractions(&Y(x, 0, j));
285 m_rho[j] = m_thermo->density();
286 }
287}
288
289void Flow1D::setGas(const double* x, size_t j)
290{
292 const double* yy = x + m_nv*j + c_offset_Y;
295}
296
297void Flow1D::setGasAtMidpoint(const double* x, size_t j)
298{
299 m_thermo->setTemperature(0.5*(T(x,j)+T(x,j+1)));
300 const double* yy_j = x + m_nv*j + c_offset_Y;
301 const double* yy_j_plus1 = x + m_nv*(j+1) + c_offset_Y;
302 for (size_t k = 0; k < m_nsp; k++) {
303 m_ybar[k] = 0.5*(yy_j[k] + yy_j_plus1[k]);
304 }
307}
308
309void Flow1D::_finalize(const double* x)
310{
311 if (!(m_do_multicomponent ||
312 m_trans->transportModel() == "mixture-averaged" ||
313 m_trans->transportModel() == "mixture-averaged-CK")
314 && m_do_soret) {
315
316 throw CanteraError("Flow1D::_finalize",
317 "Thermal diffusion (the Soret effect) is enabled, but it "
318 "only ompatible with the mixture-averaged and multicomponent "
319 "transport models.");
320 }
321
322 size_t nz = m_zfix.size();
323 bool e = m_do_energy[0];
324 for (size_t j = 0; j < m_points; j++) {
325 if (e || nz == 0) {
326 m_fixedtemp[j] = T(x, j);
327 } else {
328 double zz = (z(j) - z(0))/(z(m_points - 1) - z(0));
329 double tt = linearInterp(zz, m_zfix, m_tfix);
330 m_fixedtemp[j] = tt;
331 }
332 }
333 if (e) {
335 }
336
337 if (m_isFree) {
338 // If the domain contains the temperature fixed point, make sure that it
339 // is correctly set. This may be necessary when the grid has been modified
340 // externally.
341 if (m_tfixed != Undef) {
342 for (size_t j = 0; j < m_points; j++) {
343 if (z(j) == m_zfixed) {
344 return; // fixed point is already set correctly
345 }
346 }
347
348 for (size_t j = 0; j < m_points - 1; j++) {
349 // Find where the temperature profile crosses the current
350 // fixed temperature.
351 if ((T(x, j) - m_tfixed) * (T(x, j+1) - m_tfixed) <= 0.0) {
352 m_tfixed = T(x, j+1);
353 m_zfixed = z(j+1);
354 return;
355 }
356 }
357 }
358 }
359}
360
361void Flow1D::eval(size_t jGlobal, double* xGlobal, double* rsdGlobal,
362 integer* diagGlobal, double rdt)
363{
364 // If evaluating a Jacobian, and the global point is outside the domain of
365 // influence for this domain, then skip evaluating the residual
366 if (jGlobal != npos && (jGlobal + 1 < firstPoint() || jGlobal > lastPoint() + 1)) {
367 return;
368 }
369
370 // start of local part of global arrays
371 double* x = xGlobal + loc();
372 double* rsd = rsdGlobal + loc();
373 integer* diag = diagGlobal + loc();
374
375 size_t jmin, jmax;
376 if (jGlobal == npos) { // evaluate all points
377 jmin = 0;
378 jmax = m_points - 1;
379 } else { // evaluate points for Jacobian
380 size_t jpt = (jGlobal == 0) ? 0 : jGlobal - firstPoint();
381 jmin = std::max<size_t>(jpt, 1) - 1;
382 jmax = std::min(jpt+1,m_points-1);
383 }
384
385 updateProperties(jGlobal, x, jmin, jmax);
386
387 if (m_do_radiation) { // Calculation of qdotRadiation
388 computeRadiation(x, jmin, jmax);
389 }
390
391 evalContinuity(x, rsd, diag, rdt, jmin, jmax);
392 evalMomentum(x, rsd, diag, rdt, jmin, jmax);
393 evalEnergy(x, rsd, diag, rdt, jmin, jmax);
394 evalLambda(x, rsd, diag, rdt, jmin, jmax);
395 evalElectricField(x, rsd, diag, rdt, jmin, jmax);
396 evalUo(x, rsd, diag, rdt, jmin, jmax);
397 evalSpecies(x, rsd, diag, rdt, jmin, jmax);
398}
399
400void Flow1D::updateProperties(size_t jg, double* x, size_t jmin, size_t jmax)
401{
402 // properties are computed for grid points from j0 to j1
403 size_t j0 = std::max<size_t>(jmin, 1) - 1;
404 size_t j1 = std::min(jmax+1,m_points-1);
405
406 updateThermo(x, j0, j1);
407 if (jg == npos || m_force_full_update) {
408 // update transport properties only if a Jacobian is not being
409 // evaluated, or if specifically requested
410 updateTransport(x, j0, j1);
411 }
412 if (jg == npos) {
413 double* Yleft = x + index(c_offset_Y, jmin);
414 m_kExcessLeft = distance(Yleft, max_element(Yleft, Yleft + m_nsp));
415 double* Yright = x + index(c_offset_Y, jmax);
416 m_kExcessRight = distance(Yright, max_element(Yright, Yright + m_nsp));
417 }
418
419 // update the species diffusive mass fluxes whether or not a
420 // Jacobian is being evaluated
421 updateDiffFluxes(x, j0, j1);
422}
423
424void Flow1D::updateTransport(double* x, size_t j0, size_t j1)
425{
427 for (size_t j = j0; j < j1; j++) {
428 setGasAtMidpoint(x,j);
429 double wtm = m_thermo->meanMolecularWeight();
430 double rho = m_thermo->density();
431 m_visc[j] = (m_dovisc ? m_trans->viscosity() : 0.0);
433
434 // Use m_diff as storage for the factor outside the summation
435 for (size_t k = 0; k < m_nsp; k++) {
436 m_diff[k+j*m_nsp] = m_wt[k] * rho / (wtm*wtm);
437 }
438
440 if (m_do_soret) {
442 }
443 }
444 } else { // mixture averaged transport
445 for (size_t j = j0; j < j1; j++) {
446 setGasAtMidpoint(x,j);
447 m_visc[j] = (m_dovisc ? m_trans->viscosity() : 0.0);
448
449 if (m_fluxGradientBasis == ThermoBasis::molar) {
451 } else {
453 }
454
455 double rho = m_thermo->density();
456
457 if (m_fluxGradientBasis == ThermoBasis::molar) {
458 double wtm = m_thermo->meanMolecularWeight();
459 for (size_t k=0; k < m_nsp; k++) {
460 m_diff[k+j*m_nsp] *= m_wt[k] * rho / wtm;
461 }
462 } else {
463 for (size_t k=0; k < m_nsp; k++) {
464 m_diff[k+j*m_nsp] *= rho;
465 }
466 }
468 if (m_do_soret) {
470 }
471 }
472 }
473}
474
475void Flow1D::updateDiffFluxes(const double* x, size_t j0, size_t j1)
476{
478 for (size_t j = j0; j < j1; j++) {
479 double dz = z(j+1) - z(j);
480 for (size_t k = 0; k < m_nsp; k++) {
481 double sum = 0.0;
482 for (size_t m = 0; m < m_nsp; m++) {
483 sum += m_wt[m] * m_multidiff[mindex(k,m,j)] * (X(x,m,j+1)-X(x,m,j));
484 }
485 m_flux(k,j) = sum * m_diff[k+j*m_nsp] / dz;
486 }
487 }
488 } else {
489 for (size_t j = j0; j < j1; j++) {
490 double sum = 0.0;
491 double dz = z(j+1) - z(j);
492 if (m_fluxGradientBasis == ThermoBasis::molar) {
493 for (size_t k = 0; k < m_nsp; k++) {
494 m_flux(k,j) = m_diff[k+m_nsp*j] * (X(x,k,j) - X(x,k,j+1))/dz;
495 sum -= m_flux(k,j);
496 }
497 } else {
498 for (size_t k = 0; k < m_nsp; k++) {
499 m_flux(k,j) = m_diff[k+m_nsp*j] * (Y(x,k,j) - Y(x,k,j+1))/dz;
500 sum -= m_flux(k,j);
501 }
502 }
503 // correction flux to ensure that \sum_k Y_k V_k = 0.
504 for (size_t k = 0; k < m_nsp; k++) {
505 m_flux(k,j) += sum*Y(x,k,j);
506 }
507 }
508 }
509
510 if (m_do_soret) {
511 for (size_t m = j0; m < j1; m++) {
512 double gradlogT = 2.0 * (T(x,m+1) - T(x,m)) /
513 ((T(x,m+1) + T(x,m)) * (z(m+1) - z(m)));
514 for (size_t k = 0; k < m_nsp; k++) {
515 m_flux(k,m) -= m_dthermal(k,m)*gradlogT;
516 }
517 }
518 }
519}
520
521void Flow1D::computeRadiation(double* x, size_t jmin, size_t jmax)
522{
523 // Variable definitions for the Planck absorption coefficient and the
524 // radiation calculation:
525 double k_P_ref = 1.0*OneAtm;
526
527 // Polynomial coefficients:
528 const double c_H2O[6] = {-0.23093, -1.12390, 9.41530, -2.99880,
529 0.51382, -1.86840e-5};
530 const double c_CO2[6] = {18.741, -121.310, 273.500, -194.050,
531 56.310, -5.8169};
532
533 // Calculation of the two boundary values
534 double boundary_Rad_left = m_epsilon_left * StefanBoltz * pow(T(x, 0), 4);
535 double boundary_Rad_right = m_epsilon_right * StefanBoltz * pow(T(x, m_points - 1), 4);
536
537 for (size_t j = jmin; j < jmax; j++) {
538 // calculation of the mean Planck absorption coefficient
539 double k_P = 0;
540 // Absorption coefficient for H2O
541 if (m_kRadiating[1] != npos) {
542 double k_P_H2O = 0;
543 for (size_t n = 0; n <= 5; n++) {
544 k_P_H2O += c_H2O[n] * pow(1000 / T(x, j), (double) n);
545 }
546 k_P_H2O /= k_P_ref;
547 k_P += m_press * X(x, m_kRadiating[1], j) * k_P_H2O;
548 }
549 // Absorption coefficient for CO2
550 if (m_kRadiating[0] != npos) {
551 double k_P_CO2 = 0;
552 for (size_t n = 0; n <= 5; n++) {
553 k_P_CO2 += c_CO2[n] * pow(1000 / T(x, j), (double) n);
554 }
555 k_P_CO2 /= k_P_ref;
556 k_P += m_press * X(x, m_kRadiating[0], j) * k_P_CO2;
557 }
558
559 // Calculation of the radiative heat loss term
560 double radiative_heat_loss = 2 * k_P *(2 * StefanBoltz * pow(T(x, j), 4)
561 - boundary_Rad_left - boundary_Rad_right);
562
563 // set the radiative heat loss vector
564 m_qdotRadiation[j] = radiative_heat_loss;
565 }
566}
567
568void Flow1D::evalContinuity(double* x, double* rsd, int* diag,
569 double rdt, size_t jmin, size_t jmax)
570{
571 // The left boundary has the same form for all cases.
572 if (jmin == 0) { // left boundary
573 rsd[index(c_offset_U, jmin)] = -(rho_u(x, jmin+1) - rho_u(x, jmin))/m_dz[jmin]
574 -(density(jmin+1)*V(x, jmin+1)
575 + density(jmin)*V(x, jmin));
576 diag[index(c_offset_U, jmin)] = 0; // Algebraic constraint
577 }
578
579 if (jmax == m_points - 1) { // right boundary
580 if (m_usesLambda) { // zero mass flux
581 rsd[index(c_offset_U, jmax)] = rho_u(x, jmax);
582 } else { // zero gradient, same for unstrained or free-flow
583 rsd[index(c_offset_U, jmax)] = rho_u(x, jmax) - rho_u(x, jmax-1);
584 }
585 diag[index(c_offset_U, jmax)] = 0; // Algebraic constraint
586 }
587
588 // j0 and j1 are constrained to only interior points
589 size_t j0 = std::max<size_t>(jmin, 1);
590 size_t j1 = std::min(jmax, m_points-2);
591 if (m_usesLambda) { // "axisymmetric-flow"
592 for (size_t j = j0; j <= j1; j++) { // interior points
593 // For "axisymmetric-flow", the continuity equation propagates the
594 // mass flow rate information to the left (j+1 -> j) from the value
595 // specified at the right boundary. The Lambda information propagates
596 // in the opposite direction.
597 rsd[index(c_offset_U, j)] = -(rho_u(x, j+1) - rho_u(x, j))/m_dz[j]
598 -(density(j+1)*V(x, j+1) + density(j)*V(x, j));
599 diag[index(c_offset_U, j)] = 0; // Algebraic constraint
600 }
601 } else if (m_isFree) { // "free-flow"
602 for (size_t j = j0; j <= j1; j++) {
603 // terms involving V are zero as V=0 by definition
604 if (z(j) > m_zfixed) {
605 rsd[index(c_offset_U, j)] = -(rho_u(x, j) - rho_u(x, j-1))/m_dz[j-1];
606 } else if (z(j) == m_zfixed) {
607 if (m_do_energy[j]) {
608 rsd[index(c_offset_U, j)] = (T(x, j) - m_tfixed);
609 } else {
610 rsd[index(c_offset_U, j)] = (rho_u(x, j) - m_rho[0]*0.3); // why 0.3?
611 }
612 } else { // z(j) < m_zfixed
613 rsd[index(c_offset_U, j)] = -(rho_u(x, j+1) - rho_u(x, j))/m_dz[j];
614 }
615 diag[index(c_offset_U, j)] = 0; // Algebraic constraint
616 }
617 } else { // "unstrained-flow" (fixed mass flow rate)
618 for (size_t j = j0; j <= j1; j++) {
619 rsd[index(c_offset_U, j)] = rho_u(x, j) - rho_u(x, j-1);
620 diag[index(c_offset_U, j)] = 0; // Algebraic constraint
621 }
622 }
623}
624
625void Flow1D::evalMomentum(double* x, double* rsd, int* diag,
626 double rdt, size_t jmin, size_t jmax)
627{
628 if (!m_usesLambda) { //disable this equation
629 for (size_t j = jmin; j <= jmax; j++) {
630 rsd[index(c_offset_V, j)] = V(x, j);
631 diag[index(c_offset_V, j)] = 0;
632 }
633 return;
634 }
635
636 if (jmin == 0) { // left boundary
637 rsd[index(c_offset_V, jmin)] = V(x, jmin);
638 }
639
640 if (jmax == m_points - 1) { // right boundary
641 rsd[index(c_offset_V, jmax)] = V(x, jmax);
642 diag[index(c_offset_V, jmax)] = 0;
643 }
644
645 // j0 and j1 are constrained to only interior points
646 size_t j0 = std::max<size_t>(jmin, 1);
647 size_t j1 = std::min(jmax, m_points-2);
648 for (size_t j = j0; j <= j1; j++) { // interior points
649 rsd[index(c_offset_V, j)] = (shear(x, j) - Lambda(x, j)
650 - rho_u(x, j) * dVdz(x, j)
651 - m_rho[j] * V(x, j) * V(x, j)) / m_rho[j];
652 if (!m_twoPointControl) {
653 rsd[index(c_offset_V, j)] -= rdt * (V(x, j) - V_prev(j));
654 diag[index(c_offset_V, j)] = 1;
655 } else {
656 diag[index(c_offset_V, j)] = 0;
657 }
658 }
659}
660
661void Flow1D::evalLambda(double* x, double* rsd, int* diag,
662 double rdt, size_t jmin, size_t jmax)
663{
664 if (!m_usesLambda) { // disable this equation
665 for (size_t j = jmin; j <= jmax; j++) {
666 rsd[index(c_offset_L, j)] = Lambda(x, j);
667 diag[index(c_offset_L, j)] = 0;
668 }
669 return;
670 }
671
672 if (jmin == 0) { // left boundary
673 if (m_twoPointControl) {
674 rsd[index(c_offset_L, jmin)] = Lambda(x, jmin+1) - Lambda(x, jmin);
675 } else {
676 rsd[index(c_offset_L, jmin)] = -rho_u(x, jmin);
677 }
678 }
679
680 if (jmax == m_points - 1) { // right boundary
681 rsd[index(c_offset_L, jmax)] = Lambda(x, jmax) - Lambda(x, jmax-1);
682 diag[index(c_offset_L, jmax)] = 0;
683 }
684
685 // j0 and j1 are constrained to only interior points
686 size_t j0 = std::max<size_t>(jmin, 1);
687 size_t j1 = std::min(jmax, m_points-2);
688 for (size_t j = j0; j <= j1; j++) { // interior points
689 if (m_twoPointControl) {
690 if (z(j) == m_zLeft) {
691 rsd[index(c_offset_L, j)] = T(x,j) - m_tLeft;
692 } else if (z(j) > m_zLeft) {
693 rsd[index(c_offset_L, j)] = Lambda(x, j) - Lambda(x, j-1);
694 } else if (z(j) < m_zLeft) {
695 rsd[index(c_offset_L, j)] = Lambda(x, j) - Lambda(x, j+1);
696 }
697 } else {
698 rsd[index(c_offset_L, j)] = Lambda(x, j) - Lambda(x, j-1);
699 }
700 diag[index(c_offset_L, j)] = 0;
701 }
702}
703
704void Flow1D::evalEnergy(double* x, double* rsd, int* diag,
705 double rdt, size_t jmin, size_t jmax)
706{
707 if (jmin == 0) { // left boundary
708 rsd[index(c_offset_T, jmin)] = T(x, jmin);
709 }
710
711 if (jmax == m_points - 1) { // right boundary
712 rsd[index(c_offset_T, jmax)] = T(x, jmax);
713 }
714
715 // j0 and j1 are constrained to only interior points
716 size_t j0 = std::max<size_t>(jmin, 1);
717 size_t j1 = std::min(jmax, m_points-2);
718 for (size_t j = j0; j <= j1; j++) {
719 if (m_do_energy[j]) {
720 grad_hk(x, j);
721 double sum = 0.0;
722 for (size_t k = 0; k < m_nsp; k++) {
723 double flxk = 0.5*(m_flux(k, j-1) + m_flux(k, j));
724 sum += m_wdot(k, j)*m_hk(k, j);
725 sum += flxk * m_dhk_dz(k, j) / m_wt[k];
726 }
727
728 rsd[index(c_offset_T, j)] = - m_cp[j]*rho_u(x, j)*dTdz(x, j)
729 - conduction(x, j) - sum;
730 rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]);
731 rsd[index(c_offset_T, j)] -= (m_qdotRadiation[j] / (m_rho[j] * m_cp[j]));
732 if (!m_twoPointControl || (m_z[j] != m_tLeft && m_z[j] != m_tRight)) {
733 rsd[index(c_offset_T, j)] -= rdt*(T(x, j) - T_prev(j));
734 diag[index(c_offset_T, j)] = 1;
735 } else {
736 diag[index(c_offset_T, j)] = 0;
737 }
738 } else {
739 // residual equations if the energy equation is disabled
740 rsd[index(c_offset_T, j)] = T(x, j) - T_fixed(j);
741 diag[index(c_offset_T, j)] = 0;
742 }
743 }
744}
745
746void Flow1D::evalUo(double* x, double* rsd, int* diag,
747 double rdt, size_t jmin, size_t jmax)
748{
749 if (!m_twoPointControl) { // disable this equation
750 for (size_t j = jmin; j <= jmax; j++) {
751 rsd[index(c_offset_Uo, j)] = Uo(x, j);
752 diag[index(c_offset_Uo, j)] = 0;
753 }
754 return;
755 }
756
757 if (jmin == 0) { // left boundary
758 rsd[index(c_offset_Uo, jmin)] = Uo(x, jmin+1) - Uo(x, jmin);
759 diag[index(c_offset_Uo, jmin)] = 0;
760 }
761
762 if (jmax == m_points - 1) { // right boundary
764 rsd[index(c_offset_Uo, jmax)] = Uo(x, jmax) - Uo(x, jmax-1);
765 }
766 diag[index(c_offset_Uo, jmax)] = 0;
767 }
768
769 // j0 and j1 are constrained to only interior points
770 size_t j0 = std::max<size_t>(jmin, 1);
771 size_t j1 = std::min(jmax, m_points-2);
772 for (size_t j = j0; j <= j1; j++) { // interior points
773 if (m_twoPointControl) {
774 if (z(j) == m_zRight) {
775 rsd[index(c_offset_Uo, j)] = T(x, j) - m_tRight;
776 } else if (z(j) > m_zRight) {
777 rsd[index(c_offset_Uo, j)] = Uo(x, j) - Uo(x, j-1);
778 } else if (z(j) < m_zRight) {
779 rsd[index(c_offset_Uo, j)] = Uo(x, j) - Uo(x, j+1);
780 }
781 }
782 diag[index(c_offset_Uo, j)] = 0;
783 }
784}
785
786void Flow1D::evalSpecies(double* x, double* rsd, int* diag,
787 double rdt, size_t jmin, size_t jmax)
788{
789 if (jmin == 0) { // left boundary
790 double sum = 0.0;
791 for (size_t k = 0; k < m_nsp; k++) {
792 sum += Y(x,k,jmin);
793 rsd[index(c_offset_Y+k, jmin)] = -(m_flux(k, jmin) +
794 rho_u(x, jmin) * Y(x, k, jmin));
795 }
796 rsd[index(c_offset_Y + leftExcessSpecies(), jmin)] = 1.0 - sum;
797 diag[index(c_offset_Y + leftExcessSpecies(), jmin)] = 0;
798 }
799
800 if (jmax == m_points - 1) { // right boundary
801 double sum = 0.0;
802 for (size_t k = 0; k < m_nsp; k++) {
803 sum += Y(x,k,jmax);
804 rsd[index(k+c_offset_Y, jmax)] = m_flux(k, jmax-1) +
805 rho_u(x, jmax)*Y(x, k, jmax);
806 }
807 rsd[index(c_offset_Y + rightExcessSpecies(), jmax)] = 1.0 - sum;
808 diag[index(c_offset_Y + rightExcessSpecies(), jmax)] = 0;
809 }
810
811 // j0 and j1 are constrained to only interior points
812 size_t j0 = std::max<size_t>(jmin, 1);
813 size_t j1 = std::min(jmax, m_points-2);
814 for (size_t j = j0; j <= j1; j++) {
815 for (size_t k = 0; k < m_nsp; k++) {
816 double convec = rho_u(x, j)*dYdz(x, k, j);
817 double diffus = 2*(m_flux(k, j) - m_flux(k, j-1)) / (z(j+1) - z(j-1));
818 rsd[index(c_offset_Y + k, j)] = (m_wt[k]*m_wdot(k, j)
819 - convec - diffus) / m_rho[j]
820 - rdt*(Y(x, k, j) - Y_prev(k, j));
821 diag[index(c_offset_Y + k, j)] = 1;
822 }
823 }
824}
825
826void Flow1D::evalElectricField(double* x, double* rsd, int* diag,
827 double rdt, size_t jmin, size_t jmax)
828{
829 for (size_t j = jmin; j <= jmax; j++) {
830 // The same value is used for left/right/interior points
831 rsd[index(c_offset_E, j)] = x[index(c_offset_E, j)];
832 }
833}
834
835void Flow1D::show(const double* x)
836{
837 writelog(" Pressure: {:10.4g} Pa\n", m_press);
838
840
841 if (m_do_radiation) {
842 writeline('-', 79, false, true);
843 writelog("\n z radiative heat loss");
844 writeline('-', 79, false, true);
845 for (size_t j = 0; j < m_points; j++) {
846 writelog("\n {:10.4g} {:10.4g}", m_z[j], m_qdotRadiation[j]);
847 }
848 writelog("\n");
849 }
850}
851
852string Flow1D::componentName(size_t n) const
853{
854 switch (n) {
855 case c_offset_U:
856 return "velocity";
857 case c_offset_V:
858 return "spreadRate";
859 case c_offset_T:
860 return "T";
861 case c_offset_L:
862 return "Lambda";
863 case c_offset_E:
864 return "eField";
865 case c_offset_Uo:
866 return "Uo";
867 default:
868 if (n >= c_offset_Y && n < (c_offset_Y + m_nsp)) {
869 return m_thermo->speciesName(n - c_offset_Y);
870 } else {
871 throw IndexError("Flow1D::componentName", "component", n, m_nv);
872 }
873 }
874}
875
876size_t Flow1D::componentIndex(const string& name, bool checkAlias) const
877{
878 if (componentMap.count(name)) {
879 return componentMap.at(name);
880 }
881 for (size_t n = c_offset_Y; n < m_nsp + c_offset_Y; n++) {
882 if (componentName(n) == name) {
883 return n;
884 }
885 }
886 if (checkAlias) {
887 const auto& aliasMap = _componentAliasMap();
888 if (aliasMap.count(name)) {
889 return componentIndex(aliasMap.at(name), false);
890 }
891 }
892 throw CanteraError("Flow1D::componentIndex",
893 "Component '{}' not found", name);
894}
895
896bool Flow1D::hasComponent(const string& name, bool checkAlias) const
897{
898 if (componentMap.count(name)) {
899 return true;
900 }
901 for (size_t n = c_offset_Y; n < m_nsp + c_offset_Y; n++) {
902 if (componentName(n) == name) {
903 return true;
904 }
905 }
906 if (checkAlias && _componentAliasMap().count(name)) {
907 return true;
908 }
909 return false;
910}
911
912bool Flow1D::componentActive(size_t n) const
913{
914 switch (n) {
915 case c_offset_V: // spreadRate
916 return m_usesLambda;
917 case c_offset_L: // Lambda
918 return m_usesLambda;
919 case c_offset_E: // eField
920 return false;
921 case c_offset_Uo: // oxidizer velocity for two-point control
922 return twoPointControlEnabled();
923 default:
924 return true;
925 }
926}
928{
929 AnyMap state = Domain1D::getMeta();
930 state["transport-model"] = m_trans->transportModel();
931
932 state["phase"]["name"] = m_thermo->name();
933 AnyValue source = m_thermo->input().getMetadata("filename");
934 state["phase"]["source"] = source.empty() ? "<unknown>" : source.asString();
935
936 state["radiation-enabled"] = m_do_radiation;
937 if (m_do_radiation) {
938 state["emissivity-left"] = m_epsilon_left;
939 state["emissivity-right"] = m_epsilon_right;
940 }
941
942 set<bool> energy_flags(m_do_energy.begin(), m_do_energy.end());
943 if (energy_flags.size() == 1) {
944 state["energy-enabled"] = m_do_energy[0];
945 } else {
946 state["energy-enabled"] = m_do_energy;
947 }
948
949 state["Soret-enabled"] = m_do_soret;
950
951 state["flux-gradient-basis"] = static_cast<long int>(m_fluxGradientBasis);
952
953 state["refine-criteria"]["ratio"] = m_refiner->maxRatio();
954 state["refine-criteria"]["slope"] = m_refiner->maxDelta();
955 state["refine-criteria"]["curve"] = m_refiner->maxSlope();
956 state["refine-criteria"]["prune"] = m_refiner->prune();
957 state["refine-criteria"]["grid-min"] = m_refiner->gridMin();
958 state["refine-criteria"]["max-points"] =
959 static_cast<long int>(m_refiner->maxPoints());
960
961 if (m_zfixed != Undef) {
962 state["fixed-point"]["location"] = m_zfixed;
963 state["fixed-point"]["temperature"] = m_tfixed;
964 }
965
966 // Two-point control meta data
967 if (m_twoPointControl) {
968 state["continuation-method"]["type"] = "two-point";
969 state["continuation-method"]["left-location"] = m_zLeft;
970 state["continuation-method"]["right-location"] = m_zRight;
971 state["continuation-method"]["left-temperature"] = m_tLeft;
972 state["continuation-method"]["right-temperature"] = m_tRight;
973 }
974
975 return state;
976}
977
978void Flow1D::updateState(size_t loc)
979{
980 if (!m_state) {
981 throw CanteraError("Flow1D::updateState",
982 "Domain needs to be installed in a container.");
983 }
984 if (!m_solution) {
985 throw CanteraError("Flow1D::updateState",
986 "Domain does not have associated Solution object.");
987 }
988 const double* soln = m_state->data() + m_iloc + m_nv * loc;
989 m_solution->thermo()->setMassFractions_NoNorm(soln + c_offset_Y);
990 m_solution->thermo()->setState_TP(*(soln + c_offset_T), m_press);
991}
992
993void Flow1D::getValues(const string& component, vector<double>& values) const
994{
995 if (!m_state) {
996 throw CanteraError("Flow1D::getValues",
997 "Domain needs to be installed in a container.");
998 }
999 if (values.size() != nPoints()) {
1000 throw ArraySizeError("Flow1D::getValues", values.size(), nPoints());
1001 }
1002 auto i = componentIndex(component);
1003 if (!componentActive(i)) {
1004 warn_user(
1005 "Flow1D::getValues", "Component '{}' is not used by '{}'.",
1006 component, domainType());
1007 }
1008 const double* soln = m_state->data() + m_iloc;
1009 for (size_t j = 0; j < nPoints(); j++) {
1010 values[j] = soln[index(i,j)];
1011 }
1012}
1013
1014void Flow1D::setValues(const string& component, const vector<double>& values)
1015{
1016 if (!m_state) {
1017 throw CanteraError("Flow1D::setValues",
1018 "Domain needs to be installed in a container.");
1019 }
1020 if (values.size() != nPoints()) {
1021 throw ArraySizeError("Flow1D::_etValues", values.size(), nPoints());
1022 }
1023 auto i = componentIndex(component);
1024 if (!componentActive(i)) {
1025 throw CanteraError(
1026 "Flow1D::setValues", "Component '{}' is not used by '{}'.",
1027 component, domainType());
1028 }
1029 double* soln = m_state->data() + m_iloc;
1030 for (size_t j = 0; j < nPoints(); j++) {
1031 soln[index(i,j)] = values[j];
1032 }
1033}
1034
1035void Flow1D::getResiduals(const string& component, vector<double>& values) const
1036{
1037 if (!m_state) {
1038 throw CanteraError("Flow1D::getResiduals",
1039 "Domain needs to be installed in a container.");
1040 }
1041 if (values.size() != nPoints()) {
1042 throw ArraySizeError("Flow1D::getResiduals", values.size(), nPoints());
1043 }
1044 auto i = componentIndex(component);
1045 if (!componentActive(i)) {
1046 warn_user(
1047 "Flow1D::getResiduals", "Component '{}' is not used by '{}'.",
1048 component, domainType());
1049 }
1050 const double* soln = m_container->_workVector().data() + m_iloc;
1051 for (size_t j = 0; j < nPoints(); j++) {
1052 values[j] = soln[index(i,j)];
1053 }
1054}
1055
1056void Flow1D::setProfile(const string& component,
1057 const vector<double>& pos, const vector<double>& values)
1058{
1059 if (!m_state) {
1060 throw CanteraError("Flow1D::setProfile",
1061 "Domain needs to be installed in a container.");
1062 }
1063 if (pos.size() != values.size()) {
1064 throw CanteraError(
1065 "Flow1D::setProfile", "Vectors for positions and values must have same "
1066 "size.\nSizes are {} and {}, respectively.", pos.size(), values.size());
1067 }
1068 if (pos.front() != 0.0 || pos.back() != 1.0) {
1069 throw CanteraError("Flow1D::setProfile",
1070 "'pos' vector must span the range [0, 1]. Got a vector spanning "
1071 "[{}, {}] instead.", pos.front(), pos.back());
1072 }
1073 auto i = componentIndex(component);
1074 if (!componentActive(i)) {
1075 throw CanteraError(
1076 "Flow1D::setProfile", "Component '{}' is not used by '{}'.",
1077 component, domainType());
1078 }
1079 double* soln = m_state->data() + m_iloc;
1080 double z0 = zmin();
1081 double zDelta = zmax() - z0;
1082 for (size_t j = 0; j < nPoints(); j++) {
1083 double frac = (z(j) - z0)/zDelta;
1084 double v = linearInterp(frac, pos, values);
1085 soln[index(i,j)] = v;
1086 }
1087}
1088
1089void Flow1D::setFlatProfile(const string& component, double value)
1090{
1091 if (!m_state) {
1092 throw CanteraError("Flow1D::setFlatProfile",
1093 "Domain needs to be installed in a container.");
1094 }
1095 auto i = componentIndex(component);
1096 if (!componentActive(i)) {
1097 throw CanteraError(
1098 "Flow1D::setFlatProfile", "Component '{}' is not used by '{}'.",
1099 component, domainType());
1100 }
1101 double* soln = m_state->data() + m_iloc;
1102 for (size_t j = 0; j < nPoints(); j++) {
1103 soln[index(i,j)] = value;
1104 }
1105}
1106
1107shared_ptr<SolutionArray> Flow1D::toArray(bool normalize)
1108{
1109 if (!m_state) {
1110 throw CanteraError("Flow1D::toArray",
1111 "Domain needs to be installed in a container before calling toArray.");
1112 }
1113 double* soln = m_state->data() + m_iloc;
1114 auto arr = SolutionArray::create(
1115 m_solution, static_cast<int>(nPoints()), getMeta());
1116 arr->addExtra("grid", false); // leading entry
1118 value = m_z;
1119 arr->setComponent("grid", value);
1120 vector<double> data(nPoints());
1121 for (size_t i = 0; i < nComponents(); i++) {
1122 if (componentActive(i)) {
1123 auto name = componentName(i);
1124 for (size_t j = 0; j < nPoints(); j++) {
1125 data[j] = soln[index(i, j)];
1126 }
1127 if (!arr->hasComponent(name)) {
1128 arr->addExtra(name, componentIndex(name) > c_offset_Y);
1129 }
1130 value = data;
1131 arr->setComponent(name, value);
1132 }
1133 }
1134 updateThermo(soln, 0, m_points-1);
1135 value = m_rho;
1136 arr->setComponent("D", value); // use density rather than pressure
1137
1138 if (m_do_radiation) {
1139 arr->addExtra("radiative-heat-loss", true); // add at end
1141 arr->setComponent("radiative-heat-loss", value);
1142 }
1143
1144 if (normalize) {
1145 arr->normalize();
1146 }
1147 return arr;
1148}
1149
1150void Flow1D::fromArray(const shared_ptr<SolutionArray>& arr)
1151{
1152 if (!m_state) {
1153 throw CanteraError("Domain1D::fromArray",
1154 "Domain needs to be installed in a container before calling fromArray.");
1155 }
1156 resize(nComponents(), arr->size());
1158 double* soln = m_state->data() + m_iloc;
1159
1160 Domain1D::setMeta(arr->meta());
1161 arr->setLoc(0);
1162 auto phase = arr->thermo();
1163 m_press = phase->pressure();
1164
1165 const auto grid = arr->getComponent("grid").as<vector<double>>();
1166 setupGrid(nPoints(), &grid[0]);
1167 setMeta(arr->meta()); // can affect which components are active
1168
1169 for (size_t i = 0; i < nComponents(); i++) {
1170 if (!componentActive(i)) {
1171 continue;
1172 }
1173 string name = componentName(i);
1174 if (arr->hasComponent(name)) {
1175 const vector<double> data = arr->getComponent(name).as<vector<double>>();
1176 for (size_t j = 0; j < nPoints(); j++) {
1177 soln[index(i,j)] = data[j];
1178 }
1179 } else if (name == "Lambda" && arr->hasComponent("lambda")) {
1180 // edge case: 'lambda' is renamed to 'Lambda' in Cantera 3.2
1181 const auto data = arr->getComponent("lambda").as<vector<double>>();
1182 for (size_t j = 0; j < nPoints(); j++) {
1183 soln[index(i,j)] = data[j];
1184 }
1185 } else {
1186 warn_user("Flow1D::fromArray", "Saved state does not contain values for "
1187 "component '{}' in domain '{}'.", name, id());
1188 }
1189 }
1190
1191 updateProperties(npos, soln, 0, m_points - 1);
1192 _finalize(soln);
1193}
1194
1195void Flow1D::setMeta(const AnyMap& state)
1196{
1197 if (state.hasKey("energy-enabled")) {
1198 const AnyValue& ee = state["energy-enabled"];
1199 if (ee.isScalar()) {
1200 m_do_energy.assign(nPoints(), ee.asBool());
1201 } else {
1202 m_do_energy = ee.asVector<bool>(nPoints());
1203 }
1204 }
1205
1206 if (state.hasKey("transport-model")) {
1207 setTransportModel(state["transport-model"].asString());
1208 }
1209
1210 if (state.hasKey("Soret-enabled")) {
1211 m_do_soret = state["Soret-enabled"].asBool();
1212 }
1213
1214 if (state.hasKey("flux-gradient-basis")) {
1215 m_fluxGradientBasis = static_cast<ThermoBasis>(
1216 state["flux-gradient-basis"].asInt());
1217 }
1218
1219 if (state.hasKey("radiation-enabled")) {
1220 m_do_radiation = state["radiation-enabled"].asBool();
1221 if (m_do_radiation) {
1222 m_epsilon_left = state["emissivity-left"].asDouble();
1223 m_epsilon_right = state["emissivity-right"].asDouble();
1224 }
1225 }
1226
1227 if (state.hasKey("refine-criteria")) {
1228 const AnyMap& criteria = state["refine-criteria"].as<AnyMap>();
1229 double ratio = criteria.getDouble("ratio", m_refiner->maxRatio());
1230 double slope = criteria.getDouble("slope", m_refiner->maxDelta());
1231 double curve = criteria.getDouble("curve", m_refiner->maxSlope());
1232 double prune = criteria.getDouble("prune", m_refiner->prune());
1233 m_refiner->setCriteria(ratio, slope, curve, prune);
1234
1235 if (criteria.hasKey("grid-min")) {
1236 m_refiner->setGridMin(criteria["grid-min"].asDouble());
1237 }
1238 if (criteria.hasKey("max-points")) {
1239 m_refiner->setMaxPoints(criteria["max-points"].asInt());
1240 }
1241 }
1242
1243 if (state.hasKey("fixed-point")) {
1244 m_zfixed = state["fixed-point"]["location"].asDouble();
1245 m_tfixed = state["fixed-point"]["temperature"].asDouble();
1246 }
1247
1248 // Two-point control meta data
1249 if (state.hasKey("continuation-method")) {
1250 const AnyMap& cm = state["continuation-method"].as<AnyMap>();
1251 if (cm["type"] == "two-point") {
1252 m_twoPointControl = true;
1253 m_zLeft = cm["left-location"].asDouble();
1254 m_zRight = cm["right-location"].asDouble();
1255 m_tLeft = cm["left-temperature"].asDouble();
1256 m_tRight = cm["right-temperature"].asDouble();
1257 } else {
1258 warn_user("Flow1D::setMeta", "Unknown continuation method '{}'.",
1259 cm["type"].asString());
1260 }
1261 }
1262}
1263
1265{
1266 bool changed = false;
1267 if (j == npos) {
1268 for (size_t i = 0; i < m_points; i++) {
1269 if (!m_do_energy[i]) {
1270 changed = true;
1271 }
1272 m_do_energy[i] = true;
1273 }
1274 } else {
1275 if (!m_do_energy[j]) {
1276 changed = true;
1277 }
1278 m_do_energy[j] = true;
1279 }
1280 m_refiner->setActive(c_offset_U, true);
1281 m_refiner->setActive(c_offset_V, true);
1282 m_refiner->setActive(c_offset_T, true);
1283 if (changed) {
1284 needJacUpdate();
1285 }
1286}
1287
1289{
1290 throw NotImplementedError("Flow1D::getSolvingStage",
1291 "Not used by '{}' objects.", type());
1292}
1293
1294void Flow1D::setSolvingStage(const size_t stage)
1295{
1296 throw NotImplementedError("Flow1D::setSolvingStage",
1297 "Not used by '{}' objects.", type());
1298}
1299
1301{
1302 throw NotImplementedError("Flow1D::solveElectricField",
1303 "Not used by '{}' objects.", type());
1304}
1305
1307{
1308 throw NotImplementedError("Flow1D::fixElectricField",
1309 "Not used by '{}' objects.", type());
1310}
1311
1312bool Flow1D::doElectricField(size_t j) const
1313{
1314 throw NotImplementedError("Flow1D::doElectricField",
1315 "Not used by '{}' objects.", type());
1316}
1317
1318void Flow1D::setBoundaryEmissivities(double e_left, double e_right)
1319{
1320 if (e_left < 0 || e_left > 1) {
1321 throw CanteraError("Flow1D::setBoundaryEmissivities",
1322 "The left boundary emissivity must be between 0.0 and 1.0!");
1323 } else if (e_right < 0 || e_right > 1) {
1324 throw CanteraError("Flow1D::setBoundaryEmissivities",
1325 "The right boundary emissivity must be between 0.0 and 1.0!");
1326 } else {
1327 m_epsilon_left = e_left;
1328 m_epsilon_right = e_right;
1329 }
1330}
1331
1333{
1334 bool changed = false;
1335 if (j == npos) {
1336 for (size_t i = 0; i < m_points; i++) {
1337 if (m_do_energy[i]) {
1338 changed = true;
1339 }
1340 m_do_energy[i] = false;
1341 }
1342 } else {
1343 if (m_do_energy[j]) {
1344 changed = true;
1345 }
1346 m_do_energy[j] = false;
1347 }
1348 m_refiner->setActive(c_offset_U, false);
1349 m_refiner->setActive(c_offset_V, false);
1350 m_refiner->setActive(c_offset_T, false);
1351 if (changed) {
1352 needJacUpdate();
1353 }
1354}
1355
1356void Flow1D::grad_hk(const double* x, size_t j)
1357{
1358 size_t jloc = (u(x, j) > 0.0 ? j : j + 1);
1359 for(size_t k = 0; k < m_nsp; k++) {
1360 m_dhk_dz(k, j) = (m_hk(k, jloc) - m_hk(k, jloc-1))/m_dz[jloc-1];
1361 }
1362}
1363
1364// Two-point control functions
1366{
1367 if (m_twoPointControl) {
1368 if (m_zLeft != Undef) {
1369 return m_tLeft;
1370 } else {
1371 throw CanteraError("Flow1D::leftControlPointTemperature",
1372 "Invalid operation: left control point location is not set");
1373 }
1374 } else {
1375 throw CanteraError("Flow1D::leftControlPointTemperature",
1376 "Invalid operation: two-point control is not enabled.");
1377 }
1378}
1379
1381{
1382 if (m_twoPointControl) {
1383 if (m_zLeft != Undef) {
1384 return m_zLeft;
1385 } else {
1386 throw CanteraError("Flow1D::leftControlPointCoordinate",
1387 "Invalid operation: left control point location is not set");
1388 }
1389 } else {
1390 throw CanteraError("Flow1D::leftControlPointCoordinate",
1391 "Invalid operation: two-point control is not enabled.");
1392 }
1393}
1394
1396{
1397 if (m_twoPointControl) {
1398 if (m_zLeft != Undef) {
1399 m_tLeft = temperature;
1400 } else {
1401 throw CanteraError("Flow1D::setLeftControlPointTemperature",
1402 "Invalid operation: left control point location is not set");
1403 }
1404 } else {
1405 throw CanteraError("Flow1D::setLeftControlPointTemperature",
1406 "Invalid operation: two-point control is not enabled.");
1407 }
1408}
1409
1411{
1412 if (m_twoPointControl) {
1413 m_zLeft = z_left;
1414 } else {
1415 throw CanteraError("Flow1D::setLeftControlPointCoordinate",
1416 "Invalid operation: two-point control is not enabled.");
1417 }
1418}
1419
1421{
1422 if (m_twoPointControl) {
1423 if (m_zRight != Undef) {
1424 return m_tRight;
1425 } else {
1426 throw CanteraError("Flow1D::rightControlPointTemperature",
1427 "Invalid operation: right control point location is not set");
1428 }
1429 } else {
1430 throw CanteraError("Flow1D::rightControlPointTemperature",
1431 "Invalid operation: two-point control is not enabled.");
1432 }
1433}
1434
1436{
1437 if (m_twoPointControl) {
1438 if (m_zRight != Undef) {
1439 return m_zRight;
1440 } else {
1441 throw CanteraError("Flow1D::rightControlPointCoordinate",
1442 "Invalid operation: right control point location is not set");
1443 }
1444 } else {
1445 throw CanteraError("Flow1D::rightControlPointCoordinate",
1446 "Invalid operation: two-point control is not enabled.");
1447 }
1448}
1449
1451{
1452 if (m_twoPointControl) {
1453 if (m_zRight != Undef) {
1454 m_tRight = temperature;
1455 } else {
1456 throw CanteraError("Flow1D::setRightControlPointTemperature",
1457 "Invalid operation: right control point location is not set");
1458 }
1459 } else {
1460 throw CanteraError("Flow1D::setRightControlPointTemperature",
1461 "Invalid operation: two-point control is not enabled.");
1462 }
1463}
1464
1466{
1467 if (m_twoPointControl) {
1468 m_zRight = z_right;
1469 } else {
1470 throw CanteraError("Flow1D::setRightControlPointCoordinate",
1471 "Invalid operation: two-point control is not enabled.");
1472 }
1473}
1474
1475void Flow1D::enableTwoPointControl(bool twoPointControl)
1476{
1477 if (isStrained()) {
1478 m_twoPointControl = twoPointControl;
1479 // Prevent finding spurious solutions with negative velocity (outflow) at either
1480 // inlet.
1481 setBounds(c_offset_V, -1e-5, 1e20);
1482 } else {
1483 throw CanteraError("Flow1D::enableTwoPointControl",
1484 "Invalid operation: two-point control can only be used"
1485 "with axisymmetric flames.");
1486 }
1487}
1488
1489} // namespace
Header file defining class TransportFactory (see TransportFactory)
Headers for the Transport object, which is the virtual base class for all transport property evaluato...
const AnyValue & getMetadata(const string &key) const
Get a value from the metadata applicable to the AnyMap tree containing this node.
Definition AnyMap.cpp:623
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
double getDouble(const string &key, double default_) const
If key exists, return it as a double, otherwise return default_.
Definition AnyMap.cpp:1580
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:88
const string & asString() const
Return the held value, if it is a string.
Definition AnyMap.cpp:782
bool & asBool()
Return the held value, if it is a bool.
Definition AnyMap.cpp:914
bool empty() const
Return boolean indicating whether AnyValue is empty.
Definition AnyMap.cpp:690
bool isScalar() const
Returns true if the held value is a scalar type (such as double, long int, string,...
Definition AnyMap.cpp:694
const vector< T > & asVector(size_t nMin=npos, size_t nMax=npos) const
Return the held value, if it is a vector of type T.
Definition AnyMap.inl.h:109
double * ptrColumn(size_t j)
Return a pointer to the top of column j, columns are contiguous in memory.
Definition Array.h:203
virtual void resize(size_t n, size_t m, double v=0.0)
Resize the array, and fill the new entries with 'v'.
Definition Array.cpp:47
Array size error.
Base class for exceptions thrown by Cantera classes.
Base class for one-dimensional domains.
Definition Domain1D.h:29
size_t lastPoint() const
The index of the last (that is, right-most) grid point belonging to this domain.
Definition Domain1D.h:667
size_t m_iloc
Starting location within the solution vector for unknowns that correspond to this domain.
Definition Domain1D.h:845
shared_ptr< Solution > m_solution
Composite thermo/kinetics/transport handler.
Definition Domain1D.h:862
OneDim * m_container
Parent OneDim simulation containing this and adjacent domains.
Definition Domain1D.h:836
size_t nComponents() const
Number of components at each grid point.
Definition Domain1D.h:174
virtual void setMeta(const AnyMap &meta)
Retrieve meta data.
Definition Domain1D.cpp:171
string id() const
Returns the identifying tag for this domain.
Definition Domain1D.h:718
vector< double > & grid()
Access the array of grid coordinates [m].
Definition Domain1D.h:754
double zmin() const
Get the coordinate [m] of the first (leftmost) grid point in this domain.
Definition Domain1D.h:736
size_t m_nv
Number of solution components.
Definition Domain1D.h:824
size_t nPoints() const
Number of grid points in this domain.
Definition Domain1D.h:202
bool m_force_full_update
see forceFullUpdate()
Definition Domain1D.h:859
shared_ptr< vector< double > > m_state
data pointer shared from OneDim
Definition Domain1D.h:821
vector< double > values(const string &component) const
Retrieve component values.
Definition Domain1D.h:459
virtual void resize(size_t nv, size_t np)
Resize the domain to have nv components and np grid points.
Definition Domain1D.cpp:52
double z(size_t jlocal) const
Get the coordinate [m] of the point with local index jlocal
Definition Domain1D.h:731
virtual void show(const double *x)
Print the solution.
Definition Domain1D.cpp:248
void setSolution(shared_ptr< Solution > sol)
Set the solution manager.
Definition Domain1D.cpp:31
vector< double > m_z
1D spatial grid coordinates
Definition Domain1D.h:833
size_t m_points
Number of grid points.
Definition Domain1D.h:825
string m_id
Identity tag for the domain.
Definition Domain1D.h:855
string type() const
String indicating the domain implemented.
Definition Domain1D.h:51
unique_ptr< Refiner > m_refiner
Refiner object used for placing grid points.
Definition Domain1D.h:856
void setBounds(size_t n, double lower, double upper)
Set the upper and lower bounds for a solution component, n.
Definition Domain1D.h:268
double value(const double *x, size_t n, size_t j) const
Returns the value of solution component n at grid point j of the solution vector x.
Definition Domain1D.h:423
double zmax() const
Get the coordinate [m] of the last (rightmost) grid point in this domain.
Definition Domain1D.h:741
size_t firstPoint() const
The index of the first (that is, left-most) grid point belonging to this domain.
Definition Domain1D.h:662
void needJacUpdate()
Set this if something has changed in the governing equations (for example, the value of a constant ha...
Definition Domain1D.cpp:135
size_t index(size_t n, size_t j) const
Returns the index of the solution vector, which corresponds to component n at grid point j.
Definition Domain1D.h:408
virtual size_t loc(size_t j=0) const
Location of the start of the local solution vector in the global solution vector.
Definition Domain1D.h:657
virtual AnyMap getMeta() const
Retrieve meta data.
Definition Domain1D.cpp:143
This class represents 1D flow domains that satisfy the one-dimensional similarity solution for chemic...
Definition Flow1D.h:47
double dYdz(const double *x, size_t k, size_t j) const
Calculates the spatial derivative of the species mass fraction with respect to z for species k at po...
Definition Flow1D.h:833
void setLeftControlPointTemperature(double temperature)
Sets the temperature of the left control point.
Definition Flow1D.cpp:1395
ThermoPhase * m_thermo
Phase object used for calculating thermodynamic properties.
Definition Flow1D.h:969
void eval(size_t jGlobal, double *xGlobal, double *rsdGlobal, integer *diagGlobal, double rdt) override
Evaluate the residual functions for axisymmetric stagnation flow.
Definition Flow1D.cpp:361
void setLeftControlPointCoordinate(double z_left)
Sets the coordinate of the left control point.
Definition Flow1D.cpp:1410
double dTdz(const double *x, size_t j) const
Calculates the spatial derivative of temperature T with respect to z at point j using upwind differen...
Definition Flow1D.h:847
vector< double > m_zfix
Relative coordinates used to specify a fixed temperature profile.
Definition Flow1D.h:1048
double density(size_t j) const
Get the density [kg/m³] at point j
Definition Flow1D.h:425
size_t m_kExcessLeft
Index of species with a large mass fraction at the left boundary, for which the mass fraction may be ...
Definition Flow1D.h:1056
void setMeta(const AnyMap &state) override
Retrieve meta data.
Definition Flow1D.cpp:1195
void setValues(const string &component, const vector< double > &values) override
Specify component values.
Definition Flow1D.cpp:1014
double m_zLeft
Location of the left control point when two-point control is enabled.
Definition Flow1D.h:1063
void fixTemperature(size_t j=npos)
Specify that the the temperature should be held fixed at point j.
Definition Flow1D.cpp:1332
void getValues(const string &component, vector< double > &values) const override
Retrieve component values.
Definition Flow1D.cpp:993
vector< double > m_tfix
Fixed temperature values at the relative coordinates specified in m_zfix.
Definition Flow1D.h:1052
void setRightControlPointCoordinate(double z_right)
Sets the coordinate of the right control point.
Definition Flow1D.cpp:1465
double X(const double *x, size_t k, size_t j) const
Get the mole fraction of species k at point j from the local state vector x.
Definition Flow1D.h:780
void setTransport(shared_ptr< Transport > trans) override
Set the transport manager used for transport property calculations.
Definition Flow1D.cpp:177
ThermoPhase & phase()
Access the phase object used to compute thermodynamic properties for points in this domain.
Definition Flow1D.h:93
void setKinetics(shared_ptr< Kinetics > kin) override
Set the Kinetics object used for reaction rate calculations.
Definition Flow1D.cpp:163
double T_prev(size_t j) const
Get the temperature at point j from the previous time step.
Definition Flow1D.h:717
void resetBadValues(double *xg) override
When called, this function should reset "bad" values in the state vector such as negative species con...
Definition Flow1D.cpp:246
bool twoPointControlEnabled() const
Returns the status of the two-point control.
Definition Flow1D.h:403
size_t rightExcessSpecies() const
Index of the species on the right boundary with the largest mass fraction.
Definition Flow1D.h:484
bool m_do_soret
true if the Soret diffusion term should be calculated.
Definition Flow1D.h:998
Kinetics * m_kin
Kinetics object used for calculating species production rates.
Definition Flow1D.h:972
vector< double > m_qdotRadiation
radiative heat loss vector
Definition Flow1D.h:1033
virtual void evalMomentum(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the momentum equation residual.
Definition Flow1D.cpp:625
size_t componentIndex(const string &name, bool checkAlias=true) const override
Index of component with name name.
Definition Flow1D.cpp:876
void updateThermo(const double *x, size_t j0, size_t j1)
Update the thermodynamic properties from point j0 to point j1 (inclusive), based on solution x.
Definition Flow1D.h:511
double m_tLeft
Temperature of the left control point when two-point control is enabled.
Definition Flow1D.h:1066
void setRightControlPointTemperature(double temperature)
Sets the temperature of the right control point.
Definition Flow1D.cpp:1450
bool hasComponent(const string &name, bool checkAlias=true) const override
Check whether the Domain contains a component.
Definition Flow1D.cpp:896
void resize(size_t components, size_t points) override
Change the grid size. Called after grid refinement.
Definition Flow1D.cpp:205
double dVdz(const double *x, size_t j) const
Calculates the spatial derivative of velocity V with respect to z at point j using upwind differencin...
Definition Flow1D.h:818
bool m_usesLambda
Flag that is true for counterflow configurations that use the pressure eigenvalue in the radial mome...
Definition Flow1D.h:1026
vector< double > m_fixedtemp
Fixed values of the temperature at each grid point that are used when solving with the energy equatio...
Definition Flow1D.h:1041
virtual void evalContinuity(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the continuity equation residual.
Definition Flow1D.cpp:568
vector< double > m_cp
Specific heat capacity at each grid point.
Definition Flow1D.h:933
void enableTwoPointControl(bool twoPointControl)
Sets the status of the two-point control.
Definition Flow1D.cpp:1475
double m_tRight
Temperature of the right control point when two-point control is enabled.
Definition Flow1D.h:1072
void setBoundaryEmissivities(double e_left, double e_right)
Set the emissivities for the boundary values.
Definition Flow1D.cpp:1318
double shear(const double *x, size_t j) const
Compute the shear term from the momentum equation using a central three-point differencing scheme.
Definition Flow1D.h:875
ThermoBasis m_fluxGradientBasis
Determines whether diffusive fluxes are computed using gradients of mass fraction or mole fraction.
Definition Flow1D.h:1003
void setFluxGradientBasis(ThermoBasis fluxGradientBasis)
Compute species diffusive fluxes with respect to their mass fraction gradients (fluxGradientBasis = T...
Definition Flow1D.cpp:270
shared_ptr< SolutionArray > toArray(bool normalize=false) override
Save the state of this domain to a SolutionArray.
Definition Flow1D.cpp:1107
virtual void evalEnergy(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the energy equation residual.
Definition Flow1D.cpp:704
void solveEnergyEqn(size_t j=npos)
Specify that the energy equation should be solved at point j.
Definition Flow1D.cpp:1264
vector< double > m_rho
Density at each grid point.
Definition Flow1D.h:930
void _setTransport(shared_ptr< Transport > trans) override
Update transport model to existing instance.
Definition Flow1D.cpp:185
vector< bool > m_do_energy
For each point in the domain, true if energy equation is solved or false if temperature is held const...
Definition Flow1D.h:995
double m_epsilon_right
Emissivity of the surface to the right of the domain.
Definition Flow1D.h:983
Flow1D(ThermoPhase *ph=0, size_t nsp=1, size_t points=1)
Create a new flow domain.
Definition Flow1D.cpp:32
virtual bool doElectricField(size_t j=npos) const
Retrieve flag indicating whether electric field is solved or not (used by IonFlow specialization)
Definition Flow1D.cpp:1312
vector< double > m_tcon
Thermal conductivity at each grid point [W/m/K].
Definition Flow1D.h:937
vector< double > m_diff
Coefficient used in diffusion calculations for each species at each grid point.
Definition Flow1D.h:945
double Y_prev(size_t k, size_t j) const
Get the mass fraction of species k at point j from the previous time step.
Definition Flow1D.h:774
void getResiduals(const string &component, vector< double > &values) const override
Retrieve internal work array values for a component.
Definition Flow1D.cpp:1035
vector< double > m_dz
Grid spacing. Element j holds the value of z(j+1) - z(j).
Definition Flow1D.h:927
Array2D m_flux
Array of size m_nsp by m_points for saving diffusive mass fluxes.
Definition Flow1D.h:955
void setGas(const double *x, size_t j)
Set the gas object state to be consistent with the solution at point j.
Definition Flow1D.cpp:289
ThermoBasis fluxGradientBasis() const
Compute species diffusive fluxes with respect to their mass fraction gradients (fluxGradientBasis = T...
Definition Flow1D.h:149
vector< double > m_visc
Dynamic viscosity at each grid point [Pa∙s].
Definition Flow1D.h:936
double Uo(const double *x, size_t j) const
Get the oxidizer inlet velocity [m/s] linked to point j from the local state vector x.
Definition Flow1D.h:757
double m_epsilon_left
Emissivity of the surface to the left of the domain.
Definition Flow1D.h:979
Transport * m_trans
Transport object used for calculating transport properties.
Definition Flow1D.h:975
double m_tfixed
Temperature at the point used to fix the flame location.
Definition Flow1D.h:1079
virtual bool componentActive(size_t n) const
Returns true if the specified component is an active part of the solver state.
Definition Flow1D.cpp:912
void _init(ThermoPhase *ph, size_t nsp, size_t points)
Initialize arrays.
Definition Flow1D.cpp:41
Array2D m_wdot
Array of size m_nsp by m_points for saving species production rates.
Definition Flow1D.h:964
Array2D m_hk
Array of size m_nsp by m_points for saving molar enthalpies.
Definition Flow1D.h:958
double m_press
pressure [Pa]
Definition Flow1D.h:924
void _setKinetics(shared_ptr< Kinetics > kin) override
Update transport model to existing instance.
Definition Flow1D.cpp:171
double lambda(const double *x, size_t j) const
Get the radial pressure gradient [N/m⁴] at point j from the local state vector x
Definition Flow1D.cpp:147
virtual void evalSpecies(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the species equations' residuals.
Definition Flow1D.cpp:786
void fromArray(const shared_ptr< SolutionArray > &arr) override
Restore the solution for this domain from a SolutionArray.
Definition Flow1D.cpp:1150
size_t mindex(size_t k, size_t j, size_t m)
Array access mapping for a 3D array stored in a 1D vector.
Definition Flow1D.h:904
void updateState(size_t loc) override
Update state at given location to state of associated Solution object.
Definition Flow1D.cpp:978
bool m_do_multicomponent
true if transport fluxes are computed using the multicomponent diffusion coefficients,...
Definition Flow1D.h:1007
double V_prev(size_t j) const
Get the spread rate [1/s] at point j from the previous time step.
Definition Flow1D.h:738
double conduction(const double *x, size_t j) const
Compute the conduction term from the energy equation using a central three-point differencing scheme.
Definition Flow1D.h:890
vector< double > m_wt
Molecular weight of each species.
Definition Flow1D.h:932
double Y(const double *x, size_t k, size_t j) const
Get the mass fraction of species k at point j from the local state vector x.
Definition Flow1D.h:763
void setupGrid(size_t n, const double *z) override
called to set up initial grid, and after grid refinement
Definition Flow1D.cpp:231
double T(const double *x, size_t j) const
Get the temperature at point j from the local state vector x.
Definition Flow1D.h:708
size_t leftExcessSpecies() const
Index of the species on the left boundary with the largest mass fraction.
Definition Flow1D.h:479
bool m_isFree
Flag that is true for freely propagating flames anchored by a temperature fixed point.
Definition Flow1D.h:1021
Array2D m_dhk_dz
Array of size m_nsp by m_points-1 for saving enthalpy fluxes.
Definition Flow1D.h:961
virtual void evalElectricField(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the electric field equation residual to be zero everywhere.
Definition Flow1D.cpp:826
vector< double > m_wtm
Mean molecular weight at each grid point.
Definition Flow1D.h:931
vector< double > m_multidiff
Vector of size m_nsp × m_nsp × m_points for saving multicomponent diffusion coefficients.
Definition Flow1D.h:949
bool m_twoPointControl
Flag for activating two-point flame control.
Definition Flow1D.h:1029
double m_zfixed
Location of the point where temperature is fixed.
Definition Flow1D.h:1076
void _finalize(const double *x) override
In some cases, a domain may need to set parameters that depend on the initial solution estimate.
Definition Flow1D.cpp:309
virtual size_t getSolvingStage() const
Get the solving stage (used by IonFlow specialization)
Definition Flow1D.cpp:1288
size_t m_nsp
Number of species in the mechanism.
Definition Flow1D.h:966
virtual void evalLambda(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the radial pressure gradient equation residual.
Definition Flow1D.cpp:661
double rho_u(const double *x, size_t j) const
Get the axial mass flux [kg/m²/s] at point j from the local state vector x.
Definition Flow1D.h:722
double leftControlPointCoordinate() const
Returns the z-coordinate of the left control point.
Definition Flow1D.cpp:1380
void setProfile(const string &component, const vector< double > &pos, const vector< double > &values) override
Specify a profile for a component.
Definition Flow1D.cpp:1056
AnyMap getMeta() const override
Retrieve meta data.
Definition Flow1D.cpp:927
virtual void updateDiffFluxes(const double *x, size_t j0, size_t j1)
Update the diffusive mass fluxes.
Definition Flow1D.cpp:475
double leftControlPointTemperature() const
Returns the temperature at the left control point.
Definition Flow1D.cpp:1365
string componentName(size_t n) const override
Name of component n. May be overloaded.
Definition Flow1D.cpp:852
void setGasAtMidpoint(const double *x, size_t j)
Set the gas state to be consistent with the solution at the midpoint between j and j + 1.
Definition Flow1D.cpp:297
virtual void grad_hk(const double *x, size_t j)
Compute the spatial derivative of species specific molar enthalpies using upwind differencing.
Definition Flow1D.cpp:1356
bool isStrained() const
Retrieve flag indicating whether flow uses radial momentum.
Definition Flow1D.h:446
string transportModel() const
Retrieve transport model.
Definition Flow1D.cpp:266
double rightControlPointCoordinate() const
Returns the z-coordinate of the right control point.
Definition Flow1D.cpp:1435
double V(const double *x, size_t j) const
Get the spread rate (tangential velocity gradient) [1/s] at point j from the local state vector x.
Definition Flow1D.h:733
Array2D m_dthermal
Array of size m_nsp by m_points for saving thermal diffusion coefficients.
Definition Flow1D.h:952
void computeRadiation(double *x, size_t jmin, size_t jmax)
Computes the radiative heat loss vector over points jmin to jmax and stores the data in the qdotRadia...
Definition Flow1D.cpp:521
virtual void updateProperties(size_t jg, double *x, size_t jmin, size_t jmax)
Update the properties (thermo, transport, and diffusion flux).
Definition Flow1D.cpp:400
double Lambda(const double *x, size_t j) const
Get the radial pressure gradient [N/m⁴] at point j from the local state vector x
Definition Flow1D.h:749
virtual void evalUo(double *x, double *rsd, int *diag, double rdt, size_t jmin, size_t jmax)
Evaluate the oxidizer axial velocity equation residual.
Definition Flow1D.cpp:746
string domainType() const override
Domain type flag.
Definition Flow1D.cpp:153
void show(const double *x) override
Print the solution.
Definition Flow1D.cpp:835
bool m_dovisc
Determines whether the viscosity term in the momentum equation is calculated.
Definition Flow1D.h:1016
virtual void setSolvingStage(const size_t stage)
Solving stage mode for handling ionized species (used by IonFlow specialization)
Definition Flow1D.cpp:1294
void setPressure(double p)
Set the pressure.
Definition Flow1D.h:155
virtual void fixElectricField(size_t j=npos)
Set to fix voltage in a point (used by IonFlow specialization)
Definition Flow1D.cpp:1306
virtual void updateTransport(double *x, size_t j0, size_t j1)
Update the transport properties at grid points in the range from j0 to j1, based on solution x.
Definition Flow1D.cpp:424
double m_zRight
Location of the right control point when two-point control is enabled.
Definition Flow1D.h:1069
virtual void solveElectricField(size_t j=npos)
Set to solve electric field in a point (used by IonFlow specialization)
Definition Flow1D.cpp:1300
double u(const double *x, size_t j) const
Get the axial velocity [m/s] at point j from the local state vector x.
Definition Flow1D.h:727
size_t m_kExcessRight
Index of species with a large mass fraction at the right boundary, for which the mass fraction may be...
Definition Flow1D.h:1060
void _getInitialSoln(double *x) override
Write the initial solution estimate into array x.
Definition Flow1D.cpp:280
vector< size_t > m_kRadiating
Indices within the ThermoPhase of the radiating species.
Definition Flow1D.h:987
void setTransportModel(const string &model) override
Set transport model by name.
Definition Flow1D.cpp:256
void setFlatProfile(const string &component, double value) override
Specify a flat profile for a component.
Definition Flow1D.cpp:1089
double rightControlPointTemperature() const
Returns the temperature at the right control point.
Definition Flow1D.cpp:1420
double T_fixed(size_t j) const
The fixed temperature value at point j.
Definition Flow1D.h:193
vector< double > m_ybar
Holds the average of the species mass fractions between grid points j and j+1.
Definition Flow1D.h:1085
bool m_do_radiation
Determines whether radiative heat loss is calculated.
Definition Flow1D.h:1011
An array index is out of range.
An error indicating that an unimplemented function has been called.
void resize() override
Call to set the size of internal data structures after first defining the system or if the problem si...
Definition OneDim.cpp:189
const vector< double > & _workVector() const
Access internal work array.
Definition OneDim.h:253
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:270
virtual void setMassFractions_NoNorm(const double *const y)
Set the mass fractions to the specified values without normalizing.
Definition Phase.cpp:413
double temperature() const
Temperature (K).
Definition Phase.h:629
virtual void setPressure(double p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition Phase.h:683
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition Phase.h:722
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:174
const vector< double > & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:460
size_t speciesIndex(const string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:147
virtual double density() const
Density (kg/m^3).
Definition Phase.h:654
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
Definition Phase.h:690
virtual void setMassFractions(const double *const y)
Set the mass fractions to the specified values and normalize them.
Definition Phase.cpp:399
void getMassFractions(double *const y) const
Get the species mass fractions.
Definition Phase.cpp:536
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:647
string name() const
Return the name of the phase.
Definition Phase.cpp:20
static shared_ptr< SolutionArray > create(const shared_ptr< Solution > &sol, int size=0, const AnyMap &meta={})
Instantiate a new SolutionArray reference.
static shared_ptr< Solution > create()
Create an empty Solution object.
Definition Solution.h:54
Base class for a phase with thermodynamic properties.
virtual double maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
const AnyMap & input() const
Access input data associated with the phase description.
virtual void getThermalDiffCoeffs(double *const dt)
Return a vector of thermal diffusion coefficients [kg/m/s].
Definition Transport.h:269
virtual string transportModel() const
Identifies the model represented by this Transport object.
Definition Transport.h:101
virtual void getMixDiffCoeffs(double *const d)
Return a vector of mixture averaged diffusion coefficients [m²/s].
Definition Transport.h:319
virtual double thermalConductivity()
Get the mixture thermal conductivity [W/m/K].
Definition Transport.h:158
virtual void getMixDiffCoeffsMass(double *const d)
Returns a vector of mixture averaged diffusion coefficients [m²/s].
Definition Transport.h:331
virtual double viscosity()
Get the dynamic viscosity [Pa·s].
Definition Transport.h:132
virtual void getMultiDiffCoeffs(const size_t ld, double *const d)
Return the multicomponent diffusion coefficients [m²/s].
Definition Transport.h:304
Header for a file containing miscellaneous numerical functions.
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:176
double linearInterp(double x, const vector< double > &xpts, const vector< double > &fpts)
Linearly interpolate a function defined on a discrete grid.
Definition funcs.cpp:13
const double OneAtm
One atmosphere [Pa].
Definition ct_defs.h:96
const double StefanBoltz
Stefan-Boltzmann constant [W/m2/K4].
Definition ct_defs.h:128
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Definition global.h:268
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180
const map< string, string > & _componentAliasMap()
Return mapping of component alias names to standardized component names.
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition ct_defs.h:164
@ c_offset_U
axial velocity [m/s]
Definition Flow1D.h:26
@ c_offset_L
(1/r)dP/dr
Definition Flow1D.h:29
@ c_offset_V
strain rate
Definition Flow1D.h:27
@ c_offset_E
electric field
Definition Flow1D.h:30
@ c_offset_Y
mass fractions
Definition Flow1D.h:32
@ c_offset_Uo
oxidizer axial velocity [m/s]
Definition Flow1D.h:31
@ c_offset_T
temperature [kelvin]
Definition Flow1D.h:28
ThermoBasis
Differentiate between mole fractions and mass fractions for input mixture composition.
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997