class PlaneODE2D(Group): ode_options = ODEOptions() ode_options.declare_time(units='s') # dynamic trajectories for i in range(n_traj): ode_options.declare_state( name='p%dx' % i, rate_source='p%d.x_dot' % i, targets=['p%d.x' % i, 'pairwise.x%d' % i, 'space%d.x' % i], units='m') ode_options.declare_state( name='p%dy' % i, rate_source='p%d.y_dot' % i, targets=['p%d.y' % i, 'pairwise.y%d' % i, 'space%d.y' % i], units='m') # ode_options.declare_state(name='p%dmass' % i, rate_source='p%d.mass_dot' % i, # targets=['p%d.mass' % i], units='kg') # ode_options.declare_state(name='p%dimpulse' % i, rate_source='p%d.impulse_dot' % i, # targets=['t_imp.a%d' % i]) ode_options.declare_parameter(name='speed%d' % i, targets='p%d.speed' % i, dynamic=False) ode_options.declare_parameter(name='heading%d' % i, targets='p%d.heading' % i, dynamic=False) ode_options.declare_parameter(name='isp%d' % i, targets='p%d.isp' % i, dynamic=False) def initialize(self): self.options.declare('num_nodes', types=int) self.options.declare('r_space', types=float, default=r_space) self.options.declare('ignored_pairs', types=list, default=[]) def setup(self): nn = self.options['num_nodes'] r_space = self.options['r_space'] pairs = self.options['ignored_pairs'] self.linear_solver = DirectSolver() self.add_subsystem('t_imp', SumComp(num_nodes=nn, num_arrays=n_traj)) for i in range(n_traj): self.add_subsystem(name='p%d' % i, subsys=PlanePath2D(num_nodes=nn)) self.add_subsystem(name='space%d' % i, subsys=Space(num_nodes=nn, r_space=r_space)) self.add_subsystem(name='pairwise', subsys=Pairwise(n_traj=n_traj, ignored_pairs=pairs, num_nodes=nn))
class TankAloneODE(Group): """ Defines the ODE for the fuel circulation problem. Here we define the states and parameters (controls) for the problem. m : mass of the fuel in the tank T : temperature of the fuel in the tank energy : energy required to pump the fuel in the system """ ode_options = ODEOptions() ode_options.declare_time(units='s') ode_options.declare_state('m', units='kg', rate_source='m_dot', targets=['m']) ode_options.declare_state('T', units='K', rate_source='T_dot', targets=['T']) ode_options.declare_state('energy', units='J', rate_source='power') ode_options.declare_parameter('m_flow', targets=['m_flow'], units='kg/s') ode_options.declare_parameter('m_burn', targets=['m_burn'], units='kg/s') ode_options.declare_parameter('Q_env', targets=['Q_env'], units='W') ode_options.declare_parameter('Q_sink', targets=['Q_sink'], units='W') ode_options.declare_parameter('Q_out', targets=['Q_out'], units='W') def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_subsystem(name='cv', subsys=CvComp(num_nodes=nn), promotes_inputs=['T'], promotes_outputs=['Cv']) self.add_subsystem(name='tank', subsys=TankAloneComp(num_nodes=nn), promotes_inputs=['m', 'm_flow', 'm_burn', 'T', 'Q_env', 'Q_sink', 'Q_out', 'Cv'], promotes_outputs=['m_dot', 'T_dot', 'm_recirculated', 'T_o']) self.add_subsystem(name='power', subsys=PowerComp(num_nodes=nn), promotes=['m_flow', 'power']) # Set solvers self.nonlinear_solver = NonlinearBlockGS() self.linear_solver = DirectSolver(assemble_jac=True) self.options['assembled_jac_type'] = 'csc'
class MyODE(Group): ode_options = ODEOptions() ode_options.declare_time(units='s', targets=['comp.time']) ode_options.declare_state(name='F', rate_source='comp.y') ode_options.declare_parameter(name='alpha', shape=(n_traj, 2), targets='comp.alpha', dynamic=False) def initialize(self): self.options.declare('num_nodes', types=int) self.options.declare('n_traj', default=2, types=int) def setup(self): nn = self.options['num_nodes'] n_traj = self.options['n_traj'] self.add_subsystem(name='comp', subsys=MyComp(num_nodes=nn, n_traj=n_traj))
class _CannonballODE(FlightPathEOM2D): ode_options = ODEOptions() ode_options.declare_time(units='s') ode_options.declare_state(name='r', rate_source='r_dot', units='m') ode_options.declare_state(name='h', rate_source='h_dot', units='m') ode_options.declare_state(name='gam', rate_source='gam_dot', targets='gam', units='rad') ode_options.declare_state(name='v', rate_source='v_dot', targets='v', units='m/s') def __init__(self, **kwargs): super(_CannonballODE, self).__init__(**kwargs)
class MinTimeClimbODE(Group): ode_options = ODEOptions() ode_options.declare_time(units='s') ode_options.declare_state('r', units='km', rate_source='flight_dynamics.r_dot') ode_options.declare_state('h', units='m', rate_source='flight_dynamics.h_dot', targets=['h']) ode_options.declare_state('v', units='m/s', rate_source='flight_dynamics.v_dot', targets=['v']) ode_options.declare_state('gam', units='rad', rate_source='flight_dynamics.gam_dot', targets=['gam']) ode_options.declare_state('m', units='kg', rate_source='prop.m_dot', targets=['m']) ode_options.declare_parameter('alpha', targets=['alpha'], units='rad') ode_options.declare_parameter('throttle', targets=['throttle'], units=None) def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_subsystem(name='atmos', subsys=StandardAtmosphereGroup(num_nodes=nn), promotes_inputs=['h']) self.add_subsystem( name='aero', subsys=AeroGroup(num_nodes=nn), promotes_inputs=['v', 'alpha'], ) self.connect('atmos.sos', 'aero.sos') self.connect('atmos.rho', 'aero.rho') self.add_subsystem(name='prop', subsys=PropGroup(num_nodes=nn), promotes_inputs=['h', 'throttle']) self.connect('aero.mach', 'prop.mach') self.add_subsystem(name='flight_dynamics', subsys=FlightPathEOM2D(num_nodes=nn), promotes_inputs=['m', 'v', 'gam', 'alpha']) self.connect('aero.f_drag', 'flight_dynamics.D') self.connect('aero.f_lift', 'flight_dynamics.L') self.connect('prop.thrust', 'flight_dynamics.T')
class SimpleHeatODE(Group): """ Defines the ODE for the fuel circulation problem. Here we define the states and parameters (controls) for the problem. m : mass of the fuel in the tank T : temperature of the fuel in the tank energy : energy required to pump the fuel in the system """ ode_options = ODEOptions() ode_options.declare_time(units='s') ode_options.declare_state('m', units='kg', rate_source='m_dot', targets=['m']) ode_options.declare_state('T', units='K', rate_source='T_dot', targets=['T']) ode_options.declare_state('energy', units='J', rate_source='power') ode_options.declare_parameter('m_flow', targets=['m_flow'], units='kg/s') ode_options.declare_parameter('m_burn', targets=['m_burn'], units='kg/s') def initialize(self): self.options.declare('num_nodes', types=int) self.options.declare('q_tank', types=float) self.options.declare('q_hx1', types=float) self.options.declare('q_hx2', types=float) def setup(self): nn = self.options['num_nodes'] q_tank = self.options['q_tank'] q_hx1 = self.options['q_hx1'] q_hx2 = self.options['q_hx2'] self.add_subsystem(name='tank', subsys=TankComp(num_nodes=nn, q=q_tank), promotes=['m', 'm_flow', 'm_dot', 'T', 'T_dot']) self.add_subsystem(name='heat_exchanger_pre', subsys=HeatExchangerComp(num_nodes=nn, q=q_hx1), promotes=[]) self.add_subsystem(name='fuel_burner', subsys=FuelBurnerComp(num_nodes=nn), promotes=['m_burn']) self.add_subsystem(name='heat_exchanger_post', subsys=HeatExchangerComp(num_nodes=nn, q=q_hx2), promotes=[]) self.add_subsystem(name='power', subsys=PowerComp(num_nodes=nn), promotes=['m_flow', 'power']) # Tank to HX1 self.connect('tank.T_out', 'heat_exchanger_pre.T_in') self.connect('tank.m_out', 'heat_exchanger_pre.m_in') # HX1 to HX2 self.connect('heat_exchanger_pre.T_out', 'heat_exchanger_post.T_in') # HX1 to burner self.connect('tank.m_out', 'fuel_burner.m_in') # Burner to HX2 self.connect('fuel_burner.m_recirculated', 'heat_exchanger_post.m_in') # HX2 to tank self.connect('heat_exchanger_post.T_out', 'tank.T_in') self.connect('fuel_burner.m_recirculated', 'tank.m_in') # Set solvers self.nonlinear_solver = NonlinearBlockGS() self.linear_solver = DirectSolver(assembled_jac=True)
class ThermalMissionODE(Group): ode_options = ODEOptions() ode_options.declare_time(units='s') # Mission and aero ode_options.declare_state('r', units='m', rate_source='flight_dynamics.r_dot') ode_options.declare_state('h', units='m', rate_source='flight_dynamics.h_dot', targets=['h']) ode_options.declare_state('v', units='m/s', rate_source='flight_dynamics.v_dot', targets=['v']) ode_options.declare_state('gam', units='rad', rate_source='flight_dynamics.gam_dot', targets=['gam']) ode_options.declare_state('m', units='kg', rate_source='m_dot', targets=['m']) ode_options.declare_parameter('alpha', targets=['alpha'], units='rad') ode_options.declare_parameter('S', targets=['S'], units='m**2') ode_options.declare_parameter('throttle', targets=['throttle'], units=None) ode_options.declare_parameter('W0', targets=['W0'], units='kg') # Thermal ode_options.declare_state('T', units='K', rate_source='T_dot', targets=['T']) ode_options.declare_state('energy', units='J', rate_source='power') ode_options.declare_parameter('m_recirculated', targets=['m_recirculated'], units='kg/s') ode_options.declare_parameter('Q_env', targets=['Q_env'], units='W') ode_options.declare_parameter('Q_sink', targets=['Q_sink'], units='W') ode_options.declare_parameter('Q_out', targets=['Q_out'], units='W') def initialize(self): self.options.declare('num_nodes', types=int) self.options.declare('engine_heat_coeff', types=float) self.options.declare('pump_heat_coeff', types=float) def setup(self): nn = self.options['num_nodes'] engine_heat_coeff = self.options['engine_heat_coeff'] pump_heat_coeff = self.options['pump_heat_coeff'] # Aero and mission self.add_subsystem(name='atmos', subsys=StandardAtmosphereGroup(num_nodes=nn), promotes_inputs=['h']) # self.add_subsystem(name='aero', # subsys=AeroGroup(num_nodes=nn), # promotes_inputs=['v', 'alpha', 'S']) self.add_subsystem(name='aero', subsys=AeroSMTGroup(num_nodes=nn), promotes_inputs=['v', 'alpha', 'S', 'h']) self.connect('atmos.sos', 'aero.sos') self.connect('atmos.rho', 'aero.rho') self.add_subsystem(name='prop', subsys=PropGroup(num_nodes=nn), promotes_inputs=['h', 'throttle'], promotes_outputs=['m_dot']) self.connect('aero.mach', 'prop.mach') self.add_subsystem(name='flight_dynamics', subsys=FlightPathEOM2D(num_nodes=nn), promotes_inputs=['m', 'v', 'gam', 'alpha']) self.connect('aero.f_drag', 'flight_dynamics.D') self.connect('aero.f_lift', 'flight_dynamics.L') self.connect('prop.thrust', 'flight_dynamics.T') # Thermal self.add_subsystem( 'm_burn_comp', ExecComp('m_burn = - m_dot', m_burn=np.zeros(nn), m_dot=np.zeros(nn)), promotes=['*'], ) self.add_subsystem( 'm_fuel_comp', ExecComp('m_fuel = m - W0', m_fuel=np.zeros(nn), m=np.zeros(nn), W0=np.zeros(nn)), promotes=['*'], ) self.add_subsystem( 'm_flow_comp', ExecComp('m_flow = m_burn + m_recirculated', m_flow=np.zeros(nn), m_burn=np.zeros(nn), m_recirculated=np.zeros(nn)), promotes=['*'], ) self.add_subsystem(name='pump_heating_comp', subsys=PumpHeatingComp(num_nodes=nn, heat_coeff=pump_heat_coeff), promotes_inputs=['m_flow'], promotes_outputs=['Q_pump']) self.add_subsystem(name='engine_heating_comp', subsys=EngineHeatingComp( num_nodes=nn, heat_coeff=engine_heat_coeff), promotes_inputs=['throttle'], promotes_outputs=['Q_engine']) self.add_subsystem( 'Q_env_tot_comp', ExecComp('Q_env_tot = Q_env + Q_pump + Q_engine', Q_env_tot=np.zeros(nn), Q_env=np.zeros(nn), Q_pump=np.zeros(nn), Q_engine=np.zeros(nn)), promotes=['*'], ) self.add_subsystem(name='cv', subsys=CvComp(num_nodes=nn), promotes_inputs=['T'], promotes_outputs=['Cv']) self.add_subsystem(name='tank', subsys=TankMissionComp(num_nodes=nn), promotes_inputs=[ 'm_fuel', 'm_flow', 'm_burn', 'T', 'Q_env_tot', 'Q_sink', 'Q_out', 'Cv' ], promotes_outputs=['T_dot', 'T_o']) self.add_subsystem(name='power', subsys=PowerComp(num_nodes=nn), promotes=['m_flow', 'power']) # Set solvers self.linear_solver = DirectSolver(assemble_jac=True) self.options['assembled_jac_type'] = 'csc'
class PlaneODE2D(Group): ode_options = ODEOptions() ode_options.declare_time( units='s', targets=['keepout%d.time' % i for i in range(n_traj)] + ['schedule%d.time' % i for i in range(n_traj)]) targets = {} for i in range(n_traj): targets[i] = { 'x': ['keepout%d.x' % i, 'schedule%d.x' % i], 'y': ['keepout%d.y' % i, 'schedule%d.y' % i] } for i, j in combinations([i for i in range(n_traj)], 2): targets[i]['x'].append('distance_%d_%d.x1' % (i, j)) targets[i]['y'].append('distance_%d_%d.y1' % (i, j)) targets[j]['x'].append('distance_%d_%d.x2' % (i, j)) targets[j]['y'].append('distance_%d_%d.y2' % (i, j)) # dynamic trajectories for i in range(n_traj): ode_options.declare_state(name='x%d' % i, rate_source='flight_path%d.x_dot' % i, targets=targets[i]['x'], units='m') ode_options.declare_state(name='y%d' % i, rate_source='flight_path%d.y_dot' % i, targets=targets[i]['y'], units='m') #ode_options.declare_state(name='L%d' % i, rate_source='flight_path%d.L_dot' % i, units='m') ode_options.declare_parameter(name='vx%d' % i, targets='flight_path%d.vx' % i, units='m/s') ode_options.declare_parameter(name='vy%d' % i, targets='flight_path%d.vy' % i, units='m/s') ode_options.declare_parameter(name='sx%d' % i, targets='schedule%d.x_start' % i, units='m') ode_options.declare_parameter(name='sy%d' % i, targets='schedule%d.y_start' % i, units='m') ode_options.declare_parameter(name='ex%d' % i, targets='schedule%d.x_end' % i, units='m') ode_options.declare_parameter(name='ey%d' % i, targets='schedule%d.y_end' % i, units='m') ode_options.declare_parameter(name='ts%d' % i, targets='schedule%d.t_departure' % i, units='s') ode_options.declare_parameter(name='te%d' % i, targets='schedule%d.t_arrival' % i, units='s') def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_subsystem('vtotals', subsys=VSum(n_traj=n_traj)) for i in range(n_traj): self.add_subsystem(name='flight_path%d' % i, subsys=FlightPathEOM2D(num_nodes=nn)) self.connect('flight_path%d.vt' % i, 'vtotals.v%d' % i) self.add_subsystem(name='schedule%d' % i, subsys=Schedule(num_nodes=nn)) self.add_subsystem('keepout%d' % i, subsys=KeepOut(num_nodes=nn, x_loc=x_loc, y_loc=y_loc, ts=ks_start)) traj = [i for i in range(n_traj)] for i, j in combinations(traj, 2): self.add_subsystem('distance_%d_%d' % (i, j), subsys=Distance(num_nodes=nn))