26 m_do_multicomponent(false),
27 m_do_radiation(false),
33 if (ph->
type() ==
"IdealGas") {
37 "Unsupported phase type: need 'IdealGasPhase'");
58 m_nv = c_offset_Y + m_nsp;
61 m_do_species.resize(m_nsp,
true);
64 m_do_energy.resize(m_points,
false);
66 m_diff.resize(m_nsp*m_points);
67 m_multidiff.resize(m_nsp*m_nsp*m_points);
68 m_flux.
resize(m_nsp,m_points);
69 m_wdot.
resize(m_nsp,m_points, 0.0);
74 setBounds(0, -1e20, 1e20);
75 setBounds(1, -1e20, 1e20);
76 setBounds(2, 200.0, 2*m_thermo->
maxTemp());
77 setBounds(3, -1e20, 1e20);
80 for (
size_t k = 0; k < m_nsp; k++) {
81 setBounds(c_offset_Y+k, -1.0e-7, 1.0e5);
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);
91 for (
size_t ng = 0; ng < m_points; ng++) {
92 gr.push_back(1.0*ng/m_points);
105 m_rho.resize(m_points, 0.0);
106 m_wtm.resize(m_points, 0.0);
107 m_cp.resize(m_points, 0.0);
108 m_visc.resize(m_points, 0.0);
109 m_tcon.resize(m_points, 0.0);
111 m_diff.resize(m_nsp*m_points);
112 if (m_do_multicomponent) {
113 m_multidiff.resize(m_nsp*m_nsp*m_points);
114 m_dthermal.
resize(m_nsp, m_points, 0.0);
116 m_flux.
resize(m_nsp,m_points);
117 m_wdot.
resize(m_nsp,m_points, 0.0);
118 m_do_energy.resize(m_points,
false);
120 m_fixedtemp.resize(m_points);
122 m_dz.resize(m_points-1);
123 m_z.resize(m_points);
131 for (
size_t j = 1; j < m_points; j++) {
132 if (z[j] <= z[j-1]) {
134 "grid points must be monotonically increasing");
137 m_dz[j-1] = m_z[j] - m_z[j-1];
143 double* x = xg +
loc();
144 for (
size_t j = 0; j < m_points; j++) {
145 double* Y = x + m_nv*j + c_offset_Y;
156 m_diff.resize(m_nsp*m_points);
157 if (m_do_multicomponent) {
158 m_multidiff.resize(m_nsp*m_nsp*m_points);
159 m_dthermal.
resize(m_nsp, m_points, 0.0);
165 for (
size_t j = 0; j < m_points; j++) {
174 const doublereal* yy = x + m_nv*j + c_offset_Y;
182 const doublereal* yyj = x + m_nv*j + c_offset_Y;
183 const doublereal* yyjp = x + m_nv*(j+1) + c_offset_Y;
184 for (
size_t k = 0; k < m_nsp; k++) {
185 m_ybar[k] = 0.5*(yyj[k] + yyjp[k]);
193 if (!m_do_multicomponent && m_do_soret) {
195 "Thermal diffusion (the Soret effect) is enabled, and requires "
196 "using a multicomponent transport model.");
199 size_t nz = m_zfix.size();
200 bool e = m_do_energy[0];
201 for (
size_t j = 0; j < m_points; j++) {
203 m_fixedtemp[j] = T(x, j);
205 double zz = (z(j) - z(0))/(z(m_points - 1) - z(0));
219 for (
size_t j = 0; j < m_points; j++) {
225 for (
size_t j = 0; j < m_points - 1; j++) {
239 doublereal* rg, integer* diagg, doublereal rdt)
248 doublereal* x = xg +
loc();
249 doublereal* rsd = rg +
loc();
250 integer* diag = diagg +
loc();
257 size_t jpt = (jg == 0) ? 0 : jg -
firstPoint();
258 jmin = std::max<size_t>(jpt, 1) - 1;
259 jmax = std::min(jpt+1,m_points-1);
269 size_t j0 = std::max<size_t>(jmin, 1) - 1;
270 size_t j1 = std::min(jmax+1,m_points-1);
273 if (jg ==
npos || m_force_full_update) {
279 double* Yleft = x + index(c_offset_Y, jmin);
280 m_kExcessLeft = distance(Yleft, max_element(Yleft, Yleft + m_nsp));
281 double* Yright = x + index(c_offset_Y, jmax);
282 m_kExcessRight = distance(Yright, max_element(Yright, Yright + m_nsp));
291 double rdt,
size_t jmin,
size_t jmax)
316 doublereal k_P_ref = 1.0*
OneAtm;
319 const doublereal c_H2O[6] = {-0.23093, -1.12390, 9.41530, -2.99880,
320 0.51382, -1.86840e-5};
321 const doublereal c_CO2[6] = {18.741, -121.310, 273.500, -194.050,
325 double boundary_Rad_left = m_epsilon_left *
StefanBoltz * pow(T(x, 0), 4);
326 double boundary_Rad_right = m_epsilon_right *
StefanBoltz * pow(T(x, m_points - 1), 4);
329 for (
size_t j = jmin; j < jmax; j++) {
331 double radiative_heat_loss = 0;
338 for (
size_t n = 0; n <= 5; n++) {
339 k_P_H2O += c_H2O[n] * pow(1000 / T(x, j), (
double) n);
347 for (
size_t n = 0; n <= 5; n++) {
348 k_P_CO2 += c_CO2[n] * pow(1000 / T(x, j), (
double) n);
355 radiative_heat_loss = 2 * k_P *(2 *
StefanBoltz * pow(T(x, j), 4)
356 - boundary_Rad_left - boundary_Rad_right);
363 for (
size_t j = jmin; j <= jmax; j++) {
374 rsd[index(c_offset_U,0)] =
375 -(rho_u(x,1) - rho_u(x,0))/m_dz[0]
376 -(density(1)*V(x,1) + density(0)*V(x,0));
382 rsd[index(c_offset_V,0)] = V(x,0);
384 rsd[index(c_offset_T,0)] = T(x,0);
386 rsd[index(c_offset_T,0)] = T(x,0) -
T_fixed(0);
388 rsd[index(c_offset_L,0)] = -rho_u(x,0);
393 for (
size_t k = 0; k < m_nsp; k++) {
395 rsd[index(c_offset_Y + k, 0)] =
396 -(m_flux(k,0) + rho_u(x,0)* Y(x,k,0));
401 rsd[index(c_offset_E, 0)] = x[index(c_offset_E, j)];
402 }
else if (j == m_points - 1) {
405 rsd[index(c_offset_E, j)] = x[index(c_offset_E, j)];
409 rsd[index(c_offset_E, j)] = x[index(c_offset_E, j)];
417 rsd[index(c_offset_V,j)]
418 = (shear(x,j) - lambda(x,j) - rho_u(x,j)*dVdz(x,j)
419 - m_rho[j]*V(x,j)*V(x,j))/m_rho[j]
420 - rdt*(V(x,j) - V_prev(j));
421 diag[index(c_offset_V, j)] = 1;
430 for (
size_t k = 0; k < m_nsp; k++) {
431 double convec = rho_u(x,j)*dYdz(x,k,j);
432 double diffus = 2.0*(m_flux(k,j) - m_flux(k,j-1))
434 rsd[index(c_offset_Y + k, j)]
435 = (m_wt[k]*(wdot(k,j))
436 - convec - diffus)/m_rho[j]
437 - rdt*(Y(x,k,j) - Y_prev(k,j));
438 diag[index(c_offset_Y + k, j)] = 1;
449 if (m_do_energy[j]) {
457 for (
size_t k = 0; k < m_nsp; k++) {
458 double flxk = 0.5*(m_flux(k,j-1) + m_flux(k,j));
459 sum += wdot(k,j)*h_RT[k];
460 sum2 += flxk*cp_R[k]/m_wt[k];
463 double dtdzj = dTdz(x,j);
466 rsd[index(c_offset_T, j)] = - m_cp[j]*rho_u(x,j)*dtdzj
467 - divHeatFlux(x,j) - sum - sum2;
468 rsd[index(c_offset_T, j)] /= (m_rho[j]*m_cp[j]);
469 rsd[index(c_offset_T, j)] -= rdt*(T(x,j) - T_prev(j));
470 rsd[index(c_offset_T, j)] -= (
m_qdotRadiation[j] / (m_rho[j] * m_cp[j]));
471 diag[index(c_offset_T, j)] = 1;
474 rsd[index(c_offset_T, j)] = T(x,j) -
T_fixed(j);
475 diag[index(c_offset_T, j)] = 0;
478 rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1);
479 diag[index(c_offset_L, j)] = 0;
486 if (m_do_multicomponent) {
487 for (
size_t j = j0; j < j1; j++) {
490 doublereal rho = m_thermo->
density();
491 m_visc[j] = (m_dovisc ? m_trans->
viscosity() : 0.0);
495 for (
size_t k = 0; k < m_nsp; k++) {
496 m_diff[k+j*m_nsp] = m_wt[k] * rho / (wtm*wtm);
505 for (
size_t j = j0; j < j1; j++) {
507 m_visc[j] = (m_dovisc ? m_trans->
viscosity() : 0.0);
516 writelog(
" Pressure: {:10.4g} Pa\n", m_press);
521 writeline(
'-', 79,
false,
true);
522 writelog(
"\n z radiative heat loss");
523 writeline(
'-', 79,
false,
true);
524 for (
size_t j = 0; j < m_points; j++) {
533 if (m_do_multicomponent) {
534 for (
size_t j = j0; j < j1; j++) {
535 double dz = z(j+1) - z(j);
536 for (
size_t k = 0; k < m_nsp; k++) {
537 doublereal sum = 0.0;
538 for (
size_t m = 0; m < m_nsp; m++) {
539 sum += m_wt[m] * m_multidiff[mindex(k,m,j)] * (X(x,m,j+1)-X(x,m,j));
541 m_flux(k,j) = sum * m_diff[k+j*m_nsp] / dz;
545 for (
size_t j = j0; j < j1; j++) {
547 double wtm = m_wtm[j];
548 double rho = density(j);
549 double dz = z(j+1) - z(j);
550 for (
size_t k = 0; k < m_nsp; k++) {
551 m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm);
552 m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz;
556 for (
size_t k = 0; k < m_nsp; k++) {
557 m_flux(k,j) += sum*Y(x,k,j);
563 for (
size_t m = j0; m < j1; m++) {
564 double gradlogT = 2.0 * (T(x,m+1) - T(x,m)) /
565 ((T(x,m+1) + T(x,m)) * (z(m+1) - z(m)));
566 for (
size_t k = 0; k < m_nsp; k++) {
567 m_flux(k,m) -= m_dthermal(k,m)*gradlogT;
579 return "spread_rate";
587 if (n >= c_offset_Y && n < (c_offset_Y + m_nsp)) {
599 "To be changed after Cantera 2.5. "
600 "Solution component 'u' renamed to 'velocity'");
602 }
else if (name==
"velocity") {
604 }
else if (name==
"V") {
606 "To be changed after Cantera 2.5. "
607 "Solution component 'V' renamed to 'spread_rate'");
609 }
else if (name==
"spread_rate") {
611 }
else if (name==
"T") {
613 }
else if (name==
"lambda") {
615 }
else if (name ==
"eField") {
618 for (
size_t n=c_offset_Y; n<m_nsp+c_offset_Y; n++) {
624 "no component named " + name);
631 vector<string> ignored;
636 for (
size_t istr = 0; istr < str.size(); istr++) {
641 double pp =
getFloat(dom,
"pressure",
"pressure");
646 bool readgrid =
false, wrote_header =
false;
647 for (
size_t n = 0; n < d.size(); n++) {
649 string nm = fa[
"title"];
654 writelog(
"Grid contains {} points.\n", np);
662 "domain contains no grid points.");
665 debuglog(
"Importing datasets:\n", loglevel >= 2);
666 for (
size_t n = 0; n < d.size(); n++) {
668 string nm = fa[
"title"];
671 debuglog(
"axial velocity ", loglevel >= 2);
672 if (x.size() != np) {
674 "axial velocity array size error");
676 for (
size_t j = 0; j < np; j++) {
677 soln[index(c_offset_U,j)] = x[j];
679 }
else if (nm ==
"z") {
681 }
else if (nm ==
"V") {
682 debuglog(
"radial velocity ", loglevel >= 2);
683 if (x.size() != np) {
685 "radial velocity array size error");
687 for (
size_t j = 0; j < np; j++) {
688 soln[index(c_offset_V,j)] = x[j];
690 }
else if (nm ==
"T") {
691 debuglog(
"temperature ", loglevel >= 2);
692 if (x.size() != np) {
694 "temperature array size error");
696 for (
size_t j = 0; j < np; j++) {
697 soln[index(c_offset_T,j)] = x[j];
704 for (
size_t jj = 0; jj < np; jj++) {
705 zz[jj] = (grid(jj) - zmin())/(zmax() - zmin());
708 }
else if (nm ==
"L") {
710 if (x.size() != np) {
712 "lambda arary size error");
714 for (
size_t j = 0; j < np; j++) {
715 soln[index(c_offset_L,j)] = x[j];
719 if (x.size() == np) {
722 for (
size_t j = 0; j < np; j++) {
723 soln[index(k+c_offset_Y,j)] = x[j];
727 ignored.push_back(nm);
731 if (loglevel >=2 && !ignored.empty()) {
734 size_t nn = ignored.size();
735 for (
size_t n = 0; n < nn; n++) {
741 for (
size_t ks = 0; ks < nsp; ks++) {
742 if (did_species[ks] == 0) {
744 writelog(
"Missing data for species:\n");
752 if (dom.
hasChild(
"energy_enabled")) {
755 for (
size_t i = 0; i < x.size(); i++) {
756 m_do_energy[i] = (x[i] != 0);
758 }
else if (!x.empty()) {
759 throw CanteraError(
"StFlow::restore",
"energy_enabled is length {}"
760 "but should be length {}", x.size(),
nPoints());
764 if (dom.
hasChild(
"species_enabled")) {
766 if (x.size() == m_nsp) {
767 for (
size_t i = 0; i < x.size(); i++) {
768 m_do_species[i] = (x[i] != 0);
770 }
else if (!x.empty()) {
774 warn_user(
"StFlow::restore",
"species_enabled is "
775 "length {} but should be length {}. Enabling all species "
776 "equations by default.", x.size(), m_nsp);
778 m_do_species.assign(m_nsp,
true);
782 if (dom.
hasChild(
"refine_criteria")) {
804 XML_Node& gv = flow.addChild(
"grid_data");
805 addFloat(flow,
"pressure", m_press,
"Pa",
"pressure");
811 soln.
getRow(c_offset_U, x.data());
814 soln.
getRow(c_offset_V, x.data());
817 soln.
getRow(c_offset_T, x.data());
820 soln.
getRow(c_offset_L, x.data());
823 for (
size_t k = 0; k < m_nsp; k++) {
824 soln.
getRow(c_offset_Y+k, x.data());
826 x.size(),x.data(),
"",
"massFraction");
833 for (
size_t i = 0; i <
nPoints(); i++) {
834 values[i] = m_do_energy[i];
838 values.resize(m_nsp);
839 for (
size_t i = 0; i < m_nsp; i++) {
840 values[i] = m_do_species[i];
844 XML_Node& ref = flow.addChild(
"refine_criteria");
857 void StFlow::solveEnergyEqn(
size_t j)
859 bool changed =
false;
861 for (
size_t i = 0; i < m_points; i++) {
862 if (!m_do_energy[i]) {
865 m_do_energy[i] =
true;
868 if (!m_do_energy[j]) {
871 m_do_energy[j] =
true;
873 m_refiner->setActive(c_offset_U,
true);
874 m_refiner->setActive(c_offset_V,
true);
875 m_refiner->setActive(c_offset_T,
true);
883 if (e_left < 0 || e_left > 1) {
885 "The left boundary emissivity must be between 0.0 and 1.0!");
886 }
else if (e_right < 0 || e_right > 1) {
888 "The right boundary emissivity must be between 0.0 and 1.0!");
890 m_epsilon_left = e_left;
891 m_epsilon_right = e_right;
895 void StFlow::fixTemperature(
size_t j)
897 bool changed =
false;
899 for (
size_t i = 0; i < m_points; i++) {
900 if (m_do_energy[i]) {
903 m_do_energy[i] =
false;
906 if (m_do_energy[j]) {
909 m_do_energy[j] =
false;
911 m_refiner->setActive(c_offset_U,
false);
912 m_refiner->setActive(c_offset_V,
false);
913 m_refiner->setActive(c_offset_T,
false);
921 size_t j = m_points - 1;
927 rsd[index(c_offset_V,j)] = V(x,j);
928 doublereal sum = 0.0;
929 rsd[index(c_offset_L, j)] = lambda(x,j) - lambda(x,j-1);
930 diag[index(c_offset_L, j)] = 0;
931 for (
size_t k = 0; k < m_nsp; k++) {
933 rsd[index(k+c_offset_Y,j)] = m_flux(k,j-1) + rho_u(x,j)*Y(x,k,j);
937 if (
domainType() == cAxisymmetricStagnationFlow) {
938 rsd[index(c_offset_U,j)] = rho_u(x,j);
939 if (m_do_energy[j]) {
940 rsd[index(c_offset_T,j)] = T(x,j);
942 rsd[index(c_offset_T, j)] = T(x,j) -
T_fixed(j);
945 rsd[index(c_offset_U,j)] = rho_u(x,j) - rho_u(x,j-1);
946 rsd[index(c_offset_T,j)] = T(x,j) - T(x,j-1);
953 diag[index(c_offset_U, j)] = 0;
959 if (
domainType() == cAxisymmetricStagnationFlow) {
963 rsd[index(c_offset_U,j)] =
964 -(rho_u(x,j+1) - rho_u(x,j))/m_dz[j]
965 -(density(j+1)*V(x,j+1) + density(j)*V(x,j));
968 rsd[index(c_offset_U,j)] =
969 - (rho_u(x,j) - rho_u(x,j-1))/m_dz[j-1]
970 - (density(j-1)*V(x,j-1) + density(j)*V(x,j));
972 if (m_do_energy[j]) {
973 rsd[index(c_offset_U,j)] = (T(x,j) -
m_tfixed);
975 rsd[index(c_offset_U,j)] = (rho_u(x,j)
979 rsd[index(c_offset_U,j)] =
980 - (rho_u(x,j+1) - rho_u(x,j))/m_dz[j]
981 - (density(j+1)*V(x,j+1) + density(j)*V(x,j));