35 """Create minimal config for testing."""
40 PintleInjectorGeometry,
48 ChamberGeometryConfig,
53 injector=PintleInjectorConfig(
55 geometry=PintleInjectorGeometry(
61 oxidizer=OxidizerGeometry(
62 d_annulus_inner=0.008,
63 d_annulus_outer=0.012,
72 surface_tension=0.025,
74 "oxidizer": FluidConfig(
78 surface_tension=0.013,
82 "fuel": FeedSystemConfig(
88 "oxidizer": FeedSystemConfig(
96 "fuel": DischargeConfig(Cd_inf=0.7),
97 "oxidizer": DischargeConfig(Cd_inf=0.7),
99 combustion=CombustionConfig(
103 expansion_ratio=10.0,
107 chamber_geometry=ChamberGeometryConfig(
112 chamber_diameter=0.08,
118 """Test EngineEstimate dataclass structure."""
129 self.assertEqual(estimate.P_ch, 2e6)
130 self.assertEqual(estimate.F, 1000.0)
131 self.assertEqual(estimate.MR, 2.0)
132 self.assertEqual(estimate.injector_dp_F, 0.5e6)
133 self.assertEqual(estimate.injector_dp_O, 0.5e6)
143 """Test estimate_from_pressures with mocked runner."""
146 mock_runner.evaluate.return_value = {
153 "stability_state":
"stable",
154 "stability_score": 0.8,
155 "chugging": {
"frequency": 100.0},
157 "diagnostics": {
"test":
"value"},
159 mock_runner_class.return_value = mock_runner
163 wrapper.runner = mock_runner
169 estimate = wrapper.estimate_from_pressures(P_d_F, P_d_O)
172 self.assertEqual(estimate.P_ch, 2e6)
173 self.assertEqual(estimate.F, 1000.0)
174 self.assertEqual(estimate.mdot_F, 0.5)
175 self.assertEqual(estimate.mdot_O, 1.0)
176 self.assertEqual(estimate.MR, 2.0)
179 self.assertEqual(estimate.injector_dp_F, P_d_F - 2e6)
180 self.assertEqual(estimate.injector_dp_O, P_d_O - 2e6)
183 self.assertIsNotNone(estimate.stability_metrics)
184 self.assertEqual(estimate.stability_metrics[
"stability_state"],
"stable")
187 mock_runner.evaluate.assert_called_once()
188 call_args = mock_runner.evaluate.call_args
189 self.assertEqual(call_args.kwargs[
"P_tank_F"], P_d_F)
190 self.assertEqual(call_args.kwargs[
"P_tank_O"], P_d_O)
191 self.assertTrue(call_args.kwargs.get(
"silent",
False))
195 """Test estimate when stability results are not available."""
197 mock_runner.evaluate.return_value = {
205 mock_runner_class.return_value = mock_runner
208 wrapper.runner = mock_runner
210 estimate = wrapper.estimate_from_pressures(3e6, 3.5e6)
213 self.assertIsNotNone(estimate.stability_metrics)
214 self.assertIn(
"injector_stiffness_ok", estimate.stability_metrics)
215 self.assertIn(
"injector_dp_frac_F", estimate.stability_metrics)
216 self.assertIn(
"injector_dp_frac_O", estimate.stability_metrics)
220 """Test estimate handles evaluation errors gracefully."""
222 mock_runner.evaluate.side_effect = ValueError(
"Evaluation failed")
223 mock_runner_class.return_value = mock_runner
226 wrapper.runner = mock_runner
228 estimate = wrapper.estimate_from_pressures(3e6, 3.5e6)
231 self.assertTrue(np.isnan(estimate.P_ch))
232 self.assertTrue(np.isnan(estimate.F))
233 self.assertTrue(np.isnan(estimate.mdot_F))
234 self.assertIsNotNone(estimate.diagnostics)
235 self.assertIn(
"error", estimate.diagnostics)
238 """Test that caching works correctly."""
242 call_count = {
"count": 0}
243 def mock_evaluate(**kwargs):
244 call_count[
"count"] += 1
254 wrapper.runner.evaluate = mock_evaluate
259 estimate1 = wrapper.estimate_from_pressures(P_d_F, P_d_O, use_cache=
True)
260 self.assertEqual(call_count[
"count"], 1)
263 estimate2 = wrapper.estimate_from_pressures(P_d_F, P_d_O, use_cache=
True)
264 self.assertEqual(call_count[
"count"], 1)
265 self.assertEqual(estimate1.P_ch, estimate2.P_ch)
268 estimate3 = wrapper.estimate_from_pressures(P_d_F, P_d_O, use_cache=
False)
269 self.assertEqual(call_count[
"count"], 2)
296 """Test convenience function."""
297 with patch(
'engine.control.robust_ddp.engine_wrapper.EngineWrapper')
as mock_wrapper_class:
298 mock_wrapper = Mock()
308 mock_wrapper.estimate_from_pressures.return_value = mock_estimate
309 mock_wrapper_class.return_value = mock_wrapper
311 estimate = estimate_from_pressures(3e6, 3.5e6, self.
config)
313 self.assertEqual(estimate.P_ch, 2e6)
314 mock_wrapper.estimate_from_pressures.assert_called_once_with(3e6, 3.5e6, use_cache=
True)