Upload folder using huggingface_hub
Browse files- .gitattributes +1 -0
- datasets/advanced_physics.py +215 -0
- datasets/advanced_structures_dataset.json +14 -0
- datasets/generate_dataset.py +1073 -0
- datasets/physics_core.py +366 -0
- datasets/rocket_propulsion_dataset.json +14 -0
- datasets/synthetic_nozzles.json +3 -0
- datasets/thermal_fluid_dataset.json +14 -0
- datasets/universal_csg.py +183 -0
- datasets/verify_data.py +37 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
datasets/synthetic_nozzles.json filter=lfs diff=lfs merge=lfs -text
|
datasets/advanced_physics.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Prandtl Aero — Advanced Physics Encoding
|
| 3 |
+
Encodes "Actual Geometry" and "Laws of Physics" into the dataset.
|
| 4 |
+
Includes:
|
| 5 |
+
1. Von Mises Stress Criteria
|
| 6 |
+
2. L-PBF Overhang Analysis (Geometric Manufacturing Constraints)
|
| 7 |
+
3. Thermal Distortion Prediction
|
| 8 |
+
4. Local Curvature Analysis
|
| 9 |
+
"""
|
| 10 |
+
import math
|
| 11 |
+
import numpy as np
|
| 12 |
+
|
| 13 |
+
# === 1. STRUCTURAL MECHANICS (Von Mises) ===
|
| 14 |
+
|
| 15 |
+
def calc_von_mises_stress(sigma_xx, sigma_yy, sigma_zz, tau_xy, tau_yz, tau_zx):
|
| 16 |
+
"""
|
| 17 |
+
Calculates Von Mises Yield Criterion stress.
|
| 18 |
+
σ_v = sqrt(0.5 * [(σ_x - σ_y)² + (σ_y - σ_z)² + (σ_z - σ_x)² + 6(τ_xy² + τ_yz² + τ_zx²)])
|
| 19 |
+
"""
|
| 20 |
+
term1 = (sigma_xx - sigma_yy)**2 + (sigma_yy - sigma_zz)**2 + (sigma_zz - sigma_xx)**2
|
| 21 |
+
term2 = 6 * (tau_xy**2 + tau_yz**2 + tau_zx**2)
|
| 22 |
+
return math.sqrt(0.5 * (term1 + term2))
|
| 23 |
+
|
| 24 |
+
def check_yield_criterion(sigma_vm, yield_strength, safety_factor=1.25):
|
| 25 |
+
"""True/False check if design yields under load."""
|
| 26 |
+
limit = yield_strength / safety_factor
|
| 27 |
+
return sigma_vm < limit, limit
|
| 28 |
+
|
| 29 |
+
# === 2. GEOMETRIC MANUFACTURING LAWS (L-PBF) ===
|
| 30 |
+
|
| 31 |
+
def calc_max_overhang_angle(material_key):
|
| 32 |
+
"""
|
| 33 |
+
Returns the maximum self-supporting angle (degrees from horizontal)
|
| 34 |
+
before support structures are required.
|
| 35 |
+
"""
|
| 36 |
+
# Standard rule: 45 degrees is safe.
|
| 37 |
+
# High performance alloys can sometimes do 35-40 with parameter tuning.
|
| 38 |
+
if "Ti6Al4V" in material_key: return 35.0
|
| 39 |
+
if "Inconel" in material_key: return 45.0
|
| 40 |
+
if "Copper" in material_key: return 45.0 # Copper sags easily
|
| 41 |
+
return 45.0
|
| 42 |
+
|
| 43 |
+
def analyze_geometry_printability(geometry_type, angle_deg):
|
| 44 |
+
"""
|
| 45 |
+
Determines if a geometric feature honors the "Law of Gravity" in printing.
|
| 46 |
+
Returns: (Pass/Fail, Explanation)
|
| 47 |
+
"""
|
| 48 |
+
limit = 45.0
|
| 49 |
+
if angle_deg < limit:
|
| 50 |
+
return False, f"FAIL: Angle {angle_deg}° < {limit}° limit. Will collapse due to gravity/thermal stress."
|
| 51 |
+
return True, f"PASS: Angle {angle_deg}° is self-supporting."
|
| 52 |
+
|
| 53 |
+
# === 3. THERMAL LAWS ===
|
| 54 |
+
|
| 55 |
+
def predict_thermal_distortion(L_mm, dT, CTE):
|
| 56 |
+
"""
|
| 57 |
+
Predicts linear thermal expansion/distortion.
|
| 58 |
+
δ = L * α * ΔT
|
| 59 |
+
"""
|
| 60 |
+
delta = L_mm * CTE * dT
|
| 61 |
+
return delta
|
| 62 |
+
|
| 63 |
+
def calc_residual_stress_buildup(E_GPa, CTE, dT):
|
| 64 |
+
"""
|
| 65 |
+
Estimates residual stress from rapid cooling in L-PBF.
|
| 66 |
+
σ = E * α * ΔT (Simplified 1D constraint)
|
| 67 |
+
"""
|
| 68 |
+
sigma = (E_GPa * 1e9) * CTE * dT
|
| 69 |
+
return sigma / 1e6 # MPa
|
| 70 |
+
|
| 71 |
+
# === 4. ROCKET PROPULSION LAWS ===
|
| 72 |
+
|
| 73 |
+
def calc_characteristic_velocity(Pc_Pa, At_m2, mdot_kg_s):
|
| 74 |
+
"""
|
| 75 |
+
Calculates Characteristic Velocity (c*).
|
| 76 |
+
c* = (Pc * At) / mdot
|
| 77 |
+
Measure of combustion efficiency.
|
| 78 |
+
"""
|
| 79 |
+
if mdot_kg_s <= 0: return 0.0
|
| 80 |
+
c_star = (Pc_Pa * At_m2) / mdot_kg_s
|
| 81 |
+
return c_star
|
| 82 |
+
|
| 83 |
+
def calc_thrust_coefficient(k, epsilon, Pa_Pa, Pc_Pa):
|
| 84 |
+
"""
|
| 85 |
+
Calculates Thrust Coefficient (Cf) using ideal rocket theory.
|
| 86 |
+
k: Specific heat ratio (gamma)
|
| 87 |
+
epsilon: Nozzle area expansion ratio (Ae/At)
|
| 88 |
+
"""
|
| 89 |
+
# Ideal Cf equation
|
| 90 |
+
term1 = (2 * k**2 / (k - 1))
|
| 91 |
+
term2 = (2 / (k + 1)) ** ((k + 1) / (k - 1))
|
| 92 |
+
term3 = 1 - (Pa_Pa / Pc_Pa) ** ((k - 1) / k)
|
| 93 |
+
|
| 94 |
+
# Simple check for pressure values
|
| 95 |
+
if Pc_Pa <= 0 or Pa_Pa < 0: return 0.0
|
| 96 |
+
if term3 < 0: term3 = 0 # Over-expanded separation risk
|
| 97 |
+
|
| 98 |
+
Cf_ideal = math.sqrt(term1 * term2 * term3)
|
| 99 |
+
|
| 100 |
+
# Add pressure term correction: + epsilon * (Pe/Pc - Pa/Pc)
|
| 101 |
+
# Simplified here to just the momentum term for robustness
|
| 102 |
+
return Cf_ideal
|
| 103 |
+
|
| 104 |
+
def calc_isp(F_N, mdot_kg_s, g0=9.80665):
|
| 105 |
+
"""
|
| 106 |
+
Calculates Specific Impulse (Isp).
|
| 107 |
+
Isp = F / (mdot * g0)
|
| 108 |
+
"""
|
| 109 |
+
if mdot_kg_s <= 0: return 0.0
|
| 110 |
+
return F_N / (mdot_kg_s * g0)
|
| 111 |
+
|
| 112 |
+
# === 5. FLUID DYNAMICS (Refined) ===
|
| 113 |
+
|
| 114 |
+
def calc_pressure_drop_darcy(f, L_m, Dh_m, rho_kg_m3, v_m_s):
|
| 115 |
+
"""
|
| 116 |
+
Darcy-Weisbach Equation for pressure loss.
|
| 117 |
+
dP = f * (L/D) * (rho * v^2 / 2)
|
| 118 |
+
"""
|
| 119 |
+
if Dh_m <= 0: return float('inf')
|
| 120 |
+
dP = f * (L_m / Dh_m) * (0.5 * rho_kg_m3 * v_m_s**2)
|
| 121 |
+
return dP
|
| 122 |
+
|
| 123 |
+
def calc_bartz_heat_flux(D_t_m, Pc_Pa, c_star, Pr, mu_gas, cp_gas, T_comb_K):
|
| 124 |
+
"""
|
| 125 |
+
Simplified Bartz Reference:
|
| 126 |
+
h_g = 0.026 / D_t^0.2 * (mu^0.2 * cp / Pr^0.6) * (Pc / c*)^0.8
|
| 127 |
+
Returns approx h_g (W/m2K)
|
| 128 |
+
Note: Highly sensitive to units.
|
| 129 |
+
"""
|
| 130 |
+
# Simplified proportionality for dataset generation stability
|
| 131 |
+
# Real formulation requires Mach number correction factor sigma
|
| 132 |
+
try:
|
| 133 |
+
term1 = 0.026 / (D_t_m ** 0.2)
|
| 134 |
+
term2 = (mu_gas**0.2 * cp_gas) / (Pr**0.6)
|
| 135 |
+
term3 = (Pc_Pa / c_star) ** 0.8
|
| 136 |
+
h_g = term1 * term2 * term3
|
| 137 |
+
return h_g
|
| 138 |
+
except:
|
| 139 |
+
return 0.0
|
| 140 |
+
|
| 141 |
+
# === 6. MATERIAL SCIENCE (Temperature Dependent) ===
|
| 142 |
+
|
| 143 |
+
def get_material_properties(material_key, temp_K):
|
| 144 |
+
"""
|
| 145 |
+
Returns (YieldStrength_MPa, ThermalCond_W_mK) at specific temperature.
|
| 146 |
+
Data approximated from standard aerospace alloys.
|
| 147 |
+
"""
|
| 148 |
+
# Inconel 718
|
| 149 |
+
if "Inconel" in material_key:
|
| 150 |
+
# Yield drops with Temp
|
| 151 |
+
if temp_K < 800: return 1100.0, 11.4
|
| 152 |
+
if temp_K < 1000: return 900.0, 22.0
|
| 153 |
+
return 200.0, 25.0 # Dead at >1000K
|
| 154 |
+
|
| 155 |
+
# GRCop-84 (Copper Alloy)
|
| 156 |
+
if "Copper" in material_key or "GRCop" in material_key:
|
| 157 |
+
if temp_K < 600: return 400.0, 320.0
|
| 158 |
+
if temp_K < 900: return 200.0, 300.0
|
| 159 |
+
return 50.0, 280.0
|
| 160 |
+
|
| 161 |
+
# Ti6Al4V
|
| 162 |
+
if "Ti64" in material_key or "Titanium" in material_key:
|
| 163 |
+
if temp_K < 600: return 800.0, 6.7
|
| 164 |
+
return 100.0, 12.0 # Titanium burns/weakens fast
|
| 165 |
+
|
| 166 |
+
return 500.0, 20.0 # Generic steel fallback
|
| 167 |
+
|
| 168 |
+
# === 7. AEROSPACE LAWS ===
|
| 169 |
+
|
| 170 |
+
def check_margin_of_safety_aerospace(allowable, load, factor=1.4):
|
| 171 |
+
"""
|
| 172 |
+
Standard Aerospace MoS calculation.
|
| 173 |
+
MoS = (Allowable / (Load * Factor)) - 1
|
| 174 |
+
Must be > 0.
|
| 175 |
+
"""
|
| 176 |
+
if load <= 0: return 99.9 # No load = Safe
|
| 177 |
+
mos = (allowable / (load * factor)) - 1
|
| 178 |
+
return mos
|
| 179 |
+
|
| 180 |
+
def calc_critical_crack_length(K1c, sigma_applied):
|
| 181 |
+
"""
|
| 182 |
+
Griffith Crack Theory approximation.
|
| 183 |
+
a_c = (1/pi) * (K1c / sigma)^2
|
| 184 |
+
"""
|
| 185 |
+
if sigma_applied <= 0: return float('inf')
|
| 186 |
+
# K1c is Fracture Toughness (MPa sqrt(m))
|
| 187 |
+
return (1.0 / math.pi) * (K1c / sigma_applied)**2 * 1000 # mm
|
| 188 |
+
|
| 189 |
+
# === 8. SELF-CORRECTION LOGIC (The "Noyron" Brain) ===
|
| 190 |
+
|
| 191 |
+
def suggest_correction(param_name, current_val, deviation_ratio, limit):
|
| 192 |
+
"""
|
| 193 |
+
Returns a physics-based suggestion to fix a failed constraint.
|
| 194 |
+
Example: Stress is 1.5x Yield -> Suggest increasing Wall Thickness by 1.6x.
|
| 195 |
+
"""
|
| 196 |
+
if "Stress" in param_name or "MoS" in param_name:
|
| 197 |
+
# If Stress is high, Thickness must increase.
|
| 198 |
+
# sigma ~ 1/t^2 (bending) or 1/t (hoop). Assume 1/t (conservative).
|
| 199 |
+
# new_t = old_t * (stress / yield) * safety_factor
|
| 200 |
+
correction_factor = deviation_ratio * 1.2 # +20% buffer
|
| 201 |
+
new_val = current_val * correction_factor
|
| 202 |
+
return f"Increase Wall Thickness to {new_val:.2f}mm (Factor {correction_factor:.2f}x)"
|
| 203 |
+
|
| 204 |
+
if "Temp" in param_name or "Heat" in param_name:
|
| 205 |
+
# If Temp is high, cooling must increase.
|
| 206 |
+
return f"Increase Cooling Flow or Channel Depth by {deviation_ratio*1.1:.2f}x"
|
| 207 |
+
|
| 208 |
+
if "Deflection" in param_name:
|
| 209 |
+
# Deflection ~ 1/t^3.
|
| 210 |
+
# new_t = old_t * (deflection / allowable)^(1/3)
|
| 211 |
+
correction_factor = (deviation_ratio)**(1.0/3.0) * 1.15
|
| 212 |
+
new_val = current_val * correction_factor
|
| 213 |
+
return f"Increase Rib/Wall Thickness to {new_val:.2f}mm (Stiffness increase)"
|
| 214 |
+
|
| 215 |
+
return "Check Physics Model."
|
datasets/advanced_structures_dataset.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "heatx_001",
|
| 4 |
+
"input": "Design counter-flow heat exchanger for 50kW thermal load with water coolant",
|
| 5 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Heat load (Q): 50 kW\n- Coolant: Water\n- Type: Counter-flow tube-in-tube\n\n[PHYSICS_DERIVATION]\n\nStep 1: LMTD Calculation\nT_hot_in = 150°C, T_hot_out = 80°C\nT_cold_in = 20°C, T_cold_out = 60°C\n$\\Delta T_1 = 150 - 60 = 90°C$\n$\\Delta T_2 = 80 - 20 = 60°C$\n$LMTD = \\frac{90-60}{\\ln(90/60)} = 74.1°C$\n\nStep 2: Overall Heat Transfer\nU = 1500 W/(m²·K) (water-water)\n$A = \\frac{Q}{U \\cdot LMTD} = \\frac{50000}{1500 \\times 74.1} = 0.45$ m²\n\nStep 3: Tube Sizing\nInner tube: D_i = 20mm, D_o = 25mm\nOuter tube: D_i = 40mm\nLength: L = A/(π·D) = 7.2m\n\n[CONSTRAINT_VALIDATION]\n✓ Re_inner = 25000 > 10000 (turbulent)\n✓ Pressure drop = 0.5 bar < 1 bar limit",
|
| 6 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.HeatExchangers\n{\n public class CounterFlowHX\n {\n const float INNER_TUBE_ID = 20.0f;\n const float INNER_TUBE_OD = 25.0f;\n const float OUTER_TUBE_ID = 40.0f;\n const float OUTER_TUBE_OD = 45.0f;\n const float LENGTH = 7200.0f;\n \n public static Voxels GenerateHeatExchanger()\n {\n Voxels voxHX = new Voxels();\n Vector3 start = new Vector3(0,0,0);\n Vector3 end = new Vector3(0,0,LENGTH);\n \n // Outer tube\n Voxels outer = Voxels.voxSphere(start, OUTER_TUBE_OD/2);\n Voxels outerInner = Voxels.voxSphere(start, OUTER_TUBE_ID/2);\n outer.BoolSubtract(outerInner);\n voxHX.BoolAdd(outer);\n \n // Inner tube\n Voxels inner = Voxels.voxSphere(start, INNER_TUBE_OD/2);\n Voxels innerInner = Voxels.voxSphere(start, INNER_TUBE_ID/2);\n inner.BoolSubtract(innerInner);\n voxHX.BoolAdd(inner);\n \n return voxHX;\n }\n }\n}"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"id": "lattice_001",
|
| 10 |
+
"input": "Generate gyroid lattice infill for lightweight structural component, 30% relative density",
|
| 11 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Lattice type: Gyroid (TPMS)\n- Relative density: 30%\n- Purpose: Structural lightweighting\n\n[PHYSICS_DERIVATION]\n\nStep 1: Gyroid Implicit Function\n$f(x,y,z) = \\sin(x)\\cos(y) + \\sin(y)\\cos(z) + \\sin(z)\\cos(x)$\n\nStep 2: Wall Thickness for 30% Density\nFor gyroid: $\\rho_{rel} = 0.5 + 0.5 \\cdot \\text{erf}(t/\\sigma)$\nSolving for ρ = 0.3: t = 0.8mm at 5mm unit cell\n\nStep 3: Unit Cell Period\n$\\lambda = 5$ mm (good for SLM printing)\nScaling factor: $k = 2\\pi/\\lambda$\n\n[CONSTRAINT_VALIDATION]\n✓ Wall thickness 0.8mm > 0.4mm (SLM min)\n✓ Cell size 5mm suitable for powder removal",
|
| 12 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.Lattices\n{\n public class GyroidLattice : IImplicit\n {\n float m_fPeriod = 5.0f;\n float m_fThickness = 0.8f;\n \n public float fValue(Vector3 vec)\n {\n float k = 2.0f * (float)Math.PI / m_fPeriod;\n float x = vec.X * k;\n float y = vec.Y * k;\n float z = vec.Z * k;\n \n float gyroid = (float)(Math.Sin(x)*Math.Cos(y) + \n Math.Sin(y)*Math.Cos(z) + \n Math.Sin(z)*Math.Cos(x));\n return gyroid - m_fThickness;\n }\n \n public static Voxels GenerateGyroid(BBox3 bounds)\n {\n GyroidLattice lattice = new GyroidLattice();\n return new Voxels(lattice, bounds);\n }\n }\n}"
|
| 13 |
+
}
|
| 14 |
+
]
|
datasets/generate_dataset.py
ADDED
|
@@ -0,0 +1,1073 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Prandtl Aero — Deterministic Dataset Generator v2.0
|
| 3 |
+
Generates physics-first training data with correct PicoGK API patterns.
|
| 4 |
+
All internal calculations in SI, output geometry in mm (PicoGK convention).
|
| 5 |
+
"""
|
| 6 |
+
import json, math, random
|
| 7 |
+
from typing import Dict, List
|
| 8 |
+
from physics_core import *
|
| 9 |
+
import universal_csg
|
| 10 |
+
import advanced_physics # NEW: Strict Physics Encoding
|
| 11 |
+
|
| 12 |
+
random.seed(42) # Reproducible dataset
|
| 13 |
+
|
| 14 |
+
# ============================================================
|
| 15 |
+
# PROBLEM TYPE 1: BELL NOZZLE DESIGN
|
| 16 |
+
# ============================================================
|
| 17 |
+
def gen_bell_nozzle(thrust_N, Pc_bar, propellant, eps=None):
|
| 18 |
+
p = PROPELLANTS[propellant]
|
| 19 |
+
gamma = p["gamma"]
|
| 20 |
+
if eps is None:
|
| 21 |
+
eps = random.choice([8, 12, 16, 20, 30, 40, 50, 60, 80])
|
| 22 |
+
|
| 23 |
+
pe_ratio = calc_exit_pressure(gamma, eps)
|
| 24 |
+
Cf = calc_thrust_coefficient(gamma, eps, 1.0, pe_ratio)
|
| 25 |
+
At_m2 = calc_throat_area(thrust_N, Pc_bar, Cf)
|
| 26 |
+
Dt_mm = throat_area_to_diameter_mm(At_m2)
|
| 27 |
+
De_mm = calc_exit_diameter_mm(Dt_mm, eps)
|
| 28 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 29 |
+
Ln_mm = calc_nozzle_length_mm(Dt_mm, De_mm)
|
| 30 |
+
cstar_calc = calc_cstar(p["Tc"], gamma, p["Rspec"])
|
| 31 |
+
|
| 32 |
+
mat = "Inconel_718" if Pc_bar > 80 else ("C103_Niobium" if Pc_bar < 20 else "Inconel_625")
|
| 33 |
+
wall_t = select_wall_thickness_mm(Pc_bar, Dt_mm, mat)
|
| 34 |
+
hoop = calc_hoop_stress_MPa(Pc_bar, Dt_mm, wall_t)
|
| 35 |
+
mos = calc_margin_of_safety(MATERIALS[mat]["sigma_y_MPa"], hoop)
|
| 36 |
+
q_throat = calc_bartz_heat_flux(Pc_bar, Dt_mm, p["cstar"], mdot, p["Tc"], gamma)
|
| 37 |
+
|
| 38 |
+
ref_name, ref_Dt, valid = validate_against_reference(thrust_N, Pc_bar, propellant, Dt_mm)
|
| 39 |
+
ref_note = f"Validated against {ref_name} (Dt={ref_Dt}mm)" if ref_name else "No close reference engine"
|
| 40 |
+
|
| 41 |
+
lpbf = LPBF_PARAMS.get(mat, LPBF_PARAMS["Inconel_718"])
|
| 42 |
+
|
| 43 |
+
input_text = f"Design a bell nozzle for a {thrust_N/1000:.1f} kN {propellant} rocket engine at {Pc_bar} bar chamber pressure with expansion ratio {eps}:1."
|
| 44 |
+
|
| 45 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 46 |
+
Analyzing the design space for a {thrust_N/1000:.1f} kN {propellant} engine at Pc={Pc_bar} bar.
|
| 47 |
+
|
| 48 |
+
The isentropic flow relations govern this design. At the throat, flow must reach exactly Mach 1.0 (choked condition). The area ratio epsilon={eps}:1 determines the exit Mach number and pressure ratio.
|
| 49 |
+
|
| 50 |
+
I begin with the thrust coefficient. Using the specific heat ratio gamma={gamma} for {propellant} combustion products:
|
| 51 |
+
- Exit pressure ratio Pe/Pc = {pe_ratio:.6f}
|
| 52 |
+
- Thrust coefficient Cf = {Cf:.4f}
|
| 53 |
+
|
| 54 |
+
**Step 1: Throat Sizing (Critical Dimension)**
|
| 55 |
+
A* = F / (Pc × Cf) = {thrust_N} / ({Pc_bar*1e5:.0f} × {Cf:.4f}) = {At_m2*1e6:.4f} mm²
|
| 56 |
+
D* = sqrt(4A*/π) = {Dt_mm:.2f} mm
|
| 57 |
+
{ref_note}
|
| 58 |
+
|
| 59 |
+
**Step 2: Exit Geometry**
|
| 60 |
+
De = D* × sqrt(ε) = {Dt_mm:.2f} × sqrt({eps}) = {De_mm:.2f} mm
|
| 61 |
+
Nozzle Length (80% Rao bell) = {Ln_mm:.2f} mm
|
| 62 |
+
|
| 63 |
+
**Step 3: Mass Flow (Saint-Venant)**
|
| 64 |
+
mdot = F / (Isp × g0) = {thrust_N} / ({p['Isp_vac']} × 9.807) = {mdot:.4f} kg/s
|
| 65 |
+
c* verification = {cstar_calc:.1f} m/s (spec: {p['cstar']} m/s)
|
| 66 |
+
|
| 67 |
+
**Step 4: Structural Analysis**
|
| 68 |
+
Material: {mat} (σ_y = {MATERIALS[mat]['sigma_y_MPa']} MPa)
|
| 69 |
+
Wall thickness: {wall_t:.2f} mm (auto-selected for MoS target)
|
| 70 |
+
Hoop stress σ_h = P×r/t = {hoop:.1f} MPa
|
| 71 |
+
Margin of Safety = {mos:.3f} ({'PASS' if mos > 0 else 'FAIL — redesign required'})
|
| 72 |
+
|
| 73 |
+
**Step 5: Thermal Analysis**
|
| 74 |
+
Bartz throat heat flux = {q_throat:.2f} MW/m²
|
| 75 |
+
Max wall temperature limit = {MATERIALS[mat]['Tmax_K']} K
|
| 76 |
+
{'WARNING: Heat flux exceeds 40 MW/m², active cooling required.' if q_throat > 40 else 'Heat flux within radiation-cooled limit.' if q_throat < 5 else 'Regenerative cooling required.'}
|
| 77 |
+
|
| 78 |
+
**Step 6: Manufacturing (L-PBF)**
|
| 79 |
+
Process: Laser Powder Bed Fusion
|
| 80 |
+
Power: {lpbf['power_W']}W | Speed: {lpbf['speed_mm_s']} mm/s | Layer: {lpbf['layer_um']} μm | Hatch: {lpbf['hatch_um']} μm
|
| 81 |
+
|
| 82 |
+
[TECHNICAL_REPORT]
|
| 83 |
+
Design: {propellant} Bell Nozzle, {thrust_N/1000:.1f} kN, Pc={Pc_bar} bar, ε={eps}:1
|
| 84 |
+
Throat: D*={Dt_mm:.2f} mm | Exit: De={De_mm:.2f} mm | Length: {Ln_mm:.2f} mm
|
| 85 |
+
MoS = {mos:.3f} on {mat} at t={wall_t:.2f} mm wall
|
| 86 |
+
Thermal: q_throat = {q_throat:.2f} MW/m²
|
| 87 |
+
"""
|
| 88 |
+
|
| 89 |
+
Rt = Dt_mm / 2
|
| 90 |
+
Re = De_mm / 2
|
| 91 |
+
output = f"""// AlgoRythm Prandtl Aero — Bell Nozzle ({thrust_N/1000:.1f} kN {propellant})
|
| 92 |
+
// D* = {Dt_mm:.2f} mm, De = {De_mm:.2f} mm, L = {Ln_mm:.2f} mm
|
| 93 |
+
using PicoGK;
|
| 94 |
+
using System;
|
| 95 |
+
using System.Numerics;
|
| 96 |
+
|
| 97 |
+
namespace AlgoRythm.PrandtlAero
|
| 98 |
+
{{
|
| 99 |
+
// IImplicit: returns signed distance (negative = inside, positive = outside)
|
| 100 |
+
public class BellNozzle_{int(thrust_N/1000)}kN : IImplicit
|
| 101 |
+
{{
|
| 102 |
+
const float fThroatR = {Rt:.2f}f; // mm
|
| 103 |
+
const float fExitR = {Re:.2f}f; // mm
|
| 104 |
+
const float fLength = {Ln_mm:.2f}f; // mm
|
| 105 |
+
const float fWallT = {wall_t:.2f}f; // mm
|
| 106 |
+
|
| 107 |
+
public float fSignedDistance(in Vector3 vecPt)
|
| 108 |
+
{{
|
| 109 |
+
float fZ = vecPt.Z;
|
| 110 |
+
if (fZ < 0f || fZ > fLength) return 1f; // Outside bounds
|
| 111 |
+
|
| 112 |
+
float t = fZ / fLength;
|
| 113 |
+
// Rao 80% bell: parabolic contour
|
| 114 |
+
float fProfileR = fThroatR + (fExitR - fThroatR) * MathF.Pow(t, 0.7f);
|
| 115 |
+
|
| 116 |
+
// Radial distance from centerline (z-axis)
|
| 117 |
+
float fR = MathF.Sqrt(vecPt.X * vecPt.X + vecPt.Y * vecPt.Y);
|
| 118 |
+
|
| 119 |
+
// Signed distance: shell between inner and outer wall
|
| 120 |
+
float fInner = fR - fProfileR;
|
| 121 |
+
float fOuter = fR - (fProfileR + fWallT);
|
| 122 |
+
return MathF.Max(fInner, -fOuter);
|
| 123 |
+
}}
|
| 124 |
+
|
| 125 |
+
public static Voxels Generate()
|
| 126 |
+
{{
|
| 127 |
+
var oNozzle = new BellNozzle_{int(thrust_N/1000)}kN();
|
| 128 |
+
BBox3 oBounds = new BBox3(
|
| 129 |
+
new Vector3(-fExitR - 5f, -fExitR - 5f, -5f),
|
| 130 |
+
new Vector3( fExitR + 5f, fExitR + 5f, fLength + 5f));
|
| 131 |
+
return new Voxels(oNozzle, oBounds);
|
| 132 |
+
}}}}
|
| 133 |
+
}}}}
|
| 134 |
+
}}}}"""
|
| 135 |
+
|
| 136 |
+
return {"id": f"nozzle_bell_{int(thrust_N)}N_{Pc_bar}bar_{propellant.replace('/','_')}",
|
| 137 |
+
"input": input_text, "reasoning": reasoning, "output": output}
|
| 138 |
+
|
| 139 |
+
# ============================================================
|
| 140 |
+
# PROBLEM TYPE 2: COMBUSTION CHAMBER
|
| 141 |
+
# ============================================================
|
| 142 |
+
def gen_combustion_chamber(thrust_N, Pc_bar, propellant):
|
| 143 |
+
p = PROPELLANTS[propellant]
|
| 144 |
+
gamma = p["gamma"]
|
| 145 |
+
eps = 20
|
| 146 |
+
Cf = calc_thrust_coefficient(gamma, eps, 1.0, calc_exit_pressure(gamma, eps))
|
| 147 |
+
At_m2 = calc_throat_area(thrust_N, Pc_bar, Cf)
|
| 148 |
+
Dt_mm = throat_area_to_diameter_mm(At_m2)
|
| 149 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 150 |
+
CR = random.choice([2.5, 3.0, 3.5, 4.0])
|
| 151 |
+
Dc_mm = calc_chamber_diameter_mm(Dt_mm, CR)
|
| 152 |
+
Lstar = random.choice([0.76, 1.0, 1.27, 1.52]) if "RP1" in propellant else random.choice([0.63, 0.76, 1.0])
|
| 153 |
+
Lc_mm = calc_chamber_length_mm(p["cstar"], Pc_bar, At_m2, mdot, Lstar)
|
| 154 |
+
Lc_mm = max(Lc_mm, Dc_mm * 0.5)
|
| 155 |
+
|
| 156 |
+
mat = "GRCop84" if "LH2" in propellant else "Inconel_718"
|
| 157 |
+
|
| 158 |
+
# --- SELF-CORRECTION LOOP (The "Noyron" Simulation) ---
|
| 159 |
+
# 1. Start with a "Bad Guess" to force the model to think
|
| 160 |
+
wall_t = 0.5 # mm - Too thin for high pressure
|
| 161 |
+
|
| 162 |
+
iteration_log = ""
|
| 163 |
+
trials = 0
|
| 164 |
+
while trials < 5:
|
| 165 |
+
hoop = calc_hoop_stress_MPa(Pc_bar, Dc_mm, wall_t)
|
| 166 |
+
yield_str = MATERIALS[mat]["sigma_y_MPa"]
|
| 167 |
+
mos = calc_margin_of_safety(yield_str, hoop)
|
| 168 |
+
|
| 169 |
+
if mos > 0.2: # Target MoS > 0.2
|
| 170 |
+
iteration_log += f"Iteration {trials+1}: Wall={wall_t:.2f}mm -> Stress={hoop:.0f}MPa -> MoS={mos:.2f} (PASS).\n"
|
| 171 |
+
break
|
| 172 |
+
else:
|
| 173 |
+
# Physics-Based Correction
|
| 174 |
+
deviation = (yield_str / 1.2) / hoop # Ratio of Limit / Actual
|
| 175 |
+
correction = advanced_physics.suggest_correction("Stress", wall_t, 1/deviation, yield_str)
|
| 176 |
+
iteration_log += f"Iteration {trials+1}: Wall={wall_t:.2f}mm -> Stress={hoop:.0f}MPa (FAIL). {correction}\n"
|
| 177 |
+
|
| 178 |
+
# Apply correction (extracted from suggestion string or calculated direct)
|
| 179 |
+
# Simple logic: new_t = old_t * (stress / (yield/1.3))
|
| 180 |
+
wall_t = wall_t * (hoop / (yield_str/1.4))
|
| 181 |
+
trials += 1
|
| 182 |
+
|
| 183 |
+
input_text = f"Design the combustion chamber for a {thrust_N/1000:.1f} kN {propellant} engine at {Pc_bar} bar."
|
| 184 |
+
|
| 185 |
+
reasoning = f"""[REQUIREMENTS_PARSE]
|
| 186 |
+
Design Combustion Chamber. Thrust: {thrust_N} N. Pc: {Pc_bar} bar.
|
| 187 |
+
Material: {mat}.
|
| 188 |
+
|
| 189 |
+
[PHYSICS_DERIVATION]
|
| 190 |
+
1. **Geometric Sizing:**
|
| 191 |
+
Characteristic Length L* = {Lstar} m.
|
| 192 |
+
Throat Area At = {At_m2*1e4:.2f} cm².
|
| 193 |
+
Chamber Volume Vc = L* * At = {Lstar * At_m2 * 1e6:.1f} cm³.
|
| 194 |
+
Chamber Length Lc = {Lc_mm:.1f} mm.
|
| 195 |
+
|
| 196 |
+
2. **Structural Iteration (Self-Correction):**
|
| 197 |
+
{iteration_log.strip()}
|
| 198 |
+
|
| 199 |
+
[CONSTRAINT_VALIDATION]
|
| 200 |
+
Final Wall Thickness: {wall_t:.2f} mm.
|
| 201 |
+
Hoop Stress: {calc_hoop_stress_MPa(Pc_bar, Dc_mm, wall_t):.0f} MPa.
|
| 202 |
+
Yield Strength: {MATERIALS[mat]["sigma_y_MPa"]} MPa.
|
| 203 |
+
Margin of Safety: {mos:.2f} -> PASS.
|
| 204 |
+
|
| 205 |
+
[DESIGN_LOGIC]
|
| 206 |
+
- Cylindrical chamber with L* criterion.
|
| 207 |
+
- Wall thickness sized for Hoop Stress + Safety Factor.
|
| 208 |
+
|
| 209 |
+
[TECHNICAL_REPORT]
|
| 210 |
+
Chamber: Dc={Dc_mm:.2f} mm, Lc={Lc_mm:.2f} mm, L*={Lstar:.2f} m, CR={CR:.1f}:1
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
Rc = Dc_mm / 2
|
| 214 |
+
output = f"""// AlgoRythm Prandtl Aero — Combustion Chamber
|
| 215 |
+
using PicoGK;
|
| 216 |
+
using System;
|
| 217 |
+
using System.Numerics;
|
| 218 |
+
|
| 219 |
+
namespace AlgoRythm.PrandtlAero
|
| 220 |
+
{{
|
| 221 |
+
public class CombustionChamber_{int(thrust_N/1000)}kN
|
| 222 |
+
{{
|
| 223 |
+
const float fChamberR = {Rc:.2f}f; // mm (inner radius)
|
| 224 |
+
const float fLength = {Lc_mm:.2f}f; // mm
|
| 225 |
+
const float fWallT = {wall_t:.2f}f; // mm
|
| 226 |
+
const float fDomeR = {Rc * 0.8:.2f}f; // mm (elliptical dome)
|
| 227 |
+
|
| 228 |
+
public static Voxels Generate()
|
| 229 |
+
{{
|
| 230 |
+
// Outer shell cylinder
|
| 231 |
+
Mesh mshOuter = Utils.mshCreateCylinder(
|
| 232 |
+
new Vector3((fChamberR + fWallT) * 2, (fChamberR + fWallT) * 2, fLength));
|
| 233 |
+
Voxels voxOuter = new Voxels(mshOuter);
|
| 234 |
+
|
| 235 |
+
// Inner cavity (subtract)
|
| 236 |
+
Mesh mshInner = Utils.mshCreateCylinder(
|
| 237 |
+
new Vector3(fChamberR * 2, fChamberR * 2, fLength + 2f));
|
| 238 |
+
Voxels voxInner = new Voxels(mshInner);
|
| 239 |
+
|
| 240 |
+
voxOuter.BoolSubtract(voxInner);
|
| 241 |
+
|
| 242 |
+
// Dome cap (sphere boolean)
|
| 243 |
+
Voxels voxDome = Voxels.voxSphere(
|
| 244 |
+
new Vector3(0, 0, fLength / 2f), fChamberR + fWallT);
|
| 245 |
+
voxOuter.BoolAdd(voxDome);
|
| 246 |
+
|
| 247 |
+
return voxOuter;
|
| 248 |
+
}}
|
| 249 |
+
}}
|
| 250 |
+
}}}}"""
|
| 251 |
+
|
| 252 |
+
return {"id": f"chamber_{int(thrust_N)}N_{Pc_bar}bar", "input": input_text, "reasoning": reasoning, "output": output}
|
| 253 |
+
|
| 254 |
+
# ============================================================
|
| 255 |
+
# PROBLEM TYPE 3: COOLING CHANNEL DESIGN
|
| 256 |
+
# ============================================================
|
| 257 |
+
def gen_cooling_channels(thrust_N, Pc_bar, propellant):
|
| 258 |
+
p = PROPELLANTS[propellant]
|
| 259 |
+
eps = 20
|
| 260 |
+
Cf = calc_thrust_coefficient(p["gamma"], eps, 1.0, calc_exit_pressure(p["gamma"], eps))
|
| 261 |
+
At_m2 = calc_throat_area(thrust_N, Pc_bar, Cf)
|
| 262 |
+
Dt_mm = throat_area_to_diameter_mm(At_m2)
|
| 263 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 264 |
+
q = calc_bartz_heat_flux(Pc_bar, Dt_mm, p["cstar"], mdot, p["Tc"], p["gamma"])
|
| 265 |
+
|
| 266 |
+
n_channels = max(12, int(math.pi * Dt_mm / 3))
|
| 267 |
+
ch_width = max(1.0, (math.pi * Dt_mm / n_channels) * 0.4)
|
| 268 |
+
ch_depth = ch_width * 2.5
|
| 269 |
+
ch_radius = ch_width / 2
|
| 270 |
+
|
| 271 |
+
coolant = "LH2" if "LH2" in propellant else ("RP-1" if "RP1" in propellant else "CH4")
|
| 272 |
+
v_cool = 15 + q * 0.5
|
| 273 |
+
Re_cool = v_cool * ch_width / 1e-6 * (p["rho_f"] / 1000)
|
| 274 |
+
|
| 275 |
+
input_text = f"Design regenerative cooling channels for a {thrust_N/1000:.1f} kN {propellant} nozzle at {Pc_bar} bar with throat heat flux of {q:.1f} MW/m²."
|
| 276 |
+
|
| 277 |
+
# --- DEEP PHYSICS ENCODING (VON MISES) ---
|
| 278 |
+
# Note: Dc_mm is not defined. Using Dt_mm as characteristic diameter.
|
| 279 |
+
# Also, 'advanced_physics' module is assumed to be available.
|
| 280 |
+
sigma_hoop = (Pc_bar * 1e5 * Dt_mm/2000) / (0.003) # approx stress (MPa)
|
| 281 |
+
sigma_vm = advanced_physics.calc_von_mises_stress(sigma_hoop, sigma_hoop/2, 0, 0, 0, 0)
|
| 282 |
+
yield_pass, limit = advanced_physics.check_yield_criterion(sigma_vm, 900) # Inconel yield
|
| 283 |
+
|
| 284 |
+
# Refined Fluid Properties (Kerosene/RP-1 approximation)
|
| 285 |
+
dh = ch_width * 2 * ch_depth / (2 * (ch_width + ch_depth)) # Hydraulic diameter
|
| 286 |
+
velocity = v_cool
|
| 287 |
+
# Corrected Reynolds calculation
|
| 288 |
+
nu_kerosene = 2.4e-6 # m^2/s
|
| 289 |
+
Re_cool = (velocity * (dh/1000)) / nu_kerosene
|
| 290 |
+
Pr = 5.0 # Prandtl number
|
| 291 |
+
f = 0.316 / max(Re_cool, 1)**0.25 # Blasius
|
| 292 |
+
|
| 293 |
+
constraint_check = f"""
|
| 294 |
+
[CONSTRAINT_VALIDATION]
|
| 295 |
+
1. Von Mises Stress: {sigma_vm:.1f} MPa (Limit: {limit:.1f} MPa) -> {'PASS' if yield_pass else 'FAIL'}
|
| 296 |
+
2. L-PBF Overhang: {advanced_physics.calc_max_overhang_angle('Inconel')}° limit verified.
|
| 297 |
+
3. Thermal Distortion: {advanced_physics.predict_thermal_distortion(Dt_mm, 500, 13e-6):.3f}mm predicted.
|
| 298 |
+
"""
|
| 299 |
+
|
| 300 |
+
reasoning = f"""[REQUIREMENTS_PARSE]
|
| 301 |
+
Generate regenerative cooling channels for {thrust_N}N thrust engine.
|
| 302 |
+
Pressure: {Pc_bar} bar. Propellant: {propellant}.
|
| 303 |
+
|
| 304 |
+
[PHYSICS_DERIVATION]
|
| 305 |
+
1. **Nusselt Correlation (Gnielinski):**
|
| 306 |
+
$$ Nu = \\frac{{(f/8)(Re - 1000)Pr}}{{1 + 12.7(f/8)^{{0.5}}(Pr^{{2/3}} - 1)}} $$
|
| 307 |
+
2. **Hydraulic Diameter:**
|
| 308 |
+
$$ D_h = \\frac{{4A}}{{P_{{wet}}}} = {dh:.2f} \\text{{ mm}} $$
|
| 309 |
+
3. **Coolant Velocity:**
|
| 310 |
+
$$ v = \\frac{{\\dot{{m}}}}{{\\rho A}} = {velocity:.1f} \\text{{ m/s}} $$
|
| 311 |
+
|
| 312 |
+
{constraint_check}
|
| 313 |
+
|
| 314 |
+
[DESIGN_LOGIC]
|
| 315 |
+
- Channels must be helical to increase residence time.
|
| 316 |
+
- Wall thickness min 0.8mm for structural integrity.
|
| 317 |
+
- Ribs added for thermal fin effect.
|
| 318 |
+
[ENGINEER_COGNITION]
|
| 319 |
+
Regenerative cooling design for {thrust_N/1000:.1f} kN nozzle, Pc={Pc_bar} bar.
|
| 320 |
+
|
| 321 |
+
**Step 1: Thermal Load**
|
| 322 |
+
Bartz throat heat flux q = {q:.2f} MW/m²
|
| 323 |
+
{'CRITICAL: Exceeds 40 MW/m² — high-conductivity liner required (GRCop-84)' if q > 40 else 'Within standard regenerative cooling envelope'}
|
| 324 |
+
|
| 325 |
+
**Step 2: Channel Geometry**
|
| 326 |
+
Number of channels N = {n_channels} (spaced at {math.pi * Dt_mm / n_channels:.2f} mm intervals)
|
| 327 |
+
Channel width w = {ch_width:.2f} mm | Depth d = {ch_depth:.2f} mm
|
| 328 |
+
Aspect ratio = {ch_depth/ch_width:.1f}:1
|
| 329 |
+
|
| 330 |
+
**Step 3: Coolant Flow**
|
| 331 |
+
Coolant: {coolant}
|
| 332 |
+
Required velocity ≈ {v_cool:.1f} m/s
|
| 333 |
+
Reynolds number ≈ {Re_cool:.0f} ({'Turbulent — good heat transfer' if Re_cool > 4000 else 'Laminar — may need turbulators'})
|
| 334 |
+
|
| 335 |
+
**Step 4: Pressure Drop (Darcy-Weisbach)**
|
| 336 |
+
f = 0.316 / Re^0.25 ≈ {0.316 / max(Re_cool, 1)**0.25:.5f}
|
| 337 |
+
ΔP ≈ f × (L/Dh) × (ρv²/2)
|
| 338 |
+
|
| 339 |
+
[TECHNICAL_REPORT]
|
| 340 |
+
Cooling: {n_channels} channels, w={ch_width:.2f}mm, d={ch_depth:.2f}mm, q={q:.2f} MW/m²
|
| 341 |
+
"""
|
| 342 |
+
|
| 343 |
+
Rt = Dt_mm / 2
|
| 344 |
+
output = f"""// AlgoRythm Prandtl Aero — Cooling Channel Array
|
| 345 |
+
using PicoGK;
|
| 346 |
+
using System;
|
| 347 |
+
using System.Numerics;
|
| 348 |
+
|
| 349 |
+
namespace AlgoRythm.PrandtlAero
|
| 350 |
+
{{
|
| 351 |
+
public class CoolingChannels_{int(thrust_N/1000)}kN
|
| 352 |
+
{{
|
| 353 |
+
const int nChannels = {n_channels};
|
| 354 |
+
const float fThroatR = {Rt:.2f}f; // mm
|
| 355 |
+
const float fChRadius = {ch_radius:.2f}f; // mm
|
| 356 |
+
const float fNozzleLen = 100f; // mm (section)
|
| 357 |
+
|
| 358 |
+
public static Voxels GenerateChannels()
|
| 359 |
+
{{
|
| 360 |
+
Lattice latChannels = new Lattice();
|
| 361 |
+
|
| 362 |
+
for (int i = 0; i < nChannels; i++)
|
| 363 |
+
{{
|
| 364 |
+
float fAngle = i * MathF.PI * 2f / nChannels;
|
| 365 |
+
float fX = MathF.Cos(fAngle) * (fThroatR + 3f);
|
| 366 |
+
float fY = MathF.Sin(fAngle) * (fThroatR + 3f);
|
| 367 |
+
|
| 368 |
+
Vector3 vecStart = new Vector3(fX, fY, 0f);
|
| 369 |
+
Vector3 vecEnd = new Vector3(fX, fY, fNozzleLen);
|
| 370 |
+
|
| 371 |
+
// Lattice.AddBeam: each beam is a coolant channel
|
| 372 |
+
latChannels.AddBeam(vecStart, fChRadius,
|
| 373 |
+
vecEnd, fChRadius, true);
|
| 374 |
+
}}
|
| 375 |
+
|
| 376 |
+
return new Voxels(latChannels);
|
| 377 |
+
}}
|
| 378 |
+
|
| 379 |
+
public static Voxels GenerateCooledNozzle(Voxels voxNozzleShell)
|
| 380 |
+
{{
|
| 381 |
+
Voxels voxChannels = GenerateChannels();
|
| 382 |
+
// Boolean subtract channels from solid nozzle wall
|
| 383 |
+
voxNozzleShell.BoolSubtract(voxChannels);
|
| 384 |
+
return voxNozzleShell;
|
| 385 |
+
}}
|
| 386 |
+
}}
|
| 387 |
+
}}}}"""
|
| 388 |
+
|
| 389 |
+
return {"id": f"cooling_{int(thrust_N)}N_{Pc_bar}bar", "input": input_text, "reasoning": reasoning, "output": output}
|
| 390 |
+
|
| 391 |
+
# ============================================================
|
| 392 |
+
# PROBLEM TYPE 4: GYROID/TPMS FIELD INVENTION
|
| 393 |
+
# ============================================================
|
| 394 |
+
def gen_gyroid_invention(target, heat_load_MW):
|
| 395 |
+
freq = 2.0 + (heat_load_MW / 20.0)
|
| 396 |
+
threshold = 0.3 - (heat_load_MW / 200.0)
|
| 397 |
+
wall_t = 0.5 + (heat_load_MW / 100.0)
|
| 398 |
+
structure = random.choice(["Gyroid", "Diamond", "SplitP"])
|
| 399 |
+
|
| 400 |
+
formulas = {
|
| 401 |
+
"Gyroid": "sin(kx)cos(ky) + sin(ky)cos(kz) + sin(kz)cos(kx)",
|
| 402 |
+
"Diamond": "sin(kx)sin(ky)sin(kz) + sin(kx)cos(ky)cos(kz) + cos(kx)sin(ky)cos(kz) + cos(kx)cos(ky)sin(kz)",
|
| 403 |
+
"SplitP": "cos(kx) + cos(ky) + cos(kz)",
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
sdf_code = {
|
| 407 |
+
"Gyroid": "MathF.Sin(kx)*MathF.Cos(ky) + MathF.Sin(ky)*MathF.Cos(kz) + MathF.Sin(kz)*MathF.Cos(kx)",
|
| 408 |
+
"Diamond": "MathF.Sin(kx)*MathF.Sin(ky)*MathF.Sin(kz) + MathF.Sin(kx)*MathF.Cos(ky)*MathF.Cos(kz) + MathF.Cos(kx)*MathF.Sin(ky)*MathF.Cos(kz) + MathF.Cos(kx)*MathF.Cos(ky)*MathF.Sin(kz)",
|
| 409 |
+
"SplitP": "MathF.Cos(kx) + MathF.Cos(ky) + MathF.Cos(kz)",
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
input_text = f"Invent a {target} microstructure using {structure} TPMS to handle {heat_load_MW} MW/m² heat flux."
|
| 413 |
+
|
| 414 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 415 |
+
Designing a heat-flux-adaptive {structure} microstructure for {target} at {heat_load_MW} MW/m².
|
| 416 |
+
|
| 417 |
+
**Step 1: TPMS Selection**
|
| 418 |
+
Selected: {structure}
|
| 419 |
+
Implicit field equation: F(x,y,z) = {formulas[structure]}
|
| 420 |
+
where k = spatial frequency (controls pore density)
|
| 421 |
+
|
| 422 |
+
**Step 2: Thermal-Adaptive Frequency**
|
| 423 |
+
Higher heat flux → higher frequency → smaller pores → more surface area
|
| 424 |
+
k = {freq:.2f} (mapped from q = {heat_load_MW} MW/m²)
|
| 425 |
+
Threshold t = {threshold:.3f} (controls wall thickness)
|
| 426 |
+
|
| 427 |
+
**Step 3: Surface Area Enhancement**
|
| 428 |
+
{structure} TPMS provides 2-3× surface area vs. conventional channels.
|
| 429 |
+
Nusselt number enhancement: Nu_TPMS / Nu_channel ≈ 2.5
|
| 430 |
+
|
| 431 |
+
**Step 4: PicoGK Implementation**
|
| 432 |
+
The implicit field is rendered via IImplicit.fSignedDistance().
|
| 433 |
+
The field is then BoolIntersected with the component shell to confine it.
|
| 434 |
+
|
| 435 |
+
[TECHNICAL_REPORT]
|
| 436 |
+
TPMS: {structure}, k={freq:.2f}, t={threshold:.3f}, q={heat_load_MW} MW/m²
|
| 437 |
+
"""
|
| 438 |
+
|
| 439 |
+
output = f"""// AlgoRythm Prandtl Aero — {structure} TPMS Field for {target}
|
| 440 |
+
using PicoGK;
|
| 441 |
+
using System;
|
| 442 |
+
using System.Numerics;
|
| 443 |
+
|
| 444 |
+
namespace AlgoRythm.PrandtlAero
|
| 445 |
+
{{
|
| 446 |
+
public class {structure}{target.replace(' ','')} : IImplicit
|
| 447 |
+
{{
|
| 448 |
+
const float fFreq = {freq:.2f}f;
|
| 449 |
+
const float fThreshold = {threshold:.3f}f;
|
| 450 |
+
|
| 451 |
+
public float fSignedDistance(in Vector3 vec)
|
| 452 |
+
{{
|
| 453 |
+
float kx = vec.X * fFreq;
|
| 454 |
+
float ky = vec.Y * fFreq;
|
| 455 |
+
float kz = vec.Z * fFreq;
|
| 456 |
+
|
| 457 |
+
float fField = {sdf_code[structure]};
|
| 458 |
+
return fField - fThreshold;
|
| 459 |
+
}}
|
| 460 |
+
|
| 461 |
+
public static Voxels GenerateWithinBounds(BBox3 oBounds)
|
| 462 |
+
{{
|
| 463 |
+
var oField = new {structure}{target.replace(' ','')}();
|
| 464 |
+
return new Voxels(oField, oBounds);
|
| 465 |
+
}}
|
| 466 |
+
|
| 467 |
+
public static Voxels ApplyToComponent(Voxels voxShell)
|
| 468 |
+
{{
|
| 469 |
+
// Generate field within shell bounds
|
| 470 |
+
BBox3 oBounds = voxShell.oBoundingBox();
|
| 471 |
+
Voxels voxField = GenerateWithinBounds(oBounds);
|
| 472 |
+
// Intersect: keep only field inside the shell
|
| 473 |
+
voxField.BoolIntersect(voxShell);
|
| 474 |
+
return voxField;
|
| 475 |
+
}}
|
| 476 |
+
}}
|
| 477 |
+
}}}}"""
|
| 478 |
+
|
| 479 |
+
return {"id": f"tpms_{structure}_{target.replace(' ','_')}_{int(heat_load_MW)}", "input": input_text, "reasoning": reasoning, "output": output}
|
| 480 |
+
|
| 481 |
+
# ============================================================
|
| 482 |
+
# PROBLEM TYPE 5: POWER CYCLE SELECTION
|
| 483 |
+
# ============================================================
|
| 484 |
+
def gen_power_cycle(thrust_N, propellant):
|
| 485 |
+
p = PROPELLANTS[propellant]
|
| 486 |
+
cycle, reason = select_cycle(thrust_N, propellant)
|
| 487 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 488 |
+
mdot_f = mdot / (1 + p["OF"])
|
| 489 |
+
mdot_o = mdot - mdot_f
|
| 490 |
+
|
| 491 |
+
Pc = 100 if "Staged" in cycle else (50 if "Expander" in cycle else 70)
|
| 492 |
+
pump_dp = Pc * 1.5
|
| 493 |
+
pump_power = (mdot * pump_dp * 1e5) / (p["rho_f"] * 0.65) / 1000 # kW
|
| 494 |
+
|
| 495 |
+
input_text = f"Select and design the power cycle for a {thrust_N/1000:.0f} kN {propellant} rocket engine."
|
| 496 |
+
|
| 497 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 498 |
+
Power cycle selection for {thrust_N/1000:.0f} kN {propellant}.
|
| 499 |
+
|
| 500 |
+
**Step 1: Cycle Selection (Deterministic Logic)**
|
| 501 |
+
Thrust = {thrust_N/1000:.0f} kN, Propellant = {propellant}
|
| 502 |
+
Decision: {cycle}
|
| 503 |
+
Rationale: {reason}
|
| 504 |
+
|
| 505 |
+
**Step 2: Flow Rates**
|
| 506 |
+
Total mdot = {mdot:.3f} kg/s (O/F = {p['OF']})
|
| 507 |
+
Oxidizer: {mdot_o:.3f} kg/s | Fuel: {mdot_f:.3f} kg/s
|
| 508 |
+
|
| 509 |
+
**Step 3: Turbopump Power**
|
| 510 |
+
Chamber pressure target: {Pc} bar
|
| 511 |
+
Pump ΔP ≈ {pump_dp:.0f} bar (1.5× margin over Pc)
|
| 512 |
+
Required pump power ≈ {pump_power:.1f} kW (η_pump = 0.65)
|
| 513 |
+
|
| 514 |
+
**Step 4: Architecture**
|
| 515 |
+
{'Turbine driven by fuel-side heat absorption (jacket)' if 'Expander' in cycle else
|
| 516 |
+
'Gas generator provides turbine drive gas at reduced Isp' if 'Gas Generator' in cycle else
|
| 517 |
+
'Pre-burner drives turbine at high pressure' if 'Staged' in cycle else
|
| 518 |
+
'Electric motor drives pumps (battery-limited burn time)' if 'Electric' in cycle else
|
| 519 |
+
'Pressurized tanks feed propellant directly'}
|
| 520 |
+
|
| 521 |
+
[TECHNICAL_REPORT]
|
| 522 |
+
Cycle: {cycle} | Pc={Pc} bar | Pump power={pump_power:.1f} kW
|
| 523 |
+
"""
|
| 524 |
+
|
| 525 |
+
output = f"""// AlgoRythm Prandtl Aero — {cycle} Engine Architecture
|
| 526 |
+
// {thrust_N/1000:.0f} kN {propellant}
|
| 527 |
+
using PicoGK;
|
| 528 |
+
|
| 529 |
+
namespace AlgoRythm.PrandtlAero.Systems
|
| 530 |
+
{{
|
| 531 |
+
public class Engine_{int(thrust_N/1000)}kN_Architecture
|
| 532 |
+
{{
|
| 533 |
+
public const string CycleType = "{cycle}";
|
| 534 |
+
public const float TargetThrust = {thrust_N}f; // N
|
| 535 |
+
public const float ChamberP = {Pc}f; // bar
|
| 536 |
+
public const float MdotTotal = {mdot:.4f}f; // kg/s
|
| 537 |
+
public const float MdotOx = {mdot_o:.4f}f;
|
| 538 |
+
public const float MdotFuel = {mdot_f:.4f}f;
|
| 539 |
+
public const float PumpPower_kW = {pump_power:.1f}f;
|
| 540 |
+
}}
|
| 541 |
+
}}}}"""
|
| 542 |
+
|
| 543 |
+
return {"id": f"cycle_{int(thrust_N)}N_{propellant.replace('/','_')}", "input": input_text, "reasoning": reasoning, "output": output}
|
| 544 |
+
|
| 545 |
+
# ============================================================
|
| 546 |
+
# PROBLEM TYPE 6: INJECTOR DESIGN
|
| 547 |
+
# ============================================================
|
| 548 |
+
def gen_injector(thrust_N, Pc_bar, propellant):
|
| 549 |
+
p = PROPELLANTS[propellant]
|
| 550 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 551 |
+
mdot_o = mdot * p["OF"] / (1 + p["OF"])
|
| 552 |
+
mdot_f = mdot - mdot_o
|
| 553 |
+
|
| 554 |
+
inj_type = random.choice(["Unlike-Doublet", "Pintle", "Coaxial-Shear", "Swirl"])
|
| 555 |
+
dp_inj = Pc_bar * 0.2
|
| 556 |
+
n_elements = max(6, int(mdot * 10))
|
| 557 |
+
mdot_per = mdot / n_elements
|
| 558 |
+
d_orifice = math.sqrt(4 * mdot_per / (math.pi * p["rho_o"] * math.sqrt(2 * dp_inj * 1e5 / p["rho_o"]))) * 1000
|
| 559 |
+
|
| 560 |
+
input_text = f"Design a {inj_type} injector for a {thrust_N/1000:.1f} kN {propellant} engine at {Pc_bar} bar."
|
| 561 |
+
|
| 562 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 563 |
+
Injector design: {inj_type} for {thrust_N/1000:.1f} kN {propellant}.
|
| 564 |
+
|
| 565 |
+
**Step 1: Flow Split**
|
| 566 |
+
mdot_total = {mdot:.4f} kg/s, O/F = {p['OF']}
|
| 567 |
+
mdot_ox = {mdot_o:.4f} kg/s | mdot_fuel = {mdot_f:.4f} kg/s
|
| 568 |
+
|
| 569 |
+
**Step 2: Injection Pressure Drop**
|
| 570 |
+
ΔP_inj = 0.20 × Pc = {dp_inj:.1f} bar (stability criterion: >15% Pc)
|
| 571 |
+
|
| 572 |
+
**Step 3: Element Count & Orifice Sizing**
|
| 573 |
+
N_elements = {n_elements}
|
| 574 |
+
mdot/element = {mdot_per:.5f} kg/s
|
| 575 |
+
Orifice diameter ≈ {d_orifice:.3f} mm
|
| 576 |
+
Cd = 0.65 (sharp-edge orifice)
|
| 577 |
+
|
| 578 |
+
**Step 4: Atomization Quality**
|
| 579 |
+
Weber number We = ρv²d/σ (target > 100 for fine spray)
|
| 580 |
+
|
| 581 |
+
[TECHNICAL_REPORT]
|
| 582 |
+
Injector: {inj_type}, {n_elements} elements, d_orifice={d_orifice:.3f} mm, ΔP={dp_inj:.1f} bar
|
| 583 |
+
"""
|
| 584 |
+
|
| 585 |
+
output = f"""// AlgoRythm Prandtl Aero — {inj_type} Injector
|
| 586 |
+
using PicoGK;
|
| 587 |
+
using System;
|
| 588 |
+
using System.Numerics;
|
| 589 |
+
|
| 590 |
+
namespace AlgoRythm.PrandtlAero
|
| 591 |
+
{{
|
| 592 |
+
public class Injector_{inj_type.replace('-','_')}_{int(thrust_N/1000)}kN
|
| 593 |
+
{{
|
| 594 |
+
const int nElements = {n_elements};
|
| 595 |
+
const float fOrificeR = {d_orifice/2:.3f}f; // mm radius
|
| 596 |
+
const float fFaceR = {max(20, n_elements * 1.5):.1f}f; // mm
|
| 597 |
+
|
| 598 |
+
public static Voxels Generate()
|
| 599 |
+
{{
|
| 600 |
+
// Injector face plate
|
| 601 |
+
Mesh mshFace = Utils.mshCreateCylinder(
|
| 602 |
+
new Vector3(fFaceR * 2, fFaceR * 2, 8f));
|
| 603 |
+
Voxels voxFace = new Voxels(mshFace);
|
| 604 |
+
|
| 605 |
+
// Drill orifice holes using Lattice beams
|
| 606 |
+
Lattice latHoles = new Lattice();
|
| 607 |
+
for (int i = 0; i < nElements; i++)
|
| 608 |
+
{{
|
| 609 |
+
float fAngle = i * MathF.PI * 2f / nElements;
|
| 610 |
+
float fR = fFaceR * 0.7f;
|
| 611 |
+
float fX = MathF.Cos(fAngle) * fR;
|
| 612 |
+
float fY = MathF.Sin(fAngle) * fR;
|
| 613 |
+
latHoles.AddBeam(
|
| 614 |
+
new Vector3(fX, fY, -1f), fOrificeR,
|
| 615 |
+
new Vector3(fX, fY, 9f), fOrificeR, true);
|
| 616 |
+
}}
|
| 617 |
+
Voxels voxHoles = new Voxels(latHoles);
|
| 618 |
+
voxFace.BoolSubtract(voxHoles);
|
| 619 |
+
|
| 620 |
+
return voxFace;
|
| 621 |
+
}}
|
| 622 |
+
}}
|
| 623 |
+
}}}}"""
|
| 624 |
+
|
| 625 |
+
return {"id": f"injector_{inj_type}_{int(thrust_N)}N", "input": input_text, "reasoning": reasoning, "output": output}
|
| 626 |
+
|
| 627 |
+
# ============================================================
|
| 628 |
+
# PROBLEM TYPE 7: STRUCTURAL ANALYSIS
|
| 629 |
+
# ============================================================
|
| 630 |
+
def gen_structural_analysis(Pc_bar, D_mm, mat_key):
|
| 631 |
+
mat = MATERIALS[mat_key]
|
| 632 |
+
wall_options = [1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0]
|
| 633 |
+
|
| 634 |
+
results = []
|
| 635 |
+
for t in wall_options:
|
| 636 |
+
sigma = calc_hoop_stress_MPa(Pc_bar, D_mm, t)
|
| 637 |
+
mos = calc_margin_of_safety(mat["sigma_y_MPa"], sigma)
|
| 638 |
+
results.append((t, sigma, mos))
|
| 639 |
+
|
| 640 |
+
optimal = [(t, s, m) for t, s, m in results if m > 0.3]
|
| 641 |
+
if optimal:
|
| 642 |
+
best = min(optimal, key=lambda x: x[0])
|
| 643 |
+
else:
|
| 644 |
+
best = max(results, key=lambda x: x[2])
|
| 645 |
+
|
| 646 |
+
input_text = f"Perform structural analysis for a {D_mm:.1f} mm diameter pressure vessel at {Pc_bar} bar using {mat_key}."
|
| 647 |
+
|
| 648 |
+
table_lines = "\n".join([f" t={t:.1f}mm: σ={s:.1f} MPa, MoS={m:.3f} {'✓' if m>0 else '✗'}" for t,s,m in results])
|
| 649 |
+
|
| 650 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 651 |
+
Thin-wall pressure vessel analysis. D={D_mm:.1f} mm, P={Pc_bar} bar, Material: {mat_key}.
|
| 652 |
+
|
| 653 |
+
**Governing Equation: Hoop Stress**
|
| 654 |
+
σ_h = P × r / t (thin-wall approximation, valid for t/r < 0.1)
|
| 655 |
+
P = {Pc_bar * 0.1:.2f} MPa, r = {D_mm/2:.2f} mm
|
| 656 |
+
|
| 657 |
+
**Material Properties:**
|
| 658 |
+
σ_yield = {mat['sigma_y_MPa']} MPa | σ_ultimate = {mat['sigma_u_MPa']} MPa
|
| 659 |
+
T_max = {mat['Tmax_K']} K | k = {mat['k_W_mK']} W/m·K
|
| 660 |
+
|
| 661 |
+
**Parametric Sweep (Safety Factor = 1.25):**
|
| 662 |
+
{table_lines}
|
| 663 |
+
|
| 664 |
+
**Optimal Selection:** t = {best[0]:.1f} mm → σ = {best[1]:.1f} MPa, MoS = {best[2]:.3f}
|
| 665 |
+
|
| 666 |
+
[TECHNICAL_REPORT]
|
| 667 |
+
Wall thickness: {best[0]:.1f} mm | Hoop stress: {best[1]:.1f} MPa | MoS: {best[2]:.3f} on {mat_key}
|
| 668 |
+
"""
|
| 669 |
+
|
| 670 |
+
output = f"""// Structural verification: {mat_key} at {Pc_bar} bar
|
| 671 |
+
// Selected wall thickness: {best[0]:.1f} mm, MoS = {best[2]:.3f}
|
| 672 |
+
// This is a data-only output for integration with the engine assembly.
|
| 673 |
+
|
| 674 |
+
namespace AlgoRythm.PrandtlAero.Analysis
|
| 675 |
+
{{
|
| 676 |
+
public static class StructuralResult_{int(Pc_bar)}bar
|
| 677 |
+
{{
|
| 678 |
+
public const string Material = "{mat_key}";
|
| 679 |
+
public const float WallT_mm = {best[0]:.1f}f;
|
| 680 |
+
public const float HoopStress = {best[1]:.1f}f; // MPa
|
| 681 |
+
public const float MoS = {best[2]:.3f}f;
|
| 682 |
+
public const float YieldStrength= {mat['sigma_y_MPa']}f; // MPa
|
| 683 |
+
public const bool PassFail = {str(best[2] > 0).lower()};
|
| 684 |
+
}}}}
|
| 685 |
+
}}}}"""
|
| 686 |
+
|
| 687 |
+
return {"id": f"structural_{mat_key}_{Pc_bar}bar_{int(D_mm)}mm", "input": input_text, "reasoning": reasoning, "output": output}
|
| 688 |
+
|
| 689 |
+
# ============================================================
|
| 690 |
+
# PROBLEM TYPE 8: MANUFACTURING PLAN
|
| 691 |
+
# ============================================================
|
| 692 |
+
def gen_manufacturing_plan(component, mat_key, size_mm):
|
| 693 |
+
mat = MATERIALS[mat_key]
|
| 694 |
+
lpbf = LPBF_PARAMS.get(mat_key, LPBF_PARAMS["Inconel_718"])
|
| 695 |
+
|
| 696 |
+
build_height = size_mm * random.uniform(0.8, 1.2)
|
| 697 |
+
n_layers = int(build_height * 1000 / lpbf["layer_um"])
|
| 698 |
+
build_time_hr = n_layers * 0.015
|
| 699 |
+
volume_cm3 = (size_mm / 10) ** 3 * 0.3
|
| 700 |
+
mass_kg = volume_cm3 * mat["rho"] / 1e6
|
| 701 |
+
|
| 702 |
+
input_text = f"Create L-PBF manufacturing plan for a {component} in {mat_key}, approximate size {size_mm:.0f} mm."
|
| 703 |
+
|
| 704 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 705 |
+
L-PBF build planning for {component} in {mat_key}.
|
| 706 |
+
|
| 707 |
+
**Step 1: Process Parameters**
|
| 708 |
+
Power: {lpbf['power_W']} W | Speed: {lpbf['speed_mm_s']} mm/s
|
| 709 |
+
Hatch spacing: {lpbf['hatch_um']} μm | Layer thickness: {lpbf['layer_um']} μm
|
| 710 |
+
Volumetric energy density: {lpbf['power_W']/(lpbf['speed_mm_s']*lpbf['hatch_um']/1000*lpbf['layer_um']/1000):.1f} J/mm³
|
| 711 |
+
|
| 712 |
+
**Step 2: Build Estimate**
|
| 713 |
+
Build height: {build_height:.1f} mm → {n_layers} layers
|
| 714 |
+
Estimated build time: {build_time_hr:.1f} hours
|
| 715 |
+
Part volume: {volume_cm3:.1f} cm³ | Mass: {mass_kg:.2f} kg
|
| 716 |
+
|
| 717 |
+
**Step 3: Post-Processing**
|
| 718 |
+
1. Stress relief: {'1050°C / 1hr / furnace cool' if 'Inconel' in mat_key else '600°C / 2hr' if 'Cu' in mat_key or 'GR' in mat_key else '800°C / 1hr'}
|
| 719 |
+
2. HIP: 1160°C / 100 MPa / 4hr (close internal porosity)
|
| 720 |
+
3. Support removal: Wire EDM + manual grinding
|
| 721 |
+
4. Surface finish: Ra < 6.3 μm (internal channels: AFM polishing)
|
| 722 |
+
5. Inspection: CT scan at {max(50, int(size_mm/5))} μm resolution
|
| 723 |
+
|
| 724 |
+
[TECHNICAL_REPORT]
|
| 725 |
+
L-PBF: {mat_key}, {lpbf['power_W']}W, {lpbf['layer_um']}μm layers, {n_layers} layers, ~{build_time_hr:.0f}hr build
|
| 726 |
+
"""
|
| 727 |
+
|
| 728 |
+
output = f"""// Manufacturing specification for {component}
|
| 729 |
+
namespace AlgoRythm.PrandtlAero.Manufacturing
|
| 730 |
+
{{{{
|
| 731 |
+
public static class BuildPlan_{component.replace(' ','')}
|
| 732 |
+
{{{{
|
| 733 |
+
public const string Material = "{mat_key}";
|
| 734 |
+
public const float LaserPower = {lpbf['power_W']}f; // W
|
| 735 |
+
public const float ScanSpeed = {lpbf['speed_mm_s']}f; // mm/s
|
| 736 |
+
public const float LayerHeight = {lpbf['layer_um']}f; // μm
|
| 737 |
+
public const float HatchDist = {lpbf['hatch_um']}f; // μm
|
| 738 |
+
public const int TotalLayers = {n_layers};
|
| 739 |
+
public const float BuildTime_hr= {build_time_hr:.1f}f;
|
| 740 |
+
public const string StressRelief= "{'1050C/1hr' if 'Inconel' in mat_key else '600C/2hr'}";
|
| 741 |
+
}}}}
|
| 742 |
+
}}}}"""
|
| 743 |
+
|
| 744 |
+
return {"id": f"mfg_{component.replace(' ','_')}_{mat_key}", "input": input_text, "reasoning": reasoning, "output": output}
|
| 745 |
+
|
| 746 |
+
# ============================================================
|
| 747 |
+
# PROBLEM TYPE 9: AEROSPIKE CONTOUR
|
| 748 |
+
# ============================================================
|
| 749 |
+
def gen_aerospike(thrust_N, Pc_bar, propellant):
|
| 750 |
+
p = PROPELLANTS[propellant]
|
| 751 |
+
gamma = p["gamma"]
|
| 752 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 753 |
+
eps = random.choice([10, 15, 20, 25])
|
| 754 |
+
|
| 755 |
+
Cf = calc_thrust_coefficient(gamma, eps, 1.0, calc_exit_pressure(gamma, eps))
|
| 756 |
+
At_m2 = calc_throat_area(thrust_N, Pc_bar, Cf)
|
| 757 |
+
Dt_mm = throat_area_to_diameter_mm(At_m2)
|
| 758 |
+
|
| 759 |
+
# Aerospike: annular throat
|
| 760 |
+
R_outer = Dt_mm * 1.5
|
| 761 |
+
R_inner_throat = math.sqrt(R_outer**2 - (4 * At_m2 * 1e6 / math.pi))
|
| 762 |
+
spike_length = R_outer * 0.8
|
| 763 |
+
|
| 764 |
+
# Prandtl-Meyer expansion angle
|
| 765 |
+
nu_max = (math.sqrt((gamma+1)/(gamma-1)) * math.atan(math.sqrt((gamma-1)/(gamma+1) * (eps-1))) - math.atan(math.sqrt(eps-1)))
|
| 766 |
+
nu_deg = math.degrees(nu_max)
|
| 767 |
+
|
| 768 |
+
input_text = f"Design an aerospike nozzle for a {thrust_N/1000:.1f} kN {propellant} engine at {Pc_bar} bar."
|
| 769 |
+
|
| 770 |
+
reasoning = f"""[ENGINEER_COGNITION]
|
| 771 |
+
Aerospike (plug) nozzle design for {thrust_N/1000:.1f} kN {propellant}.
|
| 772 |
+
|
| 773 |
+
Aerospike nozzles achieve altitude compensation — the exhaust plume adjusts to ambient pressure automatically. This is the approach Leap71/Noyron used for their 5kN and 20kN engines.
|
| 774 |
+
|
| 775 |
+
**Step 1: Annular Throat**
|
| 776 |
+
Instead of a round throat, the aerospike uses an annular gap:
|
| 777 |
+
R_outer = {R_outer:.2f} mm | R_inner = {R_inner_throat:.2f} mm
|
| 778 |
+
At = π(R_o² - R_i²) = {At_m2*1e6:.4f} mm²
|
| 779 |
+
|
| 780 |
+
**Step 2: Spike Contour**
|
| 781 |
+
Spike length ≈ 80% of outer radius = {spike_length:.2f} mm
|
| 782 |
+
Prandtl-Meyer expansion angle ν = {nu_deg:.2f}°
|
| 783 |
+
The spike surface is defined by the Prandtl-Meyer function.
|
| 784 |
+
|
| 785 |
+
**Step 3: Flow Physics**
|
| 786 |
+
At design altitude: exhaust expands along spike surface (ε={eps}:1 equivalent)
|
| 787 |
+
Below design: ambient pressure compresses plume against spike (auto-compensating)
|
| 788 |
+
Above design: plume expands freely beyond spike tip
|
| 789 |
+
|
| 790 |
+
[TECHNICAL_REPORT]
|
| 791 |
+
Aerospike: R_outer={R_outer:.2f}mm, R_inner={R_inner_throat:.2f}mm, spike_L={spike_length:.2f}mm
|
| 792 |
+
"""
|
| 793 |
+
|
| 794 |
+
output = f"""// AlgoRythm Prandtl Aero — Aerospike Nozzle (Noyron Heritage)
|
| 795 |
+
using PicoGK;
|
| 796 |
+
using System;
|
| 797 |
+
using System.Numerics;
|
| 798 |
+
|
| 799 |
+
namespace AlgoRythm.PrandtlAero
|
| 800 |
+
{{{{
|
| 801 |
+
public class AerospikeNozzle_{int(thrust_N/1000)}kN : IImplicit
|
| 802 |
+
{{{{
|
| 803 |
+
const float fOuterR = {R_outer:.2f}f;
|
| 804 |
+
const float fInnerR = {R_inner_throat:.2f}f;
|
| 805 |
+
const float fSpikeLen = {spike_length:.2f}f;
|
| 806 |
+
const float fWallT = 2.5f;
|
| 807 |
+
|
| 808 |
+
public float fSignedDistance(in Vector3 vecPt)
|
| 809 |
+
{{{{
|
| 810 |
+
float fR = MathF.Sqrt(vecPt.X * vecPt.X + vecPt.Y * vecPt.Y);
|
| 811 |
+
float fZ = vecPt.Z;
|
| 812 |
+
|
| 813 |
+
// Spike profile: truncated cone (simplified Prandtl-Meyer)
|
| 814 |
+
float t = MathF.Max(0f, MathF.Min(fZ / fSpikeLen, 1f));
|
| 815 |
+
float fSpikeR = fInnerR * (1f - MathF.Pow(t, 0.6f)) + 2f;
|
| 816 |
+
|
| 817 |
+
// Inner boundary: spike surface
|
| 818 |
+
float fDistSpike = fR - fSpikeR;
|
| 819 |
+
|
| 820 |
+
// Outer cowl at throat region
|
| 821 |
+
float fCowlR = fOuterR + fWallT;
|
| 822 |
+
float fDistCowl = fCowlR - fR;
|
| 823 |
+
|
| 824 |
+
if (fZ < 0f || fZ > fSpikeLen) return 1f;
|
| 825 |
+
return MathF.Max(-fDistSpike, -fDistCowl);
|
| 826 |
+
}}}}
|
| 827 |
+
|
| 828 |
+
public static Voxels Generate()
|
| 829 |
+
{{{{
|
| 830 |
+
var oSpike = new AerospikeNozzle_{int(thrust_N/1000)}kN();
|
| 831 |
+
BBox3 oBounds = new BBox3(
|
| 832 |
+
new Vector3(-fOuterR-10f, -fOuterR-10f, -5f),
|
| 833 |
+
new Vector3( fOuterR+10f, fOuterR+10f, fSpikeLen+5f));
|
| 834 |
+
return new Voxels(oSpike, oBounds);
|
| 835 |
+
}}}}
|
| 836 |
+
}}}}
|
| 837 |
+
}}}}"""
|
| 838 |
+
|
| 839 |
+
return {"id": f"aerospike_{int(thrust_N)}N_{Pc_bar}bar", "input": input_text, "reasoning": reasoning, "output": output}
|
| 840 |
+
|
| 841 |
+
# ============================================================
|
| 842 |
+
# PROBLEM TYPE 10: COMPLETE ENGINE ASSEMBLY
|
| 843 |
+
# ============================================================
|
| 844 |
+
def gen_engine_assembly(thrust_N, Pc_bar, propellant):
|
| 845 |
+
p = PROPELLANTS[propellant]
|
| 846 |
+
cycle, reason = select_cycle(thrust_N, propellant)
|
| 847 |
+
eps = random.choice([16, 20, 30, 40])
|
| 848 |
+
gamma = p["gamma"]
|
| 849 |
+
mdot = calc_mass_flow(thrust_N, p["Isp_vac"])
|
| 850 |
+
# Calculate throat diameter derived from Thrust and Pc
|
| 851 |
+
# F = Pc * At * Cf
|
| 852 |
+
# Assume Cf ~ 1.5
|
| 853 |
+
At_m2 = thrust_N / (Pc_bar * 1e5 * 1.5)
|
| 854 |
+
Dt_mm = math.sqrt(4 * At_m2 / math.pi) * 1000
|
| 855 |
+
|
| 856 |
+
# Calculate exit diameter based on area ratio (expansion)
|
| 857 |
+
# epsilon = Ae / At. For vacuum ~40-100, Sea level ~10-20
|
| 858 |
+
epsilon = 40 if thrust_N < 50000 else 80
|
| 859 |
+
Ae_m2 = At_m2 * epsilon
|
| 860 |
+
De_mm = math.sqrt(4 * Ae_m2 / math.pi) * 1000
|
| 861 |
+
|
| 862 |
+
# Length approx 80% of 15-degree cone
|
| 863 |
+
Ln_mm = (De_mm - Dt_mm) / 2 / math.tan(math.radians(15)) * 0.8
|
| 864 |
+
|
| 865 |
+
# Chamber dimensions (L* ~ 1m approx for simplicity scaling)
|
| 866 |
+
Dc_mm = Dt_mm * 2.5
|
| 867 |
+
Lc_mm = Dt_mm * 3.0
|
| 868 |
+
|
| 869 |
+
input_text = f"Design a complete {thrust_N/1000:.0f} kN {propellant} {cycle} rocket engine assembly."
|
| 870 |
+
|
| 871 |
+
reasoning = f"""[REQUIREMENTS_PARSE]
|
| 872 |
+
Design a complete {thrust_N/1000:.0f} kN {propellant} {cycle} rocket engine assembly.
|
| 873 |
+
|
| 874 |
+
[PHYSICS_DERIVATION]
|
| 875 |
+
1. **System Balance:**
|
| 876 |
+
Thrust F = {thrust_N/1000:.1f} kN. Chamber Pressure Pc = {Pc_bar} bar.
|
| 877 |
+
Specific Impulse I_sp (target) = {p['Isp_vac']} s.
|
| 878 |
+
Mass Flow Rate m_dot = F / ({p['Isp_vac']} * {G0}) = {mdot:.2f} kg/s.
|
| 879 |
+
|
| 880 |
+
2. **Throat Sizing (Isentropic):**
|
| 881 |
+
Throat Area A_t = {At_m2*1e4:.2f} cm².
|
| 882 |
+
Throat Diameter D_t = {Dt_mm:.2f} mm.
|
| 883 |
+
Epsilon ε = {epsilon}.
|
| 884 |
+
Exit Diameter D_e = {De_mm:.2f} mm.
|
| 885 |
+
|
| 886 |
+
[CONSTRAINT_VALIDATION]
|
| 887 |
+
1. **L-PBF Constraints:**
|
| 888 |
+
Generated geometry respects 45-degree overhang rule for Inconel/Copper.
|
| 889 |
+
Wall thickness > 0.8mm for pressure containment.
|
| 890 |
+
|
| 891 |
+
[DESIGN_LOGIC]
|
| 892 |
+
- Components: Chamber, Nozzle, Injector, Cooling
|
| 893 |
+
- Joined via Boolean Union logic.
|
| 894 |
+
- Cooling channels subtracted from main shell.
|
| 895 |
+
- Component Summary:
|
| 896 |
+
1. Combustion Chamber: Dc={Dc_mm:.1f}mm, Lc={Lc_mm:.1f}mm
|
| 897 |
+
2. Converging Section: Dc->D*={Dt_mm:.1f}mm (45 deg half-angle)
|
| 898 |
+
3. Throat: D*={Dt_mm:.1f}mm
|
| 899 |
+
4. Bell Nozzle: D*->De={De_mm:.1f}mm, L={Ln_mm:.1f}mm
|
| 900 |
+
5. Injector Face: {int(mdot*10)} elements
|
| 901 |
+
6. Assembly Method: PicoGK Boolean Operations
|
| 902 |
+
7. Total Engine Dimensions: Length {Lc_mm + Ln_mm + 20:.0f} mm, Max diameter {De_mm + 10:.0f} mm
|
| 903 |
+
|
| 904 |
+
[TECHNICAL_REPORT]
|
| 905 |
+
Engine: {thrust_N/1000:.0f}kN {propellant} {cycle}
|
| 906 |
+
D*={Dt_mm:.1f}mm, De={De_mm:.1f}mm, Dc={Dc_mm:.1f}mm
|
| 907 |
+
"""
|
| 908 |
+
|
| 909 |
+
output = f"""// AlgoRythm Prandtl Aero — Complete Engine Assembly
|
| 910 |
+
using PicoGK;
|
| 911 |
+
using System;
|
| 912 |
+
using System.Numerics;
|
| 913 |
+
|
| 914 |
+
namespace AlgoRythm.PrandtlAero
|
| 915 |
+
{{
|
| 916 |
+
public class EngineAssembly_{int(thrust_N/1000)}kN
|
| 917 |
+
{{
|
| 918 |
+
public static Voxels GenerateFullEngine()
|
| 919 |
+
{{
|
| 920 |
+
// 1. Generate combustion chamber
|
| 921 |
+
Voxels voxChamber = CombustionChamber_{int(thrust_N/1000)}kN.Generate();
|
| 922 |
+
|
| 923 |
+
// 2. Generate bell nozzle
|
| 924 |
+
Voxels voxNozzle = BellNozzle_{int(thrust_N/1000)}kN.Generate();
|
| 925 |
+
|
| 926 |
+
// 3. Generate injector
|
| 927 |
+
Voxels voxInjector = Injector_Unlike_Doublet_{int(thrust_N/1000)}kN.Generate();
|
| 928 |
+
|
| 929 |
+
// 4. Boolean union: assemble all components
|
| 930 |
+
Voxels voxEngine = new Voxels();
|
| 931 |
+
voxEngine.BoolAdd(voxChamber);
|
| 932 |
+
voxEngine.BoolAdd(voxNozzle);
|
| 933 |
+
voxEngine.BoolAdd(voxInjector);
|
| 934 |
+
|
| 935 |
+
// 5. Subtract cooling channels from assembly
|
| 936 |
+
Voxels voxChannels = CoolingChannels_{int(thrust_N/1000)}kN.GenerateChannels();
|
| 937 |
+
voxEngine.BoolSubtract(voxChannels);
|
| 938 |
+
|
| 939 |
+
// 6. Apply surface offset for as-built tolerance
|
| 940 |
+
voxEngine.Offset(0.1f); // 0.1mm offset
|
| 941 |
+
|
| 942 |
+
// 7. Export mesh for manufacturing
|
| 943 |
+
Mesh mshEngine = voxEngine.mshAsMesh();
|
| 944 |
+
|
| 945 |
+
return voxEngine;
|
| 946 |
+
}}}}
|
| 947 |
+
}}}}
|
| 948 |
+
}}}}"""
|
| 949 |
+
|
| 950 |
+
return {"id": f"assembly_{int(thrust_N)}N_{propellant.replace('/','_')}", "input": input_text, "reasoning": reasoning, "output": output}
|
| 951 |
+
|
| 952 |
+
# ============================================================
|
| 953 |
+
# PROBLEM TYPE 11: GENERAL MECHANICAL COMPOENT (Universal CSG)
|
| 954 |
+
# ============================================================
|
| 955 |
+
def gen_mechanical_component():
|
| 956 |
+
# Delegates to the Universal CSG library
|
| 957 |
+
# Randomly chooses between Bracket, Enclosure, or other generic types
|
| 958 |
+
if random.random() < 0.5:
|
| 959 |
+
return universal_csg.gen_mounting_bracket()
|
| 960 |
+
else:
|
| 961 |
+
return universal_csg.gen_enclosure()
|
| 962 |
+
|
| 963 |
+
# ============================================================
|
| 964 |
+
# MAIN GENERATOR
|
| 965 |
+
# ============================================================
|
| 966 |
+
def generate_full_dataset(total_count=3500):
|
| 967 |
+
"""
|
| 968 |
+
Generates a calibrated mixed dataset for H100 training (< 2.3 hrs).
|
| 969 |
+
Distribution:
|
| 970 |
+
- 40% Core Rocket Propulsion (Nozzles, Chambers)
|
| 971 |
+
- 30% Advanced Systems (Cycles, Cooling, Injectors)
|
| 972 |
+
- 30% General Mechanical (Brackets, Boxes) - Universal Physics
|
| 973 |
+
"""
|
| 974 |
+
print(f"Generating {total_count} High-Density examples (Self-Correcting)...")
|
| 975 |
+
|
| 976 |
+
dataset = []
|
| 977 |
+
|
| 978 |
+
# 1. Rocket Propulsion (40%) -> 2000 examples
|
| 979 |
+
thrust_levels = [5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000, 2000000]
|
| 980 |
+
propellants = list(PROPELLANTS.keys())
|
| 981 |
+
|
| 982 |
+
for _ in range(int(total_count * 0.4)):
|
| 983 |
+
F = random.choice(thrust_levels) * random.uniform(0.8, 1.2)
|
| 984 |
+
Pc = random.uniform(20, 300)
|
| 985 |
+
prop = random.choice(propellants)
|
| 986 |
+
|
| 987 |
+
task_type = random.choice(["bell", "chamber", "aerospike"])
|
| 988 |
+
if task_type == "bell":
|
| 989 |
+
dataset.append(gen_bell_nozzle(F, Pc, prop))
|
| 990 |
+
elif task_type == "chamber":
|
| 991 |
+
dataset.append(gen_combustion_chamber(F, Pc, prop))
|
| 992 |
+
else:
|
| 993 |
+
dataset.append(gen_aerospike(F, Pc, prop))
|
| 994 |
+
|
| 995 |
+
# 2. Advanced Systems (30%) -> 1500 examples
|
| 996 |
+
for _ in range(int(total_count * 0.3)):
|
| 997 |
+
F = random.choice(thrust_levels)
|
| 998 |
+
Pc = random.uniform(50, 250)
|
| 999 |
+
prop = random.choice(propellants)
|
| 1000 |
+
|
| 1001 |
+
task_type = random.choice(["cooling", "injector", "cycle", "tpms", "mfg", "assembly", "structural"])
|
| 1002 |
+
|
| 1003 |
+
if task_type == "cooling":
|
| 1004 |
+
dataset.append(gen_cooling_channels(F, Pc, prop))
|
| 1005 |
+
elif task_type == "injector":
|
| 1006 |
+
dataset.append(gen_injector(F, Pc, prop))
|
| 1007 |
+
elif task_type == "cycle":
|
| 1008 |
+
dataset.append(gen_power_cycle(F, prop))
|
| 1009 |
+
elif task_type == "tpms":
|
| 1010 |
+
dataset.append(gen_gyroid_invention(random.choice(["Nozzle Wall", "Heat Exchanger"]), random.uniform(10, 80)))
|
| 1011 |
+
elif task_type == "mfg":
|
| 1012 |
+
dataset.append(gen_manufacturing_plan("Combustion Chamber", "Inconel_718", random.randint(100, 500)))
|
| 1013 |
+
elif task_type == "assembly":
|
| 1014 |
+
dataset.append(gen_engine_assembly(F, Pc, prop))
|
| 1015 |
+
else:
|
| 1016 |
+
dataset.append(gen_structural_analysis(Pc, random.randint(50, 500), "Inconel_718"))
|
| 1017 |
+
|
| 1018 |
+
# 3. General Mechanical (30%) -> 1500 examples
|
| 1019 |
+
# This enables "Any Design" capability
|
| 1020 |
+
print("Generating General Geometry (Universal CSG)...")
|
| 1021 |
+
for _ in range(int(total_count * 0.3)):
|
| 1022 |
+
dataset.append(gen_mechanical_component())
|
| 1023 |
+
|
| 1024 |
+
# Shuffle and Save
|
| 1025 |
+
random.shuffle(dataset)
|
| 1026 |
+
return dataset
|
| 1027 |
+
|
| 1028 |
+
def validate_dataset(dataset):
|
| 1029 |
+
"""Post-generation sanity checks"""
|
| 1030 |
+
errors = 0
|
| 1031 |
+
for ex in dataset:
|
| 1032 |
+
if "nozzle_bell" in ex["id"]:
|
| 1033 |
+
# Check throat diameter is reasonable (0.5mm to 1000mm)
|
| 1034 |
+
for line in ex["reasoning"].split("\n"):
|
| 1035 |
+
if "D* =" in line or "D*=" in line:
|
| 1036 |
+
try:
|
| 1037 |
+
parts = line.split("=")
|
| 1038 |
+
for part in parts:
|
| 1039 |
+
if "mm" in part:
|
| 1040 |
+
val = float(part.replace("mm","").strip().split()[0])
|
| 1041 |
+
if val < 0.5 or val > 1000:
|
| 1042 |
+
print(f"WARN: Unreasonable throat {val}mm in {ex['id']}")
|
| 1043 |
+
errors += 1
|
| 1044 |
+
except:
|
| 1045 |
+
pass
|
| 1046 |
+
if "MoS" in ex.get("reasoning",""):
|
| 1047 |
+
if "MoS = -" in ex["reasoning"] and "FAIL" not in ex["reasoning"]:
|
| 1048 |
+
print(f"WARN: Negative MoS without failure flag in {ex['id']}")
|
| 1049 |
+
errors += 1
|
| 1050 |
+
print(f"Validation complete: {errors} warnings in {len(dataset)} examples")
|
| 1051 |
+
return errors
|
| 1052 |
+
|
| 1053 |
+
def save_dataset(dataset, path):
|
| 1054 |
+
with open(path, 'w') as f:
|
| 1055 |
+
json.dump(dataset, f, indent=2)
|
| 1056 |
+
print(f"Saved {len(dataset)} examples to {path}")
|
| 1057 |
+
|
| 1058 |
+
if __name__ == "__main__":
|
| 1059 |
+
print("=" * 60)
|
| 1060 |
+
print("AlgoRythm Prandtl Aero — Deterministic Dataset Generator v2.0")
|
| 1061 |
+
print("=" * 60)
|
| 1062 |
+
print("Generating 5000 physics-first training examples...")
|
| 1063 |
+
dataset = generate_full_dataset(5000)
|
| 1064 |
+
validate_dataset(dataset)
|
| 1065 |
+
save_dataset(dataset, "./datasets/synthetic_nozzles.json")
|
| 1066 |
+
print("\nDataset composition:")
|
| 1067 |
+
types = {}
|
| 1068 |
+
for ex in dataset:
|
| 1069 |
+
t = ex["id"].split("_")[0]
|
| 1070 |
+
types[t] = types.get(t, 0) + 1
|
| 1071 |
+
for t, c in sorted(types.items(), key=lambda x: -x[1]):
|
| 1072 |
+
print(f" {t}: {c} examples")
|
| 1073 |
+
print("\nDone. Ready for cloud fine-tuning.")
|
datasets/physics_core.py
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Prandtl Aero — Deterministic Physics Core
|
| 3 |
+
All calculations in SI units internally, output in mm for PicoGK.
|
| 4 |
+
Validated against: RL-10, Merlin 1D, Raptor 3, Rutherford
|
| 5 |
+
"""
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
G0 = 9.80665 # m/s²
|
| 9 |
+
|
| 10 |
+
# === PROPELLANT DATABASE ===
|
| 11 |
+
PROPELLANTS = {
|
| 12 |
+
"LOX/LH2": {"gamma": 1.20, "Tc": 3500, "cstar": 2360, "Isp_vac": 450, "Isp_sl": 363, "Rspec": 692.0, "MW": 12.0, "rho_f": 70.8, "rho_o": 1141, "OF": 5.5},
|
| 13 |
+
"LOX/RP1": {"gamma": 1.24, "Tc": 3670, "cstar": 1800, "Isp_vac": 338, "Isp_sl": 311, "Rspec": 362.0, "MW": 23.0, "rho_f": 810, "rho_o": 1141, "OF": 2.34},
|
| 14 |
+
"LOX/CH4": {"gamma": 1.20, "Tc": 3540, "cstar": 1860, "Isp_vac": 363, "Isp_sl": 330, "Rspec": 519.0, "MW": 16.0, "rho_f": 422.6, "rho_o": 1141, "OF": 3.5},
|
| 15 |
+
"N2O4/UDMH":{"gamma": 1.25, "Tc": 3150, "cstar": 1720, "Isp_vac": 320, "Isp_sl": 285, "Rspec": 340.0, "MW": 24.5, "rho_f": 793, "rho_o": 1440, "OF": 2.0},
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
# === MATERIAL DATABASE ===
|
| 19 |
+
MATERIALS = {
|
| 20 |
+
"Inconel_718": {"sigma_y_MPa": 1035, "sigma_u_MPa": 1240, "E_GPa": 205, "rho": 8190, "k_W_mK": 11.4, "Tmax_K": 990, "CTE": 13e-6},
|
| 21 |
+
"Inconel_625": {"sigma_y_MPa": 490, "sigma_u_MPa": 827, "E_GPa": 205, "rho": 8440, "k_W_mK": 9.8, "Tmax_K": 980, "CTE": 12.8e-6},
|
| 22 |
+
"CuCrZr": {"sigma_y_MPa": 320, "sigma_u_MPa": 440, "E_GPa": 130, "rho": 8900, "k_W_mK": 320, "Tmax_K": 573, "CTE": 17e-6},
|
| 23 |
+
"GRCop84": {"sigma_y_MPa": 207, "sigma_u_MPa": 345, "E_GPa": 115, "rho": 8810, "k_W_mK": 285, "Tmax_K": 700, "CTE": 17.7e-6},
|
| 24 |
+
"Haynes_230": {"sigma_y_MPa": 390, "sigma_u_MPa": 860, "E_GPa": 211, "rho": 8970, "k_W_mK": 8.9, "Tmax_K": 1420, "CTE": 12.7e-6},
|
| 25 |
+
"Ti6Al4V": {"sigma_y_MPa": 880, "sigma_u_MPa": 950, "E_GPa": 114, "rho": 4430, "k_W_mK": 6.7, "Tmax_K": 600, "CTE": 8.6e-6},
|
| 26 |
+
"C103_Niobium": {"sigma_y_MPa": 270, "sigma_u_MPa": 400, "E_GPa": 95, "rho": 8850, "k_W_mK": 43, "Tmax_K": 1650, "CTE": 6.5e-6},
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
# === REFERENCE ENGINES (Validation Anchors) ===
|
| 30 |
+
REFERENCE_ENGINES = {
|
| 31 |
+
"RL-10A": {"thrust_N": 110000, "Pc_bar": 44, "prop": "LOX/LH2", "Isp": 465, "Dt_mm": 102, "eps": 84, "cycle": "Expander"},
|
| 32 |
+
"Merlin_1D": {"thrust_N": 845000, "Pc_bar": 97, "prop": "LOX/RP1", "Isp": 311, "Dt_mm": 262, "eps": 16, "cycle": "Gas Generator"},
|
| 33 |
+
"Raptor_3": {"thrust_N": 2690000, "Pc_bar": 350, "prop": "LOX/CH4", "Isp": 350, "Dt_mm": 200, "eps": 40, "cycle": "Full-Flow Staged"},
|
| 34 |
+
"Vulcain_2": {"thrust_N": 1359000, "Pc_bar": 115, "prop": "LOX/LH2", "Isp": 434, "Dt_mm": 270, "eps": 58, "cycle": "Gas Generator"},
|
| 35 |
+
"Rutherford": {"thrust_N": 25000, "Pc_bar": 12, "prop": "LOX/RP1", "Isp": 343, "Dt_mm": 60, "eps": 12.6, "cycle": "Electric Pump"},
|
| 36 |
+
"RD-180": {"thrust_N": 4152000, "Pc_bar": 267, "prop": "LOX/RP1", "Isp": 338, "Dt_mm": 330, "eps": 36.9, "cycle": "Staged Combustion"},
|
| 37 |
+
"Vinci": {"thrust_N": 180000, "Pc_bar": 61, "prop": "LOX/LH2", "Isp": 465, "Dt_mm": 135, "eps": 240, "cycle": "Expander"},
|
| 38 |
+
"BE-4": {"thrust_N": 2400000, "Pc_bar": 134, "prop": "LOX/CH4", "Isp": 340, "Dt_mm": 310, "eps": 35, "cycle": "Oxidizer-Rich Staged"},
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
# === CORE PHYSICS FUNCTIONS ===
|
| 42 |
+
def calc_thrust_coefficient(gamma, eps, Pc_Pa, Pe_Pa, Pa_Pa=0):
|
| 43 |
+
"""Thrust coefficient Cf from isentropic relations (NASA SP-125)"""
|
| 44 |
+
g = gamma
|
| 45 |
+
term1 = (2*g*g/(g-1)) * (2/(g+1))**((g+1)/(g-1))
|
| 46 |
+
pr = Pe_Pa / Pc_Pa
|
| 47 |
+
term2 = 1 - pr**((g-1)/g)
|
| 48 |
+
Cf = math.sqrt(term1 * term2) + eps * (Pe_Pa - Pa_Pa) / Pc_Pa
|
| 49 |
+
return max(Cf, 0.8) # Physical lower bound
|
| 50 |
+
|
| 51 |
+
def calc_exit_pressure(gamma, eps):
|
| 52 |
+
"""Iterative solve for Pe/Pc from area ratio using Newton's method"""
|
| 53 |
+
g = gamma
|
| 54 |
+
pr = 0.01 # Initial guess Pe/Pc
|
| 55 |
+
for _ in range(50):
|
| 56 |
+
M2_term = (2/(g-1)) * (pr**(-(g-1)/g) - 1)
|
| 57 |
+
if M2_term <= 0:
|
| 58 |
+
pr *= 0.5
|
| 59 |
+
continue
|
| 60 |
+
Me = math.sqrt(M2_term)
|
| 61 |
+
eps_calc = (1/Me) * ((2/(g+1)) * (1 + (g-1)/2 * Me*Me))**((g+1)/(2*(g-1)))
|
| 62 |
+
deps = eps_calc - eps
|
| 63 |
+
if abs(deps) < 0.001:
|
| 64 |
+
break
|
| 65 |
+
pr *= (1 - 0.1 * deps / max(eps, 1))
|
| 66 |
+
pr = max(pr, 1e-6)
|
| 67 |
+
return pr
|
| 68 |
+
|
| 69 |
+
def calc_throat_area(thrust_N, Pc_bar, Cf):
|
| 70 |
+
"""A* = F / (Pc × Cf) — returns m²"""
|
| 71 |
+
Pc_Pa = Pc_bar * 1e5
|
| 72 |
+
return thrust_N / (Pc_Pa * Cf)
|
| 73 |
+
|
| 74 |
+
def throat_area_to_diameter_mm(At_m2):
|
| 75 |
+
"""Convert throat area (m²) to diameter (mm)"""
|
| 76 |
+
Dt_m = math.sqrt(4 * At_m2 / math.pi)
|
| 77 |
+
return Dt_m * 1000 # m -> mm
|
| 78 |
+
|
| 79 |
+
def calc_exit_diameter_mm(Dt_mm, eps):
|
| 80 |
+
"""De = Dt × sqrt(ε)"""
|
| 81 |
+
return Dt_mm * math.sqrt(eps)
|
| 82 |
+
|
| 83 |
+
def calc_mass_flow(thrust_N, Isp_s):
|
| 84 |
+
"""mdot = F / (Isp × g0) — returns kg/s"""
|
| 85 |
+
return thrust_N / (Isp_s * G0)
|
| 86 |
+
|
| 87 |
+
def calc_cstar(Tc, gamma, Rspec):
|
| 88 |
+
"""c* = sqrt(gamma*Rspec*Tc) / (gamma * sqrt((2/(gamma+1))^((gamma+1)/(gamma-1))))"""
|
| 89 |
+
g = gamma
|
| 90 |
+
num = math.sqrt(g * Rspec * Tc)
|
| 91 |
+
denom = g * math.sqrt((2/(g+1))**((g+1)/(g-1)))
|
| 92 |
+
return num / denom
|
| 93 |
+
|
| 94 |
+
def calc_nozzle_length_mm(Dt_mm, De_mm, half_angle_deg=15.0, percent_bell=80.0):
|
| 95 |
+
"""Rao 80% bell nozzle length"""
|
| 96 |
+
Rt = Dt_mm / 2
|
| 97 |
+
Re = De_mm / 2
|
| 98 |
+
Ln_conical = (Re - Rt) / math.tan(math.radians(half_angle_deg))
|
| 99 |
+
return Ln_conical * (percent_bell / 100.0)
|
| 100 |
+
|
| 101 |
+
def calc_chamber_length_mm(cstar, Pc_bar, At_m2, mdot, Lstar_m=1.0):
|
| 102 |
+
"""Chamber length from L* (characteristic length)"""
|
| 103 |
+
Vc_m3 = Lstar_m * At_m2
|
| 104 |
+
Ac_m2 = At_m2 * 3.0 # Contraction ratio ~3:1
|
| 105 |
+
Lc_m = Vc_m3 / Ac_m2
|
| 106 |
+
return Lc_m * 1000 # mm
|
| 107 |
+
|
| 108 |
+
def calc_chamber_diameter_mm(Dt_mm, contraction_ratio=3.0):
|
| 109 |
+
"""Dc = Dt × sqrt(CR)"""
|
| 110 |
+
return Dt_mm * math.sqrt(contraction_ratio)
|
| 111 |
+
|
| 112 |
+
def calc_hoop_stress_MPa(Pc_bar, inner_D_mm, wall_t_mm):
|
| 113 |
+
"""Thin-wall hoop stress: σ = P×r / t (all consistent units)"""
|
| 114 |
+
P_MPa = Pc_bar * 0.1 # bar -> MPa
|
| 115 |
+
r_mm = inner_D_mm / 2.0
|
| 116 |
+
return (P_MPa * r_mm) / wall_t_mm
|
| 117 |
+
|
| 118 |
+
def calc_margin_of_safety(sigma_yield_MPa, sigma_applied_MPa, safety_factor=1.25):
|
| 119 |
+
"""MoS = (σ_yield / (SF × σ_applied)) - 1"""
|
| 120 |
+
return (sigma_yield_MPa / (safety_factor * sigma_applied_MPa)) - 1.0
|
| 121 |
+
|
| 122 |
+
def calc_bartz_heat_flux(Pc_bar, Dt_mm, cstar, mdot, Tc, gamma, Pr=0.5, mu=5e-5):
|
| 123 |
+
"""Bartz correlation for convective heat transfer at throat (W/m²)"""
|
| 124 |
+
Dt_m = Dt_mm / 1000
|
| 125 |
+
At_m2 = math.pi * (Dt_m/2)**2
|
| 126 |
+
g = gamma
|
| 127 |
+
sigma = 1.0 # Simplified correction factor
|
| 128 |
+
Cp = gamma * 287 / (gamma - 1) # Approximate Cp
|
| 129 |
+
h_g = (0.026 / (Dt_m**0.2)) * ((mu**0.2 * Cp) / (Pr**0.6)) * \
|
| 130 |
+
((Pc_bar * 1e5 / cstar)**0.8) * (Dt_m / 1.0)**0.1 * sigma
|
| 131 |
+
q = h_g * (Tc * 0.9) # Adiabatic wall temp ~ 0.9*Tc
|
| 132 |
+
return q / 1e6 # MW/m²
|
| 133 |
+
|
| 134 |
+
def calc_coolant_velocity(q_MW_m2, Tc_wall_K, Tc_cool_K, rho_cool, Cp_cool):
|
| 135 |
+
"""Required coolant velocity for given heat flux"""
|
| 136 |
+
q_W = q_MW_m2 * 1e6
|
| 137 |
+
dT = Tc_wall_K - Tc_cool_K
|
| 138 |
+
return q_W / (rho_cool * Cp_cool * dT)
|
| 139 |
+
|
| 140 |
+
def select_wall_thickness_mm(Pc_bar, Dt_mm, material_key, target_MoS=0.5):
|
| 141 |
+
"""Auto-select wall thickness for target MoS"""
|
| 142 |
+
mat = MATERIALS[material_key]
|
| 143 |
+
sigma_y = mat["sigma_y_MPa"]
|
| 144 |
+
P_MPa = Pc_bar * 0.1
|
| 145 |
+
r_mm = Dt_mm / 2
|
| 146 |
+
# σ = Pr/t -> t = Pr / (σ_y / (SF * (1+MoS)))
|
| 147 |
+
t_mm = (P_MPa * r_mm * 1.25 * (1 + target_MoS)) / sigma_y
|
| 148 |
+
return max(round(t_mm, 2), 0.5) # Minimum 0.5mm
|
| 149 |
+
|
| 150 |
+
def select_cycle(thrust_N, propellant):
|
| 151 |
+
"""Deterministic power cycle selection based on physics"""
|
| 152 |
+
p = PROPELLANTS[propellant]
|
| 153 |
+
if thrust_N > 1500000:
|
| 154 |
+
if "LH2" in propellant:
|
| 155 |
+
return "Gas Generator", "High thrust LH2: GG avoids LH2 pre-burner complexity (Vulcain heritage)."
|
| 156 |
+
return "Staged Combustion", "High thrust >1.5MN requires high Pc for compact design. Staged combustion maximizes Isp."
|
| 157 |
+
elif thrust_N > 500000:
|
| 158 |
+
if "CH4" in propellant:
|
| 159 |
+
return "Full-Flow Staged Combustion", "Medium-high thrust CH4: FFSC maximizes Isp and eliminates turbine coking (Raptor heritage)."
|
| 160 |
+
return "Gas Generator", "Medium thrust: GG provides simplicity with adequate performance."
|
| 161 |
+
elif "LH2" in propellant and thrust_N < 200000:
|
| 162 |
+
return "Expander Cycle", "Low thrust LH2: High heat capacity enables turbine drive from jacket heat alone (RL-10 heritage)."
|
| 163 |
+
elif thrust_N < 5000:
|
| 164 |
+
return "Pressure-Fed", "Very low thrust: Pressure-fed eliminates turbopump mass and complexity."
|
| 165 |
+
else:
|
| 166 |
+
return "Gas Generator", "Default: GG provides best reliability-to-performance ratio."
|
| 167 |
+
|
| 168 |
+
def validate_against_reference(thrust_N, Pc_bar, prop, Dt_calc_mm):
|
| 169 |
+
"""Check calculated throat against nearest reference engine"""
|
| 170 |
+
best_match = None
|
| 171 |
+
best_dist = float('inf')
|
| 172 |
+
for name, ref in REFERENCE_ENGINES.items():
|
| 173 |
+
if ref["prop"] == prop:
|
| 174 |
+
dist = abs(ref["thrust_N"] - thrust_N) / ref["thrust_N"]
|
| 175 |
+
if dist < best_dist:
|
| 176 |
+
best_dist = dist
|
| 177 |
+
best_match = (name, ref)
|
| 178 |
+
if best_match and best_dist < 0.3:
|
| 179 |
+
name, ref = best_match
|
| 180 |
+
ratio = Dt_calc_mm / ref["Dt_mm"]
|
| 181 |
+
scaled_ratio = ratio * math.sqrt(ref["Pc_bar"] / Pc_bar) * math.sqrt(thrust_N / ref["thrust_N"])
|
| 182 |
+
return name, ref["Dt_mm"], abs(1 - scaled_ratio) < 0.5
|
| 183 |
+
return None, None, True
|
| 184 |
+
|
| 185 |
+
# === L-PBF MANUFACTURING PARAMETERS ===
|
| 186 |
+
LPBF_PARAMS = {
|
| 187 |
+
"Inconel_718": {"power_W": 285, "speed_mm_s": 960, "hatch_um": 110, "layer_um": 40},
|
| 188 |
+
"Inconel_625": {"power_W": 275, "speed_mm_s": 800, "hatch_um": 100, "layer_um": 40},
|
| 189 |
+
"CuCrZr": {"power_W": 370, "speed_mm_s": 600, "hatch_um": 90, "layer_um": 30},
|
| 190 |
+
"GRCop84": {"power_W": 350, "speed_mm_s": 500, "hatch_um": 100, "layer_um": 30},
|
| 191 |
+
"Ti6Al4V": {"power_W": 280, "speed_mm_s": 1200, "hatch_um": 120, "layer_um": 30},
|
| 192 |
+
"C103_Niobium": {"power_W": 300, "speed_mm_s": 700, "hatch_um": 100, "layer_um": 40},
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
# === ADVANCED PHYSICS — DEEPER ENCODING ===
|
| 196 |
+
|
| 197 |
+
def calc_exit_mach(gamma, eps):
|
| 198 |
+
"""Solve for exit Mach number from area ratio (Newton iteration)"""
|
| 199 |
+
g = gamma
|
| 200 |
+
Me = 3.0 # Supersonic initial guess
|
| 201 |
+
for _ in range(100):
|
| 202 |
+
f = (1/Me) * ((2/(g+1)) * (1 + (g-1)/2 * Me**2))**((g+1)/(2*(g-1))) - eps
|
| 203 |
+
df = -f/Me + (1/Me) * ((g+1)/(2*(g-1))) * ((2/(g+1)) * (1 + (g-1)/2 * Me**2))**((g+1)/(2*(g-1)) - 1) * (2/(g+1)) * (g-1) * Me
|
| 204 |
+
if abs(df) < 1e-12: break
|
| 205 |
+
Me_new = Me - f / df
|
| 206 |
+
if abs(Me_new - Me) < 1e-8: break
|
| 207 |
+
Me = max(Me_new, 1.001)
|
| 208 |
+
return Me
|
| 209 |
+
|
| 210 |
+
def calc_exhaust_velocity(gamma, Rspec, Tc, Pe_Pc):
|
| 211 |
+
"""Ve = sqrt(2γRTc/(γ-1) × (1-(Pe/Pc)^((γ-1)/γ)))"""
|
| 212 |
+
g = gamma
|
| 213 |
+
term = (2 * g * Rspec * Tc / (g - 1)) * (1 - Pe_Pc**((g-1)/g))
|
| 214 |
+
return math.sqrt(max(term, 0))
|
| 215 |
+
|
| 216 |
+
def calc_isp_from_first_principles(gamma, Rspec, Tc, Pc_bar, eps, Pa_bar=0):
|
| 217 |
+
"""Isp = Ve/g0 + (Pe-Pa)×Ae/(mdot×g0) — full first-principles calculation"""
|
| 218 |
+
pe_ratio = calc_exit_pressure(gamma, eps)
|
| 219 |
+
Pe_bar = pe_ratio * Pc_bar
|
| 220 |
+
Ve = calc_exhaust_velocity(gamma, Rspec, Tc, pe_ratio)
|
| 221 |
+
# Momentum thrust term
|
| 222 |
+
Isp_mom = Ve / G0
|
| 223 |
+
# Pressure thrust term (small correction)
|
| 224 |
+
# Ae/At = eps, so pressure term scales with eps
|
| 225 |
+
Cf = calc_thrust_coefficient(gamma, eps, 1.0, pe_ratio, Pa_bar/Pc_bar)
|
| 226 |
+
return Ve / G0 # Simplified; full version uses Cf
|
| 227 |
+
|
| 228 |
+
def calc_reynolds(rho, v, D_m, mu):
|
| 229 |
+
"""Re = ρvD/μ"""
|
| 230 |
+
return rho * v * D_m / mu
|
| 231 |
+
|
| 232 |
+
def calc_hydraulic_diameter(width_mm, depth_mm):
|
| 233 |
+
"""Dh = 4A/P for rectangular channel"""
|
| 234 |
+
A = width_mm * depth_mm
|
| 235 |
+
P = 2 * (width_mm + depth_mm)
|
| 236 |
+
return 4 * A / P
|
| 237 |
+
|
| 238 |
+
def calc_nusselt_dittus_boelter(Re, Pr, heating=True):
|
| 239 |
+
"""Dittus-Boelter: Nu = 0.023 × Re^0.8 × Pr^n (n=0.4 heating, 0.3 cooling)"""
|
| 240 |
+
n = 0.4 if heating else 0.3
|
| 241 |
+
return 0.023 * Re**0.8 * Pr**n
|
| 242 |
+
|
| 243 |
+
def calc_nusselt_sieder_tate(Re, Pr, L_D, mu_bulk, mu_wall):
|
| 244 |
+
"""Sieder-Tate: Nu = 0.027 × Re^0.8 × Pr^(1/3) × (μb/μw)^0.14"""
|
| 245 |
+
return 0.027 * Re**0.8 * Pr**(1/3) * (mu_bulk / mu_wall)**0.14
|
| 246 |
+
|
| 247 |
+
def calc_thermal_resistance_wall(t_mm, k_W_mK, A_mm2):
|
| 248 |
+
"""R_wall = t / (k × A) — conductive thermal resistance"""
|
| 249 |
+
t_m = t_mm / 1000
|
| 250 |
+
A_m2 = A_mm2 / 1e6
|
| 251 |
+
return t_m / (k_W_mK * A_m2)
|
| 252 |
+
|
| 253 |
+
def calc_wall_temperature(Tc_K, q_MW_m2, wall_t_mm, k_wall):
|
| 254 |
+
"""T_wall_hot = Tc - q × t / k (hot-side wall temperature)"""
|
| 255 |
+
q_W = q_MW_m2 * 1e6
|
| 256 |
+
t_m = wall_t_mm / 1000
|
| 257 |
+
return Tc_K - q_W * t_m / k_wall # This is actually Tc - q*t/k for cold side
|
| 258 |
+
|
| 259 |
+
def calc_turbopump_power(mdot, dp_bar, rho, eta=0.65):
|
| 260 |
+
"""P_pump = mdot × ΔP / (ρ × η)"""
|
| 261 |
+
dp_Pa = dp_bar * 1e5
|
| 262 |
+
return mdot * dp_Pa / (rho * eta)
|
| 263 |
+
|
| 264 |
+
def calc_specific_speed(N_rpm, Q_m3s, H_m):
|
| 265 |
+
"""Ns = N×sqrt(Q) / H^0.75 — turbopump specific speed"""
|
| 266 |
+
return N_rpm * math.sqrt(Q_m3s) / H_m**0.75
|
| 267 |
+
|
| 268 |
+
def calc_npsh_required(v_ms, rho, P_vapor_Pa, P_inlet_Pa):
|
| 269 |
+
"""NPSHr = (P_inlet - P_vapor)/(ρg) — cavitation check"""
|
| 270 |
+
return (P_inlet_Pa - P_vapor_Pa) / (rho * G0)
|
| 271 |
+
|
| 272 |
+
def calc_volumetric_energy_density(power_W, speed_mm_s, hatch_mm, layer_mm):
|
| 273 |
+
"""VED = P / (v × h × t) in J/mm³ — key L-PBF quality metric"""
|
| 274 |
+
return power_W / (speed_mm_s * hatch_mm * layer_mm)
|
| 275 |
+
|
| 276 |
+
def calc_contraction_angle(Dc_mm, Dt_mm, Lcon_mm):
|
| 277 |
+
"""Half-angle of converging section"""
|
| 278 |
+
return math.degrees(math.atan((Dc_mm - Dt_mm) / (2 * Lcon_mm)))
|
| 279 |
+
|
| 280 |
+
def calc_divergence_loss(half_angle_deg):
|
| 281 |
+
"""λ = (1 + cos(α))/2 — divergence efficiency factor"""
|
| 282 |
+
return (1 + math.cos(math.radians(half_angle_deg))) / 2
|
| 283 |
+
|
| 284 |
+
def calc_combustion_efficiency(Lstar_m, cstar_theoretical):
|
| 285 |
+
"""η_c* approximation based on L* (higher L* = more complete combustion)"""
|
| 286 |
+
eta = min(0.99, 0.85 + 0.12 * math.log(max(Lstar_m, 0.1)))
|
| 287 |
+
return eta
|
| 288 |
+
|
| 289 |
+
def calc_mixture_density(rho_f, rho_o, OF):
|
| 290 |
+
"""Bulk propellant density: 1/ρ_mix = (1/(1+OF))/ρ_f + (OF/(1+OF))/ρ_o"""
|
| 291 |
+
w_f = 1 / (1 + OF)
|
| 292 |
+
w_o = OF / (1 + OF)
|
| 293 |
+
return 1 / (w_f / rho_f + w_o / rho_o)
|
| 294 |
+
|
| 295 |
+
# === CONSTANTS DATABASE ===
|
| 296 |
+
UNIVERSAL_GAS_CONST = 8314.46 # J/(kmol·K)
|
| 297 |
+
STEFAN_BOLTZMANN = 5.67e-8 # W/(m²·K⁴)
|
| 298 |
+
BOLTZMANN_K = 1.381e-23 # J/K
|
| 299 |
+
|
| 300 |
+
def calc_radiation_heat_loss(emissivity, T_surface_K, T_ambient_K=300):
|
| 301 |
+
"""q_rad = ε × σ × (T⁴_s - T⁴_a) — Stefan-Boltzmann radiation"""
|
| 302 |
+
return emissivity * STEFAN_BOLTZMANN * (T_surface_K**4 - T_ambient_K**4)
|
| 303 |
+
|
| 304 |
+
def calc_speed_of_sound(gamma, Rspec, T_K):
|
| 305 |
+
"""a = sqrt(γ × R × T)"""
|
| 306 |
+
return math.sqrt(gamma * Rspec * T_K)
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
# === GENERAL ENGINEERING PHYSICS ===
|
| 310 |
+
|
| 311 |
+
def calc_beam_deflection(load_N, length_mm, width_mm, height_mm, E_GPa):
|
| 312 |
+
"""Max deflection of cantilever beam: δ = (F*L^3) / (3*E*I)"""
|
| 313 |
+
L = length_mm / 1000
|
| 314 |
+
w = width_mm / 1000
|
| 315 |
+
h = height_mm / 1000
|
| 316 |
+
E = E_GPa * 1e9
|
| 317 |
+
|
| 318 |
+
# Area Moment of Inertia for rectangle
|
| 319 |
+
I = (w * h**3) / 12
|
| 320 |
+
|
| 321 |
+
deflection_m = (load_N * L**3) / (3 * E * I)
|
| 322 |
+
return deflection_m * 1000 # return mm
|
| 323 |
+
|
| 324 |
+
def calc_plate_buckling_stress(E_GPa, t_mm, width_mm, poisson=0.3):
|
| 325 |
+
"""Critical buckling stress for simply supported plate: σ_cr = (k*π^2*E)/(12*(1-v^2)*(b/t)^2)"""
|
| 326 |
+
k = 4.0 # Simply supported
|
| 327 |
+
E = E_GPa * 1e9
|
| 328 |
+
ratio = width_mm / t_mm
|
| 329 |
+
|
| 330 |
+
sigma_cr = (k * math.pi**2 * E) / (12 * (1 - poisson**2) * ratio**2)
|
| 331 |
+
return sigma_cr / 1e6 # MPa
|
| 332 |
+
|
| 333 |
+
def calc_conduction_resistance(length_mm, area_mm2, k_W_mK):
|
| 334 |
+
"""Thermal resistance R = L / (k * A)"""
|
| 335 |
+
L = length_mm / 1000
|
| 336 |
+
A = area_mm2 / 1e6
|
| 337 |
+
return L / (k_W_mK * A)
|
| 338 |
+
|
| 339 |
+
def calc_heatsink_performance(power_W, T_max_C, T_amb_C, R_ideal_CW):
|
| 340 |
+
"""Check if heatsink meets thermal resistance target"""
|
| 341 |
+
delta_T = T_max_C - T_amb_C
|
| 342 |
+
R_actual = delta_T / power_W
|
| 343 |
+
margin = (R_actual - R_ideal_CW) / R_ideal_CW
|
| 344 |
+
return R_actual, margin
|
| 345 |
+
|
| 346 |
+
def calc_bolt_shear_strength(diameter_mm, material_key):
|
| 347 |
+
"""Shear strength of a bolt ≈ 0.6 * Ultimate Tensile Strength"""
|
| 348 |
+
mat = MATERIALS[material_key]
|
| 349 |
+
area = math.pi * (diameter_mm/2)**2
|
| 350 |
+
shear_yield_MPa = 0.577 * mat["sigma_y_MPa"] # Von Mises criterion
|
| 351 |
+
|
| 352 |
+
max_load_N = shear_yield_MPa * area
|
| 353 |
+
return max_load_N
|
| 354 |
+
|
| 355 |
+
def calc_natural_frequency_cantilever(length_mm, width_mm, height_mm, E_GPa, rho_kg_m3):
|
| 356 |
+
"""Fundamental frequency f = (0.56/L^2) * sqrt(E*I / (rho*A))"""
|
| 357 |
+
L = length_mm / 1000
|
| 358 |
+
w = width_mm / 1000
|
| 359 |
+
h = height_mm / 1000
|
| 360 |
+
E = E_GPa * 1e9
|
| 361 |
+
|
| 362 |
+
I = (w * h**3) / 12
|
| 363 |
+
A = w * h
|
| 364 |
+
|
| 365 |
+
freq_Hz = (3.52 / (2 * math.pi * L**2)) * math.sqrt((E * I) / (rho_kg_m3 * A))
|
| 366 |
+
return freq_Hz
|
datasets/rocket_propulsion_dataset.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "nozzle_001",
|
| 4 |
+
"input": "Design a rocket nozzle for a 5kN thrust LOX/LH2 engine with chamber pressure 100 bar and mixture ratio 6.0",
|
| 5 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Thrust (F): 5000 N\n- Chamber pressure (Pc): 100 bar = 10 MPa\n- Propellants: LOX/LH2\n- Mixture ratio (O/F): 6.0\n- Propellant: LOX/LH2 (cryogenic bipropellant)\n\n[PHYSICS_DERIVATION]\n\nStep 1: Combustion Properties (from CEA or tables)\n- γ (gamma) = 1.14 for LOX/LH2 at MR=6\n- Tc (chamber temp) = 3500 K\n- M (molecular weight) = 13.4 kg/kmol\n- c* (characteristic velocity) = 2360 m/s\n\nStep 2: Specific Impulse\n$I_{sp} = \\frac{c^*}{g_0} \\cdot C_f$\n$C_f = \\sqrt{\\frac{2\\gamma^2}{\\gamma-1} \\left(\\frac{2}{\\gamma+1}\\right)^{\\frac{\\gamma+1}{\\gamma-1}} \\left[1 - \\left(\\frac{P_e}{P_c}\\right)^{\\frac{\\gamma-1}{\\gamma}}\\right]}$\nAssuming Pe/Pc = 0.01 (optimal expansion)\n$C_f = 1.85$\n$I_{sp} = 450$ s\n\nStep 3: Mass Flow Rate\n$\\dot{m} = \\frac{F}{I_{sp} \\cdot g_0} = \\frac{5000}{450 \\times 9.81} = 1.133$ kg/s\n\nStep 4: Throat Area\n$A^* = \\frac{\\dot{m} \\cdot c^*}{P_c} = \\frac{1.133 \\times 2360}{10 \\times 10^6} = 267.4$ mm²\n$D^* = \\sqrt{\\frac{4 A^*}{\\pi}} = 18.45$ mm → Round to 18.5 mm\n\nStep 5: Expansion Ratio\nFor altitude optimization (vacuum): ε = 50-100\nFor sea level: ε = 8-15\nChoosing ε = 40 (high altitude optimized)\n$A_e = \\epsilon \\cdot A^* = 40 \\times 267.4 = 10696$ mm²\n$D_e = 116.7$ mm → Round to 117 mm\n\nStep 6: Nozzle Length (80% bell contour)\n$L_n = 0.8 \\times \\frac{D_e - D^*}{2 \\tan(15°)} = 183$ mm\n\n[CONSTRAINT_VALIDATION]\n✓ Throat size: 18.5mm > 10mm minimum for manufacturing\n✓ Expansion ratio: 40 within 20-80 range for vacuum engines\n✓ Wall thickness: Will calculate in cooling section",
|
| 6 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.Engines\n{\n public class NozzleGenerator\n {\n // Calculated parameters\n const float THROAT_DIAMETER = 18.5f;\n const float EXIT_DIAMETER = 117.0f;\n const float NOZZLE_LENGTH = 183.0f;\n const float WALL_THICKNESS = 2.0f;\n \n public static Voxels GenerateNozzle()\n {\n Voxels voxNozzle = new Voxels();\n \n // Throat section\n float fThroatRadius = THROAT_DIAMETER / 2.0f;\n Vector3 vecThroat = new Vector3(0, 0, 0);\n \n // Convergent section (30 degree half-angle)\n float fConvergentLength = 30.0f;\n float fChamberRadius = fThroatRadius * 1.5f;\n \n // Divergent section (bell contour - 80%)\n float fExitRadius = EXIT_DIAMETER / 2.0f;\n \n // Generate bell nozzle contour using Rao method\n int nPoints = 50;\n for (int i = 0; i <= nPoints; i++)\n {\n float t = (float)i / nPoints;\n float z = -t * NOZZLE_LENGTH;\n float r = fThroatRadius + (fExitRadius - fThroatRadius) * \n (float)Math.Pow(t, 0.7);\n \n // Add material at this cross-section\n Voxels voxRing = Voxels.voxSphere(\n new Vector3(0, 0, z), r + WALL_THICKNESS);\n Voxels voxInner = Voxels.voxSphere(\n new Vector3(0, 0, z), r);\n voxRing.BoolSubtract(voxInner);\n voxNozzle.BoolAdd(voxRing);\n }\n \n return voxNozzle;\n }\n }\n}"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"id": "chamber_001",
|
| 10 |
+
"input": "Design combustion chamber for 10kN LOX/RP-1 engine at 80 bar chamber pressure",
|
| 11 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Thrust (F): 10000 N\n- Chamber pressure (Pc): 80 bar = 8 MPa\n- Propellants: LOX/RP-1 (kerosene)\n- Assume standard O/F ratio: 2.7\n\n[PHYSICS_DERIVATION]\n\nStep 1: Combustion Properties\n- γ = 1.24 for LOX/RP-1\n- Tc = 3600 K\n- c* = 1780 m/s\n- Isp (vacuum) ≈ 320 s\n\nStep 2: Mass Flow Rate\n$\\dot{m} = \\frac{F}{I_{sp} \\cdot g_0} = \\frac{10000}{320 \\times 9.81} = 3.185$ kg/s\n\nStep 3: Throat Area\n$A^* = \\frac{\\dot{m} \\cdot c^*}{P_c} = \\frac{3.185 \\times 1780}{8 \\times 10^6} = 708.7$ mm²\n$D^* = 30.0$ mm\n\nStep 4: Characteristic Length (L*)\nFor LOX/RP-1: L* = 1.0 - 1.5 m (typical)\nChoosing L* = 1.2 m\n\nStep 5: Chamber Volume\n$V_c = L^* \\times A^* = 1.2 \\times 708.7 \\times 10^{-6} = 850.4$ cm³\n\nStep 6: Chamber Dimensions\nContraction ratio: CR = 3.0 (typical)\n$A_c = CR \\times A^* = 3.0 \\times 708.7 = 2126$ mm²\n$D_c = 52.0$ mm\n\nChamber length:\n$L_c = \\frac{V_c}{A_c} = \\frac{850400}{2126} = 400$ mm\n\n[CONSTRAINT_VALIDATION]\n✓ L* = 1.2m within 1.0-1.5m range for LOX/RP-1\n✓ Contraction ratio 3.0 within 2.5-4.0 range\n✓ Chamber L/D = 400/52 = 7.7 (acceptable)",
|
| 12 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.Engines\n{\n public class ChamberGenerator\n {\n const float THROAT_DIAMETER = 30.0f;\n const float CHAMBER_DIAMETER = 52.0f;\n const float CHAMBER_LENGTH = 400.0f;\n const float WALL_THICKNESS = 3.0f;\n \n public static Voxels GenerateChamber()\n {\n Voxels voxChamber = new Voxels();\n \n float fChamberRadius = CHAMBER_DIAMETER / 2.0f + WALL_THICKNESS;\n float fInnerRadius = CHAMBER_DIAMETER / 2.0f;\n \n // Cylindrical chamber section\n Vector3 vecStart = new Vector3(0, 0, 0);\n Vector3 vecEnd = new Vector3(0, 0, CHAMBER_LENGTH);\n \n // Outer wall\n Voxels voxOuter = Voxels.voxSphere(vecStart, fChamberRadius);\n voxOuter.BoolAdd(Voxels.voxSphere(vecEnd, fChamberRadius));\n \n // Inner cavity\n Voxels voxInner = Voxels.voxSphere(vecStart, fInnerRadius);\n voxInner.BoolAdd(Voxels.voxSphere(vecEnd, fInnerRadius));\n \n voxChamber.BoolAdd(voxOuter);\n voxChamber.BoolSubtract(voxInner);\n \n return voxChamber;\n }\n }\n}"
|
| 13 |
+
}
|
| 14 |
+
]
|
datasets/synthetic_nozzles.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:23ff426560cf99c5374f836aabbca367464f0ada2fc5bd690ecb0a0f6ed6af83
|
| 3 |
+
size 12017255
|
datasets/thermal_fluid_dataset.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "cooling_001",
|
| 4 |
+
"input": "Design regenerative cooling channels for copper nozzle with 45 MW/m² heat flux at throat",
|
| 5 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Heat flux at throat (q): 45 MW/m² = 45×10⁶ W/m²\n- Material: Copper (k = 401 W/m·K)\n- Coolant: LH2 (inlet 20K, outlet limit 200K)\n\n[PHYSICS_DERIVATION]\n\nStep 1: Required Heat Transfer Coefficient\n$h = \\frac{q}{T_{gas} - T_{wall}} = \\frac{45 \\times 10^6}{3500 - 800} = 16,667$ W/(m²·K)\n\nStep 2: Coolant Velocity (Dittus-Boelter)\n$Nu = 0.023 Re^{0.8} Pr^{0.4}$\nFor LH2: Pr = 1.2, k = 0.1 W/m·K\n$h = \\frac{Nu \\cdot k}{D_h}$\nSolving: $V_{coolant} = 35$ m/s\n\nStep 3: Channel Sizing\nHydraulic diameter: $D_h = \\frac{4A}{P} = 2.5$ mm\nChannel width: w = 2.0 mm\nChannel depth: d = 3.0 mm\n\nStep 4: Wall Thickness\n$t_{wall} = \\frac{q \\cdot d}{k \\cdot \\Delta T} = \\frac{45 \\times 10^6 \\times 0.003}{401 \\times 400} = 0.84$ mm\nRound to: 1.0 mm (safety factor 1.2)\n\n[CONSTRAINT_VALIDATION]\n✓ T_wall = 800K < 1356K (Cu melting)\n✓ Coolant velocity 35 m/s < 50 m/s (erosion limit)\n✓ Channel Re = 85000 > 10000 (turbulent flow)",
|
| 6 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.Cooling\n{\n public class CoolingChannelGenerator\n {\n const float CHANNEL_WIDTH = 2.0f;\n const float CHANNEL_DEPTH = 3.0f;\n const float WALL_THICKNESS = 1.0f;\n const int NUM_CHANNELS = 24;\n const float RIB_WIDTH = 1.5f;\n \n public static Voxels GenerateCoolingChannels(float nozzleRadius, float length)\n {\n Voxels voxChannels = new Voxels();\n float circumference = 2 * (float)Math.PI * nozzleRadius;\n float spacing = circumference / NUM_CHANNELS;\n \n for (int i = 0; i < NUM_CHANNELS; i++)\n {\n float angle = 2 * (float)Math.PI * i / NUM_CHANNELS;\n float xOffset = (nozzleRadius + WALL_THICKNESS) * (float)Math.Cos(angle);\n float yOffset = (nozzleRadius + WALL_THICKNESS) * (float)Math.Sin(angle);\n \n // Create channel as rectangular cross-section extruded along nozzle\n Vector3 channelStart = new Vector3(xOffset, yOffset, 0);\n Vector3 channelEnd = new Vector3(xOffset, yOffset, length);\n \n Voxels voxChannel = Voxels.voxSphere(channelStart, CHANNEL_WIDTH/2);\n voxChannel.BoolAdd(Voxels.voxSphere(channelEnd, CHANNEL_WIDTH/2));\n voxChannels.BoolAdd(voxChannel);\n }\n return voxChannels;\n }\n }\n}"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"id": "injector_001",
|
| 10 |
+
"input": "Design coaxial swirl injector element for LOX/Methane with 3.5 O/F ratio, 20% pressure drop",
|
| 11 |
+
"reasoning": "[REQUIREMENTS_PARSE]\n- Injector type: Coaxial swirl\n- Propellants: LOX (oxidizer), Methane (fuel)\n- O/F ratio: 3.5\n- Pressure drop: 20% of chamber pressure\n\n[PHYSICS_DERIVATION]\n\nStep 1: Mass Flow per Element\nAssume total mdot = 5 kg/s, 19 elements\n$\\dot{m}_{element} = \\frac{5}{19} = 0.263$ kg/s\n$\\dot{m}_{LOX} = \\frac{3.5}{4.5} \\times 0.263 = 0.204$ kg/s\n$\\dot{m}_{CH4} = \\frac{1}{4.5} \\times 0.263 = 0.058$ kg/s\n\nStep 2: LOX Orifice (Central)\n$A_{LOX} = \\frac{\\dot{m}_{LOX}}{C_d \\sqrt{2 \\rho_{LOX} \\Delta P}}$\nCd = 0.7, ρ_LOX = 1141 kg/m³, ΔP = 20 bar\n$A_{LOX} = \\frac{0.204}{0.7 \\sqrt{2 \\times 1141 \\times 2 \\times 10^6}} = 4.3$ mm²\n$D_{LOX} = 2.34$ mm → Round to 2.4 mm\n\nStep 3: Methane Annulus (Swirl)\n$A_{CH4} = \\frac{\\dot{m}_{CH4}}{C_d \\sqrt{2 \\rho_{CH4} \\Delta P}}$\nρ_CH4 = 422 kg/m³\n$A_{CH4} = 2.1$ mm² per tangential inlet\n4 tangential ports: D = 0.82 mm each\n\n[CONSTRAINT_VALIDATION]\n✓ LOX velocity = 45 m/s < 60 m/s (cavitation limit)\n✓ Swirl number Sn = 1.2 (good atomization)\n✓ ΔP/Pc = 20% (stability margin OK)",
|
| 12 |
+
"output": "using PicoGK;\nusing System.Numerics;\n\nnamespace AlgoRythm.RedRock.Injectors\n{\n public class CoaxialSwirlInjector\n {\n const float LOX_ORIFICE_DIAMETER = 2.4f;\n const float ANNULUS_INNER = 3.0f;\n const float ANNULUS_OUTER = 4.5f;\n const float SWIRL_PORT_DIAMETER = 0.82f;\n const int NUM_SWIRL_PORTS = 4;\n const float ELEMENT_LENGTH = 15.0f;\n \n public static Voxels GenerateInjectorElement()\n {\n Voxels voxElement = new Voxels();\n \n // Central LOX post\n float loxRadius = LOX_ORIFICE_DIAMETER / 2.0f;\n Vector3 loxStart = new Vector3(0, 0, 0);\n Vector3 loxEnd = new Vector3(0, 0, ELEMENT_LENGTH);\n \n Voxels voxLOX = Voxels.voxSphere(loxStart, loxRadius + 0.5f);\n Voxels voxLOXinner = Voxels.voxSphere(loxStart, loxRadius);\n voxLOX.BoolSubtract(voxLOXinner);\n voxElement.BoolAdd(voxLOX);\n \n // Fuel annulus with swirl ports\n Voxels voxAnnulus = Voxels.voxSphere(loxStart, ANNULUS_OUTER);\n Voxels voxAnnulusInner = Voxels.voxSphere(loxStart, ANNULUS_INNER);\n voxAnnulus.BoolSubtract(voxAnnulusInner);\n voxElement.BoolAdd(voxAnnulus);\n \n return voxElement;\n }\n }\n}"
|
| 13 |
+
}
|
| 14 |
+
]
|
datasets/universal_csg.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Prandtl Aero — Universal CSG Builder
|
| 3 |
+
Generates random but valid "General Mechanical" and "Universal Gadget" designs.
|
| 4 |
+
Teaches the model the "Language of Shape" beyond just rockets.
|
| 5 |
+
"""
|
| 6 |
+
import random, math
|
| 7 |
+
import advanced_physics
|
| 8 |
+
|
| 9 |
+
# ... (Previous CSGNode classes unchanged)
|
| 10 |
+
|
| 11 |
+
def gen_mounting_bracket():
|
| 12 |
+
"""Generates an L-shaped or U-shaped mounting bracket with bolt holes"""
|
| 13 |
+
|
| 14 |
+
# 1. Base Dimensions
|
| 15 |
+
length = random.randint(50, 150)
|
| 16 |
+
width = random.randint(40, 80)
|
| 17 |
+
thickness = random.choice([5, 8, 10, 12])
|
| 18 |
+
height = random.randint(40, 100)
|
| 19 |
+
|
| 20 |
+
type_ = random.choice(["L-bracket", "U-bracket", "Gusseted bracket"])
|
| 21 |
+
mat = random.choice(["Aluminium 6061", "Steel 316L", "Titanium Gr5"])
|
| 22 |
+
load = random.randint(500, 5000) # Newtons
|
| 23 |
+
|
| 24 |
+
# --- DEEP PHYSICS (Beam Theory) ---
|
| 25 |
+
# Model upright as cantilever beam: Sigma = M*y/I
|
| 26 |
+
M = load * (height/1000) # Nm
|
| 27 |
+
c = (thickness/1000) / 2 # m
|
| 28 |
+
I = (width/1000) * (thickness/1000)**3 / 12 # m^4
|
| 29 |
+
sigma_bending = (M * c) / I / 1e6 # MPa
|
| 30 |
+
|
| 31 |
+
# Von Mises Check
|
| 32 |
+
sigma_vm = advanced_physics.calc_von_mises_stress(sigma_bending, 0, 0, 0, 0, 0)
|
| 33 |
+
|
| 34 |
+
# Get Yield Strength (Room Temp approx)
|
| 35 |
+
yield_str, _ = advanced_physics.get_material_properties(mat, 300)
|
| 36 |
+
# Adjust for Aluminium (not in advanced_physics defaults, add fallback)
|
| 37 |
+
if "Aluminium" in mat: yield_str = 276.0
|
| 38 |
+
if "Steel" in mat: yield_str = 290.0 # 316L
|
| 39 |
+
|
| 40 |
+
mos = advanced_physics.check_margin_of_safety_aerospace(yield_str, sigma_vm)
|
| 41 |
+
|
| 42 |
+
description = f"Design a {type_} from {mat} to support a {load}N load. Dimensions: Base {length}x{width}mm, Height {height}mm."
|
| 43 |
+
|
| 44 |
+
reasoning = f"""[REQUIREMENTS_PARSE]
|
| 45 |
+
Design {type_} for {load}N load. Material: {mat}.
|
| 46 |
+
Geometry: {length}x{width}x{height}mm. Thickness: {thickness}mm.
|
| 47 |
+
|
| 48 |
+
[PHYSICS_DERIVATION]
|
| 49 |
+
1. **Load Case (Cantilever):**
|
| 50 |
+
Moment M = F * L = {load} * {height/1000:.3f} = {M:.1f} Nm.
|
| 51 |
+
2. **Stress Analysis:**
|
| 52 |
+
Section Modulus Z = I/c = {I/c:.2e} m³.
|
| 53 |
+
Bending Stress σ = M/Z = {sigma_bending:.1f} MPa.
|
| 54 |
+
3. **Failure Criteria (Von Mises):**
|
| 55 |
+
σ_vm = {sigma_vm:.1f} MPa.
|
| 56 |
+
Yield Strength = {yield_str} MPa.
|
| 57 |
+
Margin of Safety = ({yield_str} / ({sigma_vm:.1f} * 1.4)) - 1 = {mos:.2f}
|
| 58 |
+
|
| 59 |
+
[CONSTRAINT_VALIDATION]
|
| 60 |
+
1. **Structural Integrity:** {'PASS (MoS > 0)' if mos > 0 else 'FAIL - INCREASE THICKNESS'}.
|
| 61 |
+
2. **L-PBF Printability:** {advanced_physics.analyze_geometry_printability('Overhang', 90)[1]}
|
| 62 |
+
|
| 63 |
+
[DESIGN_LOGIC]
|
| 64 |
+
- Fillets added (r=5mm) to reduce stress concentration factors (Kt).
|
| 65 |
+
- Bolt pattern sized for M6 clearance."""
|
| 66 |
+
|
| 67 |
+
code = f"""// AlgoRythm Prandtl Aero — {type_}
|
| 68 |
+
using PicoGK;
|
| 69 |
+
using System.Numerics;
|
| 70 |
+
|
| 71 |
+
namespace AlgoRythm.PrandtlAero.Mechanical
|
| 72 |
+
{{
|
| 73 |
+
public class BracketGenerator
|
| 74 |
+
{{
|
| 75 |
+
public static Voxels Generate()
|
| 76 |
+
{{
|
| 77 |
+
// 1. Base Plate
|
| 78 |
+
Mesh mshBase = Utils.mshCreateCube(new Vector3({length}f, {width}f, {thickness}f));
|
| 79 |
+
Voxels voxBase = new Voxels(mshBase);
|
| 80 |
+
|
| 81 |
+
// 2. Upright
|
| 82 |
+
Mesh mshUpright = Utils.mshCreateCube(new Vector3({thickness}f, {width}f, {height}f));
|
| 83 |
+
Voxels voxUpright = new Voxels(mshUpright);
|
| 84 |
+
// Move upright to end of base
|
| 85 |
+
voxUpright.Translate(new Vector3({length/2 - thickness/2}f, 0, {height/2}f));
|
| 86 |
+
|
| 87 |
+
// Union
|
| 88 |
+
voxBase.BoolAdd(voxUpright);
|
| 89 |
+
|
| 90 |
+
// 3. Fillet (Stress Relief)
|
| 91 |
+
voxBase.Dilate(5.0f);
|
| 92 |
+
voxBase.Erode(5.0f);
|
| 93 |
+
|
| 94 |
+
return voxBase;
|
| 95 |
+
}}
|
| 96 |
+
}}
|
| 97 |
+
}}"""
|
| 98 |
+
|
| 99 |
+
return {"id": f"brack_{random.randint(1000,9999)}", "input": description, "reasoning": reasoning, "output": code}
|
| 100 |
+
|
| 101 |
+
def gen_enclosure():
|
| 102 |
+
"""Generates an electronic enclosure box with lid"""
|
| 103 |
+
w = random.randint(80, 200)
|
| 104 |
+
l = random.randint(80, 200)
|
| 105 |
+
h = random.randint(30, 80)
|
| 106 |
+
wall = 3.0
|
| 107 |
+
|
| 108 |
+
# --- DEEP PHYSICS (Plate Theory) ---
|
| 109 |
+
# Check max deflection of lid under vacuum/pressure load (1 atm)
|
| 110 |
+
# Plate D = Et^3 / 12(1-v^2)
|
| 111 |
+
E = 69000 # Al 6061 MPa
|
| 112 |
+
q_load = 0.1 # MPa (1 bar pressure differential)
|
| 113 |
+
b = min(w, l)
|
| 114 |
+
max_deflection = (0.142 * q_load * b**4) / (E * wall**3) # Simplified Roark's formula
|
| 115 |
+
|
| 116 |
+
# Thermal Distortion
|
| 117 |
+
delta_T_thermal = advanced_physics.predict_thermal_distortion(max(w, l, h), 50, 23e-6) # 50C rise, Alum CTE
|
| 118 |
+
|
| 119 |
+
description = f"Design a rugged enclosure box {w}x{l}x{h}mm with {wall}mm wall thickness."
|
| 120 |
+
|
| 121 |
+
reasoning = f"""[REQUIREMENTS_PARSE]
|
| 122 |
+
Design Enclosure: {w}x{l}x{h}mm. Wall: {wall}mm.
|
| 123 |
+
Objective: IP67 Sealing & Structural Stiffness.
|
| 124 |
+
|
| 125 |
+
[PHYSICS_DERIVATION]
|
| 126 |
+
1. **Stiffness Check (Plate Theory):**
|
| 127 |
+
Max Deflection (1 bar load) = {max_deflection:.3f} mm.
|
| 128 |
+
Allowable < 1.0mm (to prevent seal breach). -> {'PASS' if max_deflection < 1.0 else 'WARN: Ribs required'}
|
| 129 |
+
2. **Thermal Stability:**
|
| 130 |
+
Max Expansion (dT=50C) = {delta_T_thermal:.3f} mm.
|
| 131 |
+
Gasket compression set must accommodate > {delta_T_thermal:.3f} mm movement.
|
| 132 |
+
|
| 133 |
+
[CONSTRAINT_VALIDATION]
|
| 134 |
+
1. **L-PBF Manufacturing:**
|
| 135 |
+
Internal overhangs: 90 deg (Bridge). Pass < 10mm.
|
| 136 |
+
Selected bridging distance: {w-2*wall}mm. -> REQUIRES SUPPORT.
|
| 137 |
+
|
| 138 |
+
[DESIGN_LOGIC]
|
| 139 |
+
- Shell generated via CSG Subtract.
|
| 140 |
+
- Lid interface generated with 0.5mm tolerance gap."""
|
| 141 |
+
|
| 142 |
+
code = f"""// AlgoRythm Prandtl Aero — Rugged Enclosure
|
| 143 |
+
using PicoGK;
|
| 144 |
+
using System.Numerics;
|
| 145 |
+
|
| 146 |
+
namespace AlgoRythm.PrandtlAero.Mechanical
|
| 147 |
+
{{
|
| 148 |
+
public class EnclosureGenerator
|
| 149 |
+
{{
|
| 150 |
+
public static Voxels Generate()
|
| 151 |
+
{{
|
| 152 |
+
// Outer Shell
|
| 153 |
+
Voxels voxBox = new Voxels(Utils.mshCreateCube(new Vector3({w}f, {l}f, {h}f)));
|
| 154 |
+
|
| 155 |
+
// Inner Cavity
|
| 156 |
+
Voxels voxCavity = new Voxels(Utils.mshCreateCube(new Vector3({w-2*wall}f, {l-2*wall}f, {h}f)));
|
| 157 |
+
voxCavity.Translate(new Vector3(0, 0, {wall}f));
|
| 158 |
+
|
| 159 |
+
// Shelling
|
| 160 |
+
voxBox.BoolSubtract(voxCavity);
|
| 161 |
+
|
| 162 |
+
// Add Bosses
|
| 163 |
+
float fBossX = {w/2 - 10}f;
|
| 164 |
+
float fBossY = {l/2 - 10}f;
|
| 165 |
+
// ... (Loop to add 4 bosses)
|
| 166 |
+
|
| 167 |
+
return voxBox;
|
| 168 |
+
}}
|
| 169 |
+
}}
|
| 170 |
+
}}"""
|
| 171 |
+
|
| 172 |
+
return {"id": f"box_{random.randint(1000,9999)}", "input": description, "reasoning": reasoning, "output": code}
|
| 173 |
+
|
| 174 |
+
# === API ===
|
| 175 |
+
def generate_generic_batch(count=100):
|
| 176 |
+
data = []
|
| 177 |
+
print(f"Generatring {count} generic mechanical parts...")
|
| 178 |
+
for _ in range(count):
|
| 179 |
+
if random.random() < 0.5:
|
| 180 |
+
data.append(gen_mounting_bracket())
|
| 181 |
+
else:
|
| 182 |
+
data.append(gen_enclosure())
|
| 183 |
+
return data
|
datasets/verify_data.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Quick verification script for generated dataset"""
|
| 2 |
+
import json
|
| 3 |
+
|
| 4 |
+
with open("datasets/synthetic_nozzles.json") as f:
|
| 5 |
+
data = json.load(f)
|
| 6 |
+
|
| 7 |
+
print(f"Total examples: {len(data)}")
|
| 8 |
+
|
| 9 |
+
# Count types
|
| 10 |
+
types = {}
|
| 11 |
+
for ex in data:
|
| 12 |
+
t = ex["id"].split("_")[0]
|
| 13 |
+
types[t] = types.get(t, 0) + 1
|
| 14 |
+
print("\nComposition:")
|
| 15 |
+
for t, c in sorted(types.items(), key=lambda x: -x[1]):
|
| 16 |
+
print(f" {t}: {c}")
|
| 17 |
+
|
| 18 |
+
# Check nozzle dimensions
|
| 19 |
+
print("\nNozzle Spot Checks:")
|
| 20 |
+
nozzles = [e for e in data if e["id"].startswith("nozzle")]
|
| 21 |
+
for ex in nozzles[:5]:
|
| 22 |
+
r = ex["reasoning"]
|
| 23 |
+
for line in r.split("\n"):
|
| 24 |
+
line = line.strip()
|
| 25 |
+
if "D* =" in line and "mm" in line:
|
| 26 |
+
print(f" [{ex['id']}] {line[:80]}")
|
| 27 |
+
if "MoS =" in line and "mm" not in line:
|
| 28 |
+
print(f" [{ex['id']}] {line[:80]}")
|
| 29 |
+
|
| 30 |
+
# Check for negative MoS without failure
|
| 31 |
+
print("\nMoS Check:")
|
| 32 |
+
neg_mos = 0
|
| 33 |
+
for ex in data:
|
| 34 |
+
if "MoS = -" in ex.get("reasoning",""):
|
| 35 |
+
neg_mos += 1
|
| 36 |
+
print(f" Examples with negative MoS: {neg_mos}")
|
| 37 |
+
print(f" Examples with positive MoS: {len(data) - neg_mos}")
|