主题025:加权求和灰气体模型(WSGGM)

摘要

加权求和灰气体模型(Weighted Sum of Gray Gases Model, WSGGM)是工程辐射换热计算中最重要的非灰体气体辐射模型之一。本教程系统介绍WSGGM的基本原理、数学推导、参数拟合方法及其在工程实践中的应用。通过详细的理论分析和丰富的Python仿真案例,帮助读者深入理解WSGGM如何将复杂的非灰体气体辐射特性简化为多个灰气体的加权叠加,从而在保证计算精度的同时大幅降低计算成本。

关键词

WSGGM、灰气体、加权求和、非灰体气体、工程模型、辐射传热、气体发射率、吸收系数


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. 引言

1.1 非灰体气体辐射的挑战

在工程燃烧系统中,高温气体(如CO₂、H₂O、CO等)的辐射特性呈现出强烈的非灰体特征。与灰体假设不同,这些气体的吸收和发射能力随波长剧烈变化,在特定的光谱带(如CO₂的2.7μm和4.3μm带、H₂O的2.7μm和6.3μm带)表现出强烈的吸收峰,而在其他波段则几乎透明。

这种非灰体特性给辐射换热计算带来了巨大挑战:

  1. 计算复杂性:逐线计算(Line-by-Line, LBL)虽然精度最高,但需要在数千个波数点上求解辐射传递方程,计算量极其庞大。

  2. 存储需求:详细的光谱数据库(如HITRAN、HITEMP)包含数百万条谱线信息,对内存和存储提出很高要求。

  3. 工程实用性:在CFD耦合计算中,每个网格点、每个迭代步都需要计算气体辐射特性,LBL方法在工程应用中几乎不可行。

1.2 WSGGM的发展历史

加权求和灰气体模型的概念最早由Hottel和Sarofim在1967年提出,用于简化非灰体气体的辐射计算。其基本思想是用有限数量的灰气体来近似实际气体的非灰体辐射特性。

发展历程:

  • 1967年:Hottel和Sarofim提出原始WSGGM概念
  • 1970年代:Smith等人发展了基于指数宽度的灰气体模型(EWBM)
  • 1982年:Modest和Sikka提出了改进的WSGGM公式
  • 1990年代:基于详细光谱数据的WSGGM参数拟合方法成熟
  • 2000年后:针对特定工况(富氧燃烧、高压燃烧)的专用WSGGM参数集
  • 2010年后:与CFD软件(ANSYS Fluent、OpenFOAM等)的深度集成

1.3 WSGGM的工程意义

WSGGM在工程实践中具有重要意义:

  1. 计算效率:相比LBL方法,计算速度提升3-5个数量级
  2. 精度平衡:在典型燃烧工况下,辐射热流预测误差可控制在10-20%以内
  3. 易于实现:可直接集成到现有的灰体辐射求解器中
  4. 广泛验证:经过大量实验数据验证,可靠性高

2. WSGGM的基本原理

2.1 灰气体假设的局限性

灰气体假设认为介质的吸收系数与波长无关,即:

κλ=κ=常数 \kappa_{\lambda} = \kappa = \text{常数} κλ=κ=常数

在此假设下,辐射传递方程(RTE)可以沿全光谱积分,得到简化的灰体RTE:

dIds=κ(Ib−I) \frac{dI}{ds} = \kappa(I_b - I) dsdI=κ(IbI)

然而,实际气体(如CO₂、H₂O)的吸收系数随波长变化剧烈。以H₂O在1000K、1atm条件下的吸收系数为例,在2.7μm和6.3μm波段存在强烈的吸收峰,吸收系数可达100 m⁻¹以上,而在透明窗口区,吸收系数可能低于0.01 m⁻¹,相差四个数量级。

直接使用单一灰气体近似会导致:

  • 在强吸收波段低估辐射吸收
  • 在弱吸收波段高估辐射吸收
  • 整体辐射热流预测误差可达50%以上

2.2 加权求和的基本思想

WSGGM的核心思想是:用多个具有不同吸收系数的灰气体的加权叠加来近似实际气体的非灰体辐射特性

数学上,WSGGM将气体的全光谱发射率表示为:

εg=∑i=0Nai(T)(1−e−κiPL) \varepsilon_g = \sum_{i=0}^{N} a_i(T) \left(1 - e^{-\kappa_i P L}\right) εg=i=0Nai(T)(1eκiPL)

其中:

  • NNN:灰气体数量(通常3-5个)
  • ai(T)a_i(T)ai(T):第i个灰气体的权重系数(与温度相关)
  • κi\kappa_iκi:第i个灰气体的吸收系数(灰气体假设,与波长无关)
  • PPP:气体总压
  • LLL:辐射行程长度(特征长度)

物理意义理解:

想象将实际气体的复杂吸收光谱"分解"为多个灰气体:

  • 第一个灰气体(i=0i=0i=0)代表透明窗口区域,κ0=0\kappa_0 = 0κ0=0
  • 其他灰气体分别代表不同强度的吸收带
  • 权重系数aia_iai表示各灰气体对总辐射的贡献比例

2.3 从发射率到吸收系数

在辐射传递方程中,需要用到的是吸收系数κ\kappaκ而非发射率ε\varepsilonε。WSGGM通过以下方式定义等效的吸收系数:

κ=−ln⁡(1−εg)L=−ln⁡[∑i=0Naie−κiPL]L \kappa = \frac{-\ln(1-\varepsilon_g)}{L} = \frac{-\ln\left[\sum_{i=0}^{N} a_i e^{-\kappa_i P L}\right]}{L} κ=Lln(1εg)=Lln[i=0NaieκiPL]

在实际CFD计算中,更常用的方法是将辐射传递方程对每个灰气体分别求解:

dIids=κi(aiIb−Ii) \frac{dI_i}{ds} = \kappa_i(a_i I_b - I_i) dsdIi=κi(aiIbIi)

总辐射强度为各灰气体贡献的叠加:

I=∑i=0NIi I = \sum_{i=0}^{N} I_i I=i=0NIi

这种方法称为多灰气体法,是WSGGM在CFD中的标准实现方式。


3. WSGGM的数学推导

3.1 从详细光谱数据出发

考虑一个均匀等温气体层,其光谱发射率定义为:

ελ=1−e−κλL \varepsilon_{\lambda} = 1 - e^{-\kappa_{\lambda} L} ελ=1eκλL

全光谱发射率通过对普朗克加权积分得到:

εg=∫0∞ελEbλdλσT4=∫0∞(1−e−κλL)EbλdλσT4 \varepsilon_g = \frac{\int_0^{\infty} \varepsilon_{\lambda} E_{b\lambda} d\lambda}{\sigma T^4} = \frac{\int_0^{\infty} \left(1 - e^{-\kappa_{\lambda} L}\right) E_{b\lambda} d\lambda}{\sigma T^4} εg=σT40ελEdλ=σT40(1eκλL)Edλ

3.2 阶梯近似

WSGGM的核心数学技巧是对e−κλLe^{-\kappa_{\lambda} L}eκλL进行阶梯近似。将吸收系数κλ\kappa_{\lambda}κλ的取值范围划分为NNN个区间,每个区间用一个常数κi\kappa_iκi近似:

e−κλL≈∑i=0Nbi(κλ)e−κiL e^{-\kappa_{\lambda} L} \approx \sum_{i=0}^{N} b_i(\kappa_{\lambda}) e^{-\kappa_i L} eκλLi=0Nbi(κλ)eκiL

其中bib_ibi是指示函数,当κλ\kappa_{\lambda}κλ落在第i个区间时为1,否则为0。

将阶梯近似代入发射率表达式:

εg≈∑i=0N[∫0∞bi(κλ)EbλdλσT4](1−e−κiL) \varepsilon_g \approx \sum_{i=0}^{N} \left[\frac{\int_0^{\infty} b_i(\kappa_{\lambda}) E_{b\lambda} d\lambda}{\sigma T^4}\right] \left(1 - e^{-\kappa_i L}\right) εgi=0N[σT40bi(κλ)Edλ](1eκiL)

定义权重系数:

ai(T)=∫0∞bi(κλ)EbλdλσT4 a_i(T) = \frac{\int_0^{\infty} b_i(\kappa_{\lambda}) E_{b\lambda} d\lambda}{\sigma T^4} ai(T)=σT40bi(κλ)Edλ

这正是WSGGM的基本公式。

3.3 权重系数的归一化条件

权重系数必须满足归一化条件:

∑i=0Nai(T)=1 \sum_{i=0}^{N} a_i(T) = 1 i=0Nai(T)=1

这是因为当L→0L \to 0L0时,发射率应趋于0:

lim⁡L→0εg=∑i=0Nai(T)⋅0=0 \lim_{L \to 0} \varepsilon_g = \sum_{i=0}^{N} a_i(T) \cdot 0 = 0 L0limεg=i=0Nai(T)0=0

而当L→∞L \to \inftyL时,发射率应趋于1(光学厚极限):

lim⁡L→∞εg=∑i=0Nai(T)⋅1=1 \lim_{L \to \infty} \varepsilon_g = \sum_{i=0}^{N} a_i(T) \cdot 1 = 1 Llimεg=i=0Nai(T)1=1

3.4 温度依赖性的处理

权重系数aia_iai与温度相关,这是因为普朗克分布EbλE_{b\lambda}E随温度变化。通常采用多项式拟合:

ai(T)=∑j=0MbijTj a_i(T) = \sum_{j=0}^{M} b_{ij} T^j ai(T)=j=0MbijTj

或指数形式:

ai(T)=bi0+bi1T+bi2T2+bi3T3 a_i(T) = b_{i0} + b_{i1} T + b_{i2} T^2 + b_{i3} T^3 ai(T)=bi0+bi1T+bi2T2+bi3T3

对于工程应用,通常取M=3M=3M=3(三次多项式)即可获得足够的精度。


4. WSGGM参数拟合方法

4.1 参数拟合的目标函数

WSGGM参数拟合的目标是最小化模型预测与详细光谱数据之间的偏差。常用的目标函数包括:

1. 发射率误差最小化:

min⁡ai,κi∑k[εgLBL(Tk,Lk)−∑i=0Nai(Tk)(1−e−κiPLk)]2 \min_{a_i, \kappa_i} \sum_{k} \left[\varepsilon_g^{LBL}(T_k, L_k) - \sum_{i=0}^{N} a_i(T_k)(1-e^{-\kappa_i P L_k})\right]^2 ai,κimink[εgLBL(Tk,Lk)i=0Nai(Tk)(1eκiPLk)]2

2. 辐射源项误差最小化(更适合CFD应用):

min⁡∑k[κeffLBL(Tk,Lk)−κeffWSGGM(Tk,Lk)]2 \min \sum_{k} \left[\kappa_{eff}^{LBL}(T_k, L_k) - \kappa_{eff}^{WSGGM}(T_k, L_k)\right]^2 mink[κeffLBL(Tk,Lk)κeffWSGGM(Tk,Lk)]2

其中有效吸收系数定义为:

κeff=−ln⁡(1−εg)L \kappa_{eff} = \frac{-\ln(1-\varepsilon_g)}{L} κeff=Lln(1εg)

4.2 灰气体吸收系数的确定

灰气体吸收系数κi\kappa_iκi的选择对模型精度有重要影响。常用策略:

1. 对数均匀分布:

κi=κmin⋅(κmaxκmin)i/N \kappa_i = \kappa_{min} \cdot \left(\frac{\kappa_{max}}{\kappa_{min}}\right)^{i/N} κi=κmin(κminκmax)i/N

2. 基于光谱数据的聚类:

对详细光谱数据进行聚类分析,确定最优的κi\kappa_iκi值。

3. 固定值法:

基于经验选择固定的κi\kappa_iκi值,如:

  • κ0=0\kappa_0 = 0κ0=0(透明窗口)
  • κ1=0.1\kappa_1 = 0.1κ1=0.1 m⁻¹
  • κ2=1.0\kappa_2 = 1.0κ2=1.0 m⁻¹
  • κ3=10.0\kappa_3 = 10.0κ3=10.0 m⁻¹
  • κ4=100.0\kappa_4 = 100.0κ4=100.0 m⁻¹

4.3 权重系数的拟合

在确定κi\kappa_iκi后,权重系数aia_iai通过最小二乘法拟合得到。对于每个温度点TkT_kTk,求解以下优化问题:

min⁡ai∑j[εgLBL(Tk,Lj)−∑i=0Nai(1−e−κiPLj)]2 \min_{a_i} \sum_{j} \left[\varepsilon_g^{LBL}(T_k, L_j) - \sum_{i=0}^{N} a_i(1-e^{-\kappa_i P L_j})\right]^2 aiminj[εgLBL(Tk,Lj)i=0Nai(1eκiPLj)]2

约束条件:

  • ∑i=0Nai=1\sum_{i=0}^{N} a_i = 1i=0Nai=1
  • ai≥0a_i \geq 0ai0

这是一个带约束的线性最小二乘问题,可用拉格朗日乘子法或数值优化算法求解。

4.4 混合气体的处理

实际燃烧气体通常是CO₂和H₂O的混合物。WSGGM对混合气体的处理方式:

1. 独立灰气体法:

分别为CO₂和H₂O建立WSGGM参数,然后叠加:

εmix=εCO2+εH2O−Δε \varepsilon_{mix} = \varepsilon_{CO_2} + \varepsilon_{H_2O} - \Delta\varepsilon εmix=εCO2+εH2OΔε

其中Δε\Delta\varepsilonΔε是重叠修正项。

2. 联合灰气体法:

将CO₂和H₂O视为一个整体,直接拟合混合气体的WSGGM参数。这种方法精度更高,但需要针对不同的混合比例分别拟合。

4.5 典型WSGGM参数集

Smith等人(1982)参数集(空气燃烧):

灰气体 κi\kappa_iκi (m⁻¹atm⁻¹) aia_iai 多项式系数
0 0 a0=0.130−0.140Tr+0.041Tr2−0.004Tr3a_0 = 0.130 - 0.140T_r + 0.041T_r^2 - 0.004T_r^3a0=0.1300.140Tr+0.041Tr20.004Tr3
1 0.1 a1=0.595−0.450Tr+0.112Tr2−0.009Tr3a_1 = 0.595 - 0.450T_r + 0.112T_r^2 - 0.009T_r^3a1=0.5950.450Tr+0.112Tr20.009Tr3
2 1.0 a2=0.275−0.310Tr+0.074Tr2−0.006Tr3a_2 = 0.275 - 0.310T_r + 0.074T_r^2 - 0.006T_r^3a2=0.2750.310Tr+0.074Tr20.006Tr3
3 10.0 a3=0.000+0.900Tr−0.227Tr2+0.019Tr3a_3 = 0.000 + 0.900T_r - 0.227T_r^2 + 0.019T_r^3a3=0.000+0.900Tr0.227Tr2+0.019Tr3

其中Tr=T/1000T_r = T/1000Tr=T/1000(无量纲温度)。

Yin(2014)富氧燃烧参数集:

针对富氧燃烧(高CO₂浓度)工况优化的参数集,考虑了高CO₂/低N₂环境下的辐射特性变化。


5. WSGGM在CFD中的实现

5.1 与RTE求解器的耦合

在CFD计算中,WSGGM通常采用多灰气体法实现:

算法流程:

  1. 初始化:在每个网格点计算温度TTT、压力PPP、气体组分
  2. 计算权重系数:根据当前温度计算各灰气体的ai(T)a_i(T)ai(T)
  3. 求解多灰气体RTE
    • 对每个灰气体iii,求解:dIids=κi(aiIb−Ii)\frac{dI_i}{ds} = \kappa_i(a_i I_b - I_i)dsdIi=κi(aiIbIi)
    • 使用DOM、FVM或蒙特卡洛法求解
  4. 叠加辐射强度I=∑i=0NIiI = \sum_{i=0}^{N} I_iI=i=0NIi
  5. 计算辐射源项∇⋅qr=κ(4πIb−G)\nabla \cdot \mathbf{q}_r = \kappa(4\pi I_b - G)qr=κ(4πIbG)
  6. 能量方程耦合:将辐射源项加入能量方程

5.2 计算效率优化

1. 权重系数查表法:

预先计算不同温度下的aia_iai值,存储在查找表中,运行时直接插值,避免重复计算多项式。

2. 并行计算:

不同灰气体的RTE求解可以并行进行,因为各灰气体之间没有直接耦合。

3. 自适应灰气体数:

根据局部光学厚度动态调整灰气体数量,在光学薄区域减少灰气体数。

5.3 边界条件处理

对于灰体边界,第i个灰气体的边界条件为:

Iiwall=εwaiσTw4π+1−εwπ∫n⋅s′<0Ii(s′)∣n⋅s′∣dΩ′ I_i^{wall} = \frac{\varepsilon_w a_i \sigma T_w^4}{\pi} + \frac{1-\varepsilon_w}{\pi} \int_{\mathbf{n}\cdot\mathbf{s}'<0} I_i(\mathbf{s}') |\mathbf{n}\cdot\mathbf{s}'| d\Omega' Iiwall=πεwaiσTw4+π1εwns<0Ii(s)nsdΩ

注意权重系数aia_iai仅出现在发射项中,反射项不需要权重系数。

5.4 非均匀介质的处理

对于非均匀介质(温度、组分分布不均匀),WSGGM采用局部均匀近似

在每个网格点,基于局部温度和组分计算aia_iaiκi\kappa_iκi,然后求解RTE。这种方法忽略了光谱相关效应(spectral correlation effects),在温度梯度较大的区域可能引入误差。

改进方法——全光谱k分布法(FSK):

FSK方法通过重新排列光谱坐标,更好地处理非均匀介质,但计算成本也更高。


6. WSGGM的精度与局限性

6.1 精度评估

WSGGM的精度取决于多个因素:

1. 灰气体数量:

  • 2个灰气体:误差通常20-40%
  • 3个灰气体:误差通常10-20%
  • 4个灰气体:误差通常5-15%
  • 5个灰气体:误差通常<10%

2. 工况条件:

  • 在典型燃烧温度(1000-2000K)和压力(1-30atm)范围内精度较好
  • 在低温(<800K)或高压(>50atm)下误差增大
  • 富氧燃烧工况需要专用参数集

3. 行程长度:

  • 在中等光学厚度(0.1<τ<100.1 < \tau < 100.1<τ<10)范围内精度最佳
  • 光学薄极限(τ≪1\tau \ll 1τ1)和光学厚极限(τ≫10\tau \gg 10τ10)误差较大

6.2 与LBL方法的对比

案例:一维等温H₂O层

方法 发射率计算时间 相对误差
LBL 1000s 基准
WSGGM (4灰气体) 0.01s 8%
WSGGM (3灰气体) 0.008s 15%
灰气体近似 0.001s 45%

6.3 主要局限性

1. 光谱相关性忽略:

WSGGM假设各灰气体独立,忽略了实际光谱中的相关性。这在强非均匀介质中会导致误差。

2. 压力影响简化:

标准WSGGM采用简单的压力修正,难以准确描述高压下的谱线展宽效应。

3. 混合气体处理:

CO₂和H₂O的重叠处理是近似的,在特定波段(如2.7μm)误差较大。

4. 粒子辐射:

WSGGM仅处理气体辐射,对于含颗粒介质(如煤粉火焰),需要额外考虑颗粒辐射。

6.4 改进方向

1. 自适应WSGGM:

根据局部条件动态调整灰气体数量和参数。

2. 多尺度WSGGM:

结合详细光谱数据库和快速计算模型,实现多尺度模拟。

