def _setup_controls(self): control_options = self.options['control_options'] num_nodes_all = self.num_nodes_all num_nodes_output = self.num_nodes_output num_control_input_nodes = self.options['grid_data'].subset_num_nodes['control_input'] time_units = self.options['time_units'] for name, options in iteritems(control_options): self._input_names[name] = 'controls:{0}'.format(name) self._output_val_all_names[name] = 'control_values_all:{0}'.format(name) self._output_val_names[name] = 'control_values:{0}'.format(name) self._output_rate_names[name] = 'control_rates:{0}_rate'.format(name) self._output_rate2_names[name] = 'control_rates:{0}_rate2'.format(name) shape = options['shape'] input_shape = (num_control_input_nodes,) + shape all_shape = (num_nodes_all,) + shape output_shape = (num_nodes_output,) + shape units = options['units'] rate_units = get_rate_units(units, time_units) rate2_units = get_rate_units(units, time_units, deriv=2) self._dynamic_names.append(name) self.add_input(self._input_names[name], val=np.ones(input_shape), units=units) self.add_output(self._output_val_all_names[name], shape=all_shape, units=units) self.add_output(self._output_val_names[name], shape=output_shape, units=units) self.add_output(self._output_rate_names[name], shape=output_shape, units=rate_units) self.add_output(self._output_rate2_names[name], shape=output_shape, units=rate2_units)
def test_get_rate_units(self): rate_units = get_rate_units('m', 's', deriv=1) self.assertEqual(rate_units, 'm/s') rate2_units = get_rate_units('m', 's', deriv=2) self.assertEqual(rate2_units, 'm/s**2')
def configure_io(self): """ Create inputs/outputs on this component. """ state_options = self.options['state_options'] time_units = self.options['time_units'] for name, options in state_options.items(): self._input_names[name] = f'state_rates_in:{name}_rate' self._output_names[name] = f'state_rates:{name}_rate' shape = options['shape'] size = np.prod(shape, dtype=int) units = options['units'] rate_units = get_rate_units(units, time_units) self.add_input(self._input_names[name], shape=shape, units=rate_units) self.add_output(self._output_names[name], shape=shape, units=rate_units) ar = np.arange(size, dtype=int) self.declare_partials(of=self._output_names[name], wrt=self._input_names[name], rows=ar, cols=ar, val=1.0)
def setup(self): """ Create inputs/outputs for this component. """ time_units = self.options['time_units'] self.add_input('time', val=1.0, units=time_units) for control_name, options in self.options['control_options'].items(): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units, deriv=1) rate2_units = get_rate_units(units, time_units, deriv=2) self.add_output('controls:{0}'.format(control_name), shape=shape, units=units) self.add_output('control_rates:{0}_rate'.format(control_name), shape=shape, units=rate_units) self.add_output('control_rates:{0}_rate2'.format(control_name), shape=shape, units=rate2_units) for control_name, options in self.options[ 'polynomial_control_options'].items(): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units, deriv=1) rate2_units = get_rate_units(units, time_units, deriv=2) self.add_output('polynomial_controls:{0}'.format(control_name), shape=shape, units=units) self.add_output( 'polynomial_control_rates:{0}_rate'.format(control_name), shape=shape, units=rate_units) self.add_output( 'polynomial_control_rates:{0}_rate2'.format(control_name), shape=shape, units=rate2_units)
def configure_io(self): """ I/O creation is delayed until configure so that we can determine the shape and units for the states. """ self._var_names = {} num_seg = self.options['num_segments'] rk_data = rk_methods[self.options['method']] num_stages = rk_data['num_stages'] self.add_input('h', val=np.ones(num_seg), units=self.options['time_units'], desc='step size for current Runge-Kutta segment.') for name, options in self.options['state_options'].items(): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, self.options['time_units']) self._var_names[name] = {} self._var_names[name]['f'] = 'f:{0}'.format(name) self._var_names[name]['k'] = 'k:{0}'.format(name) self.add_input( self._var_names[name]['f'], shape=(num_seg, num_stages) + shape, units=rate_units, desc= 'The predicted values of the state at the ODE evaluation points.' ) self.add_output( self._var_names[name]['k'], shape=(num_seg, num_stages) + shape, units=units, desc='RK multiplier k for each stage in the segment.') size = np.prod(shape) ar = np.arange(size * num_stages * num_seg, dtype=int) self.declare_partials(of=self._var_names[name]['k'], wrt=self._var_names[name]['f'], rows=ar, cols=ar) r = np.arange(size * num_stages * num_seg, dtype=int) c = np.repeat(np.arange(num_seg, dtype=int), num_stages * size) self.declare_partials(of=self._var_names[name]['k'], wrt='h', rows=r, cols=c)
def setup(self): time_units = self.options['time_units'] self.add_input('time', val=1.0, units=time_units) for control_name, options in iteritems( self.options['control_options']): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units, deriv=1) rate2_units = get_rate_units(units, time_units, deriv=2) self.add_output('controls:{0}'.format(control_name), shape=shape, units=units) self.add_output('control_rates:{0}_rate'.format(control_name), shape=shape, units=rate_units) self.add_output('control_rates:{0}_rate2'.format(control_name), shape=shape, units=rate2_units)
def _setup_variables(self): num_nodes = self.num_nodes time_units = self.options['time_units'] for name, options in iteritems(self._var_options): self._input_names[name] = name self._output_rate_names[name] = 'dYdt:{0}'.format(name) shape = options['shape'] input_shape = (num_nodes,) + shape output_shape = (num_nodes,) + shape print(name, input_shape, output_shape) units = options['units'] rate_units = get_rate_units(units, time_units) self._dynamic_names.append(name) self.add_input(self._input_names[name], val=np.ones(input_shape), units=units) self.add_output(self._output_rate_names[name], shape=output_shape, units=rate_units) size = np.prod(shape) self.rate_jacs[name] = np.zeros((num_nodes, size, num_nodes, size)) for i in range(size): self.rate_jacs[name][:, i, :, i] = self.D self.rate_jacs[name] = self.rate_jacs[name].reshape((num_nodes * size, num_nodes * size), order='C') self.rate_jac_rows[name], self.rate_jac_cols[name] = \ np.where(self.rate_jacs[name] != 0) self.sizes[name] = size cs = np.tile(np.arange(num_nodes, dtype=int), reps=size) rs = np.concatenate([np.arange(0, num_nodes * size, size, dtype=int) + i for i in range(size)]) self.declare_partials(of=self._output_rate_names[name], wrt='dt_dstau', rows=rs, cols=cs) self.declare_partials(of=self._output_rate_names[name], wrt=self._input_names[name], rows=self.rate_jac_rows[name], cols=self.rate_jac_cols[name])
def setup(self): state_options = self.options['state_options'] time_units = self.options['time_units'] for name, options in iteritems(state_options): self._input_names[name] = 'state_rates_in:{0}_rate'.format(name) self._output_names[name] = 'state_rates:{0}_rate'.format(name) shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units) self.add_input(self._input_names[name], val=np.ones(shape), units=rate_units) self.add_output(self._output_names[name], shape=shape, units=rate_units)
def setup(self): time_units = self.options['time_units'] num_disc_nodes = self.options['grid_data'].subset_num_nodes[ 'state_disc'] num_col_nodes = self.options['grid_data'].subset_num_nodes['col'] state_options = self.options['state_options'] transcription = self.options['transcription'] self.add_input(name='dt_dstau', shape=(num_col_nodes, ), units=time_units, desc='For each node, the duration of its ' 'segment in the integration variable') self.xd_str = {} self.fd_str = {} self.xc_str = {} self.xdotc_str = {} for state_name, options in state_options.items(): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units) self.add_input( name='state_disc:{0}'.format(state_name), shape=(num_disc_nodes, ) + shape, desc='Values of state {0} at discretization nodes'.format( state_name), units=units) if transcription == 'gauss-lobatto': self.add_input(name='staterate_disc:{0}'.format(state_name), shape=(num_disc_nodes, ) + shape, units=rate_units, desc='EOM time derivative of state {0} at ' 'discretization nodes'.format(state_name)) self.add_output(name='state_col:{0}'.format(state_name), shape=(num_col_nodes, ) + shape, units=units, desc='Interpolated values of state {0} at ' 'collocation nodes'.format(state_name)) self.add_output( name='staterate_col:{0}'.format(state_name), shape=(num_col_nodes, ) + shape, units=rate_units, desc='Interpolated rate of state {0} at collocation nodes'. format(state_name)) self.xd_str[state_name] = 'state_disc:{0}'.format(state_name) self.fd_str[state_name] = 'staterate_disc:{0}'.format(state_name) self.xc_str[state_name] = 'state_col:{0}'.format(state_name) self.xdotc_str[state_name] = 'staterate_col:{0}'.format(state_name) if transcription == 'gauss-lobatto': Ai, Bi, Ad, Bd = self.options['grid_data'].phase_hermite_matrices( 'state_disc', 'col') elif transcription == 'radau-ps': Ai, Ad = self.options['grid_data'].phase_lagrange_matrices( 'state_disc', 'col') Bi = Bd = np.zeros(shape=(num_col_nodes, num_disc_nodes)) else: raise ValueError('unhandled transcription type: ' '{0}'.format(self.options['transcription'])) self.matrices = {'Ai': Ai, 'Bi': Bi, 'Ad': Ad, 'Bd': Bd} # Setup partials self.jacs = {'Ai': {}, 'Bi': {}, 'Ad': {}, 'Bd': {}} self.Bi_rows = {} self.Bi_cols = {} self.Ad_rows = {} self.Ad_cols = {} self.sizes = {} self.num_col_nodes = num_col_nodes self.num_disc_nodes = num_disc_nodes for name, options in iteritems(state_options): shape = options['shape'] size = np.prod(shape) for key in self.jacs: jac = np.zeros((num_col_nodes, size, num_disc_nodes, size)) for i in range(size): jac[:, i, :, i] = self.matrices[key] jac = jac.reshape( (num_col_nodes * size, num_disc_nodes * size), order='C') self.jacs[key][name] = jac self.sizes[name] = size # # Partial of xdotc wrt dt_dstau # # The partial of xdotc (state rate at collocation nodes) is a matrix of m bands # on and below the diagonal where m is the size of the variable. rs_dtdstau = np.zeros(num_col_nodes * size, dtype=int) cs_dtdstau = np.tile(np.arange(0, num_col_nodes, dtype=int), reps=size) r_band = np.arange(0, num_col_nodes, dtype=int) * size r0 = 0 for i in range(size): rs_dtdstau[r0:r0 + num_col_nodes] = r_band + i r0 += num_col_nodes self.declare_partials(of=self.xdotc_str[name], wrt='dt_dstau', rows=rs_dtdstau, cols=cs_dtdstau) if transcription == 'gauss-lobatto': self.declare_partials(of=self.xc_str[name], wrt='dt_dstau', rows=rs_dtdstau, cols=cs_dtdstau) Ai_rows, Ai_cols = np.where(self.jacs['Ai'][name] != 0) self.declare_partials(of=self.xc_str[name], wrt=self.xd_str[name], rows=Ai_rows, cols=Ai_cols, val=self.jacs['Ai'][name][Ai_rows, Ai_cols]) self.Bi_rows[name], self.Bi_cols[name] = np.where( self.jacs['Bi'][name] != 0) self.declare_partials(of=self.xc_str[name], wrt=self.fd_str[name], rows=self.Bi_rows[name], cols=self.Bi_cols[name]) Bd_rows, Bd_cols = np.where(self.jacs['Bd'][name] != 0) self.declare_partials(of=self.xdotc_str[name], wrt=self.fd_str[name], rows=Bd_rows, cols=Bd_cols, val=self.jacs['Bd'][name][Bd_rows, Bd_cols]) self.Ad_rows[name], self.Ad_cols[name] = np.where( self.jacs['Ad'][name] != 0) self.declare_partials(of=self.xdotc_str[name], wrt=self.xd_str[name], rows=self.Ad_rows[name], cols=self.Ad_cols[name])
def test_get_rate_units_invalid_deriv(self): with self.assertRaises(ValueError) as e: get_rate_units('m', 's', deriv=0) self.assertEqual(str(e.exception), 'deriv argument must be 1 or 2.')
def record_results(self, phase_name, filename, ode_class, ode_init_kwargs=None): """ Record the outputs to the given filename. This is done by instantiating a new problem with an IndepVarComp for the time, states, controls, and control rates, as well as an instance of the given ODE class (instantiated with the number of nodes equal to the number of times in the outputs). The system is populated with data from outputs, has a recorder attached, and is executed via problem.run_model. This data can then be retrieved from the `system_cases` attribute of CaseReader. Parameters ---------- phase_name : str The name of the phase whose simulation results are being recorded. filename : str The filename to which the recording should be saved. ode_class : openmdao.System A system class with the appropriate ODE metadata attached via the dymos declare_time, declare_state, and declare_parameter decorators. ode_init_kwargs : dict or None A dictionary of keyword arguments with which ode_class should be instantiated. """ init_kwargs = {} if ode_init_kwargs is None else ode_init_kwargs p = Problem(model=Group()) time = self.get_values('time') nn = len(time) ode_sys = ode_class(num_nodes=nn, **init_kwargs) ivc = p.model.add_subsystem('inputs', subsys=IndepVarComp(), promotes_outputs=['*']) p.model.add_subsystem('ode', subsys=ode_sys) # Connect times ivc.add_output('time', val=np.zeros((nn, 1)), units=self.time_options['units']) p.model.connect( 'time', ['ode.{0}'.format(t) for t in self.time_options['targets']]) # Connect states for name, options in iteritems(self.state_options): ivc.add_output('states:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=options['units']) p.model.connect('states:{0}'.format(name), ['ode.{0}'.format(t) for t in options['targets']]) # Connect controls sys_param_options = ode_sys.ode_options._parameters for name, options in iteritems(self.control_options): units = options['units'] ivc.add_output('controls:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) p.model.connect('controls:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[name]['targets'] ], src_indices=np.arange(nn, dtype=int)) rate_units = get_rate_units(units, self.time_options['units'], deriv=1) ivc.add_output('control_rates:{0}_rate'.format(name), val=np.zeros((nn, ) + options['shape']), units=rate_units) if options['rate_param']: rate_targets = sys_param_options[ options['rate_param']]['targets'] p.model.connect('control_rates:{0}_rate'.format(name), ['ode.{0}'.format(t) for t in rate_targets], src_indices=np.arange(nn, dtype=int)) rate2_units = get_rate_units(units, self.time_options['units'], deriv=2) ivc.add_output('control_rates:{0}_rate2'.format(name), val=np.zeros((nn, ) + options['shape']), units=rate2_units) if options['rate2_param']: rate2_targets = sys_param_options[ options['rate2_param']]['targets'] p.model.connect('control_rates:{0}_rate2'.format(name), ['ode.{0}'.format(t) for t in rate2_targets], src_indices=np.arange(nn, dtype=int)) # Connect design parameters for name, options in iteritems(self.design_parameter_options): units = options['units'] ivc.add_output('design_parameters:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) p.model.connect('design_parameters:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[name]['targets'] ], src_indices=np.arange(nn, dtype=int)) # Connect input parameters for name, options in iteritems(self.input_parameter_options): units = options['units'] ivc.add_output('input_parameters:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) p.model.connect('input_parameters:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[name]['targets'] ], src_indices=np.arange(nn, dtype=int)) p.setup(check=False) p.model.add_recorder(SqliteRecorder(filename)) p.model.recording_options['record_metadata'] = True p.model.recording_options['record_outputs'] = True # Assign times p['time'] = time # Assign states for name in self.state_options: p['states:{0}'.format(name)] = self.get_values(name) # Assign controls for name, options in iteritems(self.control_options): shape = p['controls:{0}'.format(name)].shape p['controls:{0}'.format(name)] = np.reshape( self.get_values(name), shape) p['control_rates:{0}_rate'.format(name)] = \ np.reshape(self.get_values('{0}_rate'.format(name)), shape) p['control_rates:{0}_rate2'.format(name)] = \ np.reshape(self.get_values('{0}_rate2'.format(name)), shape) # Assign design parameters for name, options in iteritems(self.design_parameter_options): shape = p['design_parameters:{0}'.format(name)].shape p['design_parameters:{0}'.format(name)] = np.reshape( self.get_values(name), shape) # Assign input parameters for name, options in iteritems(self.input_parameter_options): shape = p['input_parameters:{0}'.format(name)].shape p['input_parameters:{0}'.format(name)] = np.reshape( self.get_values(name), shape) # Populate outputs of ODE prom2abs_ode_outputs = p.model.ode._var_allprocs_prom2abs_list[ 'output'] for prom_name, abs_name in iteritems(prom2abs_ode_outputs): if p[abs_name[0]].shape[0] == 1: p[abs_name[0]] = self.get_values(prom_name)[0] else: p[abs_name[0]] = np.reshape(self.get_values(prom_name), p[abs_name[0]].shape) # Run model to record file p.run_model()
def _setup_control_continuity(self): control_options = self.options['control_options'] num_segend_nodes = self.options['grid_data'].subset_num_nodes[ 'segment_ends'] num_segments = self.options['grid_data'].num_segments time_units = self.options['time_units'] if num_segments <= 1: # Control value and rate continuity is enforced even with compressed transcription return self.add_input('t_duration', units=time_units, val=1.0, desc='time duration of the phase') for control_name, options in iteritems(control_options): shape = options['shape'] size = np.prod(shape) units = options['units'] rate_units = get_rate_units(units, time_units, deriv=1) rate2_units = get_rate_units(units, time_units, deriv=2) # Define the sparsity pattern for rate and rate2 continuity rs_size1 = np.repeat(np.arange(num_segments - 1, dtype=int), 2) cs_size1 = np.arange(1, num_segend_nodes - 1, dtype=int) template = np.zeros((num_segments - 1, num_segend_nodes)) template[rs_size1, cs_size1] = 1.0 template = np.kron(template, np.eye(size)) rs, cs = template.nonzero() vals = np.zeros(len(rs), dtype=float) vals[0::2] = -1.0 vals[1::2] = 1.0 self.rate_jac_templates[control_name] = vals # # Setup value continuity # self.name_maps[control_name] = {} self.name_maps[control_name]['value_names'] = \ ('controls:{0}'.format(control_name), 'defect_controls:{0}'.format(control_name)) self.name_maps[control_name]['rate_names'] = \ ('control_rates:{0}_rate'.format(control_name), 'defect_control_rates:{0}_rate'.format(control_name)) self.name_maps[control_name]['rate2_names'] = \ ('control_rates:{0}_rate2'.format(control_name), 'defect_control_rates:{0}_rate2'.format(control_name)) self.add_input( name='controls:{0}'.format(control_name), shape=(num_segend_nodes, ) + shape, desc='Values of control {0} at discretization nodes'.format( control_name), units=units) self.add_output( name='defect_controls:{0}'.format(control_name), val=5 * np.ones((num_segments - 1, ) + shape), desc='Continuity constraint values for control {0}'.format( control_name), units=units) self.declare_partials( 'defect_controls:{0}'.format(control_name), 'controls:{0}'.format(control_name), val=vals, rows=rs, cols=cs, ) # # Setup first derivative continuity # self.add_input(name='control_rates:{0}_rate'.format(control_name), shape=(num_segend_nodes, ) + shape, desc='Values of control {0} derivative at ' 'discretization nodes'.format(control_name), units=rate_units) self.add_output( name='defect_control_rates:{0}_rate'.format(control_name), shape=(num_segments - 1, ) + shape, desc='Consistency constraint values for ' 'control {0} derivative'.format(control_name), units=rate_units) self.declare_partials( 'defect_control_rates:{0}_rate'.format(control_name), 'control_rates:{0}_rate'.format(control_name), rows=rs, cols=cs, ) self.declare_partials( 'defect_control_rates:{0}_rate'.format(control_name), 't_duration', dependent=True, ) # # Setup second derivative continuity # self.add_input(name='control_rates:{0}_rate2'.format(control_name), shape=(num_segend_nodes, ) + shape, desc='Values of control {0} second derivative ' 'at discretization nodes'.format(control_name), units=rate2_units) self.add_output( name='defect_control_rates:{0}_rate2'.format(control_name), shape=(num_segments - 1, ) + shape, desc='Consistency constraint values for control ' '{0} second derivative'.format(control_name), units=rate2_units) self.declare_partials( 'defect_control_rates:{0}_rate2'.format(control_name), 'control_rates:{0}_rate2'.format(control_name), rows=rs, cols=cs, ) self.declare_partials( 'defect_control_rates:{0}_rate2'.format(control_name), 't_duration', dependent=True)
def setup(self): gd = self.options['grid_data'] num_col_nodes = gd.subset_num_nodes['col'] time_units = self.options['time_units'] state_options = self.options['state_options'] self.add_input('dt_dstau', units=time_units, shape=(num_col_nodes, )) self.var_names = var_names = {} for state_name in state_options: var_names[state_name] = { 'f_approx': 'f_approx:{0}'.format(state_name), 'f_computed': 'f_computed:{0}'.format(state_name), 'defect': 'defects:{0}'.format(state_name), } for state_name, options in iteritems(state_options): shape = options['shape'] units = options['units'] rate_units = get_rate_units(units, time_units) var_names = self.var_names[state_name] self.add_input(name=var_names['f_approx'], shape=(num_col_nodes, ) + shape, desc='Estimated derivative of state {0} ' 'at the collocation nodes'.format(state_name), units=rate_units) self.add_input(name=var_names['f_computed'], shape=(num_col_nodes, ) + shape, desc='Computed derivative of state {0} ' 'at the collocation nodes'.format(state_name), units=rate_units) self.add_output( name=var_names['defect'], shape=(num_col_nodes, ) + shape, desc='Interior defects of state {0}'.format(state_name), units=units) if 'defect_ref' in options and options['defect_ref'] is not None: def_scl = 1.0 / options['defect_ref'] elif 'defect_scaler' in options: def_scl = options['defect_scaler'] else: def_scl = 1.0 self.add_constraint(name=var_names['defect'], equals=0.0, scaler=def_scl) # Setup partials num_col_nodes = self.options['grid_data'].subset_num_nodes['col'] state_options = self.options['state_options'] for state_name, options in state_options.items(): shape = options['shape'] size = np.prod(shape) r = np.arange(num_col_nodes * size) var_names = self.var_names[state_name] self.declare_partials(of=var_names['defect'], wrt=var_names['f_approx'], rows=r, cols=r) self.declare_partials(of=var_names['defect'], wrt=var_names['f_computed'], rows=r, cols=r) c = np.repeat(np.arange(num_col_nodes), size) self.declare_partials(of=var_names['defect'], wrt='dt_dstau', rows=r, cols=c)
def record_results(self, traj, exp_outs, filename): """ Record the outputs to the given filename. This is done by instantiating a new problem with an IndepVarComp for the time, states, controls, and control rates, as well as an instance of the given ODE class (instantiated with the number of nodes equal to the number of times in the outputs). The system is populated with data from outputs, has a recorder attached, and is executed via problem.run_model. This data can then be retrieved from the `system_cases` attribute of CaseReader. Parameters ---------- traj : Trajectory The Trajectory whose simulated results are to be recorded. exp_outs : dict of {str : PhaseSimulationResults}. A dictionary of {phase_name : PhaseSimulationResults} for each phase to be recorded filename : str The filename to which the recording should be saved. """ # Make sure we have the same keys/phases in both the trajectory and exp_outs if set(traj._phases) != set(exp_outs): raise ValueError( 'TrajectorySimulationResults trajectory._phases and ' 'exp_outs must contain the same keys.') p = Problem(model=Group()) traj_group = p.model.add_subsystem('phases', ParallelGroup()) phase_groups = {} for phase_name, phase in iteritems(traj._phases): ode_class = phase.options['ode_class'] init_kwargs = phase.options['ode_init_kwargs'] exp_out = exp_outs[phase_name] phase_group = traj_group.add_subsystem(phase_name, subsys=Group()) phase_groups[phase_name] = phase_group time = exp_out.get_values('time') nn = len(time) ode_sys = ode_class(num_nodes=nn, **init_kwargs) ivc = phase_group.add_subsystem('inputs', subsys=IndepVarComp(), promotes_outputs=['*']) phase_group.add_subsystem('ode', subsys=ode_sys) # Connect times ivc.add_output('time', val=np.zeros((nn, 1)), units=phase.time_options['units']) phase_group.connect( 'time', ['ode.{0}'.format(t) for t in phase.time_options['targets']]) # Connect states for name, options in iteritems(phase.state_options): ivc.add_output('states:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=options['units']) phase_group.connect( 'states:{0}'.format(name), ['ode.{0}'.format(t) for t in options['targets']]) # Connect controls sys_param_options = ode_sys.ode_options._parameters for name, options in iteritems(phase.control_options): units = options['units'] ivc.add_output('controls:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) phase_group.connect('controls:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[name]['targets'] ], src_indices=np.arange(nn, dtype=int)) rate_units = get_rate_units(units, phase.time_options['units'], deriv=1) ivc.add_output('control_rates:{0}_rate'.format(name), val=np.zeros((nn, ) + options['shape']), units=rate_units) if options['rate_param']: rate_targets = sys_param_options[ options['rate_param']]['targets'] phase_group.connect( 'control_rates:{0}_rate'.format(name), ['ode.{0}'.format(t) for t in rate_targets], src_indices=np.arange(nn, dtype=int)) rate2_units = get_rate_units(units, phase.time_options['units'], deriv=2) ivc.add_output('control_rates:{0}_rate2'.format(name), val=np.zeros((nn, ) + options['shape']), units=rate2_units) if options['rate2_param']: rate2_targets = sys_param_options[ options['rate2_param']]['targets'] phase_group.connect( 'control_rates:{0}_rate2'.format(name), ['ode.{0}'.format(t) for t in rate2_targets], src_indices=np.arange(nn, dtype=int)) # Connect design parameters for name, options in iteritems(phase.design_parameter_options): units = options['units'] ivc.add_output('design_parameters:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) phase_group.connect('design_parameters:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[name]['targets'] ], src_indices=np.arange(nn, dtype=int)) # Connect input parameters for name, options in iteritems(phase.input_parameter_options): units = options['units'] ivc.add_output('input_parameters:{0}'.format(name), val=np.zeros((nn, ) + options['shape']), units=units) phase_group.connect('input_parameters:{0}'.format(name), [ 'ode.{0}'.format(t) for t in sys_param_options[ options['target_param']]['targets'] ], src_indices=np.arange(nn, dtype=int)) p.setup(check=True) p.model.add_recorder(SqliteRecorder(filename)) p.model.recording_options['record_metadata'] = True p.model.recording_options['record_outputs'] = True # Assign values for phase_name, phase in iteritems(traj._phases): exp_out = exp_outs[phase_name] # Assign times p['phases.{0}.time'.format(phase_name)] = exp_out.get_values( 'time') # Assign states for name in phase.state_options: p['phases.{0}.states:{1}'.format( phase_name, name)] = exp_out.get_values(name) # Assign controls for name, options in iteritems(phase.control_options): shape = p['phases.{0}.controls:{1}'.format(phase_name, name)].shape p['phases.{0}.controls:{1}'.format(phase_name, name)] = \ np.reshape(exp_out.get_values(name), shape) p['phases.{0}.control_rates:{1}_rate'.format(phase_name, name)] = \ np.reshape(exp_out.get_values('{0}_rate'.format(name)), shape) p['phases.{0}.control_rates:{1}_rate2'.format(phase_name, name)] = \ np.reshape(exp_out.get_values('{0}_rate2'.format(name)), shape) # Assign design parameters for name, options in iteritems(phase.design_parameter_options): shape = p['phases.{0}.design_parameters:{1}'.format( phase_name, name)].shape p['phases.{0}.design_parameters:{1}'.format(phase_name, name)] = \ np.reshape(exp_out.get_values(name), shape) # Assign input parameters for name, options in iteritems(phase.input_parameter_options): shape = p['phases.{0}.input_parameters:{1}'.format( phase_name, name)].shape p['phases.{0}.input_parameters:{1}'.format(phase_name, name)] = \ np.reshape(exp_out.get_values(name), shape) # Populate outputs of ODE prom2abs_ode_outputs = \ phase_groups[phase_name].ode._var_allprocs_prom2abs_list['output'] for prom_name, abs_name in iteritems(prom2abs_ode_outputs): if p[abs_name[0]].shape[0] == 1: p[abs_name[0]] = exp_out.get_values(prom_name)[0] else: p[abs_name[0]] = np.reshape(exp_out.get_values(prom_name), p[abs_name[0]].shape) # Run model to record file p.run_model()
def _setup_controls(self): control_options = self.options['control_options'] gd = self.options['grid_data'] num_nodes = self.num_nodes num_control_input_nodes = self.options['grid_data'].subset_num_nodes[ 'control_input'] time_units = self.options['time_units'] for name, options in iteritems(control_options): self._input_names[name] = 'controls:{0}'.format(name) self._output_val_names[name] = 'control_values:{0}'.format(name) self._output_rate_names[name] = 'control_rates:{0}_rate'.format( name) self._output_rate2_names[name] = 'control_rates:{0}_rate2'.format( name) shape = options['shape'] input_shape = (num_control_input_nodes, ) + shape output_shape = (num_nodes, ) + shape units = options['units'] rate_units = get_rate_units(units, time_units) rate2_units = get_rate_units(units, time_units, deriv=2) self._dynamic_names.append(name) self.add_input(self._input_names[name], val=np.ones(input_shape), units=units) self.add_output(self._output_val_names[name], shape=output_shape, units=units) self.add_output(self._output_rate_names[name], shape=output_shape, units=rate_units) self.add_output(self._output_rate2_names[name], shape=output_shape, units=rate2_units) size = np.prod(shape) self.val_jacs[name] = np.zeros( (num_nodes, size, num_control_input_nodes, size)) self.rate_jacs[name] = np.zeros( (num_nodes, size, num_control_input_nodes, size)) self.rate2_jacs[name] = np.zeros( (num_nodes, size, num_control_input_nodes, size)) for i in range(size): self.val_jacs[name][:, i, :, i] = self.L self.rate_jacs[name][:, i, :, i] = self.D self.rate2_jacs[name][:, i, :, i] = self.D2 self.val_jacs[name] = self.val_jacs[name].reshape( (num_nodes * size, num_control_input_nodes * size), order='C') self.rate_jacs[name] = self.rate_jacs[name].reshape( (num_nodes * size, num_control_input_nodes * size), order='C') self.rate2_jacs[name] = self.rate2_jacs[name].reshape( (num_nodes * size, num_control_input_nodes * size), order='C') self.val_jac_rows[name], self.val_jac_cols[name] = \ np.where(self.val_jacs[name] != 0) self.rate_jac_rows[name], self.rate_jac_cols[name] = \ np.where(self.rate_jacs[name] != 0) self.rate2_jac_rows[name], self.rate2_jac_cols[name] = \ np.where(self.rate2_jacs[name] != 0) self.sizes[name] = size rs, cs = self.val_jac_rows[name], self.val_jac_cols[name] self.declare_partials(of=self._output_val_names[name], wrt=self._input_names[name], rows=rs, cols=cs, val=self.val_jacs[name][rs, cs]) cs = np.tile(np.arange(num_nodes, dtype=int), reps=size) rs = np.concatenate([ np.arange(0, num_nodes * size, size, dtype=int) + i for i in range(size) ]) self.declare_partials(of=self._output_rate_names[name], wrt='dt_dstau', rows=rs, cols=cs) self.declare_partials(of=self._output_rate_names[name], wrt=self._input_names[name], rows=self.rate_jac_rows[name], cols=self.rate_jac_cols[name]) self.declare_partials(of=self._output_rate2_names[name], wrt='dt_dstau', rows=rs, cols=cs) self.declare_partials(of=self._output_rate2_names[name], wrt=self._input_names[name], rows=self.rate2_jac_rows[name], cols=self.rate2_jac_cols[name])