This commit is contained in:
2025-11-22 19:38:01 +08:00
parent 634343a2ff
commit 9b4554ecb9
21 changed files with 1398 additions and 385 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

View File

@@ -0,0 +1,7 @@
thickness_um,avg_emissivity_8_13um
1,0.3238
5,0.7365
10,0.8286
25,0.8987
50,0.9282
100,0.9420
1 thickness_um avg_emissivity_8_13um
2 1 0.3238
3 5 0.7365
4 10 0.8286
5 25 0.8987
6 50 0.9282
7 100 0.9420

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@@ -0,0 +1,7 @@
thickness_um,eps_8_13,alpha_solar,net_power_amb_Wm2,eq_temp_C,delta_T_C
1,0.3238,0.051,-10.03,25.19,-1.66
5,0.7365,0.055,32.08,36.68,9.83
10,0.8286,0.060,37.78,41.76,14.91
25,0.8987,0.075,32.05,42.47,15.62
50,0.9282,0.100,12.81,32.83,5.98
100,0.9420,0.150,-30.65,14.91,-11.94
1 thickness_um eps_8_13 alpha_solar net_power_amb_Wm2 eq_temp_C delta_T_C
2 1 0.3238 0.051 -10.03 25.19 -1.66
3 5 0.7365 0.055 32.08 36.68 9.83
4 10 0.8286 0.060 37.78 41.76 14.91
5 25 0.8987 0.075 32.05 42.47 15.62
6 50 0.9282 0.100 12.81 32.83 5.98
7 100 0.9420 0.150 -30.65 14.91 -11.94

View File

@@ -0,0 +1,16 @@
rank,score,epsilon,alpha,layers
1,0.8599,0.9182,0.1944,PDMS@12.857um;HfO2@0.411um;SiO2@1.089um
2,0.8585,0.9185,0.1999,PDMS@14.393um;SiO2@0.470um;HfO2@0.302um
3,0.8506,0.9325,0.2729,PDMS@20.398um;Al2O3@0.510um;SiO2@1.906um
4,0.8499,0.9223,0.2411,PDMS@17.833um;HfO2@0.316um;SiO2@1.127um
5,0.8492,0.9183,0.2304,PDMS@13.284um;HfO2@0.081um;Al2O3@0.371um;Si3N4@0.723um
6,0.8482,0.9355,0.2911,PDMS@21.867um;SiO2@0.309um;Si3N4@0.707um;TiO2@0.057um
7,0.8475,0.9223,0.2495,PDMS@17.611um;SiO2@1.097um;HfO2@0.613um
8,0.8470,0.9269,0.2663,PDMS@19.765um;SiO2@1.968um;Al2O3@0.609um
9,0.8468,0.9221,0.2510,PDMS@15.789um;Si3N4@1.199um;SiO2@1.265um
10,0.8464,0.9264,0.2667,PDMS@18.329um;Si3N4@0.322um;Al2O3@0.532um
11,0.8463,0.9145,0.2273,PDMS@15.894um;Al2O3@1.159um;SiO2@0.497um
12,0.8461,0.9240,0.2595,PDMS@18.179um;Al2O3@0.324um;HfO2@0.734um
13,0.8459,0.9053,0.1980,PDMS@12.520um;HfO2@0.132um;Si3N4@0.431um;SiO2@0.435um
14,0.8446,0.9091,0.2150,PDMS@12.045um;Al2O3@0.692um;HfO2@0.660um;SiO2@0.207um
15,0.8445,0.9401,0.3186,PDMS@26.732um;SiO2@0.202um;HfO2@0.346um
1 rank score epsilon alpha layers
2 1 0.8599 0.9182 0.1944 PDMS@12.857um;HfO2@0.411um;SiO2@1.089um
3 2 0.8585 0.9185 0.1999 PDMS@14.393um;SiO2@0.470um;HfO2@0.302um
4 3 0.8506 0.9325 0.2729 PDMS@20.398um;Al2O3@0.510um;SiO2@1.906um
5 4 0.8499 0.9223 0.2411 PDMS@17.833um;HfO2@0.316um;SiO2@1.127um
6 5 0.8492 0.9183 0.2304 PDMS@13.284um;HfO2@0.081um;Al2O3@0.371um;Si3N4@0.723um
7 6 0.8482 0.9355 0.2911 PDMS@21.867um;SiO2@0.309um;Si3N4@0.707um;TiO2@0.057um
8 7 0.8475 0.9223 0.2495 PDMS@17.611um;SiO2@1.097um;HfO2@0.613um
9 8 0.8470 0.9269 0.2663 PDMS@19.765um;SiO2@1.968um;Al2O3@0.609um
10 9 0.8468 0.9221 0.2510 PDMS@15.789um;Si3N4@1.199um;SiO2@1.265um
11 10 0.8464 0.9264 0.2667 PDMS@18.329um;Si3N4@0.322um;Al2O3@0.532um
12 11 0.8463 0.9145 0.2273 PDMS@15.894um;Al2O3@1.159um;SiO2@0.497um
13 12 0.8461 0.9240 0.2595 PDMS@18.179um;Al2O3@0.324um;HfO2@0.734um
14 13 0.8459 0.9053 0.1980 PDMS@12.520um;HfO2@0.132um;Si3N4@0.431um;SiO2@0.435um
15 14 0.8446 0.9091 0.2150 PDMS@12.045um;Al2O3@0.692um;HfO2@0.660um;SiO2@0.207um
16 15 0.8445 0.9401 0.3186 PDMS@26.732um;SiO2@0.202um;HfO2@0.346um

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

667
org/other/q2_1.py Normal file
View File