3. 机器学习辅助:

使用神经网络拟合WSGGM参数,提高精度和泛化能力。


7. 工程应用案例

7.1 锅炉炉膛辐射换热

应用场景: 燃煤锅炉炉膛内的辐射换热计算

关键参数:

  • 温度范围:1200-1800K
  • 压力:1 atm
  • 气体组分:CO₂(12%)、H₂O(8%)、N₂(80%)
  • 行程长度:5-15m

WSGGM设置:

  • 灰气体数:4
  • 吸收系数:0, 0.2, 2.0, 20.0 m⁻¹
  • 采用Smith参数集

结果: 与实验测量相比,炉膛出口辐射热流预测误差<12%。

7.2 燃气轮机燃烧室

应用场景: 航空发动机燃烧室高温燃气辐射

关键参数:

  • 温度范围:1800-2400K
  • 压力:10-30 atm
  • 气体组分:CO₂(8%)、H₂O(16%)、O₂(剩余)
  • 行程长度:0.1-0.5m

WSGGM设置:

  • 灰气体数:5
  • 采用高压修正参数集

结果: 壁面热流预测误差约15%,满足工程设计要求。

7.3 富氧燃烧系统

应用场景: 碳捕集与封存(CCS)中的富氧燃烧

关键参数:

  • 温度范围:1400-2000K
  • 压力:1 atm
  • 气体组分:CO₂(80-95%)、H₂O(5-20%)
  • 高CO₂浓度导致辐射特性显著变化

WSGGM设置:

  • 采用Yin(2014)富氧燃烧参数集
  • 灰气体数:4

结果: 相比标准WSGGM,富氧专用参数集将误差从25%降低到10%。


8. Python仿真案例

以下是基于WSGGM的Python仿真程序,包含多个实际应用案例。

案例1:WSGGM参数拟合与验证

"""
案例1:基于详细光谱数据的WSGGM参数拟合
验证WSGGM对H2O发射率的预测精度
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
import matplotlib
matplotlib.use('Agg')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

def planck_distribution(lam, T):
    """计算普朗克分布 [W/(m^2·sr·m)]"""
    h = 6.626e-34  # 普朗克常数 [J·s]
    c = 2.998e8    # 光速 [m/s]
    k = 1.381e-23  # 玻尔兹曼常数 [J/K]
    
    lam_m = lam * 1e-6  # 转换为米
    
    term1 = 2 * h * c**2 / lam_m**5
    term2 = np.exp(h * c / (lam_m * k * T)) - 1
    
    return term1 / term2

def generate_h2o_spectrum(lam, T, P, L):
    """
    生成H2O的简化吸收光谱
    基于典型吸收带特征
    """
    kappa = np.zeros_like(lam)
    
    # H2O主要吸收带 (简化模型)
    bands = [
        (1.38, 0.15, 50),   # 1.38 μm带
        (1.87, 0.12, 80),   # 1.87 μm带
        (2.70, 0.25, 150),  # 2.70 μm带 (强)
        (3.20, 0.10, 40),   # 3.20 μm带
        (6.30, 0.60, 200),  # 6.30 μm带 (强)
    ]
    
    for center, width, strength in bands:
        # 温度修正
        T_ref = 1000
        strength_T = strength * (T / T_ref)**0.5
        
        # 压力修正
        strength_P = strength_T * (P / 1.0)
        
        # 洛伦兹线型
        kappa += strength_P * (width/2)**2 / ((lam - center)**2 + (width/2)**2)
    
    # 添加连续吸收
    kappa += 0.5 * np.exp(-((lam - 10) / 5)**2)
    
    return kappa

def calculate_lbl_emissivity(T, P, L, n_points=10000):
    """
    使用逐线计算(LBL)方法计算发射率
    作为基准数据
    """
    lam_min, lam_max = 0.5, 20.0  # μm
    lam = np.linspace(lam_min, lam_max, n_points)
    
    # 计算吸收系数
    kappa = generate_h2o_spectrum(lam, T, P, L)
    
    # 计算光谱发射率
    epsilon_lam = 1 - np.exp(-kappa * L)
    
    # 计算普朗克分布
    E_b_lam = planck_distribution(lam, T)
    
    # 全光谱发射率
    numerator = np.trapz(epsilon_lam * E_b_lam, lam)
    denominator = np.trapz(E_b_lam, lam)
    
    epsilon_total = numerator / denominator
    
    return epsilon_total, lam, kappa, epsilon_lam

def wsggm_emissivity(T, P, L, kappa_i, a_coeffs):
    """
    计算WSGGM发射率
    kappa_i: 灰气体吸收系数数组
    a_coeffs: 权重系数多项式系数 [N_gas, 4]
    """
    T_r = T / 1000.0  # 无量纲温度
    
    epsilon = 0
    for i, kappa in enumerate(kappa_i):
        # 计算权重系数
        a_i = (a_coeffs[i, 0] + a_coeffs[i, 1] * T_r + 
               a_coeffs[i, 2] * T_r**2 + a_coeffs[i, 3] * T_r**3)
        
        # 确保权重非负
        a_i = max(0, a_i)
        
        # 发射率贡献
        epsilon += a_i * (1 - np.exp(-kappa * P * L))
    
    return epsilon

def fit_wsggm_parameters(T_range, L_range, P=1.0, n_gas=4):
    """
    拟合WSGGM参数
    """
    # 生成LBL基准数据
    print("生成LBL基准数据...")
    lbl_data = []
    for T in T_range:
        for L in L_range:
            epsilon_lbl, _, _, _ = calculate_lbl_emissivity(T, P, L)
            lbl_data.append((T, L, epsilon_lbl))
    
    # 预设灰气体吸收系数 (对数均匀分布)
    kappa_min, kappa_max = 0.01, 100.0
    kappa_i = np.logspace(np.log10(kappa_min), np.log10(kappa_max), n_gas-1)
    kappa_i = np.insert(kappa_i, 0, 0)  # 添加透明窗口
    
    print(f"灰气体吸收系数: {kappa_i}")
    
    # 拟合权重系数
    # 对每个温度点拟合权重
    a_coeffs_list = []
    
    for T in T_range:
        # 收集该温度下的数据
        T_data = [(L, eps) for (T_i, L, eps) in lbl_data if T_i == T]
        L_vals = np.array([d[0] for d in T_data])
        eps_vals = np.array([d[1] for d in T_data])
        
        # 定义目标函数
        def objective(a):
            error = 0
            for L, eps_lbl in zip(L_vals, eps_vals):
                eps_wsggm = sum(a[i] * (1 - np.exp(-kappa_i[i] * P * L)) 
                               for i in range(n_gas))
                error += (eps_lbl - eps_wsggm)**2
            return error
        
        # 约束条件
        constraints = [
            {'type': 'eq', 'fun': lambda a: np.sum(a) - 1}  # 归一化
        ]
        bounds = [(0, 1) for _ in range(n_gas)]
        
        # 初始猜测
        a0 = np.ones(n_gas) / n_gas
        
        # 优化
        result = minimize(objective, a0, method='SLSQP', 
                         bounds=bounds, constraints=constraints)
        
        a_coeffs_list.append(result.x)
        print(f"T={T}K: 权重系数 = {result.x}")
    
    # 拟合温度多项式
    T_r_vals = T_range / 1000.0
    a_coeffs = np.zeros((n_gas, 4))
    
    for i in range(n_gas):
        a_i_vals = [a_coeffs_list[j][i] for j in range(len(T_range))]
        coeffs = np.polyfit(T_r_vals, a_i_vals, 3)
        a_coeffs[i, :] = coeffs[::-1]  # 转换为常数项在前
    
    return kappa_i, a_coeffs, lbl_data

def case1_wsggm_fitting():
    """案例1:WSGGM参数拟合与验证"""
    print("=" * 60)
    print("案例1:WSGGM参数拟合与验证")
    print("=" * 60)
    
    # 定义温度范围和行程长度范围
    T_range = np.array([800, 1000, 1200, 1400, 1600, 1800, 2000])
    L_range = np.logspace(-2, 1, 20)  # 0.01 到 10 m
    
    # 拟合WSGGM参数
    kappa_i, a_coeffs, lbl_data = fit_wsggm_parameters(T_range, L_range)
    
    print("\n拟合的WSGGM参数:")
    print(f"灰气体吸收系数: {kappa_i}")
    print("权重系数多项式 (a = b0 + b1*Tr + b2*Tr^2 + b3*Tr^3):")
    for i in range(len(kappa_i)):
        print(f"  灰气体{i} (κ={kappa_i[i]:.3f}): "
              f"b={a_coeffs[i]}")
    
    # 验证WSGGM精度
    print("\n验证WSGGM精度...")
    
    # 创建验证图
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 不同温度下的发射率对比
    ax1 = axes[0, 0]
    L_plot = np.logspace(-2, 1, 100)
    
    colors = plt.cm.jet(np.linspace(0, 1, len(T_range)))
    for T, color in zip(T_range, colors):
        # LBL计算
        eps_lbl = []
        for L in L_plot:
            eps, _, _, _ = calculate_lbl_emissivity(T, 1.0, L)
            eps_lbl.append(eps)
        
        # WSGGM计算
        eps_wsggm = [wsggm_emissivity(T, 1.0, L, kappa_i, a_coeffs) for L in L_plot]
        
        ax1.semilogx(L_plot, eps_lbl, '-', color=color, linewidth=2, label=f'LBL T={T}K')
        ax1.semilogx(L_plot, eps_wsggm, '--', color=color, linewidth=2, label=f'WSGGM T={T}K')
    
    ax1.set_xlabel('行程长度 L [m]', fontsize=12)
    ax1.set_ylabel('发射率 ε', fontsize=12)
    ax1.set_title('发射率随行程长度的变化', fontsize=14)
    ax1.legend(fontsize=8, ncol=2)
    ax1.grid(True, alpha=0.3)
    ax1.set_ylim(0, 1)
    
    # 图2: 误差分析
    ax2 = axes[0, 1]
    errors = []
    for T in T_range:
        for L in L_range:
            eps_lbl, _, _, _ = calculate_lbl_emissivity(T, 1.0, L)
            eps_wsggm = wsggm_emissivity(T, 1.0, L, kappa_i, a_coeffs)
            errors.append(abs(eps_lbl - eps_wsggm) / eps_lbl * 100 if eps_lbl > 0.01 else 0)
    
    ax2.hist(errors, bins=30, edgecolor='black', alpha=0.7)
    ax2.set_xlabel('相对误差 [%]', fontsize=12)
    ax2.set_ylabel('频次', fontsize=12)
    ax2.set_title(f'WSGGM预测误差分布 (平均误差: {np.mean(errors):.2f}%)', fontsize=14)
    ax2.axvline(np.mean(errors), color='r', linestyle='--', linewidth=2, label=f'平均误差: {np.mean(errors):.2f}%')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 图3: 权重系数随温度的变化
    ax3 = axes[1, 0]
    T_plot = np.linspace(800, 2000, 100)
    T_r_plot = T_plot / 1000.0
    
    for i in range(len(kappa_i)):
        a_plot = (a_coeffs[i, 0] + a_coeffs[i, 1] * T_r_plot + 
                  a_coeffs[i, 2] * T_r_plot**2 + a_coeffs[i, 3] * T_r_plot**3)
        a_plot = np.maximum(0, a_plot)  # 确保非负
        ax3.plot(T_plot, a_plot, linewidth=2, label=f'灰气体{i} (κ={kappa_i[i]:.2f})')
    
    ax3.set_xlabel('温度 T [K]', fontsize=12)
    ax3.set_ylabel('权重系数 a', fontsize=12)
    ax3.set_title('权重系数随温度的变化', fontsize=14)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 图4: 光谱吸收系数分布
    ax4 = axes[1, 1]
    lam = np.linspace(0.5, 15, 1000)
    kappa_spectrum = generate_h2o_spectrum(lam, 1200, 1.0, 1.0)
    
    ax4.fill_between(lam, kappa_spectrum, alpha=0.3, color='blue')
    ax4.plot(lam, kappa_spectrum, 'b-', linewidth=1.5)
    
    # 标注灰气体吸收系数
    for kappa in kappa_i[1:]:  # 跳过透明窗口
        ax4.axhline(y=kappa, color='r', linestyle='--', alpha=0.5)
        ax4.text(14, kappa*1.1, f'κ={kappa:.2f}', fontsize=9, color='red')
    
    ax4.set_xlabel('波长 λ [μm]', fontsize=12)
    ax4.set_ylabel('吸收系数 κ [m⁻¹]', fontsize=12)
    ax4.set_title('H₂O光谱吸收系数分布 (T=1200K)', fontsize=14)
    ax4.set_yscale('log')
    ax4.grid(True, alpha=0.3)
    ax4.set_xlim(0.5, 15)
    
    plt.tight_layout()
    plt.savefig('case1_wsggm_fitting.png', dpi=150, bbox_inches='tight')
    plt.close()
    
    print("案例1完成:已保存 case1_wsggm_fitting.png")
    
    return kappa_i, a_coeffs

if __name__ == '__main__':
    case1_wsggm_fitting()

案例2:一维介质辐射换热计算

"""
主题025:加权求和灰气体模型(WSGGM)仿真程序
包含6个案例和3个GIF动画
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
from scipy.optimize import minimize
from scipy.integrate import trapezoid
import matplotlib
matplotlib.use('Agg')
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

