|
10 | 10 | #include "cantera/transport/TransportFactory.h" |
11 | 11 | #include "cantera/numerics/funcs.h" |
12 | 12 | #include "cantera/base/global.h" |
| 13 | +#include "cantera/thermo/Species.h" |
| 14 | + |
13 | 15 |
|
14 | 16 | using namespace std; |
15 | 17 |
|
@@ -81,10 +83,52 @@ Flow1D::Flow1D(ThermoPhase* ph, size_t nsp, size_t points) : |
81 | 83 | } |
82 | 84 | setupGrid(m_points, gr.data()); |
83 | 85 |
|
84 | | - // Find indices for radiating species |
85 | | - m_kRadiating.resize(2, npos); |
86 | | - m_kRadiating[0] = m_thermo->speciesIndex("CO2"); |
87 | | - m_kRadiating[1] = m_thermo->speciesIndex("H2O"); |
| 86 | + // Parse radiation data from the YAML file |
| 87 | + for (auto& name : m_thermo->speciesNames()) { |
| 88 | + auto& data = m_thermo->species(name)->input; |
| 89 | + if (data.hasKey("radiation")) { |
| 90 | + cout << "Radiation data found for species " << name << endl; |
| 91 | + m_absorptionSpecies.insert({name, m_thermo->speciesIndex(name)}); |
| 92 | + if (data["radiation"].hasKey("fit-type")) { |
| 93 | + m_PMAC[name]["fit-type"] = data["radiation"]["fit-type"].asString(); |
| 94 | + } else { |
| 95 | + throw InputFileError("Flow1D::Flow1D", data, |
| 96 | + "No 'fit-type' entry found for species '{}'", name); |
| 97 | + } |
| 98 | + |
| 99 | + // This is the direct tabulation of the optical path length |
| 100 | + if (data["radiation"]["fit-type"] == "table") { |
| 101 | + if (data["radiation"].hasKey("temperatures")) { |
| 102 | + cout << "Storing temperatures for species " << name << endl; |
| 103 | + // Each species may have a specific set of temperatures that are used |
| 104 | + m_PMAC[name]["temperatures"] = data["radiation"]["temperatures"].asVector<double>(); |
| 105 | + } else { |
| 106 | + throw InputFileError("Flow1D::Flow1D", data, |
| 107 | + "No 'temperatures' entry found for species '{}'", name); |
| 108 | + } |
| 109 | + if (data["radiation"].hasKey("data")) { |
| 110 | + cout << "Storing data for species " << name << endl; |
| 111 | + // This data is the Plank mean absorption coefficient |
| 112 | + m_PMAC[name]["coefficients"] = data["radiation"]["data"].asVector<double>(); |
| 113 | + } else { |
| 114 | + throw InputFileError("Flow1D::Flow1D", data, |
| 115 | + "No 'data' entry found for species '{}'", name); |
| 116 | + } |
| 117 | + } else if (data["radiation"]["fit-type"] == "polynomial") { |
| 118 | + cout << "Polynomial fit found for species " << name << endl; |
| 119 | + if (data["radiation"].hasKey("data")) { |
| 120 | + cout << "Storing data for species " << name << endl; |
| 121 | + m_PMAC[name]["coefficients"] = data["radiation"]["data"].asVector<double>(); |
| 122 | + } else { |
| 123 | + throw InputFileError("Flow1D::Flow1D", data, |
| 124 | + "No 'data' entry found for species '{}'", name); |
| 125 | + } |
| 126 | + } else { |
| 127 | + throw InputFileError("Flow1D::Flow1D", data, |
| 128 | + "Invalid 'fit-type' entry found for species '{}'", name); |
| 129 | + } |
| 130 | + } |
| 131 | + } |
88 | 132 | } |
89 | 133 |
|
90 | 134 | Flow1D::Flow1D(shared_ptr<ThermoPhase> th, size_t nsp, size_t points) |
@@ -472,34 +516,61 @@ void Flow1D::computeRadiation(double* x, size_t jmin, size_t jmax) |
472 | 516 |
|
473 | 517 | // Polynomial coefficients: |
474 | 518 | const double c_H2O[6] = {-0.23093, -1.12390, 9.41530, -2.99880, |
475 | | - 0.51382, -1.86840e-5}; |
| 519 | + 0.51382, -1.86840e-5}; |
476 | 520 | const double c_CO2[6] = {18.741, -121.310, 273.500, -194.050, |
477 | | - 56.310, -5.8169}; |
| 521 | + 56.310, -5.8169}; |
478 | 522 |
|
479 | 523 | // Calculation of the two boundary values |
480 | 524 | double boundary_Rad_left = m_epsilon_left * StefanBoltz * pow(T(x, 0), 4); |
481 | 525 | double boundary_Rad_right = m_epsilon_right * StefanBoltz * pow(T(x, m_points - 1), 4); |
482 | 526 |
|
| 527 | + double coef = 0.0; |
483 | 528 | for (size_t j = jmin; j < jmax; j++) { |
484 | 529 | // calculation of the mean Planck absorption coefficient |
485 | 530 | double k_P = 0; |
486 | | - // Absorption coefficient for H2O |
487 | | - if (m_kRadiating[1] != npos) { |
488 | | - double k_P_H2O = 0; |
489 | | - for (size_t n = 0; n <= 5; n++) { |
490 | | - k_P_H2O += c_H2O[n] * pow(1000 / T(x, j), (double) n); |
491 | | - } |
492 | | - k_P_H2O /= k_P_ref; |
493 | | - k_P += m_press * X(x, m_kRadiating[1], j) * k_P_H2O; |
494 | | - } |
495 | | - // Absorption coefficient for CO2 |
496 | | - if (m_kRadiating[0] != npos) { |
497 | | - double k_P_CO2 = 0; |
498 | | - for (size_t n = 0; n <= 5; n++) { |
499 | | - k_P_CO2 += c_CO2[n] * pow(1000 / T(x, j), (double) n); |
| 531 | + |
| 532 | + for(const auto& [sp_name, sp_idx] : m_absorptionSpecies) { |
| 533 | + if (m_PMAC[sp_name]["fit-type"].asString() == "table") { |
| 534 | + // temperature table interval search |
| 535 | + int T_index = 0; |
| 536 | + const int OPL_table_size = m_PMAC[sp_name]["temperatures"].asVector<double>().size(); |
| 537 | + for (int k = 0; k < OPL_table_size; k++) { |
| 538 | + if (T(x, j) < m_PMAC[sp_name]["temperatures"].asVector<double>()[k]) { |
| 539 | + if (T(x, j) < m_PMAC[sp_name]["temperatures"].asVector<double>()[0]) { |
| 540 | + T_index = 0; //lower table limit |
| 541 | + } |
| 542 | + else { |
| 543 | + T_index = k; |
| 544 | + } |
| 545 | + break; |
| 546 | + } |
| 547 | + else { |
| 548 | + T_index=OPL_table_size-1; //upper table limit |
| 549 | + } |
| 550 | + } |
| 551 | + |
| 552 | + // absorption coefficient for specie |
| 553 | + double k_P_specie = 0.0; |
| 554 | + if ((T_index == 0) || (T_index == OPL_table_size-1)) { |
| 555 | + coef=log(1.0/m_PMAC[sp_name]["coefficients"].asVector<double>()[T_index]); |
| 556 | + } |
| 557 | + else { |
| 558 | + coef=log(1.0/m_PMAC[sp_name]["coefficients"].asVector<double>()[T_index-1])+ |
| 559 | + (log(1.0/m_PMAC[sp_name]["coefficients"].asVector<double>()[T_index])-log(1.0/m_PMAC[sp_name]["coefficients"].asVector<double>()[T_index-1]))* |
| 560 | + (T(x, j)-m_PMAC[sp_name]["temperatures"].asVector<double>()[T_index-1])/(m_PMAC[sp_name]["temperatures"].asVector<double>()[T_index]-m_PMAC[sp_name]["temperatures"].asVector<double>()[T_index-1]); |
| 561 | + } |
| 562 | + k_P_specie = exp(coef); |
| 563 | + |
| 564 | + k_P_specie /= k_P_ref; |
| 565 | + k_P += m_press * X(x, m_absorptionSpecies[sp_name], j) * k_P_specie; |
| 566 | + } else if (m_PMAC[sp_name]["fit-type"].asString() == "polynomial") { |
| 567 | + double k_P_specie = 0.0; |
| 568 | + for (size_t n = 0; n <= 5; n++) { |
| 569 | + k_P_specie += m_PMAC[sp_name]["coefficients"].asVector<double>()[n] * pow(1000 / T(x, j), (double) n); |
| 570 | + } |
| 571 | + k_P_specie /= k_P_ref; |
| 572 | + k_P += m_press * X(x, m_absorptionSpecies[sp_name], j) * k_P_specie; |
500 | 573 | } |
501 | | - k_P_CO2 /= k_P_ref; |
502 | | - k_P += m_press * X(x, m_kRadiating[0], j) * k_P_CO2; |
503 | 574 | } |
504 | 575 |
|
505 | 576 | // Calculation of the radiative heat loss term |
|
0 commit comments