158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
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
|
||
|
||
plt.rcParams["font.sans-serif"] = ["DejaVu Sans", "Arial", "Helvetica"]
|
||
plt.rcParams["axes.unicode_minus"] = False
|
||
|
||
SIGMA = 5.670374419e-8
|
||
|
||
THICKNESSES = [1, 5, 10, 25, 50, 100] # µm
|
||
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 load_emissivity_module():
|
||
here = os.path.dirname(os.path.abspath(__file__))
|
||
target = os.path.join(here, "question1_pdms_emissivity.py")
|
||
spec = importlib.util.spec_from_file_location("q1", target)
|
||
module = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(module) # type: ignore[arg-type]
|
||
return module
|
||
|
||
|
||
def solar_absorptance(thickness_um: float) -> float:
|
||
"""
|
||
Empirical assumption: In PDMS silver-coated system, visible light absorption
|
||
is determined by thin film scattering and internal losses.
|
||
At 1 µm, α≈0.05, absorption increases by 0.01 for every 10 µm increase in thickness, capped at 0.15.
|
||
"""
|
||
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:
|
||
# No sign change, return endpoint with smaller energy consumption
|
||
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 evaluate() -> Tuple[List[CoolingResult], str]:
|
||
q1 = load_emissivity_module()
|
||
emissivity_data = q1.compute_emissivity(THICKNESSES)
|
||
|
||
results: List[CoolingResult] = []
|
||
for d in THICKNESSES:
|
||
eps_window = emissivity_data.window_avg[d]
|
||
alpha_s = solar_absorptance(d)
|
||
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.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.png")
|
||
plot_results(results, fig_path)
|
||
|
||
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", 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")
|
||
fig.tight_layout()
|
||
plt.savefig(fig_path, dpi=300)
|
||
plt.close(fig)
|
||
|
||
|
||
def main():
|
||
results, csv_path = evaluate()
|
||
print(f"Results written to: {csv_path}")
|
||
for r in results:
|
||
print(
|
||
f"d={r.thickness_um:>3} um, eps_8_13={r.eps_window:.2f}, alpha_sol={r.alpha_solar:.2f}, "
|
||
f"q_net(T_amb)={r.net_power_at_amb:.1f} W/m2, T_eq={r.eq_temp_C:.1f} °C "
|
||
f"(DeltaT={r.delta_T:.1f} K)"
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|