Cantera  3.3.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
39
40 // set pressure based on associated thermo object
42
43 // the species mass fractions are the last components in the solution
44 // vector, so the total number of components is the number of species
45 // plus the offset of the first mass fraction.
47
48 // Turn off the energy equation at all points
49 m_do_energy.resize(m_points,false);
50
51 m_diff.resize(m_nsp*m_points);
56 m_dhk_dz.resize(m_nsp, m_points - 1, 0.0);
57 m_ybar.resize(m_nsp);
58 m_qdotRadiation.resize(m_points, 0.0);
59
60 //-------------- default solution bounds --------------------
61 setBounds(c_offset_U, -1e20, 1e20); // no bounds on u
62 setBounds(c_offset_V, -1e20, 1e20); // no bounds on V
63 setBounds(c_offset_T, 200.0, 2*m_thermo->maxTemp()); // temperature bounds
64 setBounds(c_offset_L, -1e20, 1e20); // Lambda should be negative
65 setBounds(c_offset_E, -1e20, 1e20); // no bounds on electric field
66 setBounds(c_offset_Uo, -1e20, 1e20); // no bounds on Uo
67 // mass fraction bounds
68 for (size_t k = 0; k < m_nsp; k++) {
69 setBounds(c_offset_Y+k, -1.0e-7, 1.0e5);
70 }
71
72 //-------------------- grid refinement -------------------------
73 m_refiner->setActive(c_offset_U, false);
74 m_refiner->setActive(c_offset_V, false);
75 m_refiner->setActive(c_offset_T, false);
76 m_refiner->setActive(c_offset_L, false);
77 m_refiner->setActive(c_offset_Uo, false);
78
79 vector<double> gr;
80 for (size_t ng = 0; ng < m_points; ng++) {
81 gr.push_back(1.0*ng/m_points);
82 }
83 setupGrid(m_points, gr.data());
84
85 // Find indices for radiating species
86 m_kRadiating.resize(2, npos);
87 m_kRadiating[0] = m_thermo->speciesIndex("CO2", false);
88 m_kRadiating[1] = m_thermo->speciesIndex("H2O", false);
89
91 m_solution->thermo()->addSpeciesLock();
92 m_id = id;
93 m_kin = m_solution->kinetics().get();
94 m_trans = m_solution->transport().get();
95 if (m_trans->transportModel() == "none") {
96 throw CanteraError("Flow1D::Flow1D",
97 "An appropriate transport model\nshould be set when instantiating the "
98 "Solution ('gas') object.");
99 }
100 m_solution->registerChangedCallback(this, [this]() {
101 _setKinetics(m_solution->kinetics());
102 _setTransport(m_solution->transport());
103 });
104}
105
106Flow1D::~Flow1D()
107{
108 if (m_solution) {
109 m_solution->removeChangedCallback(this);
110 }
111}
112
113string Flow1D::domainType() const {
114 if (m_isFree) {
115 return "free-flow";
116 }
117 if (m_usesLambda) {
118 return "axisymmetric-flow";
119 }
120 return "unstrained-flow";
121}
122
123void Flow1D::_setKinetics(shared_ptr<Kinetics> kin)
124{
125 m_kin = kin.get();
126 m_solution->setKinetics(kin);
127}
128
129void Flow1D::_setTransport(shared_ptr<Transport> trans)
130{
131 if (!trans) {
132 throw CanteraError("Flow1D::_setTransport", "Unable to set empty transport.");
133 }
134 m_trans = trans.get();
135 if (m_trans->transportModel() == "none") {
136 throw CanteraError("Flow1D::_setTransport", "Invalid Transport model 'none'.");
137 }
138 m_do_multicomponent = (m_trans->transportModel() == "multicomponent" ||
139 m_trans->transportModel() == "multicomponent-CK");
140
141 m_diff.resize(m_nsp * m_points);
144 }
146 m_solution->setTransport(trans);
147}
148
149void Flow1D::resize(size_t ncomponents, size_t points)
150{
151 Domain1D::resize(ncomponents, points);
152 m_rho.resize(m_points, 0.0);
153 m_wtm.resize(m_points, 0.0);
154 m_cp.resize(m_points, 0.0);
155 m_visc.resize(m_points, 0.0);
156 m_tcon.resize(m_points, 0.0);
157
158 m_diff.resize(m_nsp*m_points);
161 }
165 m_hk.resize(m_nsp, m_points, 0.0);
166 m_dhk_dz.resize(m_nsp, m_points - 1, 0.0);
167 m_do_energy.resize(m_points,false);
168 m_qdotRadiation.resize(m_points, 0.0);
169 m_fixedtemp.resize(m_points);
170
171 m_dz.resize(m_points-1);
172 m_z.resize(m_points);
173}
174
175void Flow1D::setupGrid(size_t n, const double* z)
176{
177 resize(m_nv, n);
178
179 m_z[0] = z[0];
180 for (size_t j = 1; j < m_points; j++) {
181 if (z[j] <= z[j-1]) {
182 throw CanteraError("Flow1D::setupGrid",
183 "grid points must be monotonically increasing");
184 }
185 m_z[j] = z[j];
186 m_dz[j-1] = m_z[j] - m_z[j-1];
187 }
188}
189
191{
192 double* x = xg + loc();
193 for (size_t j = 0; j < m_points; j++) {
194 double* Y = x + m_nv*j + c_offset_Y;
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
225{
226 for (size_t j = 0; j < m_points; j++) {
227 T(x,j) = m_thermo->temperature();
228 m_thermo->getMassFractions(&Y(x, 0, j));
229 m_rho[j] = m_thermo->density();
230 }
231}
232
233void Flow1D::setGas(const double* x, size_t j)
234{
236 const double* yy = x + m_nv*j + c_offset_Y;
239}
240
241void Flow1D::setGasAtMidpoint(const double* x, size_t j)
242{
243 m_thermo->setTemperature(0.5*(T(x,j)+T(x,j+1)));
244 const double* yy_j = x + m_nv*j + c_offset_Y;
245 const double* yy_j_plus1 = x + m_nv*(j+1) + c_offset_Y;
246 for (size_t k = 0; k < m_nsp; k++) {
247 m_ybar[k] = 0.5*(yy_j[k] + yy_j_plus1[k]);
248 }
251}
252
253void Flow1D::_finalize(const double* x)
254{
255 if (!(m_do_multicomponent ||
256 m_trans->transportModel() == "mixture-averaged" ||
257 m_trans->transportModel() == "mixture-averaged-CK")
258 && m_do_soret) {
259
260 throw CanteraError("Flow1D::_finalize",
261 "Thermal diffusion (the Soret effect) is enabled, but it "
262 "only ompatible with the mixture-averaged and multicomponent "
263 "transport models.");
264 }
265
266 size_t nz = m_zfix.size();
267 bool e = m_do_energy[0];
268 for (size_t j = 0; j < m_points; j++) {
269 if (e || nz == 0) {
270 m_fixedtemp[j] = T(x, j);
271 } else {
272 double zz = (z(j) - z(0))/(z(m_points - 1) - z(0));
273 double tt = linearInterp(zz, m_zfix, m_tfix);
274 m_fixedtemp[j] = tt;
275 }
276 }
277 if (e) {
279 }
280
281 if (m_isFree) {
282 // If the domain contains the temperature fixed point, make sure that it
283 // is correctly set. This may be necessary when the grid has been modified
284 // externally.
285 if (m_tfixed != Undef) {
286 for (size_t j = 0; j < m_points; j++) {
287 if (z(j) == m_zfixed) {
288 return; // fixed point is already set correctly
289 }
290 }
291
292 for (size_t j = 0; j < m_points - 1; j++) {
293 // Find where the temperature profile crosses the current
294 // fixed temperature.
295 if ((T(x, j) - m_tfixed) * (T(x, j+1) - m_tfixed) <= 0.0) {
296 m_tfixed = T(x, j+1);
297 m_zfixed = z(j+1);
298 return;
299 }
300 }
301 }
302 }
303}
304
305void Flow1D::eval(size_t jGlobal, double* xGlobal, double* rsdGlobal,
306 integer* diagGlobal, double rdt)
307{
308 // If evaluating a Jacobian, and the global point is outside the domain of
309 // influence for this domain, then skip evaluating the residual
310 if (jGlobal != npos && (jGlobal + 1 < firstPoint() || jGlobal > lastPoint() + 1)) {
311 return;
312 }
313
314 // start of local part of global arrays
315 double* x = xGlobal + loc();
316 double* rsd = rsdGlobal + loc();
317 integer* diag = diagGlobal + loc();
318
319 size_t jmin, jmax;
320 if (jGlobal == npos) { // evaluate all points
321 jmin = 0;
322 jmax = m_points - 1;
323 } else { // evaluate points for Jacobian
324 size_t jpt = (jGlobal == 0) ? 0 : jGlobal - firstPoint();
325 jmin = std::max<size_t>(jpt, 1) - 1;
326 jmax = std::min(jpt+1,m_points-1);
327 }
328
329 updateProperties(jGlobal, x, jmin, jmax);
330
331 if (m_do_radiation) { // Calculation of qdotRadiation
332 computeRadiation(x, jmin, jmax);
333 }
334
335 evalContinuity(x, rsd, diag, rdt, jmin, jmax);
336 evalMomentum(x, rsd, diag, rdt, jmin, jmax);
337 evalEnergy(x, rsd, diag, rdt, jmin, jmax);
338 evalLambda(x, rsd, diag, rdt, jmin, jmax);
339 evalElectricField(x, rsd, diag, rdt, jmin, jmax);
340 evalUo(x, rsd, diag, rdt, jmin, jmax);
341 evalSpecies(x, rsd, diag, rdt, jmin, jmax);
342}
343
344void Flow1D::updateProperties(size_t jg, double* x, size_t jmin, size_t jmax)
345{
346 // properties are computed for grid points from j0 to j1
347 size_t j0 = std::max<size_t>(jmin, 1) - 1;
348 size_t j1 = std::min(jmax+1,m_points-1);
349
350 updateThermo(x, j0, j1);
351 if (jg == npos || m_force_full_update) {
352 // update transport properties only if a Jacobian is not being
353 // evaluated, or if specifically requested
354 updateTransport(x, j0, j1);
355 }
356 if (jg == npos) {
357 double* Yleft = x + index(c_offset_Y, jmin);
358 m_kExcessLeft = distance(Yleft, max_element(Yleft, Yleft + m_nsp));
359 double* Yright = x + index(c_offset_Y, jmax);
360 m_kExcessRight = distance(Yright, max_element(Yright, Yright + m_nsp));
361 }
362
363 // update the species diffusive mass fluxes whether or not a
364 // Jacobian is being evaluated
365 updateDiffFluxes(x, j0, j1);
366}
367
368void Flow1D::updateTransport(double* x, size_t j0, size_t j1)
369{
371 for (size_t j = j0; j < j1; j++) {
372 setGasAtMidpoint(x,j);
373 double wtm = m_thermo->meanMolecularWeight();
374 double rho = m_thermo->density();
375 m_visc[j] = (m_dovisc ? m_trans->viscosity() : 0.0);
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) {
395 } else {
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(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(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(double* x, double* rsd, 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(double* x, double* rsd, 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(double* x, double* rsd, 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(double* x, double* rsd, 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(double* x, double* rsd, 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(double* x, double* rsd, 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(double* x, double* rsd, 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(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(soln + c_offset_Y);
934 m_solution->thermo()->setState_TP(*(soln + c_offset_T), m_press);
935}
936
937void Flow1D::getValues(const string& component, vector<double>& values) const
938{
939 if (!m_state) {
940 throw CanteraError("Flow1D::getValues",
941 "Domain needs to be installed in a container.");
942 }
943 if (values.size() != nPoints()) {
944 throw ArraySizeError("Flow1D::getValues", values.size(), nPoints());
945 }
946 auto i = componentIndex(component);
947 if (!componentActive(i)) {
948 warn_user(
949 "Flow1D::getValues", "Component '{}' is not used by '{}'.",
950 component, domainType());
951 }
952 const double* soln = m_state->data() + m_iloc;
953 for (size_t j = 0; j < nPoints(); j++) {
954 values[j] = soln[index(i,j)];
955 }
956}
957
958void Flow1D::setValues(const string& component, const vector<double>& values)
959{
960 if (!m_state) {
961 throw CanteraError("Flow1D::setValues",
962 "Domain needs to be installed in a container.");
963 }
964 if (values.size() != nPoints()) {
965 throw ArraySizeError("Flow1D::_etValues", values.size(), nPoints());
966 }
967 auto i = componentIndex(component);
968 if (!componentActive(i)) {
969 throw CanteraError(
970 "Flow1D::setValues", "Component '{}' is not used by '{}'.",
971 component, domainType());
972 }
973 double* soln = m_state->data() + m_iloc;
974 for (size_t j = 0; j < nPoints(); j++) {
975 soln[index(i,j)] = values[j];
976 }
977}
978
979void Flow1D::getResiduals(const string& component, vector<double>& values) const
980{
981 if (!m_state) {
982 throw CanteraError("Flow1D::getResiduals",
983 "Domain needs to be installed in a container.");
984 }
985 if (values.size() != nPoints()) {
986 throw ArraySizeError("Flow1D::getResiduals", values.size(), nPoints());
987 }
988 auto i = componentIndex(component);
989 if (!componentActive(i)) {
990 warn_user(
991 "Flow1D::getResiduals", "Component '{}' is not used by '{}'.",
992 component, domainType());
993 }
994 const double* soln = m_container->_workVector().data() + m_iloc;
995 for (size_t j = 0; j < nPoints(); j++) {
996 values[j] = soln[index(i,j)];
997 }
998}
999
1000void Flow1D::setProfile(const string& component,
1001 const vector<double>& pos, const vector<double>& values)
1002{
1003 if (!m_state) {
1004 throw CanteraError("Flow1D::setProfile",
1005 "Domain needs to be installed in a container.");
1006 }
1007 if (pos.size() != values.size()) {
1008 throw CanteraError(
1009 "Flow1D::setProfile", "Vectors for positions and values must have same "
1010 "size.\nSizes are {} and {}, respectively.", pos.size(), values.size());
1011 }
1012 if (pos.front() != 0.0 || pos.back() != 1.0) {
1013 throw CanteraError("Flow1D::setProfile",
1014 "'pos' vector must span the range [0, 1]. Got a vector spanning "
1015 "[{}, {}] instead.", pos.front(), pos.back());
1016 }
1017 auto i = componentIndex(component);
1018 if (!componentActive(i)) {
1019 throw CanteraError(
1020 "Flow1D::setProfile", "Component '{}' is not used by '{}'.",
1021 component, domainType());
1022 }
1023 double* soln = m_state->data() + m_iloc;
1024 double z0 = zmin();
1025 double zDelta = zmax() - z0;
1026 for (size_t j = 0; j < nPoints(); j++) {
1027 double frac = (z(j) - z0)/zDelta;
1028 double v = linearInterp(frac, pos, values);
1029 soln[index(i,j)] = v;
1030 }
1031}
1032
1033void Flow1D::setFlatProfile(const string& component, double value)
1034{
1035 if (!m_state) {
1036 throw CanteraError("Flow1D::setFlatProfile",
1037 "Domain needs to be installed in a container.");
1038 }
1039 auto i = componentIndex(component);
1040 if (!componentActive(i)) {
1041 throw CanteraError(
1042 "Flow1D::setFlatProfile", "Component '{}' is not used by '{}'.",
1043 component, domainType());
1044 }
1045 double* soln = m_state->data() + m_iloc;
1046 for (size_t j = 0; j < nPoints(); j++) {
1047 soln[index(i,j)] = value;
1048 }
1049}
1050
1051shared_ptr<SolutionArray> Flow1D::toArray(bool normalize)
1052{
1053 if (!m_state) {
1054 throw CanteraError("Flow1D::toArray",
1055 "Domain needs to be installed in a container before calling toArray.");
1056 }
1057 double* soln = m_state->data() + m_iloc;
1058 auto arr = SolutionArray::create(
1059 m_solution, static_cast<int>(nPoints()), getMeta());
1060 arr->addExtra("grid", false); // leading entry
1062 value = m_z;
1063 arr->setComponent("grid", value);
1064 vector<double> data(nPoints());
1065 for (size_t i = 0; i < nComponents(); i++) {
1066 if (componentActive(i)) {
1067 auto name = componentName(i);
1068 for (size_t j = 0; j < nPoints(); j++) {
1069 data[j] = soln[index(i, j)];
1070 }
1071 if (!arr->hasComponent(name)) {
1072 arr->addExtra(name, componentIndex(name) > c_offset_Y);
1073 }
1074 value = data;
1075 arr->setComponent(name, value);
1076 }
1077 }
1078 updateThermo(soln, 0, m_points-1);
1079 value = m_rho;
1080 arr->setComponent("D", value); // use density rather than pressure
1081
1082 if (m_do_radiation) {
1083 arr->addExtra("radiative-heat-loss", true); // add at end
1085 arr->setComponent("radiative-heat-loss", value);
1086 }
1087
1088 if (normalize) {
1089 arr->normalize();
1090 }
1091 return arr;
1092}
1093
1094void Flow1D::fromArray(const shared_ptr<SolutionArray>& arr)
1095{
1096 if (!m_state) {
1097 throw CanteraError("Domain1D::fromArray",
1098 "Domain needs to be installed in a container before calling fromArray.");
1099 }
1100 resize(nComponents(), arr->size());
1102 double* soln = m_state->data() + m_iloc;
1103
1104 Domain1D::setMeta(arr->meta());
1105 arr->setLoc(0);
1106 auto phase = arr->thermo();
1107 m_press = phase->pressure();
1108
1109 const auto grid = arr->getComponent("grid").as<vector<double>>();
1110 setupGrid(nPoints(), &grid[0]);
1111 setMeta(arr->meta()); // can affect which components are active
1112
1113 for (size_t i = 0; i < nComponents(); i++) {
1114 if (!componentActive(i)) {
1115 continue;
1116 }
1117 string name = componentName(i);
1118 if (arr->hasComponent(name)) {
1119 const vector<double> data = arr->getComponent(name).as<vector<double>>();
1120 for (size_t j = 0; j < nPoints(); j++) {
1121 soln[index(i,j)] = data[j];
1122 }
1123 } else if (name == "Lambda" && arr->hasComponent("lambda")) {
1124 // edge case: 'lambda' is renamed to 'Lambda' in Cantera 3.2
1125 const auto data = arr->getComponent("lambda").as<vector<double>>();
1126 for (size_t j = 0; j < nPoints(); j++) {
1127 soln[index(i,j)] = data[j];
1128 }
1129 } else {
1130 warn_user("Flow1D::fromArray", "Saved state does not contain values for "
1131 "component '{}' in domain '{}'.", name, id());
1132 }
1133 }
1134
1135 updateProperties(npos, soln, 0, m_points - 1);
1136 _finalize(soln);
1137}
1138
1139void Flow1D::setMeta(const AnyMap& state)
1140{
1141 if (state.hasKey("energy-enabled")) {
1142 const AnyValue& ee = state["energy-enabled"];
1143 if (ee.isScalar()) {
1144 m_do_energy.assign(nPoints(), ee.asBool());
1145 } else {
1146 m_do_energy = ee.asVector<bool>(nPoints());
1147 }
1148 }
1149
1150 if (state.hasKey("transport-model")) {
1151 setTransportModel(state["transport-model"].asString());
1152 }
1153
1154 if (state.hasKey("Soret-enabled")) {
1155 m_do_soret = state["Soret-enabled"].asBool();
1156 }
1157
1158 if (state.hasKey("flux-gradient-basis")) {
1159 m_fluxGradientBasis = static_cast<ThermoBasis>(
1160 state["flux-gradient-basis"].asInt());
1161 }
1162
1163 if (state.hasKey("radiation-enabled")) {
1164 m_do_radiation = state["radiation-enabled"].asBool();
1165 if (m_do_radiation) {
1166 m_epsilon_left = state["emissivity-left"].asDouble();
1167 m_epsilon_right = state["emissivity-right"].asDouble();
1168 }
1169 }
1170
1171 if (state.hasKey("refine-criteria")) {
1172 const AnyMap& criteria = state["refine-criteria"].as<AnyMap>();
1173 double ratio = criteria.getDouble("ratio", m_refiner->maxRatio());
1174 double slope = criteria.getDouble("slope", m_refiner->maxDelta());
1175 double curve = criteria.getDouble("curve", m_refiner->maxSlope());
1176 double prune = criteria.getDouble("prune", m_refiner->prune());
1177 m_refiner->setCriteria(ratio, slope, curve, prune);
1178
1179 if (criteria.hasKey("grid-min")) {
1180 m_refiner->setGridMin(criteria["grid-min"].asDouble());
1181 }
1182 if (criteria.hasKey("max-points")) {
1183 m_refiner->setMaxPoints(criteria["max-points"].asInt());
1184 }
1185 }
1186
1187 if (state.hasKey("fixed-point")) {
1188 m_zfixed = state["fixed-point"]["location"].asDouble();
1189 m_tfixed = state["fixed-point"]["temperature"].asDouble();
1190 }
1191
1192 // Two-point control meta data
1193 if (state.hasKey("continuation-method")) {
1194 const AnyMap& cm = state["continuation-method"].as<AnyMap>();
1195 if (cm["type"] == "two-point") {
1196 m_twoPointControl = true;
1197 m_zLeft = cm["left-location"].asDouble();
1198 m_zRight = cm["right-location"].asDouble();
1199 m_tLeft = cm["left-temperature"].asDouble();
1200 m_tRight = cm["right-temperature"].asDouble();
1201 } else {
1202 warn_user("Flow1D::setMeta", "Unknown continuation method '{}'.",
1203 cm["type"].asString());
1204 }
1205 }
1206}
1207
1209{
1210 bool changed = false;
1211 if (j == npos) {
1212 for (size_t i = 0; i < m_points; i++) {
1213 if (!m_do_energy[i]) {
1214 changed = true;
1215 }
1216 m_do_energy[i] = true;
1217 }
1218 } else {
1219 if (!m_do_energy[j]) {
1220 changed = true;
1221 }
1222 m_do_energy[j] = true;
1223 }
1224 m_refiner->setActive(c_offset_U, true);
1225 m_refiner->setActive(c_offset_V, true);
1226 m_refiner->setActive(c_offset_T, true);
1227 if (changed) {
1228 needJacUpdate();
1229 }
1230}
1231
1233{
1234 throw NotImplementedError("Flow1D::solveElectricField",
1235 "Not used by '{}' objects.", domainType());
1236}
1237
1239{
1240 throw NotImplementedError("Flow1D::fixElectricField",
1241 "Not used by '{}' objects.", domainType());
1242}
1243
1245{
1246 throw NotImplementedError("Flow1D::doElectricField",
1247 "Not used by '{}' objects.", domainType());
1248}
1249
1250void Flow1D::setBoundaryEmissivities(double e_left, double e_right)
1251{
1252 if (e_left < 0 || e_left > 1) {
1253 throw CanteraError("Flow1D::setBoundaryEmissivities",
1254 "The left boundary emissivity must be between 0.0 and 1.0!");
1255 } else if (e_right < 0 || e_right > 1) {
1256 throw CanteraError("Flow1D::setBoundaryEmissivities",
1257 "The right boundary emissivity must be between 0.0 and 1.0!");
1258 } else {
1259 m_epsilon_left = e_left;
1260 m_epsilon_right = e_right;
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] = false;
1273 }
1274 } else {
1275 if (m_do_energy[j]) {
1276 changed = true;
1277 }
1278 m_do_energy[j] = false;
1279 }
1280 m_refiner->setActive(c_offset_U, false);
1281 m_refiner->setActive(c_offset_V, false);
1282 m_refiner->setActive(c_offset_T, false);
1283 if (changed) {
1284 needJacUpdate();
1285 }
1286}
1287
1288void Flow1D::grad_hk(const double* x, size_t j)
1289{
1290 size_t jloc = (u(x, j) > 0.0 ? j : j + 1);
1291 for(size_t k = 0; k < m_nsp; k++) {
1292 m_dhk_dz(k, j) = (m_hk(k, jloc) - m_hk(k, jloc-1))/m_dz[jloc-1];
1293 }
1294}
1295
1296// Two-point control functions
1298{
1299 if (m_twoPointControl) {
1300 if (m_zLeft != Undef) {
1301 return m_tLeft;
1302 } else {
1303 throw CanteraError("Flow1D::leftControlPointTemperature",
1304 "Invalid operation: left control point location is not set");
1305 }
1306 } else {
1307 throw CanteraError("Flow1D::leftControlPointTemperature",
1308 "Invalid operation: two-point control is not enabled.");
1309 }
1310}
1311
1313{
1314 if (m_twoPointControl) {
1315 if (m_zLeft != Undef) {
1316 return m_zLeft;
1317 } else {
1318 throw CanteraError("Flow1D::leftControlPointCoordinate",
1319 "Invalid operation: left control point location is not set");
1320 }
1321 } else {
1322 throw CanteraError("Flow1D::leftControlPointCoordinate",
1323 "Invalid operation: two-point control is not enabled.");
1324 }
1325}
1326
1328{
1329 if (m_twoPointControl) {
1330 if (m_zLeft != Undef) {
1331 m_tLeft = temperature;
1332 } else {
1333 throw CanteraError("Flow1D::setLeftControlPointTemperature",
1334 "Invalid operation: left control point location is not set");
1335 }
1336 } else {
1337 throw CanteraError("Flow1D::setLeftControlPointTemperature",
1338 "Invalid operation: two-point control is not enabled.");
1339 }
1340}
1341
1343{
1344 if (m_twoPointControl) {
1345 m_zLeft = z_left;
1346 } else {
1347 throw CanteraError("Flow1D::setLeftControlPointCoordinate",
1348 "Invalid operation: two-point control is not enabled.");
1349 }
1350}
1351
1353{
1354 if (m_twoPointControl) {
1355 if (m_zRight != Undef) {
1356 return m_tRight;
1357 } else {
1358 throw CanteraError("Flow1D::rightControlPointTemperature",
1359 "Invalid operation: right control point location is not set");
1360 }
1361 } else {
1362 throw CanteraError("Flow1D::rightControlPointTemperature",
1363 "Invalid operation: two-point control is not enabled.");
1364 }
1365}
1366
1368{
1369 if (m_twoPointControl) {
1370 if (m_zRight != Undef) {
1371 return m_zRight;
1372 } else {
1373 throw CanteraError("Flow1D::rightControlPointCoordinate",
1374 "Invalid operation: right control point location is not set");
1375 }
1376 } else {
1377 throw CanteraError("Flow1D::rightControlPointCoordinate",
1378 "Invalid operation: two-point control is not enabled.");
1379 }
1380}
1381
1383{
1384 if (m_twoPointControl) {
1385 if (m_zRight != Undef) {
1386 m_tRight = temperature;
1387 } else {
1388 throw CanteraError("Flow1D::setRightControlPointTemperature",
1389 "Invalid operation: right control point location is not set");
1390 }
1391 } else {
1392 throw CanteraError("Flow1D::setRightControlPointTemperature",
1393 "Invalid operation: two-point control is not enabled.");
1394 }
1395}
1396
1398{
1399 if (m_twoPointControl) {
1400 m_zRight = z_right;
1401 } else {
1402 throw CanteraError("Flow1D::setRightControlPointCoordinate",
1403 "Invalid operation: two-point control is not enabled.");
1404 }
1405}
1406
1407void Flow1D::enableTwoPointControl(bool twoPointControl)
1408{
1409 if (isStrained()) {
1410 m_twoPointControl = twoPointControl;
1411 // Prevent finding spurious solutions with negative velocity (outflow) at either
1412 // inlet.
1413 setBounds(c_offset_V, -1e-5, 1e20);
1414 } else {
1415 throw CanteraError("Flow1D::enableTwoPointControl",
1416 "Invalid operation: two-point control can only be used"
1417 "with axisymmetric flames.");
1418 }
1419}
1420
1421} // 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:530
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
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:575
vector< double > & grid()
Access the array of grid coordinates [m].
Definition Domain1D.h:603
double zmin() const
Get the coordinate [m] of the first (leftmost) grid point in this domain.
Definition Domain1D.h:593
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:364
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:588
virtual void show(const double *x)
Print the solution.
Definition Domain1D.cpp:232
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:340
vector< double > m_z
1D spatial grid coordinates
Definition Domain1D.h:684
size_t m_points
Number of grid points.
Definition Domain1D.h:676
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:598
size_t firstPoint() const
The index of the first (that is, left-most) grid point belonging to this domain.
Definition Domain1D.h:525
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:330
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:520
virtual AnyMap getMeta() const
Retrieve meta data.
Definition Domain1D.cpp:127
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:780
void setLeftControlPointTemperature(double temperature)
Sets the temperature of the left control point.
Definition Flow1D.cpp:1327
ThermoPhase * m_thermo
Phase object used for calculating thermodynamic properties.
Definition Flow1D.h:914
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:305
void setLeftControlPointCoordinate(double z_left)
Sets the coordinate of the left control point.
Definition Flow1D.cpp:1342
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:794
vector< double > m_zfix
Relative coordinates used to specify a fixed temperature profile.
Definition Flow1D.h:993
double density(size_t j) const
Get the density [kg/m³] at point j
Definition Flow1D.h:377
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:1001
void setMeta(const AnyMap &state) override
Retrieve meta data.
Definition Flow1D.cpp:1139
void setValues(const string &component, const vector< double > &values) override
Specify component values.
Definition Flow1D.cpp:958
double m_zLeft
Location of the left control point when two-point control is enabled.
Definition Flow1D.h:1008
void fixTemperature(size_t j=npos)
Specify that the the temperature should be held fixed at point j.
Definition Flow1D.cpp:1264
void getValues(const string &component, vector< double > &values) const override
Retrieve component values.
Definition Flow1D.cpp:937
vector< double > m_tfix
Fixed temperature values at the relative coordinates specified in m_zfix.
Definition Flow1D.h:997
void setRightControlPointCoordinate(double z_right)
Sets the coordinate of the right control point.
Definition Flow1D.cpp:1397
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:727
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:669
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:190
bool twoPointControlEnabled() const
Returns the status of the two-point control.
Definition Flow1D.h:355
size_t rightExcessSpecies() const
Index of the species on the right boundary with the largest mass fraction.
Definition Flow1D.h:436
bool m_do_soret
true if the Soret diffusion term should be calculated.
Definition Flow1D.h:943
Kinetics * m_kin
Kinetics object used for calculating species production rates.
Definition Flow1D.h:917
vector< double > m_qdotRadiation
radiative heat loss vector
Definition Flow1D.h:978
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:569
size_t componentIndex(const string &name, bool checkAlias=true) const override
Index of component with name name.
Definition Flow1D.cpp:820
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:463
double m_tLeft
Temperature of the left control point when two-point control is enabled.
Definition Flow1D.h:1011
void setRightControlPointTemperature(double temperature)
Sets the temperature of the right control point.
Definition Flow1D.cpp:1382
virtual bool doElectricField() const
Retrieve flag indicating whether electric field is solved or not (used by IonFlow specialization)
Definition Flow1D.cpp:1244
bool hasComponent(const string &name, bool checkAlias=true) const override
Check whether the Domain contains a component.
Definition Flow1D.cpp:840
void resize(size_t components, size_t points) override
Change the grid size. Called after grid refinement.
Definition Flow1D.cpp:149
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:765
bool m_usesLambda
Flag that is true for counterflow configurations that use the pressure eigenvalue in the radial mome...
Definition Flow1D.h:971
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:986
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:512
vector< double > m_cp
Specific heat capacity at each grid point.
Definition Flow1D.h:878
void enableTwoPointControl(bool twoPointControl)
Sets the status of the two-point control.
Definition Flow1D.cpp:1407
double m_tRight
Temperature of the right control point when two-point control is enabled.
Definition Flow1D.h:1017
void setBoundaryEmissivities(double e_left, double e_right)
Set the emissivities for the boundary values.
Definition Flow1D.cpp:1250
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:822
ThermoBasis m_fluxGradientBasis
Determines whether diffusive fluxes are computed using gradients of mass fraction or mole fraction.
Definition Flow1D.h:948
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:1051
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:648
void solveEnergyEqn(size_t j=npos)
Specify that the energy equation should be solved at point j.
Definition Flow1D.cpp:1208
vector< double > m_rho
Density at each grid point.
Definition Flow1D.h:875
void _setTransport(shared_ptr< Transport > trans) override
Update transport model to existing instance.
Definition Flow1D.cpp:129
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:940
double m_epsilon_right
Emissivity of the surface to the right of the domain.
Definition Flow1D.h:928
vector< double > m_tcon
Thermal conductivity at each grid point [W/m/K].
Definition Flow1D.h:882
vector< double > m_diff
Coefficient used in diffusion calculations for each species at each grid point.
Definition Flow1D.h:890
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:721
void getResiduals(const string &component, vector< double > &values) const override
Retrieve internal work array values for a component.
Definition Flow1D.cpp:979
vector< double > m_dz
Grid spacing. Element j holds the value of z(j+1) - z(j).
Definition Flow1D.h:872
Array2D m_flux
Array of size m_nsp by m_points for saving diffusive mass fluxes.
Definition Flow1D.h:900
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:233
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:881
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:704
double m_epsilon_left
Emissivity of the surface to the left of the domain.
Definition Flow1D.h:924
Transport * m_trans
Transport object used for calculating transport properties.
Definition Flow1D.h:920
double m_tfixed
Temperature at the point used to fix the flame location.
Definition Flow1D.h:1024
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
Array2D m_wdot
Array of size m_nsp by m_points for saving species production rates.
Definition Flow1D.h:909
Array2D m_hk
Array of size m_nsp by m_points for saving molar enthalpies.
Definition Flow1D.h:903
void _setKinetics(shared_ptr< Kinetics > kin) override
Update transport model to existing instance.
Definition Flow1D.cpp:123
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:730
void fromArray(const shared_ptr< SolutionArray > &arr) override
Restore the solution for this domain from a SolutionArray.
Definition Flow1D.cpp:1094
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:851
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:952
double V_prev(size_t j) const
Get the spread rate [1/s] at point j from the previous time step.
Definition Flow1D.h:690
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:837
vector< double > m_wt
Molecular weight of each species.
Definition Flow1D.h:877
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:710
void setupGrid(size_t n, const double *z) override
called to set up initial grid, and after grid refinement
Definition Flow1D.cpp:175
double T(const double *x, size_t j) const
Get the temperature at point j from the local state vector x.
Definition Flow1D.h:660
size_t leftExcessSpecies() const
Index of the species on the left boundary with the largest mass fraction.
Definition Flow1D.h:431
bool m_isFree
Flag that is true for freely propagating flames anchored by a temperature fixed point.
Definition Flow1D.h:966
Array2D m_dhk_dz
Array of size m_nsp by m_points-1 for saving enthalpy fluxes.
Definition Flow1D.h:906
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:770
vector< double > m_wtm
Mean molecular weight at each grid point.
Definition Flow1D.h:876
vector< double > m_multidiff
Vector of size m_nsp × m_nsp × m_points for saving multicomponent diffusion coefficients.
Definition Flow1D.h:894
bool m_twoPointControl
Flag for activating two-point flame control.
Definition Flow1D.h:974
double m_zfixed
Location of the point where temperature is fixed.
Definition Flow1D.h:1021
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:253
size_t m_nsp
Number of species in the mechanism.
Definition Flow1D.h:911
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:605
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:674
double leftControlPointCoordinate() const
Returns the z-coordinate of the left control point.
Definition Flow1D.cpp:1312
void setProfile(const string &component, const vector< double > &pos, const vector< double > &values) override
Specify a profile for a component.
Definition Flow1D.cpp:1000
AnyMap getMeta() const override
Retrieve meta data.
Definition Flow1D.cpp:871
virtual void updateDiffFluxes(const double *x, size_t j0, size_t j1)
Update the diffusive mass fluxes.
Definition Flow1D.cpp:419
double leftControlPointTemperature() const
Returns the temperature at the left control point.
Definition Flow1D.cpp:1297
string componentName(size_t n) const override
Name of component n. May be overloaded.
Definition Flow1D.cpp:796
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:241
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:1288
bool isStrained() const
Retrieve flag indicating whether flow uses radial momentum.
Definition Flow1D.h:398
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:1367
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:685
Array2D m_dthermal
Array of size m_nsp by m_points for saving thermal diffusion coefficients.
Definition Flow1D.h:897
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:465
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:344
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:696
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:690
string domainType() const override
Domain type flag.
Definition Flow1D.cpp:113
void show(const double *x) override
Print the solution.
Definition Flow1D.cpp:779
bool m_dovisc
Determines whether the viscosity term in the momentum equation is calculated.
Definition Flow1D.h:961
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
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:368
double m_zRight
Location of the right control point when two-point control is enabled.
Definition Flow1D.h:1014
virtual void solveElectricField()
Set to solve electric field in a point (used by IonFlow specialization)
Definition Flow1D.cpp:1232
virtual void fixElectricField()
Set to fix voltage in a point (used by IonFlow specialization)
Definition Flow1D.cpp:1238
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:679
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:1005
void _getInitialSoln(double *x) override
Write the initial solution estimate into array x.
Definition Flow1D.cpp:224
vector< size_t > m_kRadiating
Indices within the ThermoPhase of the radiating species.
Definition Flow1D.h:932
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:1033
double rightControlPointTemperature() const
Returns the temperature at the right control point.
Definition Flow1D.cpp:1352
double T_fixed(size_t j) const
The fixed temperature value at point j.
Definition Flow1D.h:163
vector< double > m_ybar
Holds the average of the species mass fractions between grid points j and j+1.
Definition Flow1D.h:1030
bool m_do_radiation
Determines whether radiative heat loss is calculated.
Definition Flow1D.h:956
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:240
virtual void setMassFractions_NoNorm(const double *const y)
Set the mass fractions to the specified values without normalizing.
Definition Phase.cpp:373
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
double temperature() const
Temperature (K).
Definition Phase.h:598
virtual void setPressure(double p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition Phase.h:652
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition Phase.h:691
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:143
const vector< double > & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:420
virtual double density() const
Density (kg/m^3).
Definition Phase.h:623
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
Definition Phase.h:659
virtual void setMassFractions(const double *const y)
Set the mass fractions to the specified values and normalize them.
Definition Phase.cpp:359
void getMassFractions(double *const y) const
Get the species mass fractions.
Definition Phase.cpp:496
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:616
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(double *const dt)
Return a vector of thermal diffusion coefficients [kg/m/s].
Definition Transport.h:263
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:313
virtual double thermalConductivity()
Get the mixture thermal conductivity [W/m/K].
Definition Transport.h:152
virtual void getMixDiffCoeffsMass(double *const d)
Returns a vector of mixture averaged diffusion coefficients [m²/s].
Definition Transport.h:325
virtual double viscosity()
Get the dynamic viscosity [Pa·s].
Definition Transport.h:126
virtual void getMultiDiffCoeffs(const size_t ld, double *const d)
Return the multicomponent diffusion coefficients [m²/s].
Definition Transport.h:298
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, 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: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: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.