16 segments: List[Dict[str, Any]],
18) -> Tuple[np.ndarray, np.ndarray]:
20 Generate a pressure curve from a list of segments.
22 Each segment can be 'linear' or 'blowdown' with its own duration and pressures.
25 segments: List of segment dicts with keys:
26 - type: 'linear' or 'blowdown'
27 - duration: segment duration in seconds
28 - start_pressure_psi: pressure at start of segment
29 - end_pressure_psi: pressure at end of segment
30 - decay_tau: time constant for blowdown (only for blowdown type)
31 n_points: Total number of points in output array
34 time_array: Array of time points [s]
35 pressure_array: Array of pressures [psi]
38 return np.array([0.0]), np.array([500.0])
41 total_duration = sum(seg[
"duration"]
for seg
in segments)
44 time_array = np.linspace(0, total_duration, n_points)
45 pressure_array = np.zeros(n_points)
50 seg_type = seg[
"type"]
51 seg_duration = seg[
"duration"]
52 P_start = seg[
"start_pressure_psi"]
53 P_end = seg[
"end_pressure_psi"]
54 t_end = t_start + seg_duration
57 mask = (time_array >= t_start) & (time_array <= t_end)
58 t_local = time_array[mask] - t_start
60 if seg_type ==
"linear":
63 pressure_array[mask] = P_start + (P_end - P_start) * t_local / seg_duration
65 pressure_array[mask] = P_start
66 elif seg_type ==
"blowdown":
68 tau = seg.get(
"decay_tau", seg_duration * 0.3)
70 tau = seg_duration * 0.3
71 pressure_array[mask] = P_end + (P_start - P_end) * np.exp(-t_local / tau)
75 pressure_array[mask] = P_start + (P_end - P_start) * t_local / seg_duration
77 pressure_array[mask] = P_start
81 return time_array, pressure_array
85 x_segments: np.ndarray,
87 base_pressure_psi: float,
88 target_burn_time: float,
89 use_initial_as_base: bool =
False,
90) -> List[Dict[str, Any]]:
92 Convert optimizer variables to segment list.
94 For each segment, optimizer provides:
95 - type (0=linear, 1=blowdown) - rounded to int
96 - duration_ratio (0-1, fraction of total burn time)
97 - start_pressure_ratio (0.7-1.0 for regulation, 0.3-1.0 for blowdown, ratio of base pressure)
98 - end_pressure_ratio (0.7-1.0 for regulation, 0.3-1.0 for blowdown, ratio of base pressure)
99 - decay_tau_ratio (0-1, fraction of segment duration, only for blowdown)
102 x_segments: Array of optimizer variables for segments
103 n_segments: Number of segments (1-20)
104 base_pressure_psi: Base pressure [psi] - either max (blowdown) or initial (regulation)
105 target_burn_time: Total burn time [s]
106 use_initial_as_base: If True, base_pressure_psi is initial pressure (for regulation)
107 If False, base_pressure_psi is max pressure (for blowdown)
110 List of segment dicts
116 max_available_segments = len(x_segments) // vars_per_segment
117 n_segments =
min(n_segments, max_available_segments)
124 for i
in range(n_segments):
125 idx_base = i * vars_per_segment
126 if idx_base + 4 >= len(x_segments):
128 duration_ratio = float(np.clip(x_segments[idx_base + 1], 0.01, 1.0))
129 duration_ratios.append(duration_ratio)
132 total_ratio = sum(duration_ratios)
134 duration_ratios = [dr / total_ratio
for dr
in duration_ratios]
137 for i
in range(n_segments):
138 idx_base = i * vars_per_segment
139 if idx_base + 4 >= len(x_segments):
141 seg_type_val = float(np.clip(x_segments[idx_base], 0.0, 1.0))
142 seg_type =
"blowdown" if seg_type_val >= 0.5
else "linear"
143 duration = duration_ratios[i] * target_burn_time
if i < len(duration_ratios)
else target_burn_time / n_segments
148 if use_initial_as_base:
150 start_ratio = float(np.clip(x_segments[idx_base + 2], 0.7, 1.0))
151 end_ratio_raw = float(np.clip(x_segments[idx_base + 3], 0.7, 1.0))
154 end_ratio = end_ratio_raw
157 start_ratio = float(np.clip(x_segments[idx_base + 2], 0.1, 1.0))
158 end_ratio_raw = float(np.clip(x_segments[idx_base + 3], 0.1, 1.0))
160 end_ratio =
min(end_ratio_raw, start_ratio)
162 tau_ratio = float(np.clip(x_segments[idx_base + 4], 0.1, 1.0))
165 start_pressure_psi = start_ratio * base_pressure_psi
166 end_pressure_psi = end_ratio * base_pressure_psi
170 "duration": duration,
171 "start_pressure_psi": start_pressure_psi,
172 "end_pressure_psi": end_pressure_psi,
175 if seg_type ==
"blowdown":
176 seg[
"decay_tau"] = duration * tau_ratio
184 segments: List[Dict[str, Any]],
185 max_pressure_psi: float,
186 target_burn_time: float,
189 Convert segment list to optimizer variables.
191 Inverse of segments_from_optimizer_vars.
194 n_segments = len(segments)
195 x = np.zeros(n_segments * vars_per_segment)
197 total_duration = sum(seg[
"duration"]
for seg
in segments)
199 for i, seg
in enumerate(segments):
200 idx_base = i * vars_per_segment
201 x[idx_base] = 1.0
if seg[
"type"] ==
"blowdown" else 0.0
202 x[idx_base + 1] = seg[
"duration"] / total_duration
if total_duration > 0
else 1.0 / n_segments
203 x[idx_base + 2] = seg[
"start_pressure_psi"] / max_pressure_psi
204 x[idx_base + 3] = seg[
"end_pressure_psi"] / max_pressure_psi
205 x[idx_base + 4] = seg.get(
"decay_tau", seg[
"duration"] * 0.3) / seg[
"duration"]
if seg[
"duration"] > 0
else 0.3
List[Dict[str, Any]] segments_from_optimizer_vars(np.ndarray x_segments, int n_segments, float base_pressure_psi, float target_burn_time, bool use_initial_as_base=False)