From 05e455ce8c665a83ff6d3535cb66fad1c3b7d6bd Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Tue, 10 Dec 2024 12:42:22 -0500 Subject: [PATCH] Fixed an issue with time promotion in the new Radau implementation. --- .../doc/test_doc_balanced_field_length.py | 4 ++ ...st_brachistochrone_control_rate_targets.py | 6 +-- .../test_ex_brachistochrone_vector_states.py | 2 +- dymos/phase/test/test_time_targets.py | 37 ++++++------------- dymos/phase/test/test_timeseries.py | 5 +-- .../components/radau_iter_group.py | 4 +- .../components/test/test_radau_iter_group.py | 2 +- .../pseudospectral/radau_new.py | 4 +- 8 files changed, 25 insertions(+), 39 deletions(-) diff --git a/dymos/examples/balanced_field/doc/test_doc_balanced_field_length.py b/dymos/examples/balanced_field/doc/test_doc_balanced_field_length.py index e4ccd25c7..187be4903 100644 --- a/dymos/examples/balanced_field/doc/test_doc_balanced_field_length.py +++ b/dymos/examples/balanced_field/doc/test_doc_balanced_field_length.py @@ -257,3 +257,7 @@ def test_balanced_field_length_for_docs(self): assert_near_equal(2114.387, sol_r_f_rto, tolerance=0.01) assert_near_equal(2114.387, sim_r_f_climb, tolerance=0.01) assert_near_equal(2114.387, sim_r_f_rto, tolerance=0.01) + + +if __name__ == '__main__': + unittest.main() diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_control_rate_targets.py b/dymos/examples/brachistochrone/test/test_brachistochrone_control_rate_targets.py index caa52d4df..58d05ddce 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_control_rate_targets.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_control_rate_targets.py @@ -138,7 +138,7 @@ def test_brachistochrone_control_rate_targets(self): with self.subTest(f'{tx_name=} {control_target_method=} {control_type=}'): - p = om.Problem(model=om.Group()) + p = om.Problem(model=om.Group(), reports=True) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() @@ -170,7 +170,7 @@ def test_brachistochrone_control_rate_targets(self): phase.add_control('int_theta', lower=0.0, upper=None, fix_initial=True, rate_targets=_unspecified if control_target_method == 'implicit' else ['theta'], - control_type=control_type, order=7) + control_type=control_type, order=7, continuity=True) phase.add_parameter('g', units='m/s**2', opt=False, val=9.80665) @@ -187,7 +187,7 @@ def test_brachistochrone_control_rate_targets(self): phase.set_state_val('x', [0, 10]) phase.set_state_val('y', [10, 5]) - phase.set_state_val('v', [0, 9.9]) + phase.set_state_val('v', [0.001, 9.9]) phase.set_control_val('int_theta', [0, 100], units='deg*s') p.run_model() diff --git a/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py b/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py index bffc95e52..e4ee83ca0 100644 --- a/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py +++ b/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py @@ -11,7 +11,7 @@ OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT') -# @use_tempdirs +@use_tempdirs class TestBrachistochroneVectorStatesExample(unittest.TestCase): def assert_results(self, p): diff --git a/dymos/phase/test/test_time_targets.py b/dymos/phase/test/test_time_targets.py index 48ce3f768..e785dace8 100644 --- a/dymos/phase/test/test_time_targets.py +++ b/dymos/phase/test/test_time_targets.py @@ -136,18 +136,11 @@ def _make_problem(self, transcription, num_seg, transcription_order=3, input_ini p.setup(check=True, force_alloc_complex=True) - p['phase0.t_initial'] = 1.0 - p['phase0.t_duration'] = 2.0 - - if transcription == 'explicit-shooting': - p['phase0.initial_states:x'] = 0 - p['phase0.initial_states:y'] = 10 - p['phase0.initial_states:v'] = 0 - else: - p['phase0.states:x'] = phase.interp('x', [0, 10]) - p['phase0.states:y'] = phase.interp('y', [10, 5]) - p['phase0.states:v'] = phase.interp('v', [0, 9.9]) - p['phase0.controls:theta'] = phase.interp('theta', [0.01, 100.5]) + phase.set_time_val(initial=1.0, duration=2.0) + phase.set_state_val('x', vals=[0, 10]) + phase.set_state_val('y', vals=[10, 5]) + phase.set_state_val('v', vals=[1.0E-6, 9.9]) + phase.set_control_val('theta', vals=[0.01, 100.5], units='deg') return p @@ -226,15 +219,11 @@ def test_radau(self): time_phase_all = p[f'phase0.timeseries.{time_name}_phase'].ravel() - assert_near_equal(p['phase0.rhs_all.time_phase'][-1], 1.8016, tolerance=1.0E-3) + assert_near_equal(p['phase0.ode_all.time_phase'][-1], 1.8016, tolerance=1.0E-3) - assert_near_equal(p['phase0.rhs_all.t_initial'], p['phase0.t_initial']) + assert_near_equal(p['phase0.ode_all.time_phase'], time_phase_all) - assert_near_equal(p['phase0.rhs_all.t_duration'], p['phase0.t_duration']) - - assert_near_equal(p['phase0.rhs_all.time_phase'], time_phase_all) - - assert_near_equal(p['phase0.rhs_all.time'], time_all) + assert_near_equal(p['phase0.ode_all.time'], time_all) exp_out = p.model.phase0.simulate() @@ -360,15 +349,11 @@ def test_radau_targets_are_inputs(self): time_phase_all = p['phase0.t_phase'] - assert_near_equal(p['phase0.rhs_all.time_phase'][-1], 1.8016, tolerance=1.0E-3) - - assert_near_equal(p['phase0.rhs_all.t_initial'], p['phase0.t_initial']) - - assert_near_equal(p['phase0.rhs_all.t_duration'], p['phase0.t_duration']) + assert_near_equal(p['phase0.ode_all.time_phase'][-1], 1.8016, tolerance=1.0E-3) - assert_near_equal(p['phase0.rhs_all.time_phase'], time_phase_all) + assert_near_equal(p['phase0.ode_all.time_phase'], time_phase_all) - assert_near_equal(p['phase0.rhs_all.time'], time_all) + assert_near_equal(p['phase0.ode_all.time'], time_all) exp_out = p.model._get_subsystem('phase0').simulate() diff --git a/dymos/phase/test/test_timeseries.py b/dymos/phase/test/test_timeseries.py index 4ef4c8bef..5d8936477 100644 --- a/dymos/phase/test/test_timeseries.py +++ b/dymos/phase/test/test_timeseries.py @@ -2,6 +2,7 @@ import warnings import numpy as np +from numpy.testing import assert_allclose from scipy.interpolate import interp1d @@ -197,13 +198,11 @@ def test_timeseries_radau(self, test_smaller_timeseries=False): t_sol = p.get_val('phase0.timeseries.time') t_sim = exp_out.get_val('phase0.timeseries.time') - p.model.list_outputs() - for state_name, rate_name in (('x', 'xdot'), ('y', 'ydot'), ('v', 'vdot')): rate_sol = p.get_val(f'phase0.timeseries.{rate_name}') rate_sim = exp_out.get_val(f'phase0.timeseries.{rate_name}') rate_t_sim = interp1d(t_sim.ravel(), rate_sim.ravel()) - assert_near_equal(rate_t_sim(t_sol), rate_sol, tolerance=1.0E-3) + assert_allclose(rate_t_sim(t_sol), rate_sol, rtol=1.0E-3, atol=1.0E-3) def test_timeseries_radau_smaller_timeseries(self): self.test_timeseries_radau(test_smaller_timeseries=True) diff --git a/dymos/transcriptions/pseudospectral/components/radau_iter_group.py b/dymos/transcriptions/pseudospectral/components/radau_iter_group.py index fa23c58f5..a969cbd78 100644 --- a/dymos/transcriptions/pseudospectral/components/radau_iter_group.py +++ b/dymos/transcriptions/pseudospectral/components/radau_iter_group.py @@ -201,12 +201,10 @@ def configure_io(self, phase): rate_source = options['rate_source'] shape = options['shape'] - # TODO: compressed transcription is not currently supported because promoting duplicate - # indices currently has a bug in OpenMDAO <= 3.35.0 for tgt in options['targets']: self.promotes('ode_all', [(tgt, f'states:{name}')], src_indices=om.slicer[state_src_idxs_input_to_all, ...]) - # src_shape=(nin,) + shape) + self.set_input_defaults(f'states:{name}', val=1.0, units=units, src_shape=(nin,) + shape) self.promotes('defects', inputs=(f'states:{name}',), diff --git a/dymos/transcriptions/pseudospectral/components/test/test_radau_iter_group.py b/dymos/transcriptions/pseudospectral/components/test/test_radau_iter_group.py index 9b6bb3e78..4e6158411 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_radau_iter_group.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_radau_iter_group.py @@ -19,7 +19,7 @@ RadauIterGroup = GroupWrapperConfig(RadauIterGroup, [PhaseStub()]) -# @use_tempdirs +@use_tempdirs class TestRadauIterGroup(unittest.TestCase): def test_solve_segments(self): diff --git a/dymos/transcriptions/pseudospectral/radau_new.py b/dymos/transcriptions/pseudospectral/radau_new.py index 6fc0dff34..5405be9a8 100644 --- a/dymos/transcriptions/pseudospectral/radau_new.py +++ b/dymos/transcriptions/pseudospectral/radau_new.py @@ -120,8 +120,8 @@ def configure_time(self, phase): flat_src_idxs = True src_shape = (1,) - phase.promotes('ode_all', inputs=[(t, name)], src_indices=src_idxs, - flat_src_indices=flat_src_idxs, src_shape=src_shape) + phase.ode_iter_group.promotes('ode_all', any=[(t, name)], src_indices=src_idxs, + flat_src_indices=flat_src_idxs, src_shape=src_shape) phase.promotes('boundary_vals', inputs=[(t, name)], src_indices=endpoint_src_idxs, flat_src_indices=flat_src_idxs, src_shape=src_shape)