def test(self): """ A simple example to compute inertial forces on four projectiles at a number of analysis points (F_inertial = - m*a) """ import numpy as np #from openmdao.api import Problem, Group, IndepVarComp from openconcept.utilities.math.multiply_divide_comp import ElementMultiplyDivideComp from openmdao.utils.assert_utils import assert_near_equal n = 5 length = 4 p = Problem(model=Group()) ivc = IndepVarComp() #the vector represents forces at 3 analysis points (rows) in 2 dimensional plane (cols) ivc.add_output(name='mass', shape=(n, length), units='kg') ivc.add_output(name='acceleration', shape=(n, length), units='m / s**2') p.model.add_subsystem(name='ivc', subsys=ivc, promotes_outputs=['mass', 'acceleration']) #construct an multi/subtracter here. create a relationship through the add_equation method multi = ElementMultiplyDivideComp() multi.add_equation('inertial_force', input_names=['mass', 'acceleration'], vec_size=n, length=length, input_units=['kg', 'm / s**2'], scaling_factor=-1) #note the scaling factors. we assume all forces are positive sign upstream p.model.add_subsystem(name='inertialforcecomp', subsys=multi, promotes_inputs=['*']) p.setup() #set thrust to exceed drag, weight to equal lift for this scenario p['mass'] = np.ones((n, length)) * 500 p['acceleration'] = np.random.rand(n, length) p.run_model() # print(p.get_val('totalforcecomp.total_force', units='kN')) # Verify the results expected_i = -p['mass'] * p['acceleration'] / 1000 assert_near_equal( p.get_val('inertialforcecomp.inertial_force', units='kN'), expected_i)
def setup(self): nn = self.options['num_nodes'] # Scale the heat transfer by the number of pipes # Used ExecComp here because multiplying vector and scalar inputs self.add_subsystem('heat_divide', ExecComp('q_div = q / n_pipes', q_div={ 'units': 'W', 'shape': (nn, ) }, q={ 'units': 'W', 'shape': (nn, ) }), promotes_inputs=['q', 'n_pipes']) # Maximum heat transfer and weight self.add_subsystem( 'q_max_calc', QMaxHeatPipe( num_nodes=nn, theta=self.options['theta'], yield_stress=self.options['yield_stress'], rho_wall=self.options['rho_wall'], stress_safety_factor=self.options['stress_safety_factor']), # Assume temp in heat pipe is close to evaporator temp promotes_inputs=[ 'inner_diam', 'length', ('design_temp', 'T_design'), ('temp', 'T_evap') ]) # Multiply max heat transfer and weight by number of pipes multiply = ElementMultiplyDivideComp() multiply.add_equation(output_name='weight', input_names=['single_pipe_weight', 'n_pipes'], input_units=['kg', None]) self.add_subsystem('weight_multiplier', multiply, promotes_inputs=['n_pipes'], promotes_outputs=['weight']) self.connect('q_max_calc.heat_pipe_weight', 'weight_multiplier.single_pipe_weight') # Used ExecComp here because multiplying vector and scalar inputs self.add_subsystem('q_max_multiplier', ExecComp('q_max = single_pipe_q_max * n_pipes', q_max={ 'units': 'W', 'shape': (nn, ) }, single_pipe_q_max={ 'units': 'W', 'shape': (nn, ) }), promotes_inputs=['n_pipes'], promotes_outputs=['q_max']) self.connect('q_max_calc.q_max', 'q_max_multiplier.single_pipe_q_max') # Thermal resistance at current operator condition self.add_subsystem( 'ammonia_surrogate', AmmoniaProperties(num_nodes=nn), # Assume temp in heat pipe is close to evaporator temp promotes_inputs=[('temp', 'T_evap')]) self.add_subsystem( 'delta_T_calc', HeatPipeVaporTempDrop(num_nodes=nn), # Assume temp in heat pipe is close to evaporator temp promotes_inputs=[('temp', 'T_evap'), 'inner_diam', 'length']) self.add_subsystem('resistance', HeatPipeThermalResistance( num_nodes=nn, length_evap=self.options['length_evap'], length_cond=self.options['length_cond'], wall_conduct=self.options['wall_conduct'], wick_thickness=self.options['wick_thickness'], wick_conduct=self.options['wick_conduct'], vapor_resistance=True), promotes_inputs=['inner_diam']) self.connect('ammonia_surrogate.rho_vapor', 'delta_T_calc.rho_vapor') self.connect('ammonia_surrogate.vapor_pressure', 'delta_T_calc.vapor_pressure') self.connect('delta_T_calc.delta_T', 'resistance.delta_T') self.connect('q_max_calc.wall_thickness', 'resistance.wall_thickness' ) # use wall thickness from hoop stress calc # Compute condenser temperature self.add_subsystem('cond_temp_calc', ExecComp('T_cond = T_evap - q*R', T_cond={ 'units': 'degC', 'shape': (nn, ) }, T_evap={ 'units': 'degC', 'shape': (nn, ) }, q={ 'units': 'W', 'shape': (nn, ) }, R={ 'units': 'K/W', 'shape': (nn, ) }), promotes_inputs=['T_evap'], promotes_outputs=['T_cond']) self.connect('heat_divide.q_div', ['delta_T_calc.q', 'resistance.q', 'cond_temp_calc.q']) self.connect('resistance.thermal_resistance', 'cond_temp_calc.R') # Warn the user if heat transfer exceeds maximum possible self.add_subsystem('q_max_warning', QMaxWarning(num_nodes=nn, q_max_warn=self.options['q_max_warn']), promotes_inputs=['q', 'q_max'])