# 兼容不同numpy版本
try:
    from numpy import trapz
except ImportError:
    from scipy.integrate import trapezoid as trapz

# ==================== 基础函数定义 ====================

def planck_distribution(lam, T):
    """计算普朗克分布 [W/(m^2·sr·m)]"""
    h = 6.626e-34
    c = 2.998e8
    k = 1.381e-23
    lam_m = lam * 1e-6
    term1 = 2 * h * c**2 / lam_m**5
    term2 = np.exp(h * c / (lam_m * k * T)) - 1
    return term1 / term2

def generate_h2o_spectrum(lam, T, P, L):
    """生成H2O的简化吸收光谱"""
    kappa = np.zeros_like(lam)
    bands = [
        (1.38, 0.15, 50),
        (1.87, 0.12, 80),
        (2.70, 0.25, 150),
        (3.20, 0.10, 40),
        (6.30, 0.60, 200),
    ]
    for center, width, strength in bands:
        T_ref = 1000
        strength_T = strength * (T / T_ref)**0.5
        strength_P = strength_T * (P / 1.0)
        kappa += strength_P * (width/2)**2 / ((lam - center)**2 + (width/2)**2)
    kappa += 0.5 * np.exp(-((lam - 10) / 5)**2)
    return kappa

def calculate_lbl_emissivity(T, P, L, n_points=5000):
    """使用逐线计算(LBL)方法计算发射率"""
    lam_min, lam_max = 0.5, 20.0
    lam = np.linspace(lam_min, lam_max, n_points)
    kappa = generate_h2o_spectrum(lam, T, P, L)
    epsilon_lam = 1 - np.exp(-kappa * L)
    E_b_lam = planck_distribution(lam, T)
    numerator = trapz(epsilon_lam * E_b_lam, lam)
    denominator = trapz(E_b_lam, lam)
    epsilon_total = numerator / denominator
    return epsilon_total, lam, kappa, epsilon_lam

def wsggm_emissivity(T, P, L, kappa_i, a_coeffs):
    """计算WSGGM发射率"""
    T_r = T / 1000.0
    epsilon = 0
    for i, kappa in enumerate(kappa_i):
        a_i = (a_coeffs[i, 0] + a_coeffs[i, 1] * T_r + 
               a_coeffs[i, 2] * T_r**2 + a_coeffs[i, 3] * T_r**3)
        a_i = max(0, min(1, a_i))
        epsilon += a_i * (1 - np.exp(-kappa * P * L))
    return epsilon

def get_smith_wsggm_params():
    """获取Smith(1982) WSGGM参数"""
    kappa_i = np.array([0.0, 0.1, 1.0, 10.0])
    a_coeffs = np.array([
        [0.130, -0.140, 0.041, -0.004],
        [0.595, -0.450, 0.112, -0.009],
        [0.275, -0.310, 0.074, -0.006],
        [0.000, 0.900, -0.227, 0.019]
    ])
    return kappa_i, a_coeffs

# ==================== 案例1:WSGGM参数拟合与验证 ====================

