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