From efc0685dd5e0948904bfe68c13752ae7d6c7380d Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Thu, 25 Apr 2019 14:35:18 -0400 Subject: [PATCH 01/13] trajectories at root level can now simulate, their path in the resulting simulation is sim_traj --- ...st_two_phase_cannonball_undecorated_ode.py | 3 + .../test/test_simulate_root_trajectory.py | 317 ++++++++++++++++++ dymos/trajectory/trajectory.py | 5 +- 3 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 dymos/examples/ssto/test/test_simulate_root_trajectory.py diff --git a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py index 48b3abc55..854902062 100644 --- a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py +++ b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py @@ -7,7 +7,10 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt +from dymos.utils.testing_utils import use_tempdirs + +@use_tempdirs class TestTwoPhaseCannonball(unittest.TestCase): @classmethod diff --git a/dymos/examples/ssto/test/test_simulate_root_trajectory.py b/dymos/examples/ssto/test/test_simulate_root_trajectory.py new file mode 100644 index 000000000..e89c74d3c --- /dev/null +++ b/dymos/examples/ssto/test/test_simulate_root_trajectory.py @@ -0,0 +1,317 @@ +from __future__ import print_function, absolute_import, division + +import unittest + +import matplotlib +matplotlib.use('Agg') +import matplotlib.pyplot as plt +plt.style.use('ggplot') + + +class TestSSTOSimulateRootTrajectory(unittest.TestCase): + + def test_ssto_simulate_root_trajectory(self): + """ + Tests that we can properly simulate a trajectory even if the trajectory is the root + group of the model. In this case the name of the trajectory in the output will + be 'sim_traj'. + """ + import numpy as np + import matplotlib.pyplot as plt + from openmdao.api import Problem, Group, ExplicitComponent, DirectSolver, \ + pyOptSparseDriver, ExecComp + from openmdao.utils.assert_utils import assert_rel_error + import dymos as dm + + g = 1.61544 # lunar gravity, m/s**2 + + class LaunchVehicle2DEOM(ExplicitComponent): + """ + Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag. + """ + def initialize(self): + self.options.declare('num_nodes', types=int) + + def setup(self): + nn = self.options['num_nodes'] + + # Inputs + self.add_input('vx', + val=np.zeros(nn), + desc='x velocity', + units='m/s') + + self.add_input('vy', + val=np.zeros(nn), + desc='y velocity', + units='m/s') + + self.add_input('m', + val=np.zeros(nn), + desc='mass', + units='kg') + + self.add_input('theta', + val=np.zeros(nn), + desc='pitch angle', + units='rad') + + self.add_input('thrust', + val=2100000 * np.ones(nn), + desc='thrust', + units='N') + + self.add_input('Isp', + val=265.2 * np.ones(nn), + desc='specific impulse', + units='s') + + # Outputs + self.add_output('xdot', + val=np.zeros(nn), + desc='velocity component in x', + units='m/s') + + self.add_output('ydot', + val=np.zeros(nn), + desc='velocity component in y', + units='m/s') + + self.add_output('vxdot', + val=np.zeros(nn), + desc='x acceleration magnitude', + units='m/s**2') + + self.add_output('vydot', + val=np.zeros(nn), + desc='y acceleration magnitude', + units='m/s**2') + + self.add_output('mdot', + val=np.zeros(nn), + desc='mass rate of change', + units='kg/s') + + # Setup partials + ar = np.arange(self.options['num_nodes']) + + self.declare_partials(of='xdot', wrt='vx', rows=ar, cols=ar, val=1.0) + self.declare_partials(of='ydot', wrt='vy', rows=ar, cols=ar, val=1.0) + + self.declare_partials(of='vxdot', wrt='vx', rows=ar, cols=ar) + self.declare_partials(of='vxdot', wrt='m', rows=ar, cols=ar) + self.declare_partials(of='vxdot', wrt='theta', rows=ar, cols=ar) + self.declare_partials(of='vxdot', wrt='thrust', rows=ar, cols=ar) + + self.declare_partials(of='vydot', wrt='m', rows=ar, cols=ar) + self.declare_partials(of='vydot', wrt='theta', rows=ar, cols=ar) + self.declare_partials(of='vydot', wrt='vy', rows=ar, cols=ar) + self.declare_partials(of='vydot', wrt='thrust', rows=ar, cols=ar) + + self.declare_partials(of='mdot', wrt='thrust', rows=ar, cols=ar) + self.declare_partials(of='mdot', wrt='Isp', rows=ar, cols=ar) + + def compute(self, inputs, outputs): + theta = inputs['theta'] + cos_theta = np.cos(theta) + sin_theta = np.sin(theta) + vx = inputs['vx'] + vy = inputs['vy'] + m = inputs['m'] + F_T = inputs['thrust'] + Isp = inputs['Isp'] + + outputs['xdot'] = vx + outputs['ydot'] = vy + outputs['vxdot'] = F_T * cos_theta / m + outputs['vydot'] = F_T * sin_theta / m - g + outputs['mdot'] = -F_T / (g * Isp) + + def compute_partials(self, inputs, jacobian): + theta = inputs['theta'] + cos_theta = np.cos(theta) + sin_theta = np.sin(theta) + m = inputs['m'] + F_T = inputs['thrust'] + Isp = inputs['Isp'] + + # jacobian['vxdot', 'vx'] = -CDA * rho * vx / m + jacobian['vxdot', 'm'] = -(F_T * cos_theta) / m ** 2 + jacobian['vxdot', 'theta'] = -(F_T / m) * sin_theta + jacobian['vxdot', 'thrust'] = cos_theta / m + + # jacobian['vydot', 'vy'] = -CDA * rho * vy / m + jacobian['vydot', 'm'] = -(F_T * sin_theta) / m ** 2 + jacobian['vydot', 'theta'] = (F_T / m) * cos_theta + jacobian['vydot', 'thrust'] = sin_theta / m + + jacobian['mdot', 'thrust'] = -1.0 / (g * Isp) + jacobian['mdot', 'Isp'] = F_T / (g * Isp ** 2) + + class LaunchVehicleLinearTangentODE(Group): + """ + The LaunchVehicleLinearTangentODE for this case consists of a guidance component and + the EOM. Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the + tan_theta variable. + """ + + def initialize(self): + self.options.declare('num_nodes', types=int, + desc='Number of nodes to be evaluated in the RHS') + + def setup(self): + nn = self.options['num_nodes'] + + self.add_subsystem('guidance', ExecComp('theta=arctan(tan_theta)', + theta={'value': np.ones(nn), + 'units': 'rad'}, + tan_theta={'value': np.ones(nn)})) + + self.add_subsystem('eom', LaunchVehicle2DEOM(num_nodes=nn)) + + self.connect('guidance.theta', 'eom.theta') + + # + # Setup and solve the optimal control problem + # + traj = dm.Trajectory() + + p = Problem(model=traj) + + phase = dm.Phase(ode_class=LaunchVehicleLinearTangentODE, + transcription=dm.Radau(num_segments=20, order=3, compressed=False)) + traj.add_phase('phase0', phase) + + phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(10, 1000), units='s') + + # + # Set the state options. We include rate_source, units, and targets here since the ODE + # is not decorated with their default values. + # + phase.set_state_options('x', fix_initial=True, lower=0, rate_source='eom.xdot', units='m') + phase.set_state_options('y', fix_initial=True, lower=0, rate_source='eom.ydot', units='m') + phase.set_state_options('vx', fix_initial=True, lower=0, rate_source='eom.vxdot', + units='m/s', targets=['eom.vx']) + phase.set_state_options('vy', fix_initial=True, rate_source='eom.vydot', + units='m/s', targets=['eom.vy']) + phase.set_state_options('m', fix_initial=True, rate_source='eom.mdot', + units='kg', targets=['eom.m']) + + # + # The tangent of theta is modeled as a linear polynomial over the duration of the phase. + # + phase.add_polynomial_control('tan_theta', order=1, units=None, opt=True, + targets=['guidance.tan_theta']) + + # + # Parameters values for thrust and specific impulse are design parameters. They are + # provided by an IndepVarComp in the phase, but with opt=False their values are not + # design variables in the optimization problem. + # + phase.add_design_parameter('thrust', units='N', opt=False, val=3.0 * 50000.0 * 1.61544, + targets=['eom.thrust']) + phase.add_design_parameter('Isp', units='s', opt=False, val=1.0E6, targets=['eom.Isp']) + + # + # Set the boundary constraints. These are all states which could also be handled + # by setting fix_final=True and including the correct final value in the initial guess. + # + phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True) + phase.add_boundary_constraint('vx', loc='final', equals=1627.0) + phase.add_boundary_constraint('vy', loc='final', equals=0) + + phase.add_objective('time', index=-1, scaler=0.01) + + # + # Add theta as a timeseries output since it's not included by default. + # + phase.add_timeseries_output('guidance.theta', units='deg') + + # + # Set the optimizer + # + p.driver = pyOptSparseDriver() + p.driver.options['optimizer'] = 'SLSQP' + p.driver.options['dynamic_simul_derivs'] = True + + # + # We don't strictly need to define a linear solver here since our problem is entirely + # feed-forward with no iterative loops. It's good practice to add one, however, since + # failing to do so can cause incorrect derivatives if iterative processes are ever + # introduced to the system. + # + p.model.linear_solver = DirectSolver() + + p.setup(check=True) + + # + # Assign initial guesses for the independent variables in the problem. + # + p['phase0.t_initial'] = 0.0 + p['phase0.t_duration'] = 500.0 + p['phase0.states:x'] = phase.interpolate(ys=[0, 350000.0], nodes='state_input') + p['phase0.states:y'] = phase.interpolate(ys=[0, 185000.0], nodes='state_input') + p['phase0.states:vx'] = phase.interpolate(ys=[0, 1627.0], nodes='state_input') + p['phase0.states:vy'] = phase.interpolate(ys=[1.0E-6, 0], nodes='state_input') + p['phase0.states:m'] = phase.interpolate(ys=[50000, 50000], nodes='state_input') + p['phase0.polynomial_controls:tan_theta'] = [[0.5 * np.pi], [0.0]] + + # + # Solve the problem. + # + p.run_driver() + + # + # Check the results. + # + assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 481, tolerance=0.01) + + # + # Get the explitly simulated results + # + exp_out = traj.simulate() + + # + # Plot the results + # + fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8)) + + axes[0].plot(p.get_val('phase0.timeseries.states:x'), + p.get_val('phase0.timeseries.states:y'), + marker='o', + ms=4, + linestyle='None', + label='solution') + + axes[0].plot(exp_out.get_val('sim_traj.phase0.timeseries.states:x'), + exp_out.get_val('sim_traj.phase0.timeseries.states:y'), + marker=None, + linestyle='-', + label='simulation') + + axes[0].set_xlabel('range (m)') + axes[0].set_ylabel('altitude (m)') + axes[0].set_aspect('equal') + + axes[1].plot(p.get_val('phase0.timeseries.time'), + p.get_val('phase0.timeseries.theta'), + marker='o', + ms=4, + linestyle='None') + + axes[1].plot(exp_out.get_val('sim_traj.phase0.timeseries.time'), + exp_out.get_val('sim_traj.phase0.timeseries.theta'), + linestyle='-', + marker=None) + + axes[1].set_xlabel('time (s)') + axes[1].set_ylabel('theta (deg)') + + plt.suptitle('Single Stage to Orbit Solution Using Polynomial Controls') + fig.legend(loc='lower center', ncol=2) + + plt.show() + + +if __name__ == "__main__": + unittest.main() diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 49845a904..929664199 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -542,7 +542,10 @@ def simulate(self, times_per_seg=10, method='RK45', atol=1.0E-9, rtol=1.0E-9, re sim_prob = Problem(model=Group()) - sim_prob.model.add_subsystem(self.name, sim_traj) + if self.name: + sim_prob.model.add_subsystem(self.name, sim_traj) + else: + sim_prob.model.add_subsystem('sim_traj', sim_traj) if record_file is not None: rec = SqliteRecorder(record_file) From 2c8fcd6ff6f037a8c3081cc1184eebb28c51105a Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 15 May 2019 12:59:02 -0400 Subject: [PATCH 02/13] progress on custom_targets for trajectory parameters, but still needs work to pass undecorated two phase cannonball. --- dymos/docs/feature_reference/trajectories.rst | 15 ++- .../test_ex_brachistochrone_vector_states.py | 8 +- .../doc/test_doc_two_phase_cannonball.py | 15 +-- ...st_two_phase_cannonball_undecorated_ode.py | 17 +-- dymos/phase/options.py | 32 +++++- dymos/trajectory/trajectory.py | 103 ++++++++---------- .../runge_kutta_state_continuity_comp.py | 3 +- dymos/utils/testing_utils.py | 1 - 8 files changed, 99 insertions(+), 95 deletions(-) diff --git a/dymos/docs/feature_reference/trajectories.rst b/dymos/docs/feature_reference/trajectories.rst index e4766a05a..0057131ee 100644 --- a/dymos/docs/feature_reference/trajectories.rst +++ b/dymos/docs/feature_reference/trajectories.rst @@ -61,9 +61,20 @@ at the trajectory level which maybe be connected to some output external to the When using Trajectory Design and Input parameters, their values are connected to each phase as an Input Parameter within the Phase. Because ODEs in different phases may have different names for parameters (e.g. 'mass', 'm', 'm_total', etc) Dymos allows the user to specify the targeted -ODE parameters on a phase-by-phase basis. +ODE parameters on a phase-by-phase basis using the `custom_targets` option. It can take on the +following values. - +* Left unspecified (`custom_targets = None`), a trajectory design or input parameter will be connected to a decorated ODE parameter of the same name in each phase. + +* Otherwise, `custom_targets` is specified as a dictionary keyed by phase name. + + * If the name of a phase is omitted from `custom_targets`, the trajectory design or input parameter will be connected to a decorated ODE parameter of the same name in that phase. + + * If the phase is specified with a corresponding value of `None`, **the trajectory parameter will not be passed to the phase**. + + * If the phase is specified and the corresponding value is a string, assume the given value is a decorated ODE parameter to which the trajectory parameter should be connected. + + * If the phase is specified and the corresponding parameter value is a list, assume the list gives ODE-level targets to which the parameter should be connected in that phase. If a phase exists within the Trajectory that doesn't utilize the trajectory design/input parameters, it is simply ignored for the purposes of that phase. 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 ac268d400..1c9df9b64 100644 --- a/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py +++ b/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py @@ -6,6 +6,7 @@ from numpy.testing import assert_almost_equal import dymos.examples.brachistochrone.test.ex_brachistochrone_vector_states as ex_brachistochrone_vs +from dymos.utils.testing_utils import use_tempdirs from openmdao.utils.general_utils import set_pyoptsparse_opt from openmdao.utils.assert_utils import assert_check_partials @@ -13,14 +14,9 @@ OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT') +@use_tempdirs class TestBrachistochroneVectorStatesExample(unittest.TestCase): - @classmethod - def tearDownClass(cls): - for filename in ['phase0_sim.db', 'brachistochrone_sim.db']: - if os.path.exists(filename): - os.remove(filename) - def assert_results(self, p): t_initial = p.get_val('phase0.time')[0] t_final = p.get_val('phase0.time')[-1] diff --git a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py index 40d4780e2..64801009c 100644 --- a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py +++ b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py @@ -7,15 +7,11 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt +from dymos.utils.testing_utils import use_tempdirs -class TestTwoPhaseCannonballForDocs(unittest.TestCase): - @classmethod - def tearDownClass(cls): - for filename in ['ex_two_phase_cannonball.db', 'ex_two_phase_cannonball_sim.db', - 'coloring.json']: - if os.path.exists(filename): - os.remove(filename) +@use_tempdirs +class TestTwoPhaseCannonballForDocs(unittest.TestCase): def test_two_phase_cannonball_for_docs(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ @@ -87,10 +83,11 @@ def test_two_phase_cannonball_for_docs(self): # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', - target_params={'ascent': 'm', 'descent': 'm'}, + custom_targets={'ascent': 'm', 'descent': 'm'}, + units='kg', val=1.0) - traj.add_input_parameter('S', val=0.005) + traj.add_input_parameter('S', val=0.005, units='m**2') # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) diff --git a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py index 854902062..0c4950276 100644 --- a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py +++ b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py @@ -13,13 +13,6 @@ @use_tempdirs class TestTwoPhaseCannonball(unittest.TestCase): - @classmethod - def tearDownClass(cls): - for filename in ['ex_two_phase_cannonball.db', 'ex_two_phase_cannonball_sim.db', - 'coloring.json']: - if os.path.exists(filename): - os.remove(filename) - def test_two_phase_cannonball_undecorated_ode(self): from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ pyOptSparseDriver @@ -321,31 +314,25 @@ def test_two_phase_cannonball_mixed_odes(self): # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', targets={'ascent': ['aero.CD']}, - target_params={'descent': 'CD'}, val=0.5, units=None, opt=False) traj.add_design_parameter('CL', targets={'ascent': ['aero.CL']}, - target_params={'descent': 'CL'}, val=0.0, units=None, opt=False) traj.add_design_parameter('T', targets={'ascent': ['eom.T']}, - target_params={'descent': 'T'}, val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', - targets={'ascent': ['eom.alpha']}, - target_params={'descent': 'alpha'}, + targets={'ascent': ['eom.alpha'], 'descent': 'alpha'}, val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', units='kg', - targets={'ascent': ['eom.m', 'kinetic_energy.m']}, - target_params={'ascent': 'm', 'descent': 'm'}, + targets={'ascent': ['eom.m', 'kinetic_energy.m'], 'descent': 'm'}, val=1.0) traj.add_input_parameter('S', units='m**2', targets={'ascent': ['aero.S']}, - target_params={'descent': 'S'}, val=0.005) # Link Phases (link time and all state variables) diff --git a/dymos/phase/options.py b/dymos/phase/options.py index 6b820eed6..bc76ff44b 100644 --- a/dymos/phase/options.py +++ b/dymos/phase/options.py @@ -236,9 +236,6 @@ def __init__(self, read_only=False): self.declare(name='dynamic', types=bool, default=True, desc='True if this parameter can be used as a dynamic control, else False') - self.declare(name='target_params', types=dict, default=None, allow_none=True, - desc='Used to store target information on a per-phase basis for trajectories.') - self.declare(name='targets', types=Iterable, default=[], desc='Used to store target information for the design parameter.') @@ -279,6 +276,19 @@ def __init__(self, read_only=False): 'option is invalid if opt=False.') +class TrajDesignParameterOptionsDictionary(DesignParameterOptionsDictionary): + """ + An OptionsDictionary specific to trajectory design parameters. + """ + + def __init__(self, read_only=False): + super(TrajDesignParameterOptionsDictionary, self).__init__(read_only) + + self.declare(name='custom_targets', types=dict, default=None, allow_none=True, + desc='Used to override the default targets of the trajectory input parameter' + ' in each phase. By default its target will be the same as its name') + + class InputParameterOptionsDictionary(OptionsDictionary): """ An OptionsDictionary specific to input parameters. @@ -301,9 +311,6 @@ def __init__(self, read_only=False): self.declare(name='dynamic', types=bool, default=True, desc='True if this parameter can be used as a dynamic control, else False') - self.declare(name='target_params', types=dict, default=None, allow_none=True, - desc='Used to store target information on a per-phase basis for trajectories.') - self.declare(name='targets', types=Iterable, default=[], desc='Used to store target information for the input parameter.') @@ -314,6 +321,19 @@ def __init__(self, read_only=False): desc='The shape of the design parameter.') +class TrajInputParameterOptionsDictionary(InputParameterOptionsDictionary): + """ + An OptionsDictionary specific to trajectory input parameters. + """ + + def __init__(self, read_only=False): + super(TrajInputParameterOptionsDictionary, self).__init__(read_only) + + self.declare(name='custom_targets', types=dict, default=None, allow_none=True, + desc='Used to override the default targets of the trajectory input parameter' + ' in each phase. By default its target will be the same as its name') + + class StateOptionsDictionary(OptionsDictionary): """ An OptionsDictionary specific to controls. diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 929664199..b7aaba537 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -1,8 +1,8 @@ from __future__ import print_function, division, absolute_import -from collections import Sequence, OrderedDict +from collections import Sequence, OrderedDict, Iterable import itertools -from six import iteritems +from six import iteritems, string_types try: from itertools import izip @@ -17,7 +17,8 @@ from ..utils.constants import INF_BOUND from ..transcriptions.common import InputParameterComp, PhaseLinkageComp -from ..phase.options import DesignParameterOptionsDictionary, InputParameterOptionsDictionary +from ..phase.options import TrajDesignParameterOptionsDictionary, \ + TrajInputParameterOptionsDictionary class Trajectory(Group): @@ -72,18 +73,16 @@ def add_input_parameter(self, name, **kwargs): Name of the design parameter. val : float or ndarray Default value of the design parameter at all nodes. - targets : dict or None - If None, then the design parameter will be connected to the controllable parameter - in the ODE of each phase. For each phase where no such controllable parameter exists, - a warning will be issued. If targets is given as a dict, the dict should provide - the relevant phase names as keys, each associated with the respective controllable - parameteter as a value. + custom_targets : dict or None + By default, the input parameter will be connect to the parameter/targets of the given + name in each phase. This argument can be used to override that behavior on a phase + by phase basis. units : str or None or 0 Units in which the design parameter is defined. If 0, use the units declared for the parameter in the ODE. """ if name not in self.input_parameter_options: - self.input_parameter_options[name] = InputParameterOptionsDictionary() + self.input_parameter_options[name] = TrajInputParameterOptionsDictionary() for kw in kwargs: if kw not in self.input_parameter_options[name]: @@ -131,7 +130,7 @@ def add_design_parameter(self, name, **kwargs): """ if name not in self.design_parameter_options: - self.design_parameter_options[name] = DesignParameterOptionsDictionary() + self.design_parameter_options[name] = TrajDesignParameterOptionsDictionary() for kw in kwargs: if kw not in self.design_parameter_options[name]: @@ -155,29 +154,26 @@ def _setup_input_parameters(self): # Connect the input parameter to its target(s) in each phase src_name = 'input_parameters:{0}_out'.format(name) - # Use target-params to rename the parameter in each phase, if desired. - target_params = options['target_params'] - - # If the phases have no corresponding parameter (are undecorated), - # specify their targets within the ODE here. - targets = options['targets'] - for phase_name, phs in iteritems(self._phases): - tgt_param_name = target_params.get(phase_name, None) \ - if isinstance(target_params, dict) else name - tgt_names = targets.get(phase_name, None) \ - if isinstance(targets, dict) else None - if tgt_param_name is None and tgt_names is not None: - tgt_param_name = name - if tgt_param_name: - kwargs = {'dynamic': options['dynamic'], - 'units': options['units'], - 'val': options['val']} - if tgt_names is not None: - kwargs['targets'] = tgt_names - phs.add_traj_parameter(tgt_param_name, **kwargs) - tgt = '{0}.traj_parameters:{1}'.format(phase_name, tgt_param_name) - self.connect(src_name=src_name, tgt_name=tgt) + # The default target in the phase is name unless otherwise specified. + kwargs = {'dynamic': options['dynamic'], + 'units': options['units'], + 'val': options['val']} + + param_name = name + + if 'custom_targets' in options and options['custom_targets'] is not None: + # Dont add the traj parameter to the phase if it is explicitly excluded. + if options['custom_targets'][phase_name] is None: + continue + if isinstance(options['custom_targets'][phase_name], string_types): + param_name = options['custom_targets'][phase_name] + elif isinstance(options['custom_targets'][phase_name], Iterable): + kwargs['targets'] = options['custom_targets'][phase_name] + + phs.add_traj_parameter(param_name, **kwargs) + tgt = '{0}.traj_parameters:{1}'.format(phase_name, param_name) + self.connect(src_name=src_name, tgt_name=tgt) def _setup_design_parameters(self): """ @@ -209,29 +205,26 @@ def _setup_design_parameters(self): # Connect the design parameter to its target in each phase src_name = 'design_parameters:{0}'.format(name) - # Use target-params to rename the parameter in each phase, if desired. - target_params = options['target_params'] - - # If the phases have no corresponding parameter (are undecorated), - # specify their targets within the ODE here. - targets = options['targets'] - for phase_name, phs in iteritems(self._phases): - tgt_param_name = target_params.get(phase_name, None) \ - if isinstance(target_params, dict) else name - tgt_names = targets.get(phase_name, None) \ - if isinstance(targets, dict) else None - if tgt_param_name is None and tgt_names is not None: - tgt_param_name = name - if tgt_param_name: - kwargs = {'dynamic': options['dynamic'], - 'units': options['units'], - 'val': options['val']} - if tgt_names is not None: - kwargs['targets'] = tgt_names - phs.add_traj_parameter(tgt_param_name, **kwargs) - tgt = '{0}.traj_parameters:{1}'.format(phase_name, tgt_param_name) - self.connect(src_name=src_name, tgt_name=tgt) + # The default target in the phase is name unless otherwise specified. + kwargs = {'dynamic': options['dynamic'], + 'units': options['units'], + 'val': options['val']} + + param_name = name + + if 'custom_targets' in options and options['custom_targets'] is not None: + # Dont add the traj parameter to the phase if it is explicitly excluded. + if options['custom_targets'][phase_name] is None: + continue + if isinstance(options['custom_targets'][phase_name], string_types): + param_name = options['custom_targets'][phase_name] + elif isinstance(options['custom_targets'][phase_name], Iterable): + kwargs['targets'] = options['custom_targets'][phase_name] + + phs.add_traj_parameter(param_name, **kwargs) + tgt = '{0}.traj_parameters:{1}'.format(phase_name, param_name) + self.connect(src_name=src_name, tgt_name=tgt) def _setup_linkages(self): link_comp = None diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_comp.py index f5c9fb638..85e58f012 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_comp.py @@ -11,7 +11,8 @@ class RungeKuttaStateContinuityComp(ImplicitComponent): """ - A simple equation balance for solving implicit equations. + Implicitly solve the RungeKutta state continuity by forcing final state values to + equal initial state values plus the state integral over each segment. Attributes ---------- diff --git a/dymos/utils/testing_utils.py b/dymos/utils/testing_utils.py index d6b598b10..dcfe65d50 100644 --- a/dymos/utils/testing_utils.py +++ b/dymos/utils/testing_utils.py @@ -14,7 +14,6 @@ def _new_setup(self): def _new_teardown(self): if hasattr(self, 'original_tearDown'): self.original_tearDown() - self.tempdir = os.getcwd() os.chdir(self.startdir) try: shutil.rmtree(self.tempdir) From 34267e906bb73e8b84438442dafb6f12deccfa3b Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 15 May 2019 13:14:03 -0400 Subject: [PATCH 03/13] trajectory parameters now take custom_targets which override the parameter name if given. --- ...st_two_phase_cannonball_undecorated_ode.py | 37 +++++++++---------- dymos/phase/options.py | 4 ++ dymos/trajectory/trajectory.py | 26 +++++++------ 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py index 0c4950276..17656063f 100644 --- a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py +++ b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py @@ -1,6 +1,5 @@ from __future__ import print_function, division, absolute_import -import os import unittest import matplotlib @@ -87,33 +86,29 @@ def test_two_phase_cannonball_undecorated_ode(self): # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', - targets={'ascent': ['aero.CD'], - 'descent': ['aero.CD']}, + custom_targets={'ascent': ['aero.CD'], 'descent': ['aero.CD']}, val=0.5, units=None, opt=False) traj.add_design_parameter('CL', - targets={'ascent': ['aero.CL'], - 'descent': ['aero.CL']}, + custom_targets={'ascent': ['aero.CL'], 'descent': ['aero.CL']}, val=0.0, units=None, opt=False) traj.add_design_parameter('T', - targets={'ascent': ['eom.T'], - 'descent': ['eom.T']}, + custom_targets={'ascent': ['eom.T'], 'descent': ['eom.T']}, val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', - targets={'ascent': ['eom.alpha'], - 'descent': ['eom.alpha']}, + custom_targets={'ascent': ['eom.alpha'], 'descent': ['eom.alpha']}, val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', units='kg', - targets={'ascent': ['eom.m', 'kinetic_energy.m'], - 'descent': ['eom.m', 'kinetic_energy.m']}, + custom_targets={'ascent': ['eom.m', 'kinetic_energy.m'], + 'descent': ['eom.m', 'kinetic_energy.m']}, val=1.0) traj.add_input_parameter('S', units='m**2', - targets={'ascent': ['aero.S'], - 'descent': ['aero.S']}, + custom_targets={'ascent': ['aero.S'], + 'descent': ['aero.S']}, val=0.005) # Link Phases (link time and all state variables) @@ -313,26 +308,28 @@ def test_two_phase_cannonball_mixed_odes(self): # Add internally-managed design parameters to the trajectory. traj.add_design_parameter('CD', - targets={'ascent': ['aero.CD']}, + custom_targets={'ascent': ['aero.CD']}, val=0.5, units=None, opt=False) - traj.add_design_parameter('CL', targets={'ascent': ['aero.CL']}, + traj.add_design_parameter('CL', + custom_targets={'ascent': ['aero.CL']}, val=0.0, units=None, opt=False) traj.add_design_parameter('T', - targets={'ascent': ['eom.T']}, + custom_targets={'ascent': ['eom.T']}, val=0.0, units='N', opt=False) traj.add_design_parameter('alpha', - targets={'ascent': ['eom.alpha'], 'descent': 'alpha'}, + custom_targets={'ascent': ['eom.alpha'], 'descent': 'alpha'}, val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. traj.add_input_parameter('mass', units='kg', - targets={'ascent': ['eom.m', 'kinetic_energy.m'], 'descent': 'm'}, + custom_targets={'ascent': ['eom.m', 'kinetic_energy.m'], + 'descent': 'm'}, val=1.0) traj.add_input_parameter('S', units='m**2', - targets={'ascent': ['aero.S']}, + custom_targets={'ascent': ['aero.S']}, val=0.005) # Link Phases (link time and all state variables) @@ -441,7 +438,7 @@ def test_two_phase_cannonball_mixed_odes(self): axes[i].plot(time_exp['ascent'], x_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], x_exp['descent'], 'r--') - params = ['CL', 'CD', 'T', 'alpha', 'm', 'S'] + params = ['CL', 'CD', 'T', 'alpha', 'S'] fig, axes = plt.subplots(nrows=6, ncols=1, figsize=(12, 6)) for i, param in enumerate(params): p_imp = { diff --git a/dymos/phase/options.py b/dymos/phase/options.py index bc76ff44b..cdeb7f50d 100644 --- a/dymos/phase/options.py +++ b/dymos/phase/options.py @@ -288,6 +288,8 @@ def __init__(self, read_only=False): desc='Used to override the default targets of the trajectory input parameter' ' in each phase. By default its target will be the same as its name') + self._dict.pop('targets') + class InputParameterOptionsDictionary(OptionsDictionary): """ @@ -333,6 +335,8 @@ def __init__(self, read_only=False): desc='Used to override the default targets of the trajectory input parameter' ' in each phase. By default its target will be the same as its name') + self._dict.pop('targets') + class StateOptionsDictionary(OptionsDictionary): """ diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index b7aaba537..4ab4c98a7 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -164,12 +164,13 @@ def _setup_input_parameters(self): if 'custom_targets' in options and options['custom_targets'] is not None: # Dont add the traj parameter to the phase if it is explicitly excluded. - if options['custom_targets'][phase_name] is None: - continue - if isinstance(options['custom_targets'][phase_name], string_types): - param_name = options['custom_targets'][phase_name] - elif isinstance(options['custom_targets'][phase_name], Iterable): - kwargs['targets'] = options['custom_targets'][phase_name] + if phase_name in options['custom_targets']: + if options['custom_targets'][phase_name] is None: + continue + if isinstance(options['custom_targets'][phase_name], string_types): + param_name = options['custom_targets'][phase_name] + elif isinstance(options['custom_targets'][phase_name], Iterable): + kwargs['targets'] = options['custom_targets'][phase_name] phs.add_traj_parameter(param_name, **kwargs) tgt = '{0}.traj_parameters:{1}'.format(phase_name, param_name) @@ -215,12 +216,13 @@ def _setup_design_parameters(self): if 'custom_targets' in options and options['custom_targets'] is not None: # Dont add the traj parameter to the phase if it is explicitly excluded. - if options['custom_targets'][phase_name] is None: - continue - if isinstance(options['custom_targets'][phase_name], string_types): - param_name = options['custom_targets'][phase_name] - elif isinstance(options['custom_targets'][phase_name], Iterable): - kwargs['targets'] = options['custom_targets'][phase_name] + if phase_name in options['custom_targets']: + if options['custom_targets'][phase_name] is None: + continue + if isinstance(options['custom_targets'][phase_name], string_types): + param_name = options['custom_targets'][phase_name] + elif isinstance(options['custom_targets'][phase_name], Iterable): + kwargs['targets'] = options['custom_targets'][phase_name] phs.add_traj_parameter(param_name, **kwargs) tgt = '{0}.traj_parameters:{1}'.format(phase_name, param_name) From dd22e25018f5c56af86b3627afe4cb6b7f9665ea Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 15 May 2019 13:59:37 -0400 Subject: [PATCH 04/13] use_tempdirs causes issues with the sphinx documentation automation --- dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py | 1 - .../doc/test_doc_finite_burn_orbit_raise.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py index 64801009c..af9e439ab 100644 --- a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py +++ b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py @@ -10,7 +10,6 @@ from dymos.utils.testing_utils import use_tempdirs -@use_tempdirs class TestTwoPhaseCannonballForDocs(unittest.TestCase): def test_two_phase_cannonball_for_docs(self): diff --git a/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py b/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py index 20c21955c..a15dcacf0 100644 --- a/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py +++ b/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py @@ -7,10 +7,7 @@ import matplotlib.pyplot as plt plt.style.use('ggplot') -from dymos.utils.testing_utils import use_tempdirs - -@use_tempdirs class TestFiniteBurnOrbitRaise(unittest.TestCase): def test_finite_burn_orbit_raise(self): From 2c6d699117d4fe5c69731740d3ca715e34655e97 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 15 May 2019 14:55:36 -0400 Subject: [PATCH 05/13] Fixed a bug that was preventing time and time_phase from being used as a path constraint in RK phases. In general the user should never want to do this anyway, since simple bounds should be preferred, but it works nonetheless. --- .../test/test_brachistochrone_rk4.py | 62 +++++++++++++++++++ .../transcriptions/runge_kutta/runge_kutta.py | 14 ++--- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py b/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py index 8b1caa687..5bfab508f 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py @@ -556,3 +556,65 @@ def test_brachistochrone_forward_shooting_boundary_constrained_ode_output(self): tolerance=1.0E-3) assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, tolerance=1.0E-3) + + def test_brachistochrone_forward_shooting_path_constrained_time(self): + from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + from openmdao.utils.assert_utils import assert_rel_error + from dymos import Phase, RungeKutta + from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE + + p = Problem(model=Group()) + p.driver = ScipyOptimizeDriver() + + phase = Phase(ode_class=BrachistochroneODE, + transcription=RungeKutta(num_segments=20)) + + p.model.add_subsystem('phase0', phase) + + phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(0.5, 2.0)) + + phase.set_state_options('x', fix_initial=True) + phase.set_state_options('y', fix_initial=True) + phase.set_state_options('v', fix_initial=True) + + phase.add_control('theta', units='deg', lower=0.01, upper=179.9, ref0=0, ref=180.0, + rate_continuity=True, rate2_continuity=True) + + phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) + + # Final state values can't be controlled with simple bounds in ExplicitPhase, + # so use nonlinear boundary constraints instead. + phase.add_boundary_constraint('x', loc='final', equals=10) + phase.add_boundary_constraint('y', loc='final', equals=5) + + phase.add_path_constraint('time', lower=0.0, upper=2.0) + phase.add_path_constraint('time_phase', lower=0.0, upper=2.0) + + # Minimize time at the end of the phase + phase.add_objective('time_phase', loc='final', scaler=1) + + p.model.linear_solver = DirectSolver() + + p.setup(check=True) + + p['phase0.t_initial'] = 0.0 + p['phase0.t_duration'] = 2.0 + + p['phase0.states:x'] = 0 + p['phase0.states:y'] = 10 + p['phase0.states:v'] = 0 + p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') + + # Solve for the optimal trajectory + p.run_driver() + + # Test the results + assert_rel_error(self, p['phase0.time'][-1], 1.8016, tolerance=1.0E-3) + + # Generate the explicitly simulated trajectory + exp_out = phase.simulate() + + assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:x')[-1, 0], 10, + tolerance=1.0E-3) + assert_rel_error(self, exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, + tolerance=1.0E-3) diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index ec6a929c7..f3e5b641b 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -525,18 +525,16 @@ def setup_path_constraints(self, phase): options['shape'] = (1,) options['units'] = time_units if con_units is None else con_units options['linear'] = True - for iseg in range(gd.num_segments): - phase.connect(src_name='time', - tgt_name='path_constraints.all_values:{0}'.format(con_name), - src_indices=self.grid_data.subset_node_indices['segment_ends']) + phase.connect(src_name='time', + tgt_name='path_constraints.all_values:{0}'.format(con_name), + src_indices=self.grid_data.subset_node_indices['segment_ends']) elif var_type == 'time_phase': options['shape'] = (1,) options['units'] = time_units if con_units is None else con_units options['linear'] = True - for iseg in range(gd.num_segments): - phase.connect(src_name='time_phase', - tgt_name='path_constraints.all_values:{0}'.format(con_name), - src_indices=self.grid_data.subset_node_indices['segment_ends']) + phase.connect(src_name='time_phase', + tgt_name='path_constraints.all_values:{0}'.format(con_name), + src_indices=self.grid_data.subset_node_indices['segment_ends']) elif var_type == 'state': state_shape = phase.state_options[var]['shape'] state_units = phase.state_options[var]['units'] From d20365126e4b091d2390873a9af11ec48f491c83 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Tue, 28 May 2019 20:45:23 -0400 Subject: [PATCH 06/13] Rk fixes (#190) * fixed issue with phase linkages on vector variables * fixed src_indices for RungeKutta rate sources when source is a state or control. * cleanup --- .../test/test_double_integrator.py | 40 +++++++++++++++++++ dymos/phase/test/test_phase.py | 17 -------- dymos/trajectory/trajectory.py | 6 +++ .../common/phase_linkage_comp.py | 17 ++++++-- .../transcriptions/runge_kutta/runge_kutta.py | 35 ++++++++++++---- 5 files changed, 86 insertions(+), 29 deletions(-) diff --git a/dymos/examples/double_integrator/test/test_double_integrator.py b/dymos/examples/double_integrator/test/test_double_integrator.py index e47b9a074..9828c324a 100644 --- a/dymos/examples/double_integrator/test/test_double_integrator.py +++ b/dymos/examples/double_integrator/test/test_double_integrator.py @@ -130,6 +130,46 @@ def test_ex_double_integrator_input_times(self, compressed=True): p.run_driver() + def test_double_integrator_rk4(self, compressed=True): + + p = Problem(model=Group()) + p.driver = pyOptSparseDriver() + p.driver.options['dynamic_simul_derivs'] = True + + t = dm.RungeKutta(num_segments=30, order=3, compressed=compressed) + + traj = p.model.add_subsystem('traj', dm.Trajectory()) + + phase = traj.add_phase('phase0', dm.Phase(ode_class=DoubleIntegratorODE, transcription=t)) + + phase.set_time_options(fix_initial=True, fix_duration=True, units='s') + + phase.set_state_options('x', fix_initial=True, rate_source='v', units='m') + phase.set_state_options('v', fix_initial=True, fix_final=False, rate_source='u', units='m/s') + + phase.add_control('u', units='m/s**2', scaler=0.01, continuity=False, rate_continuity=False, + rate2_continuity=False, lower=-1.0, upper=1.0) + + phase.add_boundary_constraint(name='v', loc='final', equals=0, units='m/s') + + # Maximize distance travelled in one second. + phase.add_objective('x', loc='final', scaler=-1) + + p.model.linear_solver = DirectSolver() + + p.setup(check=True) + + p['traj.phase0.t_initial'] = 0.0 + p['traj.phase0.t_duration'] = 1.0 + + p['traj.phase0.states:x'] = phase.interpolate(ys=[0, 0.25], nodes='state_input') + p['traj.phase0.states:v'] = phase.interpolate(ys=[0, 0], nodes='state_input') + p['traj.phase0.controls:u'] = phase.interpolate(ys=[1, -1], nodes='control_input') + + p.run_driver() + + return p + if __name__ == "__main__": diff --git a/dymos/phase/test/test_phase.py b/dymos/phase/test/test_phase.py index 984eec4c6..f33ca56cb 100644 --- a/dymos/phase/test/test_phase.py +++ b/dymos/phase/test/test_phase.py @@ -395,23 +395,6 @@ def test_control_boundary_constraint_gl(self): p.run_driver() - import matplotlib.pyplot as plt - - plt.plot(p.get_val('phase0.timeseries.states:x'), - p.get_val('phase0.timeseries.states:y'), 'ko') - - plt.figure() - - plt.plot(p.get_val('phase0.timeseries.time'), - p.get_val('phase0.timeseries.controls:theta'), 'ro') - - plt.plot(p.get_val('phase0.timeseries.time'), - p.get_val('phase0.timeseries.control_rates:theta_rate'), 'bo') - - plt.plot(p.get_val('phase0.timeseries.time'), - p.get_val('phase0.timeseries.control_rates:theta_rate2'), 'go') - plt.show() - assert_rel_error(self, p.get_val('phase0.timeseries.controls:theta', units='deg')[-1], 90.0) def test_control_rate_boundary_constraint_gl(self): diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 4ab4c98a7..429a8f3d8 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -271,6 +271,7 @@ def _setup_linkages(self): max_varname_length = max(len(name) for name in _vars.keys()) units_map = {} + shape_map = {} vars_to_constrain = [] for var, options in iteritems(_vars): @@ -285,12 +286,16 @@ def _setup_linkages(self): vars_to_constrain.append(var) if var in p1_states: units_map[var] = p1.state_options[var]['units'] + shape_map[var] = p1.state_options[var]['shape'] elif var in p1_controls: units_map[var] = p1.control_options[var]['units'] + shape_map[var] = p1.control_options[var]['shape'] elif var == 'time': units_map[var] = p1.time_options['units'] + shape_map[var] = (1,) else: units_map[var] = None + shape_map[var] = (1,) if vars_to_constrain: if not link_comp: @@ -299,6 +304,7 @@ def _setup_linkages(self): linkage_name = '{0}|{1}'.format(phase_name1, phase_name2) link_comp.add_linkage(name=linkage_name, vars=vars_to_constrain, + shape=shape_map, units=units_map) for var, options in iteritems(_vars): diff --git a/dymos/transcriptions/common/phase_linkage_comp.py b/dymos/transcriptions/common/phase_linkage_comp.py index 19ab103b0..ccf1537b6 100644 --- a/dymos/transcriptions/common/phase_linkage_comp.py +++ b/dymos/transcriptions/common/phase_linkage_comp.py @@ -64,9 +64,10 @@ def add_linkage(self, name, vars, shape=(1,), equals=None, lower=None, upper=Non The name of one or more linkage constraints to be added. vars : str or iterable The name of one or more linked variables to be added. - shape : tuple + shape : tuple or dict The shape of the constraint being formed. Must be compliant with the shape - of the variable. + of the variable. If given as a dict, it should be keyed + with variables in var, and the associated value being the corresponding units. units : str, dict, or None The units of the linkage constraint. If given as a string, the units will apply to each variable in vars. If given as a dict, it should be keyed @@ -92,8 +93,9 @@ def add_linkage(self, name, vars, shape=(1,), equals=None, lower=None, upper=Non That is, the affected variables in each phase are design variables or linear functions of design variables. Default is False. """ + print('adding linkage ', name, vars, shape) if equals is None and lower is None and upper is None: - equals = np.zeros(shape) + equals = 0.0 if isinstance(vars, string_types): _vars = (vars,) @@ -107,6 +109,13 @@ def add_linkage(self, name, vars, shape=(1,), equals=None, lower=None, upper=Non else: _units = units + if isinstance(shape, tuple): + _shapes = {} + for var in _vars: + _shapes[var] = shape + else: + _shapes = shape + for var in _vars: lnk = OptionsDictionary() @@ -133,7 +142,7 @@ def add_linkage(self, name, vars, shape=(1,), equals=None, lower=None, upper=Non lnk['adder'] = adder lnk['ref0'] = ref0 lnk['ref'] = ref - lnk['shape'] = shape + lnk['shape'] = _shapes.get(var, (1,)) lnk['linear'] = linear lnk['units'] = _units.get(var, None) lnk['cond0_name'] = '{0}:lhs'.format(lnk['name']) diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index f3e5b641b..edd21bf4d 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -136,7 +136,7 @@ def setup_ode(self, phase): k_solver_class=self.options['k_solver_class'], k_solver_options=self.options['k_solver_options']), promotes_inputs=promoted_inputs, - promotes_outputs=['states:*']) + promotes_outputs=['states:*', 'state_predict_comp.predicted_states:*']) # Since the RK Solve group evaluates the ODE at *predicted* state values, we need # to instantiate a second ODE group that will call the ODE at the actual integrated @@ -153,6 +153,7 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): raise ValueError('state \'{0}\' in phase \'{1}\' was not given a ' 'rate_source'.format(state_name, phase.name)) shape = phase.state_options[state_name]['shape'] + state_size = np.prod(shape) var_type = phase.classify_var(var) num_segments = self.options['num_segments'] num_stages = rk_methods[self.options['method']]['num_stages'] @@ -165,37 +166,55 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): rate_path = 'time_phase' src_idxs = None elif var_type == 'state': - rate_path = 'predicted_states:{0}'.format(var) + rate_path = 'state_predict_comp.predicted_states:{0}'.format(var) + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'indep_control': rate_path = 'control_values:{0}'.format(var) - src_idxs = None + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'input_control': rate_path = 'control_values:{0}'.format(var) - src_idxs = None + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'control_rate': rate_path = 'control_rates:{0}'.format(var) - src_idxs = None + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'control_rate2': rate_path = 'control_rates:{0}'.format(var) - src_idxs = None + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'indep_polynomial_control': rate_path = 'polynomial_control_values:{0}'.format(var) + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'input_polynomial_control': rate_path = 'polynomial_control_values:{0}'.format(var) + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'polynomial_control_rate': control_name = var[:-5] rate_path = 'polynomial_control_rates:{0}_rate'.format(control_name) + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'polynomial_control_rate2': control_name = var[:-6] rate_path = 'polynomial_control_rates:{0}_rate2'.format(control_name) + size = num_segments * num_stages * state_size + src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'design_parameter': rate_path = 'design_parameters:{0}'.format(var) size = np.prod(phase.design_parameter_options[var]['shape']) - src_idxs = np.zeros(num_segments * num_stages * size, dtype=int) + src_idxs = np.zeros(num_segments * num_stages * size, dtype=int).reshape((num_segments, + num_stages, + state_size)) elif var_type == 'input_parameter': rate_path = 'input_parameters:{0}_out'.format(var) size = np.prod(phase.input_parameter_options[var]['shape']) - src_idxs = np.zeros(num_segments * num_stages * size, dtype=int) + src_idxs = np.zeros(num_segments * num_stages * size, dtype=int).reshape((num_segments, + num_stages, + state_size)) else: # Failed to find variable, assume it is in the ODE rate_path = 'rk_solve_group.ode.{0}'.format(var) From 8d763d93cbfcd00a8fb85192951215c27835eda6 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Fri, 14 Jun 2019 12:58:58 -0400 Subject: [PATCH 07/13] Changed input promotion to avoid warnings in latest OpenMDAO version. (#193) * Changed input promotion to avoid warnings in latest OpenMDAO version. * fixed an issue with a variable name lingering from a list comprehension on py27. --- dymos/phase/test/test_time_targets.py | 14 +++-- dymos/trajectory/trajectory.py | 22 +++++-- .../components/runge_kutta_k_iter_group.py | 3 +- ...runge_kutta_state_continuity_iter_group.py | 5 +- .../test/test_rk_continuity_iter_group.py | 61 ++++++++++--------- .../components/test/test_rk_k_iter_group.py | 6 +- .../transcriptions/runge_kutta/runge_kutta.py | 33 +++++----- 7 files changed, 81 insertions(+), 63 deletions(-) diff --git a/dymos/phase/test/test_time_targets.py b/dymos/phase/test/test_time_targets.py index e9506c977..dc03d6c02 100644 --- a/dymos/phase/test/test_time_targets.py +++ b/dymos/phase/test/test_time_targets.py @@ -263,16 +263,20 @@ def test_runge_kutta(self): # Test the iteration ODE - assert_rel_error(self, p['phase0.rk_solve_group.ode.time_phase'][-1], 1.8016, + assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time_phase'][-1], 1.8016, tolerance=1.0E-3) - assert_rel_error(self, p['phase0.rk_solve_group.ode.t_initial'], p['phase0.t_initial']) + assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.t_initial'], + p['phase0.t_initial']) - assert_rel_error(self, p['phase0.rk_solve_group.ode.t_duration'], p['phase0.t_duration']) + assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.t_duration'], + p['phase0.t_duration']) - assert_rel_error(self, p['phase0.rk_solve_group.ode.time_phase'], time_phase_all) + assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time_phase'], + time_phase_all) - assert_rel_error(self, p['phase0.rk_solve_group.ode.time'], time_all) + assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time'], + time_all) # Now test the final ODE diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 429a8f3d8..4fb9e184e 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -351,7 +351,7 @@ def _setup_linkages(self): path = 'initial_states:{0}'.format(var) self.connect('{0}.{1}'.format(phase_name1, source1), - '{0}.{1}'.format(phase_name2, path)) + 'phases.{0}.{1}'.format(phase_name2, path)) print(' {0:<{2}s} --> {1:<{2}s}'.format(source1, source2, max_varname_length + 9)) @@ -381,14 +381,28 @@ def setup(self): if self.input_parameter_options: self._setup_input_parameters() - phases_group = self.add_subsystem('phases', subsys=ParallelGroup(), promotes_inputs=['*'], - promotes_outputs=['*']) + phases_group = ParallelGroup() + + promoted_inputs = [] for name, phs in iteritems(self._phases): g = phases_group.add_subsystem(name, phs, **self._phase_add_kwargs[name]) + phs.finalize_variables() + promoted_inputs.append('{0}.t_initial'.format(name)) + promoted_inputs.append('{0}.t_duration'.format(name)) + if phs.input_parameter_options: + promoted_inputs.append('{0}.input_parameters:*'.format(name)) + if phs.traj_parameter_options: + promoted_inputs.append('{0}.traj_parameters:*'.format(name)) + input_controls = [cname for cname, opts in iteritems(phs.control_options) if not opts['opt']] + if input_controls: + promoted_inputs.append('{0}.controls:*'.format(name)) # DirectSolvers were moved down into the phases for use with MPI g.linear_solver = DirectSolver() - phs.finalize_variables() + + self.add_subsystem('phases', phases_group, + promotes_inputs=promoted_inputs, + promotes_outputs=['*']) if self._linkages: self._setup_linkages() diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py index 2b2d12602..843d58c97 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py @@ -65,8 +65,7 @@ def setup(self): subsys=RungeKuttaKComp(method=self.options['method'], num_segments=num_seg, state_options=state_options, - time_units=self.options['time_units']), - promotes_inputs=['h']) + time_units=self.options['time_units'])) for state_name, options in iteritems(self.options['state_options']): # Connect the state predicted (assumed) value to its targets in the ode diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py index 3e0f847e8..3be43ca4f 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py @@ -61,8 +61,7 @@ def setup(self): ode_init_kwargs=self.options['ode_init_kwargs'], solver_class=self.options['k_solver_class'], solver_options=self.options['k_solver_options']), - promotes_inputs=['*'], - promotes_outputs=['*']) + promotes_inputs=['initial_states_per_seg:*']) self.add_subsystem('state_advance_comp', RungeKuttaStateAdvanceComp(num_segments=self.options['num_segments'], @@ -86,7 +85,7 @@ def setup(self): promotes_outputs=['states:*']) for state_name, options in iteritems(self.options['state_options']): - self.connect('k_comp.k:{0}'.format(state_name), + self.connect('k_iter_group.k_comp.k:{0}'.format(state_name), 'state_advance_comp.k:{0}'.format(state_name)) row_idxs = np.arange(self.options['num_segments'], dtype=int) src_idxs = get_src_indices_by_row(row_idxs, options['shape']) diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py index 197e20040..f0581ecf3 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py @@ -43,11 +43,12 @@ def test_continuity_comp_no_iteration(self): k_solver_class=NonlinearRunOnce), promotes_outputs=['states:*']) - p.model.connect('h', 'cnty_iter_group.h') - p.model.connect('time', 'cnty_iter_group.ode.t') + p.model.connect('h', 'cnty_iter_group.k_iter_group.k_comp.h') + p.model.connect('time', 'cnty_iter_group.k_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) - p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', + p.model.connect('cnty_iter_group.k_iter_group.ode.ydot', + 'cnty_iter_group.k_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = NonlinearRunOnce() @@ -61,25 +62,25 @@ def test_continuity_comp_no_iteration(self): [4.006818970044454], [5.301605229265987]]) - p['cnty_iter_group.k_comp.k:y'] = np.array([[[0.75000000], - [0.90625000], - [0.94531250], - [1.09765625]], + p['cnty_iter_group.k_iter_group.k_comp.k:y'] = np.array([[[0.75000000], + [0.90625000], + [0.94531250], + [1.09765625]], - [[1.087565104166667], - [1.203206380208333], - [1.232116699218750], - [1.328623453776042]], + [[1.087565104166667], + [1.203206380208333], + [1.232116699218750], + [1.328623453776042]], - [[1.319801330566406], - [1.368501663208008], - [1.380676746368408], - [1.385139703750610]], + [[1.319801330566406], + [1.368501663208008], + [1.380676746368408], + [1.385139703750610]], - [[1.378409485022227], - [1.316761856277783], - [1.301349949091673], - [1.154084459568063]]]) + [[1.378409485022227], + [1.316761856277783], + [1.301349949091673], + [1.154084459568063]]]) p.run_model() p.model.run_apply_nonlinear() @@ -130,21 +131,21 @@ def test_continuity_comp_newtonsolver(self): ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') p.model.add_subsystem('cnty_iter_group', - RungeKuttaStateContinuityIterGroup( - num_segments=num_seg, - method='RK4', - state_options=state_options, - time_units='s', - ode_class=TestODE, - ode_init_kwargs={}, - k_solver_class=None), + RungeKuttaStateContinuityIterGroup(num_segments=num_seg, + method='RK4', + state_options=state_options, + time_units='s', + ode_class=TestODE, + ode_init_kwargs={}, + k_solver_class=None), promotes_outputs=['states:*']) - p.model.connect('h', 'cnty_iter_group.h') - p.model.connect('time', 'cnty_iter_group.ode.t') + p.model.connect('h', 'cnty_iter_group.k_iter_group.k_comp.h') + p.model.connect('time', 'cnty_iter_group.k_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) - p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', + p.model.connect('cnty_iter_group.k_iter_group.ode.ydot', + 'cnty_iter_group.k_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = NewtonSolver() diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py index 7c183fee9..f4d9b03dc 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py @@ -38,7 +38,7 @@ def test_rk4_scalar_no_iteration(self): solver_class=NonlinearRunOnce)) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.h') + p.model.connect('h', 'k_iter_group.k_comp.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) @@ -114,7 +114,7 @@ def test_rk4_scalar_nonlinearblockgs(self): solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.h') + p.model.connect('h', 'k_iter_group.k_comp.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) @@ -173,7 +173,7 @@ def test_rk4_scalar_newton(self): solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.h') + p.model.connect('h', 'k_iter_group.k_comp.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index edd21bf4d..662f5a4a9 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -87,13 +87,14 @@ def setup_time(self, phase): phase.add_subsystem('stepsize_comp', subsys=h_comp, - promotes_inputs=['t_duration'], - promotes_outputs=['h']) + promotes_inputs=['t_duration']) + + phase.connect('stepsize_comp.h', 'rk_solve_group.k_iter_group.k_comp.h') if phase.time_options['targets']: time_tgts = phase.time_options['targets'] - phase.connect('time', ['rk_solve_group.ode.{0}'.format(t) for t in time_tgts], + phase.connect('time', ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_tgts], src_indices=grid_data.subset_node_indices['all']) phase.connect('time', ['ode.{0}'.format(t) for t in time_tgts], @@ -102,20 +103,20 @@ def setup_time(self, phase): if phase.time_options['time_phase_targets']: time_phase_tgts = phase.time_options['time_phase_targets'] phase.connect('time_phase', - ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('time_phase', ['ode.{0}'.format(t) for t in time_phase_tgts], src_indices=grid_data.subset_node_indices['segment_ends']) if phase.time_options['t_initial_targets']: time_phase_tgts = phase.time_options['t_initial_targets'] - phase.connect('t_initial', ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) + phase.connect('t_initial', ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('t_initial', ['ode.{0}'.format(t) for t in time_phase_tgts]) if phase.time_options['t_duration_targets']: time_phase_tgts = phase.time_options['t_duration_targets'] phase.connect('t_duration', - ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('t_duration', ['ode.{0}'.format(t) for t in time_phase_tgts]) @@ -123,7 +124,7 @@ def setup_ode(self, phase): num_connected = len([s for s in phase.state_options if phase.state_options[s]['connected_initial']]) - promoted_inputs = ['h'] if num_connected == 0 else ['h', 'initial_states:*'] + promoted_inputs = [] if num_connected == 0 else ['initial_states:*'] phase.add_subsystem('rk_solve_group', RungeKuttaStateContinuityIterGroup( @@ -136,7 +137,7 @@ def setup_ode(self, phase): k_solver_class=self.options['k_solver_class'], k_solver_options=self.options['k_solver_options']), promotes_inputs=promoted_inputs, - promotes_outputs=['states:*', 'state_predict_comp.predicted_states:*']) + promotes_outputs=['states:*']) # Since the RK Solve group evaluates the ODE at *predicted* state values, we need # to instantiate a second ODE group that will call the ODE at the actual integrated @@ -166,7 +167,7 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): rate_path = 'time_phase' src_idxs = None elif var_type == 'state': - rate_path = 'state_predict_comp.predicted_states:{0}'.format(var) + rate_path = 'rk_solve_group.k_iter_group.state_predict_comp.predicted_states:{0}'.format(var) size = num_segments * num_stages * state_size src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'indep_control': @@ -217,7 +218,7 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): state_size)) else: # Failed to find variable, assume it is in the ODE - rate_path = 'rk_solve_group.ode.{0}'.format(var) + rate_path = 'rk_solve_group.k_iter_group.ode.{0}'.format(var) state_size = np.prod(shape) size = num_segments * num_stages * state_size src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) @@ -247,7 +248,7 @@ def setup_states(self, phase): rate_path, src_idxs = self._get_rate_source_path(state_name, phase) phase.connect(rate_path, - 'rk_solve_group.k_comp.f:{0}'.format(state_name), + 'rk_solve_group.k_iter_group.k_comp.f:{0}'.format(state_name), src_indices=src_idxs, flat_src_indices=True) @@ -316,7 +317,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs.ravel(), flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs.ravel(), flat_src_indices=True) if phase.control_options[name]['rate_targets']: @@ -328,7 +329,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs, flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.{0}'.format(t) for t in targets], + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs, flat_src_indices=True) if phase.control_options[name]['rate2_targets']: @@ -340,7 +341,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs, flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.{0}'.format(t) for t in targets], + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs, flat_src_indices=True) def setup_polynomial_controls(self, phase): @@ -361,7 +362,7 @@ def setup_polynomial_controls(self, phase): src_indices=segend_src_idxs.ravel(), flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs.ravel(), flat_src_indices=True) if phase.polynomial_control_options[name]['rate_targets']: @@ -902,7 +903,7 @@ def get_parameter_connections(self, name, phase): src_idxs = get_src_indices_by_row(src_idxs_raw, shape) src_idxs = np.squeeze(src_idxs, axis=0) - connection_info.append((['rk_solve_group.ode.{0}'.format(tgt) for tgt in ode_tgts], + connection_info.append((['rk_solve_group.k_iter_group.ode.{0}'.format(tgt) for tgt in ode_tgts], src_idxs)) return connection_info From c0ad50186c7809d5c237d4cb817bc99a7ca821f1 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Mon, 17 Jun 2019 08:32:44 -0400 Subject: [PATCH 08/13] Revert "Changed input promotion to avoid warnings in latest OpenMDAO version. (#193)" (#194) This reverts commit 8d763d93cbfcd00a8fb85192951215c27835eda6. --- dymos/phase/test/test_time_targets.py | 14 ++--- dymos/trajectory/trajectory.py | 22 ++----- .../components/runge_kutta_k_iter_group.py | 3 +- ...runge_kutta_state_continuity_iter_group.py | 5 +- .../test/test_rk_continuity_iter_group.py | 61 +++++++++---------- .../components/test/test_rk_k_iter_group.py | 6 +- .../transcriptions/runge_kutta/runge_kutta.py | 33 +++++----- 7 files changed, 63 insertions(+), 81 deletions(-) diff --git a/dymos/phase/test/test_time_targets.py b/dymos/phase/test/test_time_targets.py index dc03d6c02..e9506c977 100644 --- a/dymos/phase/test/test_time_targets.py +++ b/dymos/phase/test/test_time_targets.py @@ -263,20 +263,16 @@ def test_runge_kutta(self): # Test the iteration ODE - assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time_phase'][-1], 1.8016, + assert_rel_error(self, p['phase0.rk_solve_group.ode.time_phase'][-1], 1.8016, tolerance=1.0E-3) - assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.t_initial'], - p['phase0.t_initial']) + assert_rel_error(self, p['phase0.rk_solve_group.ode.t_initial'], p['phase0.t_initial']) - assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.t_duration'], - p['phase0.t_duration']) + assert_rel_error(self, p['phase0.rk_solve_group.ode.t_duration'], p['phase0.t_duration']) - assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time_phase'], - time_phase_all) + assert_rel_error(self, p['phase0.rk_solve_group.ode.time_phase'], time_phase_all) - assert_rel_error(self, p['phase0.rk_solve_group.k_iter_group.ode.time'], - time_all) + assert_rel_error(self, p['phase0.rk_solve_group.ode.time'], time_all) # Now test the final ODE diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 4fb9e184e..429a8f3d8 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -351,7 +351,7 @@ def _setup_linkages(self): path = 'initial_states:{0}'.format(var) self.connect('{0}.{1}'.format(phase_name1, source1), - 'phases.{0}.{1}'.format(phase_name2, path)) + '{0}.{1}'.format(phase_name2, path)) print(' {0:<{2}s} --> {1:<{2}s}'.format(source1, source2, max_varname_length + 9)) @@ -381,28 +381,14 @@ def setup(self): if self.input_parameter_options: self._setup_input_parameters() - phases_group = ParallelGroup() - - promoted_inputs = [] + phases_group = self.add_subsystem('phases', subsys=ParallelGroup(), promotes_inputs=['*'], + promotes_outputs=['*']) for name, phs in iteritems(self._phases): g = phases_group.add_subsystem(name, phs, **self._phase_add_kwargs[name]) - phs.finalize_variables() - promoted_inputs.append('{0}.t_initial'.format(name)) - promoted_inputs.append('{0}.t_duration'.format(name)) - if phs.input_parameter_options: - promoted_inputs.append('{0}.input_parameters:*'.format(name)) - if phs.traj_parameter_options: - promoted_inputs.append('{0}.traj_parameters:*'.format(name)) - input_controls = [cname for cname, opts in iteritems(phs.control_options) if not opts['opt']] - if input_controls: - promoted_inputs.append('{0}.controls:*'.format(name)) # DirectSolvers were moved down into the phases for use with MPI g.linear_solver = DirectSolver() - - self.add_subsystem('phases', phases_group, - promotes_inputs=promoted_inputs, - promotes_outputs=['*']) + phs.finalize_variables() if self._linkages: self._setup_linkages() diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py index 843d58c97..2b2d12602 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py @@ -65,7 +65,8 @@ def setup(self): subsys=RungeKuttaKComp(method=self.options['method'], num_segments=num_seg, state_options=state_options, - time_units=self.options['time_units'])) + time_units=self.options['time_units']), + promotes_inputs=['h']) for state_name, options in iteritems(self.options['state_options']): # Connect the state predicted (assumed) value to its targets in the ode diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py index 3be43ca4f..3e0f847e8 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py @@ -61,7 +61,8 @@ def setup(self): ode_init_kwargs=self.options['ode_init_kwargs'], solver_class=self.options['k_solver_class'], solver_options=self.options['k_solver_options']), - promotes_inputs=['initial_states_per_seg:*']) + promotes_inputs=['*'], + promotes_outputs=['*']) self.add_subsystem('state_advance_comp', RungeKuttaStateAdvanceComp(num_segments=self.options['num_segments'], @@ -85,7 +86,7 @@ def setup(self): promotes_outputs=['states:*']) for state_name, options in iteritems(self.options['state_options']): - self.connect('k_iter_group.k_comp.k:{0}'.format(state_name), + self.connect('k_comp.k:{0}'.format(state_name), 'state_advance_comp.k:{0}'.format(state_name)) row_idxs = np.arange(self.options['num_segments'], dtype=int) src_idxs = get_src_indices_by_row(row_idxs, options['shape']) diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py index f0581ecf3..197e20040 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py @@ -43,12 +43,11 @@ def test_continuity_comp_no_iteration(self): k_solver_class=NonlinearRunOnce), promotes_outputs=['states:*']) - p.model.connect('h', 'cnty_iter_group.k_iter_group.k_comp.h') - p.model.connect('time', 'cnty_iter_group.k_iter_group.ode.t') + p.model.connect('h', 'cnty_iter_group.h') + p.model.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) - p.model.connect('cnty_iter_group.k_iter_group.ode.ydot', - 'cnty_iter_group.k_iter_group.k_comp.f:y', + p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = NonlinearRunOnce() @@ -62,25 +61,25 @@ def test_continuity_comp_no_iteration(self): [4.006818970044454], [5.301605229265987]]) - p['cnty_iter_group.k_iter_group.k_comp.k:y'] = np.array([[[0.75000000], - [0.90625000], - [0.94531250], - [1.09765625]], + p['cnty_iter_group.k_comp.k:y'] = np.array([[[0.75000000], + [0.90625000], + [0.94531250], + [1.09765625]], - [[1.087565104166667], - [1.203206380208333], - [1.232116699218750], - [1.328623453776042]], + [[1.087565104166667], + [1.203206380208333], + [1.232116699218750], + [1.328623453776042]], - [[1.319801330566406], - [1.368501663208008], - [1.380676746368408], - [1.385139703750610]], + [[1.319801330566406], + [1.368501663208008], + [1.380676746368408], + [1.385139703750610]], - [[1.378409485022227], - [1.316761856277783], - [1.301349949091673], - [1.154084459568063]]]) + [[1.378409485022227], + [1.316761856277783], + [1.301349949091673], + [1.154084459568063]]]) p.run_model() p.model.run_apply_nonlinear() @@ -131,21 +130,21 @@ def test_continuity_comp_newtonsolver(self): ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') p.model.add_subsystem('cnty_iter_group', - RungeKuttaStateContinuityIterGroup(num_segments=num_seg, - method='RK4', - state_options=state_options, - time_units='s', - ode_class=TestODE, - ode_init_kwargs={}, - k_solver_class=None), + RungeKuttaStateContinuityIterGroup( + num_segments=num_seg, + method='RK4', + state_options=state_options, + time_units='s', + ode_class=TestODE, + ode_init_kwargs={}, + k_solver_class=None), promotes_outputs=['states:*']) - p.model.connect('h', 'cnty_iter_group.k_iter_group.k_comp.h') - p.model.connect('time', 'cnty_iter_group.k_iter_group.ode.t') + p.model.connect('h', 'cnty_iter_group.h') + p.model.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) - p.model.connect('cnty_iter_group.k_iter_group.ode.ydot', - 'cnty_iter_group.k_iter_group.k_comp.f:y', + p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = NewtonSolver() diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py index f4d9b03dc..7c183fee9 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py @@ -38,7 +38,7 @@ def test_rk4_scalar_no_iteration(self): solver_class=NonlinearRunOnce)) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.k_comp.h') + p.model.connect('h', 'k_iter_group.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) @@ -114,7 +114,7 @@ def test_rk4_scalar_nonlinearblockgs(self): solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.k_comp.h') + p.model.connect('h', 'k_iter_group.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) @@ -173,7 +173,7 @@ def test_rk4_scalar_newton(self): solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') - p.model.connect('h', 'k_iter_group.k_comp.h') + p.model.connect('h', 'k_iter_group.h') p.model.connect('initial_states_per_seg:y', 'k_iter_group.initial_states_per_seg:y') src_idxs = np.arange(16, dtype=int).reshape((num_seg, num_stages, 1)) diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index 662f5a4a9..edd21bf4d 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -87,14 +87,13 @@ def setup_time(self, phase): phase.add_subsystem('stepsize_comp', subsys=h_comp, - promotes_inputs=['t_duration']) - - phase.connect('stepsize_comp.h', 'rk_solve_group.k_iter_group.k_comp.h') + promotes_inputs=['t_duration'], + promotes_outputs=['h']) if phase.time_options['targets']: time_tgts = phase.time_options['targets'] - phase.connect('time', ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_tgts], + phase.connect('time', ['rk_solve_group.ode.{0}'.format(t) for t in time_tgts], src_indices=grid_data.subset_node_indices['all']) phase.connect('time', ['ode.{0}'.format(t) for t in time_tgts], @@ -103,20 +102,20 @@ def setup_time(self, phase): if phase.time_options['time_phase_targets']: time_phase_tgts = phase.time_options['time_phase_targets'] phase.connect('time_phase', - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) + ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('time_phase', ['ode.{0}'.format(t) for t in time_phase_tgts], src_indices=grid_data.subset_node_indices['segment_ends']) if phase.time_options['t_initial_targets']: time_phase_tgts = phase.time_options['t_initial_targets'] - phase.connect('t_initial', ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) + phase.connect('t_initial', ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('t_initial', ['ode.{0}'.format(t) for t in time_phase_tgts]) if phase.time_options['t_duration_targets']: time_phase_tgts = phase.time_options['t_duration_targets'] phase.connect('t_duration', - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in time_phase_tgts]) + ['rk_solve_group.ode.{0}'.format(t) for t in time_phase_tgts]) phase.connect('t_duration', ['ode.{0}'.format(t) for t in time_phase_tgts]) @@ -124,7 +123,7 @@ def setup_ode(self, phase): num_connected = len([s for s in phase.state_options if phase.state_options[s]['connected_initial']]) - promoted_inputs = [] if num_connected == 0 else ['initial_states:*'] + promoted_inputs = ['h'] if num_connected == 0 else ['h', 'initial_states:*'] phase.add_subsystem('rk_solve_group', RungeKuttaStateContinuityIterGroup( @@ -137,7 +136,7 @@ def setup_ode(self, phase): k_solver_class=self.options['k_solver_class'], k_solver_options=self.options['k_solver_options']), promotes_inputs=promoted_inputs, - promotes_outputs=['states:*']) + promotes_outputs=['states:*', 'state_predict_comp.predicted_states:*']) # Since the RK Solve group evaluates the ODE at *predicted* state values, we need # to instantiate a second ODE group that will call the ODE at the actual integrated @@ -167,7 +166,7 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): rate_path = 'time_phase' src_idxs = None elif var_type == 'state': - rate_path = 'rk_solve_group.k_iter_group.state_predict_comp.predicted_states:{0}'.format(var) + rate_path = 'state_predict_comp.predicted_states:{0}'.format(var) size = num_segments * num_stages * state_size src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) elif var_type == 'indep_control': @@ -218,7 +217,7 @@ def _get_rate_source_path(self, state_name, phase, nodes=None, **kwargs): state_size)) else: # Failed to find variable, assume it is in the ODE - rate_path = 'rk_solve_group.k_iter_group.ode.{0}'.format(var) + rate_path = 'rk_solve_group.ode.{0}'.format(var) state_size = np.prod(shape) size = num_segments * num_stages * state_size src_idxs = np.arange(size, dtype=int).reshape((num_segments, num_stages, state_size)) @@ -248,7 +247,7 @@ def setup_states(self, phase): rate_path, src_idxs = self._get_rate_source_path(state_name, phase) phase.connect(rate_path, - 'rk_solve_group.k_iter_group.k_comp.f:{0}'.format(state_name), + 'rk_solve_group.k_comp.f:{0}'.format(state_name), src_indices=src_idxs, flat_src_indices=True) @@ -317,7 +316,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs.ravel(), flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs.ravel(), flat_src_indices=True) if phase.control_options[name]['rate_targets']: @@ -329,7 +328,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs, flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.{0}'.format(t) for t in targets], src_indices=all_src_idxs, flat_src_indices=True) if phase.control_options[name]['rate2_targets']: @@ -341,7 +340,7 @@ def setup_controls(self, phase): src_indices=segend_src_idxs, flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.{0}'.format(t) for t in targets], src_indices=all_src_idxs, flat_src_indices=True) def setup_polynomial_controls(self, phase): @@ -362,7 +361,7 @@ def setup_polynomial_controls(self, phase): src_indices=segend_src_idxs.ravel(), flat_src_indices=True) phase.connect(src_name, - ['rk_solve_group.k_iter_group.ode.{0}'.format(t) for t in targets], + ['rk_solve_group.ode.{0}'.format(t) for t in targets], src_indices=all_src_idxs.ravel(), flat_src_indices=True) if phase.polynomial_control_options[name]['rate_targets']: @@ -903,7 +902,7 @@ def get_parameter_connections(self, name, phase): src_idxs = get_src_indices_by_row(src_idxs_raw, shape) src_idxs = np.squeeze(src_idxs, axis=0) - connection_info.append((['rk_solve_group.k_iter_group.ode.{0}'.format(tgt) for tgt in ode_tgts], + connection_info.append((['rk_solve_group.ode.{0}'.format(tgt) for tgt in ode_tgts], src_idxs)) return connection_info From 3739becbad90afac3bb8a8ed46c4cc1d8b1a990b Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Mon, 24 Jun 2019 15:25:13 -0400 Subject: [PATCH 09/13] OpenMDAO API updates (#195) * Revert "Changed input promotion to avoid warnings in latest OpenMDAO version. (#193)" This reverts commit 8d763d93cbfcd00a8fb85192951215c27835eda6. * switched all openmdao and dymos namespaces to om and dm, respectively * converted dynamic_simul_derivs to declare_coloring * Included changes from naylor-b pull request. * SNOPT -> SLSQP * fixes for a few problematic tests. test cases do not plot by default. --- benchmark/benchmark_brachistochrone.py | 12 +- dymos/docs/examples/brachistochrone.rst | 2 +- .../figures/ssto_linear_tangent_xdsm.py | 4 +- dymos/docs/examples/figures/ssto_xdsm.py | 4 +- .../docs/examples/multibranch_trajectory.rst | 2 +- .../feature_reference/simultaneous_derivs.rst | 23 +- .../plot_high_order_gauss_lobatto.py | 10 +- .../plot_radau-pseudospectral.py | 10 +- .../aero/aero_coef_comp.py | 5 +- .../aero/aero_forces_comp.py | 4 +- .../aero/aerodynamics_group.py | 5 +- .../aero/mbi_aero_coef_comp.py | 5 +- .../aero/test/test_aero_coef_comp.py | 6 +- .../aero/test/test_mbi_aero_coef_comp.py | 12 +- .../aircraft_steady_flight/aircraft_ode.py | 30 +- .../doc/test_doc_aircraft_steady_flight.py | 12 +- .../dynamic_pressure_comp.py | 4 +- .../lift_equilibrium_comp.py | 4 +- .../steady_flight_equilibrium_group.py | 14 +- .../test/test_flight_equilibrium_group.py | 6 +- .../thrust_equilibrium_comp.py | 4 +- .../aircraft_steady_flight/mass_comp.py | 4 +- .../propulsion/fuel_burn_rate_comp.py | 4 +- .../propulsion/max_thrust_comp.py | 4 +- .../propulsion/propulsion_group.py | 8 +- .../propulsion/test/test_propulsion_group.py | 6 +- .../propulsion/throttle_comp.py | 4 +- .../propulsion/thrust_comp.py | 4 +- .../propulsion/tsfc_comp.py | 4 +- .../aircraft_steady_flight/range_rate_comp.py | 4 +- .../steady_flight_path_angle_comp.py | 4 +- .../test/test_aircraft_cruise.py | 49 ++- .../test/test_aircraft_ode.py | 10 +- .../test/test_ex_aircraft_steady_flight.py | 12 +- .../true_airspeed_comp.py | 4 +- .../examples/battery_multibranch/batteries.py | 9 +- .../battery_multibranch_ode.py | 46 ++- .../test_multibranch_trajectory_for_docs.py | 28 +- dymos/examples/battery_multibranch/motors.py | 10 +- .../test/test_multibranch_trajectory.py | 157 +++++----- .../test_multibranch_trajectory_rk_ivp.py | 45 ++- .../brachistochrone/brachistochrone_ode.py | 4 +- .../brachistochrone_vector_states_ode.py | 4 +- .../doc/test_doc_brachistochrone.py | 43 ++- .../test/ex_brachistochrone.py | 33 +- .../test/ex_brachistochrone_vector_states.py | 34 +- .../test_brachistochrone_implicit_recorder.py | 19 +- ...test_brachistochrone_integrated_control.py | 44 +-- .../test/test_brachistochrone_quick_start.py | 12 +- .../test/test_brachistochrone_rk4.py | 158 +++++----- .../test_brachistochrone_undecorated_ode.py | 54 ++-- ...histochrone_vector_boundary_constraints.py | 42 +-- ...brachistochrone_vector_path_constraints.py | 132 ++++---- .../test_brachistochrone_vector_states_ode.py | 6 +- ...doc_brachistochrone_polynomial_controls.py | 291 +++++++++--------- .../test_ex_brachistochrone_vector_states.py | 16 +- .../test/test_path_constraints.py | 60 ++-- dymos/examples/cannonball/cannonball_ode.py | 31 +- .../cannonball/cannonball_undecorated_ode.py | 6 +- .../doc/test_doc_two_phase_cannonball.py | 27 +- .../cannonball/kinetic_energy_comp.py | 4 +- dymos/examples/cannonball/size_comp.py | 4 +- ...st_two_phase_cannonball_undecorated_ode.py | 42 ++- .../doc/test_doc_double_integrator.py | 12 +- .../double_integrator_ode.py | 4 +- .../test/test_double_integrator.py | 30 +- .../doc/test_doc_finite_burn_orbit_raise.py | 12 +- .../finite_burn_eom.py | 25 +- .../test/test_ex_two_burn_orbit_raise.py | 12 +- .../test/test_finite_burn_eom.py | 6 +- .../test_two_burn_orbit_raise_linkages.py | 26 +- dymos/examples/min_time_climb/aero/aero.py | 5 +- .../examples/min_time_climb/aero/cd0_comp.py | 4 +- dymos/examples/min_time_climb/aero/cd_comp.py | 4 +- dymos/examples/min_time_climb/aero/cl_comp.py | 4 +- .../examples/min_time_climb/aero/cla_comp.py | 4 +- .../aero/dynamic_pressure_comp.py | 4 +- .../min_time_climb/aero/kappa_comp.py | 6 +- .../aero/lift_drag_force_comp.py | 4 +- .../examples/min_time_climb/aero/mach_comp.py | 4 +- .../aero/test/test_aerodynamics.py | 6 +- .../min_time_climb/aero/test/test_cd0_comp.py | 10 +- .../min_time_climb/aero/test/test_cla_comp.py | 10 +- .../aero/test/test_kappa_comp.py | 12 +- .../doc/test_doc_min_time_climb.py | 17 +- .../min_time_climb/min_time_climb_ode.py | 28 +- .../min_time_climb/prop/max_thrust_comp.py | 4 +- .../examples/min_time_climb/prop/mdot_comp.py | 4 +- dymos/examples/min_time_climb/prop/prop.py | 5 +- .../prop/test/test_max_thrust_comp.py | 6 +- .../min_time_climb/prop/thrust_comp.py | 4 +- .../test/test_ex_min_time_climb.py | 11 +- .../examples/ssto/doc/test_doc_ssto_earth.py | 11 +- .../test_doc_ssto_linear_tangent_guidance.py | 17 +- .../doc/test_doc_ssto_polynomial_control.py | 23 +- .../ssto/launch_vehicle_2d_eom_comp.py | 5 +- dymos/examples/ssto/launch_vehicle_ode.py | 25 +- dymos/examples/ssto/log_atmosphere_comp.py | 4 +- .../test/test_simulate_root_trajectory.py | 23 +- dymos/models/atmosphere/atmos_1976.py | 4 +- dymos/models/atmosphere/test/test_atmos.py | 8 +- dymos/models/eom/flight_path_eom_2d.py | 8 +- .../eom/test/test_flight_path_eom_2d.py | 22 +- dymos/phase/options.py | 14 +- dymos/phase/phase.py | 43 ++- .../test/test_input_parameter_connections.py | 34 +- dymos/phase/test/test_phase.py | 174 +++++------ dymos/phase/test/test_set_time_options.py | 65 ++-- .../phase/test/test_sized_input_parameters.py | 129 ++++---- dymos/phase/test/test_time_targets.py | 43 ++- dymos/phase/test/test_timeseries.py | 30 +- dymos/test/test_ode_options.py | 54 ++-- dymos/trajectory/test/test_trajectory.py | 48 +-- dymos/trajectory/trajectory.py | 15 +- .../common/boundary_constraint_comp.py | 4 +- .../transcriptions/common/continuity_comp.py | 4 +- dymos/transcriptions/common/control_group.py | 10 +- .../common/endpoint_conditions_comp.py | 6 +- .../common/input_parameter_comp.py | 4 +- .../common/path_constraint_comp.py | 4 +- .../common/phase_linkage_comp.py | 6 +- .../common/polynomial_control_group.py | 8 +- .../test/test_boundary_constraint_comp.py | 30 +- .../common/test/test_continuity_comp.py | 6 +- .../common/test/test_control_interp_comp.py | 22 +- .../test/test_endpoint_conditions_comp.py | 14 +- .../common/test/test_path_constraint_comp.py | 10 +- .../common/test/test_phase_linkage_comp.py | 6 +- .../test/test_polynomial_control_group.py | 38 +-- .../common/test/test_time_comp.py | 10 +- dymos/transcriptions/common/time_comp.py | 4 +- .../common/timeseries_output_comp.py | 4 +- .../components/collocation_comp.py | 4 +- .../control_endpoint_defect_comp.py | 4 +- .../components/state_independents.py | 4 +- .../components/state_interp_comp.py | 4 +- .../test/test_collocation_defect_opt.py | 6 +- .../test/test_collocation_defect_sol_opt.py | 6 +- .../test/test_collocation_defect_solver.py | 8 +- .../test/test_control_endpoint_defect_comp.py | 6 +- .../components/test/test_state_interp_comp.py | 32 +- .../pseudospectral/pseudospectral_base.py | 14 +- .../components/runge_kutta_k_comp.py | 5 +- .../components/runge_kutta_k_iter_group.py | 10 +- .../runge_kutta_state_advance_comp.py | 6 +- ...runge_kutta_state_continuity_iter_group.py | 11 +- .../runge_kutta_state_predict_comp.py | 4 +- .../components/runge_kutta_stepsize_comp.py | 4 +- .../test/test_rk_continuity_comp.py | 63 ++-- .../test/test_rk_continuity_iter_group.py | 21 +- .../components/test/test_rk_k_comp.py | 14 +- .../components/test/test_rk_k_iter_group.py | 21 +- .../test/test_rk_path_constraint_comp.py | 6 +- .../test/test_rk_state_advance_comp.py | 14 +- .../test/test_rk_state_predict_comp.py | 18 +- .../components/test/test_rk_stepsize_comp.py | 10 +- .../transcriptions/runge_kutta/runge_kutta.py | 15 +- .../runge_kutta/test/rk_test_ode.py | 10 +- .../test/test_rk4_simple_integration.py | 40 +-- .../components/ode_integration_interface.py | 8 +- .../odeint_control_interpolation_comp.py | 4 +- .../components/segment_simulation_comp.py | 5 +- .../components/segment_state_mux_comp.py | 4 +- .../components/solve_ivp_control_group.py | 11 +- .../solve_ivp_polynomial_control_group.py | 8 +- .../components/state_rate_collector_comp.py | 4 +- .../test/test_segment_simulation_comp.py | 5 +- dymos/transcriptions/solve_ivp/solve_ivp.py | 7 +- dymos/transcriptions/transcription_base.py | 9 +- 169 files changed, 1661 insertions(+), 1696 deletions(-) diff --git a/benchmark/benchmark_brachistochrone.py b/benchmark/benchmark_brachistochrone.py index c9cd57352..c24ad4f9f 100644 --- a/benchmark/benchmark_brachistochrone.py +++ b/benchmark/benchmark_brachistochrone.py @@ -1,7 +1,7 @@ import unittest -from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.brachistochrone import BrachistochroneODE @@ -9,12 +9,14 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, compressed=True, optimizer='SLSQP', simul_derivs=True): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) # if optimizer == 'SNOPT': - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = simul_derivs + + if simul_derivs: + p.driver.declare_coloring() if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=num_segments, @@ -49,7 +51,7 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/docs/examples/brachistochrone.rst b/dymos/docs/examples/brachistochrone.rst index 0808a7396..4c7572635 100644 --- a/dymos/docs/examples/brachistochrone.rst +++ b/dymos/docs/examples/brachistochrone.rst @@ -57,7 +57,7 @@ Finally, note that we are specifying rows and columns when declaring the partial Since our inputs and outputs are scalars *at each point in time*, and the value at an input at one time only directly impacts the values of an output at the same point in time, the partial derivative jacobian will be diagonal. Specifying the partial derivatives as being sparse -greatly improves the performance of Dymos when the driver option ``dynamic_simul_derivs`` is used. +greatly improves the performance of Dymos when the driver function ``declare_coloring`` is used. Using a sparse optimizer like SNOPT or IPOPT can provide significant addition improvements in performance. diff --git a/dymos/docs/examples/figures/ssto_linear_tangent_xdsm.py b/dymos/docs/examples/figures/ssto_linear_tangent_xdsm.py index b160fe447..8b91824d9 100644 --- a/dymos/docs/examples/figures/ssto_linear_tangent_xdsm.py +++ b/dymos/docs/examples/figures/ssto_linear_tangent_xdsm.py @@ -2,12 +2,12 @@ from pyxdsm.XDSM import XDSM -from openmdao.api import Problem +import openmdao.api as om from dymos.examples.ssto.launch_vehicle_linear_tangent_ode import LaunchVehicleLinearTangentODE def main(): # pragma: no cover - p = Problem() + p = om.Problem() p.model = LaunchVehicleLinearTangentODE(num_nodes=1) p.setup() diff --git a/dymos/docs/examples/figures/ssto_xdsm.py b/dymos/docs/examples/figures/ssto_xdsm.py index aaf52c74d..c026cb150 100644 --- a/dymos/docs/examples/figures/ssto_xdsm.py +++ b/dymos/docs/examples/figures/ssto_xdsm.py @@ -2,12 +2,12 @@ from pyxdsm.XDSM import XDSM -from openmdao.api import Problem +import openmdao.api as om from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE def main(): # pragma: no cover - p = Problem() + p = om.Problem() p.model = LaunchVehicleODE(num_nodes=1) p.setup() diff --git a/dymos/docs/examples/multibranch_trajectory.rst b/dymos/docs/examples/multibranch_trajectory.rst index 6af8d994e..72d1f6315 100644 --- a/dymos/docs/examples/multibranch_trajectory.rst +++ b/dymos/docs/examples/multibranch_trajectory.rst @@ -25,7 +25,7 @@ phases are connected to the output of a single phase. This way you can simulate trajectory paths in the same model. For this example, we will start with a single phase ("phase0") that simulates the model for one hour. Three follow-on phases will be linked to the output of the first phase: "phase1" will run as normal, "phase1_bfail" will fail one of the battery cells, and -"phase1_bfail" will fail a motor. All three of these phases start where "phase0" leaves off, so +"phase1_mfail" will fail a motor. All three of these phases start where "phase0" leaves off, so they share the same initial time and state of charge. diff --git a/dymos/docs/feature_reference/simultaneous_derivs.rst b/dymos/docs/feature_reference/simultaneous_derivs.rst index ebec8a748..8fb1d3b24 100644 --- a/dymos/docs/feature_reference/simultaneous_derivs.rst +++ b/dymos/docs/feature_reference/simultaneous_derivs.rst @@ -38,11 +38,30 @@ Step 1: Using OpenMDAO's Simul-Coloring Capability OpenMDAO supports dynamic simul-coloring, meaning it can automatically run the Jacobian coloring algorithm before handing the problem to the optimizer. To enable this capability, simply -add the following lines to the driver. +add the following line to the driver. .. code-block:: python - driver.options['dynamic_simul_derivs'] = True + driver.declare_coloring() + +By default the coloring algorithm will attempt to determine the sparsity pattern of the total jacobian +by filling the partial jacobian matrices with random noise and searching for nonzeros in the resulting +total jacobian. At times this might report that it failed to converge on a number of nonzero entries. +This is due to the introduction of noise during the matrix inversion by the system's linear solver. +This can be remedied by using a different linear solver, such as PETScKrylov, or by telling the +coloring algorithm to accept a given tolerance on the nonzero elements rather than trying to determine +it automatically. This can be accomplished with the following options to declare coloring: + +.. code-block:: python + + driver.declare_coloring(tol=1.0E-12, orders=None) + +Setting `orders` to None prevents the automatic tolerance detection. The value of `tol` is up to +the user. If it is too large, then some nonzero values will erroneously be determined to be zeros +and the total derivative will be incorrect. If `tol` is too small then the sparsity pattern may be +overly conservative and degrade performance somewhat. We recommend letting the coloring algorithm +detect the sparsity automatically and only resorting to a fixed tolerance if necessary. + The simul_coloring script outputs the following information about our problem: diff --git a/dymos/docs/feature_reference/transcriptions/figures/gauss-lobatto/plot_high_order_gauss_lobatto.py b/dymos/docs/feature_reference/transcriptions/figures/gauss-lobatto/plot_high_order_gauss_lobatto.py index 221a90a9b..fa77d8adf 100644 --- a/dymos/docs/feature_reference/transcriptions/figures/gauss-lobatto/plot_high_order_gauss_lobatto.py +++ b/dymos/docs/feature_reference/transcriptions/figures/gauss-lobatto/plot_high_order_gauss_lobatto.py @@ -6,13 +6,13 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group -from dymos import Phase, GaussLobatto +import openmdao.api as om +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE -p = Problem(model=Group()) -phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=4, order=[3, 5, 3, 5])) +p = om.Problem(model=om.Group()) +phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=4, order=[3, 5, 3, 5])) p.model.add_subsystem('phase0', phase) p.setup() diff --git a/dymos/docs/feature_reference/transcriptions/figures/radau-pseudospectral/plot_radau-pseudospectral.py b/dymos/docs/feature_reference/transcriptions/figures/radau-pseudospectral/plot_radau-pseudospectral.py index 2ab0a92de..d15a22121 100644 --- a/dymos/docs/feature_reference/transcriptions/figures/radau-pseudospectral/plot_radau-pseudospectral.py +++ b/dymos/docs/feature_reference/transcriptions/figures/radau-pseudospectral/plot_radau-pseudospectral.py @@ -6,13 +6,13 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group -from dymos import Phase, Radau +import openmdao.api as om +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE -p = Problem(model=Group()) -phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=4, order=[3, 5, 3, 5])) +p = om.Problem(model=om.Group()) +phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=4, order=[3, 5, 3, 5])) p.model.add_subsystem('phase0', phase) p.setup() diff --git a/dymos/examples/aircraft_steady_flight/aero/aero_coef_comp.py b/dymos/examples/aircraft_steady_flight/aero/aero_coef_comp.py index bb49e0d83..75946c2bd 100644 --- a/dymos/examples/aircraft_steady_flight/aero/aero_coef_comp.py +++ b/dymos/examples/aircraft_steady_flight/aero/aero_coef_comp.py @@ -1,13 +1,12 @@ from __future__ import print_function, division, absolute_import import numpy as np - -from openmdao.api import MetaModelStructuredComp +import openmdao.api as om from .crm_data import h_bp, alpha_bp, mach_bp, eta_bp, CL_data, CD_data, CM_data -class AeroCoefComp(MetaModelStructuredComp): +class AeroCoefComp(om.MetaModelStructuredComp): """ Interpolates aerodynamic coefficients for the NASA Common Research Model. """ def setup(self): diff --git a/dymos/examples/aircraft_steady_flight/aero/aero_forces_comp.py b/dymos/examples/aircraft_steady_flight/aero/aero_forces_comp.py index 1000481d5..ddc4c382f 100644 --- a/dymos/examples/aircraft_steady_flight/aero/aero_forces_comp.py +++ b/dymos/examples/aircraft_steady_flight/aero/aero_forces_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class AeroForcesComp(ExplicitComponent): +class AeroForcesComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/aircraft_steady_flight/aero/aerodynamics_group.py b/dymos/examples/aircraft_steady_flight/aero/aerodynamics_group.py index 9df7118a5..7cd586dcb 100644 --- a/dymos/examples/aircraft_steady_flight/aero/aerodynamics_group.py +++ b/dymos/examples/aircraft_steady_flight/aero/aerodynamics_group.py @@ -1,7 +1,6 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group - +import openmdao.api as om from .aero_coef_comp import AeroCoefComp from .aero_forces_comp import AeroForcesComp from .mbi_aero_coef_comp import MBIAeroCoeffComp, setup_surrogates_all @@ -12,7 +11,7 @@ MBI = None -class AerodynamicsGroup(Group): +class AerodynamicsGroup(om.Group): """ The purpose of the Aerodynamics is to compute the lift and drag forces on the aircraft. diff --git a/dymos/examples/aircraft_steady_flight/aero/mbi_aero_coef_comp.py b/dymos/examples/aircraft_steady_flight/aero/mbi_aero_coef_comp.py index 1dcbe27c3..742284b4a 100644 --- a/dymos/examples/aircraft_steady_flight/aero/mbi_aero_coef_comp.py +++ b/dymos/examples/aircraft_steady_flight/aero/mbi_aero_coef_comp.py @@ -5,8 +5,7 @@ import os.path import numpy as np -from openmdao.api import ExplicitComponent - +import openmdao.api as om try: import MBI except ImportError: @@ -60,7 +59,7 @@ def setup_surrogates_all(model_name='CRM'): return [CL_arr, CD_arr, CM_arr, nums] -class MBIAeroCoeffComp(ExplicitComponent): +class MBIAeroCoeffComp(om.ExplicitComponent): """ Compute the lift, drag, and moment coefficients of the aircraft """ def initialize(self): self.options.declare('vec_size', types=int) diff --git a/dymos/examples/aircraft_steady_flight/aero/test/test_aero_coef_comp.py b/dymos/examples/aircraft_steady_flight/aero/test/test_aero_coef_comp.py index 4001938c2..1903ea322 100644 --- a/dymos/examples/aircraft_steady_flight/aero/test/test_aero_coef_comp.py +++ b/dymos/examples/aircraft_steady_flight/aero/test/test_aero_coef_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy import array -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.examples.aircraft_steady_flight.aero.aero_coef_comp import AeroCoefComp @@ -17,11 +17,11 @@ def test_aero_coefs(self): nn = 100 - prob = Problem(model=Group()) + prob = om.Problem(model=om.Group()) prob.model.add_subsystem(name='aero', subsys=AeroCoefComp(vec_size=nn, method='quintic')) - ivc = prob.model.add_subsystem(name='ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivc = prob.model.add_subsystem(name='ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('mach', val=np.zeros(nn), units=None) ivc.add_output('alpha', val=np.zeros(nn), units='rad') diff --git a/dymos/examples/aircraft_steady_flight/aero/test/test_mbi_aero_coef_comp.py b/dymos/examples/aircraft_steady_flight/aero/test/test_mbi_aero_coef_comp.py index f1d6cb90e..fe4a63eee 100644 --- a/dymos/examples/aircraft_steady_flight/aero/test/test_mbi_aero_coef_comp.py +++ b/dymos/examples/aircraft_steady_flight/aero/test/test_mbi_aero_coef_comp.py @@ -2,7 +2,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.examples.aircraft_steady_flight.aero.mbi_aero_coef_comp import setup_surrogates_all, \ @@ -22,7 +22,7 @@ def test_aero_coefs(self): NUM_NODES = 100 MODEL = 'CRM' - prob = Problem(root=Group()) + prob = om.Problem(model=om.Group()) mbi_CL, mbi_CD, mbi_CM, mbi_num = setup_surrogates_all(MODEL) @@ -32,16 +32,16 @@ def test_aero_coefs(self): mbi_num=mbi_num)) prob.model.add_subsystem(name='M_ivc', - subsys=IndepVarComp('M', val=np.zeros(NUM_NODES), units=None), + subsys=om.IndepVarComp('M', val=np.zeros(NUM_NODES), units=None), promotes=['M']) prob.model.add_subsystem(name='alpha_ivc', - subsys=IndepVarComp('alpha', val=np.zeros(NUM_NODES), units='rad'), + subsys=om.IndepVarComp('alpha', val=np.zeros(NUM_NODES), units='rad'), promotes=['alpha']) prob.model.add_subsystem(name='eta_ivc', - subsys=IndepVarComp('eta', val=np.zeros(NUM_NODES), units='rad'), + subsys=om.IndepVarComp('eta', val=np.zeros(NUM_NODES), units='rad'), promotes=['eta']) prob.model.add_subsystem(name='h_ivc', - subsys=IndepVarComp('h', val=np.zeros(NUM_NODES), units='km'), + subsys=om.IndepVarComp('h', val=np.zeros(NUM_NODES), units='km'), promotes=['h']) prob.model.connect('M', 'aero.M') diff --git a/dymos/examples/aircraft_steady_flight/aircraft_ode.py b/dymos/examples/aircraft_steady_flight/aircraft_ode.py index 678dfc276..06ff98735 100644 --- a/dymos/examples/aircraft_steady_flight/aircraft_ode.py +++ b/dymos/examples/aircraft_steady_flight/aircraft_ode.py @@ -1,8 +1,7 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group, DirectSolver, NewtonSolver, BoundsEnforceLS - -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm from dymos.models.atmosphere import USatm1976Comp from .steady_flight_path_angle_comp import SteadyFlightPathAngleComp @@ -14,19 +13,18 @@ from .mass_comp import MassComp -@declare_time(units='s') -@declare_state('range', rate_source='range_rate_comp.dXdt:range', units='m') -@declare_state('mass_fuel', targets=['mass_comp.mass_fuel'], - rate_source='propulsion.dXdt:mass_fuel', units='kg') -@declare_state('alt', targets=['atmos.h', 'aero.alt', 'propulsion.alt'], - rate_source='climb_rate', units='m') -# @declare_parameter('alt', targets=['atmos.h', 'aero.alt', 'propulsion.alt'], units='m') -@declare_parameter('climb_rate', targets=['gam_comp.climb_rate'], units='m/s') -@declare_parameter('mach', targets=['tas_comp.mach', 'aero.mach'], units='m/s') -@declare_parameter('S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') -@declare_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') -@declare_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') -class AircraftODE(Group): +@dm.declare_time(units='s') +@dm.declare_state('range', rate_source='range_rate_comp.dXdt:range', units='m') +@dm.declare_state('mass_fuel', targets=['mass_comp.mass_fuel'], + rate_source='propulsion.dXdt:mass_fuel', units='kg') +@dm.declare_state('alt', targets=['atmos.h', 'aero.alt', 'propulsion.alt'], + rate_source='climb_rate', units='m') +@dm.declare_parameter('climb_rate', targets=['gam_comp.climb_rate'], units='m/s') +@dm.declare_parameter('mach', targets=['tas_comp.mach', 'aero.mach'], units='m/s') +@dm.declare_parameter('S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') +@dm.declare_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') +@dm.declare_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') +class AircraftODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int, diff --git a/dymos/examples/aircraft_steady_flight/doc/test_doc_aircraft_steady_flight.py b/dymos/examples/aircraft_steady_flight/doc/test_doc_aircraft_steady_flight.py index 6f471f1a3..62dbd9ba8 100644 --- a/dymos/examples/aircraft_steady_flight/doc/test_doc_aircraft_steady_flight.py +++ b/dymos/examples/aircraft_steady_flight/doc/test_doc_aircraft_steady_flight.py @@ -13,14 +13,14 @@ class TestSteadyAircraftFlightForDocs(unittest.TestCase): @classmethod def tearDownClass(cls): - for filename in ['coloring.json', 'test_doc_aircraft_steady_flight_rec.db', 'SLSQP.out']: + for filename in ['total_coloring.pkl', 'test_doc_aircraft_steady_flight_rec.db', 'SLSQP.out']: if os.path.exists(filename): os.remove(filename) def test_steady_aircraft_for_docs(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, pyOptSparseDriver, IndepVarComp + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm @@ -29,10 +29,10 @@ def test_steady_aircraft_for_docs(self): from dymos.examples.plotting import plot_results from dymos.utils.lgl import lgl - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() num_seg = 15 seg_ends, _ = lgl(num_seg + 1) @@ -46,7 +46,7 @@ def test_steady_aircraft_for_docs(self): order=3, compressed=False))) # Pass Reference Area from an external source - assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) + assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') diff --git a/dymos/examples/aircraft_steady_flight/dynamic_pressure_comp.py b/dymos/examples/aircraft_steady_flight/dynamic_pressure_comp.py index 7d0cc8b1d..af597c260 100644 --- a/dymos/examples/aircraft_steady_flight/dynamic_pressure_comp.py +++ b/dymos/examples/aircraft_steady_flight/dynamic_pressure_comp.py @@ -1,10 +1,10 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class DynamicPressureComp(ExplicitComponent): +class DynamicPressureComp(om.ExplicitComponent): """ Compute the dynamic pressure based on the velocity and the atmospheric density. """ def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/aircraft_steady_flight/flight_equlibrium/lift_equilibrium_comp.py b/dymos/examples/aircraft_steady_flight/flight_equlibrium/lift_equilibrium_comp.py index 668b4c87e..562e82ea8 100644 --- a/dymos/examples/aircraft_steady_flight/flight_equlibrium/lift_equilibrium_comp.py +++ b/dymos/examples/aircraft_steady_flight/flight_equlibrium/lift_equilibrium_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class LiftEquilibriumComp(ExplicitComponent): +class LiftEquilibriumComp(om.ExplicitComponent): """ Compute the rates of TAS and flight path angle required to match a given flight condition. diff --git a/dymos/examples/aircraft_steady_flight/flight_equlibrium/steady_flight_equilibrium_group.py b/dymos/examples/aircraft_steady_flight/flight_equlibrium/steady_flight_equilibrium_group.py index 67f871cde..5403ed536 100644 --- a/dymos/examples/aircraft_steady_flight/flight_equlibrium/steady_flight_equilibrium_group.py +++ b/dymos/examples/aircraft_steady_flight/flight_equlibrium/steady_flight_equilibrium_group.py @@ -2,15 +2,14 @@ import numpy as np -from openmdao.api import Group, BalanceComp, NewtonSolver, DirectSolver, ArmijoGoldsteinLS, \ - BoundsEnforceLS +import openmdao.api as om from ..aero.aerodynamics_group import AerodynamicsGroup from .lift_equilibrium_comp import LiftEquilibriumComp from .thrust_equilibrium_comp import ThrustEquilibriumComp -class SteadyFlightEquilibriumGroup(Group): +class SteadyFlightEquilibriumGroup(om.Group): def initialize(self): self.options.declare('num_nodes', types=int, @@ -33,7 +32,7 @@ def setup(self): promotes_outputs=['CL_eq']) bal = self.add_subsystem(name='alpha_eta_balance', - subsys=BalanceComp(), + subsys=om.BalanceComp(), promotes_outputs=['alpha', 'eta']) self.connect('alpha', ('aero.alpha')) @@ -50,8 +49,8 @@ def setup(self): self.connect('aero.CM', 'alpha_eta_balance.CM') self.connect('CL_eq', ('alpha_eta_balance.CL_eq')) - self.linear_solver = DirectSolver() - self.nonlinear_solver = NewtonSolver() + self.linear_solver = om.DirectSolver() + self.nonlinear_solver = om.NewtonSolver() self.nonlinear_solver.options['atol'] = 1e-14 self.nonlinear_solver.options['rtol'] = 1e-14 self.nonlinear_solver.options['solve_subsystems'] = True @@ -59,6 +58,5 @@ def setup(self): self.nonlinear_solver.options['max_sub_solves'] = 10 self.nonlinear_solver.options['maxiter'] = 150 self.nonlinear_solver.options['iprint'] = -1 - # self.nonlinear_solver.linesearch = ArmijoGoldsteinLS() - self.nonlinear_solver.linesearch = BoundsEnforceLS() + self.nonlinear_solver.linesearch = om.BoundsEnforceLS() self.nonlinear_solver.linesearch.options['print_bound_enforce'] = True diff --git a/dymos/examples/aircraft_steady_flight/flight_equlibrium/test/test_flight_equilibrium_group.py b/dymos/examples/aircraft_steady_flight/flight_equlibrium/test/test_flight_equilibrium_group.py index d652bd6ac..80b4e3119 100644 --- a/dymos/examples/aircraft_steady_flight/flight_equlibrium/test/test_flight_equilibrium_group.py +++ b/dymos/examples/aircraft_steady_flight/flight_equlibrium/test/test_flight_equilibrium_group.py @@ -3,7 +3,7 @@ import unittest import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.examples.aircraft_steady_flight.flight_equlibrium.steady_flight_equilibrium_group \ @@ -23,9 +23,9 @@ class TestFlightEquilibriumGroup(unittest.TestCase): def setUpClass(cls): cls.n = 10 - cls.p = Problem(model=Group()) + cls.p = om.Problem(model=om.Group()) - ivc = cls.p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = cls.p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('alt', val=3000 * np.ones(cls.n), units='m', desc='altitude above MSL') ivc.add_output('TAS', val=250.0 * np.ones(cls.n), units='m/s', desc='true airspeed') diff --git a/dymos/examples/aircraft_steady_flight/flight_equlibrium/thrust_equilibrium_comp.py b/dymos/examples/aircraft_steady_flight/flight_equlibrium/thrust_equilibrium_comp.py index 33819b41b..fc9f16214 100644 --- a/dymos/examples/aircraft_steady_flight/flight_equlibrium/thrust_equilibrium_comp.py +++ b/dymos/examples/aircraft_steady_flight/flight_equlibrium/thrust_equilibrium_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class ThrustEquilibriumComp(ExplicitComponent): +class ThrustEquilibriumComp(om.ExplicitComponent): """ Compute the rates of TAS and flight path angle required to match a given flight condition. diff --git a/dymos/examples/aircraft_steady_flight/mass_comp.py b/dymos/examples/aircraft_steady_flight/mass_comp.py index 8bf9d87ed..af3ef0b54 100644 --- a/dymos/examples/aircraft_steady_flight/mass_comp.py +++ b/dymos/examples/aircraft_steady_flight/mass_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class MassComp(ExplicitComponent): +class MassComp(om.ExplicitComponent): """ Compute the total mass of the aircraft """ def initialize(self): diff --git a/dymos/examples/aircraft_steady_flight/propulsion/fuel_burn_rate_comp.py b/dymos/examples/aircraft_steady_flight/propulsion/fuel_burn_rate_comp.py index 440efe651..658a1c0cf 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/fuel_burn_rate_comp.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/fuel_burn_rate_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class FuelBurnRateComp(ExplicitComponent): +class FuelBurnRateComp(om.ExplicitComponent): """ Computes the fuel burn rate (rate of change of fuel weight) based on SFC and thrust. """ def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/aircraft_steady_flight/propulsion/max_thrust_comp.py b/dymos/examples/aircraft_steady_flight/propulsion/max_thrust_comp.py index 51df12cfe..a33c8e3e3 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/max_thrust_comp.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/max_thrust_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class MaxThrustComp(ExplicitComponent): +class MaxThrustComp(om.ExplicitComponent): """ Compute the maximum thrust given the current aircraft state and its maximum sea-level thrust with a simple pressure correction. """ diff --git a/dymos/examples/aircraft_steady_flight/propulsion/propulsion_group.py b/dymos/examples/aircraft_steady_flight/propulsion/propulsion_group.py index e1e376534..28a52ad11 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/propulsion_group.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/propulsion_group.py @@ -1,8 +1,6 @@ from __future__ import print_function, division, absolute_import -import numpy as np - -from openmdao.api import Group, IndepVarComp +import openmdao.api as om from .thrust_comp import ThrustComp from .max_thrust_comp import MaxThrustComp @@ -11,7 +9,7 @@ from .fuel_burn_rate_comp import FuelBurnRateComp -class PropulsionGroup(Group): +class PropulsionGroup(om.Group): """ The PropulsionGroup computes propulsive forces (thrust), the specific fuel consumption and fuel expenditure rate, and the aircraft throttle setting. @@ -22,7 +20,7 @@ def initialize(self): def setup(self): n = self.options['num_nodes'] - assumptions = self.add_subsystem('assumptions', subsys=IndepVarComp()) + assumptions = self.add_subsystem('assumptions', subsys=om.IndepVarComp()) assumptions.add_output('tsfc_sl', val=2 * 8.951e-6 * 9.80665, units='1/s', desc='thrust specific fuel consumption at sea-level') diff --git a/dymos/examples/aircraft_steady_flight/propulsion/test/test_propulsion_group.py b/dymos/examples/aircraft_steady_flight/propulsion/test/test_propulsion_group.py index 4777572cc..b28155975 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/test/test_propulsion_group.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/test/test_propulsion_group.py @@ -3,7 +3,7 @@ import unittest import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.examples.aircraft_steady_flight.propulsion.propulsion_group import PropulsionGroup @@ -15,9 +15,9 @@ class TestPropulsionComp(unittest.TestCase): def setUpClass(cls): cls.n = 10 - cls.p = Problem(model=Group()) + cls.p = om.Problem(model=om.Group()) - ivc = cls.p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = cls.p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('alt', val=np.zeros(cls.n), units='m', desc='altitude above MSL') diff --git a/dymos/examples/aircraft_steady_flight/propulsion/throttle_comp.py b/dymos/examples/aircraft_steady_flight/propulsion/throttle_comp.py index fd0e430ff..6f12a5a26 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/throttle_comp.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/throttle_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class ThrottleComp(ExplicitComponent): +class ThrottleComp(om.ExplicitComponent): """ Compute 'tau' (throttle parameter) which is the ratio of the current thrust (as determined to provie flight equilibrium) with the maximum thrust given the current aircraft state. diff --git a/dymos/examples/aircraft_steady_flight/propulsion/thrust_comp.py b/dymos/examples/aircraft_steady_flight/propulsion/thrust_comp.py index d998d2d0c..c3f603068 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/thrust_comp.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/thrust_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class ThrustComp(ExplicitComponent): +class ThrustComp(om.ExplicitComponent): """ Compute thrust from the thrust coefficient """ def initialize(self): diff --git a/dymos/examples/aircraft_steady_flight/propulsion/tsfc_comp.py b/dymos/examples/aircraft_steady_flight/propulsion/tsfc_comp.py index cff85c3db..65b43207e 100644 --- a/dymos/examples/aircraft_steady_flight/propulsion/tsfc_comp.py +++ b/dymos/examples/aircraft_steady_flight/propulsion/tsfc_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class SFCComp(ExplicitComponent): +class SFCComp(om.ExplicitComponent): """ Compute the specific fuel consumption based on the altitude and the sea-level specific fuel consumption. """ diff --git a/dymos/examples/aircraft_steady_flight/range_rate_comp.py b/dymos/examples/aircraft_steady_flight/range_rate_comp.py index 6d53ab544..e1e1884b9 100644 --- a/dymos/examples/aircraft_steady_flight/range_rate_comp.py +++ b/dymos/examples/aircraft_steady_flight/range_rate_comp.py @@ -1,10 +1,10 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class RangeRateComp(ExplicitComponent): +class RangeRateComp(om.ExplicitComponent): """ Calculates range rate based on true airspeed and flight path angle. """ diff --git a/dymos/examples/aircraft_steady_flight/steady_flight_path_angle_comp.py b/dymos/examples/aircraft_steady_flight/steady_flight_path_angle_comp.py index 9e2c38e4f..5ed120b89 100644 --- a/dymos/examples/aircraft_steady_flight/steady_flight_path_angle_comp.py +++ b/dymos/examples/aircraft_steady_flight/steady_flight_path_angle_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class SteadyFlightPathAngleComp(ExplicitComponent): +class SteadyFlightPathAngleComp(om.ExplicitComponent): """ Compute the flight path angle (gamma) based on true airspeed and climb rate. """ def initialize(self): diff --git a/dymos/examples/aircraft_steady_flight/test/test_aircraft_cruise.py b/dymos/examples/aircraft_steady_flight/test/test_aircraft_cruise.py index 4e3801fdb..1092b3a99 100644 --- a/dymos/examples/aircraft_steady_flight/test/test_aircraft_cruise.py +++ b/dymos/examples/aircraft_steady_flight/test/test_aircraft_cruise.py @@ -3,11 +3,10 @@ import os import unittest -from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, \ - pyOptSparseDriver, ScipyOptimizeDriver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto +import dymos as dm from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE optimizer = os.environ.get('DYMOS_DEFAULT_OPT', 'SLSQP') @@ -21,11 +20,11 @@ class TestAircraftCruise(unittest.TestCase): def test_cruise_results_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) if optimizer == 'SNOPT': - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major step limit'] = 0.05 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -34,17 +33,17 @@ def test_cruise_results_gl(self): p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - transcription = GaussLobatto(num_segments=1, - order=13, - compressed=False) - phase = Phase(ode_class=AircraftODE, transcription=transcription) + transcription = dm.GaussLobatto(num_segments=1, + order=13, + compressed=False) + phase = dm.Phase(ode_class=AircraftODE, transcription=transcription) p.model.add_subsystem('phase0', phase) # Pass Reference Area from an external source - assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) + assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') @@ -76,7 +75,7 @@ def test_cruise_results_gl(self): phase.add_objective('time', loc='final', ref=3600) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -101,11 +100,11 @@ def test_cruise_results_gl(self): assert_rel_error(self, range, tas*time, tolerance=1.0E-4) def test_cruise_results_radau(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) if optimizer == 'SNOPT': - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major step limit'] = 0.05 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -114,17 +113,17 @@ def test_cruise_results_radau(self): p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - transcription = GaussLobatto(num_segments=1, - order=13, - compressed=False) - phase = Phase(ode_class=AircraftODE, transcription=transcription) + transcription = dm.GaussLobatto(num_segments=1, + order=13, + compressed=False) + phase = dm.Phase(ode_class=AircraftODE, transcription=transcription) p.model.add_subsystem('phase0', phase) # Pass Reference Area from an external source - assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) + assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') @@ -156,7 +155,7 @@ def test_cruise_results_radau(self): phase.add_objective('time', loc='final', ref=3600) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() diff --git a/dymos/examples/aircraft_steady_flight/test/test_aircraft_ode.py b/dymos/examples/aircraft_steady_flight/test/test_aircraft_ode.py index 23dedb8d5..95ead9a32 100644 --- a/dymos/examples/aircraft_steady_flight/test/test_aircraft_ode.py +++ b/dymos/examples/aircraft_steady_flight/test/test_aircraft_ode.py @@ -3,8 +3,8 @@ import unittest import numpy as np -from openmdao.api import Problem, Group, IndepVarComp, DirectSolver -from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials +import openmdao.api as om +from openmdao.utils.assert_utils import assert_rel_error from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE @@ -22,9 +22,9 @@ class TestAircraftODEGroup(unittest.TestCase): def setUpClass(cls): cls.n = 10 - cls.p = Problem(model=Group()) + cls.p = om.Problem(model=om.Group()) - ivc = cls.p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = cls.p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('mass_fuel', val=20000 * np.ones(cls.n), units='kg', desc='aircraft fuel mass') @@ -47,7 +47,7 @@ def setUpClass(cls): cls.p.model.connect('climb_rate', ['ode.gam_comp.climb_rate']) cls.p.model.connect('S', ('ode.aero.S', 'ode.flight_equilibrium.S', 'ode.propulsion.S')) - cls.p.model.linear_solver = DirectSolver() + cls.p.model.linear_solver = om.DirectSolver() cls.p.setup(check=True, force_alloc_complex=True) diff --git a/dymos/examples/aircraft_steady_flight/test/test_ex_aircraft_steady_flight.py b/dymos/examples/aircraft_steady_flight/test/test_ex_aircraft_steady_flight.py index 8fda95fed..2185e5eff 100644 --- a/dymos/examples/aircraft_steady_flight/test/test_ex_aircraft_steady_flight.py +++ b/dymos/examples/aircraft_steady_flight/test/test_ex_aircraft_steady_flight.py @@ -3,7 +3,7 @@ import os import unittest -from openmdao.api import Problem, Group, pyOptSparseDriver, IndepVarComp +import openmdao.api as om from openmdao.utils.general_utils import set_pyoptsparse_opt from openmdao.utils.assert_utils import assert_rel_error @@ -14,11 +14,11 @@ def ex_aircraft_steady_flight(optimizer='SLSQP', solve_segments=False, use_boundary_constraints=False, compressed=False): - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt(optimizer, fallback=False) p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 20 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -37,7 +37,7 @@ def ex_aircraft_steady_flight(optimizer='SLSQP', solve_segments=False, solve_segments=solve_segments)) # Pass Reference Area from an external source - assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) + assumptions = p.model.add_subsystem('assumptions', om.IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') @@ -102,7 +102,7 @@ class TestExSteadyAircraftFlight(unittest.TestCase): @classmethod def tearDownClass(cls): - for filename in ['coloring.json', 'test_ex_aircraft_steady_flight_rec.db', 'SLSQP.out']: + for filename in ['total_coloring.pkl', 'test_ex_aircraft_steady_flight_rec.db', 'SLSQP.out']: if os.path.exists(filename): os.remove(filename) diff --git a/dymos/examples/aircraft_steady_flight/true_airspeed_comp.py b/dymos/examples/aircraft_steady_flight/true_airspeed_comp.py index 347bb8097..ac7a5725a 100644 --- a/dymos/examples/aircraft_steady_flight/true_airspeed_comp.py +++ b/dymos/examples/aircraft_steady_flight/true_airspeed_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class TrueAirspeedComp(ExplicitComponent): +class TrueAirspeedComp(om.ExplicitComponent): """ Compute Mach number based on true airspeed and the local speed of sound. """ def initialize(self): diff --git a/dymos/examples/battery_multibranch/batteries.py b/dymos/examples/battery_multibranch/batteries.py index 03147014c..7e6c8350c 100644 --- a/dymos/examples/battery_multibranch/batteries.py +++ b/dymos/examples/battery_multibranch/batteries.py @@ -6,14 +6,13 @@ import numpy as np from scipy.interpolate import Akima1DInterpolator -from openmdao.api import ExplicitComponent - +import openmdao.api as om # Data for open circuit voltage model. train_SOC = np.array([0., 0.1, 0.25, 0.5, 0.75, 0.9, 1.0]) train_V_oc = np.array([3.5, 3.55, 3.65, 3.75, 3.9, 4.1, 4.2]) -class Battery(ExplicitComponent): +class Battery(om.ExplicitComponent): """ Model of a Lithium Ion battery. """ @@ -113,10 +112,10 @@ def compute_partials(self, inputs, partials): if __name__ == '__main__': - from openmdao.api import Problem, IndepVarComp + import openmdao.api as om num_nodes = 1 - prob = Problem(model=Battery(num_nodes=num_nodes)) + prob = om.Problem(model=Battery(num_nodes=num_nodes)) model = prob.model prob.setup() diff --git a/dymos/examples/battery_multibranch/battery_multibranch_ode.py b/dymos/examples/battery_multibranch/battery_multibranch_ode.py index 10dc85abf..29701b3d3 100644 --- a/dymos/examples/battery_multibranch/battery_multibranch_ode.py +++ b/dymos/examples/battery_multibranch/battery_multibranch_ode.py @@ -5,19 +5,17 @@ from __future__ import print_function, division, absolute_import import numpy as np - -from openmdao.api import Group, BalanceComp, NewtonSolver, DirectSolver - -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm from dymos.examples.battery_multibranch.batteries import Battery from dymos.examples.battery_multibranch.motors import Motors, MotorsStaticGearboxPower -@declare_time(units='s') -@declare_state('state_of_charge', targets=['SOC'], rate_source='dXdt:SOC') -@declare_parameter('P_demand', targets=['motors.power_out_gearbox'], dynamic=True) -class BatteryODE(Group): +@dm.declare_time(units='s') +@dm.declare_state('state_of_charge', targets=['SOC'], rate_source='dXdt:SOC') +@dm.declare_parameter('P_demand', targets=['motors.power_out_gearbox'], dynamic=True) +class BatteryODE(om.Group): def initialize(self): self.options.declare('num_nodes', default=1) @@ -30,10 +28,10 @@ def setup(self): num_motor = self.options['num_motor'] self.add_subsystem(name='pwr_balance', - subsys=BalanceComp(name='I_Li', val=1.0*np.ones(num_nodes), - rhs_name='pwr_out_batt', - lhs_name='P_pack', - units='A', eq_units='W', lower=0.0, upper=50.)) + subsys=om.BalanceComp(name='I_Li', val=1.0*np.ones(num_nodes), + rhs_name='pwr_out_batt', + lhs_name='P_pack', + units='A', eq_units='W', lower=0.0, upper=50.)) self.add_subsystem('battery', Battery(num_nodes=num_nodes, n_parallel=num_battery), promotes_inputs=['SOC'], @@ -46,15 +44,15 @@ def setup(self): self.connect('pwr_balance.I_Li', 'battery.I_Li') self.connect('battery.I_pack', 'motors.current_in_motor') - self.nonlinear_solver = NewtonSolver() + self.nonlinear_solver = om.NewtonSolver() self.nonlinear_solver.options['maxiter'] = 20 - self.linear_solver = DirectSolver() + self.linear_solver = om.DirectSolver() -@declare_time(units='s') -@declare_state('state_of_charge', targets=['SOC'], rate_source='dXdt:SOC') -@declare_parameter('P_demand', targets=['motors.power_out_gearbox'], dynamic=False) -class BatteryODEStaticGearboxMotorPower(Group): +@dm.declare_time(units='s') +@dm.declare_state('state_of_charge', targets=['SOC'], rate_source='dXdt:SOC') +@dm.declare_parameter('P_demand', targets=['motors.power_out_gearbox'], dynamic=False) +class BatteryODEStaticGearboxMotorPower(om.Group): def initialize(self): self.options.declare('num_nodes', default=1) @@ -67,10 +65,10 @@ def setup(self): num_motor = self.options['num_motor'] self.add_subsystem(name='pwr_balance', - subsys=BalanceComp(name='I_Li', val=1.0*np.ones(num_nodes), - rhs_name='pwr_out_batt', - lhs_name='P_pack', - units='A', eq_units='W', lower=0.0, upper=50.)) + subsys=om.BalanceComp(name='I_Li', val=1.0*np.ones(num_nodes), + rhs_name='pwr_out_batt', + lhs_name='P_pack', + units='A', eq_units='W', lower=0.0, upper=50.)) self.add_subsystem('battery', Battery(num_nodes=num_nodes, n_parallel=num_battery), promotes_inputs=['SOC'], @@ -83,6 +81,6 @@ def setup(self): self.connect('pwr_balance.I_Li', 'battery.I_Li') self.connect('battery.I_pack', 'motors.current_in_motor') - self.nonlinear_solver = NewtonSolver() + self.nonlinear_solver = om.NewtonSolver() self.nonlinear_solver.options['maxiter'] = 20 - self.linear_solver = DirectSolver() + self.linear_solver = om.DirectSolver() diff --git a/dymos/examples/battery_multibranch/doc/test_multibranch_trajectory_for_docs.py b/dymos/examples/battery_multibranch/doc/test_multibranch_trajectory_for_docs.py index c3dadc0ba..2cf3674aa 100644 --- a/dymos/examples/battery_multibranch/doc/test_multibranch_trajectory_for_docs.py +++ b/dymos/examples/battery_multibranch/doc/test_multibranch_trajectory_for_docs.py @@ -15,27 +15,27 @@ class TestBatteryBranchingPhasesForDocs(unittest.TestCase): def test_basic(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Trajectory, Phase, Radau + import dymos as dm from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE from dymos.utils.lgl import lgl - prob = Problem() + prob = om.Problem() - opt = prob.driver = ScipyOptimizeDriver() - opt.options['dynamic_simul_derivs'] = True + opt = prob.driver = om.ScipyOptimizeDriver() + opt.declare_coloring() opt.options['optimizer'] = 'SLSQP' num_seg = 5 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=num_seg, order=5, segment_ends=seg_ends, compressed=False) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -43,7 +43,7 @@ def test_basic(self): # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -52,8 +52,8 @@ def test_basic(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) @@ -61,8 +61,8 @@ def test_basic(self): # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) @@ -73,7 +73,7 @@ def test_basic(self): traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time']) prob.model.options['assembled_jac_type'] = 'csc' - prob.model.linear_solver = DirectSolver(assemble_jac=True) + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() diff --git a/dymos/examples/battery_multibranch/motors.py b/dymos/examples/battery_multibranch/motors.py index c3ebcc68d..47dd4c16a 100644 --- a/dymos/examples/battery_multibranch/motors.py +++ b/dymos/examples/battery_multibranch/motors.py @@ -5,10 +5,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class Motors(ExplicitComponent): +class Motors(om.ExplicitComponent): """ Model for motors in parallel. """ @@ -56,7 +56,7 @@ def compute_partials(self, inputs, partials): partials['power_in_motor', 'current_in_motor'] = 0.3 * power_out / (n_parallel * eff**2) -class MotorsStaticGearboxPower(ExplicitComponent): +class MotorsStaticGearboxPower(om.ExplicitComponent): """ Model for motors in parallel. """ @@ -107,10 +107,10 @@ def compute_partials(self, inputs, partials): if __name__ == '__main__': - from openmdao.api import Problem, IndepVarComp + import openmdao.api as om num_nodes = 1 - prob = Problem(model=Motors(num_nodes=num_nodes)) + prob = om.Problem(model=Motors(num_nodes=num_nodes)) model = prob.model prob.setup() diff --git a/dymos/examples/battery_multibranch/test/test_multibranch_trajectory.py b/dymos/examples/battery_multibranch/test/test_multibranch_trajectory.py index fe0de3439..92b1a5519 100644 --- a/dymos/examples/battery_multibranch/test/test_multibranch_trajectory.py +++ b/dymos/examples/battery_multibranch/test/test_multibranch_trajectory.py @@ -6,10 +6,10 @@ import os import unittest -from openmdao.api import Problem, pyOptSparseDriver, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Trajectory, Phase, Radau, RungeKutta +import dymos as dm from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE from dymos.utils.lgl import lgl @@ -20,12 +20,12 @@ class TestBatteryBranchingPhases(unittest.TestCase): def test_optimizer_defects(self): - prob = Problem() + prob = om.Problem() if optimizer == 'SNOPT': - opt = prob.driver = pyOptSparseDriver() + opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer - opt.options['dynamic_simul_derivs'] = True + opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -34,18 +34,17 @@ def test_optimizer_defects(self): opt.opt_settings['iSumm'] = 6 else: - opt = prob.driver = ScipyOptimizeDriver() - opt.options['dynamic_simul_derivs'] = True + opt = prob.driver = om.ScipyOptimizeDriver() + opt.declare_coloring() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - - transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=False) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=False) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -53,7 +52,7 @@ def test_optimizer_defects(self): # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -62,8 +61,8 @@ def test_optimizer_defects(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) @@ -71,8 +70,8 @@ def test_optimizer_defects(self): # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) @@ -83,7 +82,7 @@ def test_optimizer_defects(self): traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time']) prob.model.options['assembled_jac_type'] = 'csc' - prob.model.linear_solver = DirectSolver(assemble_jac=True) + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() @@ -114,17 +113,17 @@ def test_optimizer_defects(self): assert_rel_error(self, soc1m[-1], 0.18625395, 1e-6) def test_solver_defects(self): - prob = Problem() + prob = om.Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -132,7 +131,7 @@ def test_solver_defects(self): solve_segments=True) # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -141,8 +140,8 @@ def test_solver_defects(self): traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) @@ -150,8 +149,8 @@ def test_solver_defects(self): solve_segments=True) # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) @@ -196,15 +195,15 @@ def test_solver_defects(self): assert_rel_error(self, soc1m[-1], 0.18625395, 1e-6) def test_solver_defects_single_phase_reverse_propagation(self): - prob = Problem() + prob = om.Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. - transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -224,16 +223,16 @@ def test_solver_defects_single_phase_reverse_propagation(self): assert_rel_error(self, soc0[-1], 1.0, 1e-6) def test_solver_defects_reverse_propagation(self): - prob = Problem() + prob = om.Problem() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -241,7 +240,7 @@ def test_solver_defects_reverse_propagation(self): solve_segments=True) # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -268,12 +267,12 @@ def test_solver_defects_reverse_propagation(self): assert_rel_error(self, soc1[-1], 1.0, 1e-6) def test_optimizer_segments_direct_connections(self): - prob = Problem() + prob = om.Problem() if optimizer == 'SNOPT': - opt = prob.driver = pyOptSparseDriver() + opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer - opt.options['dynamic_simul_derivs'] = True + opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -282,40 +281,40 @@ def test_optimizer_segments_direct_connections(self): opt.opt_settings['iSumm'] = 6 else: - opt = prob.driver = ScipyOptimizeDriver() - opt.options['dynamic_simul_derivs'] = True + opt = prob.driver = om.ScipyOptimizeDriver() + opt.declare_coloring() num_seg = 5 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, segment_ends=seg_ends, compressed=True) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) traj_p0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) traj_p1.set_state_options('state_of_charge', fix_initial=False, fix_final=False) traj_p1.add_objective('time', loc='final') # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) @@ -328,7 +327,7 @@ def test_optimizer_segments_direct_connections(self): connected=True) prob.model.options['assembled_jac_type'] = 'csc' - prob.model.linear_solver = DirectSolver(assemble_jac=True) + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() @@ -362,12 +361,12 @@ def test_optimizer_segments_direct_connections(self): class TestBatteryBranchingPhasesRungeKutta(unittest.TestCase): def test_constraint_linkages_rk(self): - prob = Problem() + prob = om.Problem() if optimizer == 'SNOPT': - opt = prob.driver = pyOptSparseDriver() + opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer - opt.options['dynamic_simul_derivs'] = True + opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -376,17 +375,17 @@ def test_constraint_linkages_rk(self): opt.opt_settings['iSumm'] = 6 else: - opt = prob.driver = ScipyOptimizeDriver() - opt.options['dynamic_simul_derivs'] = True + opt = prob.driver = om.ScipyOptimizeDriver() + opt.declare_coloring() num_seg = 20 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = RungeKutta(num_segments=num_seg) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.RungeKutta(num_segments=num_seg) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -394,7 +393,7 @@ def test_constraint_linkages_rk(self): # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -403,8 +402,8 @@ def test_constraint_linkages_rk(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) @@ -412,8 +411,8 @@ def test_constraint_linkages_rk(self): # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) @@ -424,7 +423,7 @@ def test_constraint_linkages_rk(self): traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time']) prob.model.options['assembled_jac_type'] = 'csc' - prob.model.linear_solver = DirectSolver(assemble_jac=True) + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() @@ -455,14 +454,14 @@ def test_constraint_linkages_rk(self): assert_rel_error(self, soc1m[-1], 0.18625395, 1e-4) def test_single_phase_reverse_propagation_rk(self): - prob = Problem() + prob = om.Problem() num_seg = 10 seg_ends, _ = lgl(num_seg + 1) # First phase: normal operation. - transcription = RungeKutta(num_segments=num_seg) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.RungeKutta(num_segments=num_seg) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = prob.model.add_subsystem('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -481,12 +480,12 @@ def test_single_phase_reverse_propagation_rk(self): assert_rel_error(self, soc0[-1], 1.0, 1e-6) def test_connected_linkages_rk(self): - prob = Problem() + prob = om.Problem() if optimizer == 'SNOPT': - opt = prob.driver = pyOptSparseDriver() + opt = prob.driver = om.pyOptSparseDriver() opt.options['optimizer'] = optimizer - opt.options['dynamic_simul_derivs'] = True + opt.declare_coloring() opt.opt_settings['Major iterations limit'] = 1000 opt.opt_settings['Major feasibility tolerance'] = 1.0E-6 @@ -495,18 +494,18 @@ def test_connected_linkages_rk(self): opt.opt_settings['iSumm'] = 6 else: - opt = prob.driver = ScipyOptimizeDriver() - opt.options['dynamic_simul_derivs'] = True + opt = prob.driver = om.ScipyOptimizeDriver() + opt.declare_coloring() num_seg = 20 seg_ends, _ = lgl(num_seg + 1) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. - transcription = RungeKutta(num_segments=num_seg) - phase0 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.RungeKutta(num_segments=num_seg) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p0 = traj.add_phase('phase0', phase0) traj_p0.set_time_options(fix_initial=True, fix_duration=True) @@ -514,7 +513,7 @@ def test_connected_linkages_rk(self): # Second phase: normal operation. - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) traj_p1 = traj.add_phase('phase1', phase1) traj_p1.set_time_options(fix_initial=False, fix_duration=True) @@ -523,16 +522,16 @@ def test_connected_linkages_rk(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) traj_p1_bfail = traj.add_phase('phase1_bfail', phase1_bfail) traj_p1_bfail.set_time_options(fix_initial=False, fix_duration=True) traj_p1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False) # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) traj_p1_mfail = traj.add_phase('phase1_mfail', phase1_mfail) traj_p1_mfail.set_time_options(fix_initial=False, fix_duration=True) @@ -546,7 +545,7 @@ def test_connected_linkages_rk(self): connected=True) prob.model.options['assembled_jac_type'] = 'csc' - prob.model.linear_solver = DirectSolver(assemble_jac=True) + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() diff --git a/dymos/examples/battery_multibranch/test/test_multibranch_trajectory_rk_ivp.py b/dymos/examples/battery_multibranch/test/test_multibranch_trajectory_rk_ivp.py index 8b084c7c1..b282f10ac 100644 --- a/dymos/examples/battery_multibranch/test/test_multibranch_trajectory_rk_ivp.py +++ b/dymos/examples/battery_multibranch/test/test_multibranch_trajectory_rk_ivp.py @@ -6,9 +6,8 @@ import unittest -from openmdao.api import Problem, Group - -from dymos import Trajectory, Phase, Radau, RungeKutta +import openmdao.api as om +import dymos as dm from dymos.examples.battery_multibranch.battery_multibranch_ode import BatteryODE @@ -16,16 +15,16 @@ class TestBatteryRKIVP(unittest.TestCase): def test_dynamic_input_params(self): - prob = Problem(model=Group()) + prob = om.Problem(model=om.Group()) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 - phase0 = Phase(ode_class=BatteryODE, transcription=RungeKutta(num_segments=200)) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=dm.RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) phase0.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') @@ -36,8 +35,8 @@ def test_dynamic_input_params(self): # Second phase: normal operation. - transcription = Radau(num_segments=5, order=5, compressed=True) - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, compressed=True) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') @@ -48,8 +47,8 @@ def test_dynamic_input_params(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') @@ -60,8 +59,8 @@ def test_dynamic_input_params(self): # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') @@ -74,7 +73,7 @@ def test_dynamic_input_params(self): traj.link_phases(phases=['phase0', 'phase1_bfail'], vars=['state_of_charge', 'time'], connected=True) traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) - # prob.model.linear_solver = DirectSolver(assemble_jac=True) + # prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() @@ -159,16 +158,16 @@ def test_dynamic_input_params(self): plt.show() def test_static_input_params(self): - prob = Problem(model=Group()) + prob = om.Problem(model=om.Group()) - traj = prob.model.add_subsystem('traj', Trajectory()) + traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 - phase0 = Phase(ode_class=BatteryODE, transcription=RungeKutta(num_segments=200)) + phase0 = dm.Phase(ode_class=BatteryODE, transcription=dm.RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.set_state_options('state_of_charge', fix_initial=True, fix_final=False) phase0.add_timeseries_output('battery.V_oc', output_name='V_oc', units='V') @@ -179,8 +178,8 @@ def test_static_input_params(self): # Second phase: normal operation. - transcription = Radau(num_segments=5, order=5, compressed=True) - phase1 = Phase(ode_class=BatteryODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=5, compressed=True) + phase1 = dm.Phase(ode_class=BatteryODE, transcription=transcription) phase1.set_time_options(fix_initial=False, fix_duration=True) phase1.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) @@ -192,8 +191,8 @@ def test_static_input_params(self): # Second phase, but with battery failure. - phase1_bfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, - transcription=transcription) + phase1_bfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_battery': 2}, + transcription=transcription) phase1_bfail.set_time_options(fix_initial=False, fix_duration=True) phase1_bfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) @@ -205,8 +204,8 @@ def test_static_input_params(self): # Second phase, but with motor failure. - phase1_mfail = Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, - transcription=transcription) + phase1_mfail = dm.Phase(ode_class=BatteryODE, ode_init_kwargs={'num_motor': 2}, + transcription=transcription) phase1_mfail.set_time_options(fix_initial=False, fix_duration=True) phase1_mfail.set_state_options('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True) @@ -223,7 +222,7 @@ def test_static_input_params(self): traj.link_phases(phases=['phase0', 'phase1_mfail'], vars=['state_of_charge', 'time'], connected=True) - # prob.model.linear_solver = DirectSolver(assemble_jac=True) + # prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() diff --git a/dymos/examples/brachistochrone/brachistochrone_ode.py b/dymos/examples/brachistochrone/brachistochrone_ode.py index 9bfca7caa..9ff854120 100644 --- a/dymos/examples/brachistochrone/brachistochrone_ode.py +++ b/dymos/examples/brachistochrone/brachistochrone_ode.py @@ -1,7 +1,7 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om import dymos as dm @@ -11,7 +11,7 @@ @dm.declare_state('v', rate_source='vdot', targets='v', units='m/s') @dm.declare_parameter('theta', targets='theta', units='rad') @dm.declare_parameter('g', units='m/s**2', targets='g') -class BrachistochroneODE(ExplicitComponent): +class BrachistochroneODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/brachistochrone/brachistochrone_vector_states_ode.py b/dymos/examples/brachistochrone/brachistochrone_vector_states_ode.py index 2f683fa6a..130b3a2ed 100644 --- a/dymos/examples/brachistochrone/brachistochrone_vector_states_ode.py +++ b/dymos/examples/brachistochrone/brachistochrone_vector_states_ode.py @@ -1,7 +1,7 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om import dymos as dm @@ -10,7 +10,7 @@ @dm.declare_state('v', rate_source='vdot', targets=['v'], units='m/s') @dm.declare_parameter('theta', targets=['theta'], units='rad') @dm.declare_parameter('g', units='m/s**2', targets=['g']) -class BrachistochroneVectorStatesODE(ExplicitComponent): +class BrachistochroneVectorStatesODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/brachistochrone/doc/test_doc_brachistochrone.py b/dymos/examples/brachistochrone/doc/test_doc_brachistochrone.py index f93677e3c..2792d96d6 100644 --- a/dymos/examples/brachistochrone/doc/test_doc_brachistochrone.py +++ b/dymos/examples/brachistochrone/doc/test_doc_brachistochrone.py @@ -12,13 +12,12 @@ class TestBrachistochroneForDocs(unittest.TestCase): def tearDown(self): - for filename in ['coloring.json', 'SLSQP.out', 'SNOPT_print.out', 'SNOPT_summary.out']: + for filename in ['total_coloring.pkl', 'SLSQP.out', 'SNOPT_print.out', 'SNOPT_summary.out']: if os.path.exists(filename): os.remove(filename) def test_brachistochrone_for_docs_gauss_lobatto(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, \ - SqliteRecorder, CaseReader + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results @@ -27,9 +26,9 @@ def test_brachistochrone_for_docs_gauss_lobatto(self): # # Initialize the Problem and the optimization driver # - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() # # Create a trajectory and add a phase to it @@ -55,7 +54,7 @@ def test_brachistochrone_for_docs_gauss_lobatto(self): # phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the Problem @@ -94,7 +93,7 @@ def test_brachistochrone_for_docs_gauss_lobatto(self): plt.show() def test_brachistochrone_for_docs_radau(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, SqliteRecorder + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results @@ -103,9 +102,9 @@ def test_brachistochrone_for_docs_radau(self): # # Initialize the Problem and the optimization driver # - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() # # Create a trajectory and add a phase to it @@ -131,7 +130,7 @@ def test_brachistochrone_for_docs_radau(self): # phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the Problem @@ -171,7 +170,7 @@ def test_brachistochrone_for_docs_radau(self): plt.show() def test_brachistochrone_for_docs_runge_kutta(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, SqliteRecorder + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results @@ -180,9 +179,9 @@ def test_brachistochrone_for_docs_runge_kutta(self): # # Initialize the Problem and the optimization driver # - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() # # Create a trajectory and add a phase to it @@ -215,7 +214,7 @@ def test_brachistochrone_for_docs_runge_kutta(self): # phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the Problem @@ -255,7 +254,7 @@ def test_brachistochrone_for_docs_runge_kutta(self): plt.show() def test_brachistochrone_for_docs_runge_kutta_polynomial_controls(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, SqliteRecorder + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results @@ -264,9 +263,9 @@ def test_brachistochrone_for_docs_runge_kutta_polynomial_controls(self): # # Initialize the Problem and the optimization driver # - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() # # Create a trajectory and add a phase to it @@ -299,7 +298,7 @@ def test_brachistochrone_for_docs_runge_kutta_polynomial_controls(self): # phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the Problem diff --git a/dymos/examples/brachistochrone/test/ex_brachistochrone.py b/dymos/examples/brachistochrone/test/ex_brachistochrone.py index 350d4b81c..8d30f7c8c 100644 --- a/dymos/examples/brachistochrone/test/ex_brachistochrone.py +++ b/dymos/examples/brachistochrone/test/ex_brachistochrone.py @@ -4,9 +4,9 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group, pyOptSparseDriver, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE SHOW_PLOTS = True @@ -14,27 +14,26 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, transcription_order=3, run_driver=True, compressed=True, optimizer='SLSQP'): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - # if optimizer == 'SNOPT': - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() if transcription == 'gauss-lobatto': - t = GaussLobatto(num_segments=num_segments, - order=transcription_order, - compressed=compressed) + t = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) elif transcription == 'radau-ps': - t = Radau(num_segments=num_segments, - order=transcription_order, - compressed=compressed) + t = dm.Radau(num_segments=num_segments, + order=transcription_order, + compressed=compressed) elif transcription == 'runge-kutta': - t = RungeKutta(num_segments=num_segments, - order=transcription_order, - compressed=compressed) + t = dm.RungeKutta(num_segments=num_segments, + order=transcription_order, + compressed=compressed) - phase = Phase(ode_class=BrachistochroneODE, transcription=t) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) p.model.add_subsystem('phase0', phase) @@ -54,7 +53,7 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/examples/brachistochrone/test/ex_brachistochrone_vector_states.py b/dymos/examples/brachistochrone/test/ex_brachistochrone_vector_states.py index fb8f93281..1e05601f6 100644 --- a/dymos/examples/brachistochrone/test/ex_brachistochrone_vector_states.py +++ b/dymos/examples/brachistochrone/test/ex_brachistochrone_vector_states.py @@ -4,9 +4,8 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group, pyOptSparseDriver, ScipyOptimizeDriver, DirectSolver - -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import openmdao.api as om +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_vector_states_ode \ import BrachistochroneVectorStatesODE @@ -17,33 +16,34 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran compressed=True, sim_record='brach_min_time_sim.db', optimizer='SLSQP', dynamic_simul_derivs=True, force_alloc_complex=False, solve_segments=False, run_driver=True): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) if optimizer == 'SNOPT': - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings['iSumm'] = 6 else: - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = dynamic_simul_derivs + if dynamic_simul_derivs: + p.driver.declare_coloring() if transcription == 'runge-kutta': - transcription = RungeKutta(num_segments=num_segments, compressed=compressed) + transcription = dm.RungeKutta(num_segments=num_segments, compressed=compressed) elif transcription == 'gauss-lobatto': - transcription = GaussLobatto(num_segments=num_segments, - order=transcription_order, - compressed=compressed) + transcription = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) elif transcription == 'radau-ps': - transcription = Radau(num_segments=num_segments, - order=transcription_order, - compressed=compressed) + transcription = dm.Radau(num_segments=num_segments, + order=transcription_order, + compressed=compressed) - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=transcription) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=transcription) p.model.add_subsystem('phase0', phase) @@ -62,7 +62,7 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) p['phase0.t_initial'] = 0.0 diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_implicit_recorder.py b/dymos/examples/brachistochrone/test/test_brachistochrone_implicit_recorder.py index d2f0b3c50..c47b2f2c2 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_implicit_recorder.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_implicit_recorder.py @@ -2,6 +2,7 @@ import os import unittest +from dymos.utils.testing_utils import use_tempdirs class TestBrachistochroneRecordingExample(unittest.TestCase): @@ -12,19 +13,19 @@ def tearDownClass(cls): if os.path.exists(filename): os.remove(filename) + @use_tempdirs def test_brachistochrone_recording(self): import matplotlib matplotlib.use('Agg') - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver, \ - SqliteRecorder, CaseReader + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -41,10 +42,10 @@ def test_brachistochrone_recording(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # Recording - rec = SqliteRecorder('brachistochrone_solution.db') + rec = om.SqliteRecorder('brachistochrone_solution.db') p.driver.recording_options['record_desvars'] = True p.driver.recording_options['record_responses'] = True @@ -73,7 +74,7 @@ def test_brachistochrone_recording(self): # Test the results assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) - cr = CaseReader('brachistochrone_solution.db') + cr = om.CaseReader('brachistochrone_solution.db') system_cases = cr.list_cases('root') case = cr.get_case(system_cases[-1]) diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_integrated_control.py b/dymos/examples/brachistochrone/test/test_brachistochrone_integrated_control.py index 82d128cf9..1dd579933 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_integrated_control.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_integrated_control.py @@ -6,18 +6,18 @@ import numpy as np from scipy.interpolate import interp1d -from openmdao.api import ExplicitComponent -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm -@declare_time(units='s') -@declare_state('x', rate_source='xdot', units='m') -@declare_state('y', rate_source='ydot', units='m') -@declare_state('v', rate_source='vdot', targets=['v'], units='m/s') -@declare_state('theta', targets=['theta'], rate_source='theta_dot', units='rad') -@declare_parameter('theta_dot', targets=[], units='rad/s') -@declare_parameter('g', units='m/s**2', targets=['g']) -class BrachistochroneODE(ExplicitComponent): +@dm.declare_time(units='s') +@dm.declare_state('x', rate_source='xdot', units='m') +@dm.declare_state('y', rate_source='ydot', units='m') +@dm.declare_state('v', rate_source='vdot', targets=['v'], units='m/s') +@dm.declare_state('theta', targets=['theta'], rate_source='theta_dot', units='rad') +@dm.declare_parameter('theta_dot', targets=[], units='rad/s') +@dm.declare_parameter('g', units='m/s**2', targets=['g']) +class BrachistochroneODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) @@ -98,14 +98,14 @@ def tearDownClass(cls): def test_brachistochrone_integrated_control_gauss_lobatto(self): import numpy as np - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -123,7 +123,7 @@ def test_brachistochrone_integrated_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -173,14 +173,14 @@ def test_brachistochrone_integrated_control_gauss_lobatto(self): def test_brachistochrone_integrated_control_radau_ps(self): import numpy as np - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -198,7 +198,7 @@ def test_brachistochrone_integrated_control_radau_ps(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.model.options['assembled_jac_type'] = 'csc' p.setup() diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_quick_start.py b/dymos/examples/brachistochrone/test/test_brachistochrone_quick_start.py index 9ccfeb039..0c0729773 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_quick_start.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_quick_start.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class BrachistochroneODE(ExplicitComponent): +class BrachistochroneODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) @@ -65,7 +65,7 @@ class TestBrachistochroneQuickStart(unittest.TestCase): def test_brachistochrone_quick_start(self): import numpy as np - from openmdao.api import Problem, Group, ScipyOptimizeDriver + import openmdao.api as om import dymos as dm import matplotlib matplotlib.use('Agg') @@ -74,7 +74,7 @@ def test_brachistochrone_quick_start(self): # # Define the OpenMDAO problem # - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) # # Define a Trajectory object @@ -118,11 +118,11 @@ def test_brachistochrone_quick_start(self): phase.add_objective('time', loc='final') # Set the driver. - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() # Setup the problem p.setup(check=True) diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py b/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py index 5bfab508f..0e85a998f 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_rk4.py @@ -6,17 +6,17 @@ class TestBrachistochroneRK4Example(unittest.TestCase): def test_brachistochrone_forward_shooting(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -39,7 +39,7 @@ def test_brachistochrone_forward_shooting(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -66,17 +66,17 @@ def test_brachistochrone_forward_shooting(self): tolerance=1.0E-3) def test_brachistochrone_backward_shooting(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -100,7 +100,7 @@ def test_brachistochrone_backward_shooting(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=-1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -127,17 +127,17 @@ def test_brachistochrone_backward_shooting(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_path_constrained_state(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -161,7 +161,7 @@ def test_brachistochrone_forward_shooting_path_constrained_state(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -188,17 +188,17 @@ def test_brachistochrone_forward_shooting_path_constrained_state(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_path_constrained_control(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -222,7 +222,7 @@ def test_brachistochrone_forward_shooting_path_constrained_control(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -249,17 +249,17 @@ def test_brachistochrone_forward_shooting_path_constrained_control(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_path_constrained_control_rate(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -283,7 +283,7 @@ def test_brachistochrone_forward_shooting_path_constrained_control_rate(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -310,17 +310,17 @@ def test_brachistochrone_forward_shooting_path_constrained_control_rate(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_path_constrained_ode_output(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -344,7 +344,7 @@ def test_brachistochrone_forward_shooting_path_constrained_ode_output(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -371,17 +371,17 @@ def test_brachistochrone_forward_shooting_path_constrained_ode_output(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_boundary_constrained_control_rate(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -405,7 +405,7 @@ def test_brachistochrone_forward_shooting_boundary_constrained_control_rate(self # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -434,17 +434,17 @@ def test_brachistochrone_forward_shooting_boundary_constrained_control_rate(self tolerance=1.0E-3) def test_brachistochrone_forward_shooting_boundary_constrained_design_parameter(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -466,7 +466,7 @@ def test_brachistochrone_forward_shooting_boundary_constrained_design_parameter( # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -498,17 +498,17 @@ def test_brachistochrone_forward_shooting_boundary_constrained_design_parameter( tolerance=1.0E-3) def test_brachistochrone_forward_shooting_boundary_constrained_ode_output(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -531,7 +531,7 @@ def test_brachistochrone_forward_shooting_boundary_constrained_ode_output(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -558,16 +558,16 @@ def test_brachistochrone_forward_shooting_boundary_constrained_ode_output(self): tolerance=1.0E-3) def test_brachistochrone_forward_shooting_path_constrained_time(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -593,7 +593,7 @@ def test_brachistochrone_forward_shooting_path_constrained_time(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_undecorated_ode.py b/dymos/examples/brachistochrone/test/test_brachistochrone_undecorated_ode.py index acfed4bd2..628154a43 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_undecorated_ode.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_undecorated_ode.py @@ -2,10 +2,10 @@ import unittest import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class BrachistochroneODE(ExplicitComponent): +class BrachistochroneODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) @@ -83,14 +83,14 @@ def test_brachistochrone_undecorated_ode_gl(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -107,7 +107,7 @@ def test_brachistochrone_undecorated_ode_gl(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -130,14 +130,14 @@ def test_brachistochrone_undecorated_ode_radau(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -154,7 +154,7 @@ def test_brachistochrone_undecorated_ode_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -177,14 +177,14 @@ def test_brachistochrone_undecorated_ode_rk(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -204,7 +204,7 @@ def test_brachistochrone_undecorated_ode_rk(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -226,11 +226,11 @@ def test_brachistochrone_undecorated_ode_rk(self): class TestBrachistochroneBasePhaseClass(unittest.TestCase): def test_brachistochrone_base_phase_class_gl(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm - class BrachistochronePhase(Phase): + class BrachistochronePhase(dm.Phase): def setup(self): @@ -247,10 +247,10 @@ def setup(self): super(BrachistochronePhase, self).setup() - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = BrachistochronePhase(transcription=GaussLobatto(num_segments=20, order=3)) + phase = BrachistochronePhase(transcription=dm.GaussLobatto(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) phase.add_boundary_constraint('x', loc='final', equals=10) @@ -259,7 +259,7 @@ def setup(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_boundary_constraints.py b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_boundary_constraints.py index d3af71901..0236ae453 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_boundary_constraints.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_boundary_constraints.py @@ -6,27 +6,27 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_vector_states_ode \ import BrachistochroneVectorStatesODE -SHOW_PLOTS = True +SHOW_PLOTS = False class TestBrachistochroneVectorBoundaryConstraints(unittest.TestCase): def test_brachistochrone_vector_boundary_constraints_radau_no_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -45,7 +45,7 @@ def test_brachistochrone_vector_boundary_constraints_radau_no_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -108,12 +108,12 @@ def test_brachistochrone_vector_boundary_constraints_radau_no_indices(self): def test_brachistochrone_vector_boundary_constraints_radau_full_indices(self): - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -132,7 +132,7 @@ def test_brachistochrone_vector_boundary_constraints_radau_full_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -195,12 +195,12 @@ def test_brachistochrone_vector_boundary_constraints_radau_full_indices(self): def test_brachistochrone_vector_boundary_constraints_radau_partial_indices(self): - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -219,7 +219,7 @@ def test_brachistochrone_vector_boundary_constraints_radau_partial_indices(self) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py index d83e7b61b..b616d7c62 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py @@ -8,27 +8,27 @@ matplotlib.use('Agg') import matplotlib.pyplot as plt -from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_vector_states_ode \ import BrachistochroneVectorStatesODE -SHOW_PLOTS = True +SHOW_PLOTS = False class TestBrachistochroneVectorPathConstraints(unittest.TestCase): def test_brachistochrone_vector_state_path_constraints_radau_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -42,6 +42,8 @@ def test_brachistochrone_vector_state_path_constraints_radau_partial_indices(sel phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) + phase.add_boundary_constraint('theta_rate', loc='final', equals=0.0) + phase.add_boundary_constraint('theta_rate2', loc='final', equals=0.0) phase.add_path_constraint('pos', indices=[1], lower=5) phase.add_timeseries_output('pos_dot', shape=(2,), units='m/s') @@ -49,7 +51,7 @@ def test_brachistochrone_vector_state_path_constraints_radau_partial_indices(sel # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -65,7 +67,8 @@ def test_brachistochrone_vector_state_path_constraints_radau_partial_indices(sel p.run_driver() - assert_rel_error(self, p.get_val('phase0.time')[-1], 1.8016, tolerance=1.0E-3) + assert_rel_error(self, np.min(p.get_val('phase0.timeseries.states:pos')[:, 1]), 5.0, + tolerance=1.0E-3) # Plot results if SHOW_PLOTS: @@ -134,13 +137,13 @@ def test_brachistochrone_vector_state_path_constraints_radau_partial_indices(sel def test_brachistochrone_vector_ode_path_constraints_radau_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -162,7 +165,7 @@ def test_brachistochrone_vector_ode_path_constraints_radau_partial_indices(self) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -250,13 +253,13 @@ def test_brachistochrone_vector_ode_path_constraints_radau_partial_indices(self) def test_brachistochrone_vector_ode_path_constraints_radau_no_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=Radau(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -278,7 +281,7 @@ def test_brachistochrone_vector_ode_path_constraints_radau_no_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -366,13 +369,13 @@ def test_brachistochrone_vector_ode_path_constraints_radau_no_indices(self): def test_brachistochrone_vector_state_path_constraints_gl_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=GaussLobatto(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.GaussLobatto(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -393,7 +396,7 @@ def test_brachistochrone_vector_state_path_constraints_gl_partial_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -409,7 +412,10 @@ def test_brachistochrone_vector_state_path_constraints_gl_partial_indices(self): p.run_driver() - assert_rel_error(self, p.get_val('phase0.time')[-1], 1.8016, tolerance=1.0E-3) + assert_rel_error(self, + np.min(p.get_val('phase0.timeseries.states:pos')[:, 1]), + 5, + tolerance=1.0E-2) # Plot results if SHOW_PLOTS: @@ -478,13 +484,13 @@ def test_brachistochrone_vector_state_path_constraints_gl_partial_indices(self): def test_brachistochrone_vector_ode_path_constraints_gl_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=GaussLobatto(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.GaussLobatto(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -498,6 +504,8 @@ def test_brachistochrone_vector_ode_path_constraints_gl_partial_indices(self): phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) + phase.add_boundary_constraint('theta_rate', loc='final', equals=0.0) + phase.add_boundary_constraint('theta_rate2', loc='final', equals=0.0) phase.add_path_constraint('pos_dot', shape=(2,), units='m/s', indices=[1], lower=-4, upper=4) @@ -506,7 +514,7 @@ def test_brachistochrone_vector_ode_path_constraints_gl_partial_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -522,10 +530,8 @@ def test_brachistochrone_vector_ode_path_constraints_gl_partial_indices(self): p.run_driver() - assert_rel_error(self, - np.min(p.get_val('phase0.timeseries.pos_dot')[:, -1]), - -4, - tolerance=1.0E-2) + assert_rel_error(self, np.min(p.get_val('phase0.timeseries.pos_dot')[:, 1]), -4.0, + tolerance=1.0E-3) # Plot results if SHOW_PLOTS: @@ -594,13 +600,13 @@ def test_brachistochrone_vector_ode_path_constraints_gl_partial_indices(self): def test_brachistochrone_vector_ode_path_constraints_gl_no_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=GaussLobatto(num_segments=20, order=3)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.GaussLobatto(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) @@ -622,7 +628,7 @@ def test_brachistochrone_vector_ode_path_constraints_gl_no_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -709,13 +715,13 @@ def test_brachistochrone_vector_ode_path_constraints_gl_no_indices(self): return p def test_brachistochrone_vector_state_path_constraints_rk_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=RungeKutta(num_segments=50)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.RungeKutta(num_segments=50)) p.model.add_subsystem('phase0', phase) @@ -737,7 +743,7 @@ def test_brachistochrone_vector_state_path_constraints_rk_partial_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -823,13 +829,13 @@ def test_brachistochrone_vector_state_path_constraints_rk_partial_indices(self): def test_brachistochrone_vector_ode_path_constraints_rk_partial_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -853,7 +859,7 @@ def test_brachistochrone_vector_ode_path_constraints_rk_partial_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 @@ -941,13 +947,13 @@ def test_brachistochrone_vector_ode_path_constraints_rk_partial_indices(self): def test_brachistochrone_vector_ode_path_constraints_rk_no_indices(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=RungeKutta(num_segments=20)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.RungeKutta(num_segments=20)) p.model.add_subsystem('phase0', phase) @@ -971,7 +977,7 @@ def test_brachistochrone_vector_ode_path_constraints_rk_no_indices(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_states_ode.py b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_states_ode.py index eb26b9460..1f6dc4419 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_states_ode.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_states_ode.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import \ @@ -17,9 +17,9 @@ class TestBrachistochroneVectorStatesODE(unittest.TestCase): def setUpClass(cls): nn = 5 - p = cls.p = Problem(model=Group()) + p = cls.p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('v', val=np.ones((nn,)), units='m/s') ivc.add_output('g', val=np.zeros((nn,)), units='m/s**2') ivc.add_output('theta', val=np.zeros((nn)), units='rad') diff --git a/dymos/examples/brachistochrone/test/test_doc_brachistochrone_polynomial_controls.py b/dymos/examples/brachistochrone/test/test_doc_brachistochrone_polynomial_controls.py index d1d91cde0..b8501e927 100644 --- a/dymos/examples/brachistochrone/test/test_doc_brachistochrone_polynomial_controls.py +++ b/dymos/examples/brachistochrone/test/test_doc_brachistochrone_polynomial_controls.py @@ -9,17 +9,17 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -38,7 +38,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -95,17 +95,17 @@ def test_brachistochrone_polynomial_control_radau(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -123,7 +123,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -180,17 +180,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -211,7 +211,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -267,21 +267,20 @@ def test_brachistochrone_polynomial_control_rungekutta(self): class TestBrachistochronePolynomialControlBoundaryConstrained(unittest.TestCase): def test_brachistochrone_polynomial_control_gauss_lobatto(self): - import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -302,7 +301,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -355,21 +354,20 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): plt.show() def test_brachistochrone_polynomial_control_radau(self): - import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -390,7 +388,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -447,17 +445,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -481,7 +479,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -537,21 +535,20 @@ def test_brachistochrone_polynomial_control_rungekutta(self): class TestBrachistochronePolynomialControlPathConstrained(unittest.TestCase): def test_brachistochrone_polynomial_control_gauss_lobatto(self): - import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -571,7 +568,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -628,17 +625,17 @@ def test_brachistochrone_polynomial_control_radau(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -658,7 +655,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -715,17 +712,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -748,7 +745,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -808,17 +805,17 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -838,7 +835,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -895,17 +892,17 @@ def test_brachistochrone_polynomial_control_radau(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -925,7 +922,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -982,17 +979,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1015,7 +1012,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1075,17 +1072,17 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1105,7 +1102,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1162,17 +1159,17 @@ def test_brachistochrone_polynomial_control_radau(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1192,7 +1189,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1249,17 +1246,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1282,7 +1279,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1338,17 +1335,17 @@ def test_brachistochrone_polynomial_control_rungekutta(self): class TestBrachistochronePolynomialControlSimulation(unittest.TestCase): def test_brachistochrone_polynomial_control_gauss_lobatto(self): - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1365,7 +1362,7 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1393,17 +1390,17 @@ def test_brachistochrone_polynomial_control_gauss_lobatto(self): assert_rel_error(self, theta_exp[-1], theta_imp[-1]) def test_brachistochrone_polynomial_control_radau(self): - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1421,7 +1418,7 @@ def test_brachistochrone_polynomial_control_radau(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -1449,17 +1446,17 @@ def test_brachistochrone_polynomial_control_radau(self): assert_rel_error(self, theta_exp[-1], theta_imp[-1]) def test_brachistochrone_polynomial_control_rungekutta(self): - from openmdao.api import Problem, Group, DirectSolver, ScipyOptimizeDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, RungeKutta + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=RungeKutta(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.RungeKutta(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -1480,7 +1477,7 @@ def test_brachistochrone_polynomial_control_rungekutta(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() 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 1c9df9b64..f80f41aa4 100644 --- a/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py +++ b/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py @@ -108,19 +108,19 @@ def test_ex_brachistochrone_vs_gl_uncompressed(self): os.remove('ex_brachvs_gl_compressed.db') def test_ex_brachistochrone_vs_rungekutta_compressed(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver - from dymos import Phase, RungeKutta + import openmdao.api as om + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_vector_states_ode import \ BrachistochroneVectorStatesODE - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneVectorStatesODE, - transcription=RungeKutta(num_segments=20, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, + transcription=dm.RungeKutta(num_segments=20, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -139,7 +139,7 @@ def test_ex_brachistochrone_vs_rungekutta_compressed(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/examples/brachistochrone/test/test_path_constraints.py b/dymos/examples/brachistochrone/test/test_path_constraints.py index 9b038feed..5f03bd373 100644 --- a/dymos/examples/brachistochrone/test/test_path_constraints.py +++ b/dymos/examples/brachistochrone/test/test_path_constraints.py @@ -6,16 +6,16 @@ class TestBrachistochronePathConstraints(unittest.TestCase): def test_control_rate_path_constraint_gl(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10)) p.model.add_subsystem('phase0', phase) @@ -34,7 +34,7 @@ def test_control_rate_path_constraint_gl(self): phase.add_path_constraint('theta_rate', lower=0, upper=100, units='deg/s') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -53,16 +53,16 @@ def test_control_rate_path_constraint_gl(self): assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) def test_control_rate2_path_constraint_gl(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, GaussLobatto + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=10, order=5)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=10, order=5)) p.model.add_subsystem('phase0', phase) @@ -81,7 +81,7 @@ def test_control_rate2_path_constraint_gl(self): phase.add_path_constraint('theta_rate2', lower=-200, upper=200, units='rad/s**2') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.model.options['assembled_jac_type'] = 'csc' p.setup() @@ -101,17 +101,17 @@ def test_control_rate2_path_constraint_gl(self): assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) def test_control_rate_path_constraint_radau(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10, - compressed=False)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10, + compressed=False)) p.model.add_subsystem('phase0', phase) @@ -130,7 +130,7 @@ def test_control_rate_path_constraint_radau(self): phase.add_path_constraint('theta_rate', lower=0, upper=100, units='deg/s') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() @@ -149,17 +149,17 @@ def test_control_rate_path_constraint_radau(self): assert_rel_error(self, p.get_val('phase0.timeseries.time')[-1], 1.8016, tolerance=1.0E-3) def test_control_rate2_path_constraint_radau(self): - from openmdao.api import Problem, Group, ScipyOptimizeDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Radau + import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE - p = Problem(model=Group()) - p.driver = ScipyOptimizeDriver() + p = om.Problem(model=om.Group()) + p.driver = om.ScipyOptimizeDriver() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=10, - compressed=False)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=10, + compressed=False)) p.model.add_subsystem('phase0', phase) @@ -178,7 +178,7 @@ def test_control_rate2_path_constraint_radau(self): phase.add_path_constraint('theta_rate2', lower=-200, upper=200, units='rad/s**2') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.model.options['assembled_jac_type'] = 'csc' p.setup() diff --git a/dymos/examples/cannonball/cannonball_ode.py b/dymos/examples/cannonball/cannonball_ode.py index 3ccba13cc..f4024adb0 100644 --- a/dymos/examples/cannonball/cannonball_ode.py +++ b/dymos/examples/cannonball/cannonball_ode.py @@ -1,8 +1,7 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group - -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm from dymos.examples.min_time_climb.aero.dynamic_pressure_comp import DynamicPressureComp from dymos.examples.min_time_climb.aero.lift_drag_force_comp import LiftDragForceComp from dymos.models.atmosphere import USatm1976Comp @@ -10,19 +9,19 @@ from .kinetic_energy_comp import KineticEnergyComp -@declare_time(units='s') -@declare_state(name='r', rate_source='eom.r_dot', units='m') -@declare_state(name='h', rate_source='eom.h_dot', targets=['atmos.h'], units='m') -@declare_state(name='gam', rate_source='eom.gam_dot', targets=['eom.gam'], units='rad') -@declare_state(name='v', rate_source='eom.v_dot', - targets=['dynamic_pressure.v', 'eom.v', 'kinetic_energy.v'], units='m/s') -@declare_parameter(name='CD', targets=['aero.CD'], units=None) -@declare_parameter(name='CL', targets=['aero.CL'], units=None) -@declare_parameter(name='T', targets=['eom.T'], units='N') -@declare_parameter(name='alpha', targets=['eom.alpha'], units='deg') -@declare_parameter(name='m', targets=['eom.m', 'kinetic_energy.m'], units='kg') -@declare_parameter(name='S', targets=['aero.S'], units='m**2') -class CannonballODE(Group): +@dm.declare_time(units='s') +@dm.declare_state(name='r', rate_source='eom.r_dot', units='m') +@dm.declare_state(name='h', rate_source='eom.h_dot', targets=['atmos.h'], units='m') +@dm.declare_state(name='gam', rate_source='eom.gam_dot', targets=['eom.gam'], units='rad') +@dm.declare_state(name='v', rate_source='eom.v_dot', + targets=['dynamic_pressure.v', 'eom.v', 'kinetic_energy.v'], units='m/s') +@dm.declare_parameter(name='CD', targets=['aero.CD'], units=None) +@dm.declare_parameter(name='CL', targets=['aero.CL'], units=None) +@dm.declare_parameter(name='T', targets=['eom.T'], units='N') +@dm.declare_parameter(name='alpha', targets=['eom.alpha'], units='deg') +@dm.declare_parameter(name='m', targets=['eom.m', 'kinetic_energy.m'], units='kg') +@dm.declare_parameter(name='S', targets=['aero.S'], units='m**2') +class CannonballODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/cannonball/cannonball_undecorated_ode.py b/dymos/examples/cannonball/cannonball_undecorated_ode.py index 63a86a356..009d81806 100644 --- a/dymos/examples/cannonball/cannonball_undecorated_ode.py +++ b/dymos/examples/cannonball/cannonball_undecorated_ode.py @@ -1,8 +1,6 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group - -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om from dymos.examples.min_time_climb.aero.dynamic_pressure_comp import DynamicPressureComp from dymos.examples.min_time_climb.aero.lift_drag_force_comp import LiftDragForceComp from dymos.models.atmosphere import USatm1976Comp @@ -10,7 +8,7 @@ from .kinetic_energy_comp import KineticEnergyComp -class CannonballUndecoratedODE(Group): +class CannonballUndecoratedODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py index af9e439ab..747e06f95 100644 --- a/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py +++ b/dymos/examples/cannonball/doc/test_doc_two_phase_cannonball.py @@ -13,22 +13,21 @@ class TestTwoPhaseCannonballForDocs(unittest.TestCase): def test_two_phase_cannonball_for_docs(self): - from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ - pyOptSparseDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Trajectory, Radau, GaussLobatto + import dymos as dm from dymos.examples.cannonball.cannonball_ode import CannonballODE from dymos.examples.cannonball.size_comp import CannonballSizeComp - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - external_params = p.model.add_subsystem('external_params', IndepVarComp()) + external_params = p.model.add_subsystem('external_params', om.IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') @@ -37,10 +36,10 @@ def test_two_phase_cannonball_for_docs(self): p.model.add_subsystem('size_comp', CannonballSizeComp()) - traj = p.model.add_subsystem('traj', Trajectory()) + traj = p.model.add_subsystem('traj', dm.Trajectory()) - transcription = Radau(num_segments=5, order=3, compressed=True) - ascent = Phase(ode_class=CannonballODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=3, compressed=True) + ascent = dm.Phase(ode_class=CannonballODE, transcription=transcription) ascent = traj.add_phase('ascent', ascent) @@ -58,8 +57,8 @@ def test_two_phase_cannonball_for_docs(self): upper=400000, lower=0, ref=100000, shape=(1,)) # Second Phase (descent) - transcription = GaussLobatto(num_segments=5, order=3, compressed=True) - descent = Phase(ode_class=CannonballODE, transcription=transcription) + transcription = dm.GaussLobatto(num_segments=5, order=3, compressed=True) + descent = dm.Phase(ode_class=CannonballODE, transcription=transcription) traj.add_phase('descent', descent) @@ -99,9 +98,9 @@ def test_two_phase_cannonball_for_docs(self): p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) + p.driver.add_recorder(om.SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) diff --git a/dymos/examples/cannonball/kinetic_energy_comp.py b/dymos/examples/cannonball/kinetic_energy_comp.py index f6b6561e0..97fcf268a 100644 --- a/dymos/examples/cannonball/kinetic_energy_comp.py +++ b/dymos/examples/cannonball/kinetic_energy_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class KineticEnergyComp(ExplicitComponent): +class KineticEnergyComp(om.ExplicitComponent): """ Computes the kinetic energy of a particle based on its speed and mass diff --git a/dymos/examples/cannonball/size_comp.py b/dymos/examples/cannonball/size_comp.py index 22e52eb7c..4af9e93f9 100644 --- a/dymos/examples/cannonball/size_comp.py +++ b/dymos/examples/cannonball/size_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class CannonballSizeComp(ExplicitComponent): +class CannonballSizeComp(om.ExplicitComponent): """ Compute the reference area and mass of a cannonball with a given radius and density. diff --git a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py index 17656063f..3e80c5690 100644 --- a/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py +++ b/dymos/examples/cannonball/test/test_two_phase_cannonball_undecorated_ode.py @@ -13,22 +13,21 @@ class TestTwoPhaseCannonball(unittest.TestCase): def test_two_phase_cannonball_undecorated_ode(self): - from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ - pyOptSparseDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error - from dymos import Phase, Trajectory, Radau, GaussLobatto + import dymos as dm from dymos.examples.cannonball.cannonball_undecorated_ode import CannonballUndecoratedODE from dymos.examples.cannonball.size_comp import CannonballSizeComp - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - external_params = p.model.add_subsystem('external_params', IndepVarComp()) + external_params = p.model.add_subsystem('external_params', om.IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') @@ -37,10 +36,10 @@ def test_two_phase_cannonball_undecorated_ode(self): p.model.add_subsystem('size_comp', CannonballSizeComp()) - traj = p.model.add_subsystem('traj', Trajectory()) + traj = p.model.add_subsystem('traj', dm.Trajectory()) - transcription = Radau(num_segments=5, order=3, compressed=True) - ascent = Phase(ode_class=CannonballUndecoratedODE, transcription=transcription) + transcription = dm.Radau(num_segments=5, order=3, compressed=True) + ascent = dm.Phase(ode_class=CannonballUndecoratedODE, transcription=transcription) ascent = traj.add_phase('ascent', ascent) @@ -63,8 +62,8 @@ def test_two_phase_cannonball_undecorated_ode(self): upper=400000, lower=0, ref=100000, shape=(1,)) # Second Phase (descent) - transcription = GaussLobatto(num_segments=5, order=3, compressed=True) - descent = Phase(ode_class=CannonballUndecoratedODE, transcription=transcription) + transcription = dm.GaussLobatto(num_segments=5, order=3, compressed=True) + descent = dm.Phase(ode_class=CannonballUndecoratedODE, transcription=transcription) traj.add_phase('descent', descent) @@ -122,9 +121,9 @@ def test_two_phase_cannonball_undecorated_ode(self): p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) + p.driver.add_recorder(om.SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) @@ -239,8 +238,7 @@ def test_two_phase_cannonball_undecorated_ode(self): plt.show() def test_two_phase_cannonball_mixed_odes(self): - from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, SqliteRecorder, \ - pyOptSparseDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm @@ -249,13 +247,13 @@ def test_two_phase_cannonball_mixed_odes(self): from dymos.examples.cannonball.size_comp import CannonballSizeComp - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - external_params = p.model.add_subsystem('external_params', IndepVarComp()) + external_params = p.model.add_subsystem('external_params', om.IndepVarComp()) external_params.add_output('radius', val=0.10, units='m') external_params.add_output('dens', val=7.87, units='g/cm**3') @@ -343,9 +341,9 @@ def test_two_phase_cannonball_mixed_odes(self): p.model.connect('size_comp.S', 'traj.input_parameters:S') # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.driver.add_recorder(SqliteRecorder('ex_two_phase_cannonball.db')) + p.driver.add_recorder(om.SqliteRecorder('ex_two_phase_cannonball.db')) p.setup(check=True) diff --git a/dymos/examples/double_integrator/doc/test_doc_double_integrator.py b/dymos/examples/double_integrator/doc/test_doc_double_integrator.py index 9a256211b..11d5a1bb5 100644 --- a/dymos/examples/double_integrator/doc/test_doc_double_integrator.py +++ b/dymos/examples/double_integrator/doc/test_doc_double_integrator.py @@ -13,23 +13,23 @@ class TestDoubleIntegratorForDocs(unittest.TestCase): @classmethod def tearDownClass(cls): - for filename in ['coloring.json', 'SLSQP.out', 'SNOPT_print.out']: + for filename in ['total_coloring.pkl', 'SLSQP.out', 'SNOPT_print.out']: if os.path.exists(filename): os.remove(filename) def test_double_integrator_for_docs(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE # Initialize the problem and assign the driver - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() # Setup the trajectory and its phase traj = p.model.add_subsystem('traj', dm.Trajectory()) @@ -54,7 +54,7 @@ def test_double_integrator_for_docs(self): # phase.add_objective('x', loc='final', scaler=-1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the problem and set our initial values. diff --git a/dymos/examples/double_integrator/double_integrator_ode.py b/dymos/examples/double_integrator/double_integrator_ode.py index 5fc2dbaad..357114607 100644 --- a/dymos/examples/double_integrator/double_integrator_ode.py +++ b/dymos/examples/double_integrator/double_integrator_ode.py @@ -1,9 +1,9 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import ExplicitComponent +import openmdao.api as om -class DoubleIntegratorODE(ExplicitComponent): +class DoubleIntegratorODE(om.ExplicitComponent): """ The double integrator is a special case where the state rates are all set to other states or parameters. Since we aren't computing any other outputs, the ODE doesn't actually diff --git a/dymos/examples/double_integrator/test/test_double_integrator.py b/dymos/examples/double_integrator/test/test_double_integrator.py index 9828c324a..ef48fc955 100644 --- a/dymos/examples/double_integrator/test/test_double_integrator.py +++ b/dymos/examples/double_integrator/test/test_double_integrator.py @@ -6,7 +6,7 @@ from parameterized import parameterized -from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm @@ -15,9 +15,9 @@ def double_integrator_direct_collocation(transcription='gauss-lobatto', compressed=True): - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() + p.driver.declare_coloring() if transcription == 'gauss-lobatto': t = dm.GaussLobatto(num_segments=30, order=3, compressed=compressed) @@ -41,7 +41,7 @@ def double_integrator_direct_collocation(transcription='gauss-lobatto', compress # Maximize distance travelled in one second. phase.add_objective('x', loc='final', scaler=-1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -61,7 +61,7 @@ class TestDoubleIntegratorExample(unittest.TestCase): @classmethod def tearDownClass(cls): - for filename in ['coloring.json', 'SLSQP.out', 'SNOPT_print.out']: + for filename in ['total_coloring.pkl', 'SLSQP.out', 'SNOPT_print.out']: if os.path.exists(filename): os.remove(filename) @@ -90,11 +90,11 @@ def test_ex_double_integrator_input_times(self, compressed=True): Tests that externally connected t_initial and t_duration function as expected. """ - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() + p.driver.declare_coloring() - times_ivc = p.model.add_subsystem('times_ivc', IndepVarComp(), + times_ivc = p.model.add_subsystem('times_ivc', om.IndepVarComp(), promotes_outputs=['t0', 'tp']) times_ivc.add_output(name='t0', val=0.0, units='s') times_ivc.add_output(name='tp', val=1.0, units='s') @@ -117,7 +117,7 @@ def test_ex_double_integrator_input_times(self, compressed=True): # Maximize distance travelled in one second. phase.add_objective('x', loc='final', scaler=-1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) @@ -132,9 +132,9 @@ def test_ex_double_integrator_input_times(self, compressed=True): def test_double_integrator_rk4(self, compressed=True): - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() + p.driver.declare_coloring() t = dm.RungeKutta(num_segments=30, order=3, compressed=compressed) @@ -155,7 +155,7 @@ def test_double_integrator_rk4(self, compressed=True): # Maximize distance travelled in one second. phase.add_objective('x', loc='final', scaler=-1) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) diff --git a/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py b/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py index a15dcacf0..3cb4d8b60 100644 --- a/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py +++ b/dymos/examples/finite_burn_orbit_raise/doc/test_doc_finite_burn_orbit_raise.py @@ -15,7 +15,7 @@ def test_finite_burn_orbit_raise(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver, SqliteRecorder + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm @@ -24,16 +24,16 @@ def test_finite_burn_orbit_raise(self): # # Instantiate the problem and trajectory # - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) traj = dm.Trajectory() p.model.add_subsystem('traj', traj) # # Setup the optimization driver # - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() # # The trajectory controls the design parameter governing exhaust velocity @@ -116,9 +116,9 @@ def test_finite_burn_orbit_raise(self): # # Finish Problem Setup # - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.driver.add_recorder(SqliteRecorder('two_burn_orbit_raise_example_for_docs.db')) + p.driver.add_recorder(om.SqliteRecorder('two_burn_orbit_raise_example_for_docs.db')) p.setup(check=True) diff --git a/dymos/examples/finite_burn_orbit_raise/finite_burn_eom.py b/dymos/examples/finite_burn_orbit_raise/finite_burn_eom.py index f20a0a79f..a7c8d378c 100644 --- a/dymos/examples/finite_burn_orbit_raise/finite_burn_eom.py +++ b/dymos/examples/finite_burn_orbit_raise/finite_burn_eom.py @@ -1,11 +1,10 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om import openmdao.utils.units as units -from dymos import declare_time, declare_state, declare_parameter - +import dymos as dm # Add canonical units to OpenMDAO MU_earth = 3.986592936294783e14 R_earth = 6378137.0 @@ -17,16 +16,16 @@ units.add_unit('DU', '{0}*m'.format(R_earth)) -@declare_time(units='TU') -@declare_state('r', rate_source='r_dot', targets=['r'], units='DU') -@declare_state('theta', rate_source='theta_dot', targets=['theta'], units='rad') -@declare_state('vr', rate_source='vr_dot', targets=['vr'], units='DU/TU') -@declare_state('vt', rate_source='vt_dot', targets=['vt'], units='DU/TU') -@declare_state('accel', rate_source='at_dot', targets=['accel'], units='DU/TU**2') -@declare_state('deltav', rate_source='deltav_dot', units='DU/TU') -@declare_parameter('u1', targets=['u1'], units='rad') -@declare_parameter('c', targets=['c'], units='DU/TU') -class FiniteBurnODE(ExplicitComponent): +@dm.declare_time(units='TU') +@dm.declare_state('r', rate_source='r_dot', targets=['r'], units='DU') +@dm.declare_state('theta', rate_source='theta_dot', targets=['theta'], units='rad') +@dm.declare_state('vr', rate_source='vr_dot', targets=['vr'], units='DU/TU') +@dm.declare_state('vt', rate_source='vt_dot', targets=['vt'], units='DU/TU') +@dm.declare_state('accel', rate_source='at_dot', targets=['accel'], units='DU/TU**2') +@dm.declare_state('deltav', rate_source='deltav_dot', units='DU/TU') +@dm.declare_parameter('u1', targets=['u1'], units='rad') +@dm.declare_parameter('c', targets=['c'], units='DU/TU') +class FiniteBurnODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/finite_burn_orbit_raise/test/test_ex_two_burn_orbit_raise.py b/dymos/examples/finite_burn_orbit_raise/test/test_ex_two_burn_orbit_raise.py index f87bea3a2..2c2a40dcc 100644 --- a/dymos/examples/finite_burn_orbit_raise/test/test_ex_two_burn_orbit_raise.py +++ b/dymos/examples/finite_burn_orbit_raise/test/test_ex_two_burn_orbit_raise.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, pyOptSparseDriver, SqliteRecorder +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt @@ -127,19 +127,19 @@ def two_burn_orbit_raise_problem(transcription='gauss-lobatto', optimizer='SLSQP transcription_order=3, compressed=False, show_output=True, connected=False): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer if optimizer == 'SNOPT': - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 if show_output: p.driver.opt_settings['iSumm'] = 6 else: - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() traj = make_traj(transcription=transcription, transcription_order=transcription_order, compressed=compressed, connected=connected) @@ -150,7 +150,7 @@ def two_burn_orbit_raise_problem(transcription='gauss-lobatto', optimizer='SLSQP # Needed to move the direct solver down into the phases for use with MPI. # - After moving down, used fewer iterations (about 30 less) - p.driver.add_recorder(SqliteRecorder('two_burn_orbit_raise_example.db')) + p.driver.add_recorder(om.SqliteRecorder('two_burn_orbit_raise_example.db')) p.setup(check=True) diff --git a/dymos/examples/finite_burn_orbit_raise/test/test_finite_burn_eom.py b/dymos/examples/finite_burn_orbit_raise/test/test_finite_burn_eom.py index ab9a84e12..c20e5e42d 100644 --- a/dymos/examples/finite_burn_orbit_raise/test/test_finite_burn_eom.py +++ b/dymos/examples/finite_burn_orbit_raise/test/test_finite_burn_eom.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials @@ -17,9 +17,9 @@ class TestFiniteBurnEOM(unittest.TestCase): def setUpClass(cls): nn = 2 - p = cls.p = Problem(model=Group()) + p = cls.p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) p.model.add_subsystem('ode', subsys=FiniteBurnODE(num_nodes=nn), promotes_inputs=['*'], promotes_outputs=['*']) diff --git a/dymos/examples/finite_burn_orbit_raise/test/test_two_burn_orbit_raise_linkages.py b/dymos/examples/finite_burn_orbit_raise/test/test_two_burn_orbit_raise_linkages.py index 6f498ac48..054c9150a 100644 --- a/dymos/examples/finite_burn_orbit_raise/test/test_two_burn_orbit_raise_linkages.py +++ b/dymos/examples/finite_burn_orbit_raise/test/test_two_burn_orbit_raise_linkages.py @@ -16,29 +16,29 @@ def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from openmdao.utils.general_utils import set_pyoptsparse_opt - from dymos import Phase, GaussLobatto, RungeKutta, Trajectory + import dymos as dm from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE - traj = Trajectory() - p = Problem(model=Group()) + traj = dm.Trajectory() + p = om.Problem(model=om.Group()) p.model.add_subsystem('traj', traj) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() _, optimizer = set_pyoptsparse_opt('SNOPT', fallback=True) p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() traj.add_design_parameter('c', opt=False, val=1.5, units='DU/TU') # First Phase (burn) - burn1 = Phase(ode_class=FiniteBurnODE, - transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) + burn1 = dm.Phase(ode_class=FiniteBurnODE, + transcription=dm.GaussLobatto(num_segments=10, order=3, compressed=True)) burn1 = traj.add_phase('burn1', burn1) @@ -53,8 +53,8 @@ def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): scaler=0.01, lower=-30, upper=30) # Second Phase (Coast) - coast = Phase(ode_class=FiniteBurnODE, - transcription=RungeKutta(num_segments=20, compressed=True)) + coast = dm.Phase(ode_class=FiniteBurnODE, + transcription=dm.RungeKutta(num_segments=20, compressed=True)) traj.add_phase('coast', coast) @@ -69,8 +69,8 @@ def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): # Third Phase (burn) - burn2 = Phase(ode_class=FiniteBurnODE, - transcription=GaussLobatto(num_segments=10, order=3, compressed=True)) + burn2 = dm.Phase(ode_class=FiniteBurnODE, + transcription=dm.GaussLobatto(num_segments=10, order=3, compressed=True)) traj.add_phase('burn2', burn2) @@ -100,7 +100,7 @@ def test_two_burn_orbit_raise_gl_rk_gl_constrained(self): traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) diff --git a/dymos/examples/min_time_climb/aero/aero.py b/dymos/examples/min_time_climb/aero/aero.py index fc1a91eb2..7b2b76e3c 100644 --- a/dymos/examples/min_time_climb/aero/aero.py +++ b/dymos/examples/min_time_climb/aero/aero.py @@ -2,8 +2,7 @@ import numpy as np -from openmdao.api import Group - +import openmdao.api as om from .dynamic_pressure_comp import DynamicPressureComp from .lift_drag_force_comp import LiftDragForceComp from .cd0_comp import CD0Comp @@ -14,7 +13,7 @@ from .mach_comp import MachComp -class AeroGroup(Group): +class AeroGroup(om.Group): """ The purpose of the AeroGroup is to compute the aerodynamic forces on the aircraft in the body frame. diff --git a/dymos/examples/min_time_climb/aero/cd0_comp.py b/dymos/examples/min_time_climb/aero/cd0_comp.py index f0f084830..67c24e134 100644 --- a/dymos/examples/min_time_climb/aero/cd0_comp.py +++ b/dymos/examples/min_time_climb/aero/cd0_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class CD0Comp(ExplicitComponent): +class CD0Comp(om.ExplicitComponent): """ Computes the zero-lift drag coefficient """ def initialize(self): diff --git a/dymos/examples/min_time_climb/aero/cd_comp.py b/dymos/examples/min_time_climb/aero/cd_comp.py index b9ea4fb46..3cc5667b8 100644 --- a/dymos/examples/min_time_climb/aero/cd_comp.py +++ b/dymos/examples/min_time_climb/aero/cd_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class CDComp(ExplicitComponent): +class CDComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/min_time_climb/aero/cl_comp.py b/dymos/examples/min_time_climb/aero/cl_comp.py index de956280d..37685aef7 100644 --- a/dymos/examples/min_time_climb/aero/cl_comp.py +++ b/dymos/examples/min_time_climb/aero/cl_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class CLComp(ExplicitComponent): +class CLComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/min_time_climb/aero/cla_comp.py b/dymos/examples/min_time_climb/aero/cla_comp.py index fb1464e7f..f4ba29061 100644 --- a/dymos/examples/min_time_climb/aero/cla_comp.py +++ b/dymos/examples/min_time_climb/aero/cla_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class CLaComp(ExplicitComponent): +class CLaComp(om.ExplicitComponent): """ Computes the alpha lift coefficient for induced drag """ diff --git a/dymos/examples/min_time_climb/aero/dynamic_pressure_comp.py b/dymos/examples/min_time_climb/aero/dynamic_pressure_comp.py index bce120b28..49d91bbd0 100644 --- a/dymos/examples/min_time_climb/aero/dynamic_pressure_comp.py +++ b/dymos/examples/min_time_climb/aero/dynamic_pressure_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class DynamicPressureComp(ExplicitComponent): +class DynamicPressureComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/min_time_climb/aero/kappa_comp.py b/dymos/examples/min_time_climb/aero/kappa_comp.py index 131d31293..7c8b0f957 100644 --- a/dymos/examples/min_time_climb/aero/kappa_comp.py +++ b/dymos/examples/min_time_climb/aero/kappa_comp.py @@ -1,10 +1,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class KappaComp(ExplicitComponent): - """ Computes the term kappa in the drag equation: +class KappaComp(om.ExplicitComponent): + r""" Computes the term kappa in the drag equation: .. math:: diff --git a/dymos/examples/min_time_climb/aero/lift_drag_force_comp.py b/dymos/examples/min_time_climb/aero/lift_drag_force_comp.py index 6b1f94086..8ddd55f9e 100644 --- a/dymos/examples/min_time_climb/aero/lift_drag_force_comp.py +++ b/dymos/examples/min_time_climb/aero/lift_drag_force_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class LiftDragForceComp(ExplicitComponent): +class LiftDragForceComp(om.ExplicitComponent): """ Compute the aerodynamic forces on the vehicle in the wind axis frame (lift, drag, cross) force. diff --git a/dymos/examples/min_time_climb/aero/mach_comp.py b/dymos/examples/min_time_climb/aero/mach_comp.py index 4eca0476a..39ced9ab4 100644 --- a/dymos/examples/min_time_climb/aero/mach_comp.py +++ b/dymos/examples/min_time_climb/aero/mach_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class MachComp(ExplicitComponent): +class MachComp(om.ExplicitComponent): """ Compute the Mach number based on vehicle airspeed and local speed of sound. """ diff --git a/dymos/examples/min_time_climb/aero/test/test_aerodynamics.py b/dymos/examples/min_time_climb/aero/test/test_aerodynamics.py index e0e59f438..535b0e2a0 100644 --- a/dymos/examples/min_time_climb/aero/test/test_aerodynamics.py +++ b/dymos/examples/min_time_climb/aero/test/test_aerodynamics.py @@ -6,7 +6,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from dymos.examples.min_time_climb.aero import AeroGroup @@ -14,10 +14,10 @@ class TestAeroGroup(unittest.TestCase): def setUp(self): - self.prob = Problem(model=Group()) + self.prob = om.Problem(model=om.Group()) nn = 5 - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output('rho', val=0.0001 * np.ones(nn), units='kg/m**3') ivc.add_output('v', val=0.0001 * np.ones(nn), units='m/s') diff --git a/dymos/examples/min_time_climb/aero/test/test_cd0_comp.py b/dymos/examples/min_time_climb/aero/test/test_cd0_comp.py index 7ebdac102..13011deec 100644 --- a/dymos/examples/min_time_climb/aero/test/test_cd0_comp.py +++ b/dymos/examples/min_time_climb/aero/test/test_cd0_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.examples.min_time_climb.aero.cd0_comp import CD0Comp @@ -22,9 +22,9 @@ class TestCD0Comp(unittest.TestCase): def test_visual_inspection(self): n = 500 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) @@ -48,9 +48,9 @@ def test_partials(self): n = 10 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) diff --git a/dymos/examples/min_time_climb/aero/test/test_cla_comp.py b/dymos/examples/min_time_climb/aero/test/test_cla_comp.py index 04055224c..eae638188 100644 --- a/dymos/examples/min_time_climb/aero/test/test_cla_comp.py +++ b/dymos/examples/min_time_climb/aero/test/test_cla_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.examples.min_time_climb.aero.cla_comp import CLaComp @@ -23,9 +23,9 @@ class TestCLaComp(unittest.TestCase): def test_visual_inspection(self): n = 500 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) @@ -49,9 +49,9 @@ def test_partials(self): n = 10 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) diff --git a/dymos/examples/min_time_climb/aero/test/test_kappa_comp.py b/dymos/examples/min_time_climb/aero/test/test_kappa_comp.py index 112c5a5c5..ec5953284 100644 --- a/dymos/examples/min_time_climb/aero/test/test_kappa_comp.py +++ b/dymos/examples/min_time_climb/aero/test/test_kappa_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.examples.min_time_climb.aero.kappa_comp import KappaComp @@ -14,7 +14,7 @@ import matplotlib matplotlib.use('Agg') -SHOW_PLOTS = True +SHOW_PLOTS = False class TestCLaComp(unittest.TestCase): @@ -22,9 +22,9 @@ class TestCLaComp(unittest.TestCase): def test_visual_inspection(self): n = 500 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) @@ -48,9 +48,9 @@ def test_partials(self): n = 10 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='mach', units=None, val=np.zeros(n)) diff --git a/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py b/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py index d35ba4ca4..d51c7f682 100644 --- a/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py +++ b/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py @@ -13,7 +13,7 @@ class TestMinTimeClimbForDocs(unittest.TestCase): def test_min_time_climb_for_docs_gauss_lobatto(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm @@ -23,11 +23,16 @@ def test_min_time_climb_for_docs_gauss_lobatto(self): # # Instantiate the problem and configure the optimization driver # - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + + # Note this problem can be problematic for the coloring algorithm since the DirectSolver + # introduces a some noise when solving. Here we just specify the acceptable tolerance + # and set orders=None to prevent the coloring algorithm from trying to find the tolerance + # automatically. + p.driver.declare_coloring(tol=1.0E-9, orders=None) # # Instantiate the trajectory and phase @@ -35,7 +40,7 @@ def test_min_time_climb_for_docs_gauss_lobatto(self): traj = dm.Trajectory() phase = dm.Phase(ode_class=MinTimeClimbODE, - transcription=dm.GaussLobatto(num_segments=20, compressed=True)) + transcription=dm.GaussLobatto(num_segments=15, compressed=True)) traj.add_phase('phase0', phase) @@ -83,7 +88,7 @@ def test_min_time_climb_for_docs_gauss_lobatto(self): # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup the problem and set the initial guess diff --git a/dymos/examples/min_time_climb/min_time_climb_ode.py b/dymos/examples/min_time_climb/min_time_climb_ode.py index d2f39858c..5e120baba 100644 --- a/dymos/examples/min_time_climb/min_time_climb_ode.py +++ b/dymos/examples/min_time_climb/min_time_climb_ode.py @@ -1,26 +1,24 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group - -from dymos import declare_time, declare_state, declare_parameter - +import openmdao.api as om +import dymos as dm from ...models.atmosphere import USatm1976Comp from .aero import AeroGroup from .prop import PropGroup from ...models.eom import FlightPathEOM2D -@declare_time(units='s') -@declare_state('r', units='m', rate_source='flight_dynamics.r_dot') -@declare_state('h', units='m', rate_source='flight_dynamics.h_dot', targets=['h']) -@declare_state('v', units='m/s', rate_source='flight_dynamics.v_dot', targets=['v']) -@declare_state('gam', units='rad', rate_source='flight_dynamics.gam_dot', targets=['gam']) -@declare_state('m', units='kg', rate_source='prop.m_dot', targets=['m']) -@declare_parameter('alpha', targets=['alpha'], units='rad') -@declare_parameter('Isp', targets=['Isp'], units='s') -@declare_parameter('S', targets=['S'], units='m**2') -@declare_parameter('throttle', targets=['throttle'], units=None) -class MinTimeClimbODE(Group): +@dm.declare_time(units='s') +@dm.declare_state('r', units='m', rate_source='flight_dynamics.r_dot') +@dm.declare_state('h', units='m', rate_source='flight_dynamics.h_dot', targets=['h']) +@dm.declare_state('v', units='m/s', rate_source='flight_dynamics.v_dot', targets=['v']) +@dm.declare_state('gam', units='rad', rate_source='flight_dynamics.gam_dot', targets=['gam']) +@dm.declare_state('m', units='kg', rate_source='prop.m_dot', targets=['m']) +@dm.declare_parameter('alpha', targets=['alpha'], units='rad') +@dm.declare_parameter('Isp', targets=['Isp'], units='s') +@dm.declare_parameter('S', targets=['S'], units='m**2') +@dm.declare_parameter('throttle', targets=['throttle'], units=None) +class MinTimeClimbODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/min_time_climb/prop/max_thrust_comp.py b/dymos/examples/min_time_climb/prop/max_thrust_comp.py index a35660617..6ddee1a22 100644 --- a/dymos/examples/min_time_climb/prop/max_thrust_comp.py +++ b/dymos/examples/min_time_climb/prop/max_thrust_comp.py @@ -1,6 +1,6 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import MetaModelStructuredComp +import openmdao.api as om _FT2M = 0.3048 @@ -62,7 +62,7 @@ ]).reshape((10, 10))} -class MaxThrustComp(MetaModelStructuredComp): +class MaxThrustComp(om.MetaModelStructuredComp): """ Interpolates max thrust for 2 J79 jet engines. """ def setup(self): diff --git a/dymos/examples/min_time_climb/prop/mdot_comp.py b/dymos/examples/min_time_climb/prop/mdot_comp.py index ba8dbb813..cde84dec8 100644 --- a/dymos/examples/min_time_climb/prop/mdot_comp.py +++ b/dymos/examples/min_time_climb/prop/mdot_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class MassFlowRateComp(ExplicitComponent): +class MassFlowRateComp(om.ExplicitComponent): """ Computes mass flow rate for the F4's 2 J79 engines at full throttle. """ def initialize(self): diff --git a/dymos/examples/min_time_climb/prop/prop.py b/dymos/examples/min_time_climb/prop/prop.py index 0655d82c4..bd1d3b02c 100644 --- a/dymos/examples/min_time_climb/prop/prop.py +++ b/dymos/examples/min_time_climb/prop/prop.py @@ -1,13 +1,12 @@ from __future__ import absolute_import -from openmdao.api import Group - +import openmdao.api as om from .mdot_comp import MassFlowRateComp from .max_thrust_comp import MaxThrustComp from .thrust_comp import ThrustComp -class PropGroup(Group): +class PropGroup(om.Group): """ The purpose of the PropGroup is to compute the propulsive forces on the aircraft in the body frame. diff --git a/dymos/examples/min_time_climb/prop/test/test_max_thrust_comp.py b/dymos/examples/min_time_climb/prop/test/test_max_thrust_comp.py index 9c5e2d8b3..c3d951966 100644 --- a/dymos/examples/min_time_climb/prop/test/test_max_thrust_comp.py +++ b/dymos/examples/min_time_climb/prop/test/test_max_thrust_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from dymos.examples.min_time_climb.prop.max_thrust_comp import MaxThrustComp, THR_DATA, _LBF2N @@ -15,9 +15,9 @@ class TestBrysonThrustComp(unittest.TestCase): def test_grid_values(self): n = 10 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='h', val=np.zeros(n), units='ft') ivc.add_output(name='mach', val=np.zeros(n), units=None) diff --git a/dymos/examples/min_time_climb/prop/thrust_comp.py b/dymos/examples/min_time_climb/prop/thrust_comp.py index c43d24de3..ac070a1fb 100644 --- a/dymos/examples/min_time_climb/prop/thrust_comp.py +++ b/dymos/examples/min_time_climb/prop/thrust_comp.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class ThrustComp(ExplicitComponent): +class ThrustComp(om.ExplicitComponent): """ Computes mass flow rate for the F4's 2 J79 engines at full throttle. """ def initialize(self): diff --git a/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py b/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py index 105a2e56a..e90c267a0 100644 --- a/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py +++ b/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py @@ -3,7 +3,7 @@ import unittest -from openmdao.api import Problem, Group, pyOptSparseDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.min_time_climb.min_time_climb_ode import MinTimeClimbODE @@ -13,11 +13,11 @@ def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', transcription_order=3, force_alloc_complex=False): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring(tol=1.0E-9, orders=None) if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 1000 @@ -27,7 +27,6 @@ def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', p.driver.opt_settings['Function precision'] = 1.0E-12 p.driver.opt_settings['Linesearch tolerance'] = 0.1 p.driver.opt_settings['Major step limit'] = 0.5 - # p.driver.opt_settings['Verify level'] = 3 t = {'gauss-lobatto': dm.GaussLobatto(num_segments=num_seg, order=transcription_order), 'radau-ps': dm.Radau(num_segments=num_seg, order=transcription_order), @@ -81,7 +80,7 @@ def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', # Minimize time at the end of the phase phase.add_objective('time', loc='final', ref=1.0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=force_alloc_complex) diff --git a/dymos/examples/ssto/doc/test_doc_ssto_earth.py b/dymos/examples/ssto/doc/test_doc_ssto_earth.py index f3a662be4..f14519b0e 100644 --- a/dymos/examples/ssto/doc/test_doc_ssto_earth.py +++ b/dymos/examples/ssto/doc/test_doc_ssto_earth.py @@ -12,17 +12,16 @@ class TestDocSSTOEarth(unittest.TestCase): def test_doc_ssto_earth(self): import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, DirectSolver, \ - pyOptSparseDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm # # Setup and solve the optimal control problem # - p = Problem(model=Group()) - p.driver = pyOptSparseDriver() - p.driver.options['dynamic_simul_derivs'] = True + p = om.Problem(model=om.Group()) + p.driver = om.pyOptSparseDriver() + p.driver.declare_coloring() from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE @@ -61,7 +60,7 @@ def test_doc_ssto_earth(self): phase.add_objective('time', loc='final', scaler=0.01) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() # # Setup and set initial values diff --git a/dymos/examples/ssto/doc/test_doc_ssto_linear_tangent_guidance.py b/dymos/examples/ssto/doc/test_doc_ssto_linear_tangent_guidance.py index 7e92a3a11..13244c8bf 100644 --- a/dymos/examples/ssto/doc/test_doc_ssto_linear_tangent_guidance.py +++ b/dymos/examples/ssto/doc/test_doc_ssto_linear_tangent_guidance.py @@ -13,15 +13,14 @@ class TestDocSSTOLinearTangentGuidance(unittest.TestCase): def test_doc_ssto_linear_tangent_guidance(self): import numpy as np import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ExplicitComponent, DirectSolver, \ - pyOptSparseDriver + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.plotting import plot_results g = 1.61544 # lunar gravity, m/s**2 - class LaunchVehicle2DEOM(ExplicitComponent): + class LaunchVehicle2DEOM(om.ExplicitComponent): """ Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag. """ @@ -144,7 +143,7 @@ def compute_partials(self, inputs, jacobian): jacobian['mdot', 'thrust'] = -1.0 / (g * Isp) jacobian['mdot', 'Isp'] = F_T / (g * Isp ** 2) - class LinearTangentGuidanceComp(ExplicitComponent): + class LinearTangentGuidanceComp(om.ExplicitComponent): """ Compute pitch angle from static controls governing linear expression for pitch angle tangent as function of time. """ @@ -210,7 +209,7 @@ def compute_partials(self, inputs, jacobian): @dm.declare_parameter('a_ctrl', targets=['guidance.a_ctrl'], units='1/s') @dm.declare_parameter('b_ctrl', targets=['guidance.b_ctrl'], units=None) @dm.declare_parameter('Isp', targets=['eom.Isp'], units='s') - class LaunchVehicleLinearTangentODE(Group): + class LaunchVehicleLinearTangentODE(om.Group): """ The LaunchVehicleLinearTangentODE for this case consists of a guidance component and the EOM. Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the @@ -229,10 +228,10 @@ def setup(self): # # Setup and solve the optimal control problem # - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.pyOptSparseDriver() + p.driver.declare_coloring() traj = dm.Trajectory() p.model.add_subsystem('traj', traj) @@ -261,7 +260,7 @@ def setup(self): phase.add_objective('time', index=-1, scaler=0.01) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() phase.add_timeseries_output('guidance.theta', units='deg') diff --git a/dymos/examples/ssto/doc/test_doc_ssto_polynomial_control.py b/dymos/examples/ssto/doc/test_doc_ssto_polynomial_control.py index 864b1e82a..930389e4e 100644 --- a/dymos/examples/ssto/doc/test_doc_ssto_polynomial_control.py +++ b/dymos/examples/ssto/doc/test_doc_ssto_polynomial_control.py @@ -13,14 +13,13 @@ class TestDocSSTOPolynomialControl(unittest.TestCase): def test_doc_ssto_polynomial_control(self): import numpy as np import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ExplicitComponent, DirectSolver, \ - pyOptSparseDriver, ExecComp + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm g = 1.61544 # lunar gravity, m/s**2 - class LaunchVehicle2DEOM(ExplicitComponent): + class LaunchVehicle2DEOM(om.ExplicitComponent): """ Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag. """ @@ -143,7 +142,7 @@ def compute_partials(self, inputs, jacobian): jacobian['mdot', 'thrust'] = -1.0 / (g * Isp) jacobian['mdot', 'Isp'] = F_T / (g * Isp ** 2) - class LaunchVehicleLinearTangentODE(Group): + class LaunchVehicleLinearTangentODE(om.Group): """ The LaunchVehicleLinearTangentODE for this case consists of a guidance component and the EOM. Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the @@ -157,10 +156,10 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('guidance', ExecComp('theta=arctan(tan_theta)', - theta={'value': np.ones(nn), - 'units': 'rad'}, - tan_theta={'value': np.ones(nn)})) + self.add_subsystem('guidance', om.ExecComp('theta=arctan(tan_theta)', + theta={'value': np.ones(nn), + 'units': 'rad'}, + tan_theta={'value': np.ones(nn)})) self.add_subsystem('eom', LaunchVehicle2DEOM(num_nodes=nn)) @@ -169,7 +168,7 @@ def setup(self): # # Setup and solve the optimal control problem # - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) traj = p.model.add_subsystem('traj', dm.Trajectory()) @@ -225,9 +224,9 @@ def setup(self): # # Set the optimizer # - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() # # We don't strictly need to define a linear solver here since our problem is entirely @@ -235,7 +234,7 @@ def setup(self): # failing to do so can cause incorrect derivatives if iterative processes are ever # introduced to the system. # - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) diff --git a/dymos/examples/ssto/launch_vehicle_2d_eom_comp.py b/dymos/examples/ssto/launch_vehicle_2d_eom_comp.py index 18075690b..d160139ca 100644 --- a/dymos/examples/ssto/launch_vehicle_2d_eom_comp.py +++ b/dymos/examples/ssto/launch_vehicle_2d_eom_comp.py @@ -2,13 +2,12 @@ import numpy as np -from openmdao.api import ExplicitComponent - +import openmdao.api as om _g = {'earth': 9.80665, 'moon': 1.61544} -class LaunchVehicle2DEOM(ExplicitComponent): +class LaunchVehicle2DEOM(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/examples/ssto/launch_vehicle_ode.py b/dymos/examples/ssto/launch_vehicle_ode.py index e8d7a5338..cb7b3c921 100644 --- a/dymos/examples/ssto/launch_vehicle_ode.py +++ b/dymos/examples/ssto/launch_vehicle_ode.py @@ -1,23 +1,22 @@ from __future__ import print_function, division, absolute_import -from openmdao.api import Group - -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm from .log_atmosphere_comp import LogAtmosphereComp from .launch_vehicle_2d_eom_comp import LaunchVehicle2DEOM -@declare_time(units='s') -@declare_state('x', rate_source='eom.xdot', units='m') -@declare_state('y', rate_source='eom.ydot', targets=['atmos.y'], units='m') -@declare_state('vx', rate_source='eom.vxdot', targets=['eom.vx'], units='m/s') -@declare_state('vy', rate_source='eom.vydot', targets=['eom.vy'], units='m/s') -@declare_state('m', rate_source='eom.mdot', targets=['eom.m'], units='kg') -@declare_parameter('thrust', targets=['eom.thrust'], units='N') -@declare_parameter('theta', targets=['eom.theta'], units='rad') -@declare_parameter('Isp', targets=['eom.Isp'], units='s') -class LaunchVehicleODE(Group): +@dm.declare_time(units='s') +@dm.declare_state('x', rate_source='eom.xdot', units='m') +@dm.declare_state('y', rate_source='eom.ydot', targets=['atmos.y'], units='m') +@dm.declare_state('vx', rate_source='eom.vxdot', targets=['eom.vx'], units='m/s') +@dm.declare_state('vy', rate_source='eom.vydot', targets=['eom.vy'], units='m/s') +@dm.declare_state('m', rate_source='eom.mdot', targets=['eom.m'], units='kg') +@dm.declare_parameter('thrust', targets=['eom.thrust'], units='N') +@dm.declare_parameter('theta', targets=['eom.theta'], units='rad') +@dm.declare_parameter('Isp', targets=['eom.Isp'], units='s') +class LaunchVehicleODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int, diff --git a/dymos/examples/ssto/log_atmosphere_comp.py b/dymos/examples/ssto/log_atmosphere_comp.py index 1ed85987d..4f48922ec 100644 --- a/dymos/examples/ssto/log_atmosphere_comp.py +++ b/dymos/examples/ssto/log_atmosphere_comp.py @@ -2,10 +2,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class LogAtmosphereComp(ExplicitComponent): +class LogAtmosphereComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) self.options.declare('rho_ref', types=float, default=1.225, diff --git a/dymos/examples/ssto/test/test_simulate_root_trajectory.py b/dymos/examples/ssto/test/test_simulate_root_trajectory.py index e89c74d3c..8d4cd380e 100644 --- a/dymos/examples/ssto/test/test_simulate_root_trajectory.py +++ b/dymos/examples/ssto/test/test_simulate_root_trajectory.py @@ -18,14 +18,13 @@ def test_ssto_simulate_root_trajectory(self): """ import numpy as np import matplotlib.pyplot as plt - from openmdao.api import Problem, Group, ExplicitComponent, DirectSolver, \ - pyOptSparseDriver, ExecComp + import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm g = 1.61544 # lunar gravity, m/s**2 - class LaunchVehicle2DEOM(ExplicitComponent): + class LaunchVehicle2DEOM(om.ExplicitComponent): """ Simple 2D Cartesian Equations of Motion for a launch vehicle subject to thrust and drag. """ @@ -148,7 +147,7 @@ def compute_partials(self, inputs, jacobian): jacobian['mdot', 'thrust'] = -1.0 / (g * Isp) jacobian['mdot', 'Isp'] = F_T / (g * Isp ** 2) - class LaunchVehicleLinearTangentODE(Group): + class LaunchVehicleLinearTangentODE(om.Group): """ The LaunchVehicleLinearTangentODE for this case consists of a guidance component and the EOM. Guidance is simply an OpenMDAO ExecComp which computes the arctangent of the @@ -162,10 +161,10 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('guidance', ExecComp('theta=arctan(tan_theta)', - theta={'value': np.ones(nn), - 'units': 'rad'}, - tan_theta={'value': np.ones(nn)})) + self.add_subsystem('guidance', om.ExecComp('theta=arctan(tan_theta)', + theta={'value': np.ones(nn), + 'units': 'rad'}, + tan_theta={'value': np.ones(nn)})) self.add_subsystem('eom', LaunchVehicle2DEOM(num_nodes=nn)) @@ -176,7 +175,7 @@ def setup(self): # traj = dm.Trajectory() - p = Problem(model=traj) + p = om.Problem(model=traj) phase = dm.Phase(ode_class=LaunchVehicleLinearTangentODE, transcription=dm.Radau(num_segments=20, order=3, compressed=False)) @@ -230,9 +229,9 @@ def setup(self): # # Set the optimizer # - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() # # We don't strictly need to define a linear solver here since our problem is entirely @@ -240,7 +239,7 @@ def setup(self): # failing to do so can cause incorrect derivatives if iterative processes are ever # introduced to the system. # - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) diff --git a/dymos/models/atmosphere/atmos_1976.py b/dymos/models/atmosphere/atmos_1976.py index e1043dbc6..441c13284 100644 --- a/dymos/models/atmosphere/atmos_1976.py +++ b/dymos/models/atmosphere/atmos_1976.py @@ -4,7 +4,7 @@ import numpy as np from scipy.interpolate import Akima1DInterpolator as Akima -from openmdao.api import ExplicitComponent +import openmdao.api as om """United States standard atmosphere 1976 tables, data obtained from http://www.digitaldutch.com/atmoscalc/index.htm""" @@ -133,7 +133,7 @@ drho_dh_interp_deriv = rho_interp_deriv.derivative(1) -class USatm1976Comp(ExplicitComponent): +class USatm1976Comp(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int, diff --git a/dymos/models/atmosphere/test/test_atmos.py b/dymos/models/atmosphere/test/test_atmos.py index 4c1127024..fa263afa2 100644 --- a/dymos/models/atmosphere/test/test_atmos.py +++ b/dymos/models/atmosphere/test/test_atmos.py @@ -3,14 +3,14 @@ import unittest import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.models.atmosphere.atmos_1976 import USatm1976Comp assert_almost_equal = np.testing.assert_almost_equal -SHOW_PLOTS = True +SHOW_PLOTS = False if SHOW_PLOTS: import matplotlib @@ -46,9 +46,9 @@ class TestAtmosphere(unittest.TestCase): def test_temperature_comp(self): n = reference.shape[0] - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output(name='alt_m', val=reference[:, 0], units='m') p.model.add_subsystem('atmos', subsys=USatm1976Comp(num_nodes=n)) diff --git a/dymos/models/eom/flight_path_eom_2d.py b/dymos/models/eom/flight_path_eom_2d.py index cbe89a619..85625832d 100644 --- a/dymos/models/eom/flight_path_eom_2d.py +++ b/dymos/models/eom/flight_path_eom_2d.py @@ -1,9 +1,9 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class FlightPathEOM2D(ExplicitComponent): +class FlightPathEOM2D(om.ExplicitComponent): """ Computes the position and velocity equations of motion using a 2D flight path parameterization of states per equations 4.42 - 4.46 of _[1]. @@ -159,8 +159,8 @@ def compute_partials(self, inputs, partials): if __name__ == "__main__": - from openmdao.api import Problem - p = Problem() + import openmdao.api as om + p = om.Problem() p.model = FlightPathEOM2D(num_nodes=2) p.setup(force_alloc_complex=True) diff --git a/dymos/models/eom/test/test_flight_path_eom_2d.py b/dymos/models/eom/test/test_flight_path_eom_2d.py index d6973f274..a9d7f6f01 100644 --- a/dymos/models/eom/test/test_flight_path_eom_2d.py +++ b/dymos/models/eom/test/test_flight_path_eom_2d.py @@ -5,21 +5,21 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, pyOptSparseDriver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto, declare_time, declare_state +import dymos as dm from dymos.models.eom import FlightPathEOM2D OPTIMIZER = 'SLSQP' SHOW_PLOTS = False -@declare_time(units='s') -@declare_state(name='r', rate_source='r_dot', units='m') -@declare_state(name='h', rate_source='h_dot', units='m') -@declare_state(name='gam', rate_source='gam_dot', targets='gam', units='rad') -@declare_state(name='v', rate_source='v_dot', targets='v', units='m/s') +@dm.declare_time(units='s') +@dm.declare_state(name='r', rate_source='r_dot', units='m') +@dm.declare_state(name='h', rate_source='h_dot', units='m') +@dm.declare_state(name='gam', rate_source='gam_dot', targets='gam', units='rad') +@dm.declare_state(name='v', rate_source='v_dot', targets='v', units='m/s') class _CannonballODE(FlightPathEOM2D): pass @@ -27,17 +27,17 @@ class _CannonballODE(FlightPathEOM2D): class TestFlightPathEOM2D(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - self.p.driver = pyOptSparseDriver() + self.p.driver = om.pyOptSparseDriver() self.p.driver.options['optimizer'] = OPTIMIZER if OPTIMIZER == 'SNOPT': self.p.driver.opt_settings['Major iterations limit'] = 50 self.p.driver.opt_settings['iSumm'] = 6 self.p.driver.opt_settings['Verify level'] = 3 - phase = Phase(ode_class=_CannonballODE, - transcription=GaussLobatto(num_segments=15, order=3, compressed=False)) + phase = dm.Phase(ode_class=_CannonballODE, + transcription=dm.GaussLobatto(num_segments=15, order=3, compressed=False)) self.p.model.add_subsystem('phase0', phase) diff --git a/dymos/phase/options.py b/dymos/phase/options.py index cdeb7f50d..cf898cce6 100644 --- a/dymos/phase/options.py +++ b/dymos/phase/options.py @@ -4,10 +4,10 @@ import numpy as np -from openmdao.api import OptionsDictionary +import openmdao.api as om -class ControlOptionsDictionary(OptionsDictionary): +class ControlOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary specific to controls. """ @@ -118,7 +118,7 @@ def __init__(self, read_only=False): 'to the default value of True.') -class PolynomialControlOptionsDictionary(OptionsDictionary): +class PolynomialControlOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary specific to controls. """ @@ -211,7 +211,7 @@ def __init__(self, read_only=False): 'to the default value of True.') -class DesignParameterOptionsDictionary(OptionsDictionary): +class DesignParameterOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary specific to design parameters. """ @@ -291,7 +291,7 @@ def __init__(self, read_only=False): self._dict.pop('targets') -class InputParameterOptionsDictionary(OptionsDictionary): +class InputParameterOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary specific to input parameters. """ @@ -338,7 +338,7 @@ def __init__(self, read_only=False): self._dict.pop('targets') -class StateOptionsDictionary(OptionsDictionary): +class StateOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary specific to controls. """ @@ -458,7 +458,7 @@ def __init__(self, read_only=False): 'set by a trajectory that links phases.') -class TimeOptionsDictionary(OptionsDictionary): +class TimeOptionsDictionary(om.OptionsDictionary): """ An OptionsDictionary for time options """ diff --git a/dymos/phase/phase.py b/dymos/phase/phase.py index 6d76c601a..5df8d9b21 100644 --- a/dymos/phase/phase.py +++ b/dymos/phase/phase.py @@ -1,6 +1,6 @@ from __future__ import division, print_function, absolute_import -from collections import Iterable +from collections import Iterable, Sequence import inspect import warnings @@ -10,8 +10,9 @@ from scipy import interpolate -from openmdao.api import Problem, Group, SqliteRecorder +import openmdao.api as om from openmdao.core.system import System +import dymos as dm from .options import ControlOptionsDictionary, DesignParameterOptionsDictionary, \ InputParameterOptionsDictionary, StateOptionsDictionary, TimeOptionsDictionary, \ @@ -23,7 +24,7 @@ _unspecified = object() -class Phase(Group): +class Phase(om.Group): """ The Phase object in Dymos. @@ -115,7 +116,7 @@ def set_state_options(self, name, **kwargs): Units in which the state variable is defined. Internally components may use different units for the state variable, but the IndepVarComp which provides its value will provide it in these units, and collocation defects will use these units. If units is not - specified here then the value as defined in the ODEOptions (@declare_state) will be + specified here then the value as defined in the ODEOptions (@dm.declare_state) will be used. val : ndarray The default value of the state at the state discretization nodes of the phase. @@ -619,8 +620,7 @@ def add_path_constraint(self, name, constraint_name=None, units=None, shape=None self._path_constraints[name]['indices'] = indices self._path_constraints[name]['shape'] = shape self._path_constraints[name]['linear'] = linear - self._path_constraints[name]['units'] = units\ - + self._path_constraints[name]['units'] = units self.add_timeseries_output(name, output_name=constraint_name, units=units, shape=shape) def add_timeseries_output(self, name, output_name=None, units=None, shape=(1,)): @@ -800,13 +800,13 @@ def classify_var(self, var): elif var in self.traj_parameter_options: return 'traj_parameter' elif var.endswith('_rate') and var[:-5] in self.control_options: - return 'control_rate' + return 'control_rate' elif var.endswith('_rate2') and var[:-6] in self.control_options: - return 'control_rate2' + return 'control_rate2' elif var.endswith('_rate') and var[:-5] in self.polynomial_control_options: - return 'polynomial_control_rate' + return 'polynomial_control_rate' elif var.endswith('_rate2') and var[:-6] in self.polynomial_control_options: - return 'polynomial_control_rate2' + return 'polynomial_control_rate2' else: return 'ode' @@ -925,7 +925,6 @@ def setup(self): transcription.setup_ode(self) transcription.setup_defects(self) - # self._setup_endpoint_conditions() transcription.setup_boundary_constraints('initial', self) transcription.setup_boundary_constraints('final', self) transcription.setup_path_constraints(self) @@ -1043,9 +1042,9 @@ def interpolate(self, xs=None, ys=None, nodes='all', kind='linear', axis=0): Parameters ---------- - xs : ndarray + xs : ndarray or Sequence or None Array of integration variable values. - ys : ndarray + ys : ndarray or Sequence or None Array of control/state/parameter values. nodes : str or None The name of the node subset or None (default). @@ -1082,8 +1081,6 @@ def interpolate(self, xs=None, ys=None, nodes='all', kind='linear', axis=0): gd = self.options['transcription'].grid_data node_locations = gd.node_ptau[gd.subset_node_indices[nodes]] - # if self.options['compressed']: - # node_locations = np.array(sorted(list(set(node_locations)))) # Affine transform xs into tau space [-1, 1] _xs = np.asarray(xs).ravel() m = 2.0 / (_xs[-1] - _xs[0]) @@ -1123,12 +1120,12 @@ def get_simulation_phase(self, times_per_seg=None, method='RK45', atol=1.0E-9, r t = self.options['transcription'] - sim_phase = Phase(from_phase=self, - transcription=SolveIVP(grid_data=t.grid_data, - method=method, - atol=atol, - rtol=rtol, - output_nodes_per_seg=times_per_seg)) + sim_phase = dm.Phase(from_phase=self, + transcription=SolveIVP(grid_data=t.grid_data, + method=method, + atol=atol, + rtol=rtol, + output_nodes_per_seg=times_per_seg)) return sim_phase @@ -1231,14 +1228,14 @@ def simulate(self, times_per_seg=10, method='RK45', atol=1.0E-9, rtol=1.0E-9, """ - sim_prob = Problem(model=Group()) + sim_prob = om.Problem(model=om.Group()) sim_phase = self.get_simulation_phase(times_per_seg, method=method, atol=atol, rtol=rtol) sim_prob.model.add_subsystem(self.name, sim_phase) if record_file is not None: - rec = SqliteRecorder(record_file) + rec = om.SqliteRecorder(record_file) sim_prob.model.recording_options['includes'] = ['*.timeseries.*'] sim_prob.model.add_recorder(rec) diff --git a/dymos/phase/test/test_input_parameter_connections.py b/dymos/phase/test/test_input_parameter_connections.py index f97598f70..4c4c70715 100644 --- a/dymos/phase/test/test_input_parameter_connections.py +++ b/dymos/phase/test/test_input_parameter_connections.py @@ -1,14 +1,14 @@ import numpy as np import unittest -from openmdao.api import ExplicitComponent, Group, Problem -from dymos import ODEOptions, Phase, Radau, GaussLobatto +import openmdao.api as om +import dymos as dm n_traj = 4 -class MyComp(ExplicitComponent): +class MyComp(om.ExplicitComponent): def initialize(self): self.options.declare('n_traj', types=int) @@ -28,8 +28,8 @@ def compute_partials(self, inputs, partials): pass -class MyODE(Group): - ode_options = ODEOptions() +class MyODE(om.Group): + ode_options = dm.ODEOptions() ode_options.declare_time(units='s', targets=['comp.time']) ode_options.declare_state(name='F', rate_source='comp.y') ode_options.declare_parameter(name='alpha', shape=(n_traj, 2), targets='comp.alpha', @@ -52,13 +52,13 @@ class TestStaticInputParameters(unittest.TestCase): def test_radau(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=MyODE, - ode_init_kwargs={'n_traj': n_traj}, - transcription=Radau(num_segments=25, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=MyODE, + ode_init_kwargs={'n_traj': n_traj}, + transcription=dm.Radau(num_segments=25, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) @@ -71,13 +71,13 @@ def test_radau(self): def test_gauss_lobatto(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=MyODE, - ode_init_kwargs={'n_traj': n_traj}, - transcription=GaussLobatto(num_segments=25, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=MyODE, + ode_init_kwargs={'n_traj': n_traj}, + transcription=dm.GaussLobatto(num_segments=25, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) diff --git a/dymos/phase/test/test_phase.py b/dymos/phase/test/test_phase.py index f33ca56cb..c42946372 100644 --- a/dymos/phase/test/test_phase.py +++ b/dymos/phase/test/test_phase.py @@ -3,9 +3,9 @@ import unittest import warnings -from openmdao.api import ExplicitComponent, Group, Problem, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om -from dymos import Phase, GaussLobatto, Radau +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE from openmdao.utils.assert_utils import assert_rel_error @@ -23,15 +23,15 @@ class _A(object): pass -class _B(Group): +class _B(om.Group): pass -class _C(ExplicitComponent): +class _C(om.ExplicitComponent): pass -class _D(ExplicitComponent): +class _D(om.ExplicitComponent): ode_options = None @@ -39,14 +39,14 @@ class TestPhaseBase(unittest.TestCase): def test_invalid_ode_wrong_class(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=20, order=3, compressed=True)) + phase = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -63,7 +63,7 @@ def test_invalid_ode_wrong_class(self): # Minimize time at the end of the phase phase.add_objective('g') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() with self.assertRaises(ValueError) as e: p.setup(check=True) @@ -72,14 +72,14 @@ def test_invalid_ode_wrong_class(self): def test_invalid_ode_instance(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=_A(), - transcription=GaussLobatto(num_segments=20, order=3, compressed=True)) + phase = dm.Phase(ode_class=_A(), + transcription=dm.GaussLobatto(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -96,7 +96,7 @@ def test_invalid_ode_instance(self): # Minimize time at the end of the phase phase.add_objective('g') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() with self.assertRaises(ValueError) as e: p.setup(check=True) @@ -105,8 +105,8 @@ def test_invalid_ode_instance(self): def test_add_existing_design_parameter_as_design_parameter(self): - p = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + p = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.add_design_parameter('theta') @@ -118,8 +118,8 @@ def test_add_existing_design_parameter_as_design_parameter(self): def test_add_existing_control_as_design_parameter(self): - p = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + p = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.add_control('theta') @@ -131,8 +131,8 @@ def test_add_existing_control_as_design_parameter(self): def test_add_existing_input_parameter_as_design_parameter(self): - p = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + p = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.add_input_parameter('theta') @@ -143,13 +143,13 @@ def test_add_existing_input_parameter_as_design_parameter(self): self.assertEqual(str(e.exception), expected) def test_invalid_options_nonoptimal_design_param(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=16, order=3, compressed=True)) + p.driver.declare_coloring() + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=16, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -167,7 +167,7 @@ def test_invalid_options_nonoptimal_design_param(self): # Minimize time at the end of the phase phase.add_objective('g') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') @@ -181,8 +181,8 @@ def test_invalid_options_nonoptimal_design_param(self): self.assertIn(expected, [str(ww.message) for ww in w]) def test_add_existing_design_parameter_as_input_parameter(self): - p = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=14, order=3, compressed=True)) + p = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=14, order=3, compressed=True)) p.add_design_parameter('theta') @@ -194,8 +194,8 @@ def test_add_existing_design_parameter_as_input_parameter(self): def test_add_existing_control_as_input_parameter(self): - p = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + p = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.add_control('theta') @@ -207,8 +207,8 @@ def test_add_existing_control_as_input_parameter(self): def test_add_existing_input_parameter_as_input_parameter(self): - p = Phase(ode_class=_A, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + p = dm.Phase(ode_class=_A, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.add_input_parameter('theta') @@ -219,14 +219,14 @@ def test_add_existing_input_parameter_as_input_parameter(self): self.assertEqual(str(e.exception), expected) def test_invalid_options_nonoptimal_control(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -244,7 +244,7 @@ def test_invalid_options_nonoptimal_control(self): # Minimize time at the end of the phase phase.add_objective('g') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') @@ -257,8 +257,8 @@ def test_invalid_options_nonoptimal_control(self): def test_invalid_boundary_loc(self): - p = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + p = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) with self.assertRaises(ValueError) as e: p.add_boundary_constraint('x', loc='foo') @@ -267,14 +267,14 @@ def test_invalid_boundary_loc(self): self.assertEqual(str(e.exception), expected) def test_objective_design_parameter_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -292,7 +292,7 @@ def test_objective_design_parameter_gl(self): # Minimize time at the end of the phase phase.add_objective('g') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -309,14 +309,14 @@ def test_objective_design_parameter_gl(self): assert_rel_error(self, p['phase0.t_duration'], 10, tolerance=1.0E-3) def test_objective_design_parameter_radau(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=20, order=3, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=20, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -335,7 +335,7 @@ def test_objective_design_parameter_radau(self): phase.add_objective('g') p.model.options['assembled_jac_type'] = 'csc' - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -352,16 +352,16 @@ def test_objective_design_parameter_radau(self): assert_rel_error(self, p['phase0.t_duration'], 10, tolerance=1.0E-3) def test_control_boundary_constraint_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=20, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=20, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) @@ -381,7 +381,7 @@ def test_control_boundary_constraint_gl(self): # Minimize time at the end of the phase phase.add_objective('time') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -398,16 +398,16 @@ def test_control_boundary_constraint_gl(self): assert_rel_error(self, p.get_val('phase0.timeseries.controls:theta', units='deg')[-1], 90.0) def test_control_rate_boundary_constraint_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=20, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=20, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) @@ -427,7 +427,7 @@ def test_control_rate_boundary_constraint_gl(self): # Minimize time at the end of the phase phase.add_objective('time') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -462,16 +462,16 @@ def test_control_rate_boundary_constraint_gl(self): tolerance=1.0E-6) def test_control_rate2_boundary_constraint_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=20, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=20, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) @@ -491,7 +491,7 @@ def test_control_rate2_boundary_constraint_gl(self): # Minimize time at the end of the phase phase.add_objective('time') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -524,15 +524,15 @@ def test_control_rate2_boundary_constraint_gl(self): tolerance=1.0E-6) def test_design_parameter_boundary_constraint(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=20, - order=3, - compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=20, + order=3, + compressed=True)) p.model.add_subsystem('phase0', phase) @@ -558,7 +558,7 @@ def test_design_parameter_boundary_constraint(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/phase/test/test_set_time_options.py b/dymos/phase/test/test_set_time_options.py index 5e75bdd3b..a1b8feb5c 100644 --- a/dymos/phase/test/test_set_time_options.py +++ b/dymos/phase/test/test_set_time_options.py @@ -4,12 +4,11 @@ import unittest import warnings -from openmdao.api import Problem, Group, IndepVarComp, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE -from dymos.examples.double_integrator.double_integrator_ode import DoubleIntegratorODE class TestPhaseTimeOptions(unittest.TestCase): @@ -21,13 +20,13 @@ def tearDownClass(cls): os.remove(filename) def test_fixed_time_invalid_options(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) @@ -52,7 +51,7 @@ def test_fixed_time_invalid_options(self): phase.add_boundary_constraint('time', loc='initial', equals=0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() expected_msg0 = 'Phase time options have no effect because fix_initial=True for ' \ 'phase \'phase0\': initial_bounds, initial_scaler, initial_adder, ' \ @@ -70,13 +69,13 @@ def test_fixed_time_invalid_options(self): self.assertIn(expected_msg1, [str(w.message) for w in ctx]) def test_initial_val_and_final_val_stick(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) @@ -97,7 +96,7 @@ def test_initial_val_and_final_val_stick(self): phase.add_boundary_constraint('time', loc='initial', equals=0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) assert_rel_error(self, p['phase0.t_initial'], 0.01) @@ -108,13 +107,13 @@ def test_ex_double_integrator_input_and_fixed_times_warns(self): Tests that time optimization options cause a ValueError to be raised when t_initial and t_duration are connected to external sources. """ - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) @@ -135,7 +134,7 @@ def test_ex_double_integrator_input_and_fixed_times_warns(self): phase.add_boundary_constraint('time', loc='initial', equals=0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter('always') @@ -151,13 +150,13 @@ def test_ex_double_integrator_input_and_fixed_times_warns(self): self.assertIn(expected_msg1, [str(w.message) for w in ctx]) def test_input_time_invalid_options(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) @@ -182,7 +181,7 @@ def test_input_time_invalid_options(self): phase.add_boundary_constraint('time', loc='initial', equals=0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() expected_msg0 = 'Phase time options have no effect because fix_initial=True for ' \ 'phase \'phase0\': initial_bounds, initial_scaler, initial_adder, ' \ @@ -200,13 +199,13 @@ def test_input_time_invalid_options(self): self.assertIn(expected_msg1, [str(w.message) for w in ctx]) def test_unbounded_time(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) @@ -226,7 +225,7 @@ def test_unbounded_time(self): phase.add_boundary_constraint('time', loc='initial', equals=0) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/phase/test/test_sized_input_parameters.py b/dymos/phase/test/test_sized_input_parameters.py index 630038588..ebaa2141e 100644 --- a/dymos/phase/test/test_sized_input_parameters.py +++ b/dymos/phase/test/test_sized_input_parameters.py @@ -1,11 +1,9 @@ import unittest -from openmdao.api import Group, ExecComp, Problem -from openmdao.api import DirectSolver, pyOptSparseDriver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import declare_time, declare_state, declare_parameter -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import dymos as dm from dymos.utils.lgl import lgl from dymos.models.eom import FlightPathEOM2D @@ -16,20 +14,20 @@ class TestInputParameterConnections(unittest.TestCase): def test_dynamic_input_parameter_connections_radau(self): - @declare_time(units='s') - @declare_state('v', rate_source='eom.v_dot', units='m/s') - @declare_state('h', rate_source='eom.h_dot', units='m') - @declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2)) - class TrajectoryODE(Group): + @dm.declare_time(units='s') + @dm.declare_state('v', rate_source='eom.v_dot', units='m/s') + @dm.declare_state('h', rate_source='eom.h_dot', units='m') + @dm.declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2)) + class TrajectoryODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('sum', ExecComp('m_tot = sum(m)', - m={'value': np.zeros((nn, 2, 2))}, - m_tot={'value': np.zeros(nn)})) + self.add_subsystem('sum', om.ExecComp('m_tot = sum(m)', + m={'value': np.zeros((nn, 2, 2))}, + m_tot={'value': np.zeros(nn)})) self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn)) @@ -39,17 +37,17 @@ def setup(self): num_segments = 1 transcription_order = 5 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() seg_ends, _ = lgl(num_segments + 1) - phase = Phase(ode_class=TrajectoryODE, - transcription=Radau(num_segments=num_segments, order=transcription_order, - segment_ends=seg_ends)) + phase = dm.Phase(ode_class=TrajectoryODE, + transcription=dm.Radau(num_segments=num_segments, order=transcription_order, + segment_ends=seg_ends)) p.model.add_subsystem('phase0', phase) @@ -60,7 +58,7 @@ def setup(self): phase.add_input_parameter('m', val=[[1, 2], [3, 4]], units='kg') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -78,20 +76,20 @@ def setup(self): def test_static_input_parameter_connections_radau(self): - @declare_time(units='s') - @declare_state('v', rate_source='eom.v_dot', units='m/s') - @declare_state('h', rate_source='eom.h_dot', units='m') - @declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2), dynamic=False) - class TrajectoryODE(Group): + @dm.declare_time(units='s') + @dm.declare_state('v', rate_source='eom.v_dot', units='m/s') + @dm.declare_state('h', rate_source='eom.h_dot', units='m') + @dm.declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2), dynamic=False) + class TrajectoryODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('sum', ExecComp('m_tot = sum(m)', - m={'value': np.zeros((2, 2))}, - m_tot={'value': np.zeros(nn)})) + self.add_subsystem('sum', om.ExecComp('m_tot = sum(m)', + m={'value': np.zeros((2, 2))}, + m_tot={'value': np.zeros(nn)})) self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn)) @@ -101,17 +99,18 @@ def setup(self): num_segments = 1 transcription_order = 5 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() seg_ends, _ = lgl(num_segments + 1) - phase = Phase(ode_class=TrajectoryODE, - transcription=Radau(num_segments=num_segments, order=transcription_order, - segment_ends=seg_ends)) + phase = dm.Phase(ode_class=TrajectoryODE, + transcription=dm.Radau(num_segments=num_segments, + order=transcription_order, + segment_ends=seg_ends)) p.model.add_subsystem('phase0', phase) @@ -122,7 +121,7 @@ def setup(self): phase.add_input_parameter('m', val=[[1, 2], [3, 4]], units='kg') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -139,20 +138,20 @@ def setup(self): def test_dynamic_input_parameter_connections_gl(self): - @declare_time(units='s') - @declare_state('v', rate_source='eom.v_dot', units='m/s') - @declare_state('h', rate_source='eom.h_dot', units='m') - @declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2)) - class TrajectoryODE(Group): + @dm.declare_time(units='s') + @dm.declare_state('v', rate_source='eom.v_dot', units='m/s') + @dm.declare_state('h', rate_source='eom.h_dot', units='m') + @dm.declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2)) + class TrajectoryODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('sum', ExecComp('m_tot = sum(m)', - m={'value': np.zeros((nn, 2, 2))}, - m_tot={'value': np.zeros(nn)})) + self.add_subsystem('sum', om.ExecComp('m_tot = sum(m)', + m={'value': np.zeros((nn, 2, 2))}, + m_tot={'value': np.zeros(nn)})) self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn)) @@ -162,17 +161,18 @@ def setup(self): num_segments = 1 transcription_order = 5 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() seg_ends, _ = lgl(num_segments + 1) - phase = Phase(ode_class=TrajectoryODE, - transcription=GaussLobatto(num_segments=num_segments, order=transcription_order, - segment_ends=seg_ends)) + phase = dm.Phase(ode_class=TrajectoryODE, + transcription=dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + segment_ends=seg_ends)) p.model.add_subsystem('phase0', phase) @@ -183,7 +183,7 @@ def setup(self): phase.add_input_parameter('m', val=[[1, 2], [3, 4]], units='kg') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -207,20 +207,20 @@ def setup(self): def test_static_input_parameter_connections_gl(self): - @declare_time(units='s') - @declare_state('v', rate_source='eom.v_dot', units='m/s') - @declare_state('h', rate_source='eom.h_dot', units='m') - @declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2), dynamic=False) - class TrajectoryODE(Group): + @dm.declare_time(units='s') + @dm.declare_state('v', rate_source='eom.v_dot', units='m/s') + @dm.declare_state('h', rate_source='eom.h_dot', units='m') + @dm.declare_parameter('m', targets='sum.m', units='kg', shape=(2, 2), dynamic=False) + class TrajectoryODE(om.Group): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] - self.add_subsystem('sum', ExecComp('m_tot = sum(m)', - m={'value': np.zeros((2, 2))}, - m_tot={'value': np.zeros(nn)})) + self.add_subsystem('sum', om.ExecComp('m_tot = sum(m)', + m={'value': np.zeros((2, 2))}, + m_tot={'value': np.zeros(nn)})) self.add_subsystem('eom', FlightPathEOM2D(num_nodes=nn)) @@ -230,17 +230,18 @@ def setup(self): num_segments = 1 transcription_order = 5 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = pyOptSparseDriver() + p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() seg_ends, _ = lgl(num_segments + 1) - phase = Phase(ode_class=TrajectoryODE, - transcription=GaussLobatto(num_segments=num_segments, order=transcription_order, - segment_ends=seg_ends)) + phase = dm.Phase(ode_class=TrajectoryODE, + transcription=dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + segment_ends=seg_ends)) p.model.add_subsystem('phase0', phase) @@ -251,7 +252,7 @@ def setup(self): phase.add_input_parameter('m', val=[[1, 2], [3, 4]], units='kg') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) diff --git a/dymos/phase/test/test_time_targets.py b/dymos/phase/test/test_time_targets.py index e9506c977..c582f00aa 100644 --- a/dymos/phase/test/test_time_targets.py +++ b/dymos/phase/test/test_time_targets.py @@ -1,32 +1,25 @@ from __future__ import print_function, absolute_import, division -import itertools import unittest -from numpy.testing import assert_almost_equal - import matplotlib matplotlib.use('Agg') -from parameterized import parameterized - -from openmdao.api import Problem, Group, pyOptSparseDriver, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import numpy as np -from openmdao.api import ExplicitComponent -from dymos import declare_time, declare_state, declare_parameter, Phase, \ - GaussLobatto, Radau, RungeKutta +import dymos as dm -@declare_time(units='s', time_phase_targets=['time_phase'], t_duration_targets=['t_duration'], - t_initial_targets=['t_initial'], targets=['time']) -@declare_state('x', rate_source='xdot', units='m') -@declare_state('y', rate_source='ydot', units='m') -@declare_state('v', rate_source='vdot', targets=['v'], units='m/s') -@declare_parameter('theta', targets=['theta'], units='rad') -@declare_parameter('g', units='m/s**2', targets=['g']) -class _BrachistochroneTestODE(ExplicitComponent): +@dm.declare_time(units='s', time_phase_targets=['time_phase'], t_duration_targets=['t_duration'], + t_initial_targets=['t_initial'], targets=['time']) +@dm.declare_state('x', rate_source='xdot', units='m') +@dm.declare_state('y', rate_source='ydot', units='m') +@dm.declare_state('v', rate_source='vdot', targets=['v'], units='m/s') +@dm.declare_parameter('theta', targets=['theta'], units='rad') +@dm.declare_parameter('g', units='m/s**2', targets=['g']) +class _BrachistochroneTestODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) @@ -108,18 +101,18 @@ def compute_partials(self, inputs, jacobian): class TestPhaseTimeTargets(unittest.TestCase): def _make_problem(self, transcription, num_seg, transcription_order=3): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() + p.driver = om.ScipyOptimizeDriver() # Compute sparsity/coloring when run_driver is called - p.driver.options['dynamic_simul_derivs'] = True + p.driver.declare_coloring() - t = {'gauss-lobatto': GaussLobatto(num_segments=num_seg, order=transcription_order), - 'radau-ps': Radau(num_segments=num_seg, order=transcription_order), - 'runge-kutta': RungeKutta(num_segments=num_seg)} + t = {'gauss-lobatto': dm.GaussLobatto(num_segments=num_seg, order=transcription_order), + 'radau-ps': dm.Radau(num_segments=num_seg, order=transcription_order), + 'runge-kutta': dm.RungeKutta(num_segments=num_seg)} - phase = Phase(ode_class=_BrachistochroneTestODE, transcription=t[transcription]) + phase = dm.Phase(ode_class=_BrachistochroneTestODE, transcription=t[transcription]) p.model.add_subsystem('phase0', phase) @@ -139,7 +132,7 @@ def _make_problem(self, transcription, num_seg, transcription_order=3): # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup() diff --git a/dymos/phase/test/test_timeseries.py b/dymos/phase/test/test_timeseries.py index c908994cf..fbac35c38 100644 --- a/dymos/phase/test/test_timeseries.py +++ b/dymos/phase/test/test_timeseries.py @@ -7,25 +7,25 @@ import numpy as np -from openmdao.api import Problem, Group, pyOptSparseDriver, ScipyOptimizeDriver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, GaussLobatto, Radau, RungeKutta +import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE -SHOW_PLOTS = True +SHOW_PLOTS = False class TestTimeseriesOutput(unittest.TestCase): def test_timeseries_gl(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=GaussLobatto(num_segments=8, order=3, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.GaussLobatto(num_segments=8, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -43,7 +43,7 @@ def test_timeseries_gl(self): # Minimize time at the end of the phase phase.add_objective('time_phase', loc='final', scaler=10) - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 @@ -94,13 +94,13 @@ def test_timeseries_gl(self): p.get_val('phase0.timeseries.design_parameters:{0}'.format(dp))[i]) def test_timeseries_radau(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - p.driver = ScipyOptimizeDriver() - p.driver.options['dynamic_simul_derivs'] = True + p.driver = om.ScipyOptimizeDriver() + p.driver.declare_coloring() - phase = Phase(ode_class=BrachistochroneODE, - transcription=Radau(num_segments=8, order=3, compressed=True)) + phase = dm.Phase(ode_class=BrachistochroneODE, + transcription=dm.Radau(num_segments=8, order=3, compressed=True)) p.model.add_subsystem('phase0', phase) @@ -119,7 +119,7 @@ def test_timeseries_radau(self): phase.add_objective('time_phase', loc='final', scaler=10) p.model.options['assembled_jac_type'] = 'csc' - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 0.0 diff --git a/dymos/test/test_ode_options.py b/dymos/test/test_ode_options.py index 611bd30e7..ac506fbbc 100644 --- a/dymos/test/test_ode_options.py +++ b/dymos/test/test_ode_options.py @@ -1,14 +1,12 @@ from __future__ import print_function, division, absolute_import -import numpy as np import unittest -from dymos import declare_time, declare_state, declare_parameter +import openmdao.api as om +import dymos as dm -from openmdao.api import ExplicitComponent - -class _BrachistochroneODE(ExplicitComponent): +class _BrachistochroneODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) @@ -18,7 +16,7 @@ class TestODEOptions(unittest.TestCase): def test_declare_time(self): - @declare_time(units='s', targets=['foo', 'bar']) + @dm.declare_time(units='s', targets=['foo', 'bar']) class B(_BrachistochroneODE): pass @@ -28,9 +26,9 @@ class B(_BrachistochroneODE): def test_declare_state(self): - @declare_state('x', rate_source='xdot', units='m') - @declare_state('y', rate_source='ydot', units='m') - @declare_state('v', rate_source='vdot', targets='v', units='m/s') + @dm.declare_state('x', rate_source='xdot', units='m') + @dm.declare_state('y', rate_source='ydot', units='m') + @dm.declare_state('v', rate_source='vdot', targets='v', units='m/s') class B(_BrachistochroneODE): pass @@ -45,17 +43,17 @@ class B(_BrachistochroneODE): def test_invalid_state_name(self): with self.assertRaises(NameError) as e: - @declare_state('x', rate_source='xdot', units='m') - @declare_state('foo.x', rate_source='foox_dot', units='m') - @declare_state('v', rate_source='vdot', targets='v', units='m/s') + @dm.declare_state('x', rate_source='xdot', units='m') + @dm.declare_state('foo.x', rate_source='foox_dot', units='m') + @dm.declare_state('v', rate_source='vdot', targets='v', units='m/s') class B(_BrachistochroneODE): pass self.assertEqual(str(e.exception), "'foo.x' is not a valid OpenMDAO variable name.") def test_declare_parameters(self): - @declare_parameter('theta', targets='theta', units='rad') - @declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) + @dm.declare_parameter('theta', targets='theta', units='rad') + @dm.declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) class B(_BrachistochroneODE): pass @@ -65,20 +63,20 @@ class B(_BrachistochroneODE): def test_invalid_parameter_name(self): with self.assertRaises(NameError) as e: - @declare_parameter('theta', targets='theta', units='rad') - @declare_parameter('g?', units='m/s**2', targets=['g'], dynamic=False) + @dm.declare_parameter('theta', targets='theta', units='rad') + @dm.declare_parameter('g?', units='m/s**2', targets=['g'], dynamic=False) class B(_BrachistochroneODE): pass self.assertEqual(str(e.exception), "'g?' is not a valid OpenMDAO variable name.") def test_all(self): - @declare_time(units='s', targets=['foo', 'bar']) - @declare_state('x', rate_source='xdot', units='m') - @declare_state('y', rate_source='ydot', units='m') - @declare_state('v', rate_source='vdot', targets=['v'], units='m/s') - @declare_parameter('theta', targets=['theta'], units='rad') - @declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) + @dm.declare_time(units='s', targets=['foo', 'bar']) + @dm.declare_state('x', rate_source='xdot', units='m') + @dm.declare_state('y', rate_source='ydot', units='m') + @dm.declare_state('v', rate_source='vdot', targets=['v'], units='m/s') + @dm.declare_parameter('theta', targets=['theta'], units='rad') + @dm.declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) class B(_BrachistochroneODE): pass @@ -97,12 +95,12 @@ class B(_BrachistochroneODE): def test_str(self): - @declare_time(units='s', targets=['foo', 'bar']) - @declare_state('x', rate_source='xdot', units='m') - @declare_state('y', rate_source='ydot', units='m') - @declare_state('v', rate_source='vdot', targets=['v'], units='m/s') - @declare_parameter('theta', targets=['theta'], units='rad') - @declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) + @dm.declare_time(units='s', targets=['foo', 'bar']) + @dm.declare_state('x', rate_source='xdot', units='m') + @dm.declare_state('y', rate_source='ydot', units='m') + @dm.declare_state('v', rate_source='vdot', targets=['v'], units='m/s') + @dm.declare_parameter('theta', targets=['theta'], units='rad') + @dm.declare_parameter('g', units='m/s**2', targets=['g'], dynamic=False) class B(_BrachistochroneODE): pass diff --git a/dymos/trajectory/test/test_trajectory.py b/dymos/trajectory/test/test_trajectory.py index 67923db4d..9f1779ca8 100644 --- a/dymos/trajectory/test/test_trajectory.py +++ b/dymos/trajectory/test/test_trajectory.py @@ -5,10 +5,10 @@ import numpy as np -from openmdao.api import Problem, DirectSolver, SqliteRecorder, Group +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos import Phase, Trajectory, GaussLobatto +import dymos as dm from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE @@ -16,22 +16,22 @@ class TestTrajectory(unittest.TestCase): @classmethod def tearDownClass(cls): - for filename in ['test_trajectory_rec.db', 'coloring.json']: + for filename in ['test_trajectory_rec.db', 'total_coloring.pkl']: if os.path.exists(filename): os.remove(filename) @classmethod def setUpClass(cls): - cls.traj = Trajectory() - p = cls.p = Problem(model=cls.traj) + cls.traj = dm.Trajectory() + p = cls.p = om.Problem(model=cls.traj) # Since we're only testing features like get_values that don't rely on a converged # solution, no driver is attached. We'll just invoke run_model. # First Phase (burn) - burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=4, order=3)) + burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=4, order=3)) cls.traj.add_phase('burn1', burn1) @@ -47,7 +47,7 @@ def setUpClass(cls): # Second Phase (Coast) - coast = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3)) + coast = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) cls.traj.add_phase('coast', coast) @@ -63,7 +63,7 @@ def setUpClass(cls): # Third Phase (burn) - burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=3, order=3)) + burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=3, order=3)) cls.traj.add_phase('burn2', burn2) @@ -86,9 +86,9 @@ def setUpClass(cls): cls.traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.model.add_recorder(SqliteRecorder('test_trajectory_rec.db')) + p.model.add_recorder(om.SqliteRecorder('test_trajectory_rec.db')) p.setup(check=True) @@ -145,15 +145,15 @@ def test_linked_phases(self): class TestInvalidLinkages(unittest.TestCase): def test_invalid_linkage_variable(self): - traj = Trajectory() - p = Problem(model=traj) + traj = dm.Trajectory() + p = om.Problem(model=traj) # Since we're only testing features like get_values that don't rely on a converged # solution, no driver is attached. We'll just invoke run_model. # First Phase (burn) - burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=4, order=3)) + burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=4, order=3)) traj.add_phase('burn1', burn1) @@ -169,7 +169,7 @@ def test_invalid_linkage_variable(self): # Second Phase (Coast) - coast = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3)) + coast = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) traj.add_phase('coast', coast) @@ -185,7 +185,7 @@ def test_invalid_linkage_variable(self): # Third Phase (burn) - burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=3, order=3)) + burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=3, order=3)) traj.add_phase('burn2', burn2) @@ -209,9 +209,9 @@ def test_invalid_linkage_variable(self): traj.link_phases(phases=['burn1', 'burn2'], vars=['u1', 'bar']) # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.model.add_recorder(SqliteRecorder('test_trajectory_rec.db')) + p.model.add_recorder(om.SqliteRecorder('test_trajectory_rec.db')) with self.assertRaises(ValueError) as e: p.setup(check=True) @@ -221,16 +221,16 @@ def test_invalid_linkage_variable(self): 'or parameters may be linked via link_phases.') def test_invalid_linkage_phase(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - traj = Trajectory() + traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # Since we're only testing features like get_values that don't rely on a converged # solution, no driver is attached. We'll just invoke run_model. # First Phase (burn) - burn1 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=4, order=3)) + burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=4, order=3)) traj.add_phase('burn1', burn1) @@ -246,7 +246,7 @@ def test_invalid_linkage_phase(self): # Second Phase (Coast) - coast = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=10, order=3)) + coast = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=10, order=3)) traj.add_phase('coast', coast) @@ -262,7 +262,7 @@ def test_invalid_linkage_phase(self): # Third Phase (burn) - burn2 = Phase(ode_class=FiniteBurnODE, transcription=GaussLobatto(num_segments=3, order=3)) + burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=3, order=3)) traj.add_phase('burn2', burn2) @@ -286,9 +286,9 @@ def test_invalid_linkage_phase(self): traj.link_phases(phases=['burn1', 'foo'], vars=['u1', 'u1']) # Finish Problem Setup - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() - p.model.add_recorder(SqliteRecorder('test_trajectory_rec.db')) + p.model.add_recorder(om.SqliteRecorder('test_trajectory_rec.db')) with self.assertRaises(ValueError) as e: p.setup(check=True) diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 429a8f3d8..81c45d526 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -11,8 +11,7 @@ import numpy as np -from openmdao.api import Group, ParallelGroup, IndepVarComp, DirectSolver, Problem -from openmdao.api import SqliteRecorder +import openmdao.api as om from ..utils.constants import INF_BOUND @@ -21,7 +20,7 @@ TrajInputParameterOptionsDictionary -class Trajectory(Group): +class Trajectory(om.Group): """ A Trajectory object serves as a container for one or more Phases, as well as the linkage conditions between phases. @@ -182,7 +181,7 @@ def _setup_design_parameters(self): on transcription. """ if self.design_parameter_options: - indep = self.add_subsystem('design_params', subsys=IndepVarComp(), + indep = self.add_subsystem('design_params', subsys=om.IndepVarComp(), promotes_outputs=['*']) for name, options in iteritems(self.design_parameter_options): @@ -381,13 +380,13 @@ def setup(self): if self.input_parameter_options: self._setup_input_parameters() - phases_group = self.add_subsystem('phases', subsys=ParallelGroup(), promotes_inputs=['*'], + phases_group = self.add_subsystem('phases', subsys=om.ParallelGroup(), promotes_inputs=['*'], promotes_outputs=['*']) for name, phs in iteritems(self._phases): g = phases_group.add_subsystem(name, phs, **self._phase_add_kwargs[name]) # DirectSolvers were moved down into the phases for use with MPI - g.linear_solver = DirectSolver() + g.linear_solver = om.DirectSolver() phs.finalize_variables() if self._linkages: @@ -541,7 +540,7 @@ def simulate(self, times_per_seg=10, method='RK45', atol=1.0E-9, rtol=1.0E-9, re sim_traj.design_parameter_options.update(self.design_parameter_options) sim_traj.input_parameter_options.update(self.input_parameter_options) - sim_prob = Problem(model=Group()) + sim_prob = om.Problem(model=om.Group()) if self.name: sim_prob.model.add_subsystem(self.name, sim_traj) @@ -549,7 +548,7 @@ def simulate(self, times_per_seg=10, method='RK45', atol=1.0E-9, rtol=1.0E-9, re sim_prob.model.add_subsystem('sim_traj', sim_traj) if record_file is not None: - rec = SqliteRecorder(record_file) + rec = om.SqliteRecorder(record_file) sim_prob.model.recording_options['includes'] = ['*.timeseries.*'] sim_prob.model.add_recorder(rec) diff --git a/dymos/transcriptions/common/boundary_constraint_comp.py b/dymos/transcriptions/common/boundary_constraint_comp.py index 3fce34f84..11424167e 100644 --- a/dymos/transcriptions/common/boundary_constraint_comp.py +++ b/dymos/transcriptions/common/boundary_constraint_comp.py @@ -3,12 +3,12 @@ import numpy as np from six import iteritems -from openmdao.api import ExplicitComponent +import openmdao.api as om from dymos.utils.constants import INF_BOUND -class BoundaryConstraintComp(ExplicitComponent): +class BoundaryConstraintComp(om.ExplicitComponent): def initialize(self): self.options.declare('loc', values=('initial', 'final'), diff --git a/dymos/transcriptions/common/continuity_comp.py b/dymos/transcriptions/common/continuity_comp.py index ac64cedc7..fa3d6427c 100644 --- a/dymos/transcriptions/common/continuity_comp.py +++ b/dymos/transcriptions/common/continuity_comp.py @@ -1,14 +1,14 @@ from __future__ import print_function, division import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from six import iteritems, string_types from ..grid_data import GridData from ...utils.misc import get_rate_units -class ContinuityCompBase(ExplicitComponent): +class ContinuityCompBase(om.ExplicitComponent): """ ContinuityComp defines constraints to ensure continuity between adjacent segments. """ diff --git a/dymos/transcriptions/common/control_group.py b/dymos/transcriptions/common/control_group.py index 7f4bea60e..8d2f96aac 100644 --- a/dymos/transcriptions/common/control_group.py +++ b/dymos/transcriptions/common/control_group.py @@ -4,14 +4,14 @@ import numpy as np -from openmdao.api import ExplicitComponent, Group, IndepVarComp +import openmdao.api as om from ..grid_data import GridData from ...utils.misc import get_rate_units, CoerceDesvar from ...utils.constants import INF_BOUND -class ControlInterpComp(ExplicitComponent): +class ControlInterpComp(om.ExplicitComponent): """ Compute the approximated control values and rates given the values of a control at all nodes, given values at the control discretization nodes. @@ -231,7 +231,7 @@ def compute_partials(self, inputs, partials): (self.rate2_jacs[name] / dt_dstau_x_size ** 2)[r_nz, c_nz] -class ControlGroup(Group): +class ControlGroup(om.Group): def initialize(self): self.options.declare('control_options', types=dict, @@ -242,7 +242,7 @@ def initialize(self): def setup(self): - ivc = IndepVarComp() + ivc = om.IndepVarComp() # opts = self.options gd = self.options['grid_data'] @@ -255,7 +255,7 @@ def setup(self): opt_controls = [name for (name, opts) in iteritems(control_options) if opts['opt']] if len(opt_controls) > 0: - ivc = self.add_subsystem('indep_controls', subsys=IndepVarComp(), + ivc = self.add_subsystem('indep_controls', subsys=om.IndepVarComp(), promotes_outputs=['*']) self.add_subsystem( diff --git a/dymos/transcriptions/common/endpoint_conditions_comp.py b/dymos/transcriptions/common/endpoint_conditions_comp.py index 54dcd799d..2c16df2f1 100644 --- a/dymos/transcriptions/common/endpoint_conditions_comp.py +++ b/dymos/transcriptions/common/endpoint_conditions_comp.py @@ -2,10 +2,10 @@ from six import iteritems import numpy as np -from openmdao.api import ExplicitComponent, OptionsDictionary +import openmdao.api as om -class EndpointConditionsComp(ExplicitComponent): +class EndpointConditionsComp(om.ExplicitComponent): """ Provides values of time, states, and controls at the start/end of each phase to make it simpler to link phases together. @@ -14,7 +14,7 @@ def initialize(self): self.options.declare('loc', values=('initial', 'final'), desc='Whether the instance of the component provides conditions at ' 'the start (initial) or end (final) of the phase') - self.options.declare('time_options', types=OptionsDictionary) + self.options.declare('time_options', types=om.OptionsDictionary) self.options.declare('state_options', types=dict) self.options.declare('control_options', types=dict) diff --git a/dymos/transcriptions/common/input_parameter_comp.py b/dymos/transcriptions/common/input_parameter_comp.py index 715b65c91..e9cfb02c0 100644 --- a/dymos/transcriptions/common/input_parameter_comp.py +++ b/dymos/transcriptions/common/input_parameter_comp.py @@ -3,10 +3,10 @@ import numpy as np from six import iteritems -from openmdao.api import ExplicitComponent +import openmdao.api as om -class InputParameterComp(ExplicitComponent): +class InputParameterComp(om.ExplicitComponent): """ The InputParameterComp handles input parameters for phases and trajectories. diff --git a/dymos/transcriptions/common/path_constraint_comp.py b/dymos/transcriptions/common/path_constraint_comp.py index b45823d00..6ca4e6f2a 100644 --- a/dymos/transcriptions/common/path_constraint_comp.py +++ b/dymos/transcriptions/common/path_constraint_comp.py @@ -1,13 +1,13 @@ from __future__ import division, print_function import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from dymos.transcriptions.grid_data import GridData from dymos.utils.constants import INF_BOUND -class PathConstraintCompBase(ExplicitComponent): +class PathConstraintCompBase(om.ExplicitComponent): def initialize(self): self._path_constraints = [] diff --git a/dymos/transcriptions/common/phase_linkage_comp.py b/dymos/transcriptions/common/phase_linkage_comp.py index ccf1537b6..54438e0d3 100644 --- a/dymos/transcriptions/common/phase_linkage_comp.py +++ b/dymos/transcriptions/common/phase_linkage_comp.py @@ -2,10 +2,10 @@ from six import string_types import numpy as np -from openmdao.api import ExplicitComponent, OptionsDictionary +import openmdao.api as om -class PhaseLinkageComp(ExplicitComponent): +class PhaseLinkageComp(om.ExplicitComponent): """ Provides a 'linkage' capability between two phases to provide continuity in states, time, and other variables between two @@ -118,7 +118,7 @@ def add_linkage(self, name, vars, shape=(1,), equals=None, lower=None, upper=Non for var in _vars: - lnk = OptionsDictionary() + lnk = om.OptionsDictionary() lnk.declare('name', types=(string_types,)) lnk.declare('equals', types=(float, np.ndarray), allow_none=True) diff --git a/dymos/transcriptions/common/polynomial_control_group.py b/dymos/transcriptions/common/polynomial_control_group.py index 25af9f98b..17063301a 100644 --- a/dymos/transcriptions/common/polynomial_control_group.py +++ b/dymos/transcriptions/common/polynomial_control_group.py @@ -3,7 +3,7 @@ import numpy as np from six import iteritems, string_types -from openmdao.api import Group, ExplicitComponent, IndepVarComp +import openmdao.api as om from ..grid_data import GridData from ...utils.lgl import lgl @@ -12,7 +12,7 @@ from ...utils.constants import INF_BOUND -class LGLPolynomialControlComp(ExplicitComponent): +class LGLPolynomialControlComp(om.ExplicitComponent): """ Component which interpolates controls as a single polynomial across the entire phase. """ @@ -180,7 +180,7 @@ def compute_partials(self, inputs, partials): (self.rate2_jacs[name] / (0.5 * t_duration_x_size) ** 2)[r_nz, c_nz] -class PolynomialControlGroup(Group): +class PolynomialControlGroup(om.Group): def initialize(self): self.options.declare('polynomial_control_options', types=dict, @@ -191,7 +191,7 @@ def initialize(self): def setup(self): - ivc = IndepVarComp() + ivc = om.IndepVarComp() opts = self.options diff --git a/dymos/transcriptions/common/test/test_boundary_constraint_comp.py b/dymos/transcriptions/common/test/test_boundary_constraint_comp.py index 4e83adc67..0776c81c0 100644 --- a/dymos/transcriptions/common/test/test_boundary_constraint_comp.py +++ b/dymos/transcriptions/common/test/test_boundary_constraint_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.common.boundary_constraint_comp import BoundaryConstraintComp @@ -15,9 +15,9 @@ class TestInitialScalarBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('x', val=np.arange(100)) self.p.model.add_design_var('x', lower=0, upper=100) @@ -44,9 +44,9 @@ class TestFinalScalarBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('x', val=np.arange(100)) self.p.model.add_design_var('x', lower=0, upper=100) @@ -73,9 +73,9 @@ class TestVectorInitialBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('pos', val=np.zeros((100, 3))) self.p.model.add_design_var('pos', lower=0, upper=100) @@ -109,9 +109,9 @@ class TestVectorFinalBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('pos', val=np.zeros((100, 3))) self.p.model.add_design_var('pos', lower=0, upper=100) @@ -146,9 +146,9 @@ class TestMatrixInitialBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('M', val=np.zeros((100, 3, 3))) self.p.model.add_design_var('M', lower=0, upper=100) @@ -191,9 +191,9 @@ class TestMatrixFinalBoundaryValue(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('M', val=np.zeros((100, 3, 3))) self.p.model.add_design_var('M', lower=0, upper=100) @@ -236,9 +236,9 @@ class TestMultipleConstraints(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivp.add_output('M', val=np.zeros((100, 3, 3))) ivp.add_output('pos', val=np.zeros((100, 3))) diff --git a/dymos/transcriptions/common/test/test_continuity_comp.py b/dymos/transcriptions/common/test/test_continuity_comp.py index 12f5b0d11..216e4684b 100644 --- a/dymos/transcriptions/common/test/test_continuity_comp.py +++ b/dymos/transcriptions/common/test/test_continuity_comp.py @@ -7,7 +7,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_rel_error from dymos.transcriptions.grid_data import GridData @@ -34,9 +34,9 @@ def test_continuity_comp(self, transcription='gauss-lobatto', compressed='compre transcription=transcription, compressed=compressed == 'compressed') - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) nn = gd.subset_num_nodes['all'] diff --git a/dymos/transcriptions/common/test/test_control_interp_comp.py b/dymos/transcriptions/common/test/test_control_interp_comp.py index eaecb3807..fde2bb172 100644 --- a/dymos/transcriptions/common/test/test_control_interp_comp.py +++ b/dymos/transcriptions/common/test/test_control_interp_comp.py @@ -7,7 +7,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.common import TimeComp @@ -83,12 +83,12 @@ def test_control_interp_scalar(self, transcription='gauss-lobatto', compressed=T transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (1,), 'dynamic': True}, 'b': {'units': 'm', 'shape': (1,), 'dynamic': True}} - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', @@ -174,12 +174,12 @@ def test_control_interp_scalar_rk4(self, compressed=True): transcription_order='RK4', compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (1,), 'dynamic': True}, 'b': {'units': 'm', 'shape': (1,), 'dynamic': True}} - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', @@ -258,11 +258,11 @@ def test_control_interp_vector(self, transcription='gauss-lobatto', compressed=T transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (3,), 'dynamic': True}} - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', val=np.zeros((gd.subset_num_nodes['control_input'], 3)), @@ -360,11 +360,11 @@ def test_control_interp_matrix_3x1(self, transcription='gauss-lobatto', compress transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (3, 1), 'dynamic': True}} - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', val=np.zeros((gd.subset_num_nodes['control_input'], 3, 1)), @@ -461,11 +461,11 @@ def test_control_interp_matrix_2x2(self, transcription='gauss-lobatto', compress transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': {'units': 'm', 'shape': (2, 2), 'dynamic': True}} - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('controls:a', val=np.zeros((gd.subset_num_nodes['control_input'], 2, 2)), diff --git a/dymos/transcriptions/common/test/test_endpoint_conditions_comp.py b/dymos/transcriptions/common/test/test_endpoint_conditions_comp.py index 62a6719e9..14adccb96 100644 --- a/dymos/transcriptions/common/test/test_endpoint_conditions_comp.py +++ b/dymos/transcriptions/common/test/test_endpoint_conditions_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.phase.options import TimeOptionsDictionary, StateOptionsDictionary, \ @@ -18,7 +18,7 @@ class TestEndpointConditionComp(unittest.TestCase): def test_scalar_state_and_control(self): n = 101 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) time_options = TimeOptionsDictionary() time_options['units'] = 's' @@ -33,7 +33,7 @@ def test_scalar_state_and_control(self): control_options['theta']['units'] = 'rad' control_options['theta']['shape'] = (1,) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='phase:time', val=np.zeros(n), units='s') ivc.add_output(name='phase:initial_jump:time', val=100.0 * np.ones(1), units='s') ivc.add_output(name='phase:final_jump:time', val=1.0 * np.ones(1), units='s') @@ -96,7 +96,7 @@ def test_scalar_state_and_control(self): p.model.connect('phase:initial_jump:theta', 'initial_conditions.initial_jump:theta') p.model.connect('phase:final_jump:theta', 'final_conditions.final_jump:theta') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.setup(force_alloc_complex=True) @@ -147,7 +147,7 @@ def test_scalar_state_and_control(self): def test_vector_state_and_control(self): n = 101 - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) time_options = TimeOptionsDictionary() time_options['units'] = 's' @@ -162,7 +162,7 @@ def test_vector_state_and_control(self): control_options['cmd']['units'] = 'rad' control_options['cmd']['shape'] = (3,) - ivc = IndepVarComp() + ivc = om.IndepVarComp() ivc.add_output(name='phase:time', val=np.zeros(n), units='s') ivc.add_output(name='phase:initial_jump:time', val=100.0 * np.ones(1), units='s') @@ -221,7 +221,7 @@ def test_vector_state_and_control(self): p.model.connect('phase:initial_jump:cmd', 'initial_conditions.initial_jump:cmd') p.model.connect('phase:final_jump:cmd', 'final_conditions.final_jump:cmd') - p.model.linear_solver = DirectSolver() + p.model.linear_solver = om.DirectSolver() p.model.options['assembled_jac_type'] = 'csc' p.setup(force_alloc_complex=True) diff --git a/dymos/transcriptions/common/test/test_path_constraint_comp.py b/dymos/transcriptions/common/test/test_path_constraint_comp.py index fc8bd8ced..297d1fd21 100644 --- a/dymos/transcriptions/common/test/test_path_constraint_comp.py +++ b/dymos/transcriptions/common/test/test_path_constraint_comp.py @@ -4,7 +4,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.common import GaussLobattoPathConstraintComp, RadauPathConstraintComp @@ -27,7 +27,7 @@ def setUp(self): ncn = gd.subset_num_nodes['col'] nn = ndn + ncn - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) controls = {'a': ControlOptionsDictionary(), 'b': ControlOptionsDictionary(), @@ -38,7 +38,7 @@ def setUp(self): controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) - ivc = IndepVarComp() + ivc = om.IndepVarComp() self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('a_disc', val=np.zeros((ndn, 1)), units='m') @@ -148,7 +148,7 @@ def setUp(self): ndn = gd.subset_num_nodes['state_disc'] - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) controls = {'a': ControlOptionsDictionary(), 'b': ControlOptionsDictionary(), @@ -159,7 +159,7 @@ def setUp(self): controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) - ivc = IndepVarComp() + ivc = om.IndepVarComp() self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('a_disc', val=np.zeros((ndn, 1)), units='m') diff --git a/dymos/transcriptions/common/test/test_phase_linkage_comp.py b/dymos/transcriptions/common/test/test_phase_linkage_comp.py index d8d869757..e66452c29 100644 --- a/dymos/transcriptions/common/test/test_phase_linkage_comp.py +++ b/dymos/transcriptions/common/test/test_phase_linkage_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.common import PhaseLinkageComp @@ -15,9 +15,9 @@ class TestPhaseLinkageComp(unittest.TestCase): def setUp(self): - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) - ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivp = self.p.model.add_subsystem('ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ndn = 20 nn = 30 diff --git a/dymos/transcriptions/common/test/test_polynomial_control_group.py b/dymos/transcriptions/common/test/test_polynomial_control_group.py index 9ab4e9549..ae5e55615 100644 --- a/dymos/transcriptions/common/test/test_polynomial_control_group.py +++ b/dymos/transcriptions/common/test/test_polynomial_control_group.py @@ -4,7 +4,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.common import TimeComp, PolynomialControlGroup @@ -77,7 +77,7 @@ def test_polynomial_control_group_scalar_gl(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary(), 'b': PolynomialControlOptionsDictionary()} @@ -90,7 +90,7 @@ def test_polynomial_control_group_scalar_gl(self): controls['b']['order'] = 3 controls['b']['opt'] = True - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -171,7 +171,7 @@ def test_polynomial_control_group_scalar_radau(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary(), 'b': PolynomialControlOptionsDictionary()} @@ -184,7 +184,7 @@ def test_polynomial_control_group_scalar_radau(self): controls['b']['order'] = 3 controls['b']['opt'] = True - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -267,7 +267,7 @@ def test_polynomial_control_group_scalar_rungekutta(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary(), 'b': PolynomialControlOptionsDictionary()} @@ -280,7 +280,7 @@ def test_polynomial_control_group_scalar_rungekutta(self): controls['b']['order'] = 3 controls['b']['opt'] = True - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -361,7 +361,7 @@ def test_polynomial_control_group_vector_gl(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -370,7 +370,7 @@ def test_polynomial_control_group_vector_gl(self): controls['a']['opt'] = True controls['a']['shape'] = (3,) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -467,7 +467,7 @@ def test_polynomial_control_group_vector_radau(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -476,7 +476,7 @@ def test_polynomial_control_group_vector_radau(self): controls['a']['opt'] = True controls['a']['shape'] = (3,) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -573,7 +573,7 @@ def test_polynomial_control_group_vector_rungekutta(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -582,7 +582,7 @@ def test_polynomial_control_group_vector_rungekutta(self): controls['a']['opt'] = True controls['a']['shape'] = (3,) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -679,7 +679,7 @@ def test_polynomial_control_group_matrix_gl(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -688,7 +688,7 @@ def test_polynomial_control_group_matrix_gl(self): controls['a']['opt'] = True controls['a']['shape'] = (3, 1) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -785,7 +785,7 @@ def test_polynomial_control_group_matrix_radau(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -794,7 +794,7 @@ def test_polynomial_control_group_matrix_radau(self): controls['a']['opt'] = True controls['a']['shape'] = (3, 1) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') @@ -891,7 +891,7 @@ def test_polynomial_control_group_matrix_rungekutta(self): transcription=transcription, compressed=compressed) - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) controls = {'a': PolynomialControlOptionsDictionary()} @@ -900,7 +900,7 @@ def test_polynomial_control_group_matrix_rungekutta(self): controls['a']['opt'] = True controls['a']['shape'] = (3, 1) - ivc = IndepVarComp() + ivc = om.IndepVarComp() p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') diff --git a/dymos/transcriptions/common/test/test_time_comp.py b/dymos/transcriptions/common/test/test_time_comp.py index db07e4e95..67e6373bc 100644 --- a/dymos/transcriptions/common/test/test_time_comp.py +++ b/dymos/transcriptions/common/test/test_time_comp.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from dymos.transcriptions.grid_data import GridData from dymos.transcriptions.common import TimeComp @@ -30,9 +30,9 @@ def test_results_gauss_lobatto(self): segment_ends=_segends, transcription='gauss-lobatto') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem(name='ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem(name='ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=100.0, units='s') @@ -85,9 +85,9 @@ def test_results_radau(self): segment_ends=_segends, transcription='radau-ps') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem(name='ivc', subsys=IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem(name='ivc', subsys=om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('t_initial', val=0.0, units='s') ivc.add_output('t_duration', val=100.0, units='s') diff --git a/dymos/transcriptions/common/time_comp.py b/dymos/transcriptions/common/time_comp.py index eb7a24aa6..03b17b4b9 100644 --- a/dymos/transcriptions/common/time_comp.py +++ b/dymos/transcriptions/common/time_comp.py @@ -1,11 +1,11 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from six import string_types -class TimeComp(ExplicitComponent): +class TimeComp(om.ExplicitComponent): def initialize(self): # Required diff --git a/dymos/transcriptions/common/timeseries_output_comp.py b/dymos/transcriptions/common/timeseries_output_comp.py index 8772cf440..7fb736e18 100644 --- a/dymos/transcriptions/common/timeseries_output_comp.py +++ b/dymos/transcriptions/common/timeseries_output_comp.py @@ -3,12 +3,12 @@ from six import iteritems import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from dymos.transcriptions.grid_data import GridData -class TimeseriesOutputCompBase(ExplicitComponent): +class TimeseriesOutputCompBase(om.ExplicitComponent): """ TimeseriesOutputComp collects variable values from the phase and provides them in chronological order as outputs. Some phase types don't internally have access to a contiguous array of all diff --git a/dymos/transcriptions/pseudospectral/components/collocation_comp.py b/dymos/transcriptions/pseudospectral/components/collocation_comp.py index da481e307..ef979945e 100644 --- a/dymos/transcriptions/pseudospectral/components/collocation_comp.py +++ b/dymos/transcriptions/pseudospectral/components/collocation_comp.py @@ -4,13 +4,13 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from ...grid_data import GridData from ....utils.misc import get_rate_units -class CollocationComp(ExplicitComponent): +class CollocationComp(om.ExplicitComponent): """ CollocationComp computes the generalized defect of a segment for implicit collocation. The defect is the interpolated state derivative at the collocation nodes minus diff --git a/dymos/transcriptions/pseudospectral/components/control_endpoint_defect_comp.py b/dymos/transcriptions/pseudospectral/components/control_endpoint_defect_comp.py index cf3ede353..cbcce382b 100644 --- a/dymos/transcriptions/pseudospectral/components/control_endpoint_defect_comp.py +++ b/dymos/transcriptions/pseudospectral/components/control_endpoint_defect_comp.py @@ -1,13 +1,13 @@ from __future__ import division, print_function, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from six import iteritems from ...grid_data import GridData -class ControlEndpointDefectComp(ExplicitComponent): +class ControlEndpointDefectComp(om.ExplicitComponent): r""" Compute/enforce the control endpoint defect when using the Radau Pseudospectral method. For each dynamic control, take the control values at all nodes. Use a Radau interpolation diff --git a/dymos/transcriptions/pseudospectral/components/state_independents.py b/dymos/transcriptions/pseudospectral/components/state_independents.py index 79938ee5a..f97ab423f 100644 --- a/dymos/transcriptions/pseudospectral/components/state_independents.py +++ b/dymos/transcriptions/pseudospectral/components/state_independents.py @@ -6,12 +6,12 @@ import numpy as np -from openmdao.api import ImplicitComponent +import openmdao.api as om from dymos.transcriptions.grid_data import GridData -class StateIndependentsComp(ImplicitComponent): +class StateIndependentsComp(om.ImplicitComponent): """ A simple component that replaces the state indepvarcomps whenver the solver needs to solve for the state or whenever the initial state is connected to an external source. diff --git a/dymos/transcriptions/pseudospectral/components/state_interp_comp.py b/dymos/transcriptions/pseudospectral/components/state_interp_comp.py index 82a62eb2b..a30f78b0e 100644 --- a/dymos/transcriptions/pseudospectral/components/state_interp_comp.py +++ b/dymos/transcriptions/pseudospectral/components/state_interp_comp.py @@ -1,14 +1,14 @@ from __future__ import division, print_function, absolute_import import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om from six import string_types, iteritems from ...grid_data import GridData from ....utils.misc import get_rate_units -class StateInterpComp(ExplicitComponent): +class StateInterpComp(om.ExplicitComponent): r""" Provide interpolated state values and/or rates for pseudospectral transcriptions. When the transcription is *gauss-lobatto* it accepts the state values and derivatives diff --git a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_opt.py b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_opt.py index a6e3d1876..7697e96dd 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_opt.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_opt.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.pseudospectral.components import CollocationComp @@ -21,7 +21,7 @@ def setUp(self): num_segments=4, segment_ends=np.array([0., 2., 4., 5., 12.]), transcription=transcription, transcription_order=3) - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) state_options = {'x': {'units': 'm', 'shape': (1,), 'fix_initial': True, 'fix_final': False, 'solve_segments': False, @@ -30,7 +30,7 @@ def setUp(self): 'fix_final': True, 'solve_segments': False, 'connected_initial': False, 'connected_final': False}} - indep_comp = IndepVarComp() + indep_comp = om.IndepVarComp() self.p.model.add_subsystem('indep', indep_comp, promotes_outputs=['*']) indep_comp.add_output( diff --git a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_sol_opt.py b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_sol_opt.py index 22dee72cc..14854edbb 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_sol_opt.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_sol_opt.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from dymos.transcriptions.grid_data import GridData from dymos.transcriptions.pseudospectral.components import CollocationComp @@ -17,7 +17,7 @@ class TestCollocationCompSolOpt(unittest.TestCase): # def setUp(self): def make_prob(self, transcription, n_segs, order, compressed): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) gd = GridData(num_segments=n_segs, segment_ends=np.arange(n_segs+1), transcription=transcription, transcription_order=order, compressed=compressed) @@ -29,7 +29,7 @@ def make_prob(self, transcription, n_segs, order, compressed): 'fix_final': True, 'solve_segments': True, 'connected_initial': False}} - indep_comp = IndepVarComp() + indep_comp = om.IndepVarComp() p.model.add_subsystem('indep', indep_comp, promotes_outputs=['*']) indep_comp.add_output( diff --git a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_solver.py b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_solver.py index 85ed287f3..65d71c5a4 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_solver.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_collocation_defect_solver.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from dymos.transcriptions.grid_data import GridData from dymos.transcriptions.pseudospectral.components.collocation_comp import CollocationComp @@ -16,7 +16,7 @@ class TestCollocationBalanceIndex(unittest.TestCase): def make_prob(self, transcription, n_segs, order, compressed): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) gd = GridData(num_segments=n_segs, segment_ends=np.arange(n_segs+1), transcription=transcription, transcription_order=order, compressed=compressed) @@ -126,9 +126,9 @@ def make_prob(self, transcription, n_segs, order, compressed): num_col_nodes = gd.subset_num_nodes['col'] num_col_nodes_per_seg = gd.subset_num_nodes_per_segment['col'] - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - indep_comp = IndepVarComp() + indep_comp = om.IndepVarComp() p.model.add_subsystem('indep', indep_comp, promotes_outputs=['*']) indep_comp.add_output( diff --git a/dymos/transcriptions/pseudospectral/components/test/test_control_endpoint_defect_comp.py b/dymos/transcriptions/pseudospectral/components/test/test_control_endpoint_defect_comp.py index fd9a24473..6936cf6fd 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_control_endpoint_defect_comp.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_control_endpoint_defect_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_rel_error from dymos.transcriptions.pseudospectral.components import ControlEndpointDefectComp @@ -19,12 +19,12 @@ def setUp(self): self.gd = gd - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) control_opts = {'u': {'units': 'm', 'shape': (1,), 'dynamic': True, 'opt': True}, 'v': {'units': 'm', 'shape': (3, 2), 'dynamic': True, 'opt': True}} - indep_comp = IndepVarComp() + indep_comp = om.IndepVarComp() self.p.model.add_subsystem('indep', indep_comp, promotes=['*']) indep_comp.add_output('controls:u', diff --git a/dymos/transcriptions/pseudospectral/components/test/test_state_interp_comp.py b/dymos/transcriptions/pseudospectral/components/test/test_state_interp_comp.py index 219a350a2..c8fca991d 100644 --- a/dymos/transcriptions/pseudospectral/components/test/test_state_interp_comp.py +++ b/dymos/transcriptions/pseudospectral/components/test/test_state_interp_comp.py @@ -4,7 +4,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.pseudospectral.components import StateInterpComp @@ -46,12 +46,12 @@ def test_state_interp_comp_lobatto(self): segment_ends=segends, transcription='gauss-lobatto') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) states = {'x': {'units': 'm', 'shape': (1,)}, 'v': {'units': 'm/s', 'shape': (1,)}} - X_ivc = IndepVarComp() + X_ivc = om.IndepVarComp() p.model.add_subsystem('X_ivc', X_ivc, promotes=['state_disc:x', 'state_disc:v']) X_ivc.add_output('state_disc:x', val=np.zeros(gd.subset_num_nodes['state_disc']), @@ -60,7 +60,7 @@ def test_state_interp_comp_lobatto(self): X_ivc.add_output('state_disc:v', val=np.zeros(gd.subset_num_nodes['state_disc']), units='m/s') - F_ivc = IndepVarComp() + F_ivc = om.IndepVarComp() p.model.add_subsystem('F_ivc', F_ivc, promotes=['staterate_disc:x', 'staterate_disc:v']) F_ivc.add_output('staterate_disc:x', @@ -71,7 +71,7 @@ def test_state_interp_comp_lobatto(self): val=np.zeros(gd.subset_num_nodes['state_disc']), units='m/s**2') - dt_dtau_ivc = IndepVarComp() + dt_dtau_ivc = om.IndepVarComp() p.model.add_subsystem('dt_dstau_ivc', dt_dtau_ivc, promotes=['dt_dstau']) dt_dtau_ivc.add_output('dt_dstau', val=0.0*np.zeros(gd.subset_num_nodes['col']), units='s') @@ -158,24 +158,24 @@ def test_state_interp_comp_lobatto_vectorized(self): segment_ends=segends, transcription='gauss-lobatto') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) states = {'pos': {'units': 'm', 'shape': (2,)}} - X_ivc = IndepVarComp() + X_ivc = om.IndepVarComp() p.model.add_subsystem('X_ivc', X_ivc, promotes=['state_disc:pos']) X_ivc.add_output('state_disc:pos', val=np.zeros((gd.subset_num_nodes['state_disc'], 2)), units='m') - F_ivc = IndepVarComp() + F_ivc = om.IndepVarComp() p.model.add_subsystem('F_ivc', F_ivc, promotes=['staterate_disc:pos']) F_ivc.add_output('staterate_disc:pos', val=np.zeros((gd.subset_num_nodes['state_disc'], 2)), units='m/s') - dt_dtau_ivc = IndepVarComp() + dt_dtau_ivc = om.IndepVarComp() p.model.add_subsystem('dt_dstau_ivc', dt_dtau_ivc, promotes=['dt_dstau']) dt_dtau_ivc.add_output('dt_dstau', val=0.0*np.zeros(gd.subset_num_nodes['col']), units='s') @@ -268,24 +268,24 @@ def test_state_interp_comp_lobatto_vectorized_different_orders(self): segment_ends=segends, transcription='gauss-lobatto') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) states = {'pos': {'units': 'm', 'shape': (2,)}} - X_ivc = IndepVarComp() + X_ivc = om.IndepVarComp() p.model.add_subsystem('X_ivc', X_ivc, promotes=['state_disc:pos']) X_ivc.add_output('state_disc:pos', val=np.zeros((gd.subset_num_nodes['state_disc'], 2)), units='m') - F_ivc = IndepVarComp() + F_ivc = om.IndepVarComp() p.model.add_subsystem('F_ivc', F_ivc, promotes=['staterate_disc:pos']) F_ivc.add_output('staterate_disc:pos', val=np.zeros((gd.subset_num_nodes['state_disc'], 2)), units='m/s') - dt_dtau_ivc = IndepVarComp() + dt_dtau_ivc = om.IndepVarComp() p.model.add_subsystem('dt_dstau_ivc', dt_dtau_ivc, promotes=['dt_dstau']) dt_dtau_ivc.add_output('dt_dstau', val=0.0*np.zeros(gd.subset_num_nodes['col']), units='s') @@ -324,12 +324,12 @@ def test_state_interp_comp_radau(self): segment_ends=np.array([0, 10]), transcription='radau-ps') - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) states = {'x': {'units': 'm', 'shape': (1,)}, 'v': {'units': 'm/s', 'shape': (1,)}} - X_ivc = IndepVarComp() + X_ivc = om.IndepVarComp() p.model.add_subsystem('X_ivc', X_ivc, promotes=['state_disc:x', 'state_disc:v']) X_ivc.add_output('state_disc:x', val=np.zeros(gd.subset_num_nodes['state_disc']), @@ -338,7 +338,7 @@ def test_state_interp_comp_radau(self): X_ivc.add_output('state_disc:v', val=np.zeros(gd.subset_num_nodes['state_disc']), units='m/s') - dt_dtau_ivc = IndepVarComp() + dt_dtau_ivc = om.IndepVarComp() dt_dtau_ivc.add_output('dt_dstau', val=0.0*np.zeros(gd.subset_num_nodes['col']), units='s') p.model.add_subsystem('dt_dstau_ivc', dt_dtau_ivc, promotes=['dt_dstau']) diff --git a/dymos/transcriptions/pseudospectral/pseudospectral_base.py b/dymos/transcriptions/pseudospectral/pseudospectral_base.py index ef06d3f8d..4dda0be07 100644 --- a/dymos/transcriptions/pseudospectral/pseudospectral_base.py +++ b/dymos/transcriptions/pseudospectral/pseudospectral_base.py @@ -1,13 +1,11 @@ from __future__ import division, print_function, absolute_import from collections import Iterable -import warnings import numpy as np from dymos.transcriptions.common import EndpointConditionsComp -from openmdao.api import IndepVarComp, NonlinearRunOnce, NonlinearBlockGS, \ - NewtonSolver, BoundsEnforceLS, DirectSolver +import openmdao.api as om from six import iteritems from ..transcription_base import TranscriptionBase @@ -65,7 +63,7 @@ def setup_states(self, phase): 'indep_states.defects:{0}'.format(name)) else: - indep = IndepVarComp() + indep = om.IndepVarComp() for name, options in iteritems(phase.state_options): if not options['solve_segments'] and not options['connected_initial']: @@ -223,7 +221,7 @@ def setup_defects(self, phase): src_indices=src_idxs, flat_src_indices=True) def setup_endpoint_conditions(self, phase): - jump_comp = phase.add_subsystem('indep_jumps', subsys=IndepVarComp(), + jump_comp = phase.add_subsystem('indep_jumps', subsys=om.IndepVarComp(), promotes_outputs=['*']) jump_comp.add_output('initial_jump:time', val=0.0, units=phase.time_options['units'], @@ -316,11 +314,11 @@ def setup_endpoint_conditions(self, phase): def setup_solvers(self, phase): if self.any_solved_segs: - newton = phase.nonlinear_solver = NewtonSolver() + newton = phase.nonlinear_solver = om.NewtonSolver() newton.options['solve_subsystems'] = True newton.options['iprint'] = -1 - newton.linesearch = BoundsEnforceLS() - phase.linear_solver = DirectSolver() + newton.linesearch = om.BoundsEnforceLS() + phase.linear_solver = om.DirectSolver() def _get_boundary_constraint_src(self, var, loc, phase): # Determine the path to the variable which we will be constraining diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_comp.py index 4eadcad72..9ffb481de 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_comp.py @@ -4,13 +4,12 @@ import numpy as np -from openmdao.api import ExplicitComponent - +import openmdao.api as om from dymos.utils.rk_methods import rk_methods from dymos.utils.misc import get_rate_units -class RungeKuttaKComp(ExplicitComponent): +class RungeKuttaKComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_segments', types=int, diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py index 2b2d12602..021a8dd53 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_k_iter_group.py @@ -2,7 +2,7 @@ from six import string_types, iteritems -from openmdao.api import Group, DirectSolver, NonlinearBlockGS, NewtonSolver, NonlinearRunOnce +import openmdao.api as om from ....utils.rk_methods import rk_methods @@ -10,7 +10,7 @@ from .runge_kutta_k_comp import RungeKuttaKComp -class RungeKuttaKIterGroup(Group): +class RungeKuttaKIterGroup(om.Group): """ This Group contains the state prediction component, the ODE, and the k-calculation component. Given the initial values of the states, the times at the ODE evaluations, and the stepsize @@ -36,8 +36,8 @@ def initialize(self): self.options.declare('ode_init_kwargs', types=dict, default={}, desc='Keyword arguments provided when initializing the ODE System') - self.options.declare('solver_class', default=NonlinearBlockGS, - values=(NonlinearBlockGS, NewtonSolver, NonlinearRunOnce), + self.options.declare('solver_class', default=om.NonlinearBlockGS, + values=(om.NonlinearBlockGS, om.NewtonSolver, om.NonlinearRunOnce), allow_none=True, desc='The nonlinear solver class used to converge the numerical ' 'integration of the segment.') @@ -78,6 +78,6 @@ def setup(self): self.connect('k_comp.k:{0}'.format(state_name), 'state_predict_comp.k:{0}'.format(state_name)) - self.linear_solver = DirectSolver() + self.linear_solver = om.DirectSolver() if self.options['solver_class']: self.nonlinear_solver = self.options['solver_class'](**self.options['solver_options']) diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_advance_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_advance_comp.py index 90a82fc8a..7a58921a8 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_advance_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_advance_comp.py @@ -1,16 +1,16 @@ from __future__ import print_function, division, absolute_import -from six import string_types, iteritems +from six import iteritems import numpy as np from scipy.linalg import block_diag -from openmdao.api import ExplicitComponent +import openmdao.api as om from dymos.utils.rk_methods import rk_methods -class RungeKuttaStateAdvanceComp(ExplicitComponent): +class RungeKuttaStateAdvanceComp(om.ExplicitComponent): """ Given the initial value of each state at the start of each segment and the weight factors k for each state in each segment, compute the final value of each state at the end of each diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py index 3e0f847e8..6a913f844 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_continuity_iter_group.py @@ -3,8 +3,7 @@ import numpy as np from six import string_types, iteritems -from openmdao.api import Group, IndepVarComp, DirectSolver, NonlinearBlockGS, NewtonSolver, \ - NonlinearRunOnce +import openmdao.api as om from .runge_kutta_k_iter_group import RungeKuttaKIterGroup from .runge_kutta_state_advance_comp import RungeKuttaStateAdvanceComp @@ -12,7 +11,7 @@ from ....utils.indexing import get_src_indices_by_row -class RungeKuttaStateContinuityIterGroup(Group): +class RungeKuttaStateContinuityIterGroup(om.Group): """ This Group contains the k-iteration subgroup, the state advance component, continuity defect component. Given the initial value of each state at the beginning of the first segment, @@ -41,8 +40,8 @@ def initialize(self): self.options.declare('ode_init_kwargs', types=dict, default={}, desc='Keyword arguments provided when initializing the ODE System') - self.options.declare('k_solver_class', default=NonlinearBlockGS, - values=(NonlinearBlockGS, NewtonSolver, NonlinearRunOnce), + self.options.declare('k_solver_class', default=om.NonlinearBlockGS, + values=(om.NonlinearBlockGS, om.NewtonSolver, om.NonlinearRunOnce), allow_none=True, desc='The nonlinear solver class used to converge the numerical ' 'integration across each segment.') @@ -94,4 +93,4 @@ def setup(self): 'initial_states_per_seg:{0}'.format(state_name), src_indices=src_idxs, flat_src_indices=True) - self.linear_solver = DirectSolver() + self.linear_solver = om.DirectSolver() diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_predict_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_predict_comp.py index 8027d24ef..244c9165f 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_state_predict_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_state_predict_comp.py @@ -5,12 +5,12 @@ import numpy as np from scipy.linalg import block_diag -from openmdao.api import ExplicitComponent +import openmdao.api as om from dymos.utils.rk_methods import rk_methods -class RungeKuttaStatePredictComp(ExplicitComponent): +class RungeKuttaStatePredictComp(om.ExplicitComponent): def initialize(self): self.options.declare('num_segments', types=int, diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_stepsize_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_stepsize_comp.py index 60cd0578e..a55c8f114 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_stepsize_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_stepsize_comp.py @@ -5,10 +5,10 @@ import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class RungeKuttaStepsizeComp(ExplicitComponent): +class RungeKuttaStepsizeComp(om.ExplicitComponent): """ Given the duration of the phase and the segment relative lengths, compute the duration of each segment (the step size) for each segment (step). diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_comp.py index 59709e506..ab82c2d46 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_comp.py @@ -4,8 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp, NonlinearRunOnce, NonlinearBlockGS, \ - NewtonSolver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.transcriptions.runge_kutta.components.runge_kutta_state_continuity_comp import \ @@ -20,7 +19,7 @@ def test_continuity_comp_scalar_no_iteration_fwd(self): 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -28,8 +27,8 @@ def test_continuity_comp_scalar_no_iteration_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearRunOnce() - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearRunOnce() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -85,9 +84,9 @@ def test_continuity_comp_connected_scalar_no_iteration_fwd(self): 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': True}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states:y', units='m', shape=(1, 1)) p.model.add_subsystem('continuity_comp', @@ -96,8 +95,8 @@ def test_continuity_comp_connected_scalar_no_iteration_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearRunOnce() - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearRunOnce() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -155,7 +154,7 @@ def test_continuity_comp_scalar_nonlinearblockgs_fwd(self): 'fix_final': False, 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -163,8 +162,8 @@ def test_continuity_comp_scalar_nonlinearblockgs_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearBlockGS(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearBlockGS(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -220,9 +219,9 @@ def test_continuity_comp_connected_scalar_nonlinearblockgs_fwd(self): 'fix_final': False, 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': True}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states:y', units='m', shape=(1, 1)) p.model.add_subsystem('continuity_comp', @@ -231,8 +230,8 @@ def test_continuity_comp_connected_scalar_nonlinearblockgs_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearBlockGS(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearBlockGS(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -290,7 +289,7 @@ def test_continuity_comp_scalar_newton_fwd(self): 'fix_final': False, 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -298,8 +297,8 @@ def test_continuity_comp_scalar_newton_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NewtonSolver(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NewtonSolver(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -348,7 +347,7 @@ def test_continuity_comp_vector_no_iteration_fwd(self): 'lower': None, 'upper': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -356,8 +355,8 @@ def test_continuity_comp_vector_no_iteration_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearRunOnce() - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearRunOnce() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -410,7 +409,7 @@ def test_continuity_comp_vector_nonlinearblockgs_fwd(self): 'fix_final': False, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -418,8 +417,8 @@ def test_continuity_comp_vector_nonlinearblockgs_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearBlockGS(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearBlockGS(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -464,9 +463,9 @@ def test_continuity_comp_connected_vector_nonlinearblockgs_fwd(self): 'fix_final': False, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': True}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states:y', units='m', shape=(1, 2)) p.model.add_subsystem('continuity_comp', @@ -475,8 +474,8 @@ def test_continuity_comp_connected_vector_nonlinearblockgs_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NonlinearBlockGS(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearBlockGS(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -523,7 +522,7 @@ def test_continuity_comp_vector_newton_fwd(self): 'fix_final': False, 'defect_ref': 1, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) p.model.add_subsystem('continuity_comp', RungeKuttaStateContinuityComp(num_segments=num_seg, @@ -531,8 +530,8 @@ def test_continuity_comp_vector_newton_fwd(self): promotes_inputs=['*'], promotes_outputs=['*']) - p.model.nonlinear_solver = NewtonSolver(iprint=2) - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NewtonSolver(iprint=2) + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py index 197e20040..ebced4d7a 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_continuity_iter_group.py @@ -4,8 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp, NonlinearRunOnce, \ - NewtonSolver, DirectSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.transcriptions.runge_kutta.components import RungeKuttaStateContinuityIterGroup @@ -21,9 +20,9 @@ def test_continuity_comp_no_iteration(self): 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, @@ -40,7 +39,7 @@ def test_continuity_comp_no_iteration(self): time_units='s', ode_class=TestODE, ode_init_kwargs={}, - k_solver_class=NonlinearRunOnce), + k_solver_class=om.NonlinearRunOnce), promotes_outputs=['states:*']) p.model.connect('h', 'cnty_iter_group.h') @@ -50,8 +49,8 @@ def test_continuity_comp_no_iteration(self): p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) - p.model.nonlinear_solver = NonlinearRunOnce() - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NonlinearRunOnce() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) @@ -118,9 +117,9 @@ def test_continuity_comp_newtonsolver(self): 'defect_ref': 1.0, 'lower': None, 'upper': None, 'connected_initial': False}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, @@ -147,8 +146,8 @@ def test_continuity_comp_newtonsolver(self): p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) - p.model.nonlinear_solver = NewtonSolver() - p.model.linear_solver = DirectSolver() + p.model.nonlinear_solver = om.NewtonSolver() + p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_comp.py index 9582a5e17..effa68801 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.transcriptions.runge_kutta.components.runge_kutta_k_comp import RungeKuttaKComp @@ -15,9 +15,9 @@ class TestRKKComp(unittest.TestCase): def test_rk_k_comp_rk4_scalar(self): state_options = {'y': {'shape': (1,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('h', shape=(4,), units='s') ivc.add_output('f:y', shape=(4, 4, 1), units='m/s') @@ -86,9 +86,9 @@ def test_rk_state_advance_comp_rk4_vector(self): num_seg = 2 state_options = {'y': {'shape': (num_seg,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('h', shape=(num_seg,), units='s') ivc.add_output('f:y', shape=(num_seg, 4, 2), units='m/s') @@ -134,9 +134,9 @@ def test_rk_state_advance_comp_rk4_matrix(self): num_stages = 4 state_options = {'y': {'shape': (2, 2), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('h', shape=(num_seg,), units='s') ivc.add_output('f:y', shape=(num_seg, num_stages, 2, 2), units='m/s') diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py index 7c183fee9..9ee6f4b29 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_k_iter_group.py @@ -5,8 +5,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp, NonlinearRunOnce, NonlinearBlockGS, \ - NewtonSolver +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.runge_kutta.components.runge_kutta_k_iter_group import RungeKuttaKIterGroup @@ -20,9 +19,9 @@ def test_rk4_scalar_no_iteration(self): num_stages = 4 state_options = {'y': {'shape': (1,), 'units': 'm', 'targets': ['y']}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states_per_seg:y', shape=(num_seg, 1), units='m') ivc.add_output('h', shape=(num_seg, 1), units='s') @@ -35,7 +34,7 @@ def test_rk4_scalar_no_iteration(self): time_units='s', ode_class=TestODE, ode_init_kwargs={}, - solver_class=NonlinearRunOnce)) + solver_class=om.NonlinearRunOnce)) p.model.connect('t', 'k_iter_group.ode.t') p.model.connect('h', 'k_iter_group.h') @@ -95,9 +94,9 @@ def test_rk4_scalar_nonlinearblockgs(self): num_stages = 4 state_options = {'y': {'shape': (1,), 'units': 'm', 'targets': ['y']}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states_per_seg:y', shape=(num_seg, 1), units='m') ivc.add_output('h', shape=(num_seg, 1), units='s') @@ -110,7 +109,7 @@ def test_rk4_scalar_nonlinearblockgs(self): time_units='s', ode_class=TestODE, ode_init_kwargs={}, - solver_class=NonlinearBlockGS, + solver_class=om.NonlinearBlockGS, solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') @@ -154,9 +153,9 @@ def test_rk4_scalar_newton(self): num_stages = 4 state_options = {'y': {'shape': (1,), 'units': 'm', 'targets': ['y']}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('initial_states_per_seg:y', shape=(num_seg, 1), units='m') ivc.add_output('h', shape=(num_seg, 1), units='s') @@ -169,7 +168,7 @@ def test_rk4_scalar_newton(self): time_units='s', ode_class=TestODE, ode_init_kwargs={}, - solver_class=NewtonSolver, + solver_class=om.NewtonSolver, solver_options={'iprint': 2})) p.model.connect('t', 'k_iter_group.ode.t') diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py index 6695309df..33263b298 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py @@ -4,7 +4,7 @@ import numpy as np from numpy.testing import assert_almost_equal -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials from dymos.transcriptions.runge_kutta.components import RungeKuttaPathConstraintComp @@ -25,7 +25,7 @@ def setUp(self): nn = 4 - self.p = Problem(model=Group()) + self.p = om.Problem(model=om.Group()) controls = {'a': ControlOptionsDictionary(), 'b': ControlOptionsDictionary(), @@ -36,7 +36,7 @@ def setUp(self): controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) - ivc = IndepVarComp() + ivc = om.IndepVarComp() self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) ivc.add_output('a_disc', val=np.zeros((nn, 1)), units='m') diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_state_advance_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_state_advance_comp.py index 90aba5aca..12c633617 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_state_advance_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_state_advance_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.transcriptions.runge_kutta.components.runge_kutta_state_advance_comp import \ @@ -16,9 +16,9 @@ class TestRKStateAdvanceComp(unittest.TestCase): def test_rk_state_advance_comp_rk4_scalar(self): state_options = {'y': {'shape': (1,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(4, 4, 1), units='m') ivc.add_output('y0', shape=(4, 1), units='m') @@ -70,9 +70,9 @@ def test_rk_state_advance_comp_rk4_scalar(self): def test_rk_state_advance_comp_rk4_vector(self): state_options = {'y': {'shape': (2,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(2, 4, 2), units='m') ivc.add_output('y0', shape=(2, 2), units='m') @@ -107,9 +107,9 @@ def test_rk_state_advance_comp_rk4_vector(self): def test_rk_state_advance_comp_rk4_matrix(self): state_options = {'y': {'shape': (2, 2), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(4, 2, 2), units='m') ivc.add_output('y0', shape=(2, 2), units='m') diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_state_predict_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_state_predict_comp.py index 7748dde05..11543666b 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_state_predict_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_state_predict_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.transcriptions.runge_kutta.components.runge_kutta_state_predict_comp import \ @@ -17,9 +17,9 @@ def test_rk_state_predict_comp_rk4(self): num_seg = 4 state_options = {'y': {'shape': (1,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(num_seg, 4, 1), units='m') ivc.add_output('y0', shape=(num_seg, 1), units='m') @@ -87,9 +87,9 @@ def test_rk_state_predict_comp_rk4_3seg(self): num_seg = 3 state_options = {'y': {'shape': (1,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(num_seg, 4, 1), units='m') ivc.add_output('y0', shape=(num_seg, 1), units='m') @@ -147,9 +147,9 @@ def test_rk_state_predict_comp_rk4_vector(self): num_seg = 2 state_options = {'y': {'shape': (2,), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(num_seg, 4, 2), units='m') ivc.add_output('y0', shape=(num_seg, 2), units='m') @@ -195,9 +195,9 @@ def test_rk_state_predict_comp_rk4_vector(self): def test_rk_state_advance_comp_rk4_matrix(self): state_options = {'y': {'shape': (2, 2), 'units': 'm'}} - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('k:y', shape=(1, 4, 2, 2), units='m') ivc.add_output('y0', shape=(1, 2, 2), units='m') diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_stepsize_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_stepsize_comp.py index 7a0b08dd0..fe12ecebe 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_stepsize_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_stepsize_comp.py @@ -4,7 +4,7 @@ import numpy as np -from openmdao.api import Problem, Group, IndepVarComp +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials from dymos.transcriptions.runge_kutta.components.runge_kutta_stepsize_comp import RungeKuttaStepsizeComp @@ -13,9 +13,9 @@ class TestRKStepsizeComp(unittest.TestCase): def test_rk_stepsize_comp(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('t_duration', shape=(1,), units='s') @@ -41,9 +41,9 @@ def test_rk_stepsize_comp(self): assert_check_partials(cpd) def test_rk_stepsize_comp_nonuniform(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - ivc = p.model.add_subsystem('ivc', IndepVarComp(), promotes_outputs=['*']) + ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('t_duration', shape=(1,), units='s') diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index edd21bf4d..835074267 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -1,11 +1,8 @@ from __future__ import division, print_function, absolute_import -import warnings - import numpy as np -from openmdao.api import IndepVarComp, NonlinearRunOnce, NonlinearBlockGS, \ - NewtonSolver, BoundsEnforceLS +import openmdao.api as om from six import iteritems from ..transcription_base import TranscriptionBase @@ -31,8 +28,8 @@ def initialize(self): self.options.declare('method', default='RK4', values=('RK4',), desc='The integrator used within the explicit phase.') - self.options.declare('k_solver_class', default=NonlinearBlockGS, - values=(NonlinearBlockGS, NewtonSolver, NonlinearRunOnce), + self.options.declare('k_solver_class', default=om.NonlinearBlockGS, + values=(om.NonlinearBlockGS, om.NewtonSolver, om.NonlinearRunOnce), allow_none=True, desc='The nonlinear solver class used to converge the numerical ' 'integration across each segment.') @@ -61,11 +58,11 @@ def setup_solvers(self, phase): ------- """ - phase.nonlinear_solver = NewtonSolver() + phase.nonlinear_solver = om.NewtonSolver() phase.nonlinear_solver.options['iprint'] = -1 phase.nonlinear_solver.options['solve_subsystems'] = True phase.nonlinear_solver.options['err_on_maxiter'] = True - phase.nonlinear_solver.linesearch = BoundsEnforceLS() + phase.nonlinear_solver.linesearch = om.BoundsEnforceLS() def setup_time(self, phase): time_units = phase.time_options['units'] @@ -428,7 +425,7 @@ def setup_defects(self, phase): def setup_endpoint_conditions(self, phase): - jump_comp = phase.add_subsystem('indep_jumps', subsys=IndepVarComp(), + jump_comp = phase.add_subsystem('indep_jumps', subsys=om.IndepVarComp(), promotes_outputs=['*']) jump_comp.add_output('initial_jump:time', val=0.0, units=phase.time_options['units'], diff --git a/dymos/transcriptions/runge_kutta/test/rk_test_ode.py b/dymos/transcriptions/runge_kutta/test/rk_test_ode.py index 02d464bf8..e352b95b6 100644 --- a/dymos/transcriptions/runge_kutta/test/rk_test_ode.py +++ b/dymos/transcriptions/runge_kutta/test/rk_test_ode.py @@ -1,13 +1,13 @@ from __future__ import print_function, division, absolute_import import numpy as np -from openmdao.api import ExplicitComponent -from dymos import declare_time, declare_state +import openmdao.api as om +import dymos as dm -@declare_time(targets=['t'], units='s') -@declare_state('y', targets=['y'], rate_source='ydot', units='m') -class TestODE(ExplicitComponent): +@dm.declare_time(targets=['t'], units='s') +@dm.declare_state('y', targets=['y'], rate_source='ydot', units='m') +class TestODE(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) diff --git a/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py b/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py index 5b833060f..abd416f42 100644 --- a/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py +++ b/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py @@ -4,11 +4,10 @@ import numpy as np -from openmdao.api import Problem, Group +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error -from dymos.phase import Phase -from dymos.transcriptions import RungeKutta +import dymos as dm from dymos.transcriptions.runge_kutta.test.rk_test_ode import TestODE, _test_ode_solution @@ -16,8 +15,8 @@ class TestRK4SimpleIntegration(unittest.TestCase): def test_simple_integration_forward(self): - p = Problem(model=Group()) - phase = Phase(ode_class=TestODE, transcription=RungeKutta(num_segments=200, method='RK4')) + p = om.Problem(model=om.Group()) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) @@ -39,10 +38,11 @@ def test_simple_integration_forward(self): def test_simple_integration_forward_connected_initial(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=TestODE, transcription=RungeKutta(num_segments=200, method='RK4')) - p.model.add_subsystem('phase0', subsys=phase) + traj = p.model.add_subsystem('traj', subsys=dm.Trajectory()) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) + traj.add_phase('phase0', phase) phase.set_time_options(fix_initial=True, fix_duration=True) phase.set_state_options('y', fix_initial=False, connected_initial=True) @@ -51,25 +51,25 @@ def test_simple_integration_forward_connected_initial(self): p.setup(check=True, force_alloc_complex=True) - p['phase0.t_initial'] = 0.0 - p['phase0.t_duration'] = 2.0 + p['traj.phase0.t_initial'] = 0.0 + p['traj.phase0.t_duration'] = 2.0 # The initial guess of states at the segment boundaries - p['phase0.states:y'] = 0.0 + p['traj.phase0.states:y'] = 0.0 # The initial value of the states from which the integration proceeds - p['phase0.initial_states:y'] = 0.5 + p['traj.phase0.initial_states:y'] = 0.5 p.run_model() - expected = _test_ode_solution(p['phase0.ode.y'], p['phase0.ode.t']) - assert_rel_error(self, p['phase0.ode.y'], expected, tolerance=1.0E-3) + expected = _test_ode_solution(p['traj.phase0.ode.y'], p['traj.phase0.ode.t']) + assert_rel_error(self, p['traj.phase0.ode.y'], expected, tolerance=1.0E-3) def test_simple_integration_forward_connected_initial_fixed_initial(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=TestODE, transcription=RungeKutta(num_segments=200, method='RK4')) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) @@ -85,9 +85,9 @@ def test_simple_integration_forward_connected_initial_fixed_initial(self): def test_simple_integration_backward(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=TestODE, transcription=RungeKutta(num_segments=4, method='RK4')) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=4, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) @@ -109,9 +109,9 @@ def test_simple_integration_backward(self): def test_simple_integration_backward_connected_initial(self): - p = Problem(model=Group()) + p = om.Problem(model=om.Group()) - phase = Phase(ode_class=TestODE, transcription=RungeKutta(num_segments=4, method='RK4')) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=4, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) diff --git a/dymos/transcriptions/solve_ivp/components/ode_integration_interface.py b/dymos/transcriptions/solve_ivp/components/ode_integration_interface.py index d497b254d..2978e4319 100644 --- a/dymos/transcriptions/solve_ivp/components/ode_integration_interface.py +++ b/dymos/transcriptions/solve_ivp/components/ode_integration_interface.py @@ -7,9 +7,7 @@ import numpy as np from .odeint_control_interpolation_comp import ODEIntControlInterpolationComp from .state_rate_collector_comp import StateRateCollectorComp -from openmdao.core.group import Group -from openmdao.core.indepvarcomp import IndepVarComp -from openmdao.core.problem import Problem +import openmdao.api as om class ODEIntegrationInterface(object): @@ -74,11 +72,11 @@ def __init__(self, ode_class, time_options, state_options, control_options, # # Build odeint problem interface # - self.prob = Problem(model=Group()) + self.prob = om.Problem(model=om.Group()) model = self.prob.model # The time IVC - ivc = IndepVarComp() + ivc = om.IndepVarComp() time_units = self.time_options['units'] ivc.add_output('time', val=0.0, units=time_units) ivc.add_output('time_phase', val=-88.0, units=time_units) diff --git a/dymos/transcriptions/solve_ivp/components/odeint_control_interpolation_comp.py b/dymos/transcriptions/solve_ivp/components/odeint_control_interpolation_comp.py index cb6b11379..fcca26bc8 100644 --- a/dymos/transcriptions/solve_ivp/components/odeint_control_interpolation_comp.py +++ b/dymos/transcriptions/solve_ivp/components/odeint_control_interpolation_comp.py @@ -1,9 +1,9 @@ from dymos.utils.misc import get_rate_units -from openmdao.core.explicitcomponent import ExplicitComponent +import openmdao.api as om from six import string_types, iteritems -class ODEIntControlInterpolationComp(ExplicitComponent): +class ODEIntControlInterpolationComp(om.ExplicitComponent): """ Provides the interpolated value and rate of a control variable during explicit integration. diff --git a/dymos/transcriptions/solve_ivp/components/segment_simulation_comp.py b/dymos/transcriptions/solve_ivp/components/segment_simulation_comp.py index 7faeb4963..73052ced4 100644 --- a/dymos/transcriptions/solve_ivp/components/segment_simulation_comp.py +++ b/dymos/transcriptions/solve_ivp/components/segment_simulation_comp.py @@ -10,15 +10,14 @@ from scipy.integrate import solve_ivp -from openmdao.api import ExplicitComponent - +import openmdao.api as om from ....utils.interpolate import LagrangeBarycentricInterpolant from ....utils.lgl import lgl from .ode_integration_interface import ODEIntegrationInterface from ....phase.options import TimeOptionsDictionary -class SegmentSimulationComp(ExplicitComponent): +class SegmentSimulationComp(om.ExplicitComponent): """ SegmentSimulationComp is a component which, given values for time, states, and controls within a given segment, explicitly simulates the segment using scipy.integrate.solve_ivp. diff --git a/dymos/transcriptions/solve_ivp/components/segment_state_mux_comp.py b/dymos/transcriptions/solve_ivp/components/segment_state_mux_comp.py index 93139d00b..6cea62e9d 100644 --- a/dymos/transcriptions/solve_ivp/components/segment_state_mux_comp.py +++ b/dymos/transcriptions/solve_ivp/components/segment_state_mux_comp.py @@ -3,10 +3,10 @@ from six import iteritems import numpy as np -from openmdao.api import ExplicitComponent +import openmdao.api as om -class SegmentStateMuxComp(ExplicitComponent): +class SegmentStateMuxComp(om.ExplicitComponent): def initialize(self): self.options.declare('grid_data', desc='the grid data of the corresponding phase.') diff --git a/dymos/transcriptions/solve_ivp/components/solve_ivp_control_group.py b/dymos/transcriptions/solve_ivp/components/solve_ivp_control_group.py index 15240819e..01a47867d 100644 --- a/dymos/transcriptions/solve_ivp/components/solve_ivp_control_group.py +++ b/dymos/transcriptions/solve_ivp/components/solve_ivp_control_group.py @@ -5,14 +5,14 @@ import numpy as np from scipy.linalg import block_diag -from openmdao.api import ExplicitComponent, Group, IndepVarComp +import openmdao.api as om from ...grid_data import GridData from dymos.utils.misc import get_rate_units from ....utils.lagrange import lagrange_matrices -class SolveIVPControlInterpComp(ExplicitComponent): +class SolveIVPControlInterpComp(om.ExplicitComponent): """ Compute the approximated control values and rates given the values of a control at output nodes and the approximated values at output nodes, given values at the control input nodes. @@ -187,7 +187,7 @@ def compute(self, inputs, outputs): outputs[self._output_rate2_names[name]] = (b / inputs['dt_dstau'] ** 2).T -class SolveIVPControlGroup(Group): +class SolveIVPControlGroup(om.Group): def initialize(self): self.options.declare('control_options', types=dict, @@ -202,9 +202,6 @@ def initialize(self): def setup(self): - ivc = IndepVarComp() - - # opts = self.options gd = self.options['grid_data'] control_options = self.options['control_options'] time_units = self.options['time_units'] @@ -215,7 +212,7 @@ def setup(self): opt_controls = [name for (name, opts) in iteritems(control_options) if opts['opt']] if len(opt_controls) > 0: - ivc = self.add_subsystem('indep_controls', subsys=IndepVarComp(), + ivc = self.add_subsystem('indep_controls', subsys=om.IndepVarComp(), promotes_outputs=['*']) self.add_subsystem( diff --git a/dymos/transcriptions/solve_ivp/components/solve_ivp_polynomial_control_group.py b/dymos/transcriptions/solve_ivp/components/solve_ivp_polynomial_control_group.py index 50c984b89..2b935de71 100644 --- a/dymos/transcriptions/solve_ivp/components/solve_ivp_polynomial_control_group.py +++ b/dymos/transcriptions/solve_ivp/components/solve_ivp_polynomial_control_group.py @@ -3,7 +3,7 @@ import numpy as np from six import iteritems, string_types -from openmdao.api import Group, ExplicitComponent, IndepVarComp +import openmdao.api as om from ...grid_data import GridData from ....utils.lgl import lgl @@ -11,7 +11,7 @@ from ....utils.misc import get_rate_units -class SolveIVPLGLPolynomialControlComp(ExplicitComponent): +class SolveIVPLGLPolynomialControlComp(om.ExplicitComponent): """ Component which interpolates controls as a single polynomial across the entire phase. """ @@ -197,7 +197,7 @@ def compute_partials(self, inputs, partials): (self.rate2_jacs[name] / (0.5 * t_duration_x_size) ** 2)[r_nz, c_nz] -class SolveIVPPolynomialControlGroup(Group): +class SolveIVPPolynomialControlGroup(om.Group): def initialize(self): self.options.declare('polynomial_control_options', types=dict, @@ -212,7 +212,7 @@ def initialize(self): def setup(self): - ivc = IndepVarComp() + ivc = om.IndepVarComp() opts = self.options pcos = self.options['polynomial_control_options'] diff --git a/dymos/transcriptions/solve_ivp/components/state_rate_collector_comp.py b/dymos/transcriptions/solve_ivp/components/state_rate_collector_comp.py index 994f2b220..380f225ac 100644 --- a/dymos/transcriptions/solve_ivp/components/state_rate_collector_comp.py +++ b/dymos/transcriptions/solve_ivp/components/state_rate_collector_comp.py @@ -1,10 +1,10 @@ import numpy as np from dymos.utils.misc import get_rate_units -from openmdao.core.explicitcomponent import ExplicitComponent +import openmdao.api as om from six import string_types, iteritems -class StateRateCollectorComp(ExplicitComponent): +class StateRateCollectorComp(om.ExplicitComponent): """ Collects the state rates and outputs them in the units specified in the state options. For explicit integration this is necessary when the output providing the state rate has diff --git a/dymos/transcriptions/solve_ivp/components/test/test_segment_simulation_comp.py b/dymos/transcriptions/solve_ivp/components/test/test_segment_simulation_comp.py index 07a0edce4..1ecd29e33 100644 --- a/dymos/transcriptions/solve_ivp/components/test/test_segment_simulation_comp.py +++ b/dymos/transcriptions/solve_ivp/components/test/test_segment_simulation_comp.py @@ -2,7 +2,7 @@ import unittest -from openmdao.api import Problem, Group +import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error from dymos.transcriptions.solve_ivp.components.segment_simulation_comp import SegmentSimulationComp @@ -15,8 +15,7 @@ class TestSegmentSimulationComp(unittest.TestCase): def test_simple_integration(self): - p = Problem(model=Group()) - p.model = Group() + p = om.Problem(model=om.Group()) time_options = TimeOptionsDictionary() time_options['units'] = 's' diff --git a/dymos/transcriptions/solve_ivp/solve_ivp.py b/dymos/transcriptions/solve_ivp/solve_ivp.py index ee00bbe05..4da1854b7 100644 --- a/dymos/transcriptions/solve_ivp/solve_ivp.py +++ b/dymos/transcriptions/solve_ivp/solve_ivp.py @@ -2,11 +2,10 @@ import numpy as np -from openmdao.api import Group, IndepVarComp +import openmdao.api as om from six import iteritems, string_types from ..transcription_base import TranscriptionBase -from ..grid_data import GridData from .components import SegmentSimulationComp, ODEIntegrationInterface, SegmentStateMuxComp, \ SolveIVPControlGroup, SolveIVPPolynomialControlGroup, SolveIVPTimeseriesOutputComp from ..common import TimeComp @@ -117,7 +116,7 @@ def setup_states(self, phase): """ num_seg = self.grid_data.num_segments - indep_states_ivc = phase.add_subsystem('indep_states', IndepVarComp(), + indep_states_ivc = phase.add_subsystem('indep_states', om.IndepVarComp(), promotes_outputs=['*']) for state_name, options in iteritems(phase.state_options): @@ -158,7 +157,7 @@ def setup_ode(self, phase): gd = self.grid_data num_seg = gd.num_segments - segments_group = phase.add_subsystem(name='segments', subsys=Group(), + segments_group = phase.add_subsystem(name='segments', subsys=om.Group(), promotes_outputs=['*'], promotes_inputs=['*']) # All segments use a common ODEIntegrationInterface to save some memory. diff --git a/dymos/transcriptions/transcription_base.py b/dymos/transcriptions/transcription_base.py index 662521189..15839d60a 100644 --- a/dymos/transcriptions/transcription_base.py +++ b/dymos/transcriptions/transcription_base.py @@ -7,7 +7,7 @@ import numpy as np -from openmdao.api import IndepVarComp, OptionsDictionary +import openmdao.api as om from .common import BoundaryConstraintComp, InputParameterComp, ControlGroup, \ PolynomialControlGroup @@ -22,7 +22,7 @@ def __init__(self, **kwargs): self.grid_data = None - self.options = OptionsDictionary() + self.options = om.OptionsDictionary() self.options.declare('num_segments', types=int, desc='Number of segments') self.options.declare('segment_ends', default=None, types=(Sequence, np.ndarray), @@ -92,7 +92,7 @@ def setup_time(self, phase): # phase.connect('t_duration', 'time.t_duration') if indeps: - indep = IndepVarComp() + indep = om.IndepVarComp() for var in indeps: indep.add_output(var, val=default_vals[var], units=time_units) @@ -163,7 +163,8 @@ def setup_design_parameters(self, phase): phase._check_design_parameter_options() if phase.design_parameter_options: - indep = phase.add_subsystem('design_params', subsys=IndepVarComp(), + indep = phase.add_subsystem('design_params', + subsys=om.IndepVarComp(), promotes_outputs=['*']) for name, options in iteritems(phase.design_parameter_options): From 35430029c962821e2a8444f680b12915d1584710 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 26 Jun 2019 20:12:17 -0400 Subject: [PATCH 10/13] Ide friendly (#198) * Added more IDE-friendly methods for problem definition to Phase and Trajectory that will enable hints/autocompletion in IDEs. --- dymos/phase/phase.py | 401 +++++++++++++++++++++++++++------ dymos/trajectory/trajectory.py | 121 ++++++++-- 2 files changed, 431 insertions(+), 91 deletions(-) diff --git a/dymos/phase/phase.py b/dymos/phase/phase.py index 5df8d9b21..c23c5d902 100644 --- a/dymos/phase/phase.py +++ b/dymos/phase/phase.py @@ -104,7 +104,11 @@ def initialize(self): self.options.declare('transcription', types=TranscriptionBase, desc='Transcription technique of the optimal control problem.') - def set_state_options(self, name, **kwargs): + def set_state_options(self, name, units=_unspecified, rate_source=_unspecified, targets=_unspecified, + val=_unspecified, fix_initial=_unspecified, fix_final=_unspecified, + lower=_unspecified, upper=_unspecified, scaler=_unspecified, adder=_unspecified, + ref0=_unspecified, ref=_unspecified, defect_scaler=_unspecified, + defect_ref=_unspecified, solve_segments=_unspecified, connected_initial=_unspecified): """ Set options that apply the EOM state variable of the given name. @@ -118,6 +122,12 @@ def set_state_options(self, name, **kwargs): it in these units, and collocation defects will use these units. If units is not specified here then the value as defined in the ODEOptions (@dm.declare_state) will be used. + rate_source : str + The path to the ODE output which provides the rate of this state variable. If given + this will override the value given by the @declare_state decorator on the ODE. + targets : str or Sequence of str + The path to the targets of the state variable in the ODE system. If given + this will override the value given by the @declare_state decorator on the ODE. val : ndarray The default value of the state at the state discretization nodes of the phase. fix_initial : bool(False) @@ -150,24 +160,60 @@ def set_state_options(self, name, **kwargs): connected_initial : bool If True, then the initial value for this state comes from an externally connected source. - rate_source : str - The path to the ODE output which provides the rate of this state variable. - targets : str or Sequence of str - The path to the targets of the state variable in the ODE system. """ if name not in self.user_state_options: - self.user_state_options[name] = {} + self.user_state_options[name] = {'name': name} + + if units is not _unspecified: + self.user_state_options[name]['units'] = units + + if rate_source is not _unspecified: + self.user_state_options[name]['rate_source'] = rate_source + + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_state_options[name]['targets'] = (targets,) + else: + self.user_state_options[name]['targets'] = targets + + if val is not _unspecified: + self.user_state_options[name]['val'] = val + + if fix_initial is not _unspecified: + self.user_state_options[name]['fix_initial'] = fix_initial + + if fix_final is not _unspecified: + self.user_state_options[name]['fix_final'] = fix_final + + if lower is not _unspecified: + self.user_state_options[name]['lower'] = lower - kwargs['name'] = name + if upper is not _unspecified: + self.user_state_options[name]['upper'] = upper - for kw in kwargs: - if kw not in StateOptionsDictionary(): - raise KeyError('Invalid argument to set_state_options: {0}'.format(kw)) + if scaler is not _unspecified: + self.user_state_options[name]['scaler'] = scaler - if 'targets' in kwargs and isinstance(kwargs['targets'], string_types): - kwargs['targets'] = (kwargs['targets'],) + if adder is not _unspecified: + self.user_state_options[name]['adder'] = adder - self.user_state_options[name].update(kwargs) + if ref0 is not _unspecified: + self.user_state_options[name]['ref0'] = ref0 + + if ref is not _unspecified: + self.user_state_options[name]['ref'] = ref + + if defect_scaler is not _unspecified: + self.user_state_options[name]['defect_scaler'] = defect_scaler + + if defect_ref is not _unspecified: + self.user_state_options[name]['defect_ref'] = defect_ref + + if solve_segments is not _unspecified: + self.user_state_options[name]['solve_segments'] = solve_segments + + if connected_initial is not _unspecified: + self.user_state_options[name]['connected_initial'] = connected_initial def check_parameter(self, name): """ @@ -202,7 +248,14 @@ def check_parameter(self, name): raise ValueError('{0} has already been added as a trajectory-level ' 'parameter.'.format(name)) - def add_control(self, name, **kwargs): + def add_control(self, name, units=_unspecified, desc=_unspecified, opt=_unspecified, + fix_initial=_unspecified, fix_final=_unspecified, targets=_unspecified, + rate_targets=_unspecified, rate2_targets=_unspecified, val=_unspecified, + shape=_unspecified, lower=_unspecified, upper=_unspecified, scaler=_unspecified, + adder=_unspecified, ref0=_unspecified, ref=_unspecified, continuity=_unspecified, + continuity_scaler=_unspecified, rate_continuity=_unspecified, + rate_continuity_scaler=_unspecified, rate2_continuity=_unspecified, + rate2_continuity_scaler=_unspecified): """ Adds a dynamic control variable to be tied to a parameter in the ODE. @@ -256,6 +309,10 @@ def add_control(self, name, **kwargs): continuity : bool Enforce continuity of control values at segment boundaries. This option is invalid if opt=False. + continuity_scaler : bool + Scaler of the continuity constraint. This option is invalid if opt=False. This + option is only relevant in the Radau pseudospectral transcription where the continuity + constraint is nonlinear. For Gauss-Lobatto the continuity constraint is linear. rate_continuity : bool Enforce continuity of control first derivatives (in dimensionless time) at segment boundaries. @@ -269,12 +326,6 @@ def add_control(self, name, **kwargs): rate2_continuity_scaler : float Scaler of the dimensionless rate continuity constraint at segment boundaries. This option is invalid if opt=False. - dynamic : bool - If True, the value of the shape of the parameter will be (num_nodes, ...), - allowing the variable to be used as either a static or dynamic control. - This impacts the shape of the partial derivatives matrix. Unless a parameter is - large and broadcasting a value to each individual node would be inefficient, - users should stick to the default value of True.) Notes ----- @@ -284,21 +335,89 @@ def add_control(self, name, **kwargs): self.check_parameter(name) if name not in self.user_control_options: - self.user_control_options[name] = {} + self.user_control_options[name] = {'name': name} + + if units is not _unspecified: + self.user_control_options[name]['units'] = units + + if opt is not _unspecified: + self.user_control_options[name]['opt'] = opt + + if desc is not _unspecified: + self.user_control_options[name]['desc'] = desc + + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_control_options[name]['targets'] = (targets,) + else: + self.user_control_options[name]['targets'] = targets - kwargs['name'] = name + if rate_targets is not _unspecified: + if isinstance(rate_targets, string_types): + self.user_control_options[name]['rate_targets'] = (rate_targets,) + else: + self.user_control_options[name]['rate_targets'] = rate_targets + + if rate2_targets is not _unspecified: + if isinstance(rate2_targets, string_types): + self.user_control_options[name]['rate2_targets'] = (rate2_targets,) + else: + self.user_control_options[name]['rate2_targets'] = rate2_targets + + if val is not _unspecified: + self.user_control_options[name]['val'] = val + + if shape is not _unspecified: + self.user_control_options[name]['shape'] = shape + + if fix_initial is not _unspecified: + self.user_control_options[name]['fix_initial'] = fix_initial + + if fix_final is not _unspecified: + self.user_control_options[name]['fix_final'] = fix_final + + if lower is not _unspecified: + self.user_control_options[name]['lower'] = lower + + if upper is not _unspecified: + self.user_control_options[name]['upper'] = upper + + if scaler is not _unspecified: + self.user_control_options[name]['scaler'] = scaler + + if adder is not _unspecified: + self.user_control_options[name]['adder'] = adder + + if ref0 is not _unspecified: + self.user_control_options[name]['ref0'] = ref0 - for kw in kwargs: - if kw not in ControlOptionsDictionary(): - raise KeyError('Invalid argument to add_control: {0}'.format(kw)) + if ref is not _unspecified: + self.user_control_options[name]['ref'] = ref - for key in ('targets', 'rate_targets', 'rate2_targets'): - if key in kwargs and isinstance(kwargs[key], string_types): - kwargs[key] = (kwargs[key],) + if continuity is not _unspecified: + self.user_control_options[name]['continuity'] = continuity - self.user_control_options[name].update(kwargs) + if continuity_scaler is not _unspecified: + self.user_control_options[name]['continuity_scaler'] = continuity_scaler - def add_polynomial_control(self, name, **kwargs): + if rate_continuity is not _unspecified: + self.user_control_options[name]['rate_continuity'] = rate_continuity + + if rate_continuity_scaler is not _unspecified: + self.user_control_options[name]['rate_continuity_scaler'] = rate_continuity_scaler + + if rate2_continuity is not _unspecified: + self.user_control_options[name]['rate2_continuity'] = rate2_continuity + + if rate2_continuity_scaler is not _unspecified: + self.user_control_options[name]['rate2_continuity_scaler'] = rate2_continuity_scaler + + def add_polynomial_control(self, name, order, desc=_unspecified, val=_unspecified, units=_unspecified, + opt=_unspecified, fix_initial=_unspecified, fix_final=_unspecified, + lower=_unspecified, upper=_unspecified, + scaler=_unspecified, adder=_unspecified, ref0=_unspecified, + ref=_unspecified, targets=_unspecified, rate_targets=_unspecified, + rate2_targets=_unspecified, shape=_unspecified): """ Adds an polynomial control variable to be tied to a parameter in the ODE. @@ -318,13 +437,21 @@ def add_polynomial_control(self, name, **kwargs): val : float or ndarray Default value of the control at all nodes. If val scalar and the control is dynamic it will be broadcast. + desc : str + A description of the polynomial control. units : str or None or 0 Units in which the control variable is defined. If 0, use the units declared for the parameter in the ODE. opt : bool If True (default) the value(s) of this control will be design variables in the optimization problem, in the path 'phase_name.indep_controls.controls:control_name'. - If False, the values of this control will exist as aainput controls:{name} + If False, the values of this control will exist as input controls:{name} + fix_initial : bool + If True, the given initial value of the polynomial control is not a design variable and + will not be changed during the optimization. + fix_final : bool + If True, the given final value of the polynomial control is not a design variable and + will not be changed during the optimization. lower : float or ndarray The lower bound of the control at the nodes of the phase. upper : float or ndarray @@ -337,37 +464,84 @@ def add_polynomial_control(self, name, **kwargs): The zero-reference value of the control at the nodes of the phase. ref : float or ndarray The unit-reference value of the control at the nodes of the phase - rate_param : None or str + targets : Sequence of str or None + Targets in the ODE to which this polynomial control is connected. + rate_targets : None or str The name of the parameter in the ODE to which the first time-derivative of the control value is connected. - rate2_param : None or str + rate2_targets : None or str The name of the parameter in the ODE to which the second time-derivative of the control value is connected. - targets : Sequence of str or None - Targets in the ODE to which this polynomial control is connected. + shape : Sequence of int + The shape of the control variable at each point in time. """ self.check_parameter(name) if name not in self.user_polynomial_control_options: - self.user_polynomial_control_options[name] = {} + self.user_polynomial_control_options[name] = {'name': name, + 'order': order} + + if units is not _unspecified: + self.user_polynomial_control_options[name]['units'] = units + + if opt is not _unspecified: + self.user_polynomial_control_options[name]['opt'] = opt + + if desc is not _unspecified: + self.user_polynomial_control_options[name]['desc'] = desc + + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_polynomial_control_options[name]['targets'] = (targets,) + else: + self.user_polynomial_control_options[name]['targets'] = targets + + if rate_targets is not _unspecified: + if isinstance(rate_targets, string_types): + self.user_polynomial_control_options[name]['rate_targets'] = (rate_targets,) + else: + self.user_polynomial_control_options[name]['rate_targets'] = rate_targets + + if rate2_targets is not _unspecified: + if isinstance(rate2_targets, string_types): + self.user_polynomial_control_options[name]['rate2_targets'] = (rate2_targets,) + else: + self.user_polynomial_control_options[name]['rate2_targets'] = rate2_targets + + if val is not _unspecified: + self.user_polynomial_control_options[name]['val'] = val - if 'order' not in kwargs: - raise RuntimeError('Keyword argument \'order\' must be specified for polynomial ' - 'control \'{0}\''.format(name)) + if shape is not _unspecified: + self.user_polynomial_control_options[name]['shape'] = shape - kwargs['name'] = name + if fix_initial is not _unspecified: + self.user_polynomial_control_options[name]['fix_initial'] = fix_initial - for kw in kwargs: - if kw not in PolynomialControlOptionsDictionary(): - raise KeyError('Invalid argument to add_polynomial_control: {0}'.format(kw)) + if fix_final is not _unspecified: + self.user_polynomial_control_options[name]['fix_final'] = fix_final - for key in ('targets', 'rate_targets', 'rate2_targets'): - if key in kwargs and isinstance(kwargs[key], string_types): - kwargs[key] = (kwargs[key],) + if lower is not _unspecified: + self.user_polynomial_control_options[name]['lower'] = lower - self.user_polynomial_control_options[name].update(kwargs) + if upper is not _unspecified: + self.user_polynomial_control_options[name]['upper'] = upper - def add_design_parameter(self, name, **kwargs): + if scaler is not _unspecified: + self.user_polynomial_control_options[name]['scaler'] = scaler + + if adder is not _unspecified: + self.user_polynomial_control_options[name]['adder'] = adder + + if ref0 is not _unspecified: + self.user_polynomial_control_options[name]['ref0'] = ref0 + + if ref is not _unspecified: + self.user_polynomial_control_options[name]['ref'] = ref + + def add_design_parameter(self, name, val=_unspecified, units=_unspecified, opt=_unspecified, + desc=_unspecified, lower=_unspecified, upper=_unspecified, scaler=_unspecified, + adder=_unspecified, ref0=_unspecified, ref=_unspecified, targets=_unspecified, + shape=_unspecified, dynamic=_unspecified): """ Add a design parameter (static control variable) to the phase. @@ -385,6 +559,8 @@ def add_design_parameter(self, name, **kwargs): the optimization problem, in the path 'phase_name.indep_controls.controls:control_name'. If False, the this design parameter will still be owned by an IndepVarComp in the phase, but it will not be a design variable in the optimization. + desc : str + A description of the design parameter. lower : float or ndarray The lower bound of the design parameter value. upper : float or ndarray @@ -399,25 +575,61 @@ def add_design_parameter(self, name, **kwargs): The unit-reference value of the design parameter for the optimizer. targets : Sequence of str or None Targets in the ODE to which this parameter is connected. - + shape : Sequence of int + The shape of the design parameter. + dynamic : bool + True if the targets in the ODE may be dynamic (if the inputs are sized to the number + of nodes) else False. """ self.check_parameter(name) if name not in self.user_design_parameter_options: - self.user_design_parameter_options[name] = {} + self.user_design_parameter_options[name] = {'name': name} + + if units is not _unspecified: + self.user_design_parameter_options[name]['units'] = units + + if opt is not _unspecified: + self.user_design_parameter_options[name]['opt'] = opt + + if desc is not _unspecified: + self.user_design_parameter_options[name]['desc'] = desc - kwargs['name'] = name + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_design_parameter_options[name]['targets'] = (targets,) + else: + self.user_design_parameter_options[name]['targets'] = targets + + if val is not _unspecified: + self.user_design_parameter_options[name]['val'] = val + + if shape is not _unspecified: + self.user_design_parameter_options[name]['shape'] = shape + + if dynamic is not _unspecified: + self.user_design_parameter_options[name]['dynamic'] = dynamic + + if lower is not _unspecified: + self.user_design_parameter_options[name]['lower'] = lower + + if upper is not _unspecified: + self.user_design_parameter_options[name]['upper'] = upper - for kw in kwargs: - if kw not in DesignParameterOptionsDictionary(): - raise KeyError('Invalid argument to add_design_parameter: {0}'.format(kw)) + if scaler is not _unspecified: + self.user_design_parameter_options[name]['scaler'] = scaler - if 'targets' in kwargs and isinstance(kwargs['targets'], string_types): - kwargs['targets'] = (kwargs['targets'],) + if adder is not _unspecified: + self.user_design_parameter_options[name]['adder'] = adder - self.user_design_parameter_options[name].update(kwargs) + if ref0 is not _unspecified: + self.user_design_parameter_options[name]['ref0'] = ref0 - def add_input_parameter(self, name, **kwargs): + if ref is not _unspecified: + self.user_design_parameter_options[name]['ref'] = ref + + def add_input_parameter(self, name, val=_unspecified, units=_unspecified, targets=_unspecified, + desc=_unspecified, shape=_unspecified, dynamic=_unspecified): """ Add an input parameter (static control variable) to the phase. @@ -430,26 +642,46 @@ def add_input_parameter(self, name, **kwargs): units : str or None or 0 Units in which the design parameter is defined. If 0, use the units declared for the parameter in the ODE. + desc : str + A description of the input parameter + targets : Sequence of str or None + Targets in the ODE to which this parameter is connected. + shape : Sequence of str or None + Targets in the ODE to which this parameter is connected. + dynamic : bool + True if the targets in the ODE may be dynamic (if the inputs are sized to the number + of nodes) else False. targets : Sequence of str or None Targets in the ODE to which this parameter is connected. """ self.check_parameter(name) if name not in self.user_input_parameter_options: - self.user_input_parameter_options[name] = {} + self.user_input_parameter_options[name] = {'name': name} - kwargs['name'] = name + if units is not _unspecified: + self.user_input_parameter_options[name]['units'] = units - for kw in kwargs: - if kw not in InputParameterOptionsDictionary(): - raise KeyError('Invalid argument to add_input_parameter: {0}'.format(kw)) + if val is not _unspecified: + self.user_input_parameter_options[name]['val'] = val - if 'targets' in kwargs and isinstance(kwargs['targets'], string_types): - kwargs['targets'] = (kwargs['targets'],) + if desc is not _unspecified: + self.user_input_parameter_options[name]['desc'] = desc - self.user_input_parameter_options[name].update(kwargs) + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_input_parameter_options[name]['targets'] = (targets,) + else: + self.user_input_parameter_options[name]['targets'] = targets + + if shape is not _unspecified: + self.user_input_parameter_options[name]['shape'] = shape + + if dynamic is not _unspecified: + self.user_input_parameter_options[name]['dynamic'] = dynamic - def add_traj_parameter(self, name, **kwargs): + def add_traj_parameter(self, name, val=_unspecified, units=_unspecified, targets=_unspecified, + desc=_unspecified, shape=_unspecified, dynamic=_unspecified): """ Add an input parameter to the phase that is connected to an input or design parameter in the parent trajectory. @@ -463,24 +695,43 @@ def add_traj_parameter(self, name, **kwargs): units : str or None or 0 Units in which the design parameter is defined. If 0, use the units declared for the parameter in the ODE. + desc : str + A description of the input parameter + targets : Sequence of str or None + Targets in the ODE to which this parameter is connected. + shape : Sequence of str or None + Targets in the ODE to which this parameter is connected. + dynamic : bool + True if the targets in the ODE may be dynamic (if the inputs are sized to the number + of nodes) else False. targets : Sequence of str or None Targets in the ODE to which this parameter is connected. """ self.check_parameter(name) if name not in self.user_traj_parameter_options: - self.user_traj_parameter_options[name] = {} + self.user_traj_parameter_options[name] = {'name': name} + + if units is not _unspecified: + self.user_traj_parameter_options[name]['units'] = units - kwargs['name'] = name + if val is not _unspecified: + self.user_traj_parameter_options[name]['val'] = val - for kw in kwargs: - if kw not in InputParameterOptionsDictionary(): - raise KeyError('Invalid argument to add_traj_parameter: {0}'.format(kw)) + if desc is not _unspecified: + self.user_traj_parameter_options[name]['desc'] = desc + + if targets is not _unspecified: + if isinstance(targets, string_types): + self.user_traj_parameter_options[name]['targets'] = (targets,) + else: + self.user_traj_parameter_options[name]['targets'] = targets - if 'targets' in kwargs and isinstance(kwargs['targets'], string_types): - kwargs['targets'] = (kwargs['targets'],) + if shape is not _unspecified: + self.user_traj_parameter_options[name]['shape'] = shape - self.user_traj_parameter_options[name].update(kwargs) + if dynamic is not _unspecified: + self.user_traj_parameter_options[name]['dynamic'] = dynamic def add_boundary_constraint(self, name, loc, constraint_name=None, units=None, shape=None, indices=None, lower=None, upper=None, equals=None, diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index 81c45d526..dde115248 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -20,6 +20,9 @@ TrajInputParameterOptionsDictionary +_unspecified = object() + + class Trajectory(om.Group): """ A Trajectory object serves as a container for one or more Phases, as well as the linkage @@ -62,34 +65,68 @@ def add_phase(self, name, phase, **kwargs): self._phase_add_kwargs[name] = kwargs return phase - def add_input_parameter(self, name, **kwargs): + def add_input_parameter(self, name, units, val=_unspecified, desc=_unspecified, + targets=_unspecified, custom_targets=_unspecified, + shape=_unspecified, dynamic=_unspecified): """ - Add a design parameter (static control) to the trajectory. + Add na input parameter to the trajectory. Parameters ---------- name : str - Name of the design parameter. + Name of the input parameter. val : float or ndarray - Default value of the design parameter at all nodes. + Default value of the input parameter at all nodes. + desc : str + A description of the input parameter. custom_targets : dict or None By default, the input parameter will be connect to the parameter/targets of the given name in each phase. This argument can be used to override that behavior on a phase by phase basis. units : str or None or 0 - Units in which the design parameter is defined. If 0, use the units declared + Units in which the input parameter is defined. If 0, use the units declared for the parameter in the ODE. + shape : Sequence of int + The shape of the input parameter. + dynamic : bool + True if the targets in the ODE may be dynamic (if the inputs are sized to the number + of nodes) else False. """ if name not in self.input_parameter_options: self.input_parameter_options[name] = TrajInputParameterOptionsDictionary() - for kw in kwargs: - if kw not in self.input_parameter_options[name]: - raise KeyError('Invalid argument to add_input_parameter: {0}'.format(kw)) + if units is not _unspecified: + self.input_parameter_options[name]['units'] = units + + if val is not _unspecified: + self.input_parameter_options[name]['val'] = val - self.input_parameter_options[name].update(kwargs) + if desc is not _unspecified: + self.input_parameter_options[name]['desc'] = desc - def add_design_parameter(self, name, **kwargs): + if targets is not _unspecified: + if isinstance(targets, string_types): + self.input_parameter_options[name]['targets'] = (targets,) + else: + self.input_parameter_options[name]['targets'] = targets + + if custom_targets is not _unspecified: + if isinstance(targets, string_types): + self.input_parameter_options[name]['custom_targets'] = (custom_targets,) + else: + self.input_parameter_options[name]['custom_targets'] = custom_targets + + if shape is not _unspecified: + self.input_parameter_options[name]['shape'] = shape + + if dynamic is not _unspecified: + self.input_parameter_options[name]['dynamic'] = dynamic + + def add_design_parameter(self, name, units, val=_unspecified, desc=_unspecified, opt=_unspecified, + targets=_unspecified, custom_targets=_unspecified, + lower=_unspecified, upper=_unspecified, scaler=_unspecified, + adder=_unspecified, ref0=_unspecified, ref=_unspecified, + shape=_unspecified, dynamic=_unspecified): """ Add a design parameter (static control) to the trajectory. @@ -99,12 +136,18 @@ def add_design_parameter(self, name, **kwargs): Name of the design parameter. val : float or ndarray Default value of the design parameter at all nodes. + desc : str + A description of the design parameter. targets : dict or None If None, then the design parameter will be connected to the controllable parameter in the ODE of each phase. For each phase where no such controllable parameter exists, a warning will be issued. If targets is given as a dict, the dict should provide the relevant phase names as keys, each associated with the respective controllable - parameteter as a value. + parameter as a value. + custom_targets : dict or None + By default, the input parameter will be connect to the parameter/targets of the given + name in each phase. This argument can be used to override that behavior on a phase + by phase basis. units : str or None or 0 Units in which the design parameter is defined. If 0, use the units declared for the parameter in the ODE. @@ -126,16 +169,62 @@ def add_design_parameter(self, name, **kwargs): The zero-reference value of the design parameter for the optimizer. ref : float or ndarray The unit-reference value of the design parameter for the optimizer. - + shape : Sequence of int + The shape of the design parameter. + dynamic : bool + True if the targets in the ODE may be dynamic (if the inputs are sized to the number + of nodes) else False. """ if name not in self.design_parameter_options: self.design_parameter_options[name] = TrajDesignParameterOptionsDictionary() - for kw in kwargs: - if kw not in self.design_parameter_options[name]: - raise KeyError('Invalid argument to add_design_parameter: {0}'.format(kw)) + if units is not _unspecified: + self.design_parameter_options[name]['units'] = units + + if opt is not _unspecified: + self.design_parameter_options[name]['opt'] = opt + + if val is not _unspecified: + self.design_parameter_options[name]['val'] = val + + if desc is not _unspecified: + self.design_parameter_options[name]['desc'] = desc + + if lower is not _unspecified: + self.design_parameter_options[name]['lower'] = lower + + if upper is not _unspecified: + self.design_parameter_options[name]['upper'] = upper + + if scaler is not _unspecified: + self.design_parameter_options[name]['scaler'] = scaler + + if adder is not _unspecified: + self.design_parameter_options[name]['adder'] = adder + + if ref0 is not _unspecified: + self.design_parameter_options[name]['ref0'] = ref0 + + if ref is not _unspecified: + self.design_parameter_options[name]['ref'] = ref + + if targets is not _unspecified: + if isinstance(targets, string_types): + self.design_parameter_options[name]['targets'] = (targets,) + else: + self.design_parameter_options[name]['targets'] = targets + + if custom_targets is not _unspecified: + if isinstance(targets, string_types): + self.design_parameter_options[name]['custom_targets'] = (custom_targets,) + else: + self.design_parameter_options[name]['custom_targets'] = custom_targets + + if shape is not _unspecified: + self.design_parameter_options[name]['shape'] = shape - self.design_parameter_options[name].update(kwargs) + if dynamic is not _unspecified: + self.design_parameter_options[name]['dynamic'] = dynamic def _setup_input_parameters(self): """ From 6382097f8077d2fee232faffaa61979378d2dc34 Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 17 Jul 2019 15:37:07 -0400 Subject: [PATCH 11/13] Interpolated timeseries (#202) * added ability to add additional timeseries outputs and control which variables are on each timeseries, and what grid each timeseries uses for output. the default timeseries just outputs to all nodes of its phases grid. * interleave component added to gauss lobatto phases, still needs to connect to updated downstream path constraint and timeseries objects. * Made a common path constraint comp for pseudospectral transcriptions. * Added interpolated timeseries to Gauss Lobatto and Radau Transcriptions. Added an interleave component to gauss lobatto to get contiguous outputs of states and ODE outputs, allowing more consistency in the path constraint and timeseries components. Added interpolated timeseries output to RK phases, but that implementation needs more testing. * fixed issue with tensor interpolation in the RK timeseries comp * added in the gauss lobatto interleave comp * GaussLobatto and Radau timeseries now interpolating correctly, still working on RK. * tandem phases/interpolated timeseries working for GL, Radau, and RK transcriptions. example for documentation is next. * Added documentation for tandem phases and interpolating timeseries * revert min time climb back to default coloring settings --- .../feature_reference/feature_reference.rst | 1 + .../docs/feature_reference/tandem_phases.rst | 52 +++ dymos/docs/feature_reference/timeseries.rst | 11 + .../test_doc_brachistochrone_tandem_phases.py | 186 ++++++++ .../test/ex_brachistochrone.py | 11 +- .../test/test_ex_brachistochrone.py | 1 + .../test_ex_brachistochrone_vector_states.py | 3 +- .../test/test_tandem_phases.py | 196 +++++++++ .../doc/test_doc_min_time_climb.py | 7 +- .../test/test_ex_min_time_climb.py | 2 +- dymos/phase/phase.py | 46 +- dymos/transcriptions/common/__init__.py | 6 +- .../common/path_constraint_comp.py | 260 ++++++----- .../common/test/test_path_constraint_comp.py | 129 +----- .../common/timeseries_output_comp.py | 214 ++++----- dymos/transcriptions/grid_data.py | 3 +- .../pseudospectral/components/__init__.py | 1 + .../gauss_lobatto_interleave_comp.py | 96 +++++ .../test_gauss_lobatto_interleave_comp.py | 107 +++++ .../pseudospectral/gauss_lobatto.py | 407 +++++++++++------- .../pseudospectral/radau_pseudospectral.py | 295 +++++++------ .../runge_kutta_path_constraint_comp.py | 113 +++-- .../components/runge_kutta_timeseries_comp.py | 80 +++- .../test/test_rk_path_constraint_comp.py | 158 +++---- .../transcriptions/runge_kutta/runge_kutta.py | 295 +++++++------ .../test/test_rk4_simple_integration.py | 10 +- .../components/solve_ivp_timeseries_comp.py | 2 +- dymos/transcriptions/solve_ivp/solve_ivp.py | 4 +- dymos/transcriptions/transcription_base.py | 31 +- release_notes.txt | 51 --- 30 files changed, 1724 insertions(+), 1054 deletions(-) create mode 100644 dymos/docs/feature_reference/tandem_phases.rst create mode 100644 dymos/examples/brachistochrone/doc/test_doc_brachistochrone_tandem_phases.py create mode 100644 dymos/examples/brachistochrone/test/test_tandem_phases.py create mode 100644 dymos/transcriptions/pseudospectral/components/gauss_lobatto_interleave_comp.py create mode 100644 dymos/transcriptions/pseudospectral/components/test/test_gauss_lobatto_interleave_comp.py delete mode 100644 release_notes.txt diff --git a/dymos/docs/feature_reference/feature_reference.rst b/dymos/docs/feature_reference/feature_reference.rst index d9241d1a8..6d8700342 100644 --- a/dymos/docs/feature_reference/feature_reference.rst +++ b/dymos/docs/feature_reference/feature_reference.rst @@ -18,4 +18,5 @@ problems. phases/phases trajectories timeseries + tandem_phases simultaneous_derivs diff --git a/dymos/docs/feature_reference/tandem_phases.rst b/dymos/docs/feature_reference/tandem_phases.rst new file mode 100644 index 000000000..28c657a9e --- /dev/null +++ b/dymos/docs/feature_reference/tandem_phases.rst @@ -0,0 +1,52 @@ +========================================================== +Tandem Phases: Using different ODE simultaneously in time +========================================================== + +Complex models sometimes encounter state variables which are best simulated on different time +scales, with some state variables changing quickly (fast variables) and some evolving slowly (slow variables). +For instance, and aircraft trajectory optimization which includes vehicle component temperatures might +see relatively gradual changes in altitude over the course of a two hour flight while temperatures of +some components seem to exhibit step-function-like behavior on the same scale. + +To accommodate both fast and slow variables in the same ODE, one would typically need to use a _dense_ +grid (with many segments/higher order segments). This can be unnecessarily burdensome when there are +many slow variables or evaluating their rates is particularly expensive. + +As a solution, Dymos allows the user to run two phases over the same range of times, where one +phase may have a more sparse grid to accommodate the slow variables, and one has a more dense grid +for the fast variables. + +To connect the two phases, state variable values are passed from the first (slow) phase to the second +(fast) phase as non-optimal dynamic control variables. These values are then used to evaluate the +rates of the fast variables. Since outputs from the first phase in generally will not fall on the +appropriate grid points to be used by the second phase, interpolation is necessary. This is one +application of the interpolating timeseries component. + +In the following example, we solve the brachistochrone problem but do so to minimize the arclength +of the resulting wire instead of the time required for the bead to travel along the wire. +This is a trivial solution which should find a straight line from the starting point to the ending point. +There are two phases involved, the first utilizes the standard ODE for the brachistochrone problem. +The second integrates the arclength (:math:`S`) of the wire using the equation: + +.. math:: + + S = \int v \sin \theta \sqrt{1 + \frac{1}{\tan^2 \theta}} \, dt + +.. embed-code:: + dymos.examples.brachistochrone.doc.test_doc_brachistochrone_tandem_phases.BrachistochroneArclengthODE + :layout: code + +The trick is that the bead velocity (:math:`v`) is a state variable solved for in the first phase, +and the wire angle (:math:`\theta`) is a control variable "owned" by the first phase. In the +second phase they are used as control variables with option ``opt=False`` so that their values are +expected as inputs for the second phase. We need to connect their values from the first phase +to the second phase, at the :code:`control_input` node subset of the second phase. + +In the following example, we instantiate two phases and add an interpolating timeseries to the first phase +which provides outputs at the :code:`control_input` nodes of the second phase. Those values are +then connected and the entire problem run. The result is that the position and velocity variables +are solved on a relatively coarse grid while the arclength of the wire is solved on a much denser grid. + +.. embed-code:: + dymos.examples.brachistochrone.doc.test_doc_brachistochrone_tandem_phases.TestDocTandemPhases.test_tandem_phases_for_docs + :layout: code, plot diff --git a/dymos/docs/feature_reference/timeseries.rst b/dymos/docs/feature_reference/timeseries.rst index f87c05c52..832ea8e32 100644 --- a/dymos/docs/feature_reference/timeseries.rst +++ b/dymos/docs/feature_reference/timeseries.rst @@ -37,3 +37,14 @@ using the ``add_timeseries_output`` method on Phase. These outputs are availabl .. automethod:: dymos.Phase.add_timeseries_output :noindex: +Interpolated Timeseries Outputs +=============================== + +Sometimes a user may want to interpolate the results of a phase onto a different grid. This is particularly +useful in the context of tandem phases. Additional timeseries may be added to a phase using the +``add_timeseries`` method. By default all timeseries will provide times, states, controls, and +parameters on the specified output grid. Adding other variables is accomplished using the +``timeseries`` argument in the ``add_timeseries_output`` method. + +.. automethod:: dymos.Phase.add_timeseries + :noindex: diff --git a/dymos/examples/brachistochrone/doc/test_doc_brachistochrone_tandem_phases.py b/dymos/examples/brachistochrone/doc/test_doc_brachistochrone_tandem_phases.py new file mode 100644 index 000000000..234f8176a --- /dev/null +++ b/dymos/examples/brachistochrone/doc/test_doc_brachistochrone_tandem_phases.py @@ -0,0 +1,186 @@ +from __future__ import print_function, division, absolute_import + +import unittest + +from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE + +import numpy as np +import matplotlib.pyplot as plt +import openmdao.api as om +import dymos as dm + +from openmdao.utils.assert_utils import assert_rel_error + + +plt.switch_backend('Agg') + + +@dm.declare_time(units='s') +@dm.declare_state('S', rate_source='Sdot', units='m') +@dm.declare_parameter('v', targets='v', units='m/s') +@dm.declare_parameter('theta', targets='theta', units='rad') +class BrachistochroneArclengthODE(om.ExplicitComponent): + + def initialize(self): + self.options.declare('num_nodes', types=int) + + def setup(self): + nn = self.options['num_nodes'] + + # Inputs + self.add_input('v', val=np.zeros(nn), desc='velocity', units='m/s') + self.add_input('theta', val=np.zeros(nn), desc='angle of wire', units='rad') + self.add_output('Sdot', val=np.zeros(nn), desc='rate of change of arclength', units='m/s') + + # Setup partials + arange = np.arange(self.options['num_nodes']) + + self.declare_partials(of='Sdot', wrt='v', rows=arange, cols=arange) + self.declare_partials(of='Sdot', wrt='theta', rows=arange, cols=arange) + + def compute(self, inputs, outputs): + theta = inputs['theta'] + v = inputs['v'] + outputs['Sdot'] = np.sqrt(1.0 + (1.0/np.tan(theta))**2) * v * np.sin(theta) + + def compute_partials(self, inputs, jacobian): + theta = inputs['theta'] + v = inputs['v'] + cos_theta = np.cos(theta) + sin_theta = np.sin(theta) + tan_theta = np.tan(theta) + cot_theta = 1.0 / tan_theta + csc_theta = 1.0 / sin_theta + + jacobian['Sdot', 'v'] = sin_theta * np.sqrt(1.0 + cot_theta**2) + jacobian['Sdot', 'theta'] = v * (cos_theta * (cot_theta**2 + 1) - cot_theta * csc_theta) / \ + (np.sqrt(1 + cot_theta**2)) + + +def make_brachistochrone_phase(transcription='gauss-lobatto', num_segments=8, transcription_order=3, + compressed=True): + + if transcription == 'gauss-lobatto': + t = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + elif transcription == 'radau-ps': + t = dm.Radau(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + elif transcription == 'runge-kutta': + t = dm.RungeKutta(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) + + return phase + + +class TestDocTandemPhases(unittest.TestCase): + + def test_tandem_phases_for_docs(self): + p = om.Problem(model=om.Group()) + + p.driver = om.pyOptSparseDriver() + p.driver.options['optimizer'] = 'SLSQP' + p.driver.declare_coloring() + + # + # First Phase: Standard Brachistochrone + # + num_segments = 10 + transcription_order = 3 + compressed = False + + tx0 = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + + tx1 = dm.Radau(num_segments=num_segments*2, + order=transcription_order*3, + compressed=compressed) + + phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0) + + p.model.add_subsystem('phase0', phase0) + + phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) + + phase0.set_state_options('x', fix_initial=True, fix_final=False, solve_segments=False) + phase0.set_state_options('y', fix_initial=True, fix_final=False, solve_segments=False) + phase0.set_state_options('v', fix_initial=True, fix_final=False, solve_segments=False) + + phase0.add_control('theta', continuity=True, rate_continuity=True, + units='deg', lower=0.1, upper=179.0) + + phase0.add_input_parameter('g', units='m/s**2', val=9.80665) + + phase0.add_boundary_constraint('x', loc='final', equals=10) + phase0.add_boundary_constraint('y', loc='final', equals=5) + + # Add alternative timeseries output to provide control inputs for the next phase + phase0.add_timeseries('timeseries2', transcription=tx1, subset='control_input') + + # + # Second Phase: Integration of ArcLength + # + + phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE, transcription=tx1) + + p.model.add_subsystem('phase1', phase1) + + phase1.set_time_options(fix_initial=True, input_duration=True) + + phase1.set_state_options('S', fix_initial=True, fix_final=False) + + phase1.add_control('theta', opt=False, units='deg') + phase1.add_control('v', opt=False, units='m/s') + + # + # Connect the two phases + # + p.model.connect('phase0.t_duration', 'phase1.t_duration') + + p.model.connect('phase0.timeseries2.controls:theta', 'phase1.controls:theta') + p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v') + + # Minimize time at the end of the phase + # phase1.add_objective('time', loc='final', scaler=1) + # phase1.add_boundary_constraint('S', loc='final', upper=12) + + phase1.add_objective('S', loc='final', ref=1) + + p.model.linear_solver = om.DirectSolver() + p.setup(check=True) + + p['phase0.t_initial'] = 0.0 + p['phase0.t_duration'] = 2.0 + + p['phase0.states:x'] = phase0.interpolate(ys=[0, 10], nodes='state_input') + p['phase0.states:y'] = phase0.interpolate(ys=[10, 5], nodes='state_input') + p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9], nodes='state_input') + p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100], nodes='control_input') + p['phase0.input_parameters:g'] = 9.80665 + + p['phase1.states:S'] = 0.0 + + p.run_driver() + + expected = np.sqrt((10-0)**2 + (10 - 5)**2) + assert_rel_error(self, p['phase1.timeseries.states:S'][-1], expected, tolerance=1.0E-3) + + fig, (ax0, ax1) = plt.subplots(2, 1) + fig.tight_layout() + ax0.plot(p.get_val('phase0.timeseries.states:x'), p.get_val('phase0.timeseries.states:y'), '.') + ax0.set_xlabel('x (m)') + ax0.set_ylabel('y (m)') + ax1.plot(p.get_val('phase1.timeseries.time'), p.get_val('phase1.timeseries.states:S'), '+') + ax1.set_xlabel('t (s)') + ax1.set_ylabel('S (m)') + plt.show() + + +if __name__ == '__main__': + unittest.main() diff --git a/dymos/examples/brachistochrone/test/ex_brachistochrone.py b/dymos/examples/brachistochrone/test/ex_brachistochrone.py index 8d30f7c8c..e034e1ab1 100644 --- a/dymos/examples/brachistochrone/test/ex_brachistochrone.py +++ b/dymos/examples/brachistochrone/test/ex_brachistochrone.py @@ -48,6 +48,12 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran phase.add_input_parameter('g', units='m/s**2', val=9.80665) + phase.add_timeseries('timeseries2', + transcription=dm.Radau(num_segments=num_segments*5, + order=transcription_order, + compressed=compressed), + subset='control_input') + phase.add_boundary_constraint('x', loc='final', equals=10) phase.add_boundary_constraint('y', loc='final', equals=5) # Minimize time at the end of the phase @@ -65,10 +71,7 @@ def brachistochrone_min_time(transcription='gauss-lobatto', num_segments=8, tran p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.input_parameters:g'] = 9.80665 - p.run_model() - - if run_driver: - p.run_driver() + p.run_driver() # Plot results if SHOW_PLOTS: diff --git a/dymos/examples/brachistochrone/test/test_ex_brachistochrone.py b/dymos/examples/brachistochrone/test/test_ex_brachistochrone.py index bddb9297a..8ee0ce112 100644 --- a/dymos/examples/brachistochrone/test/test_ex_brachistochrone.py +++ b/dymos/examples/brachistochrone/test/test_ex_brachistochrone.py @@ -6,6 +6,7 @@ import dymos.examples.brachistochrone.test.ex_brachistochrone as ex_brachistochrone +import openmdao.api as om from openmdao.utils.general_utils import set_pyoptsparse_opt OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT', fallback=True) 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 f80f41aa4..ef025fb6e 100644 --- a/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py +++ b/dymos/examples/brachistochrone/test/test_ex_brachistochrone_vector_states.py @@ -48,7 +48,8 @@ def assert_results(self, p): assert_almost_equal(thetaf, 100.12, decimal=0) def assert_partials(self, p): - cpd = p.check_partials(method='cs', out_stream=None) + with np.printoptions(linewidth=1024, edgeitems=100): + cpd = p.check_partials(method='cs') assert_check_partials(cpd) def test_ex_brachistochrone_vs_radau_compressed(self): diff --git a/dymos/examples/brachistochrone/test/test_tandem_phases.py b/dymos/examples/brachistochrone/test/test_tandem_phases.py new file mode 100644 index 000000000..d4241004f --- /dev/null +++ b/dymos/examples/brachistochrone/test/test_tandem_phases.py @@ -0,0 +1,196 @@ +from __future__ import print_function, division, absolute_import + +import unittest + +from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE + +SHOW_PLOTS = True + +import numpy as np +import openmdao.api as om +import dymos as dm + +from openmdao.utils.assert_utils import assert_rel_error, assert_check_partials + + +@dm.declare_time(units='s') +@dm.declare_state('S', rate_source='Sdot', units='m') +@dm.declare_parameter('v', targets='v', units='m/s') +@dm.declare_parameter('theta', targets='theta', units='rad') +class BrachistochroneArclengthODE(om.ExplicitComponent): + + def initialize(self): + self.options.declare('num_nodes', types=int) + + def setup(self): + nn = self.options['num_nodes'] + + # Inputs + self.add_input('v', val=np.zeros(nn), desc='velocity', units='m/s') + self.add_input('theta', val=np.zeros(nn), desc='angle of wire', units='rad') + self.add_output('Sdot', val=np.zeros(nn), desc='rate of change of arclength', units='m/s') + + # Setup partials + arange = np.arange(self.options['num_nodes']) + + self.declare_partials(of='Sdot', wrt='v', rows=arange, cols=arange) + self.declare_partials(of='Sdot', wrt='theta', rows=arange, cols=arange) + + def compute(self, inputs, outputs): + theta = inputs['theta'] + v = inputs['v'] + outputs['Sdot'] = np.sqrt(1.0 + (1.0/np.tan(theta))**2) * v * np.sin(theta) + + def compute_partials(self, inputs, jacobian): + theta = inputs['theta'] + v = inputs['v'] + cos_theta = np.cos(theta) + sin_theta = np.sin(theta) + tan_theta = np.tan(theta) + cot_theta = 1.0 / tan_theta + csc_theta = 1.0 / sin_theta + + jacobian['Sdot', 'v'] = sin_theta * np.sqrt(1.0 + cot_theta**2) + jacobian['Sdot', 'theta'] = v * (cos_theta * (cot_theta**2 + 1) - cot_theta * csc_theta) / \ + (np.sqrt(1 + cot_theta**2)) + + +def make_brachistochrone_phase(transcription='gauss-lobatto', num_segments=8, transcription_order=3, + compressed=True): + + if transcription == 'gauss-lobatto': + t = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + elif transcription == 'radau-ps': + t = dm.Radau(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + elif transcription == 'runge-kutta': + t = dm.RungeKutta(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + + phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) + + return phase + + +class TestTandemPhases(unittest.TestCase): + + def _run_transcription(self, transcription): + p = om.Problem(model=om.Group()) + + p.driver = om.pyOptSparseDriver() + p.driver.options['optimizer'] = 'SLSQP' + p.driver.declare_coloring() + + # + # First Phase: Standard Brachistochrone + # + num_segments = 10 + transcription_order = 3 + compressed = False + + if transcription == 'gauss-lobatto': + tx0 = dm.GaussLobatto(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + tx1 = dm.GaussLobatto(num_segments=num_segments*2, order=transcription_order*3, + compressed=compressed) + + elif transcription == 'radau-ps': + tx0 = dm.Radau(num_segments=num_segments, + order=transcription_order, + compressed=compressed) + tx1 = dm.Radau(num_segments=num_segments*2, + order=transcription_order*3, + compressed=compressed) + + elif transcription == 'runge-kutta': + tx0 = dm.RungeKutta(num_segments=20, + compressed=compressed) + tx1 = dm.RungeKutta(num_segments=20*4, + compressed=compressed) + + phase0 = dm.Phase(ode_class=BrachistochroneODE, transcription=tx0) + + p.model.add_subsystem('phase0', phase0) + + phase0.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) + + phase0.set_state_options('x', fix_initial=True, fix_final=False, solve_segments=False) + phase0.set_state_options('y', fix_initial=True, fix_final=False, solve_segments=False) + phase0.set_state_options('v', fix_initial=True, fix_final=False, solve_segments=False) + + phase0.add_control('theta', continuity=True, rate_continuity=True, + units='deg', lower=0.1, upper=179.0) + + phase0.add_input_parameter('g', units='m/s**2', val=9.80665) + + phase0.add_boundary_constraint('x', loc='final', equals=10) + phase0.add_boundary_constraint('y', loc='final', equals=5) + + # Add alternative timeseries output to provide control inputs for the next phase + phase0.add_timeseries('timeseries2', transcription=tx1, subset='control_input') + + # + # Second Phase: Integration of ArcLength + # + + phase1 = dm.Phase(ode_class=BrachistochroneArclengthODE, transcription=tx1) + + p.model.add_subsystem('phase1', phase1) + + phase1.set_time_options(fix_initial=True, input_duration=True) + + phase1.set_state_options('S', fix_initial=True, fix_final=False) + + phase1.add_control('theta', opt=False, units='deg') + phase1.add_control('v', opt=False, units='m/s') + + # + # Connect the two phases + # + p.model.connect('phase0.t_duration', 'phase1.t_duration') + + p.model.connect('phase0.timeseries2.controls:theta', 'phase1.controls:theta') + p.model.connect('phase0.timeseries2.states:v', 'phase1.controls:v') + + # Minimize time at the end of the phase + # phase1.add_objective('time', loc='final', scaler=1) + # phase1.add_boundary_constraint('S', loc='final', upper=12) + + phase1.add_objective('S', loc='final', ref=1) + + p.model.linear_solver = om.DirectSolver() + p.setup(check=True) + + p['phase0.t_initial'] = 0.0 + p['phase0.t_duration'] = 2.0 + + p['phase0.states:x'] = phase0.interpolate(ys=[0, 10], nodes='state_input') + p['phase0.states:y'] = phase0.interpolate(ys=[10, 5], nodes='state_input') + p['phase0.states:v'] = phase0.interpolate(ys=[0, 9.9], nodes='state_input') + p['phase0.controls:theta'] = phase0.interpolate(ys=[5, 100], nodes='control_input') + p['phase0.input_parameters:g'] = 9.80665 + + p['phase1.states:S'] = 0.0 + + p.run_driver() + + expected = np.sqrt((10-0)**2 + (10 - 5)**2) + assert_rel_error(self, p['phase1.timeseries.states:S'][-1], expected, tolerance=1.0E-3) + + def test_tandem_phases_radau(self): + self._run_transcription('radau-ps') + + def test_tandem_phases_gl(self): + self._run_transcription('gauss-lobatto') + + def test_tandem_phases_rk(self): + self._run_transcription('runge-kutta') + + +if __name__ == '__main__': + unittest.main() diff --git a/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py b/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py index d51c7f682..9a51b4bc5 100644 --- a/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py +++ b/dymos/examples/min_time_climb/doc/test_doc_min_time_climb.py @@ -27,12 +27,7 @@ def test_min_time_climb_for_docs_gauss_lobatto(self): p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' - - # Note this problem can be problematic for the coloring algorithm since the DirectSolver - # introduces a some noise when solving. Here we just specify the acceptable tolerance - # and set orders=None to prevent the coloring algorithm from trying to find the tolerance - # automatically. - p.driver.declare_coloring(tol=1.0E-9, orders=None) + p.driver.declare_coloring() # # Instantiate the trajectory and phase diff --git a/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py b/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py index e90c267a0..02ee5fd03 100644 --- a/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py +++ b/dymos/examples/min_time_climb/test/test_ex_min_time_climb.py @@ -17,7 +17,7 @@ def min_time_climb(optimizer='SLSQP', num_seg=3, transcription='gauss-lobatto', p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = optimizer - p.driver.declare_coloring(tol=1.0E-9, orders=None) + p.driver.declare_coloring() if optimizer == 'SNOPT': p.driver.opt_settings['Major iterations limit'] = 1000 diff --git a/dymos/phase/phase.py b/dymos/phase/phase.py index c23c5d902..63962ddd1 100644 --- a/dymos/phase/phase.py +++ b/dymos/phase/phase.py @@ -70,7 +70,10 @@ def __init__(self, from_phase=None, **kwargs): self._initial_boundary_constraints = {} self._final_boundary_constraints = {} self._path_constraints = {} - self._timeseries_outputs = {} + self._timeseries = {} + self._timeseries['timeseries'] = {'transcription': None, + 'subset': 'all', + 'outputs': {}} self._objectives = {} else: self.user_time_options = TimeOptionsDictionary() @@ -83,12 +86,11 @@ def __init__(self, from_phase=None, **kwargs): # Don't copy over the trajectory parameters. The owning trajectory object will # handle that. self.user_traj_parameter_options = {} - self._timeseries_outputs = from_phase._timeseries_outputs.copy() self._initial_boundary_constraints = from_phase._initial_boundary_constraints.copy() self._final_boundary_constraints = from_phase._final_boundary_constraints.copy() self._path_constraints = from_phase._path_constraints.copy() - self._timeseries_outputs = from_phase._timeseries_outputs.copy() + self._timeseries = from_phase._timeseries.copy() self._objectives = from_phase._objectives.copy() _kwargs['ode_class'] = from_phase.options['ode_class'] @@ -103,6 +105,8 @@ def initialize(self): desc='Keyword arguments provided when initializing the ODE System') self.options.declare('transcription', types=TranscriptionBase, desc='Transcription technique of the optimal control problem.') + self.options.declare('timeseries', types=(dict,), + desc='Alternative timeseries.') def set_state_options(self, name, units=_unspecified, rate_source=_unspecified, targets=_unspecified, val=_unspecified, fix_initial=_unspecified, fix_final=_unspecified, @@ -874,7 +878,7 @@ def add_path_constraint(self, name, constraint_name=None, units=None, shape=None self._path_constraints[name]['units'] = units self.add_timeseries_output(name, output_name=constraint_name, units=units, shape=shape) - def add_timeseries_output(self, name, output_name=None, units=None, shape=(1,)): + def add_timeseries_output(self, name, output_name=None, units=None, shape=(1,), timeseries='timeseries'): r""" Add a variable to the timeseries outputs of the phase. @@ -895,16 +899,40 @@ def add_timeseries_output(self, name, output_name=None, units=None, shape=(1,)): shape : tuple The shape of the timeseries output variable. This must be provided (if not scalar) since Dymos doesn't necessarily know the shape of ODE outputs until setup time. + timeseries : str or None + The name of the timeseries to which the output is being added. """ if output_name is None: output_name = name.split('.')[-1] - if name not in self._timeseries_outputs: - self._timeseries_outputs[name] = {} - self._timeseries_outputs[name]['output_name'] = output_name + if timeseries not in self._timeseries: + raise ValueError('Timeseries {0} does not exist in phase {1}'.format(timeseries, self.pathname)) - self._timeseries_outputs[name]['units'] = units - self._timeseries_outputs[name]['shape'] = shape + if name not in self._timeseries[timeseries]['outputs']: + self._timeseries[timeseries]['outputs'][name] = {} + self._timeseries[timeseries]['outputs'][name]['output_name'] = output_name + + self._timeseries[timeseries]['outputs'][name]['units'] = units + self._timeseries[timeseries]['outputs'][name]['shape'] = shape + + def add_timeseries(self, name, transcription, subset='all'): + r""" + Adds a new timeseries output upon which outputs can be provided. + + Parameters + ---------- + name : str + A name for the timeseries output path. + transcription : str + A transcription object which provides a grid upon which the outputs of the timeseries + are provided. + subset : str + The name of the node subset in the given transcription at which outputs + are to be provided. + """ + self._timeseries[name] = {'transcription': transcription, + 'subset': subset, + 'outputs': {}} def add_objective(self, name, loc='final', index=None, shape=(1,), ref=None, ref0=None, adder=None, scaler=None, parallel_deriv_color=None, diff --git a/dymos/transcriptions/common/__init__.py b/dymos/transcriptions/common/__init__.py index 055ed15fe..43dd10d8f 100644 --- a/dymos/transcriptions/common/__init__.py +++ b/dymos/transcriptions/common/__init__.py @@ -2,13 +2,11 @@ from .boundary_constraint_comp import BoundaryConstraintComp from .continuity_comp import RadauPSContinuityComp, GaussLobattoContinuityComp -# from .control_interp_comp import ControlInterpComp from .control_group import ControlGroup from .polynomial_control_group import PolynomialControlGroup from .input_parameter_comp import InputParameterComp from .endpoint_conditions_comp import EndpointConditionsComp -from .path_constraint_comp import GaussLobattoPathConstraintComp, RadauPathConstraintComp -from .timeseries_output_comp import GaussLobattoTimeseriesOutputComp, RadauTimeseriesOutputComp, \ - ExplicitTimeseriesOutputComp +from .path_constraint_comp import PseudospectralPathConstraintComp +from .timeseries_output_comp import PseudospectralTimeseriesOutputComp, ExplicitTimeseriesOutputComp from .phase_linkage_comp import PhaseLinkageComp from .time_comp import TimeComp diff --git a/dymos/transcriptions/common/path_constraint_comp.py b/dymos/transcriptions/common/path_constraint_comp.py index 6ca4e6f2a..1f21c6f88 100644 --- a/dymos/transcriptions/common/path_constraint_comp.py +++ b/dymos/transcriptions/common/path_constraint_comp.py @@ -12,7 +12,9 @@ class PathConstraintCompBase(om.ExplicitComponent): def initialize(self): self._path_constraints = [] self._vars = [] - self.options.declare('grid_data', types=GridData, desc='Container object for grid info') + self.options.declare('num_nodes', types=(int,), desc='The number of nodes in the phase ' + 'at which the path constraint is to ' + 'be evaluated') def _add_path_constraint(self, name, var_class, shape=None, units=None, res_units=None, desc='', indices=None, lower=None, upper=None, equals=None, scaler=None, @@ -87,54 +89,153 @@ def _add_path_constraint(self, name, var_class, shape=None, units=None, res_unit self._path_constraints.append((name, kwargs)) -class GaussLobattoPathConstraintComp(PathConstraintCompBase): +# class GaussLobattoPathConstraintComp(PathConstraintCompBase): +# +# def setup(self): +# """ +# Define the independent variables as output variables. +# """ +# grid_data = self.options['grid_data'] +# +# num_nodes = grid_data.num_nodes +# num_state_disc_nodes = grid_data.subset_num_nodes['state_disc'] +# num_col_nodes = grid_data.subset_num_nodes['col'] +# for (name, kwargs) in self._path_constraints: +# input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} +# shape = kwargs['shape'] +# +# if isinstance(shape, list): +# shape = tuple(shape) +# +# if not isinstance(shape, tuple): +# shape = (shape,) +# +# if kwargs['src_all']: +# all_input_name = 'all_values:{0}'.format(name) +# disc_input_name = col_input_name = '' +# self.add_input(all_input_name, +# shape=(num_nodes,) + shape, +# **input_kwargs) +# else: +# all_input_name = '' +# disc_input_name = 'disc_values:{0}'.format(name) +# col_input_name = 'col_values:{0}'.format(name) +# +# self.add_input(disc_input_name, +# shape=(num_state_disc_nodes,) + shape, +# **input_kwargs) +# +# self.add_input(col_input_name, +# shape=(num_col_nodes,) + shape, +# **input_kwargs) +# +# output_name = 'path:{0}'.format(name) +# output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} +# output_kwargs['shape'] = (num_nodes,) + shape +# self.add_output(output_name, **output_kwargs) +# +# self._vars.append((disc_input_name, col_input_name, all_input_name, +# kwargs['src_all'], output_name, shape)) +# +# constraint_kwargs = {k: kwargs.get(k, None) +# for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', +# 'scaler', 'indices', 'linear')} +# +# # Convert indices from those in one time instance to those in all time instances +# template = np.zeros(np.prod(kwargs['shape']), dtype=int) +# template[kwargs['indices']] = 1 +# template = np.tile(template, num_nodes) +# constraint_kwargs['indices'] = np.nonzero(template)[0] +# +# self.add_constraint(output_name, **constraint_kwargs) +# +# # Setup partials +# if kwargs['src_all']: +# all_shape = (num_nodes,) + shape +# var_size = np.prod(shape) +# all_size = np.prod(all_shape) +# +# all_row_starts = grid_data.subset_node_indices['all'] * var_size +# all_rows = [] +# for i in all_row_starts: +# all_rows.extend(range(i, i + var_size)) +# all_rows = np.asarray(all_rows, dtype=int) +# +# self.declare_partials( +# of=output_name, +# wrt=all_input_name, +# dependent=True, +# rows=all_rows, +# cols=np.arange(all_size), +# val=1.0) +# else: +# disc_shape = (num_state_disc_nodes,) + shape +# col_shape = (num_col_nodes,) + shape +# +# var_size = np.prod(shape) +# disc_size = np.prod(disc_shape) +# col_size = np.prod(col_shape) +# +# state_disc_row_starts = grid_data.subset_node_indices['state_disc'] * var_size +# disc_rows = [] +# for i in state_disc_row_starts: +# disc_rows.extend(range(i, i + var_size)) +# disc_rows = np.asarray(disc_rows, dtype=int) +# +# self.declare_partials( +# of=output_name, +# wrt=disc_input_name, +# dependent=True, +# rows=disc_rows, +# cols=np.arange(disc_size), +# val=1.0) +# +# col_row_starts = grid_data.subset_node_indices['col'] * var_size +# col_rows = [] +# for i in col_row_starts: +# col_rows.extend(range(i, i + var_size)) +# col_rows = np.asarray(col_rows, dtype=int) +# +# self.declare_partials( +# of=output_name, +# wrt=col_input_name, +# dependent=True, +# rows=col_rows, +# cols=np.arange(col_size), +# val=1.0) +# +# def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): +# disc_indices = self.options['grid_data'].subset_node_indices['state_disc'] +# col_indices = self.options['grid_data'].subset_node_indices['col'] +# for (disc_input_name, col_input_name, all_inp_name, src_all, output_name, _) in self._vars: +# if src_all: +# outputs[output_name] = inputs[all_inp_name] +# else: +# outputs[output_name][disc_indices] = inputs[disc_input_name] +# outputs[output_name][col_indices] = inputs[col_input_name] + + +class RadauPathConstraintComp(PathConstraintCompBase): def setup(self): """ Define the independent variables as output variables. """ grid_data = self.options['grid_data'] - num_nodes = grid_data.num_nodes - num_state_disc_nodes = grid_data.subset_num_nodes['state_disc'] - num_col_nodes = grid_data.subset_num_nodes['col'] + for (name, kwargs) in self._path_constraints: input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - shape = kwargs['shape'] - - if isinstance(shape, list): - shape = tuple(shape) - - if not isinstance(shape, tuple): - shape = (shape,) - - if kwargs['src_all']: - all_input_name = 'all_values:{0}'.format(name) - disc_input_name = col_input_name = '' - self.add_input(all_input_name, - shape=(num_nodes,) + shape, - **input_kwargs) - else: - all_input_name = '' - disc_input_name = 'disc_values:{0}'.format(name) - col_input_name = 'col_values:{0}'.format(name) - - self.add_input(disc_input_name, - shape=(num_state_disc_nodes,) + shape, - **input_kwargs) - - self.add_input(col_input_name, - shape=(num_col_nodes,) + shape, - **input_kwargs) + input_name = 'all_values:{0}'.format(name) + self.add_input(input_name, + shape=(num_nodes,) + kwargs['shape'], + **input_kwargs) output_name = 'path:{0}'.format(name) output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + shape + output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] self.add_output(output_name, **output_kwargs) - self._vars.append((disc_input_name, col_input_name, all_input_name, - kwargs['src_all'], output_name, shape)) - constraint_kwargs = {k: kwargs.get(k, None) for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', 'scaler', 'indices', 'linear')} @@ -147,80 +248,39 @@ def setup(self): self.add_constraint(output_name, **constraint_kwargs) + self._vars.append((input_name, output_name, kwargs['shape'])) + # Setup partials - if kwargs['src_all']: - all_shape = (num_nodes,) + shape - var_size = np.prod(shape) - all_size = np.prod(all_shape) - - all_row_starts = grid_data.subset_node_indices['all'] * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=all_input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) - else: - disc_shape = (num_state_disc_nodes,) + shape - col_shape = (num_col_nodes,) + shape - - var_size = np.prod(shape) - disc_size = np.prod(disc_shape) - col_size = np.prod(col_shape) - - state_disc_row_starts = grid_data.subset_node_indices['state_disc'] * var_size - disc_rows = [] - for i in state_disc_row_starts: - disc_rows.extend(range(i, i + var_size)) - disc_rows = np.asarray(disc_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=disc_input_name, - dependent=True, - rows=disc_rows, - cols=np.arange(disc_size), - val=1.0) - - col_row_starts = grid_data.subset_node_indices['col'] * var_size - col_rows = [] - for i in col_row_starts: - col_rows.extend(range(i, i + var_size)) - col_rows = np.asarray(col_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=col_input_name, - dependent=True, - rows=col_rows, - cols=np.arange(col_size), - val=1.0) + all_shape = (num_nodes,) + kwargs['shape'] + var_size = np.prod(kwargs['shape']) + all_size = np.prod(all_shape) + + all_row_starts = grid_data.subset_node_indices['all'] * var_size + all_rows = [] + for i in all_row_starts: + all_rows.extend(range(i, i + var_size)) + all_rows = np.asarray(all_rows, dtype=int) + + self.declare_partials( + of=output_name, + wrt=input_name, + dependent=True, + rows=all_rows, + cols=np.arange(all_size), + val=1.0) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - disc_indices = self.options['grid_data'].subset_node_indices['state_disc'] - col_indices = self.options['grid_data'].subset_node_indices['col'] - for (disc_input_name, col_input_name, all_inp_name, src_all, output_name, _) in self._vars: - if src_all: - outputs[output_name] = inputs[all_inp_name] - else: - outputs[output_name][disc_indices] = inputs[disc_input_name] - outputs[output_name][col_indices] = inputs[col_input_name] + for (input_name, output_name, _) in self._vars: + outputs[output_name] = inputs[input_name] -class RadauPathConstraintComp(PathConstraintCompBase): +class PseudospectralPathConstraintComp(PathConstraintCompBase): def setup(self): """ Define the independent variables as output variables. """ - grid_data = self.options['grid_data'] - num_nodes = grid_data.num_nodes + num_nodes = self.options['num_nodes'] for (name, kwargs) in self._path_constraints: input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} @@ -253,7 +313,7 @@ def setup(self): var_size = np.prod(kwargs['shape']) all_size = np.prod(all_shape) - all_row_starts = grid_data.subset_node_indices['all'] * var_size + all_row_starts = np.arange(num_nodes, dtype=int) * var_size all_rows = [] for i in all_row_starts: all_rows.extend(range(i, i + var_size)) diff --git a/dymos/transcriptions/common/test/test_path_constraint_comp.py b/dymos/transcriptions/common/test/test_path_constraint_comp.py index 297d1fd21..e8a9d60b7 100644 --- a/dymos/transcriptions/common/test/test_path_constraint_comp.py +++ b/dymos/transcriptions/common/test/test_path_constraint_comp.py @@ -7,135 +7,12 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials -from dymos.transcriptions.common import GaussLobattoPathConstraintComp, RadauPathConstraintComp +from dymos.transcriptions.common import PseudospectralPathConstraintComp from dymos.transcriptions.grid_data import GridData from dymos.phase.options import ControlOptionsDictionary -class TestPathConstraintCompGL(unittest.TestCase): - - def setUp(self): - - transcription = 'gauss-lobatto' - - self.gd = gd = GridData(num_segments=2, - transcription_order=3, - segment_ends=[0.0, 3.0, 10.0], - transcription=transcription) - - ndn = gd.subset_num_nodes['state_disc'] - ncn = gd.subset_num_nodes['col'] - nn = ndn + ncn - - self.p = om.Problem(model=om.Group()) - - controls = {'a': ControlOptionsDictionary(), - 'b': ControlOptionsDictionary(), - 'c': ControlOptionsDictionary(), - 'd': ControlOptionsDictionary()} - - controls['a'].update({'units': 'm', 'shape': (1,), 'opt': False}) - controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) - controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) - - ivc = om.IndepVarComp() - self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) - - ivc.add_output('a_disc', val=np.zeros((ndn, 1)), units='m') - ivc.add_output('a_col', val=np.zeros((ncn, 1)), units='m') - ivc.add_output('b_disc', val=np.zeros((ndn, 3)), units='s') - ivc.add_output('b_col', val=np.zeros((ncn, 3)), units='s') - ivc.add_output('c_disc', val=np.zeros((ndn, 3, 3)), units='kg') - ivc.add_output('c_col', val=np.zeros((ncn, 3, 3)), units='kg') - ivc.add_output('a_ctrl', val=np.zeros((nn, 1)), units='m') - ivc.add_output('b_ctrl', val=np.zeros((nn, 3)), units='s') - ivc.add_output('c_ctrl', val=np.zeros((nn, 3, 3)), units='kg') - - path_comp = GaussLobattoPathConstraintComp(grid_data=gd) - - self.p.model.add_subsystem('path_constraints', subsys=path_comp) - - path_comp._add_path_constraint('a', var_class='ode', - shape=(1,), lower=0, upper=10, units='m') - path_comp._add_path_constraint('b', var_class='ode', - shape=(3,), lower=0, upper=10, units='s') - path_comp._add_path_constraint('c', var_class='ode', - shape=(3, 3), lower=0, upper=10, units='kg') - - path_comp._add_path_constraint('a_ctrl', var_class='time', - shape=(1,), lower=0, upper=10, units='m') - path_comp._add_path_constraint('b_ctrl', var_class='indep_control', - shape=(3,), lower=0, upper=10, units='s') - path_comp._add_path_constraint('c_ctrl', var_class='control_rate', - shape=(3, 3), lower=0, upper=10, units='kg') - - self.p.model.connect('a_disc', 'path_constraints.disc_values:a') - self.p.model.connect('a_col', 'path_constraints.col_values:a') - - self.p.model.connect('b_disc', 'path_constraints.disc_values:b') - self.p.model.connect('b_col', 'path_constraints.col_values:b') - - self.p.model.connect('c_disc', 'path_constraints.disc_values:c') - self.p.model.connect('c_col', 'path_constraints.col_values:c') - - self.p.model.connect('a_ctrl', 'path_constraints.all_values:a_ctrl') - self.p.model.connect('b_ctrl', 'path_constraints.all_values:b_ctrl') - self.p.model.connect('c_ctrl', 'path_constraints.all_values:c_ctrl') - - self.p.setup() - - self.p['a_disc'] = np.random.rand(*self.p['a_disc'].shape) - self.p['a_col'] = np.random.rand(*self.p['a_col'].shape) - - self.p['b_disc'] = np.random.rand(*self.p['b_disc'].shape) - self.p['b_col'] = np.random.rand(*self.p['b_col'].shape) - - self.p['c_disc'] = np.random.rand(*self.p['c_disc'].shape) - self.p['c_col'] = np.random.rand(*self.p['c_col'].shape) - - self.p['a_ctrl'] = np.random.rand(*self.p['a_ctrl'].shape) - self.p['b_ctrl'] = np.random.rand(*self.p['b_ctrl'].shape) - self.p['c_ctrl'] = np.random.rand(*self.p['c_ctrl'].shape) - - self.p.run_model() - - def test_results(self): - p = self.p - gd = self.gd - assert_almost_equal(p['a_disc'], - p['path_constraints.path:a'][gd.subset_node_indices['state_disc'], ...]) - - assert_almost_equal(p['a_col'], - p['path_constraints.path:a'][gd.subset_node_indices['col'], ...]) - - assert_almost_equal(p['b_disc'], - p['path_constraints.path:b'][gd.subset_node_indices['state_disc'], ...]) - - assert_almost_equal(p['b_col'], - p['path_constraints.path:b'][gd.subset_node_indices['col'], ...]) - - assert_almost_equal(p['c_disc'], - p['path_constraints.path:c'][gd.subset_node_indices['state_disc'], ...]) - - assert_almost_equal(p['c_col'], - p['path_constraints.path:c'][gd.subset_node_indices['col'], ...]) - - assert_almost_equal(p['a_ctrl'], - p['path_constraints.path:a_ctrl']) - - assert_almost_equal(p['b_ctrl'], - p['path_constraints.path:b_ctrl']) - - assert_almost_equal(p['c_ctrl'], - p['path_constraints.path:c_ctrl']) - - def test_partials(self): - np.set_printoptions(linewidth=1024, edgeitems=1000) - cpd = self.p.check_partials(out_stream=None) - assert_check_partials(cpd) - - -class TestPathConstraintCompRadau(unittest.TestCase): +class TestPathConstraintComp(unittest.TestCase): def setUp(self): @@ -166,7 +43,7 @@ def setUp(self): ivc.add_output('b_disc', val=np.zeros((ndn, 3)), units='s') ivc.add_output('c_disc', val=np.zeros((ndn, 3, 3)), units='kg') - path_comp = RadauPathConstraintComp(grid_data=gd) + path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) self.p.model.add_subsystem('path_constraints', subsys=path_comp) diff --git a/dymos/transcriptions/common/timeseries_output_comp.py b/dymos/transcriptions/common/timeseries_output_comp.py index 7fb736e18..a1dad814d 100644 --- a/dymos/transcriptions/common/timeseries_output_comp.py +++ b/dymos/transcriptions/common/timeseries_output_comp.py @@ -4,8 +4,10 @@ import numpy as np import openmdao.api as om +from scipy.linalg import block_diag from dymos.transcriptions.grid_data import GridData +from dymos.utils.lagrange import lagrange_matrices class TimeseriesOutputCompBase(om.ExplicitComponent): @@ -19,9 +21,25 @@ class TimeseriesOutputCompBase(om.ExplicitComponent): """ def initialize(self): + self._timeseries_outputs = [] + self._vars = [] - self.options.declare('grid_data', types=GridData, desc='Container object for grid info') + + self.options.declare('input_grid_data', + types=GridData, + desc='Container object for grid on which inputs are provided.') + + self.options.declare('output_grid_data', + types=GridData, + allow_none=True, + default=None, + desc='Container object for grid on which outputs are interpolated.') + + self.options.declare('output_subset', + types=str, + default='all', + desc='Name of the node subset at which outputs are desired.') def _add_timeseries_output(self, name, var_class, shape=(1,), units=None, desc='', distributed=False): @@ -57,159 +75,92 @@ def _add_timeseries_output(self, name, var_class, shape=(1,), units=None, desc=' self._timeseries_outputs.append((name, kwargs)) -class GaussLobattoTimeseriesOutputComp(TimeseriesOutputCompBase): +class PseudospectralTimeseriesOutputComp(TimeseriesOutputCompBase): def setup(self): """ Define the independent variables as output variables. """ - grid_data = self.options['grid_data'] - - num_nodes = grid_data.num_nodes - num_state_disc_nodes = grid_data.subset_num_nodes['state_disc'] - num_col_nodes = grid_data.subset_num_nodes['col'] - for (name, kwargs) in self._timeseries_outputs: - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - shape = kwargs['shape'] - if kwargs['src_all']: - all_input_name = 'all_values:{0}'.format(name) - disc_input_name = col_input_name = '' - self.add_input(all_input_name, - shape=(num_nodes,) + shape, - **input_kwargs) - else: - all_input_name = '' - disc_input_name = 'disc_values:{0}'.format(name) - col_input_name = 'col_values:{0}'.format(name) - - self.add_input(disc_input_name, - shape=(num_state_disc_nodes,) + shape, - **input_kwargs) - - self.add_input(col_input_name, - shape=(num_col_nodes,) + shape, - **input_kwargs) - - output_name = name - output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + shape - self.add_output(output_name, **output_kwargs) - - self._vars.append((disc_input_name, col_input_name, all_input_name, - kwargs['src_all'], output_name, shape)) - - # Setup partials - if kwargs['src_all']: - all_shape = (num_nodes,) + shape - var_size = np.prod(shape) - all_size = np.prod(all_shape) - - all_row_starts = grid_data.subset_node_indices['all'] * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=all_input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) + igd = self.options['input_grid_data'] + ogd = self.options['output_grid_data'] + output_subset = self.options['output_subset'] + + if ogd is None: + ogd = igd + + input_num_nodes = igd.num_nodes + output_num_nodes = ogd.subset_num_nodes[output_subset] + + # Build the interpolation matrix which maps from the input grid to the output grid. + # Rather than a single phase-wide interpolating polynomial, map each segment. + # To do this, find the nodes in the output grid which fall in each segment of the input + # grid. Then build a Lagrange interpolating polynomial for that segment + L_blocks = [] + output_nodes_ptau = ogd.node_ptau[ogd.subset_node_indices[output_subset]].tolist() + all_idxs = [] + for iseg in range(igd.num_segments): + i1, i2 = igd.segment_indices[iseg] + iptau_segi = igd.node_ptau[i1:i2] + istau_segi = igd.node_stau[i1:i2] + + # The indices of the output grid that fall within this segment of the input grid + if ogd is igd: + optau_segi = iptau_segi else: - disc_shape = (num_state_disc_nodes,) + shape - col_shape = (num_col_nodes,) + shape - - var_size = np.prod(shape) - disc_size = np.prod(disc_shape) - col_size = np.prod(col_shape) - - state_disc_row_starts = grid_data.subset_node_indices['state_disc'] * var_size - disc_rows = [] - for i in state_disc_row_starts: - disc_rows.extend(range(i, i + var_size)) - disc_rows = np.asarray(disc_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=disc_input_name, - dependent=True, - rows=disc_rows, - cols=np.arange(disc_size), - val=1.0) + ptau_hi = igd.segment_ends[iseg+1] + if iseg < igd.num_segments - 1: + idxs_in_iseg = np.where(output_nodes_ptau <= ptau_hi)[0] + else: + idxs_in_iseg = np.arange(len(output_nodes_ptau)) + optau_segi = np.asarray(output_nodes_ptau)[idxs_in_iseg] + # Remove the captured nodes so we don't accidentally include them again + output_nodes_ptau = output_nodes_ptau[len(idxs_in_iseg):] - col_row_starts = grid_data.subset_node_indices['col'] * var_size - col_rows = [] - for i in col_row_starts: - col_rows.extend(range(i, i + var_size)) - col_rows = np.asarray(col_rows, dtype=int) + # # Now get the output nodes which fall in iseg in iseg's segment tau space. + ostau_segi = 2.0 * (optau_segi - iptau_segi[0]) / (iptau_segi[-1] - iptau_segi[0]) - 1 - self.declare_partials( - of=output_name, - wrt=col_input_name, - dependent=True, - rows=col_rows, - cols=np.arange(col_size), - val=1.0) - - def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - disc_indices = self.options['grid_data'].subset_node_indices['state_disc'] - col_indices = self.options['grid_data'].subset_node_indices['col'] - for (disc_input_name, col_input_name, all_inp_name, src_all, output_name, _) in self._vars: - if src_all: - outputs[output_name] = inputs[all_inp_name] - else: - outputs[output_name][disc_indices] = inputs[disc_input_name] - outputs[output_name][col_indices] = inputs[col_input_name] + # Create the interpolation matrix and add it to the blocks + L, _ = lagrange_matrices(istau_segi, ostau_segi) + L_blocks.append(L) - -class RadauTimeseriesOutputComp(TimeseriesOutputCompBase): - - def setup(self): - """ - Define the independent variables as output variables. - """ - grid_data = self.options['grid_data'] - num_nodes = grid_data.num_nodes + self.interpolation_matrix = block_diag(*L_blocks) for (name, kwargs) in self._timeseries_outputs: - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'all_values:{0}'.format(name) + input_name = 'input_values:{0}'.format(name) + shape = kwargs['shape'] + self.add_input(input_name, - shape=(num_nodes,) + kwargs['shape'], + shape=(input_num_nodes,) + shape, **input_kwargs) output_name = name output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] + output_kwargs['shape'] = (output_num_nodes,) + kwargs['shape'] self.add_output(output_name, **output_kwargs) - self._vars.append((input_name, output_name, kwargs['shape'])) + self._vars.append((input_name, output_name, shape)) - # Setup partials - all_shape = (num_nodes,) + kwargs['shape'] - var_size = np.prod(kwargs['shape']) - all_size = np.prod(all_shape) + size = np.prod(shape) + val_jac = np.zeros((output_num_nodes, size, input_num_nodes, size)) - all_row_starts = grid_data.subset_node_indices['all'] * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) + for i in range(size): + val_jac[:, i, :, i] = self.interpolation_matrix - self.declare_partials( - of=output_name, - wrt=input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) + val_jac = val_jac.reshape((output_num_nodes * size, input_num_nodes * size), + order='C') + + val_jac_rows, val_jac_cols = np.where(val_jac != 0) + + rs, cs = val_jac_rows, val_jac_cols + self.declare_partials(of=output_name, + wrt=input_name, + rows=rs, cols=cs, val=val_jac[rs, cs]) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): for (input_name, output_name, _) in self._vars: - outputs[output_name] = inputs[input_name] + outputs[output_name] = np.tensordot(self.interpolation_matrix, inputs[input_name], + axes=(1, 0)) class ExplicitTimeseriesOutputComp(TimeseriesOutputCompBase): @@ -259,11 +210,6 @@ def setup(self): idx0 = idx1 - # constraint_kwargs = {k: kwargs.get(k, None) - # for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', - # 'scaler', 'indices', 'linear')} - # self.add_constraint(output_name, **constraint_kwargs) - self._vars[name]['output'] = output_name def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): diff --git a/dymos/transcriptions/grid_data.py b/dymos/transcriptions/grid_data.py index b4c124ff6..deacbea84 100644 --- a/dymos/transcriptions/grid_data.py +++ b/dymos/transcriptions/grid_data.py @@ -173,8 +173,7 @@ def rk_subsets_and_nodes(method, seg_idx, compressed=False): 'all': np.arange(n, dtype=int) } subsets['state_disc'] = subsets['segment_ends'] - subsets['state_input'] = subsets['segment_ends'] if not compressed or seg_idx == 0 else \ - subsets['segment_ends'][1:] + subsets['state_input'] = subsets['state_disc'] if seg_idx == 0 else subsets['state_disc'][-1:] return subsets, nodes diff --git a/dymos/transcriptions/pseudospectral/components/__init__.py b/dymos/transcriptions/pseudospectral/components/__init__.py index 1142ae4b7..e57a24992 100644 --- a/dymos/transcriptions/pseudospectral/components/__init__.py +++ b/dymos/transcriptions/pseudospectral/components/__init__.py @@ -4,3 +4,4 @@ from .state_interp_comp import StateInterpComp from .state_independents import StateIndependentsComp from .control_endpoint_defect_comp import ControlEndpointDefectComp +from .gauss_lobatto_interleave_comp import GaussLobattoInterleaveComp diff --git a/dymos/transcriptions/pseudospectral/components/gauss_lobatto_interleave_comp.py b/dymos/transcriptions/pseudospectral/components/gauss_lobatto_interleave_comp.py new file mode 100644 index 000000000..e166d03a2 --- /dev/null +++ b/dymos/transcriptions/pseudospectral/components/gauss_lobatto_interleave_comp.py @@ -0,0 +1,96 @@ +from __future__ import division, print_function, absolute_import + +import numpy as np +import openmdao.api as om +from six import iteritems + +from ...grid_data import GridData + + +class GaussLobattoInterleaveComp(om.ExplicitComponent): + r""" Provides a contiguous output at all nodes for inputs which are only known at + state discretiation or collocation nodes. + """ + + def initialize(self): + + self.vars = {} + self.options.declare('grid_data', types=GridData, desc='Container object for grid info') + + def add_var(self, name, shape, units): + """ + Add a variable to be interleaved. In general these need to be variables whose values are + stored separately for state discretization or collocation nodes (such as states + or ODE outputs). + + Parameters + ---------- + name : str + The name of variable as it should appear in the outputs of the + component ('interleave_comp.all_values:{name}'). + shape : tuple + The shape of the variable at each instance in time. + units : str + The units of the variable. + """ + self.vars[name] = {'shape': shape, 'units': units} + + def setup(self): + + num_disc_nodes = self.options['grid_data'].subset_num_nodes['state_disc'] + num_col_nodes = self.options['grid_data'].subset_num_nodes['col'] + num_nodes = self.options['grid_data'].subset_num_nodes['all'] + + self._varnames = {} + + for name, options in iteritems(self.vars): + shape = options['shape'] + units = options['units'] + size = np.prod(shape) + + self._varnames[name] = {} + self._varnames[name]['disc'] = 'disc_values:{0}'.format(name) + self._varnames[name]['col'] = 'col_values:{0}'.format(name) + self._varnames[name]['all'] = 'all_values:{0}'.format(name) + + self.add_input( + name=self._varnames[name]['disc'], + shape=(num_disc_nodes,) + shape, + desc='Values of {0} at discretization nodes'.format(name), + units=units) + + self.add_input( + name=self._varnames[name]['col'], + shape=(num_col_nodes,) + shape, + desc='Values of {0} at collocation nodes'.format(name), + units=units) + + self.add_output( + name=self._varnames[name]['all'], + shape=(num_nodes,) + shape, + desc='Values of {0} at all nodes'.format(name), + units=units) + + start_rows = self.options['grid_data'].subset_node_indices['state_disc'] * size + r = (start_rows[:, np.newaxis] + np.arange(size, dtype=int)).ravel() + c = np.arange(size * num_disc_nodes, dtype=int) + + self.declare_partials(of=self._varnames[name]['all'], + wrt=self._varnames[name]['disc'], + rows=r, cols=c, val=1.0) + + start_rows = self.options['grid_data'].subset_node_indices['col'] * size + r = (start_rows[:, np.newaxis] + np.arange(size, dtype=int)).ravel() + c = np.arange(size * num_col_nodes, dtype=int) + + self.declare_partials(of=self._varnames[name]['all'], + wrt=self._varnames[name]['col'], + rows=r, cols=c, val=1.0) + + def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): + disc_idxs = self.options['grid_data'].subset_node_indices['disc'] + col_idxs = self.options['grid_data'].subset_node_indices['col'] + + for name in self.vars: + outputs[self._varnames[name]['all']][disc_idxs] = inputs[self._varnames[name]['disc']] + outputs[self._varnames[name]['all']][col_idxs] = inputs[self._varnames[name]['col']] diff --git a/dymos/transcriptions/pseudospectral/components/test/test_gauss_lobatto_interleave_comp.py b/dymos/transcriptions/pseudospectral/components/test/test_gauss_lobatto_interleave_comp.py new file mode 100644 index 000000000..f82624446 --- /dev/null +++ b/dymos/transcriptions/pseudospectral/components/test/test_gauss_lobatto_interleave_comp.py @@ -0,0 +1,107 @@ +from __future__ import print_function, division, absolute_import + +import unittest + +import numpy as np + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_rel_error + +from dymos.transcriptions.pseudospectral.components import GaussLobattoInterleaveComp +from dymos.transcriptions.grid_data import GridData + + +class TestGaussLobattoInterleaveComp(unittest.TestCase): + + def setUp(self): + self.grid_data = gd = GridData(num_segments=3, segment_ends=np.array([0., 2., 4., 10.0]), + transcription='gauss-lobatto', transcription_order=[3, 3, 3]) + + num_disc_nodes = gd.subset_num_nodes['state_disc'] + num_col_nodes = gd.subset_num_nodes['col'] + + self.p = om.Problem(model=om.Group()) + + state_options = {'u': {'units': 'm', 'shape': (1,)}, + 'v': {'units': 'm', 'shape': (3, 2)}} + + ode_outputs = {'vehicle_cg': {'units': 'm', 'shape': (3,)}} + + indep_comp = om.IndepVarComp() + self.p.model.add_subsystem('indep', indep_comp, promotes=['*']) + + indep_comp.add_output('state_disc:u', + val=np.zeros((num_disc_nodes, 1)), units='m') + + indep_comp.add_output('state_disc:v', + val=np.zeros((num_disc_nodes, 3, 2)), units='m') + + indep_comp.add_output('state_col:u', + val=np.zeros((num_col_nodes, 1)), units='m') + + indep_comp.add_output('state_col:v', + val=np.zeros((num_col_nodes, 3, 2)), units='m') + + indep_comp.add_output('ode_disc:cg', + val=np.zeros((num_disc_nodes, 3)), units='m') + + indep_comp.add_output('ode_col:cg', + val=np.zeros((num_col_nodes, 3)), units='m') + + glic = self.p.model.add_subsystem('interleave_comp', + subsys=GaussLobattoInterleaveComp(grid_data=gd)) + + glic.add_var('u', **state_options['u']) + glic.add_var('v', **state_options['v']) + glic.add_var('vehicle_cg', **ode_outputs['vehicle_cg']) + + self.p.model.connect('state_disc:u', 'interleave_comp.disc_values:u') + self.p.model.connect('state_disc:v', 'interleave_comp.disc_values:v') + self.p.model.connect('state_col:u', 'interleave_comp.col_values:u') + self.p.model.connect('state_col:v', 'interleave_comp.col_values:v') + + self.p.model.connect('ode_disc:cg', 'interleave_comp.disc_values:vehicle_cg') + self.p.model.connect('ode_col:cg', 'interleave_comp.col_values:vehicle_cg') + + self.p.setup(force_alloc_complex=True) + + self.p['state_disc:u'] = np.random.random((num_disc_nodes, 1)) + self.p['state_disc:v'] = np.random.random((num_disc_nodes, 3, 2)) + self.p['state_col:u'] = np.random.random((num_col_nodes, 1)) + self.p['state_col:v'] = np.random.random((num_col_nodes, 3, 2)) + + self.p.run_model() + + def test_results(self): + + u_disc = self.p.get_val('state_disc:u') + v_disc = self.p.get_val('state_disc:v') + u_col = self.p.get_val('state_col:u') + v_col = self.p.get_val('state_col:v') + + u_all = self.p.get_val('interleave_comp.all_values:u') + v_all = self.p.get_val('interleave_comp.all_values:v') + + assert_rel_error(self, + u_all[self.grid_data.subset_node_indices['state_disc'], ...], + u_disc) + + assert_rel_error(self, + v_all[self.grid_data.subset_node_indices['state_disc'], ...], + v_disc) + + assert_rel_error(self, + u_all[self.grid_data.subset_node_indices['col'], ...], + u_col) + + assert_rel_error(self, + v_all[self.grid_data.subset_node_indices['col'], ...], + v_col) + + def test_partials(self): + cpd = self.p.check_partials(compact_print=True, method='cs', out_stream=None) + assert_check_partials(cpd) + + +if __name__ == '__main__': + unittest.main() diff --git a/dymos/transcriptions/pseudospectral/gauss_lobatto.py b/dymos/transcriptions/pseudospectral/gauss_lobatto.py index 8259f7d31..318acd334 100644 --- a/dymos/transcriptions/pseudospectral/gauss_lobatto.py +++ b/dymos/transcriptions/pseudospectral/gauss_lobatto.py @@ -6,7 +6,8 @@ from six import iteritems from .pseudospectral_base import PseudospectralBase -from ..common import GaussLobattoPathConstraintComp, GaussLobattoTimeseriesOutputComp, \ +from .components import GaussLobattoInterleaveComp +from ..common import PseudospectralPathConstraintComp, PseudospectralTimeseriesOutputComp, \ GaussLobattoContinuityComp from ...utils.misc import get_rate_units from ...utils.indexing import get_src_indices_by_row @@ -202,6 +203,98 @@ def setup_ode(self, phase): 'state_interp.staterate_disc:{0}'.format(name), src_indices=src_idxs) + # + # Setup the interleave comp to interleave all states, any path constraints from the ODE, + # and any timeseries outputs from the ODE. + # + self.setup_interleave_comp(phase) + + def setup_interleave_comp(self, phase): + num_input_nodes = self.grid_data.subset_num_nodes['state_input'] + + map_input_indices_to_disc = self.grid_data.input_maps['state_input_to_disc'] + + interleave_comp = GaussLobattoInterleaveComp(grid_data=self.grid_data) + + # + # First do the states + # + for state_name, options in iteritems(phase.state_options): + shape = options['shape'] + units = options['units'] + interleave_comp.add_var('states:{0}'.format(state_name), shape, units) + + size = np.prod(options['shape']) + src_idxs_mat = np.reshape(np.arange(size * num_input_nodes, dtype=int), + (num_input_nodes, size), order='C') + src_idxs = src_idxs_mat[map_input_indices_to_disc, :] + + if size == 1: + """ Flat state variable is passed as 1D data.""" + src_idxs = src_idxs.ravel() + + phase.connect('states:{0}'.format(state_name), + 'interleave_comp.disc_values:states:{0}'.format(state_name), + src_indices=src_idxs, flat_src_indices=True) + + phase.connect('state_interp.state_col:{0}'.format(state_name), + 'interleave_comp.col_values:states:{0}'.format(state_name)) + + # + # Do the path constraints + # + for var, options in iteritems(phase._path_constraints): + + var_type = phase.classify_var(var) + + # We only need to interleave state variables (covered above) and ODE outputs + if var_type != 'ode': + continue + + shape = (1,) if options['shape'] is None else options['shape'] + units = options['units'] + con_name = options['constraint_name'] + + if con_name in interleave_comp.vars: + continue + + interleave_comp.add_var(con_name, shape, units) + + phase.connect(src_name='rhs_disc.{0}'.format(var), + tgt_name='interleave_comp.disc_values:{0}'.format(con_name)) + phase.connect(src_name='rhs_col.{0}'.format(var), + tgt_name='interleave_comp.col_values:{0}'.format(con_name)) + + # + # Do the timeseries outputs + # + for timeseries_name, timeseries_options in iteritems(phase._timeseries): + + for var, options in iteritems(timeseries_options['outputs']): + + var_type = phase.classify_var(var) + + # We only need to interleave state variables (covered above) and ODE outputs + if var_type != 'ode': + continue + + # Assume scalar shape here, but check config will warn that it's inferred. + output_name = options['output_name'] + shape = (1,) if options['shape'] is None else options['shape'] + units = options['units'] + + if output_name in interleave_comp.vars: + continue + + interleave_comp.add_var(output_name, shape, units) + + phase.connect(src_name='rhs_disc.{0}'.format(var), + tgt_name='interleave_comp.disc_values:{0}'.format(output_name)) + phase.connect(src_name='rhs_col.{0}'.format(var), + tgt_name='interleave_comp.col_values:{0}'.format(output_name)) + + phase.add_subsystem('interleave_comp', interleave_comp) + def setup_defects(self, phase): super(GaussLobatto, self).setup_defects(phase) grid_data = self.grid_data @@ -229,7 +322,7 @@ def setup_path_constraints(self, phase): time_units = phase.time_options['units'] if phase._path_constraints: - path_comp = GaussLobattoPathConstraintComp(grid_data=gd) + path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): @@ -262,12 +355,8 @@ def setup_path_constraints(self, phase): options['shape'] = state_shape options['units'] = state_units if con_units is None else con_units options['linear'] = False - src_idxs = get_src_indices_by_row(gd.input_maps['state_input_to_disc'], state_shape) - phase.connect(src_name='states:{0}'.format(var), - tgt_name='path_constraints.disc_values:{0}'.format(con_name), - src_indices=src_idxs, flat_src_indices=True) - phase.connect(src_name='state_interp.state_col:{0}'.format(var), - tgt_name='path_constraints.col_values:{0}'.format(con_name)) + phase.connect(src_name='interleave_comp.all_values:states:{0}'.format(var), + tgt_name='path_constraints.all_values:{0}'.format(con_name)) elif var_type in ('indep_control', 'input_control'): control_shape = phase.control_options[var]['shape'] @@ -342,10 +431,8 @@ def setup_path_constraints(self, phase): options['linear'] = False if options['shape'] is None: options['shape'] = (1,) - phase.connect(src_name='rhs_disc.{0}'.format(var), - tgt_name='path_constraints.disc_values:{0}'.format(con_name)) - phase.connect(src_name='rhs_col.{0}'.format(var), - tgt_name='path_constraints.col_values:{0}'.format(con_name)) + phase.connect(src_name='interleave_comp.all_values:{0}'.format(con_name), + tgt_name='path_constraints.all_values:{0}'.format(con_name)) kwargs = options.copy() kwargs.pop('constraint_name', None) @@ -354,166 +441,170 @@ def setup_path_constraints(self, phase): def setup_timeseries_outputs(self, phase): gd = self.grid_data time_units = phase.time_options['units'] - timeseries_comp = GaussLobattoTimeseriesOutputComp(grid_data=gd) - phase.add_subsystem('timeseries', subsys=timeseries_comp) - timeseries_comp._add_timeseries_output('time', - var_class=phase.classify_var('time'), - units=time_units) - phase.connect(src_name='time', tgt_name='timeseries.all_values:time') + for name, options in iteritems(phase._timeseries): - timeseries_comp._add_timeseries_output('time_phase', - var_class=phase.classify_var('time_phase'), - units=time_units) - phase.connect(src_name='time_phase', tgt_name='timeseries.all_values:time_phase') - - for name, options in iteritems(phase.state_options): - timeseries_comp._add_timeseries_output('states:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=options['units']) - src_rows = gd.input_maps['state_input_to_disc'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='states:{0}'.format(name), - tgt_name='timeseries.disc_values:states:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) - phase.connect(src_name='state_interp.state_col:{0}'.format(name), - tgt_name='timeseries.col_values:states:{0}'.format(name)) - - for name, options in iteritems(phase.control_options): - control_units = options['units'] - - # Control values - timeseries_comp._add_timeseries_output('controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - phase.connect(src_name='control_values:{0}'.format(name), - tgt_name='timeseries.all_values:controls:{0}'.format(name)) - - # # Control rates - timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='control_rates:{0}_rate'.format(name), - tgt_name='timeseries.all_values:control_rates:{0}_rate'.format(name)) - - # Control second derivatives - timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.all_values:control_rates:{0}_rate2'.format(name)) - - for name, options in iteritems(phase.polynomial_control_options): - control_units = options['units'] - - # Control values - timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - phase.connect(src_name='polynomial_control_values:{0}'.format(name), - tgt_name='timeseries.all_values:' - 'polynomial_controls:{0}'.format(name)) - - # # Control rates - timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(name), - tgt_name='timeseries.all_values:' - 'polynomial_control_rates:{0}_rate'.format(name)) - - # Control second derivatives - timeseries_comp._add_timeseries_output('polynomial_control_rates:' - '{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.all_values:' - 'polynomial_control_rates:{0}_rate2'.format(name)) - - for name, options in iteritems(phase.design_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) - - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - - phase.connect(src_name='design_parameters:{0}'.format(name), - tgt_name='timeseries.all_values:design_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + if options['transcription'] is None: + ogd = None + else: + options['transcription'].setup_grid(phase) + ogd = options['transcription'].grid_data + + timeseries_comp = PseudospectralTimeseriesOutputComp(input_grid_data=gd, + output_grid_data=ogd, + output_subset=options['subset']) + phase.add_subsystem(name, subsys=timeseries_comp) + + timeseries_comp._add_timeseries_output('time', + var_class=phase.classify_var('time'), + units=time_units) + phase.connect(src_name='time', tgt_name='{0}.input_values:time'.format(name)) + + timeseries_comp._add_timeseries_output('time_phase', + var_class=phase.classify_var('time_phase'), + units=time_units) + phase.connect(src_name='time_phase', tgt_name='{0}.input_values:time_phase'.format(name)) + + for state_name, options in iteritems(phase.state_options): + timeseries_comp._add_timeseries_output('states:{0}'.format(state_name), + var_class=phase.classify_var(state_name), + shape=options['shape'], + units=options['units']) + phase.connect(src_name='interleave_comp.all_values:states:{0}'.format(state_name), + tgt_name='{0}.input_values:states:{1}'.format(name, state_name)) + + for control_name, options in iteritems(phase.control_options): + control_units = options['units'] + + # Control values + timeseries_comp._add_timeseries_output('controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + phase.connect(src_name='control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:controls:{1}'.format(name, control_name)) + + # # Control rates + timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate'.format(name, control_name)) + + # Control second derivatives + timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate2'.format(name, control_name)) + + for control_name, options in iteritems(phase.polynomial_control_options): + control_units = options['units'] + + # Control values + timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + phase.connect(src_name='polynomial_control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:' + 'polynomial_controls:{1}'.format(name, control_name)) + + # # Control rates + timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:' + 'polynomial_control_rates:{1}_rate'.format(name, control_name)) + + # Control second derivatives + timeseries_comp._add_timeseries_output('polynomial_control_rates:' + '{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:' + 'polynomial_control_rates:{1}_rate2'.format(name, control_name)) + + for param_name, options in iteritems(phase.design_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) + + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + + phase.connect(src_name='design_parameters:{0}'.format(param_name), + tgt_name='{0}.input_values:design_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.input_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) + for param_name, options in iteritems(phase.input_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - phase.connect(src_name='input_parameters:{0}_out'.format(name), - tgt_name='timeseries.all_values:input_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + phase.connect(src_name='input_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:input_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.traj_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) + for param_name, options in iteritems(phase.traj_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - phase.connect(src_name='traj_parameters:{0}_out'.format(name), - tgt_name='timeseries.all_values:traj_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + phase.connect(src_name='traj_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:traj_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for var, options in iteritems(phase._timeseries_outputs): - output_name = options['output_name'] + for var, options in iteritems(phase._timeseries[name]['outputs']): + output_name = options['output_name'] - # Determine the path to the variable which we will be constraining - # This is more complicated for path constraints since, for instance, - # a single state variable has two sources which must be connected to - # the path component. - var_type = phase.classify_var(var) + # Determine the path to the variable which we will be constraining + # This is more complicated for path constraints since, for instance, + # a single state variable has two sources which must be connected to + # the path component. + var_type = phase.classify_var(var) - # Ignore any variables that we've already added (states, times, controls, etc) - if var_type != 'ode': - continue + # Ignore any variables that we've already added (states, times, controls, etc) + if var_type != 'ode': + continue - # Assume scalar shape here, but check config will warn that it's inferred. - if options['shape'] is None: - options['shape'] = (1,) + # Assume scalar shape here, but check config will warn that it's inferred. + if options['shape'] is None: + options['shape'] = (1,) - # Failed to find variable, assume it is in the ODE - phase.connect(src_name='rhs_disc.{0}'.format(var), - tgt_name='timeseries.disc_values:{0}'.format(output_name)) - phase.connect(src_name='rhs_col.{0}'.format(var), - tgt_name='timeseries.col_values:{0}'.format(output_name)) + # Failed to find variable, assume it is in the ODE + phase.connect(src_name='interleave_comp.all_values:{0}'.format(output_name), + tgt_name='{0}.input_values:{1}'.format(name, output_name)) - kwargs = options.copy() - kwargs.pop('output_name', None) - timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) + kwargs = options.copy() + kwargs.pop('output_name', None) + timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) def get_rate_source_path(self, state_name, nodes, phase): gd = self.grid_data diff --git a/dymos/transcriptions/pseudospectral/radau_pseudospectral.py b/dymos/transcriptions/pseudospectral/radau_pseudospectral.py index e5eb2e290..7830bc41e 100644 --- a/dymos/transcriptions/pseudospectral/radau_pseudospectral.py +++ b/dymos/transcriptions/pseudospectral/radau_pseudospectral.py @@ -7,7 +7,7 @@ from six import iteritems from .pseudospectral_base import PseudospectralBase -from ..common import RadauPathConstraintComp, RadauPSContinuityComp, RadauTimeseriesOutputComp +from ..common import PseudospectralPathConstraintComp, RadauPSContinuityComp, PseudospectralTimeseriesOutputComp from ...utils.misc import get_rate_units from ...utils.indexing import get_src_indices_by_row from ..grid_data import GridData @@ -158,7 +158,7 @@ def setup_path_constraints(self, phase): time_units = phase.time_options['units'] if phase._path_constraints: - path_comp = RadauPathConstraintComp(grid_data=gd) + path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): @@ -303,163 +303,174 @@ def setup_path_constraints(self, phase): def setup_timeseries_outputs(self, phase): gd = self.grid_data time_units = phase.time_options['units'] - timeseries_comp = RadauTimeseriesOutputComp(grid_data=gd) - phase.add_subsystem('timeseries', subsys=timeseries_comp) - timeseries_comp._add_timeseries_output('time', - var_class=phase.classify_var('time'), - units=time_units) - phase.connect(src_name='time', tgt_name='timeseries.all_values:time') + for name, options in iteritems(phase._timeseries): - timeseries_comp._add_timeseries_output('time_phase', - var_class=phase.classify_var('time_phase'), - units=time_units) - phase.connect(src_name='time_phase', tgt_name='timeseries.all_values:time_phase') - - for name, options in iteritems(phase.state_options): - timeseries_comp._add_timeseries_output('states:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=options['units']) - src_rows = gd.input_maps['state_input_to_disc'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='states:{0}'.format(name), - tgt_name='timeseries.all_values:states:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) - - for name, options in iteritems(phase.control_options): - control_units = options['units'] - timeseries_comp._add_timeseries_output('controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - src_rows = gd.subset_node_indices['all'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='control_values:{0}'.format(name), - tgt_name='timeseries.all_values:controls:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + if options['transcription'] is None: + ogd = None + else: + options['transcription'].setup_grid(phase) + ogd = options['transcription'].grid_data + + timeseries_comp = PseudospectralTimeseriesOutputComp(input_grid_data=gd, + output_grid_data=ogd, + output_subset=options['subset']) + phase.add_subsystem(name, subsys=timeseries_comp) + + timeseries_comp._add_timeseries_output('time', + var_class=phase.classify_var('time'), + units=time_units) + phase.connect(src_name='time', tgt_name='{0}.input_values:time'.format(name)) + + timeseries_comp._add_timeseries_output('time_phase', + var_class=phase.classify_var('time_phase'), + units=time_units) + phase.connect(src_name='time_phase', tgt_name='{0}.input_values:time_phase'.format(name)) + + for state_name, options in iteritems(phase.state_options): + timeseries_comp._add_timeseries_output('states:{0}'.format(state_name), + var_class=phase.classify_var(state_name), + shape=options['shape'], + units=options['units']) + src_rows = gd.input_maps['state_input_to_disc'] + src_idxs = get_src_indices_by_row(src_rows, options['shape']) + phase.connect(src_name='states:{0}'.format(state_name), + tgt_name='{0}.input_values:states:{1}'.format(name, state_name), + src_indices=src_idxs, flat_src_indices=True) - # # Control rates - timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='control_rates:{0}_rate'.format(name), - tgt_name='timeseries.all_values:control_rates:{0}_rate'.format(name)) - - # Control second derivatives - timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.all_values:control_rates:{0}_rate2'.format(name)) + for control_name, options in iteritems(phase.control_options): + control_units = options['units'] + timeseries_comp._add_timeseries_output('controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + src_rows = gd.subset_node_indices['all'] + src_idxs = get_src_indices_by_row(src_rows, options['shape']) + phase.connect(src_name='control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:controls:{1}'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.polynomial_control_options): - control_units = options['units'] - timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - src_rows = gd.subset_node_indices['all'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='polynomial_control_values:{0}'.format(name), - tgt_name='timeseries.all_values:' - 'polynomial_controls:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + # # Control rates + timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate'.format(name, control_name)) + + # Control second derivatives + timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate2'.format(name, control_name)) + + for control_name, options in iteritems(phase.polynomial_control_options): + control_units = options['units'] + timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + src_rows = gd.subset_node_indices['all'] + src_idxs = get_src_indices_by_row(src_rows, options['shape']) + phase.connect(src_name='polynomial_control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:' + 'polynomial_controls:{1}'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - # # Control rates - timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(name), - tgt_name='timeseries.all_values:polynomial_control_rates:' - '{0}_rate'.format(name)) - - # Control second derivatives - timeseries_comp._add_timeseries_output('polynomial_control_rates:' - '{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.all_values:polynomial_control_rates:' - '{0}_rate2'.format(name)) - - for name, options in iteritems(phase.design_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) - - src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - - phase.connect(src_name='design_parameters:{0}'.format(name), - tgt_name='timeseries.all_values:design_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + # # Control rates + timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:polynomial_control_rates:' + '{1}_rate'.format(name, control_name)) + + # Control second derivatives + timeseries_comp._add_timeseries_output('polynomial_control_rates:' + '{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:polynomial_control_rates:' + '{1}_rate2'.format(name, control_name)) + + for param_name, options in iteritems(phase.design_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) + + src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + + phase.connect(src_name='design_parameters:{0}'.format(param_name), + tgt_name='{0}.input_values:design_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.input_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) + for param_name, options in iteritems(phase.input_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) - src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - phase.connect(src_name='input_parameters:{0}_out'.format(name), - tgt_name='timeseries.all_values:input_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + phase.connect(src_name='input_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:input_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.traj_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - units=units) + for param_name, options in iteritems(phase.traj_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + units=units) - src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + src_idxs_raw = np.zeros(gd.subset_num_nodes['all'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - phase.connect(src_name='traj_parameters:{0}_out'.format(name), - tgt_name='timeseries.all_values:traj_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + phase.connect(src_name='traj_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:traj_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - for var, options in iteritems(phase._timeseries_outputs): - output_name = options['output_name'] + for var, options in iteritems(phase._timeseries[name]['outputs']): + output_name = options['output_name'] - # Determine the path to the variable which we will be constraining - # This is more complicated for path constraints since, for instance, - # a single state variable has two sources which must be connected to - # the path component. - var_type = phase.classify_var(var) + # Determine the path to the variable which we will be constraining + # This is more complicated for path constraints since, for instance, + # a single state variable has two sources which must be connected to + # the path component. + var_type = phase.classify_var(var) - # Ignore any variables that we've already added (states, times, controls, etc) - if var_type != 'ode': - continue + # Ignore any variables that we've already added (states, times, controls, etc) + if var_type != 'ode': + continue - # Assume scalar shape here if None, but check config will warn that it's inferred. - if options['shape'] is None: - options['shape'] = (1,) + # Assume scalar shape here if None, but check config will warn that it's inferred. + if options['shape'] is None: + options['shape'] = (1,) - # Failed to find variable, assume it is in the ODE - phase.connect(src_name='rhs_all.{0}'.format(var), - tgt_name='timeseries.all_values:{0}'.format(output_name)) + # Failed to find variable, assume it is in the ODE + phase.connect(src_name='rhs_all.{0}'.format(var), + tgt_name='{0}.input_values:{1}'.format(name, output_name)) - kwargs = options.copy() - kwargs.pop('output_name', None) - timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) + kwargs = options.copy() + kwargs.pop('output_name', None) + timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) def get_rate_source_path(self, state_name, nodes, phase): gd = self.grid_data diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py index 02453d27b..6304f9097 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py @@ -7,60 +7,59 @@ class RungeKuttaPathConstraintComp(PathConstraintCompBase): - def setup(self): - """ - Define the independent variables as output variables. - """ - grid_data = self.options['grid_data'] - num_nodes = 2 * grid_data.num_segments - - for (name, kwargs) in self._path_constraints: - - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'all_values:{0}'.format(name) - self.add_input(input_name, - shape=(num_nodes,) + kwargs['shape'], - **input_kwargs) - - output_name = 'path:{0}'.format(name) - output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] - self.add_output(output_name, **output_kwargs) - - constraint_kwargs = {k: kwargs.get(k, None) - for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', - 'scaler', 'indices', 'linear')} - - # Convert indices from those in one time instance to those in all time instances - template = np.zeros(np.prod(kwargs['shape']), dtype=int) - template[kwargs['indices']] = 1 - template = np.tile(template, num_nodes) - constraint_kwargs['indices'] = np.nonzero(template)[0] - - self.add_constraint(output_name, **constraint_kwargs) - - self._vars.append((input_name, output_name, kwargs['shape'])) - - # Setup partials - - all_shape = (num_nodes,) + kwargs['shape'] - var_size = np.prod(kwargs['shape']) - all_size = np.prod(all_shape) - - all_row_starts = np.arange(num_nodes, dtype=int) * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) - - def compute(self, inputs, outputs): - for (input_name, output_name, _) in self._vars: - outputs[output_name] = inputs[input_name] + def setup(self): + """ + Define the independent variables as output variables. + """ + num_nodes = self.options['num_nodes'] + + for (name, kwargs) in self._path_constraints: + + input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} + input_name = 'all_values:{0}'.format(name) + self.add_input(input_name, + shape=(num_nodes,) + kwargs['shape'], + **input_kwargs) + + output_name = 'path:{0}'.format(name) + output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} + output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] + self.add_output(output_name, **output_kwargs) + + constraint_kwargs = {k: kwargs.get(k, None) + for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', + 'scaler', 'indices', 'linear')} + + # Convert indices from those in one time instance to those in all time instances + template = np.zeros(np.prod(kwargs['shape']), dtype=int) + template[kwargs['indices']] = 1 + template = np.tile(template, num_nodes) + constraint_kwargs['indices'] = np.nonzero(template)[0] + + self.add_constraint(output_name, **constraint_kwargs) + + self._vars.append((input_name, output_name, kwargs['shape'])) + + # Setup partials + + all_shape = (num_nodes,) + kwargs['shape'] + var_size = np.prod(kwargs['shape']) + all_size = np.prod(all_shape) + + all_row_starts = np.arange(num_nodes, dtype=int) * var_size + all_rows = [] + for i in all_row_starts: + all_rows.extend(range(i, i + var_size)) + all_rows = np.asarray(all_rows, dtype=int) + + self.declare_partials( + of=output_name, + wrt=input_name, + dependent=True, + rows=all_rows, + cols=np.arange(all_size), + val=1.0) + + def compute(self, inputs, outputs): + for (input_name, output_name, _) in self._vars: + outputs[output_name] = inputs[input_name] diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_timeseries_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_timeseries_comp.py index 5ed0c113a..510eb4553 100644 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_timeseries_comp.py +++ b/dymos/transcriptions/runge_kutta/components/runge_kutta_timeseries_comp.py @@ -1,8 +1,11 @@ from __future__ import print_function, division, absolute_import import numpy as np +from scipy.linalg import block_diag from ...common.timeseries_output_comp import TimeseriesOutputCompBase +from ....transcriptions.grid_data import GridData +from dymos.utils.lagrange import lagrange_matrices class RungeKuttaTimeseriesOutputComp(TimeseriesOutputCompBase): @@ -11,37 +14,82 @@ def setup(self): """ Define the independent variables as output variables. """ - grid_data = self.options['grid_data'] - num_nodes = 2 * grid_data.num_segments + igd = self.options['input_grid_data'] + ogd = self.options['output_grid_data'] + output_subset = self.options['output_subset'] + + if ogd is None: + ogd = igd + + # Build the interpolation matrix which maps from the input grid to the output grid. + # Rather than a single phase-wide interpolating polynomial, map each segment. + # To do this, find the nodes in the output grid which fall in each segment of the input + # grid. Then build a Lagrange interpolating polynomial for that segment + L_blocks = [] + output_nodes_ptau = list(ogd.node_ptau[ogd.subset_node_indices[output_subset]]) + + for iseg in range(igd.num_segments): + i1, i2 = igd.segment_indices[iseg] + iptau_segi = np.take(igd.node_ptau, (i1, i2-1)) + istau_segi = np.take(igd.node_stau, (i1, i2-1)) + + # The indices of the output grid that fall within this segment of the input grid + if ogd is igd: + optau_segi = iptau_segi + else: + ptau_hi = igd.segment_ends[iseg+1] + if iseg < igd.num_segments - 1: + idxs_in_iseg = np.where(output_nodes_ptau <= ptau_hi)[0] + else: + idxs_in_iseg = np.arange(len(output_nodes_ptau)) + optau_segi = np.asarray(output_nodes_ptau)[idxs_in_iseg] + # Remove the captured nodes so we don't accidentally include them again + output_nodes_ptau = output_nodes_ptau[len(idxs_in_iseg):] + + # Now get the output nodes which fall in iseg in iseg's segment tau space. + ostau_segi = 2.0 * (optau_segi - iptau_segi[0]) / (iptau_segi[-1] - iptau_segi[0]) - 1 + + # Create the interpolation matrix and add it to the blocks + L, _ = lagrange_matrices(istau_segi, ostau_segi) + L_blocks.append(L) + + self.interpolation_matrix = block_diag(*L_blocks) + r, c = np.nonzero(self.interpolation_matrix) + + output_num_nodes, input_num_nodes = self.interpolation_matrix.shape for (name, kwargs) in self._timeseries_outputs: input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'segend_values:{0}'.format(name) + input_name = 'input_values:{0}'.format(name) self.add_input(input_name, - shape=(num_nodes,) + kwargs['shape'], + shape=(input_num_nodes,) + kwargs['shape'], **input_kwargs) output_name = name output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] + output_kwargs['shape'] = (output_num_nodes,) + kwargs['shape'] self.add_output(output_name, **output_kwargs) self._vars.append((input_name, output_name, kwargs['shape'])) - # Setup partials - segend_shape = (num_nodes,) + kwargs['shape'] - segend_size = np.prod(segend_shape) + size = np.prod(kwargs['shape']) + val_jac = np.zeros((output_num_nodes, size, input_num_nodes, size)) + + for i in range(size): + val_jac[:, i, :, i] = self.interpolation_matrix + + val_jac = val_jac.reshape((output_num_nodes * size, input_num_nodes * size), + order='C') - ar = np.arange(segend_size) + val_jac_rows, val_jac_cols = np.where(val_jac != 0) - self.declare_partials( - of=output_name, - wrt=input_name, - rows=ar, - cols=ar, - val=1.0) + rs, cs = val_jac_rows, val_jac_cols + self.declare_partials(of=output_name, + wrt=input_name, + rows=rs, cols=cs, val=val_jac[rs, cs]) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): for (input_name, output_name, _) in self._vars: - outputs[output_name] = inputs[input_name] + outputs[output_name] = np.tensordot(self.interpolation_matrix, inputs[input_name], + axes=(1, 0)) diff --git a/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py b/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py index 33263b298..1b3e09d46 100644 --- a/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py +++ b/dymos/transcriptions/runge_kutta/components/test/test_rk_path_constraint_comp.py @@ -1,79 +1,79 @@ -from __future__ import print_function, division, absolute_import - -import unittest - -import numpy as np -from numpy.testing import assert_almost_equal -import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials - -from dymos.transcriptions.runge_kutta.components import RungeKuttaPathConstraintComp -from dymos.transcriptions.grid_data import GridData -from dymos.phase.options import ControlOptionsDictionary - - -class TestPathConstraintCompExplicit(unittest.TestCase): - - def setUp(self): - - transcription = 'runge-kutta' - - self.gd = gd = GridData(num_segments=2, - transcription_order='RK4', - segment_ends=[0.0, 3.0, 10.0], - transcription=transcription) - - nn = 4 - - self.p = om.Problem(model=om.Group()) - - controls = {'a': ControlOptionsDictionary(), - 'b': ControlOptionsDictionary(), - 'c': ControlOptionsDictionary(), - 'd': ControlOptionsDictionary()} - - controls['a'].update({'units': 'm', 'shape': (1,), 'opt': False}) - controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) - controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) - - ivc = om.IndepVarComp() - self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) - - ivc.add_output('a_disc', val=np.zeros((nn, 1)), units='m') - ivc.add_output('b_disc', val=np.zeros((nn, 3)), units='s') - ivc.add_output('c_disc', val=np.zeros((nn, 3, 3)), units='kg') - - path_comp = RungeKuttaPathConstraintComp(grid_data=gd) - - self.p.model.add_subsystem('path_constraints', subsys=path_comp) - - path_comp._add_path_constraint('a', var_class='ode', shape=(1,), - lower=0, upper=10, units='m') - path_comp._add_path_constraint('b', var_class='input_control', shape=(3,), - lower=0, upper=10, units='s') - path_comp._add_path_constraint('c', var_class='control_rate2', shape=(3, 3), - lower=0, upper=10, units='kg') - - self.p.model.connect('a_disc', 'path_constraints.all_values:a') - self.p.model.connect('b_disc', 'path_constraints.all_values:b') - self.p.model.connect('c_disc', 'path_constraints.all_values:c') - - self.p.setup() - - self.p.run_model() - - def test_results(self): - p = self.p - assert_almost_equal(p['a_disc'], - p['path_constraints.path:a'][...]) - - assert_almost_equal(p['b_disc'], - p['path_constraints.path:b'][...]) - - assert_almost_equal(p['c_disc'], - p['path_constraints.path:c'][...]) - - def test_partials(self): - np.set_printoptions(linewidth=1024, edgeitems=1000) - cpd = self.p.check_partials(out_stream=None) - assert_check_partials(cpd) +# from __future__ import print_function, division, absolute_import +# +# import unittest +# +# import numpy as np +# from numpy.testing import assert_almost_equal +# import openmdao.api as om +# from openmdao.utils.assert_utils import assert_check_partials +# +# from dymos.transcriptions.runge_kutta.components import RungeKuttaPathConstraintComp +# from dymos.transcriptions.grid_data import GridData +# from dymos.phase.options import ControlOptionsDictionary +# +# +# class TestPathConstraintCompExplicit(unittest.TestCase): +# +# def setUp(self): +# +# transcription = 'runge-kutta' +# +# self.gd = gd = GridData(num_segments=2, +# transcription_order='RK4', +# segment_ends=[0.0, 3.0, 10.0], +# transcription=transcription) +# +# nn = gd.subset_num_nodes['segment_ends'] +# +# self.p = om.Problem(model=om.Group()) +# +# controls = {'a': ControlOptionsDictionary(), +# 'b': ControlOptionsDictionary(), +# 'c': ControlOptionsDictionary(), +# 'd': ControlOptionsDictionary()} +# +# controls['a'].update({'units': 'm', 'shape': (1,), 'opt': False}) +# controls['b'].update({'units': 's', 'shape': (3,), 'opt': False}) +# controls['c'].update({'units': 'kg', 'shape': (3, 3), 'opt': False}) +# +# ivc = om.IndepVarComp() +# self.p.model.add_subsystem('ivc', ivc, promotes_outputs=['*']) +# +# ivc.add_output('a_disc', val=np.zeros((nn, 1)), units='m') +# ivc.add_output('b_disc', val=np.zeros((nn, 3)), units='s') +# ivc.add_output('c_disc', val=np.zeros((nn, 3, 3)), units='kg') +# +# path_comp = RungeKuttaPathConstraintComp(num_nodes=gd.num_nodes) +# +# self.p.model.add_subsystem('path_constraints', subsys=path_comp) +# +# path_comp._add_path_constraint('a', var_class='ode', shape=(1,), +# lower=0, upper=10, units='m') +# path_comp._add_path_constraint('b', var_class='input_control', shape=(3,), +# lower=0, upper=10, units='s') +# path_comp._add_path_constraint('c', var_class='control_rate2', shape=(3, 3), +# lower=0, upper=10, units='kg') +# +# self.p.model.connect('a_disc', 'path_constraints.all_values:a') +# self.p.model.connect('b_disc', 'path_constraints.all_values:b') +# self.p.model.connect('c_disc', 'path_constraints.all_values:c') +# +# self.p.setup() +# +# self.p.run_model() +# +# def test_results(self): +# p = self.p +# assert_almost_equal(p['a_disc'], +# p['path_constraints.path:a'][...]) +# +# assert_almost_equal(p['b_disc'], +# p['path_constraints.path:b'][...]) +# +# assert_almost_equal(p['c_disc'], +# p['path_constraints.path:c'][...]) +# +# def test_partials(self): +# np.set_printoptions(linewidth=1024, edgeitems=1000) +# cpd = self.p.check_partials(out_stream=None) +# assert_check_partials(cpd) diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index 835074267..3ec8242c9 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -8,7 +8,7 @@ from ..transcription_base import TranscriptionBase from .components import RungeKuttaStepsizeComp, RungeKuttaStateContinuityIterGroup, \ RungeKuttaTimeseriesOutputComp, RungeKuttaPathConstraintComp, RungeKuttaControlContinuityComp -from ..common import TimeComp, EndpointConditionsComp +from ..common import TimeComp, EndpointConditionsComp, PseudospectralPathConstraintComp from ...utils.rk_methods import rk_methods from ...utils.misc import CoerceDesvar, get_rate_units from ...utils.constants import INF_BOUND @@ -524,7 +524,7 @@ def setup_path_constraints(self, phase): num_seg = gd.num_segments if phase._path_constraints: - path_comp = RungeKuttaPathConstraintComp(grid_data=gd) + path_comp = PseudospectralPathConstraintComp(num_nodes=gd.subset_num_nodes['segment_ends']) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): @@ -679,169 +679,180 @@ def setup_timeseries_outputs(self, phase): gd = self.grid_data num_seg = gd.num_segments time_units = phase.time_options['units'] - timeseries_comp = RungeKuttaTimeseriesOutputComp(grid_data=gd) - phase.add_subsystem('timeseries', subsys=timeseries_comp) - src_idxs = get_src_indices_by_row(gd.subset_node_indices['segment_ends'], (1,)) - - timeseries_comp._add_timeseries_output('time', - var_class=phase.classify_var('time'), - units=time_units) - phase.connect(src_name='time', tgt_name='timeseries.segend_values:time', - src_indices=src_idxs, flat_src_indices=True) - - timeseries_comp._add_timeseries_output('time_phase', - var_class=phase.classify_var('time_phase'), - units=time_units) - phase.connect(src_name='time_phase', tgt_name='timeseries.segend_values:time_phase', - src_indices=src_idxs, flat_src_indices=True) - - for name, options in iteritems(phase.state_options): - timeseries_comp._add_timeseries_output('states:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=options['units']) - row_idxs = np.repeat(np.arange(1, num_seg, dtype=int), repeats=2) - row_idxs = np.concatenate(([0], row_idxs, [num_seg])) - src_idxs = get_src_indices_by_row(row_idxs, options['shape']) - phase.connect(src_name='states:{0}'.format(name), - tgt_name='timeseries.segend_values:states:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.control_options): - control_units = options['units'] - timeseries_comp._add_timeseries_output('controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - src_rows = gd.subset_node_indices['segment_ends'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='control_values:{0}'.format(name), - tgt_name='timeseries.segend_values:controls:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + for name, options in iteritems(phase._timeseries): - # # Control rates - timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='control_rates:{0}_rate'.format(name), - tgt_name='timeseries.segend_values:control_rates:{0}_rate'.format(name), + if options['transcription'] is None: + ogd = None + else: + options['transcription'].setup_grid(phase) + ogd = options['transcription'].grid_data + + timeseries_comp = RungeKuttaTimeseriesOutputComp(input_grid_data=gd, + output_grid_data=ogd, + output_subset=options['subset']) + phase.add_subsystem(name, subsys=timeseries_comp) + src_idxs = get_src_indices_by_row(gd.subset_node_indices['segment_ends'], (1,)) + + timeseries_comp._add_timeseries_output('time', + var_class=phase.classify_var('time'), + units=time_units) + phase.connect(src_name='time', tgt_name='{0}.input_values:time'.format(name), src_indices=src_idxs, flat_src_indices=True) - # Control second derivatives - timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.segend_values:control_rates:{0}_rate2'.format(name), + timeseries_comp._add_timeseries_output('time_phase', + var_class=phase.classify_var('time_phase'), + units=time_units) + phase.connect(src_name='time_phase', tgt_name='{0}.input_values:time_phase'.format(name), src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.polynomial_control_options): - control_units = options['units'] - timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=control_units) - src_rows = gd.subset_node_indices['segment_ends'] - src_idxs = get_src_indices_by_row(src_rows, options['shape']) - phase.connect(src_name='polynomial_control_values:{0}'.format(name), - tgt_name='timeseries.segend_values:polynomial_controls:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + for state_name, options in iteritems(phase.state_options): + timeseries_comp._add_timeseries_output('states:{0}'.format(state_name), + var_class=phase.classify_var(state_name), + shape=options['shape'], + units=options['units']) + row_idxs = np.repeat(np.arange(1, num_seg, dtype=int), repeats=2) + row_idxs = np.concatenate(([0], row_idxs, [num_seg])) + src_idxs = get_src_indices_by_row(row_idxs, options['shape']) + phase.connect(src_name='states:{0}'.format(state_name), + tgt_name='{0}.input_values:states:{1}'.format(name, state_name), + src_indices=src_idxs, flat_src_indices=True) - # # Control rates - timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=1)) - phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(name), - tgt_name='timeseries.segend_values:polynomial_control_rates' - ':{0}_rate'.format(name), - src_indices=src_idxs, flat_src_indices=True) + for control_name, options in iteritems(phase.control_options): + control_units = options['units'] + timeseries_comp._add_timeseries_output('controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + src_rows = gd.subset_node_indices['segment_ends'] + src_idxs = get_src_indices_by_row(src_rows, options['shape']) + phase.connect(src_name='control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:controls:{1}'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - # Control second derivatives - timeseries_comp._add_timeseries_output('polynomial_control_rates:' - '{0}_rate2'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=get_rate_units(control_units, - time_units, - deriv=2)) - phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(name), - tgt_name='timeseries.segend_values:polynomial_control_rates' - ':{0}_rate2'.format(name), - src_indices=src_idxs, flat_src_indices=True) + # # Control rates + timeseries_comp._add_timeseries_output('control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.design_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - shape=options['shape'], - units=units) + # Control second derivatives + timeseries_comp._add_timeseries_output('control_rates:{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:control_rates:{1}_rate2'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + for control_name, options in iteritems(phase.polynomial_control_options): + control_units = options['units'] + timeseries_comp._add_timeseries_output('polynomial_controls:{0}'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=control_units) + src_rows = gd.subset_node_indices['segment_ends'] + src_idxs = get_src_indices_by_row(src_rows, options['shape']) + phase.connect(src_name='polynomial_control_values:{0}'.format(control_name), + tgt_name='{0}.input_values:polynomial_controls:{1}'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - phase.connect(src_name='design_parameters:{0}'.format(name), - tgt_name='timeseries.segend_values:design_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + # # Control rates + timeseries_comp._add_timeseries_output('polynomial_control_rates:{0}_rate'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=1)) + phase.connect(src_name='polynomial_control_rates:{0}_rate'.format(control_name), + tgt_name='{0}.input_values:polynomial_control_rates' + ':{1}_rate'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - for name, options in iteritems(phase.input_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - units=units) + # Control second derivatives + timeseries_comp._add_timeseries_output('polynomial_control_rates:' + '{0}_rate2'.format(control_name), + var_class=phase.classify_var(control_name), + shape=options['shape'], + units=get_rate_units(control_units, + time_units, + deriv=2)) + phase.connect(src_name='polynomial_control_rates:{0}_rate2'.format(control_name), + tgt_name='{0}.input_values:polynomial_control_rates' + ':{1}_rate2'.format(name, control_name), + src_indices=src_idxs, flat_src_indices=True) - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + for param_name, options in iteritems(phase.design_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('design_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + shape=options['shape'], + units=units) - phase.connect(src_name='input_parameters:{0}_out'.format(name), - tgt_name='timeseries.segend_values:input_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - for name, options in iteritems(phase.traj_parameter_options): - units = options['units'] - timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(name), - var_class=phase.classify_var(name), - units=units) + phase.connect(src_name='design_parameters:{0}'.format(param_name), + tgt_name='{0}.input_values:design_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) - src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) + for param_name, options in iteritems(phase.input_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('input_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + units=units) - phase.connect(src_name='traj_parameters:{0}_out'.format(name), - tgt_name='timeseries.segend_values:traj_parameters:{0}'.format(name), - src_indices=src_idxs, flat_src_indices=True) + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - for var, options in iteritems(phase._timeseries_outputs): - output_name = options['output_name'] + phase.connect(src_name='input_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:input_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - # Determine the path to the variable which we will be constraining - # This is more complicated for path constraints since, for instance, - # a single state variable has two sources which must be connected to - # the path component. - var_type = phase.classify_var(var) + for param_name, options in iteritems(phase.traj_parameter_options): + units = options['units'] + timeseries_comp._add_timeseries_output('traj_parameters:{0}'.format(param_name), + var_class=phase.classify_var(param_name), + units=units) - # Ignore any variables that we've already added (states, times, controls, etc) - if var_type != 'ode': - continue + src_idxs_raw = np.zeros(self.grid_data.subset_num_nodes['segment_ends'], dtype=int) + src_idxs = get_src_indices_by_row(src_idxs_raw, options['shape']) - # Assume scalar shape if None, but check config will warn that it's inferred. - if options['shape'] is None: - options['shape'] = (1,) + phase.connect(src_name='traj_parameters:{0}_out'.format(param_name), + tgt_name='{0}.input_values:traj_parameters:{1}'.format(name, param_name), + src_indices=src_idxs, flat_src_indices=True) - # Failed to find variable, assume it is in the RHS - phase.connect(src_name='ode.{0}'.format(var), - tgt_name='timeseries.segend_values:{0}'.format(output_name)) + for var, options in iteritems(phase._timeseries[name]['outputs']): + output_name = options['output_name'] - kwargs = options.copy() - kwargs.pop('output_name', None) - timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) + # Determine the path to the variable which we will be constraining + # This is more complicated for path constraints since, for instance, + # a single state variable has two sources which must be connected to + # the path component. + var_type = phase.classify_var(var) + + # Ignore any variables that we've already added (states, times, controls, etc) + if var_type != 'ode': + continue + + # Assume scalar shape if None, but check config will warn that it's inferred. + if options['shape'] is None: + options['shape'] = (1,) + + # Failed to find variable, assume it is in the RHS + phase.connect(src_name='ode.{0}'.format(var), + tgt_name='{0}.input_values:{1}'.format(name, output_name)) + + kwargs = options.copy() + kwargs.pop('output_name', None) + timeseries_comp._add_timeseries_output(output_name, var_type, **kwargs) def get_parameter_connections(self, name, phase): """ diff --git a/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py b/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py index abd416f42..45eb78355 100644 --- a/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py +++ b/dymos/transcriptions/runge_kutta/test/test_rk4_simple_integration.py @@ -87,7 +87,7 @@ def test_simple_integration_backward(self): p = om.Problem(model=om.Group()) - phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=4, method='RK4')) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) @@ -104,14 +104,16 @@ def test_simple_integration_backward(self): p.run_model() - expected = np.atleast_2d(_test_ode_solution(p['phase0.ode.y'], p['phase0.ode.t'])).T + expected = np.atleast_2d(_test_ode_solution(p['phase0.ode.y'], p['phase0.timeseries.time'])) + print(expected) + print(p['phase0.timeseries.states:y']) assert_rel_error(self, p['phase0.timeseries.states:y'], expected, tolerance=1.0E-3) def test_simple_integration_backward_connected_initial(self): p = om.Problem(model=om.Group()) - phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=4, method='RK4')) + phase = dm.Phase(ode_class=TestODE, transcription=dm.RungeKutta(num_segments=200, method='RK4')) p.model.add_subsystem('phase0', subsys=phase) phase.set_time_options(fix_initial=True, fix_duration=True) @@ -132,7 +134,7 @@ def test_simple_integration_backward_connected_initial(self): p.run_model() - expected = np.atleast_2d(_test_ode_solution(p['phase0.ode.y'], p['phase0.ode.t'])).T + expected = np.atleast_2d(_test_ode_solution(p['phase0.ode.y'], p['phase0.timeseries.time'])) assert_rel_error(self, p['phase0.timeseries.states:y'], expected, tolerance=1.0E-3) diff --git a/dymos/transcriptions/solve_ivp/components/solve_ivp_timeseries_comp.py b/dymos/transcriptions/solve_ivp/components/solve_ivp_timeseries_comp.py index e6bde4080..93a1231a1 100644 --- a/dymos/transcriptions/solve_ivp/components/solve_ivp_timeseries_comp.py +++ b/dymos/transcriptions/solve_ivp/components/solve_ivp_timeseries_comp.py @@ -17,7 +17,7 @@ def setup(self): """ Define the independent variables as output variables. """ - grid_data = self.options['grid_data'] + grid_data = self.options['input_grid_data'] if self.options['output_nodes_per_seg'] is None: num_nodes = grid_data.num_nodes else: diff --git a/dymos/transcriptions/solve_ivp/solve_ivp.py b/dymos/transcriptions/solve_ivp/solve_ivp.py index 4da1854b7..338f40a5a 100644 --- a/dymos/transcriptions/solve_ivp/solve_ivp.py +++ b/dymos/transcriptions/solve_ivp/solve_ivp.py @@ -338,7 +338,7 @@ def setup_timeseries_outputs(self, phase): output_nodes_per_seg = self.options['output_nodes_per_seg'] timeseries_comp = \ - SolveIVPTimeseriesOutputComp(grid_data=gd, + SolveIVPTimeseriesOutputComp(input_grid_data=gd, output_nodes_per_seg=self.options['output_nodes_per_seg']) phase.add_subsystem('timeseries', subsys=timeseries_comp) @@ -476,7 +476,7 @@ def setup_timeseries_outputs(self, phase): tgt_name='timeseries.all_values:traj_parameters:{0}'.format(name), src_indices=src_idxs, flat_src_indices=True) - for var, options in iteritems(phase._timeseries_outputs): + for var, options in iteritems(phase._timeseries['timeseries']['outputs']): output_name = options['output_name'] # Determine the path to the variable which we will be constraining diff --git a/dymos/transcriptions/transcription_base.py b/dymos/transcriptions/transcription_base.py index 15839d60a..074afc956 100644 --- a/dymos/transcriptions/transcription_base.py +++ b/dymos/transcriptions/transcription_base.py @@ -458,21 +458,22 @@ def check_config(self, phase, logger): 'is not scalar, connection errors will ' 'result.'.format(var, phase.name)) - for var, options in iteritems(phase._timeseries_outputs): + for name, timeseries_options in iteritems(phase._timeseries): + for var, options in iteritems(phase._timeseries[name]['outputs']): - # Determine the path to the variable which we will be constraining - # This is more complicated for path constraints since, for instance, - # a single state variable has two sources which must be connected to - # the path component. - var_type = phase.classify_var(var) + # Determine the path to the variable which we will be constraining + # This is more complicated for path constraints since, for instance, + # a single state variable has two sources which must be connected to + # the path component. + var_type = phase.classify_var(var) - # Ignore any variables that we've already added (states, times, controls, etc) - if var_type != 'ode': - continue + # Ignore any variables that we've already added (states, times, controls, etc) + if var_type != 'ode': + continue - # Assume scalar shape here, but check config will warn that it's inferred. - if options['shape'] is None: - logger.warning('Unable to infer shape of timeseries output \'{0}\' in ' - 'phase \'{1}\'. Scalar assumed. If this ODE output is ' - 'is not scalar, connection errors will ' - 'result.'.format(var, phase.name)) + # Assume scalar shape here, but check config will warn that it's inferred. + if options['shape'] is None: + logger.warning('Unable to infer shape of timeseries output \'{0}\' in ' + 'phase \'{1}\'. Scalar assumed. If this ODE output is ' + 'is not scalar, connection errors will ' + 'result.'.format(var, phase.name)) diff --git a/release_notes.txt b/release_notes.txt deleted file mode 100644 index a110b87e6..000000000 --- a/release_notes.txt +++ /dev/null @@ -1,51 +0,0 @@ -################################################################################################ -Release Notes for Dymos 0.9.0 - -July 05, 2018 - - -This version updates the way controls are parameterized in Radau Pseudospectral phases. For a -segment of order n, there are n+1 total nodes. The left-most n nodes comprise the 'control_disc' -subset. Due to differences with the Gauss-Lobatto method, new subsets 'control_input' and -'state_input' were added. These are identical to the discretization subsets when using an uncompessed -transcription. When transcription is compressed, the control is only specified at the first point -in a shared segment bound. - -For instance, for Radau Pseudospectral, three adjacent segments of order 3might look like this: - -0 1 2 3 -x--x--x--o 5 6 7 - x--x--x--o 9 10 11 - 4 x--x--x--o - 8 - -Subsets 'control_input' and 'control_disc' consists of indices [0, 1, 2, 4, 5, 6, 8, 9, 10]. -Since the control is defined by n nodes on each segment, it has order n-1, consistent with that of -the Gauss-Lobatto method. - -For Gauss-Lobatto, three adjacent segments of order 3 might look like this: - -0 1 2 -o--x--o 4 5 - o--x--o 7 8 - 3 o--x--o - 6 - -Here the 'control_disc' subset consists of all nodes [0, 1, 2, 3, 4, 5, 6, 7, 8] while the control -input subset omits the duplicate indices, 3 and 6, and is thus [0, 1, 2, 4, 5, 7, 8]. Again, the -control has order n-1. - -Control value continuity is a linear constraint in the Gauss-Lobatto phase while it is a nonlinear -constraint in the Radau Pseudospectral phase, since an interpolation is required. For instance, the -value on segment 0, node 3 is obtained by an interpolation using values at [0, 1, 2]. - - -New Features: -------------- -- The 'control_input' subset is now where all controls should be provided, and changes based on the transcription and compression setting. -- The 'state_input' is where all state values should be provided. -- The argument `dynamic` is no longer valid for `add_control`. All controls are dynamic, and static controls should be added with `add_design_parameter`. -- Design parameters do not have associated rates. -- Control continuity is always computed, but only enforced when requested by the user. - -################################################################################################ From ea828901e6a15f07385baa101982d49b30be881e Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Wed, 17 Jul 2019 17:48:54 -0400 Subject: [PATCH 12/13] Cleanup (#204) * removed uncessary components --- dymos/trajectory/trajectory.py | 1 + dymos/transcriptions/common/__init__.py | 2 +- .../common/path_constraint_comp.py | 191 +----------------- .../common/test/test_path_constraint_comp.py | 4 +- .../pseudospectral/gauss_lobatto.py | 4 +- .../pseudospectral/radau_pseudospectral.py | 4 +- .../runge_kutta/components/__init__.py | 1 - .../runge_kutta_path_constraint_comp.py | 65 ------ .../transcriptions/runge_kutta/runge_kutta.py | 6 +- 9 files changed, 12 insertions(+), 266 deletions(-) delete mode 100644 dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py diff --git a/dymos/trajectory/trajectory.py b/dymos/trajectory/trajectory.py index dde115248..c2318ae4b 100644 --- a/dymos/trajectory/trajectory.py +++ b/dymos/trajectory/trajectory.py @@ -476,6 +476,7 @@ def setup(self): g = phases_group.add_subsystem(name, phs, **self._phase_add_kwargs[name]) # DirectSolvers were moved down into the phases for use with MPI g.linear_solver = om.DirectSolver() + phs.finalize_variables() if self._linkages: diff --git a/dymos/transcriptions/common/__init__.py b/dymos/transcriptions/common/__init__.py index 43dd10d8f..ce41abe66 100644 --- a/dymos/transcriptions/common/__init__.py +++ b/dymos/transcriptions/common/__init__.py @@ -6,7 +6,7 @@ from .polynomial_control_group import PolynomialControlGroup from .input_parameter_comp import InputParameterComp from .endpoint_conditions_comp import EndpointConditionsComp -from .path_constraint_comp import PseudospectralPathConstraintComp +from .path_constraint_comp import PathConstraintComp from .timeseries_output_comp import PseudospectralTimeseriesOutputComp, ExplicitTimeseriesOutputComp from .phase_linkage_comp import PhaseLinkageComp from .time_comp import TimeComp diff --git a/dymos/transcriptions/common/path_constraint_comp.py b/dymos/transcriptions/common/path_constraint_comp.py index 1f21c6f88..c593a1bd5 100644 --- a/dymos/transcriptions/common/path_constraint_comp.py +++ b/dymos/transcriptions/common/path_constraint_comp.py @@ -3,11 +3,10 @@ import numpy as np import openmdao.api as om -from dymos.transcriptions.grid_data import GridData from dymos.utils.constants import INF_BOUND -class PathConstraintCompBase(om.ExplicitComponent): +class PathConstraintComp(om.ExplicitComponent): def initialize(self): self._path_constraints = [] @@ -88,194 +87,6 @@ def _add_path_constraint(self, name, var_class, shape=None, units=None, res_unit 'type_': type_} self._path_constraints.append((name, kwargs)) - -# class GaussLobattoPathConstraintComp(PathConstraintCompBase): -# -# def setup(self): -# """ -# Define the independent variables as output variables. -# """ -# grid_data = self.options['grid_data'] -# -# num_nodes = grid_data.num_nodes -# num_state_disc_nodes = grid_data.subset_num_nodes['state_disc'] -# num_col_nodes = grid_data.subset_num_nodes['col'] -# for (name, kwargs) in self._path_constraints: -# input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} -# shape = kwargs['shape'] -# -# if isinstance(shape, list): -# shape = tuple(shape) -# -# if not isinstance(shape, tuple): -# shape = (shape,) -# -# if kwargs['src_all']: -# all_input_name = 'all_values:{0}'.format(name) -# disc_input_name = col_input_name = '' -# self.add_input(all_input_name, -# shape=(num_nodes,) + shape, -# **input_kwargs) -# else: -# all_input_name = '' -# disc_input_name = 'disc_values:{0}'.format(name) -# col_input_name = 'col_values:{0}'.format(name) -# -# self.add_input(disc_input_name, -# shape=(num_state_disc_nodes,) + shape, -# **input_kwargs) -# -# self.add_input(col_input_name, -# shape=(num_col_nodes,) + shape, -# **input_kwargs) -# -# output_name = 'path:{0}'.format(name) -# output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} -# output_kwargs['shape'] = (num_nodes,) + shape -# self.add_output(output_name, **output_kwargs) -# -# self._vars.append((disc_input_name, col_input_name, all_input_name, -# kwargs['src_all'], output_name, shape)) -# -# constraint_kwargs = {k: kwargs.get(k, None) -# for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', -# 'scaler', 'indices', 'linear')} -# -# # Convert indices from those in one time instance to those in all time instances -# template = np.zeros(np.prod(kwargs['shape']), dtype=int) -# template[kwargs['indices']] = 1 -# template = np.tile(template, num_nodes) -# constraint_kwargs['indices'] = np.nonzero(template)[0] -# -# self.add_constraint(output_name, **constraint_kwargs) -# -# # Setup partials -# if kwargs['src_all']: -# all_shape = (num_nodes,) + shape -# var_size = np.prod(shape) -# all_size = np.prod(all_shape) -# -# all_row_starts = grid_data.subset_node_indices['all'] * var_size -# all_rows = [] -# for i in all_row_starts: -# all_rows.extend(range(i, i + var_size)) -# all_rows = np.asarray(all_rows, dtype=int) -# -# self.declare_partials( -# of=output_name, -# wrt=all_input_name, -# dependent=True, -# rows=all_rows, -# cols=np.arange(all_size), -# val=1.0) -# else: -# disc_shape = (num_state_disc_nodes,) + shape -# col_shape = (num_col_nodes,) + shape -# -# var_size = np.prod(shape) -# disc_size = np.prod(disc_shape) -# col_size = np.prod(col_shape) -# -# state_disc_row_starts = grid_data.subset_node_indices['state_disc'] * var_size -# disc_rows = [] -# for i in state_disc_row_starts: -# disc_rows.extend(range(i, i + var_size)) -# disc_rows = np.asarray(disc_rows, dtype=int) -# -# self.declare_partials( -# of=output_name, -# wrt=disc_input_name, -# dependent=True, -# rows=disc_rows, -# cols=np.arange(disc_size), -# val=1.0) -# -# col_row_starts = grid_data.subset_node_indices['col'] * var_size -# col_rows = [] -# for i in col_row_starts: -# col_rows.extend(range(i, i + var_size)) -# col_rows = np.asarray(col_rows, dtype=int) -# -# self.declare_partials( -# of=output_name, -# wrt=col_input_name, -# dependent=True, -# rows=col_rows, -# cols=np.arange(col_size), -# val=1.0) -# -# def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): -# disc_indices = self.options['grid_data'].subset_node_indices['state_disc'] -# col_indices = self.options['grid_data'].subset_node_indices['col'] -# for (disc_input_name, col_input_name, all_inp_name, src_all, output_name, _) in self._vars: -# if src_all: -# outputs[output_name] = inputs[all_inp_name] -# else: -# outputs[output_name][disc_indices] = inputs[disc_input_name] -# outputs[output_name][col_indices] = inputs[col_input_name] - - -class RadauPathConstraintComp(PathConstraintCompBase): - - def setup(self): - """ - Define the independent variables as output variables. - """ - grid_data = self.options['grid_data'] - num_nodes = grid_data.num_nodes - - for (name, kwargs) in self._path_constraints: - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'all_values:{0}'.format(name) - self.add_input(input_name, - shape=(num_nodes,) + kwargs['shape'], - **input_kwargs) - - output_name = 'path:{0}'.format(name) - output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] - self.add_output(output_name, **output_kwargs) - - constraint_kwargs = {k: kwargs.get(k, None) - for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', - 'scaler', 'indices', 'linear')} - - # Convert indices from those in one time instance to those in all time instances - template = np.zeros(np.prod(kwargs['shape']), dtype=int) - template[kwargs['indices']] = 1 - template = np.tile(template, num_nodes) - constraint_kwargs['indices'] = np.nonzero(template)[0] - - self.add_constraint(output_name, **constraint_kwargs) - - self._vars.append((input_name, output_name, kwargs['shape'])) - - # Setup partials - all_shape = (num_nodes,) + kwargs['shape'] - var_size = np.prod(kwargs['shape']) - all_size = np.prod(all_shape) - - all_row_starts = grid_data.subset_node_indices['all'] * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) - - def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - for (input_name, output_name, _) in self._vars: - outputs[output_name] = inputs[input_name] - - -class PseudospectralPathConstraintComp(PathConstraintCompBase): - def setup(self): """ Define the independent variables as output variables. diff --git a/dymos/transcriptions/common/test/test_path_constraint_comp.py b/dymos/transcriptions/common/test/test_path_constraint_comp.py index e8a9d60b7..35a97dd35 100644 --- a/dymos/transcriptions/common/test/test_path_constraint_comp.py +++ b/dymos/transcriptions/common/test/test_path_constraint_comp.py @@ -7,7 +7,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials -from dymos.transcriptions.common import PseudospectralPathConstraintComp +from dymos.transcriptions.common import PathConstraintComp from dymos.transcriptions.grid_data import GridData from dymos.phase.options import ControlOptionsDictionary @@ -43,7 +43,7 @@ def setUp(self): ivc.add_output('b_disc', val=np.zeros((ndn, 3)), units='s') ivc.add_output('c_disc', val=np.zeros((ndn, 3, 3)), units='kg') - path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) + path_comp = PathConstraintComp(num_nodes=gd.num_nodes) self.p.model.add_subsystem('path_constraints', subsys=path_comp) diff --git a/dymos/transcriptions/pseudospectral/gauss_lobatto.py b/dymos/transcriptions/pseudospectral/gauss_lobatto.py index 318acd334..82b11a586 100644 --- a/dymos/transcriptions/pseudospectral/gauss_lobatto.py +++ b/dymos/transcriptions/pseudospectral/gauss_lobatto.py @@ -7,7 +7,7 @@ from .pseudospectral_base import PseudospectralBase from .components import GaussLobattoInterleaveComp -from ..common import PseudospectralPathConstraintComp, PseudospectralTimeseriesOutputComp, \ +from ..common import PathConstraintComp, PseudospectralTimeseriesOutputComp, \ GaussLobattoContinuityComp from ...utils.misc import get_rate_units from ...utils.indexing import get_src_indices_by_row @@ -322,7 +322,7 @@ def setup_path_constraints(self, phase): time_units = phase.time_options['units'] if phase._path_constraints: - path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) + path_comp = PathConstraintComp(num_nodes=gd.num_nodes) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): diff --git a/dymos/transcriptions/pseudospectral/radau_pseudospectral.py b/dymos/transcriptions/pseudospectral/radau_pseudospectral.py index 7830bc41e..e866411db 100644 --- a/dymos/transcriptions/pseudospectral/radau_pseudospectral.py +++ b/dymos/transcriptions/pseudospectral/radau_pseudospectral.py @@ -7,7 +7,7 @@ from six import iteritems from .pseudospectral_base import PseudospectralBase -from ..common import PseudospectralPathConstraintComp, RadauPSContinuityComp, PseudospectralTimeseriesOutputComp +from ..common import PathConstraintComp, RadauPSContinuityComp, PseudospectralTimeseriesOutputComp from ...utils.misc import get_rate_units from ...utils.indexing import get_src_indices_by_row from ..grid_data import GridData @@ -158,7 +158,7 @@ def setup_path_constraints(self, phase): time_units = phase.time_options['units'] if phase._path_constraints: - path_comp = PseudospectralPathConstraintComp(num_nodes=gd.num_nodes) + path_comp = PathConstraintComp(num_nodes=gd.num_nodes) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): diff --git a/dymos/transcriptions/runge_kutta/components/__init__.py b/dymos/transcriptions/runge_kutta/components/__init__.py index 84582c3eb..7a9ddc46a 100644 --- a/dymos/transcriptions/runge_kutta/components/__init__.py +++ b/dymos/transcriptions/runge_kutta/components/__init__.py @@ -4,5 +4,4 @@ from .runge_kutta_stepsize_comp import RungeKuttaStepsizeComp from .runge_kutta_state_continuity_iter_group import RungeKuttaStateContinuityIterGroup from .runge_kutta_timeseries_comp import RungeKuttaTimeseriesOutputComp -from .runge_kutta_path_constraint_comp import RungeKuttaPathConstraintComp from .runge_kutta_control_continuity_comp import RungeKuttaControlContinuityComp diff --git a/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py b/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py deleted file mode 100644 index 6304f9097..000000000 --- a/dymos/transcriptions/runge_kutta/components/runge_kutta_path_constraint_comp.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import print_function, division, absolute_import - -import numpy as np - -from ...common.path_constraint_comp import PathConstraintCompBase - - -class RungeKuttaPathConstraintComp(PathConstraintCompBase): - - def setup(self): - """ - Define the independent variables as output variables. - """ - num_nodes = self.options['num_nodes'] - - for (name, kwargs) in self._path_constraints: - - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'all_values:{0}'.format(name) - self.add_input(input_name, - shape=(num_nodes,) + kwargs['shape'], - **input_kwargs) - - output_name = 'path:{0}'.format(name) - output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (num_nodes,) + kwargs['shape'] - self.add_output(output_name, **output_kwargs) - - constraint_kwargs = {k: kwargs.get(k, None) - for k in ('lower', 'upper', 'equals', 'ref', 'ref0', 'adder', - 'scaler', 'indices', 'linear')} - - # Convert indices from those in one time instance to those in all time instances - template = np.zeros(np.prod(kwargs['shape']), dtype=int) - template[kwargs['indices']] = 1 - template = np.tile(template, num_nodes) - constraint_kwargs['indices'] = np.nonzero(template)[0] - - self.add_constraint(output_name, **constraint_kwargs) - - self._vars.append((input_name, output_name, kwargs['shape'])) - - # Setup partials - - all_shape = (num_nodes,) + kwargs['shape'] - var_size = np.prod(kwargs['shape']) - all_size = np.prod(all_shape) - - all_row_starts = np.arange(num_nodes, dtype=int) * var_size - all_rows = [] - for i in all_row_starts: - all_rows.extend(range(i, i + var_size)) - all_rows = np.asarray(all_rows, dtype=int) - - self.declare_partials( - of=output_name, - wrt=input_name, - dependent=True, - rows=all_rows, - cols=np.arange(all_size), - val=1.0) - - def compute(self, inputs, outputs): - for (input_name, output_name, _) in self._vars: - outputs[output_name] = inputs[input_name] diff --git a/dymos/transcriptions/runge_kutta/runge_kutta.py b/dymos/transcriptions/runge_kutta/runge_kutta.py index 3ec8242c9..a366fb7f9 100644 --- a/dymos/transcriptions/runge_kutta/runge_kutta.py +++ b/dymos/transcriptions/runge_kutta/runge_kutta.py @@ -7,8 +7,8 @@ from ..transcription_base import TranscriptionBase from .components import RungeKuttaStepsizeComp, RungeKuttaStateContinuityIterGroup, \ - RungeKuttaTimeseriesOutputComp, RungeKuttaPathConstraintComp, RungeKuttaControlContinuityComp -from ..common import TimeComp, EndpointConditionsComp, PseudospectralPathConstraintComp + RungeKuttaTimeseriesOutputComp, RungeKuttaControlContinuityComp +from ..common import TimeComp, EndpointConditionsComp, PathConstraintComp from ...utils.rk_methods import rk_methods from ...utils.misc import CoerceDesvar, get_rate_units from ...utils.constants import INF_BOUND @@ -524,7 +524,7 @@ def setup_path_constraints(self, phase): num_seg = gd.num_segments if phase._path_constraints: - path_comp = PseudospectralPathConstraintComp(num_nodes=gd.subset_num_nodes['segment_ends']) + path_comp = PathConstraintComp(num_nodes=gd.subset_num_nodes['segment_ends']) phase.add_subsystem('path_constraints', subsys=path_comp) for var, options in iteritems(phase._path_constraints): From a4ce10f46f86933e62045a2e30c4730589c77c1a Mon Sep 17 00:00:00 2001 From: Rob Falck Date: Thu, 18 Jul 2019 10:21:33 -0400 Subject: [PATCH 13/13] coverage improvements (#205) --- ...brachistochrone_vector_path_constraints.py | 5 +- dymos/transcriptions/common/__init__.py | 2 +- .../common/timeseries_output_comp.py | 58 +------------------ 3 files changed, 4 insertions(+), 61 deletions(-) diff --git a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py index b616d7c62..349a38f39 100644 --- a/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py +++ b/dymos/examples/brachistochrone/test/test_brachistochrone_vector_path_constraints.py @@ -4,9 +4,8 @@ import numpy as np -import matplotlib -matplotlib.use('Agg') import matplotlib.pyplot as plt +plt.switch_backend('Agg') import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error @@ -15,7 +14,7 @@ from dymos.examples.brachistochrone.brachistochrone_vector_states_ode \ import BrachistochroneVectorStatesODE -SHOW_PLOTS = False +SHOW_PLOTS = True class TestBrachistochroneVectorPathConstraints(unittest.TestCase): diff --git a/dymos/transcriptions/common/__init__.py b/dymos/transcriptions/common/__init__.py index ce41abe66..ac839475d 100644 --- a/dymos/transcriptions/common/__init__.py +++ b/dymos/transcriptions/common/__init__.py @@ -7,6 +7,6 @@ from .input_parameter_comp import InputParameterComp from .endpoint_conditions_comp import EndpointConditionsComp from .path_constraint_comp import PathConstraintComp -from .timeseries_output_comp import PseudospectralTimeseriesOutputComp, ExplicitTimeseriesOutputComp +from .timeseries_output_comp import PseudospectralTimeseriesOutputComp from .phase_linkage_comp import PhaseLinkageComp from .time_comp import TimeComp diff --git a/dymos/transcriptions/common/timeseries_output_comp.py b/dymos/transcriptions/common/timeseries_output_comp.py index a1dad814d..ddd7dbd11 100644 --- a/dymos/transcriptions/common/timeseries_output_comp.py +++ b/dymos/transcriptions/common/timeseries_output_comp.py @@ -97,7 +97,7 @@ def setup(self): # grid. Then build a Lagrange interpolating polynomial for that segment L_blocks = [] output_nodes_ptau = ogd.node_ptau[ogd.subset_node_indices[output_subset]].tolist() - all_idxs = [] + for iseg in range(igd.num_segments): i1, i2 = igd.segment_indices[iseg] iptau_segi = igd.node_ptau[i1:i2] @@ -161,59 +161,3 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): for (input_name, output_name, _) in self._vars: outputs[output_name] = np.tensordot(self.interpolation_matrix, inputs[input_name], axes=(1, 0)) - - -class ExplicitTimeseriesOutputComp(TimeseriesOutputCompBase): - - def setup(self): - """ - Define the independent variables as output variables. - """ - gd = self.options['grid_data'] - total_num_steps = np.sum(gd.num_steps_per_segment) + gd.num_segments - self._vars = {} - - for (name, kwargs) in self._timeseries_outputs: - - self._vars[name] = {'inputs': [], - 'output': '', - 'dest_indices': []} - - output_name = name - output_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - output_kwargs['shape'] = (total_num_steps,) + kwargs['shape'] - size = np.prod(kwargs['shape']) - self.add_output(output_name, **output_kwargs) - - idx0 = 0 - for iseg in range(gd.num_segments): - num_steps = gd.num_steps_per_segment[iseg] - idx1 = idx0 + num_steps + 1 - input_kwargs = {k: kwargs[k] for k in ('units', 'desc')} - input_name = 'seg_{0}_values:{1}'.format(iseg, name) - - self.add_input(input_name, - shape=(num_steps + 1,) + kwargs['shape'], - **input_kwargs) - - self._vars[name]['inputs'].append(input_name) - self._vars[name]['dest_indices'].append((idx0, idx1)) - - ar = np.arange((num_steps + 1) * size, dtype=int) - - self.declare_partials( - of=output_name, - wrt=input_name, - rows=idx0 * size + ar, - cols=ar, - val=1.0) - - idx0 = idx1 - - self._vars[name]['output'] = output_name - - def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - for name, options in iteritems(self._vars): - for i, input_name in enumerate(options['inputs']): - idx0, idx1 = options['dest_indices'][i] - outputs[options['output']][idx0:idx1, ...] = inputs[input_name]