def case1_wsggm_fitting():
    """案例1:基于详细光谱数据的WSGGM参数拟合与验证"""
    print("=" * 60)
    print("案例1:WSGGM参数拟合与验证")
    print("=" * 60)
    
    T_range = np.array([800, 1000, 1200, 1400, 1600, 1800, 2000])
    L_range = np.logspace(-2, 1, 15)
    
    # 生成LBL基准数据
    print("生成LBL基准数据...")
    lbl_data = []
    for T in T_range:
        for L in L_range:
            epsilon_lbl, _, _, _ = calculate_lbl_emissivity(T, 1.0, L)
            lbl_data.append((T, L, epsilon_lbl))
    
    # 预设灰气体吸收系数
    n_gas = 4
    kappa_min, kappa_max = 0.01, 100.0
    kappa_i = np.logspace(np.log10(kappa_min), np.log10(kappa_max), n_gas-1)
    kappa_i = np.insert(kappa_i, 0, 0)
    print(f"灰气体吸收系数: {kappa_i}")
    
    # 拟合权重系数
    a_coeffs_list = []
    for T in T_range:
        T_data = [(L, eps) for (T_i, L, eps) in lbl_data if T_i == T]
        L_vals = np.array([d[0] for d in T_data])
        eps_vals = np.array([d[1] for d in T_data])
        
        def objective(a):
            error = 0
            for L, eps_lbl in zip(L_vals, eps_vals):
                eps_wsggm = sum(a[i] * (1 - np.exp(-kappa_i[i] * L)) for i in range(n_gas))
                error += (eps_lbl - eps_wsggm)**2
            return error
        
        constraints = [{'type': 'eq', 'fun': lambda a: np.sum(a) - 1}]
        bounds = [(0, 1) for _ in range(n_gas)]
        a0 = np.ones(n_gas) / n_gas
        result = minimize(objective, a0, method='SLSQP', bounds=bounds, constraints=constraints)
        a_coeffs_list.append(result.x)
    
    # 拟合温度多项式
    T_r_vals = T_range / 1000.0
    a_coeffs = np.zeros((n_gas, 4))
    for i in range(n_gas):
        a_i_vals = [a_coeffs_list[j][i] for j in range(len(T_range))]
        coeffs = np.polyfit(T_r_vals, a_i_vals, 3)
        a_coeffs[i, :] = coeffs[::-1]
    
    # 创建验证图
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 不同温度下的发射率对比
    ax1 = axes[0, 0]
    L_plot = np.logspace(-2, 1, 100)
    colors = plt.cm.jet(np.linspace(0, 1, len(T_range)))
    for T, color in zip(T_range, colors):
        eps_lbl = []
        for L in L_plot:
            eps, _, _, _ = calculate_lbl_emissivity(T, 1.0, L)
            eps_lbl.append(eps)
        eps_wsggm = [wsggm_emissivity(T, 1.0, L, kappa_i, a_coeffs) for L in L_plot]
        ax1.semilogx(L_plot, eps_lbl, '-', color=color, linewidth=2, label=f'LBL T={T}K')
        ax1.semilogx(L_plot, eps_wsggm, '--', color=color, linewidth=2)
    ax1.set_xlabel('行程长度 L [m]', fontsize=12)
    ax1.set_ylabel('发射率 ε', fontsize=12)
    ax1.set_title('发射率随行程长度的变化', fontsize=14)
    ax1.legend(fontsize=8, ncol=2)
    ax1.grid(True, alpha=0.3)
    ax1.set_ylim(0, 1)
    
    # 图2: 误差分析
    ax2 = axes[0, 1]
    errors = []
    for T in T_range:
        for L in L_range:
            eps_lbl, _, _, _ = calculate_lbl_emissivity(T, 1.0, L)
            eps_wsggm = wsggm_emissivity(T, 1.0, L, kappa_i, a_coeffs)
            if eps_lbl > 0.01:
                errors.append(abs(eps_lbl - eps_wsggm) / eps_lbl * 100)
    ax2.hist(errors, bins=25, edgecolor='black', alpha=0.7, color='steelblue')
    ax2.set_xlabel('相对误差 [%]', fontsize=12)
    ax2.set_ylabel('频次', fontsize=12)
    ax2.set_title(f'WSGGM预测误差分布 (平均误差: {np.mean(errors):.2f}%)', fontsize=14)
    ax2.axvline(np.mean(errors), color='r', linestyle='--', linewidth=2)
    ax2.grid(True, alpha=0.3)
    
    # 图3: 权重系数随温度的变化
    ax3 = axes[1, 0]
    T_plot = np.linspace(800, 2000, 100)
    T_r_plot = T_plot / 1000.0
    for i in range(len(kappa_i)):
        a_plot = (a_coeffs[i, 0] + a_coeffs[i, 1] * T_r_plot + 
                  a_coeffs[i, 2] * T_r_plot**2 + a_coeffs[i, 3] * T_r_plot**3)
        a_plot = np.maximum(0, a_plot)
        ax3.plot(T_plot, a_plot, linewidth=2, label=f'灰气体{i} (κ={kappa_i[i]:.2f})')
    ax3.set_xlabel('温度 T [K]', fontsize=12)
    ax3.set_ylabel('权重系数 a', fontsize=12)
    ax3.set_title('权重系数随温度的变化', fontsize=14)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 图4: 光谱吸收系数分布
    ax4 = axes[1, 1]
    lam = np.linspace(0.5, 15, 1000)
    kappa_spectrum = generate_h2o_spectrum(lam, 1200, 1.0, 1.0)
    ax4.fill_between(lam, kappa_spectrum, alpha=0.3, color='blue')
    ax4.plot(lam, kappa_spectrum, 'b-', linewidth=1.5)
    for kappa in kappa_i[1:]:
        ax4.axhline(y=kappa, color='r', linestyle='--', alpha=0.5)
        ax4.text(14, kappa*1.1, f'κ={kappa:.2f}', fontsize=9, color='red')
    ax4.set_xlabel('波长 λ [μm]', fontsize=12)
    ax4.set_ylabel('吸收系数 κ [m⁻¹]', fontsize=12)
    ax4.set_title('H₂O光谱吸收系数分布 (T=1200K)', fontsize=14)
    ax4.set_yscale('log')
    ax4.grid(True, alpha=0.3)
    ax4.set_xlim(0.5, 15)
    
    plt.tight_layout()
    plt.savefig('case1_wsggm_fitting.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例1完成:已保存 case1_wsggm_fitting.png")

# ==================== 案例2:一维介质辐射换热计算 ====================

def solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa, L):
    """求解一维灰体介质辐射换热"""
    sigma = 5.67e-8
    dx = L / (N - 1)
    x = np.linspace(0, L, N)
    
    # 离散坐标法 (S2近似)
    mu = 1.0 / np.sqrt(3)
    
    # 初始化辐射强度
    I_plus = np.zeros(N)  # 正向
    I_minus = np.zeros(N)  # 负向
    
    # 边界条件
    I_plus[0] = sigma * T_w1**4 / np.pi
    I_minus[-1] = sigma * T_w2**4 / np.pi
    
    # 迭代求解
    for _ in range(1000):
        I_plus_old = I_plus.copy()
        I_minus_old = I_minus.copy()
        
        # 正向扫描
        for i in range(1, N):
            S = sigma * T_g**4 / np.pi
            I_plus[i] = (I_plus[i-1] * (mu/dx - kappa/2) + kappa * S) / (mu/dx + kappa/2)
        
        # 负向扫描
        for i in range(N-2, -1, -1):
            S = sigma * T_g**4 / np.pi
            I_minus[i] = (I_minus[i+1] * (mu/dx - kappa/2) + kappa * S) / (mu/dx + kappa/2)
        
        if np.max(np.abs(I_plus - I_plus_old)) < 1e-6 and np.max(np.abs(I_minus - I_minus_old)) < 1e-6:
            break
    
    # 计算辐射热流
    q = np.pi * mu * (I_plus - I_minus)
    G = 2 * np.pi * (I_plus + I_minus)
    
    return x, q, G

