@@ -74,8 +74,13 @@ def test_flight_with_3d_drag_basic(example_plain_env, cesaroni_m1670):
7474 assert hasattr (flight , "angle_of_attack" )
7575
7676
77- def test_3d_drag_with_varying_alpha (example_plain_env , cesaroni_m1670 ):
78- """Test that 3D drag responds to angle of attack changes."""
77+ def test_3d_drag_with_varying_alpha ():
78+ """Test that 3D drag responds to angle of attack changes.
79+
80+ This test only verifies the Function mapping from alpha -> Cd. The
81+ integration-level comparison is placed in a separate test to keep each
82+ test function small and easier to lint/maintain.
83+ """
7984 # Create drag function with strong alpha dependency
8085 mach = np .array ([0.0 , 0.5 , 1.0 , 1.5 ])
8186 reynolds = np .array ([1e5 , 1e6 ])
@@ -102,103 +107,50 @@ def test_3d_drag_with_varying_alpha(example_plain_env, cesaroni_m1670):
102107 assert cd_10 > cd_0
103108 assert cd_10 - cd_0 > 0.2 # Should show significant difference
104109
105- # --- Integration test: verify flight uses alpha-dependent Cd ---
106- # Create a flat (alpha-agnostic) drag by averaging over alpha
107- cd_flat = cd_data .mean (axis = 2 )
108- drag_flat = Function .from_grid (
109- cd_flat ,
110- [mach , reynolds ],
111- inputs = ["Mach" , "Reynolds" ],
112- outputs = "Cd" ,
113- )
114-
115- # Use fixtures for environment and motor
116- env = example_plain_env
117- env .set_atmospheric_model (type = "standard_atmosphere" )
118- motor = cesaroni_m1670
119-
120- # Build two rockets: one that uses alpha-sensitive drag, one flat
121- rocket_alpha = Rocket (
122- radius = 0.0635 ,
123- mass = 16.24 ,
124- inertia = (6.321 , 6.321 , 0.034 ),
125- power_off_drag = drag_func ,
126- power_on_drag = drag_func ,
127- center_of_mass_without_motor = 0 ,
128- coordinate_system_orientation = "tail_to_nose" ,
129- )
130- rocket_alpha .set_rail_buttons (0.2 , - 0.5 , 30 )
131- rocket_alpha .add_motor (motor , position = - 1.255 )
132-
133- rocket_flat = Rocket (
134- radius = 0.0635 ,
135- mass = 16.24 ,
136- inertia = (6.321 , 6.321 , 0.034 ),
137- power_off_drag = drag_flat ,
138- power_on_drag = drag_flat ,
139- center_of_mass_without_motor = 0 ,
140- coordinate_system_orientation = "tail_to_nose" ,
141- )
142- rocket_flat .set_rail_buttons (0.2 , - 0.5 , 30 )
143- rocket_flat .add_motor (motor , position = - 1.255 )
144-
145- # Run flights
146- flight_alpha = Flight (
147- rocket = rocket_alpha ,
148- environment = env ,
149- rail_length = 5.2 ,
150- inclination = 85 ,
151- heading = 0 ,
152- )
153110
154- flight_flat = Flight (
155- rocket = rocket_flat ,
156- environment = env ,
157- rail_length = 5.2 ,
158- inclination = 85 ,
159- heading = 0 ,
160- )
111+ def test_flight_apogee_diff (flight_alpha , flight_flat ):
112+ """Run paired flights (fixtures) and assert their apogees differ."""
161113
162114 # Flights should both launch
163115 assert flight_alpha .apogee > 100
164116 assert flight_flat .apogee > 100
165117
166- # The two rockets should behave differently since one depends on alpha
167- # while the other uses a flat-averaged Cd. Do not assume which direction
168- # is larger (depends on encountered alpha vs averaged alpha) but ensure
169- # the apogees differ.
118+ # Apogees should differ
170119 assert flight_alpha .apogee != flight_flat .apogee
171120
172- # Additionally, sample Cd during flight from aerodynamic state and
173- # compare values computed from each rocket's drag function at the
174- # same time index to ensure alpha actually affects the evaluated Cd.
175- # Use mid-ascent index (avoid t=0). Find a time index where speed > 5 m/s
121+
122+ def test_flight_cd_sample_consistency (flight_alpha , flight_flat ):
123+ """Sample Cd during a flight and ensure Cd difference matches apogee ordering.
124+
125+ Uses the `flight_alpha` and `flight_flat` fixtures which provide paired
126+ flights constructed with alpha-dependent and alpha-averaged Cd functions.
127+ """
128+
129+ # Sample a mid-ascent time and compare Cd evaluations
176130 speeds = flight_alpha .free_stream_speed [:, 1 ]
177- times = flight_alpha .time
178131 idx_candidates = np .where (speeds > 5 )[0 ]
179132 assert idx_candidates .size > 0
180133 idx = idx_candidates [len (idx_candidates ) // 2 ]
181- t_sample = times [idx ]
134+ t_sample = flight_alpha . time [idx ]
182135
183136 mach_sample = flight_alpha .mach_number .get_value_opt (t_sample )
184- rho_sample = flight_alpha .density .get_value_opt (t_sample )
185- mu_sample = flight_alpha .dynamic_viscosity .get_value_opt (t_sample )
186- V_sample = flight_alpha .free_stream_speed .get_value_opt (t_sample )
187- reynolds_sample = rho_sample * V_sample * (2 * rocket_alpha .radius ) / mu_sample
137+ v_sample = flight_alpha .free_stream_speed .get_value_opt (t_sample )
138+ reynolds_sample = (
139+ flight_alpha .density .get_value_opt (t_sample )
140+ * v_sample
141+ * (2 * flight_alpha .rocket .radius )
142+ / flight_alpha .dynamic_viscosity .get_value_opt (t_sample )
143+ )
188144 alpha_sample = flight_alpha .angle_of_attack .get_value_opt (t_sample )
189145
190- cd_alpha_sample = rocket_alpha .power_on_drag .get_value_opt (
146+ cd_alpha_sample = flight_alpha . rocket .power_on_drag .get_value_opt (
191147 mach_sample , reynolds_sample , alpha_sample
192148 )
193- cd_flat_sample = rocket_flat .power_on_drag .get_value_opt (
149+ cd_flat_sample = flight_flat . rocket .power_on_drag .get_value_opt (
194150 mach_sample , reynolds_sample
195151 )
196152
197- # Alpha-sensitive Cd should differ from the flat Cd at the sampled time
198153 assert cd_alpha_sample != cd_flat_sample
199-
200- # Ensure the sign of the Cd difference is consistent with the apogee
201- # ordering: larger Cd -> lower apogee
202154 if cd_alpha_sample > cd_flat_sample :
203155 assert flight_alpha .apogee < flight_flat .apogee
204156 else :
0 commit comments