def test_brachistochrone_forward_shooting_path_constrained_time(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.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.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_control( 'theta', targets=BrachistochroneODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], 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=10) 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'] = 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_near_equal(p['phase0.time'][-1], 1.8016, tolerance=1.0E-3) # Generate the explicitly simulated trajectory exp_out = phase.simulate() assert_near_equal(exp_out.get_val('phase0.timeseries.states:x')[-1, 0], 10, tolerance=1.0E-3) assert_near_equal(exp_out.get_val('phase0.timeseries.states:y')[-1, 0], 5, tolerance=1.0E-3)
def test_list_inputs_outputs(self): prob = om.Problem() model = prob.model indep = model.add_subsystem('indep', om.IndepVarComp()) indep.add_discrete_output('x', 11) model.add_subsystem('expl', ModCompEx(3)) model.add_subsystem('impl', ModCompIm(3)) model.connect('indep.x', ['expl.x', 'impl.x']) prob.setup() prob.run_model() # # list inputs, not hierarchical # stream = StringIO() prob.model.list_inputs(values=True, hierarchical=False, out_stream=stream) text = stream.getvalue() self.assertEqual(1, text.count("3 Input(s) in 'model'")) # make sure they are in the correct order self.assertTrue( text.find('expl.a') < text.find('expl.x') < text.find('impl.x')) # # list inputs, hierarchical # stream = StringIO() prob.model.list_inputs(values=True, hierarchical=True, out_stream=stream) text = stream.getvalue() self.assertEqual(1, text.count("3 Input(s) in 'model'")) self.assertEqual(1, text.count('top')) self.assertEqual(1, text.count(' expl')) self.assertEqual(1, text.count(' a')) self.assertEqual(1, text.count(' impl')) self.assertEqual(2, text.count(' x')) # both implicit & explicit # # list outputs, not hierarchical # stream = StringIO() prob.model.list_outputs(values=True, residuals=True, hierarchical=False, out_stream=stream) text = stream.getvalue() self.assertEqual(text.count('3 Explicit Output'), 1) self.assertEqual(text.count('1 Implicit Output'), 1) # make sure they are in the correct order self.assertTrue( text.find('indep.x') < text.find('expl.b') < text.find('expl.y') < text.find('impl.y')) # # list outputs, hierarchical # stream = StringIO() prob.model.list_outputs(values=True, residuals=True, hierarchical=True, out_stream=stream) text = stream.getvalue() self.assertEqual(text.count('top'), 2) # both implicit & explicit self.assertEqual(text.count(' indep'), 1) self.assertEqual(text.count(' x'), 1) self.assertEqual(text.count(' expl'), 1) self.assertEqual(text.count(' b'), 1) self.assertEqual(text.count(' impl'), 1) self.assertEqual(text.count(' y'), 2) # both implicit & explicit
def make_problem(self, transcription='radau-ps', num_segments=5, transcription_order=3, compressed=True): self.p = p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() 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) traj = dm.Trajectory() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=t) phase.set_refine_options(refine=True, tol=1.0E-6) traj.add_phase('phase0', phase) p.model.add_subsystem('traj0', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', fix_initial=True, fix_final=False) phase.add_state('y', fix_initial=True, fix_final=False) phase.add_state('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_parameter('g', units='m/s**2', val=9.80665) 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 phase.add_objective('time_phase', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=['unconnected_inputs']) p['traj0.phase0.t_initial'] = 0.0 p['traj0.phase0.t_duration'] = 2.0 p['traj0.phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['traj0.phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['traj0.phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['traj0.phase0.controls:theta'] = phase.interpolate( ys=[5, 100], nodes='control_input') p['traj0.phase0.parameters:g'] = 9.80665 return p
def test_static_params(self): prob = om.Problem(model=om.Group()) traj = prob.model.add_subsystem('traj', dm.Trajectory()) # First phase: normal operation. # NOTE: using RK4 integration here P_DEMAND = 2.0 phase0 = dm.Phase(ode_class=BatteryODE, transcription=dm.RungeKutta(num_segments=200)) phase0.set_time_options(fix_initial=True, fix_duration=True) phase0.add_state('state_of_charge', fix_initial=True, fix_final=False, targets=['SOC'], rate_source='dXdt:SOC') phase0.add_timeseries_output('battery.V_oc', output_name='V_oc') phase0.add_timeseries_output('battery.V_pack', output_name='V_pack') phase0.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase0', phase0) # Second phase: normal operation. 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.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') phase1.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1', phase1) # Second phase, but with battery failure. 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.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') phase1_bfail.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1_bfail.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1_bfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1_bfail', phase1_bfail) # Second phase, but with motor failure. 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.add_state('state_of_charge', fix_initial=False, fix_final=False, solve_segments=True, targets=['SOC'], rate_source='dXdt:SOC') phase1_mfail.add_timeseries_output('battery.V_oc', output_name='V_oc') phase1_mfail.add_timeseries_output('battery.V_pack', output_name='V_pack') phase1_mfail.add_timeseries_output('pwr_balance.I_Li', output_name='I_Li') traj.add_phase('phase1_mfail', phase1_mfail) traj.link_phases(phases=['phase0', 'phase1'], vars=['state_of_charge', 'time'], connected=True) 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 = om.DirectSolver(assemble_jac=True) prob.setup() prob.final_setup() prob['traj.phases.phase0.time_extents.t_initial'] = 0 prob['traj.phases.phase0.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_bfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_bfail.time_extents.t_duration'] = 1.0 * 3600 # prob['traj.phases.phase1_mfail.time_extents.t_initial'] = 1.0*3600 prob['traj.phases.phase1_mfail.time_extents.t_duration'] = 1.0 * 3600 prob.set_solver_print(level=0) prob.run_model() plot = True if plot: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt t0 = prob['traj.phase0.timeseries.time'] t1 = prob['traj.phase1.timeseries.time'] t1b = prob['traj.phase1_bfail.timeseries.time'] t1m = prob['traj.phase1_mfail.timeseries.time'] soc0 = prob['traj.phase0.timeseries.states:state_of_charge'] soc1 = prob['traj.phase1.timeseries.states:state_of_charge'] soc1b = prob['traj.phase1_bfail.timeseries.states:state_of_charge'] soc1m = prob['traj.phase1_mfail.timeseries.states:state_of_charge'] plt.subplot(2, 2, 1) plt.plot(t0, soc0, 'b') plt.plot(t1, soc1, 'b') plt.plot(t1b, soc1b, 'r') plt.plot(t1m, soc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('State of Charge (percent)') V_oc0 = prob['traj.phase0.timeseries.V_oc'] V_oc1 = prob['traj.phase1.timeseries.V_oc'] V_oc1b = prob['traj.phase1_bfail.timeseries.V_oc'] V_oc1m = prob['traj.phase1_mfail.timeseries.V_oc'] plt.subplot(2, 2, 2) plt.plot(t0, V_oc0, 'b') plt.plot(t1, V_oc1, 'b') plt.plot(t1b, V_oc1b, 'r') plt.plot(t1m, V_oc1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Open Circuit Voltage (V)') V_pack0 = prob['traj.phase0.timeseries.V_pack'] V_pack1 = prob['traj.phase1.timeseries.V_pack'] V_pack1b = prob['traj.phase1_bfail.timeseries.V_pack'] V_pack1m = prob['traj.phase1_mfail.timeseries.V_pack'] plt.subplot(2, 2, 3) plt.plot(t0, V_pack0, 'b') plt.plot(t1, V_pack1, 'b') plt.plot(t1b, V_pack1b, 'r') plt.plot(t1m, V_pack1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Terminal Voltage (V)') I_Li0 = prob['traj.phase0.timeseries.I_Li'] I_Li1 = prob['traj.phase1.timeseries.I_Li'] I_Li1b = prob['traj.phase1_bfail.timeseries.I_Li'] I_Li1m = prob['traj.phase1_mfail.timeseries.I_Li'] plt.subplot(2, 2, 4) plt.plot(t0, I_Li0, 'b') plt.plot(t1, I_Li1, 'b') plt.plot(t1b, I_Li1b, 'r') plt.plot(t1m, I_Li1m, 'c') plt.xlabel('Time (hour)') plt.ylabel('Line Current (A)') plt.show()
ar = np.arange(nn, dtype=int) self.declare_partials(of='y_dot', wrt='vy', rows=ar, cols=ar, val=1.0) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): vy = inputs['vy'] outputs['y_dot'] = vy outputs['vy_dot'] = -9.80665 # Instantiate an OpenMDAO Problem instance. prob = om.Problem() prob.driver = om.ScipyOptimizeDriver() prob.driver.add_recorder(om.SqliteRecorder('collocation_figures.db')) prob.driver.recording_options['includes'] = [ '*dstau*', '*rhs_col*', '*staterate*', '*timeseries*', '*timeseries2*', '*rhs_disc*' ] # Instantiate a Dymos Trajectory and add it to the Problem model. traj = dm.Trajectory() prob.model.add_subsystem('traj', traj) # Instantiate a Phase and add it to the Trajectory. phase = dm.Phase(ode_class=FallEOM, transcription=dm.GaussLobatto(num_segments=NUM_SEG,
def _make_problem(self, transcription, num_seg, transcription_order=3): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() # Compute sparsity/coloring when run_driver is called p.driver.declare_coloring() 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 = dm.Phase(ode_class=_BrachistochroneTestODE, transcription=t[transcription]) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(1, 1), duration_bounds=(.5, 10), units='s', time_phase_targets=['time_phase'], t_duration_targets=['t_duration'], t_initial_targets=['t_initial'], targets=['time']) phase.add_state('x', fix_initial=True, rate_source='xdot', units='m') phase.add_state('y', fix_initial=True, rate_source='ydot', units='m') phase.add_state('v', fix_initial=True, rate_source='vdot', targets=['v'], units='m/s') phase.add_control('theta', units='deg', rate_continuity=True, lower=0.01, upper=179.9, targets=['theta']) phase.add_parameter('g', units='m/s**2', opt=False, val=9.80665, targets=['g']) 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 phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True) p['phase0.t_initial'] = 1.0 p['phase0.t_duration'] = 3.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') return p
def test_ccblade_loads(self): prob = om.Problem() # Load in airfoil and blade shape inputs for NREL 5MW npzfile = np.load(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'smaller_dataset.npz', allow_pickle=True) n_span = npzfile['r'].size n_aoa = npzfile['aoa'].size n_Re = npzfile['Re'].size modeling_options = {} modeling_options['blade'] = {} modeling_options['blade']['n_span'] = n_span modeling_options['blade']['n_aoa'] = n_aoa modeling_options['blade']['n_Re'] = n_Re modeling_options['blade']['n_tab'] = 1 n_span, n_aoa, n_Re, n_tab = np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1).shape modeling_options['airfoils'] = {} modeling_options['airfoils']['n_aoa'] = n_aoa modeling_options['airfoils']['n_Re'] = n_Re modeling_options['airfoils']['n_tab'] = n_tab comp = CCBladeLoads(modeling_options=modeling_options) prob.model.add_subsystem('comp', comp, promotes=['*']) prob.setup(force_alloc_complex=True) # Add some arbitrary inputs prob.set_val('airfoils_aoa', npzfile['aoa'], units='deg') prob.set_val('airfoils_Re', npzfile['Re']) prob.set_val('airfoils_cl', np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1)) prob.set_val('airfoils_cd', np.moveaxis(npzfile['cd'][:,:,:,np.newaxis], 0, 1)) prob.set_val('airfoils_cm', np.moveaxis(npzfile['cm'][:,:,:,np.newaxis], 0, 1)) prob.set_val('r', npzfile['r'], units='m') prob.set_val('chord', npzfile['chord'], units='m') prob.set_val('theta', npzfile['theta'], units='deg') # parameters prob.set_val('V_load', 12., units='m/s') prob.set_val('Omega_load', 7.0, units='rpm') prob.set_val('pitch_load', 2.0, units='deg') prob.set_val('azimuth_load', 3.0, units='deg') prob.set_val('Rhub', 1., units='m') prob.set_val('Rtip', 70., units='m') prob.set_val('hub_height', 100., units='m') prob.set_val('precone', 0., units='deg') prob.set_val('tilt', 0., units='deg') prob.set_val('yaw', 0., units='deg') prob.set_val('precurve', np.zeros(n_span), units='m') prob.set_val('precurveTip', 0., units='m') prob.set_val('rho', 1.225, units='kg/m**3') prob.set_val('mu', 1.81206e-5, units='kg/(m*s)') prob.set_val('shearExp', 0.25) prob.set_val('nBlades', 3) prob.set_val('nSector', 4) prob.set_val('tiploss', True) prob.set_val('hubloss', True) prob.set_val('wakerotation', True) prob.set_val('usecd', True) prob.run_model() check = prob.check_partials(out_stream=None, compact_print=True) # Manually filter some entries out of the assert_check_partials call. # Will want to add this functionality to OpenMDAO itself at some point. new_check = {} for comp_name in check: new_check[comp_name] = {} for (output_name, input_name) in check[comp_name]: if 'airfoil' not in input_name and 'rho' not in input_name and 'mu' not in input_name and 'shearExp' not in input_name: new_check[comp_name][(output_name, input_name)] = check[comp_name][(output_name, input_name)] assert_check_partials(new_check, rtol=5e-5, atol=1e-4)
n_xsecs = degen_obj.surf.num_secs points = np.empty((npts * n_xsecs, 3)) points[:, 0] = list(itertools.chain.from_iterable(degen_obj.surf.x)) points[:, 1] = list(itertools.chain.from_iterable(degen_obj.surf.y)) points[:, 2] = list(itertools.chain.from_iterable(degen_obj.surf.z)) return points if __name__ == "__main__": from openmdao.api import DirectSolver, NewtonSolver, BoundsEnforceLS vsp_comp = VSPeCRM(horiz_tail_name="Tail", vert_tail_name="VerticalTail", wing_name="Wing") p = om.Problem() model = p.model #newton = model.nonlinear_solver = NewtonSolver() #newton.options['iprint'] = 2 #newton.options['maxiter'] = 100 #newton.options['solve_subsystems'] = True #newton.options['atol'] = 1e-7 #newton.options['rtol'] = 1e-15 #newton.options['err_on_non_converge'] = True #model.linear_solver = DirectSolver() #ls = newton.linesearch = BoundsEnforceLS() #ls.options['iprint'] = 2 #ls.options['print_bound_enforce'] = True #ls.options['bound_enforcement'] = 'scalar'
def test_two_phase_cannonball_for_docs(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.cannonball.size_comp import CannonballSizeComp from dymos.examples.cannonball.cannonball_phase import CannonballPhase p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() 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') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=5, order=3, compressed=True) ascent = CannonballPhase(transcription=transcription) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100, units='s') ascent.set_state_options('r', fix_initial=True, fix_final=False) ascent.set_state_options('h', fix_initial=True, fix_final=False) ascent.set_state_options('gam', fix_initial=False, fix_final=True) ascent.set_state_options('v', fix_initial=False, fix_final=False) ascent.add_parameter('S', targets=['aero.S'], units='m**2') ascent.add_parameter('mass', targets=['eom.m', 'kinetic_energy.m'], units='kg') # Limit the muzzle energy ascent.add_boundary_constraint('kinetic_energy.ke', loc='initial', units='J', upper=400000, lower=0, ref=100000, shape=(1,)) # Second Phase (descent) transcription = dm.GaussLobatto(num_segments=5, order=3, compressed=True) descent = CannonballPhase(transcription=transcription) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100, units='s') descent.add_state('r', ) descent.add_state('h', fix_initial=False, fix_final=True) descent.add_state('gam', fix_initial=False, fix_final=False) descent.add_state('v', fix_initial=False, fix_final=False) descent.add_parameter('S', targets=['aero.S'], units='m**2') descent.add_parameter('mass', targets=['eom.m', 'kinetic_energy.m'], units='kg') descent.add_objective('r', loc='final', scaler=-1.0) # Add internally-managed design parameters to the trajectory. traj.add_parameter('CD', targets={'ascent': ['aero.CD'], 'descent': ['aero.CD']}, val=0.5, units=None, opt=False) traj.add_parameter('CL', targets={'ascent': ['aero.CL'], 'descent': ['aero.CL']}, val=0.0, units=None, opt=False) traj.add_parameter('T', targets={'ascent': ['eom.T'], 'descent': ['eom.T']}, val=0.0, units='N', opt=False) traj.add_parameter('alpha', targets={'ascent': ['eom.alpha'], 'descent': ['eom.alpha']}, val=0.0, units='deg', opt=False) # Add externally-provided design parameters to the trajectory. # In this case, we connect 'm' to pre-existing input parameters named 'mass' in each phase. traj.add_parameter('m', units='kg', val=1.0, targets={'ascent': 'mass', 'descent': 'mass'}) # In this case, by omitting targets, we're connecting these parameters to parameters # with the same name in each phase. traj.add_parameter('S', units='m**2', val=0.005) # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.parameters:m') p.model.connect('size_comp.S', 'traj.parameters:S') # A linear solver at the top level can improve performance. p.model.linear_solver = om.DirectSolver() # Finish Problem Setup p.setup() # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.parameters:CD', 0.5) p.set_val('traj.parameters:CL', 0.0) p.set_val('traj.parameters:T', 0.0) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:h', ascent.interpolate(ys=[0, 100], nodes='state_input')) p.set_val('traj.ascent.states:v', ascent.interpolate(ys=[200, 150], nodes='state_input')) p.set_val('traj.ascent.states:gam', ascent.interpolate(ys=[25, 0], nodes='state_input'), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interpolate(ys=[100, 200], nodes='state_input')) p.set_val('traj.descent.states:h', descent.interpolate(ys=[100, 0], nodes='state_input')) p.set_val('traj.descent.states:v', descent.interpolate(ys=[150, 200], nodes='state_input')) p.set_val('traj.descent.states:gam', descent.interpolate(ys=[0, -45], nodes='state_input'), units='deg') dm.run_problem(p) assert_near_equal(p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2) exp_out = traj.simulate() print('optimal radius: {0:6.4f} m '.format(p.get_val('external_params.radius', units='m')[0])) print('cannonball mass: {0:6.4f} kg '.format(p.get_val('size_comp.mass', units='kg')[0])) print('launch angle: {0:6.4f} ' 'deg '.format(p.get_val('traj.ascent.timeseries.states:gam', units='deg')[0, 0])) print('maximum range: {0:6.4f} ' 'm '.format(p.get_val('traj.descent.timeseries.states:r')[-1, 0])) fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(10, 6)) time_imp = {'ascent': p.get_val('traj.ascent.timeseries.time'), 'descent': p.get_val('traj.descent.timeseries.time')} time_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.time'), 'descent': exp_out.get_val('traj.descent.timeseries.time')} r_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:r'), 'descent': p.get_val('traj.descent.timeseries.states:r')} r_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:r'), 'descent': exp_out.get_val('traj.descent.timeseries.states:r')} h_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:h'), 'descent': p.get_val('traj.descent.timeseries.states:h')} h_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:h'), 'descent': exp_out.get_val('traj.descent.timeseries.states:h')} axes.plot(r_imp['ascent'], h_imp['ascent'], 'bo') axes.plot(r_imp['descent'], h_imp['descent'], 'ro') axes.plot(r_exp['ascent'], h_exp['ascent'], 'b--') axes.plot(r_exp['descent'], h_exp['descent'], 'r--') axes.set_xlabel('range (m)') axes.set_ylabel('altitude (m)') fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(10, 6)) states = ['r', 'h', 'v', 'gam'] for i, state in enumerate(states): x_imp = {'ascent': p.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': p.get_val('traj.descent.timeseries.states:{0}'.format(state))} x_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.states:{0}'.format(state)), 'descent': exp_out.get_val('traj.descent.timeseries.states:{0}'.format(state))} axes[i].set_ylabel(state) axes[i].plot(time_imp['ascent'], x_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], x_imp['descent'], 'ro') 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', 'mass', 'S'] fig, axes = plt.subplots(nrows=6, ncols=1, figsize=(12, 6)) for i, param in enumerate(params): p_imp = { 'ascent': p.get_val('traj.ascent.timeseries.parameters:{0}'.format(param)), 'descent': p.get_val('traj.descent.timeseries.parameters:{0}'.format(param))} p_exp = {'ascent': exp_out.get_val('traj.ascent.timeseries.' 'parameters:{0}'.format(param)), 'descent': exp_out.get_val('traj.descent.timeseries.' 'parameters:{0}'.format(param))} axes[i].set_ylabel(param) axes[i].plot(time_imp['ascent'], p_imp['ascent'], 'bo') axes[i].plot(time_imp['descent'], p_imp['descent'], 'ro') axes[i].plot(time_exp['ascent'], p_exp['ascent'], 'b--') axes[i].plot(time_exp['descent'], p_exp['descent'], 'r--') plt.show()
def test_finite_burn_orbit_raise(self): import numpy as np import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.finite_burn_orbit_raise.finite_burn_eom import FiniteBurnODE p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'IPOPT' p.driver.declare_coloring() traj = dm.Trajectory() traj.add_parameter('c', opt=False, val=1.5, units='DU/TU', targets={'burn1': ['c'], 'coast': ['c'], 'burn2': ['c']}) # First Phase (burn) burn1 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False)) burn1 = traj.add_phase('burn1', burn1) burn1.set_time_options(fix_initial=True, duration_bounds=(.5, 10), units='TU') burn1.add_state('r', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='r_dot', units='DU') burn1.add_state('theta', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', units='rad') burn1.add_state('vr', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='vr_dot', units='DU/TU') burn1.add_state('vt', fix_initial=True, fix_final=False, defect_scaler=100.0, rate_source='vt_dot', units='DU/TU') burn1.add_state('accel', fix_initial=True, fix_final=False, rate_source='at_dot', units='DU/TU**2') burn1.add_state('deltav', fix_initial=True, fix_final=False, rate_source='deltav_dot', units='DU/TU') burn1.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, rate_continuity_scaler=0.001, rate2_continuity_scaler=0.001, lower=-30, upper=30) # Second Phase (Coast) coast = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False)) coast.set_time_options(initial_bounds=(0.5, 20), duration_bounds=(.5, 50), duration_ref=50, units='TU') coast.add_state('r', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='r_dot', targets=['r'], units='DU') coast.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', targets=['theta'], units='rad') coast.add_state('vr', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='vr_dot', targets=['vr'], units='DU/TU') coast.add_state('vt', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='vt_dot', targets=['vt'], units='DU/TU') coast.add_state('accel', fix_initial=True, fix_final=True, rate_source='at_dot', targets=['accel'], units='DU/TU**2') coast.add_state('deltav', fix_initial=False, fix_final=False, rate_source='deltav_dot', units='DU/TU') coast.add_parameter('u1', opt=False, val=0.0, units='deg', targets=['u1']) # Third Phase (burn) burn2 = dm.Phase(ode_class=FiniteBurnODE, transcription=dm.GaussLobatto(num_segments=5, order=3, compressed=False)) traj.add_phase('coast', coast) traj.add_phase('burn2', burn2) burn2.set_time_options(initial_bounds=(0.5, 50), duration_bounds=(.5, 10), initial_ref=10, units='TU') burn2.add_state('r', fix_initial=False, fix_final=True, defect_scaler=100.0, rate_source='r_dot', units='DU') burn2.add_state('theta', fix_initial=False, fix_final=False, defect_scaler=100.0, rate_source='theta_dot', units='rad') burn2.add_state('vr', fix_initial=False, fix_final=True, defect_scaler=1000.0, rate_source='vr_dot', units='DU/TU') burn2.add_state('vt', fix_initial=False, fix_final=True, defect_scaler=1000.0, rate_source='vt_dot', units='DU/TU') burn2.add_state('accel', fix_initial=False, fix_final=False, defect_scaler=1.0, rate_source='at_dot', units='DU/TU**2') burn2.add_state('deltav', fix_initial=False, fix_final=False, defect_scaler=1.0, rate_source='deltav_dot', units='DU/TU') burn2.add_objective('deltav', loc='final', scaler=100.0) burn2.add_control('u1', rate_continuity=True, rate2_continuity=True, units='deg', scaler=0.01, lower=-90, upper=90) burn1.add_timeseries_output('pos_x') coast.add_timeseries_output('pos_x') burn2.add_timeseries_output('pos_x') burn1.add_timeseries_output('pos_y') coast.add_timeseries_output('pos_y') burn2.add_timeseries_output('pos_y') # Link Phases traj.link_phases(phases=['burn1', 'coast', 'burn2'], vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav']) traj.link_phases(phases=['burn1', 'burn2'], vars=['accel']) p.model.add_subsystem('traj', subsys=traj) # Finish Problem Setup # 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(om.SqliteRecorder('two_burn_orbit_raise_example.db')) p.setup(check=True, mode='fwd') # Set Initial Guesses p.set_val('traj.parameters:c', value=1.5, units='DU/TU') burn1 = p.model.traj.phases.burn1 burn2 = p.model.traj.phases.burn2 coast = p.model.traj.phases.coast p.set_val('traj.burn1.t_initial', value=0.0) p.set_val('traj.burn1.t_duration', value=2.25) p.set_val('traj.burn1.states:r', value=burn1.interp('r', [1, 1.5])) p.set_val('traj.burn1.states:theta', value=burn1.interp('theta', [0, 1.7])) p.set_val('traj.burn1.states:vr', value=burn1.interp('vr', [0, 0])) p.set_val('traj.burn1.states:vt', value=burn1.interp('vt', [1, 1])) p.set_val('traj.burn1.states:accel', value=burn1.interp('accel', [0.1, 0])) p.set_val('traj.burn1.states:deltav', value=burn1.interp('deltav', [0, 0.1])) p.set_val('traj.burn1.controls:u1', value=burn1.interp('u1', [-3.5, 13.0])) p.set_val('traj.coast.t_initial', value=2.25) p.set_val('traj.coast.t_duration', value=3.0) p.set_val('traj.coast.states:r', value=coast.interp('r', [1.3, 1.5])) p.set_val('traj.coast.states:theta', value=coast.interp('theta', [2.1767, 1.7])) p.set_val('traj.coast.states:vr', value=coast.interp('vr', [0.3285, 0])) p.set_val('traj.coast.states:vt', value=coast.interp('vt', [0.97, 1])) p.set_val('traj.coast.states:accel', value=coast.interp('accel', [0, 0])) p.set_val('traj.burn2.t_initial', value=5.25) p.set_val('traj.burn2.t_duration', value=1.75) p.set_val('traj.burn2.states:r', value=burn2.interp('r', [1, 3.])) p.set_val('traj.burn2.states:theta', value=burn2.interp('theta', [0, 4.0])) p.set_val('traj.burn2.states:vr', value=burn2.interp('vr', [0, 0])) p.set_val('traj.burn2.states:vt', value=burn2.interp('vt', [1, np.sqrt(1 / 3.)])) p.set_val('traj.burn2.states:deltav', value=burn2.interp('deltav', [0.1, 0.2])) p.set_val('traj.burn2.states:accel', value=burn2.interp('accel', [0.1, 0])) p.set_val('traj.burn2.controls:u1', value=burn2.interp('u1', [0, 0])) dm.run_problem(p) assert_near_equal(p.get_val('traj.burn2.states:deltav')[-1], 0.3995, tolerance=2.0E-3) # # Plot results # traj = p.model.traj exp_out = traj.simulate() fig = plt.figure(figsize=(8, 4)) fig.suptitle('Two Burn Orbit Raise Solution') ax_u1 = plt.subplot2grid((2, 2), (0, 0)) ax_deltav = plt.subplot2grid((2, 2), (1, 0)) ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2) span = np.linspace(0, 2 * np.pi, 100) ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1) ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1) ax_xy.set_xlim(-4.5, 4.5) ax_xy.set_ylim(-4.5, 4.5) ax_xy.set_xlabel('x ($R_e$)') ax_xy.set_ylabel('y ($R_e$)') ax_u1.set_xlabel('time ($TU$)') ax_u1.set_ylabel('$u_1$ ($deg$)') ax_u1.grid(True) ax_deltav.set_xlabel('time ($TU$)') ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)') ax_deltav.grid(True) t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_sol = dict((phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_sol = dict((phs, p.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) t_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) x_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) y_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) dv_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs))) for phs in ['burn1', 'coast', 'burn2']) u1_exp = dict((phs, exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs), units='deg')) for phs in ['burn1', 'burn2']) for phs in ['burn1', 'coast', 'burn2']: try: ax_u1.plot(t_exp[phs], u1_exp[phs], '-', marker=None, color='C0') ax_u1.plot(t_sol[phs], u1_sol[phs], 'o', mfc='C1', mec='C1', ms=3) except KeyError: pass ax_deltav.plot(t_exp[phs], dv_exp[phs], '-', marker=None, color='C0') ax_deltav.plot(t_sol[phs], dv_sol[phs], 'o', mfc='C1', mec='C1', ms=3) ax_xy.plot(x_exp[phs], y_exp[phs], '-', marker=None, color='C0', label='explicit') ax_xy.plot(x_sol[phs], y_sol[phs], 'o', mfc='C1', mec='C1', ms=3, label='implicit') plt.show()
def test_connect_control_to_parameter(self): """ Test that the final value of a control in one phase can be connected as the value of a parameter in a subsequent phase. """ import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.cannonball.size_comp import CannonballSizeComp p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() 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') external_params.add_design_var('radius', lower=0.01, upper=0.10, ref0=0.01, ref=0.10) p.model.add_subsystem('size_comp', CannonballSizeComp()) traj = p.model.add_subsystem('traj', dm.Trajectory()) transcription = dm.Radau(num_segments=5, order=3, compressed=True) ascent = dm.Phase(ode_class=CannonballODEVectorCD, transcription=transcription) ascent = traj.add_phase('ascent', ascent) # All initial states except flight path angle are fixed # Final flight path angle is fixed (we will set it to zero so that the phase ends at apogee) ascent.set_time_options(fix_initial=True, duration_bounds=(1, 100), duration_ref=100, units='s') ascent.add_state('r', fix_initial=True, fix_final=False, rate_source='r_dot', units='m') ascent.add_state('h', fix_initial=True, fix_final=False, units='m', rate_source='h_dot') ascent.add_state('gam', fix_initial=False, fix_final=True, units='rad', rate_source='gam_dot') ascent.add_state('v', fix_initial=False, fix_final=False, units='m/s', rate_source='v_dot') ascent.add_parameter('S', targets=['S'], units='m**2', static_target=True) ascent.add_parameter('mass', targets=['m'], units='kg', static_target=True) ascent.add_control('CD', targets=['CD'], opt=False, val=0.05) # Limit the muzzle energy ascent.add_boundary_constraint('ke', loc='initial', upper=400000, lower=0, ref=100000) # Second Phase (descent) transcription = dm.GaussLobatto(num_segments=5, order=3, compressed=True) descent = dm.Phase(ode_class=CannonballODEVectorCD, transcription=transcription) traj.add_phase('descent', descent) # All initial states and time are free (they will be linked to the final states of ascent. # Final altitude is fixed (we will set it to zero so that the phase ends at ground impact) descent.set_time_options(initial_bounds=(.5, 100), duration_bounds=(.5, 100), duration_ref=100, units='s') descent.add_state('r', units='m', rate_source='r_dot') descent.add_state('h', units='m', rate_source='h_dot', fix_initial=False, fix_final=True) descent.add_state('gam', units='rad', rate_source='gam_dot', fix_initial=False, fix_final=False) descent.add_state('v', units='m/s', rate_source='v_dot', fix_initial=False, fix_final=False) descent.add_parameter('S', targets=['S'], units='m**2', static_target=True) descent.add_parameter('mass', targets=['m'], units='kg', static_target=True) descent.add_parameter('CD', targets=['CD'], val=0.01) descent.add_objective('r', loc='final', scaler=-1.0) # Add externally-provided design parameters to the trajectory. # In this case, we connect 'm' to pre-existing input parameters named 'mass' in each phase. traj.add_parameter('m', units='kg', val=1.0, targets={ 'ascent': 'mass', 'descent': 'mass' }, static_target=True) # In this case, by omitting targets, we're connecting these parameters to parameters # with the same name in each phase. traj.add_parameter('S', units='m**2', val=0.005, static_target=True) # Link Phases (link time and all state variables) traj.link_phases(phases=['ascent', 'descent'], vars=['*']) # Issue Connections p.model.connect('external_params.radius', 'size_comp.radius') p.model.connect('external_params.dens', 'size_comp.dens') p.model.connect('size_comp.mass', 'traj.parameters:m') p.model.connect('size_comp.S', 'traj.parameters:S') traj.connect('ascent.timeseries.controls:CD', 'descent.parameters:CD', src_indices=[-1], flat_src_indices=True) # A linear solver at the top level can improve performance. p.model.linear_solver = om.DirectSolver() # Finish Problem Setup p.setup() # Set Initial Guesses p.set_val('external_params.radius', 0.05, units='m') p.set_val('external_params.dens', 7.87, units='g/cm**3') p.set_val('traj.ascent.controls:CD', 0.5) p.set_val('traj.ascent.t_initial', 0.0) p.set_val('traj.ascent.t_duration', 10.0) p.set_val('traj.ascent.states:r', ascent.interp('r', [0, 100])) p.set_val('traj.ascent.states:h', ascent.interp('h', [0, 100])) p.set_val('traj.ascent.states:v', ascent.interp('v', [200, 150])) p.set_val('traj.ascent.states:gam', ascent.interp('gam', [25, 0]), units='deg') p.set_val('traj.descent.t_initial', 10.0) p.set_val('traj.descent.t_duration', 10.0) p.set_val('traj.descent.states:r', descent.interp('r', [100, 200])) p.set_val('traj.descent.states:h', descent.interp('h', [100, 0])) p.set_val('traj.descent.states:v', descent.interp('v', [150, 200])) p.set_val('traj.descent.states:gam', descent.interp('gam', [0, -45]), units='deg') dm.run_problem(p, simulate=True, make_plots=True) assert_near_equal(p.get_val('traj.descent.states:r')[-1], 3183.25, tolerance=1.0E-2) assert_near_equal( p.get_val('traj.ascent.timeseries.controls:CD')[-1], p.get_val('traj.descent.timeseries.parameters:CD')[0])
def test_partial_deriv_plot(self): class ArrayComp2D(om.ExplicitComponent): """ A fairly simple array component with an intentional error in compute_partials. """ def setup(self): self.JJ = np.array([[1.0, 0.0, 0.0, 7.0], [0.0, 2.5, 0.0, 0.0], [-1.0, 0.0, 8.0, 0.0], [0.0, 4.0, 0.0, 6.0]]) # Params self.add_input('x1', np.zeros([4])) # Unknowns self.add_output('y1', np.zeros([4])) self.declare_partials(of='*', wrt='*') def compute(self, inputs, outputs): """ Execution. """ outputs['y1'] = self.JJ.dot(inputs['x1']) def compute_partials(self, inputs, partials): """ Analytical derivatives. """ # create some error to force the diff plot to show something error = np.zeros((4,4)) err = 1e-7 error[0][3] = err error[1][2] = - 2.0 * err partials[('y1', 'x1')] = self.JJ + error prob = om.Problem() model = prob.model model.add_subsystem('x_param1', om.IndepVarComp('x1', np.ones((4))), promotes=['x1']) model.add_subsystem('mycomp', ArrayComp2D(), promotes=['x1', 'y1']) prob.setup(check=False, mode='fwd') check_partials_data = prob.check_partials(out_stream=None) # plot with defaults fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, title="Defaults") # Instead of seeing if the images created by matplotlib match what we expect, which # is a fragile thing to do in testing, check a data structure inside matplotlib's # objects. We will assume matplotlib draws the correct thing. expected_array = np.array([[1., 0., 0., 1.], [0., 1., 0., 0.], [1., 0., 1., 0.], [0., 1., 0., 1.]]) actual_array = ax[0].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 1., 0., 0., 1.], [ 0., 1., 1., 0.], [ 1., 0., 1., 0.], [ 0., 1., 0., 1.]]) actual_array = ax[1].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 9.31322575e-10, 0.0, 0.0, 1.0e-07], [ 0.0, 0.0, -2.0e-07, 0.0], [ 0.0, 0.0, 9.31322575e-10, 0.0], [ 0.0, 0.0, 0.0, 1.86264515e-09]]) actual_array = ax[2].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) # plot with specified jac_method fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, jac_method = "J_rev", title="specified jac_method") expected_array = np.array([[1., 0., 0., 1.], [0., 1., 0., 0.], [1., 0., 1., 0.], [0., 1., 0., 1.]]) actual_array = ax[0].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 1., 0., 0., 1.], [ 0., 1., 1., 0.], [ 1., 0., 1., 0.], [ 0., 1., 0., 1.]]) actual_array = ax[1].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 9.31322575e-10, 0.0, 0.0, 1.0e-07], [ 0.0, 0.0, -2.0e-07, 0.0], [ 0.0, 0.0, 9.31322575e-10, 0.0], [ 0.0, 0.0, 0.0, 1.86264515e-09]]) actual_array = ax[2].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) # plot in non-binary mode fig, ax = om.partial_deriv_plot('y1', 'x1', check_partials_data, binary = False, title="non-binary") expected_array = np.array([[ 1. , 0. , 0. , 7. ], [ 0. , 2.5, 0. , 0. ], [-1. , 0. , 8. , 0. ], [ 0. , 4. , 0. , 6. ]]) actual_array = ax[0].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 1.0e+00, 0.0, 0.0, 7.00000010e+00], [ 0.0, 2.5e+00, -2.0e-07, 0.0], [ -1.0e+00, 0.0, 8.0e+00, 0.0], [ 0.0, 4.0e+00, 0.0, 6.0e+00]]) actual_array = ax[1].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) expected_array = np.array([[ 9.31322575e-10, 0.0, 0.0, 1.0e-07], [ 0.0, 0.0, -2.0e-07, 0.0], [ 0.0, 0.0, 9.31322575e-10, 0.0], [ 0.0, 0.0, 0.0, 1.86264515e-09]]) actual_array = ax[2].images[0]._A.data assert_near_equal(expected_array, actual_array, 1e-8) # plot with different tol values # Not obvious how to test this other than image matching om.partial_deriv_plot('y1', 'x1', check_partials_data, tol=1e-5, title="tol greater than err") om.partial_deriv_plot('y1', 'x1', check_partials_data, tol=1e-10, title="tol less than err")
def test_doc_ssto_earth(self): import matplotlib.pyplot as plt import openmdao.api as om import dymos as dm # # Setup and solve the optimal control problem # p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.declare_coloring(tol=1.0E-12) from dymos.examples.ssto.launch_vehicle_ode import LaunchVehicleODE # # Initialize our Trajectory and Phase # traj = dm.Trajectory() phase = dm.Phase(ode_class=LaunchVehicleODE, transcription=dm.GaussLobatto(num_segments=12, order=3, compressed=False)) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) # # Set the options for the variables # phase.set_time_options(fix_initial=True, duration_bounds=(10, 500)) phase.add_state('x', fix_initial=True, ref=1.0E5, defect_ref=10000.0, rate_source='xdot') phase.add_state('y', fix_initial=True, ref=1.0E5, defect_ref=10000.0, rate_source='ydot') phase.add_state('vx', fix_initial=True, ref=1.0E3, defect_ref=1000.0, rate_source='vxdot') phase.add_state('vy', fix_initial=True, ref=1.0E3, defect_ref=1000.0, rate_source='vydot') phase.add_state('m', fix_initial=True, ref=1.0E3, defect_ref=100.0, rate_source='mdot') phase.add_control('theta', units='rad', lower=-1.57, upper=1.57, targets=['theta']) phase.add_parameter('thrust', units='N', opt=False, val=2100000.0, targets=['thrust']) # # Set the options for our constraints and objective # phase.add_boundary_constraint('y', loc='final', equals=1.85E5, linear=True) phase.add_boundary_constraint('vx', loc='final', equals=7796.6961) phase.add_boundary_constraint('vy', loc='final', equals=0) phase.add_objective('time', loc='final', scaler=0.01) p.model.linear_solver = om.DirectSolver() # # Setup and set initial values # p.setup(check=True) p.set_val('traj.phase0.t_initial', 0.0) p.set_val('traj.phase0.t_duration', 150.0) p.set_val('traj.phase0.states:x', phase.interp('x', [0, 1.15E5])) p.set_val('traj.phase0.states:y', phase.interp('y', [0, 1.85E5])) p.set_val('traj.phase0.states:vy', phase.interp('vx', [1.0E-6, 0])) p.set_val('traj.phase0.states:m', phase.interp('vy', [117000, 1163])) p.set_val('traj.phase0.controls:theta', phase.interp('theta', [1.5, -0.76])) p.set_val('traj.phase0.parameters:thrust', 2.1, units='MN') # # Solve the Problem # dm.run_problem(p) assert_near_equal(p.get_val('traj.phase0.timeseries.time')[-1], 143, tolerance=0.05) assert_near_equal( p.get_val('traj.phase0.timeseries.states:y')[-1], 1.85E5, 1e-4) assert_near_equal( p.get_val('traj.phase0.timeseries.states:vx')[-1], 7796.6961, 1e-4) assert_near_equal( p.get_val('traj.phase0.timeseries.states:vy')[-1], 0, 1e-4) # # Get the explicitly 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('traj.phase0.timeseries.states:x'), p.get_val('traj.phase0.timeseries.states:y'), marker='o', ms=4, linestyle='None', label='solution') axes[0].plot(exp_out.get_val('traj.phase0.timeseries.states:x'), exp_out.get_val('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('traj.phase0.timeseries.time'), p.get_val('traj.phase0.timeseries.controls:theta'), marker='o', ms=4, linestyle='None') axes[1].plot(exp_out.get_val('traj.phase0.timeseries.time'), exp_out.get_val('traj.phase0.timeseries.controls:theta'), linestyle='-', marker=None) axes[1].set_xlabel('time (s)') axes[1].set_ylabel('theta (deg)') plt.suptitle( 'Single Stage to Orbit Solution Using Linear Tangent Guidance') fig.legend(loc='lower center', ncol=2) plt.show()
def test_brachistochrone_external_control(self): import numpy as np import openmdao.api as om import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # # Define the OpenMDAO problem # p = om.Problem(model=om.Group()) # Instantiate the transcription so we can get the number of nodes from it while # building the problem. tx = dm.GaussLobatto(num_segments=10, order=3) # Add an indep var comp to provide the external control values ivc = p.model.add_subsystem('control_ivc', om.IndepVarComp(), promotes_outputs=['*']) # Add the output to provide the values of theta at the control input nodes of the transcription. ivc.add_output('theta', shape=(tx.grid_data.subset_num_nodes['control_input']), units='rad') # Add this external control as a design variable # Note the lower bound to avoid the singularity in the ODE when theta = 0 p.model.add_design_var('theta', units='rad', lower=1.0E-4, upper=np.pi) # Connect this to controls:theta in the appropriate phase. # connect calls are cached, so we can do this before we actually add the trajectory to the problem. p.model.connect('theta', 'traj.phase0.controls:theta') # # Define a Trajectory object # traj = dm.Trajectory() p.model.add_subsystem('traj', subsys=traj) # # Define a Dymos Phase object with GaussLobatto Transcription # phase = dm.Phase(ode_class=BrachistochroneODE, transcription=tx) traj.add_phase(name='phase0', phase=phase) # # Set the time options # Time has no targets in our ODE. # We fix the initial time so that the it is not a design variable in the optimization. # The duration of the phase is allowed to be optimized, but is bounded on [0.5, 10]. # phase.set_time_options(fix_initial=True, duration_bounds=(0.5, 10.0), units='s') # # Set the time options # Initial values of positions and velocity are all fixed. # The final value of position are fixed, but the final velocity is a free variable. # The equations of motion are not functions of position, so 'x' and 'y' have no targets. # The rate source points to the output in the ODE which provides the time derivative of the # given state. phase.add_state('x', fix_initial=True, fix_final=True, rate_source='xdot') phase.add_state('y', fix_initial=True, fix_final=True, rate_source='ydot') phase.add_state('v', fix_initial=True, fix_final=False, rate_source='vdot') # Define theta as a control. # Use opt=False to allow it to be connected to an external source. # Arguments lower and upper are no longer valid for an input control. phase.add_control(name='theta', units='rad', targets=['theta'], opt=False) # Minimize final time. phase.add_objective('time', loc='final') # Set the driver. p.driver = om.ScipyOptimizeDriver() # Allow OpenMDAO to automatically determine our sparsity pattern. # Doing so can significant speed up the execution of Dymos. p.driver.declare_coloring() # Setup the problem p.setup(check=True) # Now that the OpenMDAO problem is setup, we can set the values of the states. p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 10], nodes='state_input'), units='m') p.set_val('traj.phase0.states:y', phase.interpolate(ys=[10, 5], nodes='state_input'), units='m') p.set_val('traj.phase0.states:v', phase.interpolate(ys=[0, 5], nodes='state_input'), units='m/s') p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[90, 90], nodes='control_input'), units='deg') # Run the driver to solve the problem p.run_driver() # Check the validity of our results by using scipy.integrate.solve_ivp to # integrate the solution. sim_out = traj.simulate() # Plot the results fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4.5)) axes[0].plot(p.get_val('traj.phase0.timeseries.states:x'), p.get_val('traj.phase0.timeseries.states:y'), 'ro', label='solution') axes[0].plot(sim_out.get_val('traj.phase0.timeseries.states:x'), sim_out.get_val('traj.phase0.timeseries.states:y'), 'b-', label='simulation') axes[0].set_xlabel('x (m)') axes[0].set_ylabel('y (m/s)') axes[0].legend() axes[0].grid() axes[1].plot(p.get_val('traj.phase0.timeseries.time'), p.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'ro', label='solution') axes[1].plot(sim_out.get_val('traj.phase0.timeseries.time'), sim_out.get_val('traj.phase0.timeseries.controls:theta', units='deg'), 'b-', label='simulation') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'$\theta$ (deg)') axes[1].legend() axes[1].grid() plt.show()
def test_units_with_scaling(self): prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units='degF') model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={ 'value': 2.0, 'units': 'degF' }, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_subsystem('comp2', om.ExecComp('y2 = 3.0*x', x={ 'value': 2.0, 'units': 'degF' }, y2={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y2']) model.add_design_var('x', units='degC', lower=0.0, upper=100.0, scaler=3.5, adder=77.0) model.add_constraint('y1', units='degC', lower=0.0, upper=100.0, scaler=3.5, adder=77.0) model.add_objective('y2', units='degC', scaler=3.5, adder=77.0) recorder = om.SqliteRecorder('cases.sql') prob.driver.add_recorder(recorder) prob.driver.recording_options['record_objectives'] = True prob.driver.recording_options['record_constraints'] = True prob.driver.recording_options['record_desvars'] = True prob.setup() prob.run_driver() dv = prob.driver.get_design_var_values() assert_near_equal(dv['p.x'][0], ((3.0 * 5 / 9) + 77.0) * 3.5, 1e-8) obj = prob.driver.get_objective_values(driver_scaling=True) assert_near_equal(obj['comp2.y2'][0], ((73.0 * 5 / 9) + 77.0) * 3.5, 1e-8) con = prob.driver.get_constraint_values(driver_scaling=True) assert_near_equal(con['comp1.y1'][0], ((38.0 * 5 / 9) + 77.0) * 3.5, 1e-8) meta = model.get_design_vars() assert_near_equal(meta['p.x']['lower'], ((0.0) + 77.0) * 3.5, 1e-7) assert_near_equal(meta['p.x']['upper'], ((100.0) + 77.0) * 3.5, 1e-7) meta = model.get_constraints() assert_near_equal(meta['comp1.y1']['lower'], ((0.0) + 77.0) * 3.5, 1e-7) assert_near_equal(meta['comp1.y1']['upper'], ((100.0) + 77.0) * 3.5, 1e-7) stdout = sys.stdout strout = StringIO() sys.stdout = strout try: prob.list_problem_vars(desvar_opts=['units'], objs_opts=['units'], cons_opts=['units']) finally: sys.stdout = stdout output = strout.getvalue().split('\n') self.assertTrue('275.33' in output[5]) self.assertTrue('343.3888' in output[12]) self.assertTrue('411.444' in output[19]) self.assertTrue('degC' in output[5]) self.assertTrue('degC' in output[12]) self.assertTrue('degC' in output[19]) totals = prob.check_totals(out_stream=None, driver_scaling=True) for key, val in totals.items(): assert_near_equal(val['rel error'][0], 0.0, 1e-6) cr = om.CaseReader("cases.sql") cases = cr.list_cases('driver') case = cr.get_case(cases[0]) dv = case.get_design_vars() assert_near_equal(dv['p.x'][0], ((3.0 * 5 / 9) + 77.0) * 3.5, 1e-8) obj = case.get_objectives() assert_near_equal(obj['comp2.y2'][0], ((73.0 * 5 / 9) + 77.0) * 3.5, 1e-8) con = case.get_constraints() assert_near_equal(con['comp1.y1'][0], ((38.0 * 5 / 9) + 77.0) * 3.5, 1e-8)
def test_steady_aircraft_for_docs(self): import matplotlib.pyplot as plt import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal import dymos as dm from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE from dymos.examples.plotting import plot_results from dymos.utils.lgl import lgl p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.declare_coloring() num_seg = 15 seg_ends, _ = lgl(num_seg + 1) traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=False))) # Pass Reference Area from an external source 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') phase.set_time_options(fix_initial=True, duration_bounds=(300, 10000), duration_ref=5600) phase.add_state('range', units='NM', rate_source='range_rate_comp.dXdt:range', fix_initial=True, fix_final=False, ref=1e-3, defect_ref=1e-3, lower=0, upper=2000) phase.add_state('mass_fuel', units='lbm', rate_source='propulsion.dXdt:mass_fuel', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, ref=1e2, defect_ref=1e2) phase.add_state('alt', units='kft', rate_source='climb_rate', fix_initial=True, fix_final=True, lower=0.0, upper=60, ref=1e-3, defect_ref=1e-3) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, targets=['gam_comp.climb_rate'], rate_continuity=True, rate2_continuity=False) phase.add_control('mach', targets=['tas_comp.mach', 'aero.mach'], units=None, opt=False) phase.add_parameter( 'S', targets=['aero.S', 'flight_equilibrium.S', 'propulsion.S'], units='m**2') phase.add_parameter('mass_empty', targets=['mass_comp.mass_empty'], units='kg') phase.add_parameter('mass_payload', targets=['mass_comp.mass_payload'], units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0) p.model.connect('assumptions.S', 'traj.phase0.parameters:S') p.model.connect('assumptions.mass_empty', 'traj.phase0.parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'traj.phase0.parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0e-4) phase.add_timeseries_output('aero.CL') phase.add_timeseries_output('aero.CD') p.setup() p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 3600.0 p['traj.phase0.states:range'][:] = phase.interpolate( ys=(0, 724.0), nodes='state_input') p['traj.phase0.states:mass_fuel'][:] = phase.interpolate( ys=(30000, 1e-3), nodes='state_input') p['traj.phase0.states:alt'][:] = 10.0 p['traj.phase0.controls:mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 dm.run_problem(p) assert_near_equal(p.get_val('traj.phase0.timeseries.states:range', units='NM')[-1], 726.85, tolerance=1.0E-2) exp_out = traj.simulate() assert_near_equal(p.get_val('traj.phase0.timeseries.CL')[0], exp_out.get_val('traj.phase0.timeseries.CL')[0], tolerance=1.0E-9) assert_near_equal(p.get_val('traj.phase0.timeseries.CD')[0], exp_out.get_val('traj.phase0.timeseries.CD')[0], tolerance=1.0E-9) plot_results( [('traj.phase0.timeseries.states:range', 'traj.phase0.timeseries.states:alt', 'range (NM)', 'altitude (kft)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:mass_fuel', 'time (s)', 'fuel mass (lbm)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.CL', 'time (s)', 'lift coefficient'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.CD', 'time (s)', 'drag coefficient')], title='Commercial Aircraft Optimization', p_sol=p, p_sim=exp_out) plt.show()
def test_units_error_messages(self): prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units='degF') model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={ 'value': 2.0, 'units': 'degF' }, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_design_var('x', units='ft', lower=0.0, upper=100.0, scaler=3.5, adder=77.0) prob.setup() with self.assertRaises(RuntimeError) as context: prob.final_setup() msg = "<model> <class Group>: Target for design variable x has 'degF' units, but 'ft' units were specified." self.assertEqual(str(context.exception), msg) prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units='degF') model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={ 'value': 2.0, 'units': 'degF' }, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_constraint('x', units='ft', lower=0.0, upper=100.0) prob.setup() with self.assertRaises(RuntimeError) as context: prob.final_setup() msg = "<model> <class Group>: Target for constraint x has 'degF' units, but 'ft' units were specified." self.assertEqual(str(context.exception), msg) prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units=None) model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={'value': 2.0}, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_design_var('x', units='ft', lower=0.0, upper=100.0, scaler=3.5, adder=77.0) prob.setup() with self.assertRaises(RuntimeError) as context: prob.final_setup() msg = "<model> <class Group>: Target for design variable x has no units, but 'ft' units were specified." self.assertEqual(str(context.exception), msg) prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units=None) model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={'value': 2.0}, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_constraint('x', units='ft', lower=0.0, upper=100.0) prob.setup() with self.assertRaises(RuntimeError) as context: prob.final_setup() msg = "<model> <class Group>: Target for constraint x has no units, but 'ft' units were specified." self.assertEqual(str(context.exception), msg)
def test_zero_shape(self): raise unittest.SkipTest("zero shapes not fully supported yet") class MultComp(ExplicitComponent): def __init__(self, mult): self.mult = mult super().__init__() def setup(self): if self.comm.rank == 0: self.add_input('x', shape=1) self.add_output('y', shape=1) else: self.add_input('x', shape=0) self.add_output('y', shape=0) def compute(self, inputs, outputs): outputs['y'] = inputs['x'] * self.mult def compute_partials(self, inputs, partials): partials['y', 'x'] = np.array([self.mult]) prob = om.Problem() model = prob.model model.add_subsystem('iv', om.IndepVarComp('x', 1.0)) model.add_subsystem('c1', MultComp(3.0)) model.sub = model.add_subsystem('sub', om.ParallelGroup()) model.sub.add_subsystem('c2', MultComp(-2.0)) model.sub.add_subsystem('c3', MultComp(5.0)) model.add_subsystem('c2', MultComp(1.0)) model.add_subsystem('c3', MultComp(1.0)) model.connect('iv.x', 'c1.x') model.connect('c1.y', 'sub.c2.x') model.connect('c1.y', 'sub.c3.x') model.connect('sub.c2.y', 'c2.x') model.connect('sub.c3.y', 'c3.x') of = ['c2.y', "c3.y"] wrt = ['iv.x'] prob.setup(check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x']) assert_near_equal(J['c2.y', 'iv.x'][0][0], -6.0, 1e-6) assert_near_equal(J['c3.y', 'iv.x'][0][0], 15.0, 1e-6) assert_near_equal(prob['c2.y'], -6.0, 1e-6) assert_near_equal(prob['c3.y'], 15.0, 1e-6) prob.setup(check=False, mode='rev') prob.run_model() J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x']) assert_near_equal(J['c2.y', 'iv.x'][0][0], -6.0, 1e-6) assert_near_equal(J['c3.y', 'iv.x'][0][0], 15.0, 1e-6) assert_near_equal(prob['c2.y'], -6.0, 1e-6) assert_near_equal(prob['c3.y'], 15.0, 1e-6)
def test_ccblade_twist(self): """ Right now this just compares fd to fd so it is not a meaningful test. However, it ensures that we have the derivatives set up in the component to actually be finite differenced. """ prob = om.Problem() # Add some arbitrary inputs # Load in airfoil and blade shape inputs for NREL 5MW npzfile = np.load(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'smaller_dataset.npz', allow_pickle=True) n_span = npzfile['r'].size n_aoa = npzfile['aoa'].size n_Re = npzfile['Re'].size modeling_options = {} modeling_options['blade'] = {} modeling_options['blade']['n_span'] = n_span modeling_options['blade']['n_aoa'] = n_aoa modeling_options['blade']['n_Re'] = n_Re modeling_options['blade']['n_tab'] = 1 modeling_options['assembly'] = {} modeling_options['assembly']['number_of_blades'] = 3 n_span, n_aoa, n_Re, n_tab = np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1).shape modeling_options['airfoils'] = {} modeling_options['airfoils']['n_aoa'] = n_aoa modeling_options['airfoils']['n_Re'] = n_Re modeling_options['airfoils']['n_tab'] = n_tab opt_options = {} opt_options['optimization_variables'] = {} opt_options['optimization_variables']['blade'] = {} opt_options['optimization_variables']['blade']['aero_shape'] = {} opt_options['optimization_variables']['blade']['aero_shape']['chord'] = {} opt_options['optimization_variables']['blade']['aero_shape']['chord']['n_opt'] = 8 opt_options['optimization_variables']['blade']['aero_shape']['twist'] = {} opt_options['optimization_variables']['blade']['aero_shape']['twist']['n_opt'] = 8 opt_options['optimization_variables']['blade']['aero_shape']['twist']['inverse'] = False opt_options['constraints'] = {} opt_options['constraints']['blade'] = {} opt_options['constraints']['blade']['stall'] = {} opt_options['constraints']['blade']['stall']['margin'] = 0.05233 comp = CCBladeTwist(modeling_options=modeling_options, opt_options=opt_options) prob.model.add_subsystem('comp', comp, promotes=['*']) prob.setup(force_alloc_complex=True) prob.set_val('airfoils_aoa', npzfile['aoa'], units='deg') prob.set_val('airfoils_Re', npzfile['Re']) prob.set_val('airfoils_cl', np.moveaxis(npzfile['cl'][:,:,:,np.newaxis], 0, 1)) prob.set_val('airfoils_cd', np.moveaxis(npzfile['cd'][:,:,:,np.newaxis], 0, 1)) prob.set_val('airfoils_cm', np.moveaxis(npzfile['cm'][:,:,:,np.newaxis], 0, 1)) prob.set_val('r', npzfile['r'], units='m') prob.set_val('chord', npzfile['chord'], units='m') prob.set_val('Rhub', 1., units='m') prob.set_val('Rtip', 70., units='m') prob.set_val('hub_height', 100., units='m') prob.set_val('precone', 0., units='deg') prob.set_val('tilt', 0., units='deg') prob.set_val('yaw', 0., units='deg') prob.set_val('precurve', np.zeros(n_span), units='m') prob.set_val('precurveTip', 0., units='m') prob.set_val('rho', 1.225, units='kg/m**3') prob.set_val('mu', 1.81206e-5, units='kg/(m*s)') prob.set_val('shearExp', 0.25) prob.set_val('nBlades', 3) prob.set_val('nSector', 4) prob.set_val('tiploss', True) prob.set_val('hubloss', True) prob.set_val('wakerotation', True) prob.set_val('usecd', True) prob.run_model() check = prob.check_partials(out_stream=None, compact_print=True) # Manually filter some entries out of the assert_check_partials call. # Will want to add this functionality to OpenMDAO itself at some point. new_check = {} for comp_name in check: new_check[comp_name] = {} for (output_name, input_name) in check[comp_name]: if 'airfoil' not in input_name and 'rho' not in input_name and 'mu' not in input_name and 'shearExp' not in input_name: new_check[comp_name][(output_name, input_name)] = check[comp_name][(output_name, input_name)] assert_check_partials(new_check) #, rtol=5e-5, atol=1e-4)
def _make_tree_model(): p = om.Problem() model = p.model units1 = units2 = 'ft' val = 1.0 g1 = model.add_subsystem("G1", om.Group(), promotes_inputs=['x']) g2 = g1.add_subsystem("G2", om.Group(), promotes_inputs=['x']) g2.add_subsystem("C1", om.ExecComp("y = 2. * x", x={ 'val': val, 'units': units2 }, y={ 'val': 1.0, 'units': units2 }), promotes_inputs=['x']) g2.add_subsystem("C2", om.ExecComp("y = 3. * x", x={ 'val': val, 'units': units1 }, y={ 'val': 1.0, 'units': units1 }), promotes_inputs=['x']) g3 = model.add_subsystem("G3", om.Group(), promotes_inputs=['x']) g3.add_subsystem("C3", om.ExecComp("y = 4. * x", x={ 'val': val, 'units': units1 }, y={ 'val': 1.0, 'units': units1 }), promotes_inputs=['x']) g3.add_subsystem("C4", om.ExecComp("y = 5. * x", x={ 'val': val, 'units': units2 }, y={ 'val': 1.0, 'units': units2 }), promotes_inputs=['x']) par = model.add_subsystem("par", om.ParallelGroup(), promotes_inputs=['x']) g4 = par.add_subsystem("G4", om.Group(), promotes_inputs=['x']) g4.add_subsystem("C5", om.ExecComp("y = 6. * x", x={ 'val': val, 'units': units2 }, y={ 'val': 1.0, 'units': units2 }), promotes_inputs=['x']) g4.add_subsystem("C6", om.ExecComp("y = 7. * x", x={ 'val': val, 'units': units1 }, y={ 'val': 1.0, 'units': units1 }), promotes_inputs=['x']) g5 = par.add_subsystem("G5", om.Group(), promotes_inputs=['x']) g5.add_subsystem("C7", om.ExecComp("y = 8. * x", x={ 'val': val, 'units': units1 }, y={ 'val': 1.0, 'units': units1 }), promotes_inputs=['x']) g5.add_subsystem("C8", om.ExecComp("y = 9. * x", x={ 'val': val, 'units': units2 }, y={ 'val': 1.0, 'units': units2 }), promotes_inputs=['x']) model.add_subsystem("C9", om.ExecComp("y = 10. * x", x={ 'val': val, 'units': units2 }, y={ 'val': 1.0, 'units': units2 }), promotes_inputs=['x']) return p
def test_length_constrained_brachistochrone(self): import openmdao.api as om import dymos as dm import matplotlib.pyplot as plt from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE from dymos.examples.length_constrained_brachistochrone.arc_length_comp import ArcLengthComp MAX_ARCLENGTH = 11.9 OPTIMIZER = 'SLSQP' p = om.Problem(model=om.Group()) p.add_recorder(om.SqliteRecorder('length_constrained_brach_sol.db')) if OPTIMIZER == 'SNOPT': p.driver = om.pyOptSparseDriver() p.driver.options['optimizer'] = OPTIMIZER p.driver.opt_settings['Major iterations limit'] = 1000 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-5 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() # Create the transcription so we can get the number of nodes for the downstream analysis tx = dm.Radau(num_segments=20, order=3, compressed=False) traj = dm.Trajectory() phase = dm.Phase(transcription=tx, ode_class=BrachistochroneODE) traj.add_phase('phase0', phase) p.model.add_subsystem('traj', traj) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state('x', units='m', rate_source='xdot', fix_initial=True, fix_final=True) phase.add_state('y', units='m', rate_source='ydot', fix_initial=True, fix_final=True) phase.add_state('v', units='m/s', rate_source='vdot', fix_initial=True, fix_final=False) phase.add_control('theta', units='deg', lower=0.01, upper=179.9, continuity=True, rate_continuity=True) phase.add_parameter('g', units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=1) # p.model.options['assembled_jac_type'] = top_level_jacobian.lower() # p.model.linear_solver = DirectSolver(assemble_jac=True) # Add the arc length component p.model.add_subsystem('arc_length_comp', subsys=ArcLengthComp(num_nodes=tx.grid_data.num_nodes)) p.model.connect('traj.phase0.timeseries.controls:theta', 'arc_length_comp.theta') p.model.connect('traj.phase0.timeseries.states:x', 'arc_length_comp.x') p.model.add_constraint('arc_length_comp.S', upper=MAX_ARCLENGTH, ref=1) p.setup(check=True) p.set_val('traj.phase0.t_initial', 0.0) p.set_val('traj.phase0.t_duration', 2.0) p.set_val('traj.phase0.states:x', phase.interpolate(ys=[0, 10], nodes='state_input')) p.set_val('traj.phase0.states:y', phase.interpolate(ys=[10, 5], nodes='state_input')) p.set_val('traj.phase0.states:v', phase.interpolate(ys=[0, 9.9], nodes='state_input')) p.set_val('traj.phase0.controls:theta', phase.interpolate(ys=[5, 100], nodes='control_input')) p.set_val('traj.phase0.parameters:g', 9.80665) p.run_driver() p.record(case_name='final') # Plot results if SHOW_PLOTS: # Generate the explicitly simulated trajectory exp_out = traj.simulate() # Extract the timeseries from the implicit solution and the explicit simulation x = p.get_val('traj.phase0.timeseries.states:x') y = p.get_val('traj.phase0.timeseries.states:y') t = p.get_val('traj.phase0.timeseries.time') theta = p.get_val('traj.phase0.timeseries.controls:theta') x_exp = exp_out.get_val('traj.phase0.timeseries.states:x') y_exp = exp_out.get_val('traj.phase0.timeseries.states:y') t_exp = exp_out.get_val('traj.phase0.timeseries.time') theta_exp = exp_out.get_val('traj.phase0.timeseries.controls:theta') fig, axes = plt.subplots(nrows=2, ncols=1) axes[0].plot(x, y, 'o') axes[0].plot(x_exp, y_exp, '-') axes[0].set_xlabel('x (m)') axes[0].set_ylabel('y (m)') axes[1].plot(t, theta, 'o') axes[1].plot(t_exp, theta_exp, '-') axes[1].set_xlabel('time (s)') axes[1].set_ylabel(r'$\theta$ (deg)') plt.show() return p
def run_opt(layout_number, wec_method_number, wake_model, opt_alg_number, max_wec, nsteps): OPENMDAO_REQUIRE_MPI = False run_number = layout_number model = wake_model # set model MODELS = ['FLORIS', 'BPA', 'JENSEN', 'LARSEN'] print(MODELS[model]) # select optimization approach/method opt_algs = ['snopt', 'ga', 'ps'] opt_algorithm = opt_algs[opt_alg_number] # select wec method wec_methods = ['none', 'diam', 'angle', 'hybrid'] wec_method = wec_methods[wec_method_number] # pop_size = 760 # save and show options show_start = False show_end = False save_start = False save_end = False save_locations = True save_aep = True save_time = True rec_func_calls = True input_directory = "../../../input_files/" # set options for BPA print_ti = False sort_turbs = True # turbine_type = 'NREL5MW' #can be 'V80' or 'NREL5MW' turbine_type = 'V80' # can be 'V80' or 'NREL5MW' wake_model_version = 2016 WECH = 0 if wec_method == 'diam': output_directory = "../output_files/%s_wec_diam_max_wec_%i_nsteps_%.3f/" % ( opt_algorithm, max_wec, nsteps) relax = True # expansion_factors = np.array([3, 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0, 1.0]) expansion_factors = np.linspace(1.0, max_wec, nsteps) expansion_factors = np.append(np.flip(expansion_factors), 1.0) conv_tols = np.array([9E-3, 9E-3, 9E-3, 9E-3, 9E-3, 9E-3, 1E-3]) elif wec_method == 'angle': output_directory = "../output_files/%s_wec_angle_max_wec_%i_nsteps_%.3f/" % ( opt_algorithm, max_wec, nsteps) relax = True # expansion_factors = np.array([50, 40, 30, 20, 10, 0.0, 0.0]) expansion_factors = np.linspace(0.0, max_wec, nsteps) expansion_factors = np.append(np.flip(expansion_factors), 0.0) elif wec_method == 'hybrid': expansion_factors = np.linspace(1.0, max_wec, nsteps) expansion_factors = np.append(np.flip(expansion_factors), 1.0) output_directory = "../output_files/%s_wec_hybrid_max_wec_%i_nsteps_%.3f/" % ( opt_algorithm, max_wec, nsteps) relax = True WECH = 1 elif wec_method == 'none': relax = False if opt_algorithm == "ps": expansion_factors = np.array([1.0]) conv_tols = np.array([1E-4]) else: expansion_factors = np.array([1.0, 1.0]) conv_tols = np.array([9E-3, 1E-3]) output_directory = "../output_files/%s/" % opt_algorithm else: raise ValueError('wec_method must be diam, angle, hybrid, or none') # create output directory if it does not exist yet import distutils.dir_util distutils.dir_util.mkpath(output_directory) differentiable = True # for expansion_factor in np.array([5., 4., 3., 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0]): # for expansion_factor in np.array([20., 15., 10., 5., 4., 3., 2.5, 1.25, 1.0]): # expansion_factors = np.array([20., 10., 5., 2.5, 1.25, 1.0]) wake_combination_method = 1 # can be [0:Linear freestreem superposition, # 1:Linear upstream velocity superposition, # 2:Sum of squares freestream superposition, # 3:Sum of squares upstream velocity superposition] ti_calculation_method = 4 # can be [0:No added TI calculations, # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas, # 2:TI by Niayifar and Porte Agel 2016, # 3:TI by Niayifar and Porte Agel 2016 with added soft max function, # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio, # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function] if wec_method_number > 0: ti_opt_method = 0 # can be [0:No added TI calculations, # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas, # 2:TI by Niayifar and Porte Agel 2016, # 3:TI by Niayifar and Porte Agel 2016 with added soft max function, # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio, # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function] else: ti_opt_method = 0 final_ti_opt_method = 5 if opt_algorithm == 'ps': ti_opt_method = ti_calculation_method sm_smoothing = 700. if ti_calculation_method == 0: calc_k_star_calc = False else: calc_k_star_calc = True if ti_opt_method == 0: calc_k_star_opt = False else: calc_k_star_opt = True nRotorPoints = 1 wind_rose_file = 'nantucket' # can be one of: 'amalia', 'nantucket', 'directional TI = 0.108 k_calc = 0.3837 * TI + 0.003678 # k_calc = 0.022 # k_opt = 0.04 shear_exp = 0.31 # air_density = 1.1716 # kg/m^3 air_density = 1.225 # kg/m^3 (from Jen) if turbine_type == 'V80': # define turbine size rotor_diameter = 80. # (m) hub_height = 70.0 z_ref = 80.0 # m z_0 = 0.0 # load performance characteristics cut_in_speed = 4. # m/s cut_out_speed = 25. # m/s rated_wind_speed = 16. # m/s rated_power = 2000. # kW generator_efficiency = 0.944 ct_curve_data = np.loadtxt(input_directory + 'mfg_ct_vestas_v80_niayifar2016.txt', delimiter=",") ct_curve_wind_speed = ct_curve_data[:, 0] ct_curve_ct = ct_curve_data[:, 1] # air_density = 1.1716 # kg/m^3 Ar = 0.25 * np.pi * rotor_diameter**2 # cp_curve_wind_speed = ct_curve[:, 0] power_data = np.loadtxt(input_directory + 'niayifar_vestas_v80_power_curve_observed.txt', delimiter=',') # cp_curve_cp = niayifar_power_model(cp_curve_wind_speed)/(0.5*air_density*cp_curve_wind_speed**3*Ar) cp_curve_cp = power_data[:, 1] * (1E6) / (0.5 * air_density * power_data[:, 0]**3 * Ar) cp_curve_wind_speed = power_data[:, 0] cp_curve_spline = UnivariateSpline(cp_curve_wind_speed, cp_curve_cp, ext='const') cp_curve_spline.set_smoothing_factor(.0001) elif turbine_type == 'NREL5MW': # define turbine size rotor_diameter = 126.4 # (m) hub_height = 90.0 z_ref = 80.0 # m z_0 = 0.0 # load performance characteristics cut_in_speed = 3. # m/s cut_out_speed = 25. # m/s rated_wind_speed = 11.4 # m/s rated_power = 5000. # kW generator_efficiency = 0.944 filename = input_directory + "NREL5MWCPCT_dict.p" # filename = "../input_files/NREL5MWCPCT_smooth_dict.p" import pickle data = pickle.load(open(filename, "rb"), encoding='latin1') ct_curve = np.zeros([data['wind_speed'].size, 2]) ct_curve_wind_speed = data['wind_speed'] ct_curve_ct = data['CT'] # cp_curve_cp = data['CP'] # cp_curve_wind_speed = data['wind_speed'] loc0 = np.where(data['wind_speed'] < 11.55) loc1 = np.where(data['wind_speed'] > 11.7) cp_curve_cp = np.hstack([data['CP'][loc0], data['CP'][loc1]]) cp_curve_wind_speed = np.hstack( [data['wind_speed'][loc0], data['wind_speed'][loc1]]) cp_curve_spline = UnivariateSpline(cp_curve_wind_speed, cp_curve_cp, ext='const') cp_curve_spline.set_smoothing_factor(.000001) else: raise ValueError("Turbine type is undefined.") # load starting locations layout_directory = input_directory layout_data = np.loadtxt( layout_directory + "layouts/round_38turbs/nTurbs38_spacing5_layout_%i.txt" % layout_number) # layout_data = np.loadtxt(layout_directory + "layouts/grid_16turbs/nTurbs16_spacing5_layout_%i.txt" % layout_number) # layout_data = np.loadtxt(layout_directory+"layouts/nTurbs9_spacing5_layout_%i.txt" % layout_number) turbineX = layout_data[:, 0] * rotor_diameter + rotor_diameter / 2. turbineY = layout_data[:, 1] * rotor_diameter + rotor_diameter / 2. turbineX_init = np.copy(turbineX) turbineY_init = np.copy(turbineY) nTurbines = turbineX.size # create boundary specifications boundary_radius = 0.5 * (rotor_diameter * 4000. / 126.4 - rotor_diameter ) # 1936.8 center = np.array([boundary_radius, boundary_radius]) + rotor_diameter / 2. start_min_spacing = 5. nVertices = 1 boundary_center_x = center[0] boundary_center_y = center[1] xmax = np.max(turbineX) ymax = np.max(turbineY) xmin = np.min(turbineX) ymin = np.min(turbineY) boundary_radius_plot = boundary_radius + 0.5 * rotor_diameter plot_round_farm(turbineX, turbineY, rotor_diameter, [boundary_center_x, boundary_center_y], boundary_radius, show_start=show_start) # quit() # initialize input variable arrays nTurbs = nTurbines rotorDiameter = np.zeros(nTurbs) hubHeight = np.zeros(nTurbs) axialInduction = np.zeros(nTurbs) Ct = np.zeros(nTurbs) Cp = np.zeros(nTurbs) generatorEfficiency = np.zeros(nTurbs) yaw = np.zeros(nTurbs) minSpacing = 2. # number of rotor diameters # define initial values for turbI in range(0, nTurbs): rotorDiameter[turbI] = rotor_diameter # m hubHeight[turbI] = hub_height # m axialInduction[turbI] = 1.0 / 3.0 Ct[turbI] = 4.0 * axialInduction[turbI] * (1.0 - axialInduction[turbI]) # print(Ct) Cp[turbI] = 4.0 * 1.0 / 3.0 * np.power((1 - 1.0 / 3.0), 2) generatorEfficiency[turbI] = generator_efficiency yaw[turbI] = 0. # deg. # Define flow properties if wind_rose_file == 'nantucket': windRose = np.loadtxt(input_directory + 'nantucket_windrose_ave_speeds.txt') # windRose = np.loadtxt(input_directory + 'nantucket_wind_rose_for_LES.txt') windDirections = windRose[:, 0] windSpeeds = windRose[:, 1] windFrequencies = windRose[:, 2] size = np.size(windDirections) elif wind_rose_file == 'amalia': windRose = np.loadtxt( input_directory + 'windrose_amalia_directionally_averaged_speeds.txt') windDirections = windRose[:, 0] windSpeeds = windRose[:, 1] windFrequencies = windRose[:, 2] size = np.size(windDirections) elif wind_rose_file == 'directional': windRose = np.loadtxt(input_directory + 'directional_windrose.txt') windDirections = windRose[:, 0] windSpeeds = windRose[:, 1] windFrequencies = windRose[:, 2] size = np.size(windDirections) elif wind_rose_file == '1d': windDirections = np.array([270.]) windSpeeds = np.array([8.0]) windFrequencies = np.array([1.0]) size = np.size(windDirections) else: size = 20 windDirections = np.linspace(0, 270, size) windFrequencies = np.ones(size) / size wake_model_options = { 'nSamples': 0, 'nRotorPoints': nRotorPoints, 'use_ct_curve': True, 'ct_curve_ct': ct_curve_ct, 'ct_curve_wind_speed': ct_curve_wind_speed, 'interp_type': 1, 'use_rotor_components': False, 'differentiable': differentiable, 'verbose': False } if MODELS[model] == 'BPA': # initialize problem prob = om.Problem( model=OptAEP(nTurbines=nTurbs, nDirections=windDirections.size, nVertices=nVertices, minSpacing=minSpacing, differentiable=differentiable, use_rotor_components=False, wake_model=gauss_wrapper, params_IdepVar_func=add_gauss_params_IndepVarComps, params_IdepVar_args={'nRotorPoints': nRotorPoints}, wake_model_options=wake_model_options, cp_points=cp_curve_cp.size, cp_curve_spline=cp_curve_spline, record_function_calls=True, runparallel=False)) elif MODELS[model] == 'FLORIS': # initialize problem prob = om.Problem( model=OptAEP(nTurbines=nTurbs, nDirections=windDirections.size, nVertices=nVertices, minSpacing=minSpacing, differentiable=differentiable, use_rotor_components=False, wake_model=floris_wrapper, params_IdepVar_func=add_floris_params_IndepVarComps, params_IdepVar_args={}, record_function_calls=True)) # elif MODELS[model] == 'JENSEN': # initialize problem # prob = om.Problem(model=OptAEP(nTurbines=nTurbs, nDirections=windDirections.size, nVertices=nVertices, # minSpacing=minSpacing, differentiable=False, use_rotor_components=False, # wake_model=jensen_wrapper, # params_IdepVar_func=add_jensen_params_IndepVarComps, # params_IdepVar_args={}, # record_function_calls=True)) else: ValueError( 'The %s model is not currently available. Please select BPA or FLORIS' % (MODELS[model])) # prob.model.deriv_options['type'] = 'fd' # prob.model.deriv_options['form'] = 'central' # prob.model.deriv_options['step_size'] = 1.0e-8 # prob.model.linear_solver = om.LinearBlockGS() # prob.model.linear_solver.options['iprint'] = 0 # prob.model.linear_solver.options['maxiter'] = 5 # # prob.model.nonlinear_solver = om.NonlinearBlockGS() # prob.model.nonlinear_solver.options['iprint'] = 0 # prob.model.linear_solver = om.DirectSolver() prob.driver = om.pyOptSparseDriver() if opt_algorithm == 'snopt': # set up optimizer prob.driver.options['optimizer'] = 'SNOPT' # prob.driver.options['gradient method'] = 'snopt_fd' # set optimizer options prob.driver.opt_settings['Verify level'] = -1 # set optimizer options prob.driver.opt_settings['Major optimality tolerance'] = np.float(1e-3) prob.driver.opt_settings[ 'Print file'] = output_directory + 'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number) prob.driver.opt_settings[ 'Summary file'] = output_directory + 'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number) prob.model.add_constraint('sc', lower=np.zeros( int(((nTurbs - 1.) * nTurbs / 2.))), scaler=1E-4) # , # active_tol=(2. * rotor_diameter) ** 2) prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-4) # , # active_tol=2. * rotor_diameter) prob.driver.options['dynamic_derivs_sparsity'] = True elif opt_algorithm == 'ga': prob.driver.options['optimizer'] = 'NSGA2' prob.driver.opt_settings['PrintOut'] = 1 prob.driver.opt_settings['maxGen'] = 50000 prob.driver.opt_settings['PopSize'] = 10 * nTurbines * 2 # prob.driver.opt_settings['pMut_real'] = 0.001 prob.driver.opt_settings['xinit'] = 1 prob.driver.opt_settings['rtol'] = 1E-4 prob.driver.opt_settings['atol'] = 1E-4 prob.driver.opt_settings['min_tol_gens'] = 200 prob.driver.opt_settings['file_number'] = run_number prob.model.add_constraint('sc', lower=np.zeros( int(((nTurbs - 1.) * nTurbs / 2.))), scaler=1E-4) prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-4) elif opt_algorithm == 'ps': prob.driver.options['optimizer'] = 'ALPSO' prob.driver.opt_settings['fileout'] = 1 prob.driver.opt_settings[ 'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number) prob.driver.opt_settings['maxOuterIter'] = 10000 prob.driver.opt_settings['SwarmSize'] = 25 prob.driver.opt_settings[ 'xinit'] = 1 # Initial Position Flag (0 - no position, 1 - position given) prob.driver.opt_settings[ 'Scaling'] = 1 # Design Variables Scaling Flag (0 - no scaling, 1 - scaling between [-1, 1]) # prob.driver.opt_settings['rtol'] = 1E-3 # Relative Tolerance for Lagrange Multipliers # # prob.driver.opt_settings['atol'] = 1E-2 # Absolute Tolerance for Lagrange Function # prob.driver.opt_settings[ 'dtol'] = 0.01 # Relative Tolerance in Distance of All Particles to Terminate (GCPSO) # # prob.driver.opt_settings['itol'] = 1E-3 # Absolute Tolerance for Inequality constraints # # prob.driver.opt_settings['dynInnerIter'] = 1 # Dynamic Number of Inner Iterations Flag prob.model.add_constraint('sc', lower=np.zeros( int(((nTurbs - 1.) * nTurbs / 2.))), scaler=1E-4) prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-4) # prob.driver.add_objective('obj', scaler=1E0) prob.model.add_objective('obj', scaler=1E-4) # select design variables prob.model.add_design_var('turbineX', scaler=1E0, lower=np.zeros(nTurbines), upper=np.ones(nTurbines) * 3. * boundary_radius) prob.model.add_design_var('turbineY', scaler=1E0, lower=np.zeros(nTurbines), upper=np.ones(nTurbines) * 3. * boundary_radius) # prob.model.ln_solver.options['single_voi_relevance_reduction'] = True # prob.model.ln_solver.options['mode'] = 'rev' # if run_number == 0: # # set up recorder # recorder = SqliteRecorder(output_directory+'recorder_database_run%i' % run_number) # recorder.options['record_params'] = True # recorder.options['record_metadata'] = False # recorder.options['record_unknowns'] = True # recorder.options['record_derivs'] = False # recorder.options['includes'] = ['turbineX', 'turbineY', 'AEP'] # prob.driver.add_recorder(recorder) driver_recorder = om.SqliteRecorder(output_directory + 'recorded_data_driver_%s.sql' % (run_number)) # model_recorder = om.SqliteRecorder(output_directory + 'recorded_data_model_%s.sql' %(run_number)) prob.driver.add_recorder(driver_recorder) # prob.model.add_recorder(model_recorder) prob.driver.recording_options['record_constraints'] = False prob.driver.recording_options['record_derivatives'] = False prob.driver.recording_options['record_desvars'] = True prob.driver.recording_options['record_inputs'] = False prob.driver.recording_options['record_model_metadata'] = True prob.driver.recording_options['record_objectives'] = True prob.driver.recording_options['includes'] = ['AEP'] prob.driver.recording_options['record_responses'] = False # # prob_recorder = om.SqliteRecorder(output_directory + 'recorded_data_prob_%s.sql' %(run_number)) # prob.add_recorder(prob_recorder) # prob.recording_options['includes'] = [] # prob.recording_options['record_objectives'] = True # set up profiling # from plantenergy.GeneralWindFarmComponents import WindFarmAEP # methods = [ # ('*', (WindFarmAEP,)) # ] # # iprofile.setup(methods=methods) print("almost time for setup") tic = time.time() print("entering setup at time = ", tic) prob.setup(check=True) toc = time.time() print("setup complete at time = ", toc) # print the results print(('Problem setup took %.03f sec.' % (toc - tic))) # assign initial values to design variables prob['turbineX'] = np.copy(turbineX) prob['turbineY'] = np.copy(turbineY) for direction_id in range(0, windDirections.size): prob['yaw%i' % direction_id] = yaw # assign values to constant inputs (not design variables) prob['rotorDiameter'] = rotorDiameter prob['hubHeight'] = hubHeight prob['axialInduction'] = axialInduction prob['generatorEfficiency'] = generatorEfficiency prob['windSpeeds'] = windSpeeds prob['air_density'] = air_density prob['windDirections'] = windDirections prob['windFrequencies'] = windFrequencies prob['Ct_in'] = Ct prob['Cp_in'] = Cp prob['cp_curve_cp'] = cp_curve_cp prob['cp_curve_wind_speed'] = cp_curve_wind_speed cutInSpeeds = np.ones(nTurbines) * cut_in_speed prob['cut_in_speed'] = cutInSpeeds ratedPowers = np.ones(nTurbines) * rated_power prob['rated_power'] = ratedPowers # assign values to turbine states prob['cut_in_speed'] = np.ones(nTurbines) * cut_in_speed prob['cut_out_speed'] = np.ones(nTurbines) * cut_out_speed prob['rated_power'] = np.ones(nTurbines) * rated_power prob['rated_wind_speed'] = np.ones(nTurbines) * rated_wind_speed prob['use_power_curve_definition'] = True # assign boundary values prob['boundary_center'] = np.array([boundary_center_x, boundary_center_y]) prob['boundary_radius'] = boundary_radius if MODELS[model] == 'BPA': prob['model_params:wake_combination_method'] = np.copy( wake_combination_method) prob['model_params:ti_calculation_method'] = np.copy( ti_calculation_method) prob['model_params:wake_model_version'] = np.copy(wake_model_version) prob['model_params:wec_factor'] = 1.0 prob['model_params:wec_spreading_angle'] = 0.0 prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc) prob['model_params:sort'] = np.copy(sort_turbs) prob['model_params:z_ref'] = np.copy(z_ref) prob['model_params:z_0'] = np.copy(z_0) prob['model_params:ky'] = np.copy(k_calc) prob['model_params:kz'] = np.copy(k_calc) prob['model_params:print_ti'] = np.copy(print_ti) prob['model_params:shear_exp'] = np.copy(shear_exp) prob['model_params:I'] = np.copy(TI) prob['model_params:sm_smoothing'] = np.copy(sm_smoothing) prob['model_params:WECH'] = WECH if nRotorPoints > 1: prob['model_params:RotorPointsY'], prob[ 'model_params:RotorPointsZ'] = sunflower_points(nRotorPoints) modelruns = 0 prob.run_model(case_prefix='ModelRun%i' % modelruns) AEP_init_calc = np.copy(prob['AEP']) print(AEP_init_calc * 1E-6) if MODELS[model] == 'BPA': prob['model_params:ti_calculation_method'] = np.copy(ti_opt_method) prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt) modelruns += 1 prob.run_model(case_prefix='ModelRun%i' % modelruns) AEP_init_opt = np.copy(prob['AEP']) AEP_run_opt = np.copy(AEP_init_opt) print(AEP_init_opt * 1E-6) config.obj_func_calls_array[:] = 0.0 config.sens_func_calls_array[:] = 0.0 expansion_factor_last = 0.0 driverruns = 0 tict = time.time() if relax: for expansion_factor, i in zip( expansion_factors, np.arange(0, expansion_factors.size)): # best so far # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array)) # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array)) # AEP_init_run_opt = prob['AEP'] if expansion_factor_last == expansion_factor: ti_opt_method = np.copy(final_ti_opt_method) calc_k_star_opt = True print("starting run with exp. fac = ", expansion_factor) if opt_algorithm == 'snopt': prob.driver.opt_settings['Major optimality tolerance'] = float( conv_tols[i]) prob.driver.opt_settings['Print file'] = output_directory + \ 'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor, ti_opt_method) prob.driver.opt_settings['Summary file'] = output_directory + \ 'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor, ti_opt_method) elif opt_algorithm == 'ps': prob.driver.opt_settings[ 'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number) turbineX = np.copy(prob['turbineX']) turbineY = np.copy(prob['turbineY']) prob['turbineX'] = np.copy(turbineX) prob['turbineY'] = np.copy(turbineY) if MODELS[model] == 'BPA': prob['model_params:ti_calculation_method'] = np.copy( ti_opt_method) prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt) if wec_method == 'diam': prob['model_params:wec_factor'] = np.copy(expansion_factor) elif wec_method == "hybrid": prob['model_params:wec_factor'] = np.copy(expansion_factor) elif wec_method == 'angle': prob['model_params:wec_spreading_angle'] = np.copy( expansion_factor) # run the problem print('start %s run' % (MODELS[model])) tic = time.time() # iprofile.start() config.obj_func_calls_array[prob.comm.rank] = 0.0 config.sens_func_calls_array[prob.comm.rank] = 0.0 prob.run_driver(case_prefix='DriverRun%i' % driverruns) driverruns += 1 # quit() toc = time.time() obj_calls = np.copy(config.obj_func_calls_array[0]) sens_calls = np.copy(config.sens_func_calls_array[0]) # iprofile.stop() toc = time.time() # print(np.sum(config.obj_func_calls_array)) # print(np.sum(config.sens_func_calls_array)) print('end %s run' % (MODELS[model])) run_time = toc - tic # print(run_time, expansion_factor) AEP_run_opt = np.copy(prob['AEP']) # print("AEP improvement = ", AEP_run_opt / AEP_init_opt) if MODELS[model] == 'BPA': prob['model_params:wec_factor'] = 1.0 prob['model_params:wec_spreading_angle'] = 0.0 prob['model_params:ti_calculation_method'] = np.copy( ti_calculation_method) prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc) modelruns += 1 prob.run_model(case_prefix='ModelRun%i' % modelruns) AEP_run_calc = np.copy(prob['AEP']) # print("compare: ", aep_run, prob['AEP']) print("AEP calc improvement = ", AEP_run_calc / AEP_init_calc) if prob.model.comm.rank == 0: # if save_aep: # np.savetxt(output_directory + '%s_multistart_aep_results_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f.txt' % ( # opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor), # np.c_[AEP_init, prob['AEP']], # header="Initial AEP, Final AEP") if save_locations: np.savetxt( output_directory + '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f_TItype%i.txt' % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor, ti_opt_method), np.c_[turbineX_init, turbineY_init, prob['turbineX'], prob['turbineY']], header= "initial turbineX, initial turbineY, final turbineX, final turbineY" ) # if save_time: # np.savetxt(output_directory + '%s_multistart_time_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f.txt' % ( # opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor), # np.c_[run_time], # header="run time") if save_time and save_aep and rec_func_calls: output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i.txt' \ % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number) f = open(output_file, "a") if i == 0: header = "run number, exp fac, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \ "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls" else: header = '' np.savetxt(f, np.c_[run_number, expansion_factor, ti_calculation_method, ti_opt_method, AEP_init_calc, AEP_init_opt, AEP_run_calc, AEP_run_opt, run_time, obj_calls, sens_calls], header=header) f.close() expansion_factor_last = expansion_factor else: for expansion_factor, i in zip( expansion_factors, np.arange(0, expansion_factors.size)): # best so far # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array)) # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array)) # AEP_init_run_opt = prob['AEP'] if expansion_factor_last == expansion_factor: ti_opt_method = np.copy(final_ti_opt_method) calc_k_star_opt = True if opt_algorithm == 'snopt': prob.driver.opt_settings['Major optimality tolerance'] = float( conv_tols[i]) prob.driver.opt_settings['Print file'] = output_directory + \ 'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method) prob.driver.opt_settings['Summary file'] = output_directory + \ 'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % ( nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method) print("starting run with exp. fac = ", expansion_factor) # run the problem print('start %s run' % (MODELS[model])) # cProfile.run('prob.run_driver()') if MODELS[model] == 'BPA': # prob['model_params:wec_factor'] = 1. prob['model_params:ti_calculation_method'] = np.copy( ti_opt_method) prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt) tic = time.time() # cProfile.run('prob.run_driver()') config.obj_func_calls_array[prob.comm.rank] = 0.0 config.sens_func_calls_array[prob.comm.rank] = 0.0 prob.run_driver(case_prefix='DriverRun%i' % driverruns) driverruns += 1 # quit() toc = time.time() obj_calls = np.copy(config.obj_func_calls_array[0]) sens_calls = np.copy(config.sens_func_calls_array[0]) run_time = toc - tic AEP_run_opt = np.copy(prob['AEP']) # print("AEP improvement = ", AEP_run_calc / AEP_init_calc) if MODELS[model] == 'BPA': prob['model_params:wec_factor'] = 1.0 prob['model_params:wec_spreading_angle'] = 0.0 prob['model_params:ti_calculation_method'] = np.copy( ti_calculation_method) prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc) modelruns += 1 prob.run_model(case_prefix='ModelRun%i' % modelruns) AEP_run_calc = np.copy(prob['AEP']) if prob.model.comm.rank == 0: if save_locations: np.savetxt( output_directory + '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt' % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method), np.c_[turbineX_init, turbineY_init, prob['turbineX'], prob['turbineY']], header= "initial turbineX, initial turbineY, final turbineX, final turbineY" ) if save_time and save_aep and rec_func_calls: output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt' \ % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method) f = open(output_file, "a") header = "run number, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \ "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls" np.savetxt(f, np.c_[run_number, ti_calculation_method, ti_opt_method, AEP_init_calc, AEP_init_opt, AEP_run_calc, AEP_run_opt, run_time, obj_calls, sens_calls], header=header) f.close() expansion_factor_last = expansion_factor turbineX_end = np.copy(prob['turbineX']) turbineY_end = np.copy(prob['turbineY']) toct = time.time() total_time = toct - tict if prob.model.comm.rank == 0: # print the results print(('Opt. calculation took %.03f sec.' % (toct - tict))) for direction_id in range(0, windDirections.size): print('yaw%i (deg) = ' % direction_id, prob['yaw%i' % direction_id]) print('turbine X positions in wind frame (m): %s' % prob['turbineX']) print('turbine Y positions in wind frame (m): %s' % prob['turbineY']) print('wind farm power in each direction (kW): %s' % prob['dirPowers']) print('Initial AEP (kWh): %s' % AEP_init_opt) print('Final AEP (kWh): %s' % AEP_run_calc) print('AEP improvement: %s' % (AEP_run_calc / AEP_init_calc)) if show_end: plot_square_farm(turbineX_end, turbineY_end, rotor_diameter, boundary_x, boundary_y, boundary_x[1] - boundary_x[0], show_start=show_start) prob.cleanup() if MODELS[model] == 'BPA': prob['model_params:wec_factor'] = 1.0 prob['model_params:wec_spreading_angle'] = 0.0 prob['model_params:ti_calculation_method'] = 4 prob['model_params:calc_k_star'] = True cr = om.CaseReader(output_directory + 'recorded_data_driver_%s.sql' % run_number) driver_cases = cr.list_cases('driver') nits = len(driver_cases) objectives = np.zeros(nits) AEPopt = np.zeros(nits) AEPcalc = np.zeros(nits) calls = np.zeros(nits) for i in np.arange(0, nits): case = cr.get_case(driver_cases[i]) # print(case) AEPopt[i] = case['AEP'] objectives[i] = case.get_objectives()['obj'] prob['turbineX'] = np.copy(case['turbineX']) prob['turbineY'] = np.copy(case['turbineY']) if opt_algorithm == "snopt": prob.run_model(case_prefix='ProcessingRun') AEPcalc[i] = np.copy(prob['AEP']) else: AEPcalc[i] = case['AEP'] calls[i] = i
# Compute the stall margins self.add_subsystem('stall_margins', StallCalcs(), promotes_inputs=[('PR_actual', 'PRmap'), ('Wc_actual', 'WcMap')], promotes_outputs=['SMN', 'SMW']) self.connect('SMN_map.PRmap', 'stall_margins.PR_SMN') self.connect('SMW_map.PRmap', 'stall_margins.PR_SMW') self.connect('SMN_map.WcMap', 'stall_margins.Wc_SMN') if __name__ == "__main__": from pycycle.maps.ncp01 import NCP01 p1 = om.Problem() ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes=['*']) # Design variables ivc.add_output('alphaMap', 0.0) ivc.add_output('PR', 2.0) ivc.add_output('Nc', 1000.0, units='rpm') ivc.add_output('eff', .9) ivc.add_output('Wc', 3000., units='lbm/s') # Off-design variables # ivc.add_output('alphaMap', 0.0) # ivc.add_output('Nc', 1000.0, units='rpm') # ivc.add_output('Wc', 3000., units='lbm/s') # ivc.add_output('s_Nc', 1.0) # ivc.add_output('s_Wc', 1.0) # ivc.add_output('s_PR', 1.0)
def test_debug_print_desvar_physical_with_indices(self): prob = om.Problem() model = prob.model size = 3 model.add_subsystem('p1', om.IndepVarComp('x', np.array([50.0] * size))) model.add_subsystem('p2', om.IndepVarComp('y', np.array([50.0] * size))) model.add_subsystem( 'comp', om.ExecComp('f_xy = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0', x=np.zeros(size), y=np.zeros(size), f_xy=np.zeros(size))) model.add_subsystem( 'con', om.ExecComp('c = - x + y', c=np.zeros(size), x=np.zeros(size), y=np.zeros(size))) model.connect('p1.x', 'comp.x') model.connect('p2.y', 'comp.y') model.connect('p1.x', 'con.x') model.connect('p2.y', 'con.y') prob.set_solver_print(level=0) prob.driver = om.ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False model.add_design_var('p1.x', indices=[1], lower=-50.0, upper=50.0, ref=[ 5.0, ]) model.add_design_var('p2.y', indices=[1], lower=-50.0, upper=50.0) model.add_objective('comp.f_xy', index=1) model.add_constraint('con.c', indices=[1], upper=-15.0) prob.setup() prob.driver.options['debug_print'] = [ 'desvars', ] stdout = sys.stdout strout = StringIO() sys.stdout = strout try: # formatting has changed in numpy 1.14 and beyond. if LooseVersion(np.__version__) >= LooseVersion("1.14"): with printoptions(precision=2, legacy="1.13"): prob.run_driver() else: with printoptions(precision=2): prob.run_driver() finally: sys.stdout = stdout output = strout.getvalue().split('\n') # should see unscaled (physical) and the full arrays, not just what is indicated by indices self.assertEqual( output[3], "{'p1.x': array([ 50., 50., 50.]), 'p2.y': array([ 50., 50., 50.])}" )
def test(self): """ This is an opt problem that tests the wingbox model with wave drag and the fuel vol constraint """ # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 6, 'chord_cos_spacing' : 0, 'span_cos_spacing' : 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'symmetry' : True, # if true, model one half of wing # reflected across the plane y = 0 'S_ref_type' : 'wetted', # how we compute the wing area, # can be 'wetted' or 'projected' 'fem_model_type' : 'wingbox', 'spar_thickness_cp' : np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp' : np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp' : np.array([4., 5., 8., 8., 8., 9.]), 'mesh' : mesh, 'data_x_upper' : upper_x, 'data_x_lower' : lower_x, 'data_y_upper' : upper_y, 'data_y_lower' : lower_y, 'strength_factor_for_upper_skin' : 1., # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. 'CL0' : 0.0, # CL of the surface at alpha=0 'CD0' : 0.0078, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c_cp' : np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c' : 0.12, 'c_max_t' : .38, # chordwise location of maximum thickness 'with_viscous' : True, 'with_wave' : True, # if true, compute wave drag # Structural values are based on aluminum 7075 'E' : 73.1e9, # [Pa] Young's modulus 'G' : (73.1e9/2/1.33), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield' : (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho' : 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin' : 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio' : 1.25, 'struct_weight_relief' : True, 'distributed_fuel_weight' : False, # Constraints 'exact_failure_constraint' : False, # if false, use KS function 'fuel_density' : 803., # [kg/m^3] fuel density (only needed if the fuel-in-wing volume constraint is used) 'Wf_reserve' :15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = om.Problem() # Add problem information as an independent variables component indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348*295.07*.85*1./(1.43*1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53/3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('speed_of_sound', point_name + '.speed_of_sound') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: com_name = point_name + '.' + name + '_perf.' prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') #======================================================================================= # Here we add the fuel volume constraint componenet to the model #======================================================================================= prob.model.add_subsystem('fuel_vol_delta', WingboxFuelVolDelta(surface=surface)) prob.model.connect('AS_point_0.fuelburn', 'fuel_vol_delta.fuelburn') prob.model.connect('wing.struct_setup.fuel_vols', 'fuel_vol_delta.fuel_vols') #======================================================================================= #======================================================================================= prob.driver = om.ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # prob.driver = om.pyOptSparseDriver() # prob.driver.add_recorder(om.SqliteRecorder("cases.sql")) # prob.driver.options['optimizer'] = "SNOPT" # prob.driver.opt_settings['Major optimality tolerance'] = 1e-6 # prob.driver.opt_settings['Major feasibility tolerance'] = 1e-8 # prob.driver.opt_settings['Major iterations limit'] = 200 prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15., scaler=0.1) prob.model.add_design_var('wing.spar_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.skin_thickness_cp', lower=0.003, upper=0.1, scaler=1e2) prob.model.add_design_var('wing.geometry.t_over_c_cp', lower=0.07, upper=0.2, scaler=10.) prob.model.add_constraint('AS_point_0.CL', equals=0.5) prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.) #======================================================================================= # Here we add the fuel volume constraint #======================================================================================= prob.model.add_constraint('fuel_vol_delta.fuel_vol_delta', lower=0.) #======================================================================================= #======================================================================================= # Set up the problem prob.setup() # om.view_model(prob) prob.run_driver() # prob.check_partials(form='central', compact_print=True) # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_mass'][0]/1.25) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 85029.7479699, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0]/1.25, 18927.5387802, 1e-5)
def test_driver_recording_options_deprecated(self): prob = om.Problem() msg = "The recording option, record_model_metadata, on Driver is deprecated. " \ "Recording of model metadata will always be done" with assert_warning(DeprecationWarning, msg): prob.driver.recording_options['record_model_metadata'] = True
def test_obj_pass(self): prob = om.Problem() model = prob.model indep = model.add_subsystem('indep', om.IndepVarComp(), promotes_outputs=['x']) indep.add_discrete_output('x', _DiscreteVal(19)) G = model.add_subsystem('G', om.ParallelGroup(), promotes_inputs=['x']) G1 = G.add_subsystem('G1', om.Group(), promotes_inputs=['x'], promotes_outputs=['y']) G1.add_subsystem('C1_1', ObjAdderCompEx(_DiscreteVal(5)), promotes_inputs=['x']) G1.add_subsystem('C1_2', ObjAdderCompEx(_DiscreteVal(7)), promotes_outputs=['y']) G1.connect('C1_1.y', 'C1_2.x') G2 = G.add_subsystem('G2', om.Group(), promotes_inputs=['x']) G2.add_subsystem('C2_1', ObjAdderCompEx(_DiscreteVal(1)), promotes_inputs=['x']) G2.add_subsystem('C2_2', ObjAdderCompEx(_DiscreteVal(11)), promotes_outputs=['y']) G2.connect('C2_1.y', 'C2_2.x') model.add_subsystem('C3', ObjAdderCompEx(_DiscreteVal(9))) model.add_subsystem('C4', ObjAdderCompEx(_DiscreteVal(21))) model.connect('G.y', 'C3.x') model.connect('G.G2.y', 'C4.x') prob.setup() prob.run_model() self.assertEqual(prob['C3.y'].getval(), 40) self.assertEqual(prob['C4.y'].getval(), 52) def _var_iter(obj): name = obj['name'] if 'children' in obj: for c in obj['children']: for vname in _var_iter(c): if name: yield '.'.join((name, vname)) else: yield vname else: yield name # add a test to see if discrete vars show up in n2 data = _get_viewer_data(prob) findvars = [ 'indep.x', 'G.G1.C1_1.x', 'G.G1.C1_1.y', 'G.G1.C1_2.x', 'G.G1.C1_2.y', 'G.G2.C2_1.x', 'G.G2.C2_1.y', 'G.G2.C2_2.x', 'G.G2.C2_2.y', 'C3.x', 'C3.y', 'C4.x', 'C4.y', ] vnames = list(_var_iter(data['tree'])) self.assertTrue(sorted(findvars), sorted(vnames))
def test_units_basic(self): prob = om.Problem() model = prob.model ivc = om.IndepVarComp() ivc.add_output('x', 35.0, units='degF') model.add_subsystem('p', ivc, promotes=['x']) model.add_subsystem('comp1', om.ExecComp('y1 = 2.0*x', x={ 'value': 2.0, 'units': 'degF' }, y1={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y1']) model.add_subsystem('comp2', om.ExecComp('y2 = 3.0*x', x={ 'value': 2.0, 'units': 'degF' }, y2={ 'value': 2.0, 'units': 'degF' }), promotes=['x', 'y2']) model.add_design_var('x', units='degC', lower=0.0, upper=100.0) model.add_constraint('y1', units='degC', lower=0.0, upper=100.0) model.add_objective('y2', units='degC') prob.setup() prob.run_driver() dv = prob.driver.get_design_var_values() assert_near_equal(dv['p.x'][0], 3.0 * 5 / 9, 1e-8) obj = prob.driver.get_objective_values(driver_scaling=True) assert_near_equal(obj['comp2.y2'][0], 73.0 * 5 / 9, 1e-8) con = prob.driver.get_constraint_values(driver_scaling=True) assert_near_equal(con['comp1.y1'][0], 38.0 * 5 / 9, 1e-8) meta = model.get_design_vars() assert_near_equal(meta['p.x']['lower'], 0.0, 1e-7) assert_near_equal(meta['p.x']['upper'], 100.0, 1e-7) meta = model.get_constraints() assert_near_equal(meta['comp1.y1']['lower'], 0.0, 1e-7) assert_near_equal(meta['comp1.y1']['upper'], 100.0, 1e-7) stdout = sys.stdout strout = StringIO() sys.stdout = strout try: prob.list_problem_vars(desvar_opts=['units'], objs_opts=['units'], cons_opts=['units']) finally: sys.stdout = stdout output = strout.getvalue().split('\n') self.assertTrue('1.666' in output[5]) self.assertTrue('21.111' in output[12]) self.assertTrue('40.555' in output[19]) self.assertTrue('degC' in output[5]) self.assertTrue('degC' in output[12]) self.assertTrue('degC' in output[19])
import openmdao.api as om import dymos as dm from donner_sub_ode import DonnerSubODE # Create the problem p = om.Problem(model=om.Group()) # Add the trajectory (optional for single phase problems) traj = dm.Trajectory() # Create the phase phase = dm.Phase(ode_class=DonnerSubODE, transcription=dm.GaussLobatto(num_segments=20, order=3, compressed=False)) # Add the phase to the trajectory, and the trajectory to the model traj.add_phase('phase0', phase=phase) p.model.add_subsystem('traj', traj) # # Configure the phase # phase.set_time_options(units=None, targets=['threat_comp.time'], fix_initial=True, duration_bounds=(0.1, 100)) phase.add_state('x', rate_source='eom_comp.dx_dt', targets=['nav_comp.x'],
def testRunAll(self): opt = {} opt["floating"] = {} opt["WISDEM"] = {} opt["WISDEM"]["FloatingSE"] = {} opt["floating"]["members"] = {} opt["floating"]["members"]["n_members"] = n_member = 6 opt["floating"]["members"]["n_height"] = [2] opt["floating"]["members"]["n_bulkheads"] = [4] opt["floating"]["members"]["n_layers"] = [1] opt["floating"]["members"]["n_ballasts"] = [0] opt["floating"]["members"]["n_axial_joints"] = [1] opt["floating"]["tower"] = {} opt["floating"]["tower"]["n_height"] = [3] opt["floating"]["tower"]["n_bulkheads"] = [0] opt["floating"]["tower"]["n_layers"] = [1] opt["floating"]["tower"]["n_ballasts"] = [0] opt["floating"]["tower"]["n_axial_joints"] = [0] opt["WISDEM"]["FloatingSE"]["frame3dd"] = {} opt["WISDEM"]["FloatingSE"]["frame3dd"]["shear"] = True opt["WISDEM"]["FloatingSE"]["frame3dd"]["geom"] = True opt["WISDEM"]["FloatingSE"]["frame3dd"]["tol"] = 1e-7 opt["WISDEM"]["FloatingSE"]["frame3dd"]["modal"] = False # True opt["WISDEM"]["FloatingSE"]["gamma_f"] = 1.35 # Safety factor on loads opt["WISDEM"]["FloatingSE"]["gamma_m"] = 1.3 # Safety factor on materials opt["WISDEM"]["FloatingSE"]["gamma_n"] = 1.0 # Safety factor on consequence of failure opt["WISDEM"]["FloatingSE"]["gamma_b"] = 1.1 # Safety factor on buckling opt["WISDEM"]["FloatingSE"]["gamma_fatigue"] = 1.755 # Not used opt["mooring"] = {} opt["mooring"]["n_attach"] = 3 opt["mooring"]["n_anchors"] = 3 opt["materials"] = {} opt["materials"]["n_mat"] = 2 prob = om.Problem() prob.model = frame.FloatingFrame(modeling_options=opt) prob.setup() # Material properties prob["rho_mat"] = np.array([7850.0, 5000.0]) # Steel, ballast slurry [kg/m^3] prob["E_mat"] = 200e9 * np.ones((2, 3)) # Young's modulus [N/m^2] prob["G_mat"] = 79.3e9 * np.ones((2, 3)) # Shear modulus [N/m^2] prob["sigma_y_mat"] = 3.45e8 * np.ones(2) # Elastic yield stress [N/m^2] prob["unit_cost_mat"] = np.array([2.0, 1.0]) prob["material_names"] = ["steel", "slurry"] # Mass and cost scaling factors prob["labor_cost_rate"] = 1.0 # Cost factor for labor time [$/min] prob["painting_cost_rate"] = 14.4 # Cost factor for column surface finishing [$/m^2] prob["member0:nodes_xyz"][:2, :] = np.array([[0, 0, 0], [1, 0, 0]]) prob["member1:nodes_xyz"][:2, :] = np.array([[1, 0, 0], [0.5, 1, 0]]) prob["member2:nodes_xyz"][:2, :] = np.array([[0.5, 1, 0], [0, 0, 0]]) prob["member3:nodes_xyz"][:2, :] = np.array([[0, 0, 0], [0, 0, 1]]) prob["member4:nodes_xyz"][:2, :] = np.array([[1, 0, 0], [0, 0, 1]]) prob["member5:nodes_xyz"][:2, :] = np.array([[0.5, 1, 0], [0, 0, 1]]) for k in range(n_member): L = np.sqrt(np.sum(np.diff(prob["member" + str(k) + ":nodes_xyz"][:, 2], axis=0) ** 2)) prob["member" + str(k) + ":nodes_r"][:2] = 0.1 * k * np.ones(2) prob["member" + str(k) + ":section_D"][:1] = 2.0 prob["member" + str(k) + ":section_t"][:1] = 0.1 prob["member" + str(k) + ":section_A"][:1] = 0.5 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_Asx"][:1] = 0.5 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_Asy"][:1] = 0.5 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_Ixx"][:1] = 2 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_Iyy"][:1] = 2 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_Izz"][:1] = 2 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_rho"][:1] = 1e3 / (0.5 * k * np.ones(1) + 1) / L prob["member" + str(k) + ":section_E"][:1] = 3 * k * np.ones(1) + 1 prob["member" + str(k) + ":section_G"][:1] = 4 * k * np.ones(1) + 1 prob["member" + str(k) + ":idx_cb"] = 0 prob["member" + str(k) + ":buoyancy_force"] = 1e2 prob["member" + str(k) + ":displacement"] = 1e1 prob["member" + str(k) + ":center_of_buoyancy"] = prob["member" + str(k) + ":nodes_xyz"][:2, :].mean(axis=0) prob["member" + str(k) + ":center_of_mass"] = prob["member" + str(k) + ":nodes_xyz"][:2, :].mean(axis=0) prob["member" + str(k) + ":total_mass"] = 1e3 prob["member" + str(k) + ":total_cost"] = 2e3 prob["member" + str(k) + ":Awater"] = 5.0 prob["member" + str(k) + ":Iwater"] = 15.0 prob["member" + str(k) + ":added_mass"] = np.arange(6) # Set environment to that used in OC3 testing campaign # prob["rho_air"] = 1.226 # Density of air [kg/m^3] # prob["mu_air"] = 1.78e-5 # Viscosity of air [kg/m/s] prob["rho_water"] = 1025.0 # Density of water [kg/m^3] # prob["mu_water"] = 1.08e-3 # Viscosity of water [kg/m/s] # prob["water_depth"] = 320.0 # Distance to sea floor [m] # prob["Hsig_wave"] = 0.0 # Significant wave height [m] # prob["Tsig_wave"] = 1e3 # Wave period [s] # prob["shearExp"] = 0.11 # Shear exponent in wind power law # prob["cm"] = 2.0 # Added mass coefficient # prob["Uc"] = 0.0 # Mean current speed # prob["yaw"] = 0.0 # Turbine yaw angle # prob["beta_wind"] = prob["beta_wave"] = 0.0 # prob["cd_usr"] = -1.0 # Compute drag coefficient # prob["Uref"] = 10.0 # prob["zref"] = 100.0 # Porperties of turbine tower nTower = prob.model.options["modeling_options"]["floating"]["tower"]["n_height"][0] prob["hub_height"] = 85.0 prob["distance_tt_hub"] = 5.0 prob["tower.s"] = np.linspace(0.0, 1.0, nTower) prob["tower.outer_diameter_in"] = np.linspace(6.5, 3.87, nTower) prob["tower.layer_thickness"] = np.linspace(0.027, 0.019, nTower).reshape((1, nTower)) prob["tower.layer_materials"] = ["steel"] prob["tower.outfitting_factor"] = 1.07 prob["mooring_neutral_load"] = np.zeros((3, 3)) prob["mooring_neutral_load"][:, 0] = [200, -100.0, -100] prob["mooring_neutral_load"][:, 1] = [0.0, 50, -50] prob["mooring_neutral_load"][:, 2] = -1e3 prob["mooring_fairlead_joints"] = np.array([[0.0, 0.0, 0.0], [0.5, 1.0, 0.0], [1.0, 0.0, 0.0]]) prob["rna_mass"] = 1e4 prob["rna_cg"] = np.ones(3) prob["rna_I"] = 1e4 * np.arange(6) prob["rna_F"] = np.array([1e2, 1e1, 0.0]) prob["rna_M"] = np.array([2e1, 2e2, 0.0]) prob["transition_piece_mass"] = 1e3 prob["transition_node"] = prob["member4:nodes_xyz"][0, :] prob.run_model() self.assertTrue(True)