def case2_1d_radiation_wsggm():
    """案例2:使用WSGGM计算一维介质辐射换热"""
    print("=" * 60)
    print("案例2:一维介质辐射换热计算")
    print("=" * 60)
    
    # 参数设置
    T_g = 1500  # 气体温度 [K]
    T_w1 = 1000  # 左壁温度 [K]
    T_w2 = 800   # 右壁温度 [K]
    L = 2.0      # 介质厚度 [m]
    P = 1.0      # 压力 [atm]
    N = 50       # 网格数
    
    # 获取WSGGM参数
    kappa_i, a_coeffs = get_smith_wsggm_params()
    
    # 计算各灰气体的权重系数
    T_r = T_g / 1000.0
    a_i = np.array([a_coeffs[j, 0] + a_coeffs[j, 1] * T_r + 
                    a_coeffs[j, 2] * T_r**2 + a_coeffs[j, 3] * T_r**3 for j in range(len(kappa_i))])
    a_i = np.maximum(0, a_i)
    a_i = a_i / np.sum(a_i)  # 重新归一化
    
    print(f"温度: {T_g}K, 权重系数: {a_i}")
    
    # 求解各灰气体的辐射场
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    x_total = None
    q_total = None
    
    colors = plt.cm.tab10(np.linspace(0, 1, len(kappa_i)))
    
    # 图1: 各灰气体的辐射热流
    ax1 = axes[0, 0]
    for i, (kappa, a, color) in enumerate(zip(kappa_i, a_i, colors)):
        x, q, G = solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa, L)
        if x_total is None:
            x_total = x
            q_total = np.zeros_like(q)
        q_total += a * q
        ax1.plot(x, q/1000, color=color, linewidth=2, label=f'灰气体{i} (κ={kappa:.2f}, a={a:.3f})')
    
    ax1.plot(x_total, q_total/1000, 'k--', linewidth=3, label='WSGGM总热流')
    ax1.set_xlabel('位置 x [m]', fontsize=12)
    ax1.set_ylabel('辐射热流 q [kW/m²]', fontsize=12)
    ax1.set_title('各灰气体的辐射热流分布', fontsize=14)
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 图2: 总辐射热流对比
    ax2 = axes[0, 1]
    
    # 灰气体近似 (单一吸收系数)
    kappa_gray = -np.log(1 - wsggm_emissivity(T_g, P, L, kappa_i, a_coeffs)) / L
    x_gray, q_gray, _ = solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa_gray, L)
    
    ax2.plot(x_total, q_total/1000, 'b-', linewidth=3, label='WSGGM (4灰气体)')
    ax2.plot(x_gray, q_gray/1000, 'r--', linewidth=2, label=f'灰气体近似 (κ={kappa_gray:.3f})')
    ax2.set_xlabel('位置 x [m]', fontsize=12)
    ax2.set_ylabel('辐射热流 q [kW/m²]', fontsize=12)
    ax2.set_title('WSGGM与灰气体近似对比', fontsize=14)
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 图3: 不同光学厚度下的热流
    ax3 = axes[1, 0]
    L_values = [0.5, 1.0, 2.0, 4.0]
    for L_val in L_values:
        kappa_eff = -np.log(1 - wsggm_emissivity(T_g, P, L_val, kappa_i, a_coeffs)) / L_val
        x, q, _ = solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa_eff, L_val)
        tau = kappa_eff * L_val
        ax3.plot(x, q/1000, linewidth=2, label=f'L={L_val}m, τ={tau:.2f}')
    ax3.set_xlabel('位置 x [m]', fontsize=12)
    ax3.set_ylabel('辐射热流 q [kW/m²]', fontsize=12)
    ax3.set_title('不同光学厚度下的辐射热流', fontsize=14)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 图4: 壁面热流随介质厚度的变化
    ax4 = axes[1, 1]
    L_range = np.linspace(0.1, 5.0, 50)
    q_w1_wsggm = []
    q_w1_gray = []
    
    for L_val in L_range:
        # WSGGM
        kappa_eff = -np.log(1 - wsggm_emissivity(T_g, P, L_val, kappa_i, a_coeffs)) / L_val
        x, q, _ = solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa_eff, L_val)
        q_w1_wsggm.append(q[0])
        
        # 灰气体
        x_gray, q_gray, _ = solve_1d_radiation_gray(N, T_g, T_w1, T_w2, kappa_eff, L_val)
        q_w1_gray.append(q_gray[0])
    
    ax4.plot(L_range, np.array(q_w1_wsggm)/1000, 'b-', linewidth=2, label='WSGGM')
    ax4.plot(L_range, np.array(q_w1_gray)/1000, 'r--', linewidth=2, label='灰气体近似')
    ax4.set_xlabel('介质厚度 L [m]', fontsize=12)
    ax4.set_ylabel('壁面热流 q_w [kW/m²]', fontsize=12)
    ax4.set_title('壁面热流随介质厚度的变化', fontsize=14)
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('case2_1d_radiation_wsggm.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例2完成:已保存 case2_1d_radiation_wsggm.png")

# ==================== 案例3:WSGGM与LBL对比分析 ====================

def case3_wsggm_vs_lbl():
    """案例3:WSGGM与逐线计算(LBL)的详细对比"""
    print("=" * 60)
    print("案例3:WSGGM与LBL对比分析")
    print("=" * 60)
    
    # 获取Smith WSGGM参数
    kappa_i, a_coeffs = get_smith_wsggm_params()
    
    # 测试条件
    T_range = np.linspace(800, 2000, 20)
    L_values = [0.1, 0.5, 1.0, 2.0, 5.0]
    P = 1.0
    
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 不同行程长度下的发射率-温度曲线
    ax1 = axes[0, 0]
    colors = plt.cm.viridis(np.linspace(0, 1, len(L_values)))
    
    for L, color in zip(L_values, colors):
        eps_lbl_list = []
        eps_wsggm_list = []
        for T in T_range:
            eps_lbl, _, _, _ = calculate_lbl_emissivity(T, P, L)
            eps_wsggm = wsggm_emissivity(T, P, L, kappa_i, a_coeffs)
            eps_lbl_list.append(eps_lbl)
            eps_wsggm_list.append(eps_wsggm)
        
        ax1.plot(T_range, eps_lbl_list, '-', color=color, linewidth=2, label=f'LBL L={L}m')
        ax1.plot(T_range, eps_wsggm_list, '--', color=color, linewidth=2)
    
    ax1.set_xlabel('温度 T [K]', fontsize=12)
    ax1.set_ylabel('发射率 ε', fontsize=12)
    ax1.set_title('发射率随温度的变化', fontsize=14)
    ax1.legend(fontsize=8)
    ax1.grid(True, alpha=0.3)
    ax1.set_ylim(0, 1)
    
    # 图2: 误差热力图
    ax2 = axes[0, 1]
    T_grid = np.linspace(800, 2000, 15)
    L_grid = np.logspace(-1, 0.7, 15)
    error_grid = np.zeros((len(T_grid), len(L_grid)))
    
    for i, T in enumerate(T_grid):
        for j, L in enumerate(L_grid):
            eps_lbl, _, _, _ = calculate_lbl_emissivity(T, P, L)
            eps_wsggm = wsggm_emissivity(T, P, L, kappa_i, a_coeffs)
            if eps_lbl > 0.01:
                error_grid[i, j] = abs(eps_lbl - eps_wsggm) / eps_lbl * 100
    
    im = ax2.contourf(L_grid, T_grid, error_grid, levels=20, cmap='YlOrRd')
    plt.colorbar(im, ax=ax2, label='相对误差 [%]')
    ax2.set_xlabel('行程长度 L [m]', fontsize=12)
    ax2.set_ylabel('温度 T [K]', fontsize=12)
    ax2.set_title('WSGGM预测误差分布', fontsize=14)
    ax2.set_xscale('log')
    
    # 图3: 不同灰气体数量的精度对比
    ax3 = axes[1, 0]
    n_gas_values = [2, 3, 4, 5]
    T_test = 1200
    L_test_range = np.logspace(-2, 1, 50)
    
    for n_gas in n_gas_values:
        # 简化处理:使用预设的kappa值
        if n_gas == 2:
            kappa_test = np.array([0.0, 1.0])
            a_test = np.array([[0.5, 0, 0, 0], [0.5, 0, 0, 0]])
        elif n_gas == 3:
            kappa_test = np.array([0.0, 0.3, 3.0])
            a_test = np.array([[0.3, 0, 0, 0], [0.4, 0, 0, 0], [0.3, 0, 0, 0]])
        elif n_gas == 4:
            kappa_test, a_test = get_smith_wsggm_params()
        else:
            kappa_test = np.array([0.0, 0.1, 0.5, 2.0, 10.0])
            a_test = np.array([[0.2, 0, 0, 0], [0.25, 0, 0, 0], [0.25, 0, 0, 0], 
                               [0.2, 0, 0, 0], [0.1, 0, 0, 0]])
        
        errors_n = []
        for L in L_test_range:
            eps_lbl, _, _, _ = calculate_lbl_emissivity(T_test, P, L)
            eps_wsggm = wsggm_emissivity(T_test, P, L, kappa_test, a_test)
            if eps_lbl > 0.01:
                errors_n.append(abs(eps_lbl - eps_wsggm) / eps_lbl * 100)
            else:
                errors_n.append(0)
        
        ax3.semilogx(L_test_range, errors_n, linewidth=2, label=f'{n_gas}灰气体')
    
    ax3.set_xlabel('行程长度 L [m]', fontsize=12)
    ax3.set_ylabel('相对误差 [%]', fontsize=12)
    ax3.set_title(f'不同灰气体数量的精度对比 (T={T_test}K)', fontsize=14)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 图4: 有效吸收系数对比
    ax4 = axes[1, 1]
    L_plot = np.logspace(-2, 1, 100)
    T_test = 1500
    
    kappa_eff_lbl = []
    kappa_eff_wsggm = []
    
    for L in L_plot:
        eps_lbl, _, _, _ = calculate_lbl_emissivity(T_test, P, L)
        eps_wsggm = wsggm_emissivity(T_test, P, L, kappa_i, a_coeffs)
        
        kappa_eff_lbl.append(-np.log(1 - eps_lbl) / L if eps_lbl < 0.99 else 10)
        kappa_eff_wsggm.append(-np.log(1 - eps_wsggm) / L if eps_wsggm < 0.99 else 10)
    
    ax4.loglog(L_plot, kappa_eff_lbl, 'b-', linewidth=2, label='LBL')
    ax4.loglog(L_plot, kappa_eff_wsggm, 'r--', linewidth=2, label='WSGGM')
    ax4.set_xlabel('行程长度 L [m]', fontsize=12)
    ax4.set_ylabel('有效吸收系数 κ_eff [m⁻¹]', fontsize=12)
    ax4.set_title(f'有效吸收系数对比 (T={T_test}K)', fontsize=14)
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('case3_wsggm_vs_lbl.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例3完成:已保存 case3_wsggm_vs_lbl.png")

# ==================== 案例4:锅炉炉膛辐射换热模拟 ====================

def case4_boiler_furnace():
    """案例4:锅炉炉膛辐射换热模拟"""
    print("=" * 60)
    print("案例4:锅炉炉膛辐射换热模拟")
    print("=" * 60)
    
    # 炉膛参数
    H = 15.0  # 炉膛高度 [m]
    D = 8.0   # 炉膛直径 [m]
    T_wall = 800  # 水冷壁温度 [K]
    epsilon_wall = 0.8  # 壁面发射率
    
    # 温度分布 (抛物线型)
    z = np.linspace(0, H, 100)
    T_center = 1800  # 中心最高温度
    T_gas = T_wall + (T_center - T_wall) * np.sin(np.pi * z / H)
    
    # 气体组分
    X_CO2 = 0.12
    X_H2O = 0.08
    P = 1.0  # atm
    
    # WSGGM参数
    kappa_i, a_coeffs = get_smith_wsggm_params()
    
    # 计算各位置的发射率和吸收系数
    epsilon_gas = []
    kappa_eff = []
    
    for T in T_gas:
        # 简化:假设平均行程长度 L = 0.9 * D (球形近似)
        L_mean = 0.9 * D
        eps = wsggm_emissivity(T, P, L_mean, kappa_i, a_coeffs)
        epsilon_gas.append(eps)
        if eps < 0.99:
            kappa_eff.append(-np.log(1 - eps) / L_mean)
        else:
            kappa_eff.append(10.0)
    
    epsilon_gas = np.array(epsilon_gas)
    kappa_eff = np.array(kappa_eff)
    
    # 计算辐射热流 (简化模型)
    sigma = 5.67e-8
    q_rad = sigma * (epsilon_gas * T_gas**4 - epsilon_wall * T_wall**4)
    
    # 创建图表
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 炉膛温度分布
    ax1 = axes[0, 0]
    ax1.plot(T_gas, z, 'r-', linewidth=2)
    ax1.fill_betweenx(z, T_gas, T_wall, alpha=0.3, color='red')
    ax1.axvline(T_wall, color='blue', linestyle='--', linewidth=2, label='壁面温度')
    ax1.set_xlabel('温度 T [K]', fontsize=12)
    ax1.set_ylabel('高度 z [m]', fontsize=12)
    ax1.set_title('炉膛温度分布', fontsize=14)
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    ax1.invert_yaxis()
    
    # 图2: 气体发射率分布
    ax2 = axes[0, 1]
    ax2.plot(epsilon_gas, z, 'g-', linewidth=2)
    ax2.fill_betweenx(z, epsilon_gas, alpha=0.3, color='green')
    ax2.set_xlabel('发射率 ε', fontsize=12)
    ax2.set_ylabel('高度 z [m]', fontsize=12)
    ax2.set_title('气体发射率分布', fontsize=14)
    ax2.grid(True, alpha=0.3)
    ax2.invert_yaxis()
    
    # 图3: 辐射热流分布
    ax3 = axes[1, 0]
    colors = ['red' if q > 0 else 'blue' for q in q_rad]
    ax3.barh(z[::5], q_rad[::5]/1000, height=0.5, color=colors[::5], alpha=0.7)
    ax3.axvline(0, color='black', linewidth=1)
    ax3.set_xlabel('辐射热流 q [kW/m²]', fontsize=12)
    ax3.set_ylabel('高度 z [m]', fontsize=12)
    ax3.set_title('壁面辐射热流分布', fontsize=14)
    ax3.grid(True, alpha=0.3)
    ax3.invert_yaxis()
    
    # 图4: 不同工况对比
    ax4 = axes[1, 1]
    
    # 不同过量空气系数
    excess_air = [1.0, 1.2, 1.4]
    for ea in excess_air:
        # 简化:过量空气增加会降低温度
        T_gas_case = T_gas - (ea - 1.0) * 200
        epsilon_case = []
        for T in T_gas_case:
            eps = wsggm_emissivity(T, P, 0.9*D, kappa_i, a_coeffs)
            epsilon_case.append(eps)
        q_case = sigma * (np.array(epsilon_case) * T_gas_case**4 - epsilon_wall * T_wall**4)
        ax4.plot(q_case/1000, z, linewidth=2, label=f'过量空气系数={ea}')
    
    ax4.set_xlabel('辐射热流 q [kW/m²]', fontsize=12)
    ax4.set_ylabel('高度 z [m]', fontsize=12)
    ax4.set_title('不同过量空气系数下的辐射热流', fontsize=14)
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    ax4.invert_yaxis()
    
    plt.tight_layout()
    plt.savefig('case4_boiler_furnace.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例4完成:已保存 case4_boiler_furnace.png")

# ==================== 案例5:富氧燃烧WSGGM参数 ====================

def case5_oxyfuel_wsggm():
    """案例5:富氧燃烧专用WSGGM参数"""
    print("=" * 60)
    print("案例5:富氧燃烧专用WSGGM参数")
    print("=" * 60)
    
    # 标准WSGGM参数 (Smith 1982)
    kappa_std, a_coeffs_std = get_smith_wsggm_params()
    
    # 富氧燃烧WSGGM参数 (Yin 2014简化版)
    kappa_oxy = np.array([0.0, 0.2, 2.0, 20.0])
    a_coeffs_oxy = np.array([
        [0.150, -0.100, 0.030, -0.003],
        [0.400, -0.200, 0.050, -0.004],
        [0.350, -0.150, 0.040, -0.003],
        [0.100, 0.450, -0.120, 0.010]
    ])
    
    # 富氧燃烧工况
    T_range = np.linspace(1000, 2000, 50)
    P = 1.0
    L = 2.0
    
    # 高CO2浓度环境
    X_CO2_high = 0.85
    X_H2O_high = 0.15
    
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 标准与富氧WSGGM对比
    ax1 = axes[0, 0]
    eps_std = [wsggm_emissivity(T, P, L, kappa_std, a_coeffs_std) for T in T_range]
    eps_oxy = [wsggm_emissivity(T, P, L, kappa_oxy, a_coeffs_oxy) for T in T_range]
    
    ax1.plot(T_range, eps_std, 'b-', linewidth=2, label='标准WSGGM (Smith 1982)')
    ax1.plot(T_range, eps_oxy, 'r--', linewidth=2, label='富氧WSGGM (Yin 2014)')
    ax1.set_xlabel('温度 T [K]', fontsize=12)
    ax1.set_ylabel('发射率 ε', fontsize=12)
    ax1.set_title(f'标准与富氧WSGGM对比 (L={L}m)', fontsize=14)
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 图2: 不同CO2浓度下的发射率
    ax2 = axes[0, 1]
    L_test = 2.0
    
    # 模拟不同CO2浓度的影响 (通过调整WSGGM参数)
    for X_CO2, label, color in [(0.12, '空气燃烧 (12% CO2)', 'blue'),
                                 (0.50, '中浓度 (50% CO2)', 'green'),
                                 (0.85, '富氧燃烧 (85% CO2)', 'red')]:
        # 简化:通过调整权重系数模拟浓度影响
        scale = X_CO2 / 0.12
        a_scaled = a_coeffs_oxy.copy()
        a_scaled[0, 0] = max(0.05, 0.15 - 0.1 * scale)
        a_scaled[1:, 0] = a_coeffs_oxy[1:, 0] * scale
        a_scaled = a_scaled / np.sum(a_scaled[:, 0]) * np.sum(a_coeffs_oxy[:, 0])
        
        eps = [wsggm_emissivity(T, P, L_test, kappa_oxy, a_scaled) for T in T_range]
        ax2.plot(T_range, eps, linewidth=2, label=label, color=color)
    
    ax2.set_xlabel('温度 T [K]', fontsize=12)
    ax2.set_ylabel('发射率 ε', fontsize=12)
    ax2.set_title(f'不同CO₂浓度下的发射率 (L={L_test}m)', fontsize=14)
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 图3: 权重系数对比
    ax3 = axes[1, 0]
    T_r = T_range / 1000.0
    
    for i in range(len(kappa_std)):
        a_std = a_coeffs_std[i, 0] + a_coeffs_std[i, 1] * T_r + \
                a_coeffs_std[i, 2] * T_r**2 + a_coeffs_std[i, 3] * T_r**3
        a_oxy = a_coeffs_oxy[i, 0] + a_coeffs_oxy[i, 1] * T_r + \
                a_coeffs_oxy[i, 2] * T_r**2 + a_coeffs_oxy[i, 3] * T_r**3
        
        ax3.plot(T_range, np.maximum(0, a_std), '--', linewidth=2, 
                label=f'标准 κ={kappa_std[i]:.1f}', alpha=0.7)
        ax3.plot(T_range, np.maximum(0, a_oxy), '-', linewidth=2, 
                label=f'富氧 κ={kappa_oxy[i]:.1f}')
    
    ax3.set_xlabel('温度 T [K]', fontsize=12)
    ax3.set_ylabel('权重系数 a', fontsize=12)
    ax3.set_title('权重系数对比', fontsize=14)
    ax3.legend(fontsize=8, ncol=2)
    ax3.grid(True, alpha=0.3)
    
    # 图4: 辐射热流对比 (简化炉膛模型)
    ax4 = axes[1, 1]
    T_gas = 1600
    T_wall = 800
    L_range = np.linspace(0.5, 5.0, 50)
    
    q_std = []
    q_oxy = []
    sigma = 5.67e-8
    
    for L in L_range:
        eps_std_val = wsggm_emissivity(T_gas, P, L, kappa_std, a_coeffs_std)
        eps_oxy_val = wsggm_emissivity(T_gas, P, L, kappa_oxy, a_coeffs_oxy)
        
        q_std.append(sigma * eps_std_val * (T_gas**4 - T_wall**4))
        q_oxy.append(sigma * eps_oxy_val * (T_gas**4 - T_wall**4))
    
    ax4.plot(L_range, np.array(q_std)/1000, 'b-', linewidth=2, label='标准WSGGM')
    ax4.plot(L_range, np.array(q_oxy)/1000, 'r--', linewidth=2, label='富氧WSGGM')
    ax4.set_xlabel('行程长度 L [m]', fontsize=12)
    ax4.set_ylabel('辐射热流 q [kW/m²]', fontsize=12)
    ax4.set_title(f'辐射热流对比 (T_gas={T_gas}K)', fontsize=14)
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('case5_oxyfuel_wsggm.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例5完成:已保存 case5_oxyfuel_wsggm.png")

# ==================== 案例6:WSGGM在CFD中的应用 ====================

def case6_cfd_application():
    """案例6:WSGGM在CFD耦合计算中的应用"""
    print("=" * 60)
    print("案例6:WSGGM在CFD中的应用")
    print("=" * 60)
    
    # 模拟CFD网格
    nx, ny = 40, 30
    x = np.linspace(0, 4.0, nx)
    y = np.linspace(0, 3.0, ny)
    X, Y = np.meshgrid(x, y)
    
    # 温度场 (模拟燃烧室)
    T_field = 1200 + 600 * np.exp(-((X-2)**2 + (Y-1.5)**2) / 1.5)
    
    # 压力
    P = 1.0
    
    # WSGGM参数
    kappa_i, a_coeffs = get_smith_wsggm_params()
    
    # 计算各网格点的发射率
    epsilon_field = np.zeros_like(T_field)
    kappa_field = np.zeros_like(T_field)
    L_mean = 0.5  # 特征长度
    
    for i in range(ny):
        for j in range(nx):
            T = T_field[i, j]
            epsilon_field[i, j] = wsggm_emissivity(T, P, L_mean, kappa_i, a_coeffs)
            if epsilon_field[i, j] < 0.99:
                kappa_field[i, j] = -np.log(1 - epsilon_field[i, j]) / L_mean
            else:
                kappa_field[i, j] = 10.0
    
    # 计算辐射源项 (简化)
    sigma = 5.67e-8
    T_wall = 800
    q_rad_field = sigma * kappa_field * (T_field**4 - T_wall**4)
    
    # 创建图表
    fig, axes = plt.subplots(2, 2, figsize=(14, 12))
    
    # 图1: 温度场
    ax1 = axes[0, 0]
    im1 = ax1.contourf(X, Y, T_field, levels=20, cmap='hot')
    plt.colorbar(im1, ax=ax1, label='温度 [K]')
    ax1.set_xlabel('x [m]', fontsize=12)
    ax1.set_ylabel('y [m]', fontsize=12)
    ax1.set_title('温度场分布', fontsize=14)
    ax1.set_aspect('equal')
    
    # 图2: 发射率场
    ax2 = axes[0, 1]
    im2 = ax2.contourf(X, Y, epsilon_field, levels=20, cmap='viridis')
    plt.colorbar(im2, ax=ax2, label='发射率')
    ax2.set_xlabel('x [m]', fontsize=12)
    ax2.set_ylabel('y [m]', fontsize=12)
    ax2.set_title('气体发射率分布', fontsize=14)
    ax2.set_aspect('equal')
    
    # 图3: 辐射源项
    ax3 = axes[1, 0]
    im3 = ax3.contourf(X, Y, q_rad_field/1e6, levels=20, cmap='RdBu_r')
    plt.colorbar(im3, ax=ax3, label='辐射源项 [MW/m³]')
    ax3.set_xlabel('x [m]', fontsize=12)
    ax3.set_ylabel('y [m]', fontsize=12)
    ax3.set_title('辐射源项分布', fontsize=14)
    ax3.set_aspect('equal')
    
    # 图4: 沿中心线的温度与辐射热流
    ax4 = axes[1, 1]
    center_idx = ny // 2
    ax4_twin = ax4.twinx()
    
    line1 = ax4.plot(x, T_field[center_idx, :], 'r-', linewidth=2, label='温度')
    line2 = ax4_twin.plot(x, q_rad_field[center_idx, :]/1000, 'b--', linewidth=2, label='辐射热流')
    
    ax4.set_xlabel('x [m]', fontsize=12)
    ax4.set_ylabel('温度 T [K]', fontsize=12, color='red')
    ax4_twin.set_ylabel('辐射热流 q [kW/m³]', fontsize=12, color='blue')
    ax4.set_title('中心线温度与辐射热流', fontsize=14)
    ax4.grid(True, alpha=0.3)
    
    # 合并图例
    lines = line1 + line2
    labels = [l.get_label() for l in lines]
    ax4.legend(lines, labels, loc='upper right')
    
    plt.tight_layout()
    plt.savefig('case6_cfd_application.png', dpi=150, bbox_inches='tight')
    plt.close()
    print("案例6完成:已保存 case6_cfd_application.png")

# ==================== GIF动画生成 ====================

def create_gif_temperature_evolution():
    """创建GIF动画1:温度演化对WSGGM预测的影响"""
    print("正在生成GIF动画1:温度演化...")
    
    kappa_i, a_coeffs = get_smith_wsggm_params()
    T_range = np.linspace(800, 2000, 30)
    L_range = np.logspace(-2, 1, 100)
    P = 1.0
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
    
    def update(frame):
        ax1.clear()
        ax2.clear()
        
        T = T_range[frame]
        T_r = T / 1000.0
        
        # 计算发射率曲线
        eps_wsggm = [wsggm_emissivity(T, P, L, kappa_i, a_coeffs) for L in L_range]
        
        ax1.semilogx(L_range, eps_wsggm, 'b-', linewidth=2)
        ax1.set_xlabel('行程长度 L [m]', fontsize=12)
        ax1.set_ylabel('发射率 ε', fontsize=12)
        ax1.set_title(f'WSGGM发射率 (T={T:.0f}K)', fontsize=14)
        ax1.grid(True, alpha=0.3)
        ax1.set_ylim(0, 1)
        ax1.set_xlim(0.01, 10)
        
        # 权重系数饼图
        a_i = np.array([a_coeffs[j, 0] + a_coeffs[j, 1] * T_r + 
                        a_coeffs[j, 2] * T_r**2 + a_coeffs[j, 3] * T_r**3 
                        for j in range(len(kappa_i))])
        a_i = np.maximum(0, a_i)
        
        labels = [f'κ={k:.1f}' for k in kappa_i]
        colors = plt.cm.Set3(np.linspace(0, 1, len(kappa_i)))
        ax2.pie(a_i, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
        ax2.set_title(f'灰气体权重分布 (T={T:.0f}K)', fontsize=14)
        
        return ax1, ax2
    
    ani = FuncAnimation(fig, update, frames=len(T_range), interval=200, blit=False)
    writer = PillowWriter(fps=5)
    ani.save('gif1_temperature_evolution.gif', writer=writer)
    plt.close()
    print("GIF动画1完成:已保存 gif1_temperature_evolution.gif")

def create_gif_gray_gas_comparison():
    """创建GIF动画2:不同灰气体数量的对比"""
    print("正在生成GIF动画2:灰气体数量对比...")
    
    T = 1500
    P = 1.0
    L_range = np.logspace(-2, 1, 100)
    
    fig, ax = plt.subplots(figsize=(10, 6))
    
    # 计算LBL基准
    eps_lbl = []
    for L in L_range:
        eps, _, _, _ = calculate_lbl_emissivity(T, P, L)
        eps_lbl.append(eps)
    
    n_gas_values = [1, 2, 3, 4]
    kappa_sets = [
        np.array([1.0]),
        np.array([0.0, 2.0]),
        np.array([0.0, 0.5, 5.0]),
        np.array([0.0, 0.1, 1.0, 10.0])
    ]
    a_sets = [
        np.array([[1.0, 0, 0, 0]]),
        np.array([[0.3, 0, 0, 0], [0.7, 0, 0, 0]]),
        np.array([[0.2, 0, 0, 0], [0.3, 0, 0, 0], [0.5, 0, 0, 0]]),
        np.array([[0.1, 0, 0, 0], [0.3, 0, 0, 0], [0.4, 0, 0, 0], [0.2, 0, 0, 0]])
    ]
    
    def update(frame):
        ax.clear()
        
        # 绘制LBL基准
        ax.semilogx(L_range, eps_lbl, 'k-', linewidth=3, label='LBL (基准)', alpha=0.5)
        
        # 绘制不同灰气体数量的结果
        for i in range(min(frame + 1, len(n_gas_values))):
            n_gas = n_gas_values[i]
            kappa_i = kappa_sets[i]
            a_coeffs = a_sets[i]
            
            eps_wsggm = [wsggm_emissivity(T, P, L, kappa_i, a_coeffs) for L in L_range]
            ax.semilogx(L_range, eps_wsggm, '--', linewidth=2, 
                       label=f'{n_gas}灰气体')
        
        ax.set_xlabel('行程长度 L [m]', fontsize=12)
        ax.set_ylabel('发射率 ε', fontsize=12)
        ax.set_title(f'不同灰气体数量的对比 (T={T}K)', fontsize=14)
        ax.legend()
        ax.grid(True, alpha=0.3)
        ax.set_ylim(0, 1)
        ax.set_xlim(0.01, 10)
        
        return ax,
    
    ani = FuncAnimation(fig, update, frames=len(n_gas_values), interval=800, blit=False)
    writer = PillowWriter(fps=2)
    ani.save('gif2_gray_gas_comparison.gif', writer=writer)
    plt.close()
    print("GIF动画2完成:已保存 gif2_gray_gas_comparison.gif")

def create_gif_furnace_radiation():
    """创建GIF动画3:炉膛辐射换热动态模拟"""
    print("正在生成GIF动画3:炉膛辐射换热...")
    
    kappa_i, a_coeffs = get_smith_wsggm_params()
    sigma = 5.67e-8
    
    # 炉膛参数
    H = 15.0
    z = np.linspace(0, H, 100)
    
    # 时间演化 (模拟负荷变化)
    time_frames = 20
    T_center_values = np.linspace(1600, 2000, time_frames)
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
    
    def update(frame):
        ax1.clear()
        ax2.clear()
        
        T_center = T_center_values[frame]
        T_wall = 800
        
        # 温度分布
        T_gas = T_wall + (T_center - T_wall) * np.sin(np.pi * z / H)
        
        # 计算发射率和热流
        epsilon_gas = []
        q_rad = []
        L_mean = 5.0
        
        for T in T_gas:
            eps = wsggm_emissivity(T, 1.0, L_mean, kappa_i, a_coeffs)
            epsilon_gas.append(eps)
            q = sigma * eps * (T**4 - T_wall**4)
            q_rad.append(q)
        
        # 左图:温度分布
        ax1.plot(T_gas, z, 'r-', linewidth=2, label='气体温度')
        ax1.axvline(T_wall, color='blue', linestyle='--', linewidth=2, label='壁面温度')
        ax1.fill_betweenx(z, T_gas, T_wall, alpha=0.3, color='red')
        ax1.set_xlabel('温度 T [K]', fontsize=12)
        ax1.set_ylabel('高度 z [m]', fontsize=12)
        ax1.set_title(f'炉膛温度分布 (T_center={T_center:.0f}K)', fontsize=14)
        ax1.legend()
        ax1.grid(True, alpha=0.3)
        ax1.invert_yaxis()
        ax1.set_xlim(700, 2100)
        
        # 右图:辐射热流
        colors = ['red' if q > 0 else 'blue' for q in q_rad]
        ax2.barh(z[::5], np.array(q_rad[::5])/1000, height=0.8, color=colors[::5], alpha=0.7)
        ax2.axvline(0, color='black', linewidth=1)
        ax2.set_xlabel('辐射热流 q [kW/m²]', fontsize=12)
        ax2.set_ylabel('高度 z [m]', fontsize=12)
        ax2.set_title(f'壁面辐射热流', fontsize=14)
        ax2.grid(True, alpha=0.3)
        ax2.invert_yaxis()
        
        return ax1, ax2
    
    ani = FuncAnimation(fig, update, frames=time_frames, interval=300, blit=False)
    writer = PillowWriter(fps=3)
    ani.save('gif3_furnace_radiation.gif', writer=writer)
    plt.close()
    print("GIF动画3完成:已保存 gif3_furnace_radiation.gif")

# ==================== 主程序 ====================

if __name__ == '__main__':
    print("=" * 70)
    print("主题025:加权求和灰气体模型(WSGGM)仿真程序")
    print("=" * 70)
    
    # 运行所有案例
    case1_wsggm_fitting()
    case2_1d_radiation_wsggm()
    case3_wsggm_vs_lbl()
    case4_boiler_furnace()
    case5_oxyfuel_wsggm()
    case6_cfd_application()
    
    print("\n" + "=" * 70)
    print("所有静态图片生成完成!")
    print("=" * 70)
    
    # 生成GIF动画
    print("\n开始生成GIF动画...")
    create_gif_temperature_evolution()
    create_gif_gray_gas_comparison()
    create_gif_furnace_radiation()
    
    print("\n" + "=" * 70)
    print("所有仿真案例和GIF动画生成完成!")
    print("=" * 70)
    
    print("\n生成的文件列表:")
    print("  - case1_wsggm_fitting.png")
    print("  - case2_1d_radiation_wsggm.png")
    print("  - case3_wsggm_vs_lbl.png")
    print("  - case4_boiler_furnace.png")
    print("  - case5_oxyfuel_wsggm.png")
    print("  - case6_cfd_application.png")
    print("  - gif1_temperature_evolution.gif")
    print("  - gif2_gray_gas_comparison.gif")
    print("  - gif3_furnace_radiation.gif")
    print("=" * 70)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