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