Create C# code based on acticle of T.F. Smith "Eval of Coeff for WSGG model" in Heat transfer 1982 v104 n4
Loading
Create C# code based on acticle of T.F. Smith "Eval of Coeff for WSGG model" in Heat transfer 1982 v104 n4
Know the answer? Post it — somebody with the same question will find it here.
Sign in to answer this question
It is the same account you read, post and publish with — and you will come straight back to this page.
Patrick KearnsPosted Nov 3, 2025, 6:41 AM
```
using System;
using System.Collections.Generic;
using System.Linq;
namespace RadiativeTransfer.WSGG
{
///
/// Implements the Weighted-Sum-of-Gray-Gases (WSGG) model in the form popularized by
/// Smith, Shen & Friedman (J. Heat Transfer, 1982, 104(4):602–608).
///
/// Total emissivity (or absorptivity for an isothermal homogeneous layer) is:
/// e(T, p_H2O, p_CO2, L) = 1 - S_{i=0..N-1} a_i(T) exp( - (?_i,H2O p_H2O + ?_i,CO2 p_CO2) L )
///
/// Notes:
/// - i = 0 corresponds to the clear-gas term (?_0,* = 0), which ensures S a_i(T) = 1.
/// - a_i(T) are temperature-dependent weighting factors, typically Mth-order polynomials in normalized T.
/// - ?_i,* are gray-gas absorption coefficients (temperature-independent constants in the Smith 1982 fit).
/// - Pressures in atm, path length L in meters, ? in 1/(atm·m). Temperature in Kelvin.
///
/// Important: Insert the numeric polynomial and ? coefficients from your chosen correlation
/// (e.g., Smith et al. 1982) via an IWSGGCoefficientsProvider implementation.
///
public static class Wsgg
{
///
/// Computes total emissivity of a homogeneous, isothermal H2O/CO2 mixture slab.
///
/// Gas temperature [K]
/// Partial pressure of H2O [atm]
/// Partial pressure of CO2 [atm]
/// Path length [m]
/// Coefficient provider (e.g., Smith1982 coefficients)
public static double TotalEmissivity(double T, double pH2O, double pCO2, double L, IWSGGCoefficientsProvider provider)
{
if (provider == null) throw new ArgumentNullException(nameof(provider));
var coeffs = provider.GetCoefficients();
// Normalize temperature for the polynomial basis (Smith-style implementations often use T_hat = T/1000).
double tHat = coeffs.TemperatureNormalization switch
{
TemperatureNormalization.None => T,
TemperatureNormalization.By1000K => T / 1000.0,
_ => T
};
// Evaluate a_i(T) via polynomials and enforce sum(a_i) ~= 1 by renormalizing tiny drift.
var a = new double[coeffs.Gases.Count];
for (int i = 0; i < coeffs.Gases.Count; i++)
{
a[i] = EvaluatePolynomial(tHat, coeffs.Gases[i].WeightPolynomial);
}
// Lightly normalize to 1.0 to remove minor numerical drift from polynomial evaluation.
var sumA = a.Sum();
if (sumA > 0.0) for (int i = 0; i < a.Length; i++) a[i] /= sumA;
// Build effective absorption for each gray gas per Smith-style mixing:
// ?_eff,i = ?_i,H2O pH2O + ?_i,CO2 pCO2. For the clear gas (i=0), ?=0 by construction.
double emissivityComplement = 0.0;
for (int i = 0; i < coeffs.Gases.Count; i++)
{
var g = coeffs.Gases[i];
double kEff = g.KappaH2O pH2O + g.KappaCO2 pCO2; // [1/m]
double term = Math.Exp(-kEff * L);
emissivityComplement += a[i] * term;
}
double epsilon = 1.0 - emissivityComplement;
return Clamp01(epsilon);
}
///
/// For an isothermal, homogeneous layer, absorptivity ˜ emissivity by Kirchhoff’s law.
/// This is provided as a convenience alias.
///
public static double TotalAbsorptivity(double T, double pH2O, double pCO2, double L, IWSGGCoefficientsProvider provider)
=> TotalEmissivity(T, pH2O, pCO2, L, provider);
private static double EvaluatePolynomial(double x, IReadOnlyList coeffs)
{
// Horner’s method: c0 + c1 x + c2 x^2 + ...
double y = 0.0;
for (int i = coeffs.Count - 1; i >= 0; i--)
y = y * x + coeffs[i];
return y;
}
private static double Clamp01(double v) => v < 0 ? 0 : (v > 1 ? 1 : v);
}
///
/// Describes a single fictitious gray gas entry for WSGG.
///
public sealed record GrayGas(
///Polynomial coefficients for a_i(T_hat). Order M means list length M+1: [b0, b1, ..., bM].
IReadOnlyList WeightPolynomial,
///Absorption coefficient for H2O contribution ?_i,H2O [1/(atm·m)]. ?_0,* = 0 for the clear gas.
double KappaH2O,
///Absorption coefficient for CO2 contribution ?_i,CO2 [1/(atm·m)]. ?_0,* = 0 for the clear gas.
double KappaCO2
);
///
/// A bundle of gray gases plus normalization rule for temperature.
///
public sealed record WsggCoefficients(
IReadOnlyList Gases,
TemperatureNormalization TemperatureNormalization = TemperatureNormalization.By1000K
);
public enum TemperatureNormalization
{
None,
By1000K
}
///
/// Interface for supplying a particular coefficient set (e.g., Smith 1982 for a specific H2O/CO2 regime).
///
public interface IWSGGCoefficientsProvider
{
WsggCoefficients GetCoefficients();
}
///
/// Example provider skeleton for Smith, Shen & Friedman (1982).
/// Replace the placeholder numbers with the polynomial and ? values from Table(s) in the paper
/// for your target H2O/CO2 ratio/pressure range. Keep ?_0,* = 0 and choose polynomials so that S a_i(T) ˜ 1.
///
/// IMPORTANT:
/// - The original ASME paper is paywalled; paste the numbers from your licensed copy.
/// - Smith’s classic set uses N=5 gray gases (including the clear gas i=0), temperature range ~400–2500 K,
/// partial pressures in atm, path length in meters. Weighting factors are low-order polynomials in T/1000.
/// - Different tables exist for different p_H2O/p_CO2 ratios; pick the appropriate one for your application.
///
public sealed class Smith1982_AirFuel_FixedRatio_Stub : IWSGGCoefficientsProvider
{
public WsggCoefficients GetCoefficients()
{
// ***** PLACEHOLDER *****
// Put the real values from Smith et al. (1982) here. Below is a schematic with fake numbers (DO NOT USE).
// Structure: GrayGas(weightPolynomial: [b0, b1, b2, ...], kH2O, kCO2)
// i=0 should be the clear gas => kH2O=0, kCO2=0
var gases = new List
{
// i = 0 (clear gas) a0(T) polynomial; ?=0
new GrayGas(
WeightPolynomial: new double[] { 0.10, 0.00, 0.00 }, // <-- REPLACE
KappaH2O: 0.0, KappaCO2: 0.0),
// i = 1
new GrayGas(
WeightPolynomial: new double[] { 0.30, -0.05, 0.01 }, // <-- REPLACE
KappaH2O: 0.25, KappaCO2: 0.35), // <-- REPLACE
// i = 2
new GrayGas(
WeightPolynomial: new double[] { 0.25, 0.02, 0.00 }, // <-- REPLACE
KappaH2O: 1.20, KappaCO2: 1.60), // <-- REPLACE
// i = 3
new GrayGas(
WeightPolynomial: new double[] { 0.20, 0.02, -0.01 },// <-- REPLACE
KappaH2O: 6.50, KappaCO2: 7.50), // <-- REPLACE
// i = 4
new GrayGas(
WeightPolynomial: new double[] { 0.15, 0.01, 0.00 }, // <-- REPLACE
KappaH2O: 25.0, KappaCO2: 30.0) // <-- REPLACE
};
return new WsggCoefficients(gases, TemperatureNormalization.By1000K);
}
}
///
/// A minimal convenience provider you can use for testing or for inserting updated public models
/// (e.g., Johansson 2011, Dorigon 2013, or more recent 2025 updates) without touching the core code.
///
public sealed class CustomWsggProvider : IWSGGCoefficientsProvider
{
private readonly WsggCoefficients _coeffs;
public CustomWsggProvider(WsggCoefficients coeffs) => _coeffs = coeffs ?? throw new ArgumentNullException(nameof(coeffs));
public WsggCoefficients GetCoefficients() => _coeffs;
}
}
```