STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
regen_cooling.py
Go to the documentation of this file.
1"""Regenerative cooling channel pressure drop model"""
2
3import numpy as np
4from typing import Optional, Dict, List
5from engine.pipeline.config_schemas import RegenCoolingConfig
7 DEFAULT_GAMMA_ND,
8 DEFAULT_GAS_CONST_J_KG_K,
9 DEFAULT_THROAT_AREA_M2,
10 DEFAULT_COOLANT_SPEC_HEAT_J_KG_K,
11 DEFAULT_COOLANT_THERMAL_COND_W_M_K,
12 DEFAULT_COOLANT_DENS_KG_M3,
13 DEFAULT_COOLANT_TEMP_K,
14 NU_LAMINAR_ND,
15 NU_TURBULENT_COEFFICIENT_ND,
16 NU_TURBULENT_RE_EXPONENT_ND,
17 NU_TURBULENT_PR_EXPONENT_ND,
18 K_ENTRANCE_SHARP_ND,
19 MIN_DENS_KG_M3,
20 EPSILON_TINY,
21 EPSILON_SMALL,
22 DEFAULT_RECOVERY_FACTOR_ND,
23)
24
25# Unit conversion constants for viscosity formula
26# Formula uses Rankine and lb/lb-mol, result in lb·s/in²
27# Import from constants to avoid duplication
28from engine.pipeline.constants import RANKINE_PER_KELVIN, LBM_PER_IN_S_TO_PA_S
29
30
31def _gas_radiation(gas_props: Dict[str, float], Tg: float, P: float, Tw: float, D: float,
32 eps_wall: float) -> float:
33 """Net gas-to-wall radiation of the chamber gas (Leckner gray gas, beam length 0.95 D).
34 Needs the CEA mole fractions x_H2O and x_CO2 in ``gas_props``."""
36 CYLINDER_BEAM_LENGTH_OVER_D, gas_absorptivity, gray_enclosure_flux, leckner_emissivity)
37 if "x_H2O" not in gas_props or "x_CO2" not in gas_props:
38 raise ValueError("gas radiation needs the CEA mole fractions x_H2O and x_CO2")
39 P_bar = P / 1e5
40 pH, pC = gas_props["x_H2O"] * P_bar, gas_props["x_CO2"] * P_bar
41 L = CYLINDER_BEAM_LENGTH_OVER_D * D
42 eps_g = float(leckner_emissivity(Tg, P_bar, pH, pC, L)["eps"])
43 alpha = float(gas_absorptivity(Tg, min(Tw, Tg), P_bar, pH, pC, L))
44 return float(gray_enclosure_flux(eps_g, alpha, eps_wall, Tg, Tw))
45
46
48 temperature: float,
49 molecular_weight: float,
50) -> float:
51 """
52 Calculate gas dynamic viscosity using Huzel's empirical correlation.
53
54 Formula: μ = (46.6 × 10^-10) × M^0.5 × T^0.6
55
56 Where:
57 - M = molecular weight [lb/lb-mol] (same as kg/kmol numerically)
58 - T = temperature [°R] (Rankine)
59 - Result: μ [lb·s/in²], converted to [Pa·s]
60
61 This correlation is specifically for combustion gases and accounts for:
62 - Temperature dependence (T^0.6)
63 - Molecular weight dependence (M^0.5)
64
65 Parameters
66 ----------
67 temperature : float
68 Gas temperature [K]
69 molecular_weight : float
70 Molecular weight [kg/kmol] (same as lb/lb-mol numerically)
71
72 Returns
73 -------
74 viscosity : float
75 Dynamic viscosity [Pa·s]
76
77 References
78 ----------
79 Huzel & Huang, "Design of Liquid Propellant Rocket Engines"
80 Equation (4-16) for combustion gas viscosity estimation
81 """
82 # Convert temperature from Kelvin to Rankine
83 T_rankine = temperature * RANKINE_PER_KELVIN
84
85 # Molecular weight: lb/lb-mol = kg/kmol (same numerically)
86 M_lb_lbmol = molecular_weight
87
88 # Calculate viscosity using Huzel's formula
89 # μ = (46.6 × 10^-10) × M^0.5 × T^0.6
90 # Result is in lbm/(in*s) (mass pounds -- see constants.LBM_PER_IN_S_TO_PA_S)
91 mu_lbm_in_s = 46.6e-10 * (M_lb_lbmol ** 0.5) * (T_rankine ** 0.6)
92
93 viscosity_pa_s = mu_lbm_in_s * LBM_PER_IN_S_TO_PA_S
94
95 return float(viscosity_pa_s)
96
97
98def calculate_channel_hydraulic_diameter(width: float, height: float) -> float:
99 """
100 Calculate hydraulic diameter for rectangular channel.
101
102 d_hyd = 4 × A / P_wetted
103 For rectangle: d_hyd = 2 × w × h / (w + h)
104
105 Parameters:
106 -----------
107 width : float
108 Channel width [m]
109 height : float
110 Channel height [m]
111
112 Returns:
113 --------
114 d_hyd : float
115 Hydraulic diameter [m]
116 """
117 if width <= 0 or height <= 0:
118 raise ValueError("Channel dimensions must be positive")
119
120 d_hyd = 2 * width * height / (width + height)
121 return float(d_hyd)
122
123
124def calculate_friction_factor(Re: float, d_hyd: float, roughness: float = 0.0) -> float:
125 """
126 Calculate Darcy-Weisbach friction factor.
127
128 For smooth pipes (roughness = 0): Blasius correlation
129 f = 0.316 / Re^0.25 (for Re < 10^5)
130
131 For rough pipes: Colebrook equation (iterative)
132 Or Swamee-Jain approximation
133
134 Parameters:
135 -----------
136 Re : float
137 Reynolds number
138 d_hyd : float
139 Hydraulic diameter [m]
140 roughness : float
141 Surface roughness [m] (default: 0 = smooth)
142
143 Returns:
144 --------
145 f : float
146 Friction factor
147 """
148 if Re <= 0:
149 return 1.0 # Avoid division by zero
150
151 if roughness == 0 or roughness / d_hyd < 1e-6:
152 # Smooth pipe: Blasius correlation
153 if Re < 1e5:
154 f = 0.316 / (Re ** 0.25)
155 else:
156 # For higher Re, use more accurate correlation
157 f = 0.184 / (Re ** 0.2)
158 else:
159 # Rough pipe: Swamee-Jain approximation
160 relative_roughness = roughness / d_hyd
161 f = 0.25 / (np.log10(relative_roughness / 3.7 + 5.74 / (Re ** 0.9))) ** 2
162
163 return float(f)
164
165
167 mdot: float,
168 rho: float,
169 mu: float,
170 config: RegenCoolingConfig,
171 P_tank: float
172) -> float:
173 """
174 Calculate pressure drop through regenerative cooling channels.
175
176 Flow path:
177 1. Inlet pipe (3/8" diameter)
178 2. Split into N parallel channels
179 3. N channels (each with friction)
180 4. Merge back
181 5. Pipe to injector
182
183 Pressure drop is a function of tank pressure:
184 - Higher tank pressure → higher mass flow → higher velocity → higher pressure drop
185 - This is already captured through mdot(P_tank), but we add explicit pressure scaling
186 - Channel length should match chamber length (cooling channels go across the length of the chamber)
187
188 Parameters:
189 -----------
190 mdot : float
191 Total mass flow rate [kg/s] (already depends on P_tank)
192 rho : float
193 Fluid density [kg/m³]
194 mu : float
195 Dynamic viscosity [Pa·s]
196 config : RegenCoolingConfig
197 Regenerative cooling configuration
198 P_tank : float
199 Tank pressure [Pa] - used for pressure-dependent scaling
200
201 Returns:
202 --------
203 delta_p : float
204 Total pressure drop [Pa]
205 """
206 # Note: Pressure dependence is already captured through mdot(P_tank)
207 # Higher tank pressure → higher mdot → higher velocity → higher pressure drop
208 # No additional scaling factor needed - the physics is already in the equations
209
210 # 1. Inlet pipe (3/8" = 9.525 mm)
211 d_inlet = config.d_inlet # m
212 A_inlet = np.pi * (d_inlet / 2) ** 2
213 u_inlet = mdot / (rho * A_inlet)
214 d_hyd_inlet = d_inlet
215 Re_inlet = (rho * u_inlet * d_hyd_inlet) / mu
216 f_inlet = calculate_friction_factor(Re_inlet, d_hyd_inlet, config.roughness)
217
218 # Pressure drop in inlet pipe
219 # Δp = f × (L/D) × (ρ/2) × u²
220 delta_p_inlet = f_inlet * (config.L_inlet / d_hyd_inlet) * (rho / 2) * u_inlet ** 2
221
222 # Add minor loss for inlet (entrance loss)
223 delta_p_inlet += K_ENTRANCE_SHARP_ND * (rho / 2) * u_inlet ** 2
224
225 # 2. Split loss (manifold)
226 # Loss coefficient for flow splitting
227 K_split = config.K_manifold_split
228 delta_p_split = K_split * (rho / 2) * u_inlet ** 2
229
230 # 3. N parallel channels
231 # Each channel gets mdot / N
232 mdot_channel = mdot / config.n_channels
233
234 # Channel geometry
236 config.channel_width,
237 config.channel_height
238 )
239 A_channel = config.channel_width * config.channel_height
240
241 # Channel entrance loss (discharge coefficient effect)
242 # Flow contracts entering small channel, creating entrance loss
243 # Cd varies with Reynolds number (flow contraction depends on Re)
244 # Calculate Re for entrance (use channel velocity estimate)
245 u_channel_estimate = mdot_channel / (rho * A_channel)
246 Re_channel_entrance = (rho * u_channel_estimate * d_hyd_channel) / mu
247
248 # Dynamic Cd for entrance: Cd(Re) = Cd_∞ - a_Re/√Re (same model as injector)
249 if Re_channel_entrance <= 0:
250 Cd_entrance_dynamic = config.Cd_entrance_min
251 else:
252 # FIXED: Ensure sqrt input is positive
253 Cd_entrance_dynamic = config.Cd_entrance_inf - config.a_Re_entrance / np.sqrt(max(Re_channel_entrance, 1e-6))
254 Cd_entrance_dynamic = np.clip(Cd_entrance_dynamic, config.Cd_entrance_min, config.Cd_entrance_inf)
255
256 # Effective area reduction: A_eff = Cd_entrance × A_channel
257 A_eff_entrance = Cd_entrance_dynamic * A_channel
258 u_channel_entrance = mdot_channel / (rho * A_eff_entrance)
259
260 # Entrance loss: Δp = (1/Cd² - 1) × (ρ/2) × u²
261 # This accounts for flow contraction at channel entrance
262 K_entrance_channel = (1.0 / (Cd_entrance_dynamic ** 2) - 1.0)
263 delta_p_entrance_channel = K_entrance_channel * (rho / 2) * u_channel_entrance ** 2
264
265 # Channel flow (after entrance)
266 u_channel = mdot_channel / (rho * A_channel)
267 Re_channel = (rho * u_channel * d_hyd_channel) / mu
268 f_channel = calculate_friction_factor(Re_channel, d_hyd_channel, config.roughness)
269
270 # Pressure drop in one channel (friction)
271 # Δp = f × (L/D) × (ρ/2) × u²
272 # Channel length should be the chamber length (cooling channels go across the length of the chamber)
273 delta_p_channel_friction = f_channel * (config.channel_length / d_hyd_channel) * (rho / 2) * u_channel ** 2
274
275 # Channel exit loss (discharge coefficient effect)
276 # Flow expands exiting channel, creating exit loss
277 # Cd varies with Reynolds number (flow expansion depends on Re)
278 # Re_channel is already calculated above
279
280 # Dynamic Cd for exit: Cd(Re) = Cd_∞ - a_Re/√Re (same model as injector)
281 if Re_channel <= 0:
282 Cd_exit_dynamic = config.Cd_exit_min
283 else:
284 # FIXED: Ensure sqrt input is positive
285 Cd_exit_dynamic = config.Cd_exit_inf - config.a_Re_exit / np.sqrt(max(Re_channel, 1e-6))
286 Cd_exit_dynamic = np.clip(Cd_exit_dynamic, config.Cd_exit_min, config.Cd_exit_inf)
287
288 K_exit_channel = (1.0 - Cd_exit_dynamic ** 2)
289 delta_p_exit_channel = K_exit_channel * (rho / 2) * u_channel ** 2
290
291 # Total channel pressure drop (entrance + friction + exit)
292 delta_p_channel = delta_p_entrance_channel + delta_p_channel_friction + delta_p_exit_channel
293
294 # All channels are parallel, so same pressure drop
295 # (flow splits equally if channels are identical)
296
297 # 4. Merge loss (manifold)
298 # Loss coefficient for flow merging
299 K_merge = config.K_manifold_merge
300 delta_p_merge = K_merge * (rho / 2) * u_channel ** 2
301
302 # 5. Pipe to injector (after merge)
303 # Use d_outlet if specified, otherwise same as inlet
304 d_outlet = config.d_outlet if config.d_outlet is not None else d_inlet
305 A_outlet = np.pi * (d_outlet / 2) ** 2
306 u_outlet = mdot / (rho * A_outlet)
307 d_hyd_outlet = d_outlet
308 Re_outlet = (rho * u_outlet * d_hyd_outlet) / mu
309 f_outlet = calculate_friction_factor(Re_outlet, d_hyd_outlet, config.roughness)
310
311 delta_p_outlet = f_outlet * (config.L_outlet / d_hyd_outlet) * (rho / 2) * u_outlet ** 2
312
313 # Total pressure drop
314 delta_p_total = (
315 delta_p_inlet +
316 delta_p_split +
317 delta_p_channel +
318 delta_p_merge +
319 delta_p_outlet
320 )
321
322 return float(delta_p_total)
323
324
326 mdot: float,
327 rho: float,
328 config: RegenCoolingConfig
329) -> dict:
330 """
331 Calculate velocity profile through regen cooling system.
332
333 Returns velocities at each section for diagnostics.
334
335 Parameters:
336 -----------
337 mdot : float
338 Total mass flow rate [kg/s]
339 rho : float
340 Fluid density [kg/m³]
341 config : RegenCoolingConfig
342 Regenerative cooling configuration
343
344 Returns:
345 --------
346 velocities : dict
347 Dictionary with velocities at each section [m/s]
348 """
349 d_inlet = config.d_inlet
350 A_inlet = np.pi * (d_inlet / 2) ** 2
351 u_inlet = mdot / (rho * A_inlet)
352
353 mdot_channel = mdot / config.n_channels
354 A_channel = config.channel_width * config.channel_height
355 u_channel = mdot_channel / (rho * A_channel)
356
357 d_outlet = config.d_outlet if config.d_outlet is not None else d_inlet
358 A_outlet = np.pi * (d_outlet / 2) ** 2
359 u_outlet = mdot / (rho * A_outlet)
360
361 return {
362 "u_inlet": float(u_inlet),
363 "u_channel": float(u_channel),
364 "u_outlet": float(u_outlet),
365 "mdot_channel": float(mdot_channel),
366 }
367
368
370 mdot_coolant: float,
371 coolant_props: Dict[str, float],
372 gas_props: Dict[str, float],
373 config: RegenCoolingConfig,
374 mdot_total: float,
375) -> Dict[str, float]:
376 """Calculate heat-transfer coupling for regenerative cooling channels."""
377
378 results = {
379 "enabled": config.use_heat_transfer,
380 "coolant_outlet_temperature": coolant_props.get("temperature", 0.0),
381 "heat_removed": 0.0,
382 "heat_flux_convective": 0.0,
383 "heat_flux_radiative": 0.0,
384 "overall_heat_flux": 0.0,
385 "h_hot": 0.0,
386 "h_coolant": 0.0,
387 "wall_temperature_hot": gas_props.get("Tc", 0.0),
388 "wall_temperature_coolant": coolant_props.get("temperature", 0.0),
389 "film_effectiveness": 0.0,
390 "effective_gas_temperature": gas_props.get("Tc", 0.0),
391 "coolant_bulk_temperature": coolant_props.get("temperature", 0.0),
392 "segment_wall_temperatures": [],
393 "segment_heat_flux": [],
394 }
395
396 if not config.use_heat_transfer or mdot_coolant <= 0:
397 return results
398
399 cp_c = max(coolant_props.get("cp", DEFAULT_COOLANT_SPEC_HEAT_J_KG_K), 1.0)
400 k_c = max(coolant_props.get("thermal_conductivity", DEFAULT_COOLANT_THERMAL_COND_W_M_K), EPSILON_SMALL)
401 mu_c = max(coolant_props.get("viscosity", 1e-4), EPSILON_TINY)
402 rho_c = max(coolant_props.get("density", DEFAULT_COOLANT_DENS_KG_M3), 1.0)
403 T_c_bulk = coolant_props.get("temperature", DEFAULT_COOLANT_TEMP_K)
404
405 channel_area = config.channel_width * config.channel_height
406 d_hyd_channel = calculate_channel_hydraulic_diameter(config.channel_width, config.channel_height)
407 mdot_channel = mdot_coolant / max(config.n_channels, 1)
408
409 Pc = gas_props.get("Pc", 0.0)
410 Tc = gas_props.get("Tc", 0.0)
411 gamma = gas_props.get("gamma", DEFAULT_GAMMA_ND)
412 R_g = gas_props.get("R", DEFAULT_GAS_CONST_J_KG_K)
413
414 chamber_d_inner = config.chamber_inner_diameter
415 if chamber_d_inner is None:
416 chamber_area = gas_props.get("chamber_area")
417 if chamber_area is not None and chamber_area > 0:
418 chamber_d_inner = np.sqrt(4.0 * chamber_area / np.pi)
419 else:
420 throat_area = gas_props.get("A_throat", DEFAULT_THROAT_AREA_M2)
421 chamber_d_inner = np.sqrt(4.0 * throat_area / np.pi)
422
423 # Use chamber_length from gas_props (comes from chamber.length in config)
424 # This is the actual physical chamber length, which should match channel_length
425 chamber_length = gas_props.get("chamber_length", config.channel_length)
426 # Fallback to config.channel_length if not in gas_props
427 if chamber_length <= 0:
428 chamber_length = config.channel_length
429 circumference = np.pi * chamber_d_inner
430 segment_count = max(config.n_segments, 1)
431 segment_length = chamber_length / segment_count
432 segment_area_hot = circumference * segment_length
433
434 A_cross = np.pi * (chamber_d_inner ** 2) / 4.0
435 rho_g = max(Pc / (R_g * max(Tc, 1.0)), MIN_DENS_KG_M3)
436 V_g = mdot_total / (rho_g * A_cross)
437
438 # Get viscosity from config (for reference)
439 mu_g_config = config.hot_gas_viscosity
440
441 # Calculate viscosity using Huzel's formula if molecular weight is available
442 M = gas_props.get("M") # Molecular weight [kg/kmol]
443 if M is not None and M > 0 and Tc > 0:
444 mu_g_calculated = calculate_gas_viscosity_huzel(Tc, M)
445 else:
446 mu_g_calculated = mu_g_config # Fallback to config if M not available
447
448 # Use calculated viscosity for calculations (more accurate)
449 mu_g = mu_g_calculated
450
451 k_g = config.hot_gas_thermal_conductivity
452 cp_g = gamma * R_g / max(gamma - 1.0, EPSILON_SMALL)
453 Pr_g = config.hot_gas_prandtl if config.hot_gas_prandtl > 0 else (mu_g * cp_g / max(k_g, EPSILON_SMALL))
454
455 Re_g = rho_g * V_g * chamber_d_inner / max(mu_g, EPSILON_TINY)
456 if Re_g < 2000:
457 Nu_g = NU_LAMINAR_ND
458 else:
459 Nu_g = NU_TURBULENT_COEFFICIENT_ND * (Re_g ** NU_TURBULENT_RE_EXPONENT_ND) * (Pr_g ** NU_TURBULENT_PR_EXPONENT_ND)
460 # CRITICAL FIX: Remove arbitrary 0.8 exponent - use linear scaling
461 turbulence_boost_g = 1.0 + config.gas_turbulence_intensity # Remove arbitrary 0.8 exponent
462 h_g_base = Nu_g * k_g / chamber_d_inner * turbulence_boost_g
463
464 # Calculate adiabatic wall temperature using recovery factor
465 # Taw = Tc × recovery_factor (accounts for kinetic energy recovery in boundary layer)
466 recovery_factor = config.recovery_factor if config.recovery_factor is not None else DEFAULT_RECOVERY_FACTOR_ND
467 Taw = Tc * recovery_factor
468
469 heat_removed_total = 0.0
470 heat_flux_conv_total = 0.0
471 heat_flux_rad_total = 0.0
472 wall_hot_segments: List[float] = []
473 wall_cold_segments: List[float] = []
474 segment_heat_fluxes: List[float] = []
475
476 for _ in range(segment_count):
477 u_channel = mdot_channel / (rho_c * channel_area)
478 Re_c = rho_c * u_channel * d_hyd_channel / max(mu_c, 1e-8)
479 Pr_c = mu_c * cp_c / max(k_c, 1e-4)
480
481 if Re_c <= 0:
482 Nu_c = 0.0
483 else:
484 f_c = (0.79 * np.log(Re_c) - 1.64) ** -2 if Re_c > 2300 else 64.0 / max(Re_c, 1.0)
485 Nu_c = (f_c / 8.0 * (Re_c - 1000.0) * Pr_c) / (1.0 + 12.7 * np.sqrt(f_c / 8.0) * (Pr_c ** (2.0 / 3.0) - 1.0))
486 if Nu_c <= 0:
487 Nu_c = NU_LAMINAR_ND
488 # CRITICAL FIX: Remove arbitrary 0.8 exponent - use linear scaling
489 turbulence_boost_c = 1.0 + config.coolant_turbulence_intensity # Remove arbitrary 0.8 exponent
490 h_c = Nu_c * k_c / d_hyd_channel * turbulence_boost_c
491
492 h_g = h_g_base
493 U_inv = (1.0 / max(h_g, EPSILON_SMALL)) + (config.wall_thickness / max(config.wall_thermal_conductivity, EPSILON_SMALL)) + (1.0 / max(h_c, EPSILON_SMALL))
494 U = 1.0 / U_inv
495 # Use adiabatic wall temperature (Taw) instead of chamber temperature (Tc)
496 # More accurate: q = h_g × (Taw - Tw) where Taw = Tc × recovery_factor
497 delta_T = max(Taw - T_c_bulk, 0.0)
498 heat_flux_conv = U * delta_T
499 # Gas radiation: H2O/CO2 gray gas (Leckner) onto the hot wall; radiation_emissivity_hot
500 # is the WALL's emissivity, not the gas's.
501 Tw_rad = Taw - heat_flux_conv / max(h_g, EPSILON_SMALL)
502 heat_flux_rad = config.radiation_view_factor * _gas_radiation(gas_props, Tc, Pc, Tw_rad,
503 chamber_d_inner,
504 config.radiation_emissivity_hot)
505 heat_flux_rad = max(heat_flux_rad, 0.0)
506 heat_flux_total = heat_flux_conv + heat_flux_rad
507
508 q_segment = heat_flux_total * segment_area_hot
509 heat_removed_total += q_segment
510 heat_flux_conv_total += heat_flux_conv * segment_area_hot
511 heat_flux_rad_total += heat_flux_rad * segment_area_hot
512
513 T_c_bulk += q_segment / max(mdot_coolant * cp_c, EPSILON_SMALL)
514
515 # Wall temperature calculated from adiabatic wall temperature
516 Tw_hot = Taw - heat_flux_conv / max(h_g, EPSILON_SMALL)
517 Tw_cold = Tw_hot - heat_flux_conv * config.wall_thickness / max(config.wall_thermal_conductivity, EPSILON_SMALL)
518
519 wall_hot_segments.append(Tw_hot)
520 wall_cold_segments.append(Tw_cold)
521 segment_heat_fluxes.append(heat_flux_total)
522
523 avg_heat_flux = heat_removed_total / (circumference * chamber_length) if chamber_length > 0 else 0.0
524
525 results.update(
526 {
527 "coolant_outlet_temperature": float(T_c_bulk),
528 "heat_removed": float(heat_removed_total),
529 "heat_flux_convective": float(heat_flux_conv_total / max(circumference * chamber_length, EPSILON_SMALL)),
530 "heat_flux_radiative": float(heat_flux_rad_total / max(circumference * chamber_length, EPSILON_SMALL)),
531 "overall_heat_flux": float(avg_heat_flux),
532 "h_hot": float(h_g_base),
533 "h_coolant": float(h_c),
534 "wall_temperature_hot": float(np.mean(wall_hot_segments) if wall_hot_segments else Taw),
535 "wall_temperature_coolant": float(np.mean(wall_cold_segments) if wall_cold_segments else T_c_bulk),
536 "gas_viscosity": float(mu_g), # Viscosity used in calculations (calculated from Huzel if available)
537 "gas_viscosity_config": float(mu_g_config), # Viscosity from config (for reference)
538 "gas_viscosity_calculated": float(mu_g_calculated), # Viscosity from Huzel formula (for reference)
539 "effective_gas_temperature": float(Tc),
540 "adiabatic_wall_temperature": float(Taw),
541 "coolant_bulk_temperature": float(T_c_bulk),
542 "segment_wall_temperatures": wall_hot_segments,
543 "segment_coolant_wall_temperatures": wall_cold_segments,
544 "segment_heat_flux": segment_heat_fluxes,
545 "segment_positions": [i * segment_length + segment_length / 2 for i in range(segment_count)],
546 }
547 )
548
549 return results
#define min(a, b)
Definition Arduino.h:42
#define max(a, b)
Definition Arduino.h:43
float calculate_gas_viscosity_huzel(float temperature, float molecular_weight)
Dict[str, float] compute_regen_heat_transfer(float mdot_coolant, Dict[str, float] coolant_props, Dict[str, float] gas_props, RegenCoolingConfig config, float mdot_total)
dict calculate_regen_velocity_profile(float mdot, float rho, RegenCoolingConfig config)
float calculate_friction_factor(float Re, float d_hyd, float roughness=0.0)
float _gas_radiation(Dict[str, float] gas_props, float Tg, float P, float Tw, float D, float eps_wall)
float calculate_channel_hydraulic_diameter(float width, float height)
float delta_p_regen_channels(float mdot, float rho, float mu, RegenCoolingConfig config, float P_tank)