1"""Run full pipeline and display all performance metrics"""
5from pathlib
import Path
7sys.path.insert(0, str(Path(__file__).parent.parent))
14print(
"FULL PIPELINE PERFORMANCE ANALYSIS")
18config_path = Path(__file__).parent.parent /
"configs" /
"default.yaml"
19config = load_config(str(config_path))
25P_tank_O = 400 * 6894.76
26P_tank_F = 300 * 6894.76
28print(f
"\nINPUT CONDITIONS:")
29print(f
" P_tank_O = {P_tank_O/6894.76:.0f} psi ({P_tank_O/1e6:.2f} MPa)")
30print(f
" P_tank_F = {P_tank_F/6894.76:.0f} psi ({P_tank_F/1e6:.2f} MPa)")
34print(
"SOLVING FOR CHAMBER PRESSURE AND CALCULATING PERFORMANCE...")
37results = runner.evaluate(P_tank_O, P_tank_F)
40diagnostics = results.get(
'diagnostics', {})
41if isinstance(diagnostics, list):
42 diagnostics = diagnostics[0]
if diagnostics
else {}
45print(
"CHAMBER PERFORMANCE")
49print(f
" Solved Pc = {Pc/6894.76:.1f} psi ({Pc/1e6:.3f} MPa)")
52mdot_O = results[
'mdot_O']
53mdot_F = results[
'mdot_F']
54mdot_total = mdot_O + mdot_F
57print(f
"\n Mass Flow Rates:")
58print(f
" Oxidizer: {mdot_O:.4f} kg/s")
59print(f
" Fuel: {mdot_F:.4f} kg/s")
60print(f
" Total: {mdot_total:.4f} kg/s")
61print(f
" Mixture Ratio (O/F): {MR:.3f}")
64cstar_actual = results[
'cstar_actual']
65eta_cstar = diagnostics.get(
'eta_cstar', np.nan)
67print(f
"\n Combustion Properties:")
68print(f
" c*_actual = {cstar_actual:.1f} m/s ({cstar_actual*3.28084:.0f} ft/s)")
69if not np.isnan(eta_cstar):
70 print(f
" η_c* (combustion efficiency) = {eta_cstar:.4f}")
73Tc = diagnostics.get(
'Tc', np.nan)
74gamma = diagnostics.get(
'gamma', np.nan)
75R = diagnostics.get(
'R', np.nan)
76M = diagnostics.get(
'M', np.nan)
79 print(f
" Chamber Temperature: {Tc:.1f} K ({Tc*9/5-459.67:.0f} °F)")
80if not np.isnan(gamma):
81 print(f
" Gamma: {gamma:.4f}")
83 print(f
" Gas Constant R: {R:.2f} J/(kg·K)")
85 print(f
" Molecular Weight: {M:.2f} kg/kmol ({M:.2f} lb/lbmol)")
87 print(
" Molecular Weight: unavailable from CEA cache")
92F_momentum = results.get(
'F_momentum', np.nan)
93F_pressure = results.get(
'F_pressure', np.nan)
94P_exit = results.get(
'P_exit', np.nan)
95v_exit = results.get(
'v_exit', np.nan)
97print(f
"\n Performance Metrics:")
98print(f
" Thrust: {F/1000:.3f} kN ({F:.1f} N)")
99if not np.isnan(F_momentum):
100 print(f
" Momentum component: {F_momentum/1000:.3f} kN")
101if not np.isnan(F_pressure):
102 print(f
" Pressure component: {F_pressure/1000:.3f} kN")
103print(f
" Specific Impulse: {Isp:.2f} s")
104if not np.isnan(v_exit):
105 print(f
" Exit Velocity: {v_exit:.1f} m/s")
106if not np.isnan(P_exit):
107 print(f
" Exit Pressure: {P_exit/6894.76:.2f} psi ({P_exit/1e6:.3f} MPa)")
110print(
"INJECTOR PERFORMANCE")
116delta_p_feed_O = delta_p_feed(mdot_O, config.fluids[
"oxidizer"].density,
117 config.feed_system[
"oxidizer"], P_tank_O)
120delta_p_feed_F_base = delta_p_feed(mdot_F, config.fluids[
"fuel"].density,
121 config.feed_system[
"fuel"], P_tank_F)
124if config.regen_cooling
is not None and config.regen_cooling.enabled:
126 mu_F = config.fluids[
"fuel"].viscosity
127 delta_p_regen = delta_p_regen_channels(
128 mdot_F, config.fluids[
"fuel"].density, mu_F, config.regen_cooling, P_tank_F
130 delta_p_feed_F = delta_p_feed_F_base + delta_p_regen
132 delta_p_feed_F = delta_p_feed_F_base
134P_inj_O = P_tank_O - delta_p_feed_O
135P_inj_F = P_tank_F - delta_p_feed_F
137delta_p_inj_O = P_inj_O - Pc
138delta_p_inj_F = P_inj_F - Pc
140print(f
"\n Pressure Drops:")
141print(f
" Feed System (LOX):")
142print(f
" P_tank = {P_tank_O/6894.76:.1f} psi")
143print(f
" Δp_feed = {delta_p_feed_O/6894.76:.2f} psi")
144print(f
" P_injector = {P_inj_O/6894.76:.1f} psi")
145print(f
" Δp_injector = {delta_p_inj_O/6894.76:.1f} psi")
146print(f
" Feed System (Fuel):")
147print(f
" P_tank = {P_tank_F/6894.76:.1f} psi")
148print(f
" Δp_feed_base = {delta_p_feed_F_base/6894.76:.2f} psi")
149if config.regen_cooling
is not None and config.regen_cooling.enabled:
150 print(f
" Δp_regen_cooling = {delta_p_regen/6894.76:.2f} psi")
151 print(f
" Δp_feed_total = {delta_p_feed_F/6894.76:.2f} psi")
152print(f
" P_injector = {P_inj_F/6894.76:.1f} psi")
153print(f
" Δp_injector = {delta_p_inj_F/6894.76:.1f} psi")
158A_LOX, A_fuel = get_effective_areas(config.injector.geometry)
159d_hyd_O, d_hyd_F = get_hydraulic_diameters(config.injector.geometry)
161print(f
"\n Injector Geometry:")
163print(f
" Number of orifices: {config.injector.geometry.lox.n_orifices}")
164print(f
" Orifice diameter: {config.injector.geometry.lox.d_orifice*1000:.2f} mm")
165print(f
" Total area: {A_LOX*1e6:.4f} mm²")
166print(f
" Hydraulic diameter: {d_hyd_O*1000:.2f} mm")
168print(f
" Pintle tip diameter: {config.injector.geometry.fuel.d_pintle_tip*1000:.2f} mm")
169print(f
" Gap height: {config.injector.geometry.fuel.h_gap*1000:.2f} mm")
170print(f
" Total area: {A_fuel*1e6:.4f} mm²")
171print(f
" Hydraulic diameter: {d_hyd_F*1000:.2f} mm")
174rho_O = config.fluids[
"oxidizer"].density
175rho_F = config.fluids[
"fuel"].density
177u_O = mdot_O / (rho_O * A_LOX)
178u_F = mdot_F / (rho_F * A_fuel)
180print(f
"\n Flow Velocities:")
181print(f
" LOX: {u_O:.2f} m/s")
182print(f
" Fuel: {u_F:.2f} m/s")
187mu_O = config.fluids[
"oxidizer"].viscosity
188mu_F = config.fluids[
"fuel"].viscosity
190Re_O = calculate_reynolds_number(rho_O, u_O, d_hyd_O, mu_O)
191Re_F = calculate_reynolds_number(rho_F, u_F, d_hyd_F, mu_F)
193Cd_O = cd_from_re(Re_O, config.discharge[
"oxidizer"])
194Cd_F = cd_from_re(Re_F, config.discharge[
"fuel"])
196print(f
"\n Discharge Coefficients:")
197print(f
" LOX: Cd = {Cd_O:.4f} (Re = {Re_O:.0f})")
198print(f
" Fuel: Cd = {Cd_F:.4f} (Re = {Re_F:.0f})")
201J = diagnostics.get(
'J', np.nan)
202TMR = diagnostics.get(
'TMR', np.nan)
203theta = diagnostics.get(
'theta', np.nan)
204We_O = diagnostics.get(
'We_O', np.nan)
205We_F = diagnostics.get(
'We_F', np.nan)
206D32_O = diagnostics.get(
'D32_O', np.nan)
207D32_F = diagnostics.get(
'D32_F', np.nan)
208x_star = diagnostics.get(
'x_star', np.nan)
211print(
"SPRAY DIAGNOSTICS")
215 print(f
" Momentum Flux Ratio (J): {J:.3f}")
217 print(f
" Thrust/Momentum Ratio (TMR): {TMR:.3f}")
218if not np.isnan(theta):
219 print(f
" Spray Angle (θ): {theta*180/np.pi:.1f}°")
220if not np.isnan(We_O):
221 print(f
" Weber Number (LOX): {We_O:.0f}")
222if not np.isnan(We_F):
223 print(f
" Weber Number (Fuel): {We_F:.0f}")
224if not np.isnan(D32_O):
225 print(f
" Sauter Mean Diameter (LOX): {D32_O*1e6:.2f} μm")
226if not np.isnan(D32_F):
227 print(f
" Sauter Mean Diameter (Fuel): {D32_F*1e6:.2f} μm")
228if not np.isnan(x_star):
229 print(f
" Evaporation Length (x*): {x_star*1000:.2f} mm")
231constraints_satisfied = diagnostics.get(
'constraints_satisfied',
False)
232print(f
" Spray Constraints Satisfied: {constraints_satisfied}")
235cooling = results.get(
"cooling", {})
238 print(
"COOLING SUMMARY")
241 regen = cooling.get(
"regen")
242 if regen
and regen.get(
"enabled",
False):
243 print(
" Regenerative Cooling:")
244 print(f
" Coolant outlet temperature: {regen['coolant_outlet_temperature']:.1f} K")
245 print(f
" Heat removed: {regen['heat_removed']/1000:.1f} kW")
246 print(f
" Hot-side heat flux: {regen['overall_heat_flux']/1000:.1f} kW/m²")
247 if 'mdot_coolant' in regen:
248 print(f
" Coolant flow through channels: {regen['mdot_coolant']:.3f} kg/s")
249 print(f
" Wall temperature (hot/cool): {regen['wall_temperature_hot']:.1f} K / {regen['wall_temperature_coolant']:.1f} K")
250 if regen.get(
'film_effectiveness', 0.0) > 0:
251 print(f
" Film effectiveness applied: {regen['film_effectiveness']:.2f}")
253 film = cooling.get(
"film")
254 if film
and film.get(
"enabled",
False):
255 print(
" Film Cooling:")
256 print(f
" Mass fraction: {film['mass_fraction']:.3f}")
257 print(f
" Effectiveness: {film['effectiveness']:.2f}")
258 print(f
" Film mass flow: {film['mdot_film']:.3f} kg/s")
259 print(f
" Heat-flux reduction factor: {film['heat_flux_factor']:.2f}")
261 ablative = cooling.get(
"ablative")
262 if ablative
and ablative.get(
"enabled",
False):
263 print(
" Ablative Cooling:")
264 print(f
" Recession rate: {ablative['recession_rate']*1e6:.3f} µm/s")
265 print(f
" Effective heat flux: {ablative['effective_heat_flux']/1000:.1f} kW/m²")
271print(
"FLIGHT SIMULATION")
275 rocket = setup_flight(config, F, mdot_O, mdot_F)
279 print(
"FLIGHT RESULTS")
281 print(f
" Apogee: {rocket.apogee:.2f} m")
282 print(f
" Max Velocity: {rocket.maxVelocity:.2f} m/s")
283 print(f
" Flight Time: {rocket.totalTime:.2f} s")
284 print(f
" Burn Time: {rocket.motor.burnOut:.2f} s")
285 print(f
" Launch Rail Exit Velocity: {rocket.outOfRailVelocity:.2f} m/s")
287except Exception
as e:
288 print(f
"\n[ERROR] Flight simulation failed: {e}")
289 print(
"Skipping flight simulation section.")
293print(
"COMPARISON TO TARGET (from engine specs)")
302print(f
" Target: {target_mdot:.3f} kg/s")
303print(f
" Actual: {mdot_total:.3f} kg/s")
304print(f
" Difference: {mdot_total - target_mdot:.3f} kg/s ({abs(mdot_total - target_mdot)/target_mdot*100:.1f}%)")
307print(f
" Target: {target_F:.3f} kN")
308print(f
" Actual: {F/1000:.3f} kN")
309print(f
" Difference: {F/1000 - target_F:.3f} kN ({abs(F/1000 - target_F)/target_F*100:.1f}%)")
311print(f
"\n Mixture Ratio:")
312print(f
" Target: {target_MR:.2f}")
313print(f
" Actual: {MR:.2f}")
314print(f
" Difference: {MR - target_MR:.2f} ({abs(MR - target_MR)/target_MR*100:.1f}%)")
316print(f
"\n Specific Impulse:")
317print(f
" Target: {target_Isp:.1f} s")
318print(f
" Actual: {Isp:.1f} s")
319print(f
" Difference: {Isp - target_Isp:.1f} s ({abs(Isp - target_Isp)/target_Isp*100:.1f}%)")
322print(
"[OK] FULL PIPELINE ANALYSIS COMPLETE")