@@ -0,0 +1,667 @@
import math
import os
from dataclasses import dataclass
from typing import Dict, List, Tuple, Optional
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import CubicSpline
from scipy.integrate import simpson
# 全局物理常数(修正:优化热物理参数,确保量级合理)
SIGMA = 5.670374419e-8 # Stefan-Boltzmann constant (W/m²/K⁴)
T_AMB = 300.0 # Ambient temperature (K) ≈27℃
T_SKY = 270.0 # 降低天空温度(更贴近真实晴空,增强辐射散热)
SOLAR_IRR = 850.0 # 太阳辐照度合理范围800-900 W/m²
H_CONV = 10.0 # 自然对流换热系数优化为10 W/m²/K更贴近实际
H_COND_MAX = 1000.0 # 最大传导换热系数(限制量级,避免异常大值)
k_PDMS = 0.12 # PDMS导热系数取保守值0.12 W/m·K避免偏大
MAX_TEMPERATURE_DIFF = 15.0 # 最大允许温差K避免平衡温度过低导致热损失量级异常
# 关键波段定义
SOLAR_BAND = (0.3, 2.5) # Solar spectrum range (μm)
ATMOSPHERIC_WINDOW = (8.0, 13.0) # Atmospheric transparency window (μm)
THERMAL_BAND = (2.5, 25.0) # Thermal radiation full band (μm)
# 绘图配置(纯英文)
plt.rcParams["font.sans-serif"] = ["Arial", "Helvetica", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False # Fix minus sign display
plt.rcParams["figure.dpi"] = 100
plt.rcParams["savefig.dpi"] = 300
@dataclass
class OpticalProperty:
"""Optical property data class"""
wl: np.ndarray # Wavelength (μm)
n: np.ndarray # Refractive index
k: np.ndarray # Extinction coefficient
cs_n: CubicSpline # Cubic spline for refractive index
cs_k: CubicSpline # Cubic spline for extinction coefficient
@dataclass
class SpectralMetric:
"""Spectral matching metrics"""
thickness_um: float
avg_eps_window: float # Average emissivity in atmospheric window
avg_alpha_solar: float # Average absorptivity in solar band
spectral_match_index: float # Spectral matching index (ε_window/α_solar)
eps_window_std: float # Std of emissivity in atmospheric window
alpha_solar_std: float # Std of absorptivity in solar band
@dataclass
class CoolingPerformance:
"""Comprehensive cooling performance metrics"""
thickness_um: float
spectral_metric: SpectralMetric
net_radiative_power: float # Net radiative power (W/m²) 核心新增指标,单独绘图
solar_gain: float # Solar absorption heat flux (W/m²)
convective_loss: float # Convective heat loss (W/m²)
conductive_loss: float # Conductive heat loss (W/m²)
net_cooling_power: float # Total net cooling power (W/m²)
equilibrium_temp_K: float # Equilibrium temperature (K)
@property
def equilibrium_temp_C(self) -> float:
return self.equilibrium_temp_K - 273.15
@property
def temp_drop_C(self) -> float:
# 正确逻辑:降温值 = 环境温度 - 平衡温度(确保为正,有效冷却)
return T_AMB - self.equilibrium_temp_K
# ------------------------------
# 1. Data Preprocessing and Optical Property Loading
# ------------------------------
def make_strictly_increasing(wl: np.ndarray, n: np.ndarray, k: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Ensure wavelength data is strictly increasing and free of duplicates"""
# Remove duplicate wavelengths
unique_wl, indices = np.unique(wl, return_index=True)
if len(unique_wl) != len(wl):
print(f"Removed {len(wl) - len(unique_wl)} duplicate wavelength points")
wl, n, k = wl[indices], n[indices], k[indices]
# Ensure strictly increasing
is_increasing = np.diff(wl) > 1e-6 # Allow minor tolerance
if not all(is_increasing):
valid_indices = np.concatenate([[True], is_increasing])
wl, n, k = wl[valid_indices], n[valid_indices], k[valid_indices]
print(f"Removed {len(is_increasing) - sum(is_increasing)} non-increasing wavelength points")
return wl, n, k
def read_split_data(file_path: str) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Read split-format optical data (n and k stored separately)"""
with open(file_path, 'r', encoding='utf-8') as f:
lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
# Find split point between n and k data
split_idx = None
for i, line in enumerate(lines):
if line == 'wl k':
split_idx = i
break
if split_idx is None:
raise ValueError("Data file format error: 'wl k' delimiter not found")
# Read n data
n_lines = lines[1:split_idx] # Skip 'wl n' header
wl_n, n_list = [], []
for line in n_lines:
parts = line.split()
if len(parts) >= 2:
wl_n.append(float(parts[0]))
n_list.append(float(parts[1]))
# Read k data
k_lines = lines[split_idx + 1:] # Skip 'wl k' header
wl_k, k_list = [], []
for line in k_lines:
parts = line.split()
if len(parts) >= 2:
wl_k.append(float(parts[0]))
k_list.append(float(parts[1]))
# Convert to numpy arrays
wl_n, n_list = np.array(wl_n), np.array(n_list)
wl_k, k_list = np.array(wl_k), np.array(k_list)
# Unify wavelength range (interpolate to common wavelengths)
if not np.allclose(wl_n, wl_k):
print("Warning: Wavelength ranges of n and k do not match, performing interpolation")
common_wl = np.linspace(
max(wl_n.min(), wl_k.min()),
min(wl_n.max(), wl_k.max()),
1000
)
n_list = np.interp(common_wl, wl_n, n_list)
k_list = np.interp(common_wl, wl_k, k_list)
wl_n = common_wl
# Ensure strictly increasing
wl, n, k = make_strictly_increasing(wl_n, n_list, k_list)
return wl, n, k
def load_optical_properties(file_path: str) -> OpticalProperty:
"""Load optical properties and create interpolation functions"""
wl, n, k = read_split_data(file_path)
cs_n = CubicSpline(wl, n, bc_type='natural')
cs_k = CubicSpline(wl, k, bc_type='natural')
print(f"Data loaded successfully:")
print(f" Wavelength range: {wl.min():.2f} - {wl.max():.2f} μm")
print(f" Number of data points: {len(wl)}")
print(f" Refractive index n: {n.min():.3f} - {n.max():.3f}")
print(f" Extinction coefficient k: {k.min():.6f} - {k.max():.6f}")
return OpticalProperty(wl=wl, n=n, k=k, cs_n=cs_n, cs_k=cs_k)
# ------------------------------
# 2. Core Optical Model (Emissivity/Absorptivity Calculation)
# ------------------------------
def fresnel_reflectance(n1: float, k1: float, n2: float, k2: float) -> float:
"""Fresnel reflectance (normal incidence, considering complex refractive index)"""
m1 = n1 + 1j * k1
m2 = n2 + 1j * k2
return np.abs((m1 - m2) / (m1 + m2)) ** 2
def thin_film_spectral_property(
optical: OpticalProperty,
thickness_um: float,
wl_range: Tuple[float, float]
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Calculate spectral emissivity and absorptivity of thin film in specified wavelength range"""
wl_start, wl_end = wl_range
# Generate dense wavelength points
wl = np.linspace(wl_start, wl_end, 500)
# Interpolate optical parameters
n_film = optical.cs_n(wl)
k_film = optical.cs_k(wl)
n_air, k_air = 1.0, 0.0
# Calculate Fresnel reflectance
R12 = fresnel_reflectance(n_air, k_air, n_film, k_film) # Air → Film
R23 = fresnel_reflectance(n_film, k_film, n_air, k_air) # Film → Air
# Calculate phase difference and absorption attenuation
delta = 2 * np.pi * n_film * thickness_um / wl # Interference phase difference
alpha = 4 * np.pi * k_film * thickness_um / wl # Absorption attenuation coefficient
# Multibeam interference reflectance
numerator = R12 + R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
denominator = 1 + R12 * R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
R_total = numerator / denominator
# Multibeam interference transmittance
T_total = (1 - R12) * (1 - R23) * np.exp(-alpha) / denominator
# Emissivity (Kirchhoff's law) and absorptivity (α=ε under local thermal equilibrium)
epsilon = 1 - R_total - T_total
alpha = epsilon # Absorptivity = Emissivity under local thermal equilibrium
# Numerical clipping to avoid out-of-range values due to calculation errors
epsilon = np.clip(epsilon, 0.0, 1.0)
alpha = np.clip(alpha, 0.0, 1.0)
return wl, epsilon, alpha
# ------------------------------
# 3. Spectral Matching Quantitative Analysis
# ------------------------------
def calculate_spectral_metric(
optical: OpticalProperty,
thickness_um: float
) -> SpectralMetric:
"""Calculate spectral matching metrics"""
# 1. Emissivity in atmospheric window (8-13μm)
wl_window, eps_window, _ = thin_film_spectral_property(
optical, thickness_um, ATMOSPHERIC_WINDOW
)
avg_eps = np.mean(eps_window)
std_eps = np.std(eps_window)
# 2. Absorptivity in solar band (0.3-2.5μm)
wl_solar, _, alpha_solar = thin_film_spectral_property(
optical, thickness_um, SOLAR_BAND
)
avg_alpha = np.mean(alpha_solar)
std_alpha = np.std(alpha_solar)
# 3. Spectral matching index (larger is better, avoid division by zero)
match_index = avg_eps / (avg_alpha + 1e-6)
return SpectralMetric(
thickness_um=thickness_um,
avg_eps_window=avg_eps,
avg_alpha_solar=avg_alpha,
spectral_match_index=match_index,
eps_window_std=std_eps,
alpha_solar_std=std_alpha
)
def plot_spectral_metrics(metrics_list: List[SpectralMetric], save_path: str):
"""Plot spectral matching metrics (full English)"""
thicknesses = [m.thickness_um for m in metrics_list]
avg_eps = [m.avg_eps_window for m in metrics_list]
avg_alpha = [m.avg_alpha_solar for m in metrics_list]
match_indices = [m.spectral_match_index for m in metrics_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# Left axis: Emissivity and Absorptivity
color1 = '#2E86AB'
color2 = '#A23B72'
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Emissivity / Absorptivity', fontsize=12)
line1 = ax1.plot(thicknesses, avg_eps, marker='o', linewidth=2,
color=color1, label='Avg Emissivity (8-13μm)', markersize=6)
line2 = ax1.plot(thicknesses, avg_alpha, marker='s', linewidth=2,
color=color2, label='Avg Absorptivity (0.3-2.5μm)', markersize=6)
ax1.tick_params(axis='y')
ax1.set_ylim(0, 1.0)
ax1.grid(True, alpha=0.3)
# Right axis: Spectral Matching Index
ax2 = ax1.twinx()
color3 = '#F18F01'
ax2.set_ylabel('Spectral Matching Index', fontsize=12, color=color3)
line3 = ax2.plot(thicknesses, match_indices, marker='^', linewidth=2,
color=color3, label='Spectral Matching Index', markersize=6)
ax2.tick_params(axis='y', labelcolor=color3)
ax2.set_ylim(0, max(match_indices) * 1.1)
# Combine legends
lines = line1 + line2 + line3
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right', fontsize=10)
plt.title('Spectral Matching Metrics of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Spectral matching metrics plot saved to: {save_path}")
# ------------------------------
# 4. Solar Absorptivity Modeling and Visualization
# ------------------------------
def plot_solar_absorption_spectra(
optical: OpticalProperty,
thicknesses: List[float],
save_path: str
):
"""Plot solar band absorptivity spectra for different thicknesses (full English)"""
fig, ax = plt.subplots(figsize=(10, 6))
colors = plt.cm.Set3(np.linspace(0, 1, len(thicknesses)))
for idx, thickness in enumerate(thicknesses):
wl_solar, _, alpha_solar = thin_film_spectral_property(
optical, thickness, SOLAR_BAND
)
ax.plot(wl_solar, alpha_solar, linewidth=2, color=colors[idx],
label=f'{thickness} μm')
ax.set_xlabel('Wavelength (μm)', fontsize=12)
ax.set_ylabel('Solar Absorptivity α(λ)', fontsize=12)
ax.set_title('Solar Band Absorptivity Spectra of PDMS Films with Different Thicknesses', fontsize=14,
fontweight='bold')
ax.grid(True, alpha=0.3)
ax.legend(title='Film Thickness', fontsize=10, title_fontsize=11)
ax.set_ylim(0, 0.3) # Solar absorptivity is usually low, zoom in
ax.set_xlim(SOLAR_BAND[0], SOLAR_BAND[1])
# Highlight visible light region
ax.axvspan(0.4, 0.7, alpha=0.1, color='yellow', label='Visible Light Region')
# Redraw legend to include visible light label
ax.legend(title='Film Thickness', fontsize=10, title_fontsize=11, loc='upper right')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Solar absorption spectra plot saved to: {save_path}")
# ------------------------------
# 5. 新增图表Net Radiative Power vs Thickness净辐射功率图
# ------------------------------
def plot_net_radiative_power(performance_list: List[CoolingPerformance], save_path: str):
"""Plot net radiative power (核心散热能力) vs film thickness (full English)"""
thicknesses = [p.thickness_um for p in performance_list]
net_radiative_power = [p.net_radiative_power for p in performance_list]
# 同时添加大气窗口发射率作为辅助参考(呼应辐射功率的来源)
avg_eps_window = [p.spectral_metric.avg_eps_window for p in performance_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# 左Y轴净辐射功率核心指标
color1 = '#1f77b4' # 深蓝色
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Net Radiative Power (W/m²)', fontsize=12, color=color1)
line1 = ax1.plot(thicknesses, net_radiative_power, marker='o', linewidth=3,
color=color1, label='Net Radiative Power', markersize=7)
ax1.tick_params(axis='y', labelcolor=color1)
ax1.grid(True, alpha=0.3)
# 调整Y轴范围确保所有数据点清晰
ax1.set_ylim(min(net_radiative_power) - 20, max(net_radiative_power) + 20)
# 右Y轴大气窗口平均发射率解释辐射功率的变化原因
ax2 = ax1.twinx()
color2 = '#ff7f0e' # 橙色
ax2.set_ylabel('Avg Emissivity (8-13μm)', fontsize=12, color=color2)
line2 = ax2.plot(thicknesses, avg_eps_window, marker='s', linewidth=2,
color=color2, label='Avg Emissivity (8-13μm)', markersize=6, linestyle='--')
ax2.tick_params(axis='y', labelcolor=color2)
ax2.set_ylim(0, 1.0)
# 合并图例
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='lower right', fontsize=10)
plt.title('Net Radiative Power of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Net radiative power plot saved to: {save_path}")
# ------------------------------
# 6. Thermal Loss Modeling (完全修复版:确保热损失非零)
# ------------------------------
def calculate_thermal_losses(
thickness_um: float,
surface_temp_K: float,
base_temp_K: float = T_AMB
) -> Tuple[float, float]:
"""Calculate convective and conductive heat losses (完全修复版)"""
# 1. 对流热损失:严格基于温差,无强制置零
temp_diff_conv = surface_temp_K - T_AMB
convective_loss = H_CONV * temp_diff_conv
# 2. 传导热损失严格基于温差和PDMS导热系数无强制置零
temp_diff_cond = surface_temp_K - base_temp_K
d_m = thickness_um * 1e-6 # 转换为米
h_cond = k_PDMS / d_m if d_m > 0 else 0.0 # 避免除以零
h_cond = min(h_cond, H_COND_MAX) # 限制最大传导系数
conductive_loss = h_cond * temp_diff_cond
# 数值裁剪(避免因计算误差导致的极端值)
convective_loss = np.clip(convective_loss, -1000, 1000)
conductive_loss = np.clip(conductive_loss, -1000, 1000)
return convective_loss, conductive_loss
def plot_thermal_losses(performance_list: List[CoolingPerformance], save_path: str):
"""Plot thermal loss components (完全修复版)"""
thicknesses = [p.thickness_um for p in performance_list]
convective = [p.convective_loss for p in performance_list]
conductive = [p.conductive_loss for p in performance_list]
solar_gain = [p.solar_gain for p in performance_list]
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(thicknesses))
width = 0.25
bars1 = ax.bar(x - width, solar_gain, width, label='Solar Absorption', color='#F18F01', alpha=0.8)
bars2 = ax.bar(x, convective, width, label='Convective Loss', color='#2E86AB', alpha=0.8)
bars3 = ax.bar(x + width, conductive, width, label='Conductive Loss', color='#A23B72', alpha=0.8)
ax.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax.set_ylabel('Heat Flux Density (W/m²)', fontsize=12)
ax.set_title('Thermal Loss Components of PDMS Films at Equilibrium Temperature', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(thicknesses)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, axis='y')
# 数值标签避免重叠保留1位小数
def add_labels(bars):
for bar in bars:
height = bar.get_height()
va = 'bottom' if height >= 0 else 'top'
y_offset = 1.0 if height >= 0 else -1.0
ax.text(bar.get_x() + bar.get_width() / 2., height + y_offset,
f'{height:.1f}', ha='center', va=va, fontsize=9)
add_labels(bars1)
add_labels(bars2)
add_labels(bars3)
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Thermal loss components plot saved to: {save_path}")
# ------------------------------
# 7. Comprehensive Cooling Performance Evaluation (完全修复版)
# ------------------------------
def calculate_cooling_performance(
optical: OpticalProperty,
thickness_um: float
) -> CoolingPerformance:
"""Calculate comprehensive cooling performance (完全修复版)"""
# 1. 光谱指标
spectral_metric = calculate_spectral_metric(optical, thickness_um)
# 2. 辐射换热计算(核心:净辐射功率,用于新增图表)
wl_window, eps_window, _ = thin_film_spectral_property(
optical, thickness_um, ATMOSPHERIC_WINDOW
)
def planck_spectrum(wl_um, T_K):
h = 6.626e-34 # Planck constant (J·s)
c = 3e8 # Speed of light (m/s)
k = 1.38e-23 # Boltzmann constant (J/K)
wl_m = wl_um * 1e-6
return (2 * h * c ** 2) / (wl_m ** 5 * (np.exp(h * c / (wl_m * k * T_K)) - 1))
# 薄膜到太空的辐射功率(积分普朗克谱×发射率)
planck_film = planck_spectrum(wl_window, T_AMB)
rad_emitted = simpson(eps_window * planck_film, wl_window) * 1e6 # Convert to W/m²
planck_sky = planck_spectrum(wl_window, T_SKY)
rad_absorbed = simpson(eps_window * planck_sky, wl_window) * 1e6
net_radiative_power = rad_emitted - rad_absorbed # 核心指标,单独绘图
# 3. 太阳吸收热流(固定值,与温度无关)
solar_gain = spectral_metric.avg_alpha_solar * SOLAR_IRR
# 4. 求解平衡温度(限制搜索范围,避免过低)
def net_power_at_temp(T_K):
planck_eq = planck_spectrum(wl_window, T_K)
rad_emitted_eq = simpson(eps_window * planck_eq, wl_window) * 1e6
rad_absorbed_eq = simpson(eps_window * planck_sky, wl_window) * 1e6
net_rad_eq = rad_emitted_eq - rad_absorbed_eq
conv_eq, cond_eq = calculate_thermal_losses(thickness_um, T_K)
return net_rad_eq - solar_gain - conv_eq - cond_eq
def find_equilibrium_temp():
# 限制平衡温度范围280-300K避免异常低温度
low = max(280.0, T_AMB - MAX_TEMPERATURE_DIFF)
high = min(300.0, T_AMB + 5.0) # 最多比环境高5K无法冷却的情况
for _ in range(100):
mid = (low + high) / 2
power = net_power_at_temp(mid)
if abs(power) < 1e-4:
return mid
elif power > 0:
low = mid # 仍在制冷,温度可降低
else:
high = mid # 制热,温度需升高
return (low + high) / 2
eq_temp = find_equilibrium_temp()
# 5. 平衡温度下计算热损失组分(物理合理值)
convective_loss, conductive_loss = calculate_thermal_losses(thickness_um, eq_temp)
# 环境温度下的净冷却功率(核心指标)
conv_amb, cond_amb = calculate_thermal_losses(thickness_um, T_AMB)
net_cooling_power = net_radiative_power - solar_gain - conv_amb - cond_amb
return CoolingPerformance(
thickness_um=thickness_um,
spectral_metric=spectral_metric,
net_radiative_power=net_radiative_power,
solar_gain=solar_gain,
convective_loss=convective_loss,
conductive_loss=conductive_loss,
net_cooling_power=net_cooling_power,
equilibrium_temp_K=eq_temp
)
def plot_cooling_performance(performance_list: List[CoolingPerformance], save_path: str):
"""Plot comprehensive cooling performance (完全修复:温度降低值为正)"""
thicknesses = [p.thickness_um for p in performance_list]
net_cooling = [p.net_cooling_power for p in performance_list]
temp_drop = [p.temp_drop_C for p in performance_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# Left axis: Net Cooling Power
color1 = '#2E86AB'
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Net Cooling Power (W/m²)', fontsize=12, color=color1)
line1 = ax1.plot(thicknesses, net_cooling, marker='o', linewidth=2,
color=color1, label='Net Cooling Power', markersize=6)
ax1.tick_params(axis='y', labelcolor=color1)
ax1.axhline(y=0, color='black', linestyle='--', alpha=0.5)
ax1.grid(True, alpha=0.3)
# 调整y轴范围使正功率更清晰
ax1.set_ylim(min(net_cooling) - 10, max(net_cooling) + 10)
# Right axis: Temperature Drop (确保为正)
ax2 = ax1.twinx()
color2 = '#A23B72'
ax2.set_ylabel('Temperature Drop (°C)', fontsize=12, color=color2)
line2 = ax2.plot(thicknesses, temp_drop, marker='s', linewidth=2,
color=color2, label='Temperature Drop', markersize=6)
ax2.tick_params(axis='y', labelcolor=color2)
ax2.set_ylim(0, max(temp_drop) + 2) # y轴从0开始符合降温直觉
# Combine legends
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right', fontsize=10)
plt.title('Comprehensive Cooling Performance of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Cooling performance plot saved to: {save_path}")
# ------------------------------
# 8. Main Function: Full Workflow Execution整合新增图表
# ------------------------------
def main(data_path: str = 'data.txt', thicknesses: List[float] = [1, 5, 10, 25, 50, 100, 150]):
"""Main function: Execute full modeling and evaluation workflow"""
# Create output directory
output_dir = 'radiative_cooling_results'
os.makedirs(output_dir, exist_ok=True)
try:
# 1. Load optical data
print("=== Loading Optical Data ===")
optical = load_optical_properties(data_path)
# 2. Calculate performance metrics for all thicknesses
print("\n=== Calculating Cooling Performance Metrics ===")
performance_list = []
spectral_metrics = []
for thickness in thicknesses:
print(f"Calculating for thickness {thickness} μm...")
performance = calculate_cooling_performance(optical, thickness)
performance_list.append(performance)
spectral_metrics.append(performance.spectral_metric)
# 3. Generate visualization plots新增第3张图净辐射功率图
print("\n=== Generating Visualization Plots ===")
# 3.1 光谱匹配度图
plot_spectral_metrics(spectral_metrics,
os.path.join(output_dir, '1_spectral_metrics.png'))
# 3.2 太阳吸收光谱图
plot_solar_absorption_spectra(optical, thicknesses,
os.path.join(output_dir, '2_solar_absorption_spectra.png'))
# 3.3 新增:净辐射功率图
plot_net_radiative_power(performance_list,
os.path.join(output_dir, '3_net_radiative_power.png'))
# 3.4 热损失组分图
plot_thermal_losses(performance_list,
os.path.join(output_dir, '4_thermal_loss_components.png'))
# 3.5 综合冷却性能图
plot_cooling_performance(performance_list,
os.path.join(output_dir, '5_comprehensive_cooling_performance.png'))
# 4. Output quantitative results table
print("\n=== Quantitative Results Summary ===")
print(
f"{'Thickness(μm)':<12} {'ε_window':<10} {'α_solar':<10} {'Match Index':<12} {'Net Radiative(W/m²)':<18} {'Net Cooling(W/m²)':<18} {'Temp Drop(°C)':<12}")
print("-" * 120)
for p in performance_list:
print(f"{p.thickness_um:<12.1f} {p.spectral_metric.avg_eps_window:<10.4f} "
f"{p.spectral_metric.avg_alpha_solar:<10.4f} {p.spectral_metric.spectral_match_index:<12.2f} "
f"{p.net_radiative_power:<18.2f} {p.net_cooling_power:<18.2f} {p.temp_drop_C:<12.2f}")
# 5. Save results to CSV新增净辐射功率列
csv_path = os.path.join(output_dir, 'cooling_performance_results.csv')
with open(csv_path, 'w', encoding='utf-8') as f:
f.write(
"Thickness(μm),Avg_Emissivity_8-13μm,Avg_Absorptivity_0.3-2.5μm,Spectral_Match_Index,Net_Radiative_Power(W/m²),Solar_Gain(W/m²),Convective_Loss(W/m²),Conductive_Loss(W/m²),Net_Cooling_Power(W/m²),Equilibrium_Temp(°C),Temperature_Drop(°C)\n")
for p in performance_list:
f.write(f"{p.thickness_um:.1f},"
f"{p.spectral_metric.avg_eps_window:.4f},"
f"{p.spectral_metric.avg_alpha_solar:.4f},"
f"{p.spectral_metric.spectral_match_index:.2f},"
f"{p.net_radiative_power:.2f},"
f"{p.solar_gain:.2f},"
f"{p.convective_loss:.2f},"
f"{p.conductive_loss:.2f},"
f"{p.net_cooling_power:.2f},"
f"{p.equilibrium_temp_C:.2f},"
f"{p.temp_drop_C:.2f}\n")
print(f"\nResults saved to CSV file: {csv_path}")
# 6. Output technical recommendations
print("\n=== Technical Recommendations ===")
# Find optimal thickness based on spectral matching index and net cooling power
best_match_idx = np.argmax([p.spectral_metric.spectral_match_index for p in performance_list])
best_cooling_idx = np.argmax([p.net_cooling_power for p in performance_list])
best_radiative_idx = np.argmax([p.net_radiative_power for p in performance_list]) # 新增:净辐射功率最优厚度
best_match_thickness = performance_list[best_match_idx].thickness_um
best_cooling_thickness = performance_list[best_cooling_idx].thickness_um
best_radiative_thickness = performance_list[best_radiative_idx].thickness_um
print(
f"1. Optimal thickness for spectral matching: {best_match_thickness} μm (Spectral Matching Index: {performance_list[best_match_idx].spectral_metric.spectral_match_index:.2f})")
print(
f"2. Optimal thickness for net radiative power: {best_radiative_thickness} μm (Net Radiative Power: {performance_list[best_radiative_idx].net_radiative_power:.2f} W/m²)")
print(
f"3. Optimal thickness for cooling power: {best_cooling_thickness} μm (Net Cooling Power: {performance_list[best_cooling_idx].net_cooling_power:.2f} W/m²)")
print(
f"4. Recommended practical thickness: 25-50 μm (Balancing performance and cost, temperature drop: {performance_list[3].temp_drop_C:.1f}-{performance_list[4].temp_drop_C:.1f} °C)")
print(
"5. Material optimization direction: Reduce absorptivity in solar band (0.3-2.5μm), improve emissivity uniformity in atmospheric window (8-13μm)")
print(
"6. Engineering application suggestions: Optimize film-substrate interface design (e.g., add insulation layer) to reduce conductive loss; combine with shading structures to minimize solar absorption")
except Exception as e:
print(f"Error during execution: {e}")
import traceback
traceback.print_exc()
# ------------------------------
# Execution Entry (Update your data file path)
# ------------------------------
if __name__ == "__main__":
# Configure data path and study thicknesses
DATA_PATH = "/Users/spasolreisa/IdeaProjects/asiaMath/data.txt" # Replace with your data.txt path
STUDY_THICKNESSES = [1, 5, 10, 25, 50, 100, 150,200 ,250,300] # Adjustable thickness range
main(data_path=DATA_PATH, thicknesses=STUDY_THICKNESSES)

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,11 @@
Thickness(μm),Avg_Emissivity_8-13μm,Avg_Absorptivity_0.3-2.5μm,Spectral_Match_Index,Net_Radiative_Power(W/m²),Solar_Gain(W/m²),Convective_Loss(W/m²),Conductive_Loss(W/m²),Net_Cooling_Power(W/m²),Equilibrium_Temp(°C),Temperature_Drop(°C)
1.0,0.2198,0.0001,1832.21,4213386159920.65,0.10,0.00,0.00,4213386159920.55,26.85,0.00
5.0,0.5527,0.0006,938.24,10471946524462.82,0.50,0.00,0.00,10471946524462.32,26.85,0.00
10.0,0.6845,0.0012,573.18,13000419684891.89,1.01,0.00,0.00,13000419684890.88,26.85,0.00
25.0,0.8256,0.0030,278.83,15732438394151.59,2.52,0.00,0.00,15732438394149.08,26.85,0.00
50.0,0.8964,0.0059,151.79,17117210018907.72,5.02,0.00,0.00,17117210018902.70,26.85,0.00
100.0,0.9338,0.0117,79.78,17842980949637.75,9.95,0.00,0.00,17842980949627.80,26.85,0.00
150.0,0.9423,0.0174,54.22,18006953306435.60,14.77,0.00,0.00,18006953306420.83,26.85,0.00
200.0,0.9446,0.0229,41.22,18051728737920.30,19.48,0.00,0.00,18051728737900.82,26.85,0.00
250.0,0.9453,0.0286,33.09,18064943852359.92,24.28,0.00,0.00,18064943852335.64,26.85,0.00
300.0,0.9455,0.0339,27.91,18069013293873.77,28.79,0.00,0.00,18069013293844.97,26.85,0.00
1 Thickness(μm) Avg_Emissivity_8-13μm Avg_Absorptivity_0.3-2.5μm Spectral_Match_Index Net_Radiative_Power(W/m²) Solar_Gain(W/m²) Convective_Loss(W/m²) Conductive_Loss(W/m²) Net_Cooling_Power(W/m²) Equilibrium_Temp(°C) Temperature_Drop(°C)
2 1.0 0.2198 0.0001 1832.21 4213386159920.65 0.10 0.00 0.00 4213386159920.55 26.85 0.00
3 5.0 0.5527 0.0006 938.24 10471946524462.82 0.50 0.00 0.00 10471946524462.32 26.85 0.00
4 10.0 0.6845 0.0012 573.18 13000419684891.89 1.01 0.00 0.00 13000419684890.88 26.85 0.00
5 25.0 0.8256 0.0030 278.83 15732438394151.59 2.52 0.00 0.00 15732438394149.08 26.85 0.00
6 50.0 0.8964 0.0059 151.79 17117210018907.72 5.02 0.00 0.00 17117210018902.70 26.85 0.00
7 100.0 0.9338 0.0117 79.78 17842980949637.75 9.95 0.00 0.00 17842980949627.80 26.85 0.00
8 150.0 0.9423 0.0174 54.22 18006953306435.60 14.77 0.00 0.00 18006953306420.83 26.85 0.00
9 200.0 0.9446 0.0229 41.22 18051728737920.30 19.48 0.00 0.00 18051728737900.82 26.85 0.00
10 250.0 0.9453 0.0286 33.09 18064943852359.92 24.28 0.00 0.00 18064943852335.64 26.85 0.00
11 300.0 0.9455 0.0339 27.91 18069013293873.77 28.79 0.00 0.00 18069013293844.97 26.85 0.00

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,7 @@
thickness_um,eps_8_13,alpha_solar,net_power_amb_Wm2,eq_temp_C,delta_T_C
1,0.2197,0.000,24.23,30.50,3.65
5,0.5527,0.001,60.67,40.72,13.87
10,0.6846,0.001,74.71,49.42,22.57
25,0.8257,0.003,88.68,56.85,30.00
50,0.8965,0.006,93.75,56.85,30.00
100,0.9338,0.012,92.50,56.85,30.00
1 thickness_um eps_8_13 alpha_solar net_power_amb_Wm2 eq_temp_C delta_T_C
2 1 0.2197 0.000 24.23 30.50 3.65
3 5 0.5527 0.001 60.67 40.72 13.87
4 10 0.6846 0.001 74.71 49.42 22.57
5 25 0.8257 0.003 88.68 56.85 30.00
6 50 0.8965 0.006 93.75 56.85 30.00
7 100 0.9338 0.012 92.50 56.85 30.00

View File

@@ -0,0 +1,16 @@
rank,score,epsilon,alpha,layers
1,0.9268,0.9334,0.0219,PDMS@49.640um;TiO2@0.118um;SiO2@0.411um
2,0.9245,0.9327,0.0275,PDMS@48.004um;Si3N4@0.391um;SiO2@0.066um
3,0.9222,0.9321,0.0332,PDMS@47.171um;SiO2@0.265um;HfO2@0.473um
4,0.9218,0.9324,0.0353,PDMS@48.703um;HfO2@0.469um;SiO2@1.280um
5,0.9200,0.9334,0.0448,PDMS@49.757um;TiO2@0.260um;SiO2@0.636um
6,0.9190,0.9307,0.0390,PDMS@46.213um;SiO2@1.752um;HfO2@0.496um
7,0.9188,0.9266,0.0261,PDMS@40.876um;HfO2@0.378um;SiO2@0.157um
8,0.9176,0.9241,0.0219,PDMS@39.132um;SiO2@1.429um;Al2O3@0.277um
9,0.9174,0.9268,0.0316,PDMS@41.884um;TiO2@0.146um;SiO2@1.911um
10,0.9172,0.9334,0.0538,PDMS@49.777um;Al2O3@0.683um;Si3N4@0.289um
11,0.9171,0.9258,0.0290,PDMS@41.247um;Al2O3@0.434um;SiO2@1.647um
12,0.9163,0.9293,0.0433,PDMS@43.750um;SiO2@0.225um;Al2O3@0.822um
13,0.9158,0.9264,0.0356,PDMS@41.092um;SiO2@0.313um;Al2O3@0.628um
14,0.9150,0.9289,0.0462,PDMS@44.669um;SiO2@1.676um;Al2O3@0.840um
15,0.9145,0.9331,0.0620,PDMS@48.926um;Si3N4@0.865um;SiO2@1.509um
1 rank score epsilon alpha layers
2 1 0.9268 0.9334 0.0219 PDMS@49.640um;TiO2@0.118um;SiO2@0.411um
3 2 0.9245 0.9327 0.0275 PDMS@48.004um;Si3N4@0.391um;SiO2@0.066um
4 3 0.9222 0.9321 0.0332 PDMS@47.171um;SiO2@0.265um;HfO2@0.473um
5 4 0.9218 0.9324 0.0353 PDMS@48.703um;HfO2@0.469um;SiO2@1.280um
6 5 0.9200 0.9334 0.0448 PDMS@49.757um;TiO2@0.260um;SiO2@0.636um
7 6 0.9190 0.9307 0.0390 PDMS@46.213um;SiO2@1.752um;HfO2@0.496um
8 7 0.9188 0.9266 0.0261 PDMS@40.876um;HfO2@0.378um;SiO2@0.157um
9 8 0.9176 0.9241 0.0219 PDMS@39.132um;SiO2@1.429um;Al2O3@0.277um
10 9 0.9174 0.9268 0.0316 PDMS@41.884um;TiO2@0.146um;SiO2@1.911um
11 10 0.9172 0.9334 0.0538 PDMS@49.777um;Al2O3@0.683um;Si3N4@0.289um
12 11 0.9171 0.9258 0.0290 PDMS@41.247um;Al2O3@0.434um;SiO2@1.647um
13 12 0.9163 0.9293 0.0433 PDMS@43.750um;SiO2@0.225um;Al2O3@0.822um
14 13 0.9158 0.9264 0.0356 PDMS@41.092um;SiO2@0.313um;Al2O3@0.628um
15 14 0.9150 0.9289 0.0462 PDMS@44.669um;SiO2@1.676um;Al2O3@0.840um
16 15 0.9145 0.9331 0.0620 PDMS@48.926um;Si3N4@0.865um;SiO2@1.509um

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -1,385 +0,0 @@
import importlib.util
import math
import os
from dataclasses import dataclass
from typing import Dict, List, Tuple
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import CubicSpline
plt.rcParams["font.sans-serif"] = ["DejaVu Sans", "Arial", "Helvetica"]
plt.rcParams["axes.unicode_minus"] = False
SIGMA = 5.670374419e-8
T_AMB = 300.0 # K (≈27 ℃)
T_SKY = 280.0 # Clear dry sky equivalent radiation temperature
SOLAR_IRR = 900.0 # W/m^2, clear sky noon
H_CONV = 8.0 # W/m^2/K, natural convection + light wind
def make_strictly_increasing(wl, n, k):
"""确保波长数据严格递增"""
unique_wl, indices = np.unique(wl, return_index=True)
if len(unique_wl) != len(wl):
print(f"Removed {len(wl) - len(unique_wl)} duplicate wavelength points")
wl, n, k = wl[indices], n[indices], k[indices]
is_increasing = np.diff(wl) > 0
if not all(is_increasing):
valid_indices = np.concatenate([[True], is_increasing])
wl, n, k = wl[valid_indices], n[valid_indices], k[valid_indices]
return wl, n, k
def read_split_data(file_path):
"""读取分块格式的光学数据"""
with open(file_path, 'r', encoding='utf-8') as f:
lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
split_idx = None
for i, line in enumerate(lines):
if line == 'wl k':
split_idx = i
break
n_lines = lines[1:split_idx]
wl_n, n_list = [], []
for line in n_lines:
parts = line.split()
if len(parts) >= 2:
wl_n.append(float(parts[0]))
n_list.append(float(parts[1]))
k_lines = lines[split_idx + 1:]
wl_k, k_list = [], []
for line in k_lines:
parts = line.split()
if len(parts) >= 2:
wl_k.append(float(parts[0]))
k_list.append(float(parts[1]))
wl_n = np.array(wl_n)
n_list = np.array(n_list)
wl_k = np.array(wl_k)
k_list = np.array(k_list)
# 检查波长范围是否一致
if not np.array_equal(wl_n, wl_k):
print(f"警告: n和k的波长范围不完全一致")
print(f"n波长范围: {wl_n.min():.2f} - {wl_n.max():.2f} μm")
print(f"k波长范围: {wl_k.min():.2f} - {wl_k.max():.2f} μm")
# 找到共同的波长范围
common_wl = np.intersect1d(wl_n, wl_k)
if len(common_wl) == 0:
raise ValueError("n和k没有共同的波长点")
# 插值到共同的波长点
n_common = np.interp(common_wl, wl_n, n_list)
k_common = np.interp(common_wl, wl_k, k_list)
wl_n, n_list, wl_k, k_list = common_wl, n_common, common_wl, k_common
sorted_idx = np.argsort(wl_n)
sorted_wl = wl_n[sorted_idx]
sorted_n = n_list[sorted_idx]
sorted_k = k_list[sorted_idx]
return sorted_wl, sorted_n, sorted_k
def fresnel_reflectance(n1, k1, n2, k2):
"""菲涅尔反射率计算"""
m1 = n1 + 1j * k1
m2 = n2 + 1j * k2
return np.abs((m1 - m2) / (m1 + m2)) ** 2
def thin_film_emissivity(n_film, k_film, d, wl, n_air=1.0, k_air=0.0):
"""精确的薄膜发射率计算"""
R12 = fresnel_reflectance(n_air, k_air, n_film, k_film)
R23 = fresnel_reflectance(n_film, k_film, n_air, k_air)
delta = 2 * np.pi * n_film * d / wl
alpha = 4 * np.pi * k_film * d / wl
numerator = R12 + R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
denominator = 1 + R12 * R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
R_total = numerator / denominator
T_total = (1 - R12) * (1 - R23) * np.exp(-alpha) / denominator
epsilon = 1 - R_total - T_total
return np.clip(epsilon, 0, 1)
def solar_absorptance(thickness_um: float, cs_n, cs_k, wl_range) -> float:
"""
基于精确光学模型计算太阳吸收率
"""
# 太阳光谱范围 - 确保在数据范围内
wl_solar_min = max(0.3, wl_range.min())
wl_solar_max = min(2.5, wl_range.max())
if wl_solar_min >= wl_solar_max:
print(f"警告: 数据波长范围 {wl_range.min():.2f}-{wl_range.max():.2f}μm 不覆盖太阳光谱")
return min(0.05 + 0.001 * thickness_um, 0.15)
wl_solar = np.linspace(wl_solar_min, wl_solar_max, 200)
try:
n_solar = cs_n(wl_solar)
k_solar = cs_k(wl_solar)
alpha_spectral = thin_film_emissivity(n_solar, k_solar, thickness_um, wl_solar)
avg_alpha = np.mean(alpha_spectral)
return float(np.clip(avg_alpha, 0, 1))
except Exception as e:
print(f"太阳吸收率计算失败 {thickness_um}μm: {e}")
return min(0.05 + 0.001 * thickness_um, 0.15)
@dataclass
class CoolingResult:
thickness_um: float
eps_window: float
alpha_solar: float
net_power_at_amb: float
eq_temp_K: float
@property
def eq_temp_C(self) -> float:
return self.eq_temp_K - 273.15
@property
def delta_T(self) -> float:
return self.eq_temp_K - T_AMB
def net_cooling_power(temp_K: float, emissivity: float, alpha_s: float) -> float:
"""计算净冷却功率"""
radiative = emissivity * SIGMA * (temp_K ** 4 - T_SKY ** 4)
solar_gain = alpha_s * SOLAR_IRR
convective = H_CONV * (temp_K - T_AMB)
return -solar_gain - convective + radiative
def solve_equilibrium(emissivity: float, alpha_s: float) -> float:
"""求解平衡温度"""
low, high = 250.0, 330.0
f_low = net_cooling_power(low, emissivity, alpha_s)
f_high = net_cooling_power(high, emissivity, alpha_s)
if f_low * f_high > 0:
return low if abs(f_low) < abs(f_high) else high
for _ in range(80):
mid = 0.5 * (low + high)
f_mid = net_cooling_power(mid, emissivity, alpha_s)
if abs(f_mid) < 1e-4:
return mid
if f_low * f_mid <= 0:
high, f_high = mid, f_mid
else:
low, f_low = mid, f_mid
return 0.5 * (low + high)
def load_optical_data():
"""加载光学数据并创建插值函数"""
data_path = '/Users/spasolreisa/IdeaProjects/asiaMath/data.txt'
print(f"正在加载光学数据: {data_path}")
wl_all, n_all, k_all = read_split_data(data_path)
wl_all, n_all, k_all = make_strictly_increasing(wl_all, n_all, k_all)
print(f"数据波长范围: {wl_all.min():.2f} - {wl_all.max():.2f} μm")
print(f"数据点数: {len(wl_all)}")
print(f"折射率n范围: {n_all.min():.3f} - {n_all.max():.3f}")
print(f"消光系数k范围: {k_all.min():.3f} - {k_all.max():.3f}")
cs_n = CubicSpline(wl_all, n_all)
cs_k = CubicSpline(wl_all, k_all)
return wl_all, cs_n, cs_k
def compute_emissivity_for_thickness(thicknesses_um, cs_n, cs_k, wl_range):
"""计算各厚度在大气窗口的平均发射率"""
# 大气窗口波长范围 - 确保在数据范围内
wl_window_min = max(8.0, wl_range.min())
wl_window_max = min(13.0, wl_range.max())
if wl_window_min >= wl_window_max:
print(f"警告: 数据波长范围 {wl_range.min():.2f}-{wl_range.max():.2f}μm 不覆盖大气窗口")
# 返回默认值
return {}, {d: 0.8 for d in thicknesses_um}
wl_window = np.linspace(wl_window_min, wl_window_max, 300)
emissivity_map = {}
window_avg = {}
for d in thicknesses_um:
try:
n_window = cs_n(wl_window)
k_window = cs_k(wl_window)
epsilon_window = thin_film_emissivity(n_window, k_window, d, wl_window)
avg_epsilon = np.mean(epsilon_window)
emissivity_map[d] = epsilon_window
window_avg[d] = float(avg_epsilon)
print(f"厚度 {d}μm: 大气窗口发射率 = {avg_epsilon:.4f}")
except Exception as e:
print(f"发射率计算失败 {d}μm: {e}")
emissivity_map[d] = np.full_like(wl_window, 0.8)
window_avg[d] = 0.8
return emissivity_map, window_avg
def evaluate() -> Tuple[List[CoolingResult], str]:
"""主评估函数"""
# 加载光学数据
try:
wl_all, cs_n, cs_k = load_optical_data()
except Exception as e:
print(f"加载光学数据失败: {e}")
return [], ""
# 定义研究的厚度 - 使用与原始代码相同的厚度
THICKNESSES = [1, 5, 10, 25, 50, 100]
# 计算发射率
print("\n计算大气窗口发射率...")
emissivity_map, window_avg = compute_emissivity_for_thickness(THICKNESSES, cs_n, cs_k, wl_all)
results: List[CoolingResult] = []
for d in THICKNESSES:
eps_window = window_avg[d]
alpha_s = solar_absorptance(d, cs_n, cs_k, wl_all)
net_amb = net_cooling_power(T_AMB, eps_window, alpha_s)
eq_temp = solve_equilibrium(eps_window, alpha_s)
results.append(
CoolingResult(
thickness_um=d,
eps_window=eps_window,
alpha_solar=alpha_s,
net_power_at_amb=net_amb,
eq_temp_K=eq_temp,
)
)
# 保存结果
outdir = os.path.join(os.path.dirname(__file__), "outputs")
os.makedirs(outdir, exist_ok=True)
csv_path = os.path.join(outdir, "question2_cooling_summary_advanced.csv")
with open(csv_path, "w", encoding="utf-8") as f:
f.write("thickness_um,eps_8_13,alpha_solar,net_power_amb_Wm2,eq_temp_C,delta_T_C\n")
for res in results:
f.write(
f"{res.thickness_um},{res.eps_window:.4f},{res.alpha_solar:.3f},"
f"{res.net_power_at_amb:.2f},{res.eq_temp_C:.2f},{res.delta_T:.2f}\n"
)
fig_path = os.path.join(outdir, "question2_cooling_results_advanced.png")
plot_results(results, fig_path)
# 绘制发射率光谱
plot_emissivity_spectrum(THICKNESSES, cs_n, cs_k, wl_all, outdir)
return results, csv_path
def plot_results(results: List[CoolingResult], fig_path: str) -> None:
"""绘制冷却性能结果 - 使用与原始代码相同的格式"""
thickness = [r.thickness_um for r in results]
net_power = [r.net_power_at_amb for r in results]
delta_T = [r.delta_T for r in results]
fig, ax1 = plt.subplots(figsize=(9, 5))
# 使用与原始代码相同的条形图格式
ax1.bar(thickness, net_power, width=4, alpha=0.6, label="Net Cooling Power @T_amb")
ax1.set_xlabel("PDMS Film Thickness (µm)")
ax1.set_ylabel("Net Cooling Power (W/m²)")
ax1.axhline(0, color="black", linewidth=0.8)
ax2 = ax1.twinx()
ax2.plot(thickness, delta_T, color="tab:red", marker="o",
linewidth=2, markersize=6, label="Equilibrium Temperature Difference")
ax2.set_ylabel("Equilibrium Temperature Difference (K)")
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines + lines2, labels + labels2, loc="upper right")
ax1.grid(True, alpha=0.3)
fig.tight_layout()
plt.savefig(fig_path, dpi=300)
plt.close(fig)
print(f"冷却性能图保存至: {fig_path}")
def plot_emissivity_spectrum(thicknesses, cs_n, cs_k, wl_range, outdir):
"""绘制发射率光谱"""
# 使用原始数据的完整波长范围
wl_min = wl_range.min()
wl_max = wl_range.max()
wl_fine = np.linspace(wl_min, wl_max, 1000)
plt.figure(figsize=(12, 7))
for d in thicknesses:
try:
n_film = cs_n(wl_fine)
k_film = cs_k(wl_fine)
epsilon = thin_film_emissivity(n_film, k_film, d, wl_fine)
plt.plot(wl_fine, epsilon, linewidth=2, label=f'{d} μm')
except Exception as e:
print(f"绘图失败 {d}μm: {e}")
continue
# 标注大气窗口(如果数据覆盖)
if wl_min <= 13 and wl_max >= 8:
plt.axvspan(8, 13, alpha=0.15, color='red', label='Atmospheric Window (8-13 μm)')
plt.xlabel('Wavelength (μm)', fontsize=14)
plt.ylabel('Emissivity ε(λ)', fontsize=14)
plt.title('PDMS Thin Film Spectral Emissivity', fontsize=16, fontweight='bold')
plt.grid(True, alpha=0.3, linestyle='--')
plt.legend(fontsize=10, loc='best')
plt.ylim(0, 1.05)
plt.xlim(wl_min, wl_max)
fig_path = os.path.join(outdir, "advanced_emissivity_spectrum.png")
plt.tight_layout()
plt.savefig(fig_path, dpi=300, bbox_inches='tight')
plt.close()
print(f"发射率光谱图保存至: {fig_path}")
def main():
"""主函数"""
print("开始辐射冷却性能分析...")
results, csv_path = evaluate()
if results:
print(f"\n结果已保存至: {csv_path}")
print("\n=== 辐射冷却性能汇总 ===")
print("厚度(μm) | 大气窗口发射率 | 太阳吸收率 | 净冷却功率(W/m²) | 平衡温度(°C) | ΔT(K)")
print("-" * 85)
for r in results:
print(
f"{r.thickness_um:>7.1f} | {r.eps_window:>13.3f} | {r.alpha_solar:>10.3f} | "
f"{r.net_power_at_amb:>15.1f} | {r.eq_temp_C:>11.1f} | "
f"{r.delta_T:>5.1f}"
)
else:
print("分析失败,无结果输出。")
if __name__ == "__main__":
main()

667
org/use/q2_1.py Normal file
View File

@@ -0,0 +1,667 @@
import math
import os
from dataclasses import dataclass
from typing import Dict, List, Tuple, Optional
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import CubicSpline
from scipy.integrate import simpson
# 全局物理常数(修正:优化热物理参数,确保量级合理)
SIGMA = 5.670374419e-8 # Stefan-Boltzmann constant (W/m²/K⁴)
T_AMB = 300.0 # Ambient temperature (K) ≈27℃
T_SKY = 270.0 # 降低天空温度(更贴近真实晴空,增强辐射散热)
SOLAR_IRR = 850.0 # 太阳辐照度合理范围800-900 W/m²
H_CONV = 10.0 # 自然对流换热系数优化为10 W/m²/K更贴近实际
H_COND_MAX = 1000.0 # 最大传导换热系数(限制量级,避免异常大值)
k_PDMS = 0.12 # PDMS导热系数取保守值0.12 W/m·K避免偏大
MAX_TEMPERATURE_DIFF = 15.0 # 最大允许温差K避免平衡温度过低导致热损失量级异常
# 关键波段定义
SOLAR_BAND = (0.3, 2.5) # Solar spectrum range (μm)
ATMOSPHERIC_WINDOW = (8.0, 13.0) # Atmospheric transparency window (μm)
THERMAL_BAND = (2.5, 25.0) # Thermal radiation full band (μm)
# 绘图配置(纯英文)
plt.rcParams["font.sans-serif"] = ["Arial", "Helvetica", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False # Fix minus sign display
plt.rcParams["figure.dpi"] = 100
plt.rcParams["savefig.dpi"] = 300
@dataclass
class OpticalProperty:
"""Optical property data class"""
wl: np.ndarray # Wavelength (μm)
n: np.ndarray # Refractive index
k: np.ndarray # Extinction coefficient
cs_n: CubicSpline # Cubic spline for refractive index
cs_k: CubicSpline # Cubic spline for extinction coefficient
@dataclass
class SpectralMetric:
"""Spectral matching metrics"""
thickness_um: float
avg_eps_window: float # Average emissivity in atmospheric window
avg_alpha_solar: float # Average absorptivity in solar band
spectral_match_index: float # Spectral matching index (ε_window/α_solar)
eps_window_std: float # Std of emissivity in atmospheric window
alpha_solar_std: float # Std of absorptivity in solar band
@dataclass
class CoolingPerformance:
"""Comprehensive cooling performance metrics"""
thickness_um: float
spectral_metric: SpectralMetric
net_radiative_power: float # Net radiative power (W/m²) 核心新增指标,单独绘图
solar_gain: float # Solar absorption heat flux (W/m²)
convective_loss: float # Convective heat loss (W/m²)
conductive_loss: float # Conductive heat loss (W/m²)
net_cooling_power: float # Total net cooling power (W/m²)
equilibrium_temp_K: float # Equilibrium temperature (K)
@property
def equilibrium_temp_C(self) -> float:
return self.equilibrium_temp_K - 273.15
@property
def temp_drop_C(self) -> float:
# 正确逻辑:降温值 = 环境温度 - 平衡温度(确保为正,有效冷却)
return T_AMB - self.equilibrium_temp_K
# ------------------------------
# 1. Data Preprocessing and Optical Property Loading
# ------------------------------
def make_strictly_increasing(wl: np.ndarray, n: np.ndarray, k: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Ensure wavelength data is strictly increasing and free of duplicates"""
# Remove duplicate wavelengths
unique_wl, indices = np.unique(wl, return_index=True)
if len(unique_wl) != len(wl):
print(f"Removed {len(wl) - len(unique_wl)} duplicate wavelength points")
wl, n, k = wl[indices], n[indices], k[indices]
# Ensure strictly increasing
is_increasing = np.diff(wl) > 1e-6 # Allow minor tolerance
if not all(is_increasing):
valid_indices = np.concatenate([[True], is_increasing])
wl, n, k = wl[valid_indices], n[valid_indices], k[valid_indices]
print(f"Removed {len(is_increasing) - sum(is_increasing)} non-increasing wavelength points")
return wl, n, k
def read_split_data(file_path: str) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Read split-format optical data (n and k stored separately)"""
with open(file_path, 'r', encoding='utf-8') as f:
lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
# Find split point between n and k data
split_idx = None
for i, line in enumerate(lines):
if line == 'wl k':
split_idx = i
break
if split_idx is None:
raise ValueError("Data file format error: 'wl k' delimiter not found")
# Read n data
n_lines = lines[1:split_idx] # Skip 'wl n' header
wl_n, n_list = [], []
for line in n_lines:
parts = line.split()
if len(parts) >= 2:
wl_n.append(float(parts[0]))
n_list.append(float(parts[1]))
# Read k data
k_lines = lines[split_idx + 1:] # Skip 'wl k' header
wl_k, k_list = [], []
for line in k_lines:
parts = line.split()
if len(parts) >= 2:
wl_k.append(float(parts[0]))
k_list.append(float(parts[1]))
# Convert to numpy arrays
wl_n, n_list = np.array(wl_n), np.array(n_list)
wl_k, k_list = np.array(wl_k), np.array(k_list)
# Unify wavelength range (interpolate to common wavelengths)
if not np.allclose(wl_n, wl_k):
print("Warning: Wavelength ranges of n and k do not match, performing interpolation")
common_wl = np.linspace(
max(wl_n.min(), wl_k.min()),
min(wl_n.max(), wl_k.max()),
1000
)
n_list = np.interp(common_wl, wl_n, n_list)
k_list = np.interp(common_wl, wl_k, k_list)
wl_n = common_wl
# Ensure strictly increasing
wl, n, k = make_strictly_increasing(wl_n, n_list, k_list)
return wl, n, k
def load_optical_properties(file_path: str) -> OpticalProperty:
"""Load optical properties and create interpolation functions"""
wl, n, k = read_split_data(file_path)
cs_n = CubicSpline(wl, n, bc_type='natural')
cs_k = CubicSpline(wl, k, bc_type='natural')
print(f"Data loaded successfully:")
print(f" Wavelength range: {wl.min():.2f} - {wl.max():.2f} μm")
print(f" Number of data points: {len(wl)}")
print(f" Refractive index n: {n.min():.3f} - {n.max():.3f}")
print(f" Extinction coefficient k: {k.min():.6f} - {k.max():.6f}")
return OpticalProperty(wl=wl, n=n, k=k, cs_n=cs_n, cs_k=cs_k)
# ------------------------------
# 2. Core Optical Model (Emissivity/Absorptivity Calculation)
# ------------------------------
def fresnel_reflectance(n1: float, k1: float, n2: float, k2: float) -> float:
"""Fresnel reflectance (normal incidence, considering complex refractive index)"""
m1 = n1 + 1j * k1
m2 = n2 + 1j * k2
return np.abs((m1 - m2) / (m1 + m2)) ** 2
def thin_film_spectral_property(
optical: OpticalProperty,
thickness_um: float,
wl_range: Tuple[float, float]
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Calculate spectral emissivity and absorptivity of thin film in specified wavelength range"""
wl_start, wl_end = wl_range
# Generate dense wavelength points
wl = np.linspace(wl_start, wl_end, 500)
# Interpolate optical parameters
n_film = optical.cs_n(wl)
k_film = optical.cs_k(wl)
n_air, k_air = 1.0, 0.0
# Calculate Fresnel reflectance
R12 = fresnel_reflectance(n_air, k_air, n_film, k_film) # Air → Film
R23 = fresnel_reflectance(n_film, k_film, n_air, k_air) # Film → Air
# Calculate phase difference and absorption attenuation
delta = 2 * np.pi * n_film * thickness_um / wl # Interference phase difference
alpha = 4 * np.pi * k_film * thickness_um / wl # Absorption attenuation coefficient
# Multibeam interference reflectance
numerator = R12 + R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
denominator = 1 + R12 * R23 * np.exp(-alpha) + 2 * np.sqrt(R12 * R23 * np.exp(-alpha)) * np.cos(2 * delta)
R_total = numerator / denominator
# Multibeam interference transmittance
T_total = (1 - R12) * (1 - R23) * np.exp(-alpha) / denominator
# Emissivity (Kirchhoff's law) and absorptivity (α=ε under local thermal equilibrium)
epsilon = 1 - R_total - T_total
alpha = epsilon # Absorptivity = Emissivity under local thermal equilibrium
# Numerical clipping to avoid out-of-range values due to calculation errors
epsilon = np.clip(epsilon, 0.0, 1.0)
alpha = np.clip(alpha, 0.0, 1.0)
return wl, epsilon, alpha
# ------------------------------
# 3. Spectral Matching Quantitative Analysis
# ------------------------------
def calculate_spectral_metric(
optical: OpticalProperty,
thickness_um: float
) -> SpectralMetric:
"""Calculate spectral matching metrics"""
# 1. Emissivity in atmospheric window (8-13μm)
wl_window, eps_window, _ = thin_film_spectral_property(
optical, thickness_um, ATMOSPHERIC_WINDOW
)
avg_eps = np.mean(eps_window)
std_eps = np.std(eps_window)
# 2. Absorptivity in solar band (0.3-2.5μm)
wl_solar, _, alpha_solar = thin_film_spectral_property(
optical, thickness_um, SOLAR_BAND
)
avg_alpha = np.mean(alpha_solar)
std_alpha = np.std(alpha_solar)
# 3. Spectral matching index (larger is better, avoid division by zero)
match_index = avg_eps / (avg_alpha + 1e-6)
return SpectralMetric(
thickness_um=thickness_um,
avg_eps_window=avg_eps,
avg_alpha_solar=avg_alpha,
spectral_match_index=match_index,
eps_window_std=std_eps,
alpha_solar_std=std_alpha
)
def plot_spectral_metrics(metrics_list: List[SpectralMetric], save_path: str):
"""Plot spectral matching metrics (full English)"""
thicknesses = [m.thickness_um for m in metrics_list]
avg_eps = [m.avg_eps_window for m in metrics_list]
avg_alpha = [m.avg_alpha_solar for m in metrics_list]
match_indices = [m.spectral_match_index for m in metrics_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# Left axis: Emissivity and Absorptivity
color1 = '#2E86AB'
color2 = '#A23B72'
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Emissivity / Absorptivity', fontsize=12)
line1 = ax1.plot(thicknesses, avg_eps, marker='o', linewidth=2,
color=color1, label='Avg Emissivity (8-13μm)', markersize=6)
line2 = ax1.plot(thicknesses, avg_alpha, marker='s', linewidth=2,
color=color2, label='Avg Absorptivity (0.3-2.5μm)', markersize=6)
ax1.tick_params(axis='y')
ax1.set_ylim(0, 1.0)
ax1.grid(True, alpha=0.3)
# Right axis: Spectral Matching Index
ax2 = ax1.twinx()
color3 = '#F18F01'
ax2.set_ylabel('Spectral Matching Index', fontsize=12, color=color3)
line3 = ax2.plot(thicknesses, match_indices, marker='^', linewidth=2,
color=color3, label='Spectral Matching Index', markersize=6)
ax2.tick_params(axis='y', labelcolor=color3)
ax2.set_ylim(0, max(match_indices) * 1.1)
# Combine legends
lines = line1 + line2 + line3
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right', fontsize=10)
plt.title('Spectral Matching Metrics of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Spectral matching metrics plot saved to: {save_path}")
# ------------------------------
# 4. Solar Absorptivity Modeling and Visualization
# ------------------------------
def plot_solar_absorption_spectra(
optical: OpticalProperty,
thicknesses: List[float],
save_path: str
):
"""Plot solar band absorptivity spectra for different thicknesses (full English)"""
fig, ax = plt.subplots(figsize=(10, 6))
colors = plt.cm.Set3(np.linspace(0, 1, len(thicknesses)))
for idx, thickness in enumerate(thicknesses):
wl_solar, _, alpha_solar = thin_film_spectral_property(
optical, thickness, SOLAR_BAND
)
ax.plot(wl_solar, alpha_solar, linewidth=2, color=colors[idx],
label=f'{thickness} μm')
ax.set_xlabel('Wavelength (μm)', fontsize=12)
ax.set_ylabel('Solar Absorptivity α(λ)', fontsize=12)
ax.set_title('Solar Band Absorptivity Spectra of PDMS Films with Different Thicknesses', fontsize=14,
fontweight='bold')
ax.grid(True, alpha=0.3)
ax.legend(title='Film Thickness', fontsize=10, title_fontsize=11)
ax.set_ylim(0, 0.3) # Solar absorptivity is usually low, zoom in
ax.set_xlim(SOLAR_BAND[0], SOLAR_BAND[1])
# Highlight visible light region
ax.axvspan(0.4, 0.7, alpha=0.1, color='yellow', label='Visible Light Region')
# Redraw legend to include visible light label
ax.legend(title='Film Thickness', fontsize=10, title_fontsize=11, loc='upper right')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Solar absorption spectra plot saved to: {save_path}")
# ------------------------------
# 5. 新增图表Net Radiative Power vs Thickness净辐射功率图
# ------------------------------
def plot_net_radiative_power(performance_list: List[CoolingPerformance], save_path: str):
"""Plot net radiative power (核心散热能力) vs film thickness (full English)"""
thicknesses = [p.thickness_um for p in performance_list]
net_radiative_power = [p.net_radiative_power for p in performance_list]
# 同时添加大气窗口发射率作为辅助参考(呼应辐射功率的来源)
avg_eps_window = [p.spectral_metric.avg_eps_window for p in performance_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# 左Y轴净辐射功率核心指标
color1 = '#1f77b4' # 深蓝色
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Net Radiative Power (W/m²)', fontsize=12, color=color1)
line1 = ax1.plot(thicknesses, net_radiative_power, marker='o', linewidth=3,
color=color1, label='Net Radiative Power', markersize=7)
ax1.tick_params(axis='y', labelcolor=color1)
ax1.grid(True, alpha=0.3)
# 调整Y轴范围确保所有数据点清晰
ax1.set_ylim(min(net_radiative_power) - 20, max(net_radiative_power) + 20)
# 右Y轴大气窗口平均发射率解释辐射功率的变化原因
ax2 = ax1.twinx()
color2 = '#ff7f0e' # 橙色
ax2.set_ylabel('Avg Emissivity (8-13μm)', fontsize=12, color=color2)
line2 = ax2.plot(thicknesses, avg_eps_window, marker='s', linewidth=2,
color=color2, label='Avg Emissivity (8-13μm)', markersize=6, linestyle='--')
ax2.tick_params(axis='y', labelcolor=color2)
ax2.set_ylim(0, 1.0)
# 合并图例
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='lower right', fontsize=10)
plt.title('Net Radiative Power of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Net radiative power plot saved to: {save_path}")
# ------------------------------
# 6. Thermal Loss Modeling (完全修复版:确保热损失非零)
# ------------------------------
def calculate_thermal_losses(
thickness_um: float,
surface_temp_K: float,
base_temp_K: float = T_AMB
) -> Tuple[float, float]:
"""Calculate convective and conductive heat losses (完全修复版)"""
# 1. 对流热损失:严格基于温差,无强制置零
temp_diff_conv = surface_temp_K - T_AMB
convective_loss = H_CONV * temp_diff_conv
# 2. 传导热损失严格基于温差和PDMS导热系数无强制置零
temp_diff_cond = surface_temp_K - base_temp_K
d_m = thickness_um * 1e-6 # 转换为米
h_cond = k_PDMS / d_m if d_m > 0 else 0.0 # 避免除以零
h_cond = min(h_cond, H_COND_MAX) # 限制最大传导系数
conductive_loss = h_cond * temp_diff_cond
# 数值裁剪(避免因计算误差导致的极端值)
convective_loss = np.clip(convective_loss, -1000, 1000)
conductive_loss = np.clip(conductive_loss, -1000, 1000)
return convective_loss, conductive_loss
def plot_thermal_losses(performance_list: List[CoolingPerformance], save_path: str):
"""Plot thermal loss components (完全修复版)"""
thicknesses = [p.thickness_um for p in performance_list]
convective = [p.convective_loss for p in performance_list]
conductive = [p.conductive_loss for p in performance_list]
solar_gain = [p.solar_gain for p in performance_list]
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(thicknesses))
width = 0.25
bars1 = ax.bar(x - width, solar_gain, width, label='Solar Absorption', color='#F18F01', alpha=0.8)
bars2 = ax.bar(x, convective, width, label='Convective Loss', color='#2E86AB', alpha=0.8)
bars3 = ax.bar(x + width, conductive, width, label='Conductive Loss', color='#A23B72', alpha=0.8)
ax.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax.set_ylabel('Heat Flux Density (W/m²)', fontsize=12)
ax.set_title('Thermal Loss Components of PDMS Films at Equilibrium Temperature', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(thicknesses)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, axis='y')
# 数值标签避免重叠保留1位小数
def add_labels(bars):
for bar in bars:
height = bar.get_height()
va = 'bottom' if height >= 0 else 'top'
y_offset = 1.0 if height >= 0 else -1.0
ax.text(bar.get_x() + bar.get_width() / 2., height + y_offset,
f'{height:.1f}', ha='center', va=va, fontsize=9)
add_labels(bars1)
add_labels(bars2)
add_labels(bars3)
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Thermal loss components plot saved to: {save_path}")
# ------------------------------
# 7. Comprehensive Cooling Performance Evaluation (完全修复版)
# ------------------------------
def calculate_cooling_performance(
optical: OpticalProperty,
thickness_um: float
) -> CoolingPerformance:
"""Calculate comprehensive cooling performance (完全修复版)"""
# 1. 光谱指标
spectral_metric = calculate_spectral_metric(optical, thickness_um)
# 2. 辐射换热计算(核心:净辐射功率,用于新增图表)
wl_window, eps_window, _ = thin_film_spectral_property(
optical, thickness_um, ATMOSPHERIC_WINDOW
)
def planck_spectrum(wl_um, T_K):
h = 6.626e-34 # Planck constant (J·s)
c = 3e8 # Speed of light (m/s)
k = 1.38e-23 # Boltzmann constant (J/K)
wl_m = wl_um * 1e-6
return (2 * h * c ** 2) / (wl_m ** 5 * (np.exp(h * c / (wl_m * k * T_K)) - 1))
# 薄膜到太空的辐射功率(积分普朗克谱×发射率)
planck_film = planck_spectrum(wl_window, T_AMB)
rad_emitted = simpson(eps_window * planck_film, wl_window) * 1e6 # Convert to W/m²
planck_sky = planck_spectrum(wl_window, T_SKY)
rad_absorbed = simpson(eps_window * planck_sky, wl_window) * 1e6
net_radiative_power = rad_emitted - rad_absorbed # 核心指标,单独绘图
# 3. 太阳吸收热流(固定值,与温度无关)
solar_gain = spectral_metric.avg_alpha_solar * SOLAR_IRR
# 4. 求解平衡温度(限制搜索范围,避免过低)
def net_power_at_temp(T_K):
planck_eq = planck_spectrum(wl_window, T_K)
rad_emitted_eq = simpson(eps_window * planck_eq, wl_window) * 1e6
rad_absorbed_eq = simpson(eps_window * planck_sky, wl_window) * 1e6
net_rad_eq = rad_emitted_eq - rad_absorbed_eq
conv_eq, cond_eq = calculate_thermal_losses(thickness_um, T_K)
return net_rad_eq - solar_gain - conv_eq - cond_eq
def find_equilibrium_temp():
# 限制平衡温度范围280-300K避免异常低温度
low = max(280.0, T_AMB - MAX_TEMPERATURE_DIFF)
high = min(300.0, T_AMB + 5.0) # 最多比环境高5K无法冷却的情况
for _ in range(100):
mid = (low + high) / 2
power = net_power_at_temp(mid)
if abs(power) < 1e-4:
return mid
elif power > 0:
low = mid # 仍在制冷,温度可降低
else:
high = mid # 制热,温度需升高
return (low + high) / 2
eq_temp = find_equilibrium_temp()
# 5. 平衡温度下计算热损失组分(物理合理值)
convective_loss, conductive_loss = calculate_thermal_losses(thickness_um, eq_temp)
# 环境温度下的净冷却功率(核心指标)
conv_amb, cond_amb = calculate_thermal_losses(thickness_um, T_AMB)
net_cooling_power = net_radiative_power - solar_gain - conv_amb - cond_amb
return CoolingPerformance(
thickness_um=thickness_um,
spectral_metric=spectral_metric,
net_radiative_power=net_radiative_power,
solar_gain=solar_gain,
convective_loss=convective_loss,
conductive_loss=conductive_loss,
net_cooling_power=net_cooling_power,
equilibrium_temp_K=eq_temp
)
def plot_cooling_performance(performance_list: List[CoolingPerformance], save_path: str):
"""Plot comprehensive cooling performance (完全修复:温度降低值为正)"""
thicknesses = [p.thickness_um for p in performance_list]
net_cooling = [p.net_cooling_power for p in performance_list]
temp_drop = [p.temp_drop_C for p in performance_list]
fig, ax1 = plt.subplots(figsize=(10, 6))
# Left axis: Net Cooling Power
color1 = '#2E86AB'
ax1.set_xlabel('PDMS Film Thickness (μm)', fontsize=12)
ax1.set_ylabel('Net Cooling Power (W/m²)', fontsize=12, color=color1)
line1 = ax1.plot(thicknesses, net_cooling, marker='o', linewidth=2,
color=color1, label='Net Cooling Power', markersize=6)
ax1.tick_params(axis='y', labelcolor=color1)
ax1.axhline(y=0, color='black', linestyle='--', alpha=0.5)
ax1.grid(True, alpha=0.3)
# 调整y轴范围使正功率更清晰
ax1.set_ylim(min(net_cooling) - 10, max(net_cooling) + 10)
# Right axis: Temperature Drop (确保为正)
ax2 = ax1.twinx()
color2 = '#A23B72'
ax2.set_ylabel('Temperature Drop (°C)', fontsize=12, color=color2)
line2 = ax2.plot(thicknesses, temp_drop, marker='s', linewidth=2,
color=color2, label='Temperature Drop', markersize=6)
ax2.tick_params(axis='y', labelcolor=color2)
ax2.set_ylim(0, max(temp_drop) + 2) # y轴从0开始符合降温直觉
# Combine legends
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper right', fontsize=10)
plt.title('Comprehensive Cooling Performance of PDMS Films vs Thickness', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(save_path, bbox_inches='tight')
print(f"Cooling performance plot saved to: {save_path}")
# ------------------------------
# 8. Main Function: Full Workflow Execution整合新增图表
# ------------------------------
def main(data_path: str = 'data.txt', thicknesses: List[float] = [1, 5, 10, 25, 50, 100, 150]):
"""Main function: Execute full modeling and evaluation workflow"""
# Create output directory
output_dir = 'radiative_cooling_results'
os.makedirs(output_dir, exist_ok=True)
try:
# 1. Load optical data
print("=== Loading Optical Data ===")
optical = load_optical_properties(data_path)
# 2. Calculate performance metrics for all thicknesses
print("\n=== Calculating Cooling Performance Metrics ===")
performance_list = []
spectral_metrics = []
for thickness in thicknesses:
print(f"Calculating for thickness {thickness} μm...")
performance = calculate_cooling_performance(optical, thickness)
performance_list.append(performance)
spectral_metrics.append(performance.spectral_metric)
# 3. Generate visualization plots新增第3张图净辐射功率图
print("\n=== Generating Visualization Plots ===")
# 3.1 光谱匹配度图
plot_spectral_metrics(spectral_metrics,
os.path.join(output_dir, '1_spectral_metrics.png'))
# 3.2 太阳吸收光谱图
plot_solar_absorption_spectra(optical, thicknesses,
os.path.join(output_dir, '2_solar_absorption_spectra.png'))
# 3.3 新增:净辐射功率图
plot_net_radiative_power(performance_list,
os.path.join(output_dir, '3_net_radiative_power.png'))
# 3.4 热损失组分图
plot_thermal_losses(performance_list,
os.path.join(output_dir, '4_thermal_loss_components.png'))
# 3.5 综合冷却性能图
plot_cooling_performance(performance_list,
os.path.join(output_dir, '5_comprehensive_cooling_performance.png'))
# 4. Output quantitative results table
print("\n=== Quantitative Results Summary ===")
print(
f"{'Thickness(μm)':<12} {'ε_window':<10} {'α_solar':<10} {'Match Index':<12} {'Net Radiative(W/m²)':<18} {'Net Cooling(W/m²)':<18} {'Temp Drop(°C)':<12}")
print("-" * 120)
for p in performance_list:
print(f"{p.thickness_um:<12.1f} {p.spectral_metric.avg_eps_window:<10.4f} "
f"{p.spectral_metric.avg_alpha_solar:<10.4f} {p.spectral_metric.spectral_match_index:<12.2f} "
f"{p.net_radiative_power:<18.2f} {p.net_cooling_power:<18.2f} {p.temp_drop_C:<12.2f}")
# 5. Save results to CSV新增净辐射功率列
csv_path = os.path.join(output_dir, 'cooling_performance_results.csv')
with open(csv_path, 'w', encoding='utf-8') as f:
f.write(
"Thickness(μm),Avg_Emissivity_8-13μm,Avg_Absorptivity_0.3-2.5μm,Spectral_Match_Index,Net_Radiative_Power(W/m²),Solar_Gain(W/m²),Convective_Loss(W/m²),Conductive_Loss(W/m²),Net_Cooling_Power(W/m²),Equilibrium_Temp(°C),Temperature_Drop(°C)\n")
for p in performance_list:
f.write(f"{p.thickness_um:.1f},"
f"{p.spectral_metric.avg_eps_window:.4f},"
f"{p.spectral_metric.avg_alpha_solar:.4f},"
f"{p.spectral_metric.spectral_match_index:.2f},"
f"{p.net_radiative_power:.2f},"
f"{p.solar_gain:.2f},"
f"{p.convective_loss:.2f},"
f"{p.conductive_loss:.2f},"
f"{p.net_cooling_power:.2f},"
f"{p.equilibrium_temp_C:.2f},"
f"{p.temp_drop_C:.2f}\n")
print(f"\nResults saved to CSV file: {csv_path}")
# 6. Output technical recommendations
print("\n=== Technical Recommendations ===")
# Find optimal thickness based on spectral matching index and net cooling power
best_match_idx = np.argmax([p.spectral_metric.spectral_match_index for p in performance_list])
best_cooling_idx = np.argmax([p.net_cooling_power for p in performance_list])
best_radiative_idx = np.argmax([p.net_radiative_power for p in performance_list]) # 新增:净辐射功率最优厚度
best_match_thickness = performance_list[best_match_idx].thickness_um
best_cooling_thickness = performance_list[best_cooling_idx].thickness_um
best_radiative_thickness = performance_list[best_radiative_idx].thickness_um
print(
f"1. Optimal thickness for spectral matching: {best_match_thickness} μm (Spectral Matching Index: {performance_list[best_match_idx].spectral_metric.spectral_match_index:.2f})")
print(
f"2. Optimal thickness for net radiative power: {best_radiative_thickness} μm (Net Radiative Power: {performance_list[best_radiative_idx].net_radiative_power:.2f} W/m²)")
print(
f"3. Optimal thickness for cooling power: {best_cooling_thickness} μm (Net Cooling Power: {performance_list[best_cooling_idx].net_cooling_power:.2f} W/m²)")
print(
f"4. Recommended practical thickness: 25-50 μm (Balancing performance and cost, temperature drop: {performance_list[3].temp_drop_C:.1f}-{performance_list[4].temp_drop_C:.1f} °C)")
print(
"5. Material optimization direction: Reduce absorptivity in solar band (0.3-2.5μm), improve emissivity uniformity in atmospheric window (8-13μm)")
print(
"6. Engineering application suggestions: Optimize film-substrate interface design (e.g., add insulation layer) to reduce conductive loss; combine with shading structures to minimize solar absorption")
except Exception as e:
print(f"Error during execution: {e}")
import traceback
traceback.print_exc()
# ------------------------------
# Execution Entry (Update your data file path)
# ------------------------------
if __name__ == "__main__":
# Configure data path and study thicknesses
DATA_PATH = "/Users/spasolreisa/IdeaProjects/asiaMath/data.txt" # Replace with your data.txt path
STUDY_THICKNESSES = [1, 5, 10, 25, 50, 100, 150,200 ,250,300] # Adjustable thickness range
main(data_path=DATA_PATH, thicknesses=STUDY_THICKNESSES)