19 time_history: np.ndarray,
20 recession_history: np.ndarray,
21 D_chamber_initial: float,
22 D_throat_initial: float,
27 Create simple animation showing diameter evolution over time.
30 1. Recession vs time (plot)
31 2. Cross-section evolving (diameter changes over time)
35 time_history : np.ndarray
37 recession_history : np.ndarray
38 Recession array [m] (chamber recession)
39 D_chamber_initial : float
40 Initial chamber diameter [m]
41 D_throat_initial : float
42 Initial throat diameter [m]
46 Maximum number of frames
51 Plotly figure with animation
53 n_steps = len(time_history)
56 if n_steps > max_frames:
57 step =
max(1, n_steps // max_frames)
58 indices = np.arange(0, n_steps, step)
59 time_history = time_history[indices]
60 recession_history = recession_history[indices]
61 n_steps = len(time_history)
64 raise ValueError(
"No time steps")
68 positions = np.linspace(0.0, L_chamber, n_points)
69 throat_pos = L_chamber
75 for i
in range(n_steps):
76 recession = recession_history[i]
79 D_chamber = D_chamber_initial + 2.0 * recession
82 D_throat = D_throat_initial
84 all_D_chamber.append(D_chamber)
85 all_D_throat.append(D_throat)
90 subplot_titles=(
"Recession vs Time",
"Chamber Cross-Section Evolution"),
91 vertical_spacing=0.15,
92 row_heights=[0.3, 0.7],
96 fig.add_trace(go.Scatter(
98 y=recession_history * 1000,
100 name=
'Chamber Recession',
101 line=dict(color=
'red', width=2),
107 D_chamber_0 = all_D_chamber[0]
108 D_throat_0 = all_D_throat[0]
111 R_chamber = D_chamber_0 / 2.0
112 R_throat = D_throat_0 / 2.0
116 throat_idx = np.argmin([D_chamber_0, D_throat_0])
117 throat_pos_actual = L_chamber
119 R_profile = np.zeros(n_points)
120 for i, x
in enumerate(positions):
121 if x < throat_pos_actual * 0.8:
122 R_profile[i] = R_chamber
124 x_conv = (x - throat_pos_actual * 0.8) / (throat_pos_actual * 0.2 + 1e-10)
125 x_conv = np.clip(x_conv, 0.0, 1.0)
126 R_profile[i] = R_chamber + (R_throat - R_chamber) * x_conv
129 fig.add_trace(go.Scatter(
133 name=
'Gas Boundary (t=0)',
134 line=dict(color=
'orange', width=3),
138 fig.add_trace(go.Scatter(
142 name=
'Gas Boundary Lower',
143 line=dict(color=
'orange', width=3),
149 for i
in range(n_steps):
150 D_chamber_i = all_D_chamber[i]
151 D_throat_i = all_D_throat[i]
152 recession_i = recession_history[i]
155 R_chamber_i = D_chamber_i / 2.0
156 R_throat_i = D_throat_i / 2.0
159 throat_pos_actual = L_chamber
161 R_profile_i = np.zeros(n_points)
162 for j, x
in enumerate(positions):
163 if x < throat_pos_actual * 0.8:
164 R_profile_i[j] = R_chamber_i
166 x_conv = (x - throat_pos_actual * 0.8) / (throat_pos_actual * 0.2 + 1e-10)
167 x_conv = np.clip(x_conv, 0.0, 1.0)
168 R_profile_i[j] = R_chamber_i + (R_throat_i - R_chamber_i) * x_conv
171 frames.append(go.Frame(
173 go.Scatter(x=time_history[:i+1], y=recession_history[:i+1] * 1000,
174 mode=
'lines+markers', line=dict(color=
'red', width=2),
175 marker=dict(size=5), name=
'Chamber Recession'),
176 go.Scatter(x=positions, y=R_profile_i, mode=
'lines',
177 line=dict(color=
'orange', width=3), name=
'Gas Boundary'),
178 go.Scatter(x=positions, y=-R_profile_i, mode=
'lines',
179 line=dict(color=
'orange', width=3), showlegend=
False),
190 title=
"Recession Evolution Over Time",
202 "frame": {
"duration": 500,
"redraw":
True},
204 "transition": {
"duration": 0}
211 "frame": {
"duration": 0,
"redraw":
False},
213 "transition": {
"duration": 0}
220 "currentvalue": {
"prefix":
"Time: ",
"suffix":
" s",
"visible":
True},
229 "frame": {
"duration": 300,
"redraw":
True},
231 "transition": {
"duration": 0}
236 for i, t
in enumerate(time_history)
241 fig.update_xaxes(title_text=
"Time [s]", row=1, col=1)
242 fig.update_yaxes(title_text=
"Recession [mm]", row=1, col=1)
243 fig.update_xaxes(title_text=
"Axial Position [m]", row=2, col=1)
244 fig.update_yaxes(title_text=
"Radius [m]", row=2, col=1, scaleanchor=
"x", scaleratio=1)