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