@@ -132,49 +132,125 @@ end
132132
133133 # Test combinations of input variations
134134 @testset " Combined Input Variations" begin
135- # Sample some key combinations
135+ # For combination testing, we'll create targeted test cases
136+ # that use only the specific indices we want to test together
136137 combination_tests = [
137- (" Theta + VA" , [dtheta_magnitudes[1 ] * ones (4 ); dva_magnitudes[1 ] * ones (3 ); zeros (3 ); zeros (4 )]),
138- (" Theta + Omega" , [dtheta_magnitudes[1 ] * ones (4 ); zeros (3 ); domega_magnitudes[1 ] * ones (3 ); zeros (4 )]),
139- (" VA + Omega" , [zeros (4 ); dva_magnitudes[1 ] * ones (3 ); domega_magnitudes[1 ] * ones (3 ); zeros (4 )]),
140- (" Delta + VA" , [zeros (4 ); dva_magnitudes[1 ] * ones (3 ); zeros (3 ); ddelta_magnitudes[1 ] * ones (4 )]),
141- (" All Inputs" , [dtheta_magnitudes[1 ] * ones (4 ); dva_magnitudes[1 ] * ones (3 );
142- domega_magnitudes[1 ] * ones (3 ); ddelta_magnitudes[1 ] * ones (4 )])
138+ # Name, active indices, perturbation vector, indices mappings
139+ (
140+ " Theta + VA" ,
141+ # Use only theta and va indices
142+ [1 : 4 ; 5 : 7 ],
143+ # Perturbation values for these indices
144+ [dtheta_magnitudes; dva_magnitudes],
145+ # Mappings for linearize function
146+ (theta_idxs= 1 : 4 , va_idxs= 5 : 7 , omega_idxs= nothing , delta_idxs= nothing )
147+ ),
148+ (
149+ " Theta + Omega" ,
150+ [1 : 4 ; 8 : 10 ],
151+ [dtheta_magnitudes; domega_magnitudes],
152+ (theta_idxs= 1 : 4 , va_idxs= nothing , omega_idxs= 5 : 7 , delta_idxs= nothing )
153+ ),
154+ (
155+ " VA + Omega" ,
156+ [5 : 7 ; 8 : 10 ],
157+ [dva_magnitudes; domega_magnitudes],
158+ (theta_idxs= nothing , va_idxs= 1 : 3 , omega_idxs= 4 : 6 , delta_idxs= nothing )
159+ ),
160+ (
161+ " Delta + VA" ,
162+ [5 : 7 ; 11 : 14 ],
163+ [dva_magnitudes; ddelta_magnitudes],
164+ (theta_idxs= nothing , va_idxs= 1 : 3 , omega_idxs= nothing , delta_idxs= 4 : 7 )
165+ ),
166+ (
167+ " All Inputs" ,
168+ [1 : 4 ; 5 : 7 ; 8 : 10 ; 11 : 14 ],
169+ [dtheta_magnitudes; dva_magnitudes;
170+ domega_magnitudes; ddelta_magnitudes],
171+ (theta_idxs= 1 : 4 , va_idxs= 5 : 7 , omega_idxs= 8 : 10 , delta_idxs= 11 : 14 )
172+ )
143173 ]
144174
145- for (combo_name, perturbation) in combination_tests
146- # Reset to baseline
147- VortexStepMethod. group_deform! (ram_wing, theta, delta; smooth= false )
148- init! (body_aero; init_aero= false , va= va, omega= zeros (3 ))
149-
150- # Extract components
151- perturbed_theta = theta + perturbation[1 : 4 ]
152- perturbed_va = va + perturbation[5 : 7 ]
153- perturbed_omega = perturbation[8 : 10 ]
154- perturbed_delta = delta + perturbation[11 : 14 ]
155-
156- # Apply to nonlinear model
157- VortexStepMethod. group_deform! (ram_wing, perturbed_theta, perturbed_delta; smooth= false )
158- init! (body_aero; init_aero= false , va= perturbed_va, omega= perturbed_omega)
159-
160- # Get nonlinear solution
161- nonlin_res = VortexStepMethod. solve! (solver, body_aero; log= false )
162- nonlin_res = [solver. sol. force; solver. sol. moment; solver. sol. group_moment_dist]
163-
164- # Compute linearized prediction
165- lin_prediction = lin_res + jac * perturbation
166-
167- # Calculate error ratio
168- prediction_error = norm (lin_prediction - nonlin_res)
169- baseline_difference = norm (lin_res - nonlin_res)
170- error_ratio = prediction_error / baseline_difference
171-
172- @info " $combo_name error ratio: $error_ratio "
173-
174- # Test combinations
175- @test lin_res ≉ nonlin_res atol= 1e-2
176- @test lin_prediction ≈ nonlin_res rtol= 0.2 atol= 0.05
177- @test error_ratio < 2e-3
175+ for (combo_name, active_indices, perturbation, idx_mappings) in combination_tests
176+ @testset " $combo_name " begin
177+ # Start with a fresh model for each combination test
178+ VortexStepMethod. group_deform! (ram_wing, theta, delta; smooth= false )
179+ init! (body_aero; init_aero= false , va, omega)
180+
181+ # Create the appropriate input vector for this combination
182+ input_vec = Vector {Float64} (undef, length (active_indices))
183+
184+ # Fill with base values
185+ if ! isnothing (idx_mappings. theta_idxs)
186+ input_vec[idx_mappings. theta_idxs] .= theta
187+ end
188+ if ! isnothing (idx_mappings. va_idxs)
189+ input_vec[idx_mappings. va_idxs] .= va
190+ end
191+ if ! isnothing (idx_mappings. omega_idxs)
192+ input_vec[idx_mappings. omega_idxs] .= omega
193+ end
194+ if ! isnothing (idx_mappings. delta_idxs)
195+ input_vec[idx_mappings. delta_idxs] .= delta
196+ end
197+
198+ # Get the Jacobian and linearization result for this specific combination
199+ jac_combo, lin_res_combo = VortexStepMethod. linearize (
200+ solver,
201+ body_aero,
202+ input_vec;
203+ idx_mappings...
204+ )
205+
206+ # Get baseline results
207+ baseline_res = VortexStepMethod. solve! (solver, body_aero; log= false )
208+ baseline_res = [solver. sol. force; solver. sol. moment; solver. sol. group_moment_dist]
209+
210+ # Should match the linearization result
211+ @test baseline_res ≈ lin_res_combo
212+
213+ # Apply perturbation using the appropriate indices
214+ perturbed_input = copy (input_vec) + perturbation
215+
216+ # Extract components based on the combination being tested
217+ perturbed_theta = ! isnothing (idx_mappings. theta_idxs) ?
218+ perturbed_input[idx_mappings. theta_idxs] : theta
219+
220+ perturbed_va = ! isnothing (idx_mappings. va_idxs) ?
221+ perturbed_input[idx_mappings. va_idxs] : va
222+
223+ perturbed_omega = ! isnothing (idx_mappings. omega_idxs) ?
224+ perturbed_input[idx_mappings. omega_idxs] : omega
225+
226+ perturbed_delta = ! isnothing (idx_mappings. delta_idxs) ?
227+ perturbed_input[idx_mappings. delta_idxs] : delta
228+
229+ # Apply to nonlinear model
230+ VortexStepMethod. group_deform! (ram_wing, perturbed_theta, perturbed_delta; smooth= false )
231+ init! (body_aero; init_aero= false , va= perturbed_va, omega= perturbed_omega)
232+
233+ # Get nonlinear solution with perturbation
234+ nonlin_res = VortexStepMethod. solve! (solver, body_aero; log= false )
235+ nonlin_res = [solver. sol. force; solver. sol. moment; solver. sol. group_moment_dist]
236+
237+ # Compute linearized prediction using our specialized Jacobian
238+ lin_prediction = lin_res_combo + jac_combo * perturbation
239+
240+ # Ensure perturbation had an effect
241+ @test baseline_res ≉ nonlin_res atol= 1e-3
242+
243+ # Calculate error ratio
244+ prediction_error = norm (lin_prediction - nonlin_res)
245+ baseline_difference = norm (baseline_res - nonlin_res)
246+ error_ratio = prediction_error / baseline_difference
247+
248+ @info " $combo_name error metrics" prediction_error baseline_difference error_ratio
249+
250+ # Validate the prediction
251+ @test lin_prediction ≈ nonlin_res rtol= 0.1 atol= 1e-3
252+ @test error_ratio < 0.05
253+ end
178254 end
179255 end
180256end
0 commit comments