14from typing
import Dict, Tuple, Optional, List
48 layers: List[MaterialLayer],
49 bc: ThermalBoundaryConditions,
50 n_points_per_layer: int = 10,
51) -> Dict[str, np.ndarray]:
53 Calculate steady-state temperature profile through multi-layer wall.
55 Uses thermal resistance network:
56 q = (T_hot - T_cold) / R_total
57 R_total = R_conv_hot + R_cond_1 + R_cond_2 + ... + R_conv_cold
60 R_cond = t / (k * A) (1D conduction)
64 layers : List[MaterialLayer]
65 Material layers from hot side to cold side
66 bc : ThermalBoundaryConditions
68 n_points_per_layer : int
69 Number of temperature points per layer
74 - positions: np.ndarray [m] - Distance from hot surface
75 - temperatures: np.ndarray [K] - Temperature at each position
76 - heat_flux: float [W/m²] - Steady-state heat flux
77 - T_surface_hot: float [K] - Hot surface temperature
78 - T_surface_cold: float [K] - Cold surface temperature
79 - layer_boundaries: List[float] - Positions of layer boundaries
82 raise ValueError(
"layers list cannot be empty")
85 R_conv_hot = 1.0 /
max(bc.h_hot_gas, 1e-6)
89 if layer.thickness <= 0:
91 R_cond_layer = layer.thickness /
max(layer.thermal_conductivity, 1e-6)
92 R_cond_total += R_cond_layer
94 R_conv_cold = 1.0 /
max(bc.h_ambient, 1e-6)
95 R_total = R_conv_hot + R_cond_total + R_conv_cold
100 T_surface_hot_guess = bc.T_hot_gas * 0.8
103 q_conv = bc.h_hot_gas * (bc.T_hot_gas - T_surface_hot_guess)
105 q_total = q_conv + q_rad
108 delta_T_hot = q_total * R_conv_hot
109 T_surface_hot = bc.T_hot_gas - delta_T_hot
111 if abs(T_surface_hot - T_surface_hot_guess) < 1.0:
113 T_surface_hot_guess = T_surface_hot
116 delta_T_cold = q_total * R_conv_cold
117 T_surface_cold = bc.T_ambient + delta_T_cold
122 layer_boundaries = [0.0]
125 current_temp = T_surface_hot
127 for i, layer
in enumerate(layers):
128 if layer.thickness <= 0:
132 R_layer = layer.thickness /
max(layer.thermal_conductivity, 1e-6)
133 delta_T_layer = q_total * R_layer
136 x_layer = np.linspace(0, layer.thickness, n_points_per_layer)
137 T_layer = current_temp - (delta_T_layer / layer.thickness) * x_layer
139 positions.extend(current_pos + x_layer)
140 temperatures.extend(T_layer)
142 current_pos += layer.thickness
143 current_temp -= delta_T_layer
144 layer_boundaries.append(current_pos)
146 positions = np.array(positions)
147 temperatures = np.array(temperatures)
150 "positions": positions,
151 "temperatures": temperatures,
152 "heat_flux": float(q_total),
153 "T_surface_hot": float(T_surface_hot),
154 "T_surface_cold": float(T_surface_cold),
155 "layer_boundaries": layer_boundaries,
156 "R_total": float(R_total),
161 surface_temperature: float,
162 ablative_config: AblativeCoolingConfig,
164 time_step: float = 0.01,
165) -> Dict[str, float]:
167 Calculate pyrolysis response including char layer formation.
169 Pyrolysis occurs when T > T_pyrolysis:
170 - Material decomposes into char + pyrolysis gases
171 - Char layer forms on surface (lower conductivity)
172 - Pyrolysis gases flow outward (blowing effect)
176 surface_temperature : float
177 Surface temperature [K]
178 ablative_config : AblativeCoolingConfig
179 Ablative material configuration
181 Incident heat flux [W/m²]
183 Time step [s] for transient calculations
188 - pyrolysis_rate: float [kg/(m²·s)] - Mass flux of pyrolysis gases
189 - char_formation_rate: float [m/s] - Char layer growth rate
190 - char_thickness: float [m] - Current char layer thickness
191 - pyrolysis_active: bool - Whether pyrolysis is occurring
192 - energy_consumed: float [J/kg] - Energy consumed by pyrolysis
194 if surface_temperature < ablative_config.pyrolysis_temperature:
196 "pyrolysis_rate": 0.0,
197 "char_formation_rate": 0.0,
198 "char_thickness": 0.0,
199 "pyrolysis_active":
False,
200 "energy_consumed": 0.0,
205 T_excess = surface_temperature - ablative_config.pyrolysis_temperature
206 T_normalized = T_excess / (ablative_config.surface_temperature_limit - ablative_config.pyrolysis_temperature)
207 T_normalized = np.clip(T_normalized, 0.0, 1.0)
211 pyrolysis_rate_max = 1.0
212 pyrolysis_rate = pyrolysis_rate_max * (T_normalized ** 2.0)
215 char_density = 1000.0
216 virgin_density = ablative_config.material_density
217 char_formation_rate = pyrolysis_rate * (virgin_density / char_density - 1.0) / virgin_density
222 char_thickness = ablative_config.char_layer_thickness
226 delta_h_pyrolysis = 2.0e6
227 energy_consumed = pyrolysis_rate * delta_h_pyrolysis
230 "pyrolysis_rate": float(pyrolysis_rate),
231 "char_formation_rate": float(char_formation_rate),
232 "char_thickness": float(char_thickness),
233 "pyrolysis_active":
True,
234 "energy_consumed": float(energy_consumed),
239 surface_temperature: float,
240 material_config: AblativeCoolingConfig | GraphiteInsertConfig,
242 pressure: float = 1e6,
243) -> Dict[str, float]:
245 Calculate material vaporization rate at high temperatures.
247 Vaporization occurs when T > T_vaporization:
248 - Material directly sublimates/vaporizes
249 - No char formation (unlike pyrolysis)
250 - High energy consumption
254 surface_temperature : float
255 Surface temperature [K]
256 material_config : AblativeCoolingConfig | GraphiteInsertConfig
257 Material configuration
259 Incident heat flux [W/m²]
266 - vaporization_rate: float [kg/(m²·s)] - Mass flux of vaporized material
267 - vaporization_active: bool - Whether vaporization is occurring
268 - energy_consumed: float [J/kg] - Energy consumed by vaporization
271 if isinstance(material_config, AblativeCoolingConfig):
272 T_vap = material_config.surface_temperature_limit * 1.1
274 T_vap = material_config.surface_temperature_limit * 0.95
276 if surface_temperature < T_vap:
278 "vaporization_rate": 0.0,
279 "vaporization_active":
False,
280 "energy_consumed": 0.0,
285 T_excess = surface_temperature - T_vap
286 P_effect = (1e6 /
max(pressure, 1e3)) ** 0.5
290 vaporization_rate_max = 0.1
291 vaporization_rate = vaporization_rate_max * np.exp(-5000.0 /
max(surface_temperature, 1000.0)) * P_effect
295 delta_h_vaporization = 10.0e6
296 energy_consumed = vaporization_rate * delta_h_vaporization
299 "vaporization_rate": float(vaporization_rate),
300 "vaporization_active":
True,
301 "energy_consumed": float(energy_consumed),
306 layers: List[MaterialLayer],
307 bc: ThermalBoundaryConditions,
308 ablative_config: Optional[AblativeCoolingConfig] =
None,
309 graphite_config: Optional[GraphiteInsertConfig] =
None,
312 Comprehensive thermal analysis of multi-layer system.
315 - Steady-state temperature profile
316 - Pyrolysis response (if ablative)
317 - Vaporization (if high temperature)
318 - Back-face temperature check
322 layers : List[MaterialLayer]
323 Material layers (hot to cold)
324 bc : ThermalBoundaryConditions
326 ablative_config : Optional[AblativeCoolingConfig]
327 Ablative configuration (if applicable)
328 graphite_config : Optional[GraphiteInsertConfig]
329 Graphite configuration (if applicable)
334 Comprehensive thermal analysis results
339 T_surface_hot = temp_profile[
"T_surface_hot"]
340 q_total = temp_profile[
"heat_flux"]
343 pyrolysis_results = {}
344 if ablative_config
is not None:
352 vaporization_results = {}
353 if ablative_config
is not None and T_surface_hot > ablative_config.surface_temperature_limit * 1.05:
359 elif graphite_config
is not None and T_surface_hot > graphite_config.surface_temperature_limit * 0.9:
367 T_backface = temp_profile[
"T_surface_cold"]
371 "temperature_profile": temp_profile,
372 "T_surface_hot": T_surface_hot,
373 "T_backface": T_backface,
374 "heat_flux": q_total,
375 "pyrolysis": pyrolysis_results,
376 "vaporization": vaporization_results,
385 ablative_config: AblativeCoolingConfig,
386 backface_temp_limit: float = 500.0,
387 stainless_thickness: float = 0.002,
388 stainless_k: float = 15.0,
389) -> Dict[str, float]:
391 Calculate required ablative thickness to keep backface below limit.
393 This is a sizing function to determine how much ablative material is needed.
398 Design heat flux [W/m²]
401 ablative_config : AblativeCoolingConfig
402 Ablative material configuration
403 backface_temp_limit : float
404 Maximum backface temperature [K]
405 stainless_thickness : float
406 Stainless steel wall thickness [m]
408 Stainless steel thermal conductivity [W/(m·K)]
413 - required_thickness: float [m] - Required ablative thickness
414 - recession_allowance: float [m] - Material lost to recession
415 - conduction_thickness: float [m] - Thickness for thermal protection
416 - safety_margin: float [m] - Recommended safety margin
419 T_surface_estimate = ablative_config.pyrolysis_temperature * 1.1
423 delta_T_pyro =
max(T_surface_estimate - ablative_config.pyrolysis_temperature, 0.0)
424 energy_per_mass = ablative_config.heat_of_ablation + ablative_config.specific_heat * delta_T_pyro
425 mass_flux = heat_flux /
max(energy_per_mass, 1e-6)
426 recession_rate = mass_flux / ablative_config.material_density
427 recession_allowance = recession_rate * burn_time
432 R_stainless = stainless_thickness / stainless_k
433 delta_T_stainless = heat_flux * R_stainless
434 delta_T_ablative_max = T_surface_estimate - backface_temp_limit - delta_T_stainless
436 if delta_T_ablative_max <= 0:
437 conduction_thickness = 0.0
439 conduction_thickness = (ablative_config.thermal_conductivity /
max(heat_flux, 1e-6)) * delta_T_ablative_max
442 total_thickness = recession_allowance + conduction_thickness
443 safety_margin = 0.3 * total_thickness
445 required_thickness = recession_allowance + conduction_thickness + safety_margin
448 "required_thickness": float(required_thickness),
449 "recession_allowance": float(recession_allowance),
450 "conduction_thickness": float(conduction_thickness),
451 "safety_margin": float(safety_margin),
452 "recession_rate": float(recession_rate),
Dict[str, float] calculate_required_ablative_thickness(float heat_flux, float burn_time, AblativeCoolingConfig ablative_config, float backface_temp_limit=500.0, float stainless_thickness=0.002, float stainless_k=15.0)