13 gas_temperature: float,
14 material_density: float,
15 heat_of_ablation: float,
17 pyrolysis_temp: float,
18 blowing_efficiency: float = 0.8,
19 char_layer_conductivity: float = 0.2,
20 char_layer_thickness: float = 0.001,
23 Calculate local ablation recession rate using physics-based heat balance.
25 The recession rate depends on:
26 1. Convective heat flux (function of Re, Pr, Mach)
27 2. Radiative heat flux
28 3. Blowing effect (pyrolysis gases blocking heat)
29 4. Char layer thermal resistance
30 5. Material properties
33 q_net = q_conv + q_rad - q_reradiation - q_blowing - q_char
34 ṁ_ablation = q_net / (h_ablation + cp × ΔT_pyrolysis)
35 recession_rate = ṁ_ablation / ρ_material
40 Incident convective heat flux [W/m²]
42 Local static pressure [Pa]
44 Local gas velocity [m/s]
45 gas_temperature : float
46 Local gas temperature [K]
47 material_density : float
48 Ablative material density [kg/m³]
49 heat_of_ablation : float
50 Effective heat of ablation [J/kg]
52 Material specific heat [J/(kg·K)]
53 pyrolysis_temp : float
54 Pyrolysis temperature [K]
55 blowing_efficiency : float
56 Effectiveness of pyrolysis gases in blocking heat (0-1)
57 char_layer_conductivity : float
58 Thermal conductivity of char layer [W/(m·K)]
59 char_layer_thickness : float
60 Thickness of protective char layer [m]
64 recession_rate : float
65 Local recession rate [m/s]
77 T_surface =
min(pyrolysis_temp + (gas_temperature - pyrolysis_temp) * 0.1, gas_temperature * 0.95)
80 q_reradiation = SIGMA * (T_surface ** 4 - 300 ** 4)
83 if char_layer_thickness > 0
and char_layer_conductivity > 0:
84 q_char_resistance = char_layer_conductivity * (gas_temperature - T_surface) / char_layer_thickness
87 q_char_resistance =
min(q_char_resistance, heat_flux)
89 q_char_resistance = 0.0
96 q_blowing_reduction = heat_flux * blowing_efficiency
99 q_net = heat_flux - q_reradiation - q_blowing_reduction + q_char_resistance
100 q_net =
max(q_net, 0.0)
103 delta_T_pyro =
max(T_surface - pyrolysis_temp, 0.0)
104 energy_per_mass = heat_of_ablation + specific_heat * delta_T_pyro
107 if energy_per_mass > 0:
108 mass_flux = q_net / energy_per_mass
109 recession_rate = mass_flux / material_density
113 return float(recession_rate)
117 chamber_pressure: float,
118 chamber_velocity: float,
119 throat_velocity: float,
120 chamber_heat_flux: float,
122 D_chamber: float =
None,
123 D_throat: float =
None,
126 Calculate throat recession multiplier based on local flow conditions using heuristic scaling.
128 Throat recession is typically 1.2-2.0x higher than chamber due to:
129 1. Higher velocity → Higher convective heat transfer
130 2. Sonic conditions → Maximum heat flux
131 3. Pressure gradient → Enhanced mass transfer
132 4. Turbulence amplification near throat
134 Heuristic scaling for heat flux ratio:
135 q_throat / q_chamber ∝ (V_throat / V_chamber)^1.0 × (P_throat / P_chamber)^0.1
137 WARNING: This is not a formal Bartz correlation. Real throat heat transfer depends on
138 geometry (D_t, curvature), viscosity/Pr, and boundary layer state. If
139 heat_transfer_coefficient at the throat is already available from a CFD or
140 boundary-layer code, this heuristic multiplier should not be used.
144 chamber_pressure : float
145 Chamber pressure [Pa]
146 chamber_velocity : float
147 Chamber gas velocity [m/s]
148 throat_velocity : float
149 Throat gas velocity (sonic) [m/s]
150 chamber_heat_flux : float
151 Chamber wall heat flux [W/m²]
162 Throat recession multiplier (typically 1.2-2.0)
164 if chamber_velocity <= 0
or throat_velocity <= 0:
175 velocity_ratio = throat_velocity / chamber_velocity
176 velocity_factor = velocity_ratio
181 pressure_ratio = (2.0 / (gamma + 1.0)) ** (gamma / (gamma - 1.0))
182 pressure_factor = pressure_ratio ** 0.1
185 heat_flux_ratio = velocity_factor * pressure_factor
195 if D_chamber
is None:
207 rho_approx = chamber_pressure / (R_approx * T_approx)
if R_approx > 0
and T_approx > 0
else chamber_pressure / (300.0 * 3000.0)
209 Re_throat_approx = rho_approx * throat_velocity * D_throat / mu_approx
if D_throat > 0
else 1e5
211 turbulence_enhancement = calculate_turbulence_enhancement_physics(
212 Re_throat=Re_throat_approx,
213 velocity_ratio=throat_velocity / chamber_velocity,
218 multiplier = heat_flux_ratio * turbulence_enhancement
221 multiplier = float(np.clip(multiplier, 1.2, 2.5))
227 V_chamber_initial: float,
228 A_throat_initial: float,
229 D_chamber_initial: float,
230 D_throat_initial: float,
232 recession_thickness_chamber: float,
233 recession_thickness_throat: Optional[float] =
None,
234 coverage_fraction: float = 1.0,
235 throat_recession_multiplier: Optional[float] =
None,
236) -> Tuple[float, float, float, float, Dict[str, float]]:
238 Update chamber volume and throat area after ablative recession.
240 Uses physics-based recession rates for chamber and throat separately.
241 Accounts for non-uniform recession patterns.
245 V_chamber_initial : float
246 Initial chamber volume [m³]
247 A_throat_initial : float
248 Initial throat area [m²]
249 D_chamber_initial : float
250 Initial chamber inner diameter [m]
251 D_throat_initial : float
252 Initial throat diameter [m]
255 recession_thickness_chamber : float
256 Total thickness of ablative material removed from chamber [m]
257 recession_thickness_throat : float, optional
258 Total thickness removed from throat [m]
259 If None, calculated from throat_recession_multiplier
260 coverage_fraction : float
261 Fraction of chamber surface with ablative (default 1.0)
262 throat_recession_multiplier : float, optional
263 Multiplier for throat recession vs chamber (default from physics)
264 Typically 1.2-2.0 depending on flow conditions
268 V_chamber_new : float
269 Updated chamber volume [m³]
271 Updated throat area [m²]
272 D_chamber_new : float
273 Updated chamber diameter [m]
275 Updated throat diameter [m]
277 Additional diagnostic information
279 if recession_thickness_chamber <= 0
or coverage_fraction <= 0:
286 "recession_chamber": 0.0,
287 "recession_throat": 0.0,
288 "volume_change_pct": 0.0,
289 "throat_area_change_pct": 0.0,
294 effective_recession_chamber = recession_thickness_chamber * coverage_fraction
297 if recession_thickness_throat
is not None:
298 effective_recession_throat = recession_thickness_throat * coverage_fraction
301 if throat_recession_multiplier
is None:
304 throat_recession_multiplier = 1.5
305 effective_recession_throat = effective_recession_chamber * throat_recession_multiplier
310 D_chamber_new = D_chamber_initial + 2.0 * effective_recession_chamber
311 R0 = D_chamber_initial / 2.0
312 V_chamber_new = V_chamber_initial + np.pi * ((R0 + effective_recession_chamber) ** 2 - R0 ** 2) * L_chamber
316 D_throat_new = D_throat_initial + 2.0 * effective_recession_throat
317 R_throat_new = D_throat_new / 2.0
318 A_throat_new = np.pi * (R_throat_new ** 2)
321 if V_chamber_initial > 0:
322 volume_change_pct = (V_chamber_new - V_chamber_initial) / V_chamber_initial * 100.0
324 volume_change_pct = 0.0
326 if A_throat_initial > 0:
327 throat_area_change_pct = (A_throat_new - A_throat_initial) / A_throat_initial * 100.0
329 throat_area_change_pct = 0.0
332 "recession_chamber": float(effective_recession_chamber),
333 "recession_throat": float(effective_recession_throat),
334 "throat_recession_multiplier": float(effective_recession_throat /
max(effective_recession_chamber, 1e-12)),
335 "volume_change_pct": float(volume_change_pct),
336 "throat_area_change_pct": float(throat_area_change_pct),
337 "D_chamber_change": float(D_chamber_new - D_chamber_initial),
338 "D_throat_change": float(D_throat_new - D_throat_initial),
342 float(V_chamber_new),
344 float(D_chamber_new),
351 A_exit_initial: float,
352 D_exit_initial: float,
353 recession_thickness_exit: float,
354 coverage_fraction: float = 1.0,
355) -> Tuple[float, float, Dict[str, float]]:
357 Update nozzle exit area due to ablative recession.
359 For graphite nozzle inserts, the exit area grows as material recedes.
360 This affects the expansion ratio: ε = A_exit / A_throat
364 A_exit_initial : float
365 Initial nozzle exit area [m²]
366 D_exit_initial : float
367 Initial nozzle exit diameter [m]
368 recession_thickness_exit : float
369 Total thickness of ablative material removed from nozzle exit [m]
370 coverage_fraction : float
371 Fraction of nozzle exit with ablative (default 1.0)
376 Updated nozzle exit area [m²]
378 Updated nozzle exit diameter [m]
380 Additional diagnostic information
382 if recession_thickness_exit <= 0
or coverage_fraction <= 0:
387 "recession_exit": 0.0,
388 "exit_area_change_pct": 0.0,
393 effective_recession_exit = recession_thickness_exit * coverage_fraction
397 D_exit_new = D_exit_initial + 2.0 * effective_recession_exit
398 R_exit_new = D_exit_new / 2.0
399 A_exit_new = np.pi * (R_exit_new ** 2)
402 exit_area_change_pct = (A_exit_new - A_exit_initial) / A_exit_initial * 100.0
405 "recession_exit": float(effective_recession_exit),
406 "exit_area_change_pct": float(exit_area_change_pct),
407 "D_exit_change": float(D_exit_new - D_exit_initial),
418 V_chamber_initial: float,
419 A_throat_initial: float,
420 recession_rate: float,
422 D_chamber_initial: float,
423 D_throat_initial: float,
425 coverage_fraction: float = 1.0,
426) -> Dict[str, float]:
428 Calculate how L* changes over time due to ablative recession.
432 V_chamber_initial : float
433 Initial chamber volume [m³]
434 A_throat_initial : float
435 Initial throat area [m²]
436 recession_rate : float
437 Ablative recession rate [m/s]
440 D_chamber_initial : float
441 Initial chamber diameter [m]
442 D_throat_initial : float
443 Initial throat diameter [m]
446 coverage_fraction : float
447 Fraction of surface with ablative
452 - Lstar_initial: Initial L* [m]
453 - Lstar_final: Final L* after burn_time [m]
454 - Lstar_change_pct: Percentage change in L*
455 - V_chamber_final: Final chamber volume [m³]
456 - A_throat_final: Final throat area [m²]
457 - total_recession: Total material removed [m]
460 if A_throat_initial > 0:
461 Lstar_initial = V_chamber_initial / A_throat_initial
466 total_recession = recession_rate * burn_time
480 if A_throat_final > 0:
481 Lstar_final = V_final / A_throat_final
483 Lstar_final = Lstar_initial
486 if Lstar_initial > 0:
487 Lstar_change_pct = (Lstar_final - Lstar_initial) / Lstar_initial * 100.0
489 Lstar_change_pct = 0.0
492 "Lstar_initial": float(Lstar_initial),
493 "Lstar_final": float(Lstar_final),
494 "Lstar_change_pct": float(Lstar_change_pct),
495 "V_chamber_initial": float(V_chamber_initial),
496 "V_chamber_final": float(V_final),
497 "A_throat_initial": float(A_throat_initial),
498 "A_throat_final": float(A_throat_final),
499 "D_chamber_initial": float(D_chamber_initial),
500 "D_chamber_final": float(D_chamber_final),
501 "D_throat_initial": float(D_throat_initial),
502 "D_throat_final": float(D_throat_final),
503 "total_recession": float(total_recession),
504 "recession_rate": float(recession_rate),
505 "burn_time": float(burn_time),
510 Lstar_initial: float,
512 efficiency_C: float = 0.3,
513 efficiency_K: float = 0.15,
514) -> Dict[str, float]:
516 Estimate combustion efficiency degradation due to L* change.
518 Uses the exponential efficiency model:
519 η_c* = 1 - C × exp(-K × L*)
523 Lstar_initial : float
528 Efficiency loss parameter (default 0.3)
530 Recovery rate parameter (default 0.15)
535 - eta_initial: Initial combustion efficiency
536 - eta_final: Final combustion efficiency
537 - eta_degradation_pct: Percentage drop in efficiency
538 - cstar_degradation_pct: Approximate c* degradation
540 eta_initial = 1.0 - efficiency_C * np.exp(-efficiency_K * Lstar_initial)
541 eta_final = 1.0 - efficiency_C * np.exp(-efficiency_K * Lstar_final)
543 eta_degradation_pct = (eta_final - eta_initial) / eta_initial * 100.0
546 cstar_degradation_pct = eta_degradation_pct
549 "eta_initial": float(eta_initial),
550 "eta_final": float(eta_final),
551 "eta_degradation_pct": float(eta_degradation_pct),
552 "cstar_degradation_pct": float(cstar_degradation_pct),
Tuple[float, float, float, float, Dict[str, float]] update_chamber_geometry_from_ablation(float V_chamber_initial, float A_throat_initial, float D_chamber_initial, float D_throat_initial, float L_chamber, float recession_thickness_chamber, Optional[float] recession_thickness_throat=None, float coverage_fraction=1.0, Optional[float] throat_recession_multiplier=None)
float calculate_local_recession_rate(float heat_flux, float pressure, float velocity, float gas_temperature, float material_density, float heat_of_ablation, float specific_heat, float pyrolysis_temp, float blowing_efficiency=0.8, float char_layer_conductivity=0.2, float char_layer_thickness=0.001)
Dict[str, float] calculate_Lstar_time_varying(float V_chamber_initial, float A_throat_initial, float recession_rate, float burn_time, float D_chamber_initial, float D_throat_initial, float L_chamber, float coverage_fraction=1.0)