STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
graphite_variable_thickness.py
Go to the documentation of this file.
1"""Variable thickness graphite insert that conforms to chamber geometry.
2
3The graphite insert should follow the chamber internal contour with variable thickness
4based on local heat flux and thermal requirements.
5"""
6
7from __future__ import annotations
8
9from typing import Dict, Optional, Tuple
10import numpy as np
11from engine.pipeline.config_schemas import GraphiteInsertConfig
12
13
15 positions: np.ndarray,
16 R_gas: np.ndarray,
17 heat_flux_profile: np.ndarray,
18 graphite_config: GraphiteInsertConfig,
19 recession_profile: Optional[np.ndarray] = None,
20) -> Dict[str, np.ndarray]:
21 """
22 Calculate variable thickness graphite insert profile conforming to chamber geometry.
23
24 The graphite insert follows the chamber internal contour (gas boundary) with
25 thickness varying based on local heat flux and thermal requirements.
26
27 Parameters:
28 -----------
29 positions : np.ndarray
30 Axial positions [m]
31 R_gas : np.ndarray
32 Gas boundary radius [m] (chamber internal contour)
33 heat_flux_profile : np.ndarray
34 Local heat flux [W/m²] at each position
35 graphite_config : GraphiteInsertConfig
36 Graphite configuration
37 recession_profile : np.ndarray, optional
38 Local recession [m] at each position
39
40 Returns:
41 --------
42 profile : dict
43 - R_inner: Inner radius (gas boundary) [m]
44 - R_outer: Outer radius (graphite outer surface) [m]
45 - thickness: Local thickness [m]
46 - thickness_remaining: Remaining thickness after recession [m]
47 """
48 n_points = len(positions)
49
50 # Inner radius follows gas boundary
51 R_inner = R_gas.copy()
52
53 # Base thickness from config
54 base_thickness = graphite_config.initial_thickness
55
56 # Calculate thickness variation based on heat flux
57 # Higher heat flux = thicker graphite needed
58 if len(heat_flux_profile) == n_points:
59 avg_heat_flux = np.mean(heat_flux_profile)
60 # Physics-based thickness scaling
61 from engine.pipeline.physics_based_replacements import calculate_graphite_thickness_multiplier_physics
62
63 # Calculate surface temperature (simplified - would come from thermal analysis)
64 surface_temp = 2000.0 # K, typical graphite surface temp
65 backface_temp_limit = 500.0 # K, typical limit
66
67 thickness = np.zeros(n_points)
68 for i in range(n_points):
69 multiplier = calculate_graphite_thickness_multiplier_physics(
70 heat_flux_local=heat_flux_profile[i],
71 heat_flux_avg=avg_heat_flux,
72 thermal_conductivity=graphite_config.thermal_conductivity,
73 backface_temp_limit=backface_temp_limit,
74 surface_temp=surface_temp,
75 )
76 thickness[i] = base_thickness * multiplier
77 else:
78 # Uniform thickness if no heat flux profile
79 thickness = np.full(n_points, base_thickness)
80
81 # Apply recession if provided
82 if recession_profile is not None and len(recession_profile) == n_points:
83 thickness_remaining = np.maximum(thickness - recession_profile, 0.0)
84 else:
85 thickness_remaining = thickness.copy()
86
87 # Outer radius = inner radius + thickness
88 R_outer = R_inner + thickness_remaining
89
90 return {
91 "R_inner": R_inner,
92 "R_outer": R_outer,
93 "thickness": thickness,
94 "thickness_remaining": thickness_remaining,
95 "positions": positions,
96 }
97
98
100 L_chamber: float,
101 D_chamber: float,
102 D_throat: float,
103 positions_chamber: np.ndarray,
104 R_gas_chamber: np.ndarray,
105 heat_flux_chamber: np.ndarray,
106 graphite_config: GraphiteInsertConfig,
107 graphite_start: float,
108 graphite_end: float,
109 recession_graphite: float = 0.0,
110) -> Dict[str, np.ndarray]:
111 """
112 Calculate graphite insert geometry that conforms to chamber internal contour.
113
114 The graphite insert:
115 1. Follows the chamber gas boundary (inner surface)
116 2. Has variable thickness based on local heat flux
117 3. Extends from graphite_start to graphite_end
118
119 Parameters:
120 -----------
121 L_chamber : float
122 Chamber length [m]
123 D_chamber : float
124 Chamber diameter [m]
125 D_throat : float
126 Throat diameter [m]
127 positions_chamber : np.ndarray
128 Axial positions along chamber [m]
129 R_gas_chamber : np.ndarray
130 Gas boundary radius along chamber [m]
131 heat_flux_chamber : np.ndarray
132 Heat flux along chamber [W/m²]
133 graphite_config : GraphiteInsertConfig
134 Graphite configuration
135 graphite_start : float
136 Graphite insert start position [m]
137 graphite_end : float
138 Graphite insert end position [m]
139 recession_graphite : float
140 Cumulative graphite recession [m]
141
142 Returns:
143 --------
144 geometry : dict
145 - positions: Axial positions in graphite region [m]
146 - R_inner: Inner radius (gas boundary) [m]
147 - R_outer: Outer radius (graphite outer) [m]
148 - thickness: Local thickness [m]
149 - thickness_remaining: Remaining thickness [m]
150 """
151 # Find positions within graphite region
152 graphite_mask = (positions_chamber >= graphite_start) & (positions_chamber <= graphite_end)
153
154 if not np.any(graphite_mask):
155 # No graphite region, return empty
156 return {
157 "positions": np.array([]),
158 "R_inner": np.array([]),
159 "R_outer": np.array([]),
160 "thickness": np.array([]),
161 "thickness_remaining": np.array([]),
162 }
163
164 # Extract graphite region
165 positions_graphite = positions_chamber[graphite_mask]
166 R_gas_graphite = R_gas_chamber[graphite_mask]
167 heat_flux_graphite = heat_flux_chamber[graphite_mask] if len(heat_flux_chamber) == len(positions_chamber) else np.full(len(positions_graphite), np.mean(heat_flux_chamber))
168
169 # Create recession profile (uniform for now, could be spatial)
170 recession_profile = np.full(len(positions_graphite), recession_graphite)
171
172 # Calculate variable thickness profile
174 positions_graphite,
175 R_gas_graphite,
176 heat_flux_graphite,
177 graphite_config,
178 recession_profile=recession_profile,
179 )
180
181 return profile
182
Dict[str, np.ndarray] calculate_graphite_geometry_conforming(float L_chamber, float D_chamber, float D_throat, np.ndarray positions_chamber, np.ndarray R_gas_chamber, np.ndarray heat_flux_chamber, GraphiteInsertConfig graphite_config, float graphite_start, float graphite_end, float recession_graphite=0.0)
Dict[str, np.ndarray] calculate_graphite_thickness_profile(np.ndarray positions, np.ndarray R_gas, np.ndarray heat_flux_profile, GraphiteInsertConfig graphite_config, Optional[np.ndarray] recession_profile=None)