1"""Unit tests for safety filter module."""
5from unittest.mock
import Mock
10 _tube_violates_constraints,
11 _find_best_safe_action,
12 _generate_action_candidates,
21 """Test safety filter."""
24 """Set up test fixtures."""
59 w_bar_array=np.ones(8) * 0.1e6,
66 """Test tube constraint violation for ullage max."""
70 x_hi[IDX_P_U_F] = 11e6
72 violates = _tube_violates_constraints(x_lo, x_hi, self.
cfg,
None)
73 self.assertTrue(violates)
76 """Test tube constraint violation for COPV min."""
80 x_hi[IDX_P_COPV] = 0.5e6
82 violates = _tube_violates_constraints(x_lo, x_hi, self.
cfg,
None)
83 self.assertTrue(violates)
86 """Test tube constraint violation for MR bounds."""
97 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
103 self.assertTrue(violates)
106 """Test tube that satisfies all constraints."""
120 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
123 self.assertFalse(violates)
126 """Test action candidate generation."""
127 candidates = _generate_action_candidates(self.
cfg)
130 self.assertGreaterEqual(len(candidates), 4)
139 candidate_set = {tuple(c)
for c
in candidates}
140 self.assertTrue(binary_set.issubset(candidate_set))
143 """Test action cost computation."""
144 u = np.array([0.5, 0.5])
147 cost = _compute_action_cost(
150 self.assertGreater(cost, 0.0)
162 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
164 cost_with_ref = _compute_action_cost(
167 self.assertGreater(cost_with_ref, cost)
170 """Test filter_action with safe proposed action."""
172 proposed = np.array([0.5, 0.5])
184 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
186 safe_action = filter_action(
195 np.testing.assert_array_almost_equal(safe_action, proposed, decimal=3)
198 """Test filter_action with unsafe action that violates ullage max."""
201 proposed = np.array([1.0, 1.0])
213 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
216 safe_action = filter_action(
227 self.assertIsNotNone(safe_action)
228 self.assertTrue(np.all(safe_action >= 0.0))
229 self.assertTrue(np.all(safe_action <= 1.0))
232 """Test filter_action with unsafe action that violates MR bounds."""
234 proposed = np.array([0.1, 1.0])
259 def mock_estimate(P_d_F, P_d_O):
262 return eng_est_high_mr
263 return eng_est_normal
265 self.
engine_wrapper.estimate_from_pressures = Mock(side_effect=mock_estimate)
267 safe_action = filter_action(
277 self.assertIsNotNone(safe_action)
279 self.assertTrue(safe_action[0] > proposed[0]
or safe_action[1] < proposed[1])
282 """Test filter_action clamps inputs."""
284 proposed = np.array([-0.1, 1.5])
295 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
297 safe_action = filter_action(
306 self.assertTrue(np.all(safe_action >= 0.0))
307 self.assertTrue(np.all(safe_action <= 1.0))
310 """Test finding best safe action from candidates."""
312 proposed = np.array([1.0, 1.0])
323 self.
engine_wrapper.estimate_from_pressures = Mock(return_value=eng_est)
325 w_bar = get_w_bar_array(self.
state)
327 best_action = _find_best_safe_action(
340 self.assertIsNotNone(best_action)
341 self.assertEqual(best_action.shape, (2,))
342 self.assertTrue(np.all(best_action >= 0.0))
343 self.assertTrue(np.all(best_action <= 1.0))
346if __name__ ==
"__main__":
test_find_best_safe_action(self)
test_tube_violates_constraints_ullage_max(self)
test_generate_action_candidates(self)
test_tube_violates_constraints_safe(self)
test_filter_action_safe(self)
test_compute_action_cost(self)
test_filter_action_clamping(self)
test_filter_action_unsafe_ullage(self)
test_filter_action_unsafe_mr(self)
test_tube_violates_constraints_copv_min(self)
test_tube_violates_constraints_mr(self)