From b2537251e47c68a06df3513303496eca56522969 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Thu, 9 Oct 2025 17:57:11 -0400 Subject: [PATCH 1/8] added xyzref as an ad var --- optvl/optvl_class.py | 1 + 1 file changed, 1 insertion(+) diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 4d2dc5de..2c69bbe3 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -109,6 +109,7 @@ class OVLSolver(object): "Sref": ["CASE_R", "SREF"], "Cref": ["CASE_R", "CREF"], "Bref": ["CASE_R", "BREF"], + "XYZref": ["CASE_R", "XYZREF"], } case_derivs_to_fort_var = { From 6bb7596dfe50d4e783ec48d124dcd941bcaf4bf9 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Thu, 9 Oct 2025 17:35:14 -0400 Subject: [PATCH 2/8] Fixed some seeds --- optvl/om_wrapper.py | 5 ++++- optvl/optvl_class.py | 2 +- tests/test_om_wrapper.py | 18 ++++++++++++++++++ tests/test_partial_derivs.py | 5 +++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/optvl/om_wrapper.py b/optvl/om_wrapper.py index d72af102..b75f217f 100644 --- a/optvl/om_wrapper.py +++ b/optvl/om_wrapper.py @@ -194,7 +194,10 @@ def om_set_avl_inputs(sys, inputs): # add the parameters to the run for ref in sys.ovl.ref_var_to_fort_var: if ref in inputs: - val = inputs[ref][0] + if ref == "XYZref": + val = inputs[ref][0:3] + else: + val = inputs[ref][0] sys.ovl.set_reference_data({ref: val}) diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 2c69bbe3..9deb6036 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -2902,7 +2902,7 @@ def set_reference_ad_seeds(self, ref_seeds: Dict[str, float], mode: str = "AD", if mode == "AD": blk += self.ad_suffix var += self.ad_suffix - val = ref_seeds[ref_key] * scale + val = ref_seeds[ref_key] * scale * np.ones(3) if ref_key == "XYZref" else ref_seeds[ref_key] * scale elif mode == "FD": val = self.get_avl_fort_arr(blk, var) val += ref_seeds[ref_key] * scale diff --git a/tests/test_om_wrapper.py b/tests/test_om_wrapper.py index 82665e70..1588071f 100644 --- a/tests/test_om_wrapper.py +++ b/tests/test_om_wrapper.py @@ -31,6 +31,7 @@ class TestOMWrapper(unittest.TestCase): def setUp(self): self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) + model = om.Group() model.add_subsystem( "ovlsolver", @@ -54,10 +55,13 @@ def test_aero_coef(self): prob.setup(mode="rev") prob.run_model() + for func in run_data: + for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] + def test_surface_param_setting(self): prob = self.prob prob.setup(mode="rev") @@ -74,20 +78,26 @@ def test_surface_param_setting(self): self.ovl_solver.avl.update_surfaces() self.ovl_solver.execute_run() + # set om surface data prob.set_val(f"ovlsolver.{surf_key}:{geom_key}", arr) prob.run_model() + run_data = self.ovl_solver.get_total_forces() + for func in run_data: for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] + stab_derivs = self.ovl_solver.get_stab_derivs() + for func in stab_derivs: for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == stab_derivs[func] + def test_param_setting(self): prob = self.prob prob.setup(mode="rev") @@ -101,21 +111,27 @@ def test_param_setting(self): self.ovl_solver.set_parameter(param, param_val) self.ovl_solver.execute_run() + # set om surface data prob.set_val(f"ovlsolver.{param}", param_val) prob.run_model() + run_data = self.ovl_solver.get_total_forces() + for func in run_data: for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] + stab_derivs = self.ovl_solver.get_stab_derivs() + for func in stab_derivs: for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") print(func, om_val, stab_derivs[func]) assert om_val == stab_derivs[func] + def test_CL_solve(self): prob = self.prob cl_star = 1.5 @@ -197,6 +213,7 @@ def test_OM_total_derivs(self): prob.run_model() om.n2(prob, show_browser=False, outfile="vlm_opt.html") + deriv_err = prob.check_totals() rtol = 5e-4 for key, data in deriv_err.items(): @@ -210,3 +227,4 @@ def test_OM_total_derivs(self): if __name__ == "__main__": unittest.main() + diff --git a/tests/test_partial_derivs.py b/tests/test_partial_derivs.py index 06336467..03cc8284 100644 --- a/tests/test_partial_derivs.py +++ b/tests/test_partial_derivs.py @@ -310,7 +310,6 @@ def test_fwd_ref(self): def test_rev_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: self.ovl_solver.clear_ad_seeds_fast() - func_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[0] self.ovl_solver.clear_ad_seeds_fast() @@ -491,7 +490,9 @@ def test_rev_param(self): def test_fwd_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: res_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[1] - res_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0}, mode="FD", step=1e-7)[1] + res_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd( + ref_seeds={ref_key: 1.0}, mode="FD", step=1e-7 + )[1] # print(f"res wrt {ref_key}", np.linalg.norm(res_seeds), np.linalg.norm(res_seeds_FD)) np.testing.assert_allclose(res_seeds, res_seeds_FD, atol=1e-6, err_msg=f"d(res) w.r.t.{ref_key}") From ee23091fab3d866df400bdddffaa0a12dd3ee635 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 15:52:12 -0400 Subject: [PATCH 3/8] minor grammar fix --- optvl/optvl_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 9deb6036..b33884db 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -3202,7 +3202,7 @@ def _execute_jac_vec_prod_fwd( mode: str = "AD", step: float = 1e-7, ) -> Tuple[Dict[str, float], np.ndarray, Dict[str, float], Dict[str, float], np.ndarray, np.ndarray]: - """Get partial derivatives in forward mode. This routine is usefulinternally and when creating wrappers for things like OpenMDAO + """Get partial derivatives in forward mode. This routine is useful internally and when creating wrappers for things like OpenMDAO Args: con_seeds: Case constraint AD seeds From e6c22cc75e3a5d261ea119800dea566c8c939653 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 13:48:41 -0400 Subject: [PATCH 4/8] Fix tests --- tests/test_total_derivs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_total_derivs.py b/tests/test_total_derivs.py index cc986e43..e8e69b37 100644 --- a/tests/test_total_derivs.py +++ b/tests/test_total_derivs.py @@ -355,7 +355,7 @@ def test_ref(self): # print(f"{func_key:5} wrt {ref_key:5} | AD:{ad_dot: 5e} FD:{fd_dot: 5e} rel err:{rel_err:.2e}") tol = 1e-13 - if np.abs(ad_dot) < tol or np.abs(fd_dot) < tol: + if np.abs(np.linalg.norm(ad_dot)) < tol or np.abs(fd_dot) < tol: # If either value is basically zero, use an absolute tolerance np.testing.assert_allclose( ad_dot, @@ -381,7 +381,7 @@ def test_ref(self): # f"{func_key} wrt {var_key:5} wrt {ref_key} | AD:{ad_dot: 5e} FD:{func_dot: 5e} rel err:{rel_err:.2e}" # ) tol = 1e-8 - if np.abs(ad_dot) < tol or np.abs(func_dot) < tol: + if np.abs(np.linalg.norm(ad_dot)) < tol or np.abs(func_dot) < tol: # If either value is basically zero, use an absolute tolerance np.testing.assert_allclose( ad_dot, From e0b28e720008f2863650d54c7d6b72b171f3de74 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 15:54:28 -0400 Subject: [PATCH 5/8] fix test one more time --- tests/test_om_wrapper.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_om_wrapper.py b/tests/test_om_wrapper.py index 1588071f..1578aff1 100644 --- a/tests/test_om_wrapper.py +++ b/tests/test_om_wrapper.py @@ -55,8 +55,6 @@ def test_aero_coef(self): prob.setup(mode="rev") prob.run_model() - for func in run_data: - for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] @@ -85,14 +83,12 @@ def test_surface_param_setting(self): run_data = self.ovl_solver.get_total_forces() - for func in run_data: for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] stab_derivs = self.ovl_solver.get_stab_derivs() - for func in stab_derivs: for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == stab_derivs[func] @@ -118,14 +114,12 @@ def test_param_setting(self): run_data = self.ovl_solver.get_total_forces() - for func in run_data: for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] stab_derivs = self.ovl_solver.get_stab_derivs() - for func in stab_derivs: for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") print(func, om_val, stab_derivs[func]) From 86b59b25feecdef49103384e144fa0c6d180f306 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 15:56:45 -0400 Subject: [PATCH 6/8] fix formatting --- tests/test_om_wrapper.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/test_om_wrapper.py b/tests/test_om_wrapper.py index 1578aff1..b73e6469 100644 --- a/tests/test_om_wrapper.py +++ b/tests/test_om_wrapper.py @@ -31,7 +31,6 @@ class TestOMWrapper(unittest.TestCase): def setUp(self): self.ovl_solver = OVLSolver(geo_file=geom_file, mass_file=mass_file) - model = om.Group() model.add_subsystem( "ovlsolver", @@ -59,7 +58,6 @@ def test_aero_coef(self): om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] - def test_surface_param_setting(self): prob = self.prob prob.setup(mode="rev") @@ -76,18 +74,15 @@ def test_surface_param_setting(self): self.ovl_solver.avl.update_surfaces() self.ovl_solver.execute_run() - # set om surface data prob.set_val(f"ovlsolver.{surf_key}:{geom_key}", arr) prob.run_model() - run_data = self.ovl_solver.get_total_forces() for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] - stab_derivs = self.ovl_solver.get_stab_derivs() for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") @@ -107,18 +102,15 @@ def test_param_setting(self): self.ovl_solver.set_parameter(param, param_val) self.ovl_solver.execute_run() - # set om surface data prob.set_val(f"ovlsolver.{param}", param_val) prob.run_model() - run_data = self.ovl_solver.get_total_forces() for func in run_data: om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == run_data[func] - stab_derivs = self.ovl_solver.get_stab_derivs() for func in stab_derivs: om_val = prob.get_val(f"ovlsolver.{func}") @@ -207,7 +199,6 @@ def test_OM_total_derivs(self): prob.run_model() om.n2(prob, show_browser=False, outfile="vlm_opt.html") - deriv_err = prob.check_totals() rtol = 5e-4 for key, data in deriv_err.items(): @@ -221,4 +212,3 @@ def test_OM_total_derivs(self): if __name__ == "__main__": unittest.main() - From f1212816c0f195b99f3dd31710066ae56bcc8e39 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 15:58:11 -0400 Subject: [PATCH 7/8] Fixed formatting one more time --- tests/test_om_wrapper.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_om_wrapper.py b/tests/test_om_wrapper.py index b73e6469..82665e70 100644 --- a/tests/test_om_wrapper.py +++ b/tests/test_om_wrapper.py @@ -88,7 +88,6 @@ def test_surface_param_setting(self): om_val = prob.get_val(f"ovlsolver.{func}") assert om_val == stab_derivs[func] - def test_param_setting(self): prob = self.prob prob.setup(mode="rev") @@ -117,7 +116,6 @@ def test_param_setting(self): print(func, om_val, stab_derivs[func]) assert om_val == stab_derivs[func] - def test_CL_solve(self): prob = self.prob cl_star = 1.5 From d4fc2a656aee3810a869ce75e2ea1026d2056fd1 Mon Sep 17 00:00:00 2001 From: Safa Bakhshi Date: Wed, 15 Oct 2025 16:26:26 -0400 Subject: [PATCH 8/8] Move changes to seeds setting back to tests --- optvl/optvl_class.py | 2 +- tests/test_partial_derivs.py | 14 +++++++++----- tests/test_stab_derivs_partial_derivs.py | 13 ++++++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index b33884db..357772e3 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -2902,7 +2902,7 @@ def set_reference_ad_seeds(self, ref_seeds: Dict[str, float], mode: str = "AD", if mode == "AD": blk += self.ad_suffix var += self.ad_suffix - val = ref_seeds[ref_key] * scale * np.ones(3) if ref_key == "XYZref" else ref_seeds[ref_key] * scale + val = ref_seeds[ref_key] * scale elif mode == "FD": val = self.get_avl_fort_arr(blk, var) val += ref_seeds[ref_key] * scale diff --git a/tests/test_partial_derivs.py b/tests/test_partial_derivs.py index 03cc8284..93290699 100644 --- a/tests/test_partial_derivs.py +++ b/tests/test_partial_derivs.py @@ -284,9 +284,10 @@ def test_rev_param(self): def test_fwd_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: - func_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[0] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 - func_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0}, mode="FD", step=1e-7)[0] + func_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[0] + func_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed}, mode="FD", step=1e-7)[0] for func_key in func_seeds: # print(f"{func_key} wrt {ref_key}", func_seeds[func_key], func_seeds_FD[func_key]) @@ -309,8 +310,9 @@ def test_fwd_ref(self): def test_rev_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 self.ovl_solver.clear_ad_seeds_fast() - func_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[0] + func_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[0] self.ovl_solver.clear_ad_seeds_fast() for func_key in self.ovl_solver.case_var_to_fort_var: @@ -489,7 +491,8 @@ def test_rev_param(self): def test_fwd_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: - res_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[1] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 + res_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[1] res_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd( ref_seeds={ref_key: 1.0}, mode="FD", step=1e-7 )[1] @@ -505,7 +508,8 @@ def test_rev_ref(self): self.ovl_solver.clear_ad_seeds_fast() for ref_key in self.ovl_solver.ref_var_to_fort_var: - res_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[1] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 + res_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[1] # do dot product res_sum = np.sum(res_seeds_rev * res_seeds_fwd) ref_sum = np.sum(ref_seeds_rev[ref_key]) diff --git a/tests/test_stab_derivs_partial_derivs.py b/tests/test_stab_derivs_partial_derivs.py index 164bee52..372a274e 100644 --- a/tests/test_stab_derivs_partial_derivs.py +++ b/tests/test_stab_derivs_partial_derivs.py @@ -180,9 +180,10 @@ def test_rev_gamma_u(self): def test_fwd_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: - res_u_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[5] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 + res_u_seeds = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[5] - res_u_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0}, mode="FD", step=1e-5)[ + res_u_seeds_FD = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed}, mode="FD", step=1e-5)[ 5 ] @@ -381,9 +382,10 @@ def test_rev_gamma_u(self): def test_fwd_ref(self): for ref_key in self.ovl_solver.ref_var_to_fort_var: - sd_d = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[3] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 + sd_d = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[3] - sd_d_fd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0}, mode="FD", step=1e-6)[3] + sd_d_fd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed}, mode="FD", step=1e-6)[3] for deriv_func in sd_d: sens_label = f"{deriv_func} wrt {ref_key}" @@ -416,7 +418,8 @@ def test_rev_ref(self): self.ovl_solver.clear_ad_seeds_fast() for ref_key in self.ovl_solver.ref_var_to_fort_var: - stab_deriv_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: 1.0})[3] + ref_seed = np.ones(3) if ref_key == "XYZref" else 1.0 + stab_deriv_seeds_fwd = self.ovl_solver._execute_jac_vec_prod_fwd(ref_seeds={ref_key: ref_seed})[3] stab_deriv_sum = 0.0 for deriv_func in stab_deriv_seeds_fwd: