def test_specified_shape(self): shape = (3, 2, 4) prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp() bal.add_balance('x', val=np.ones(shape), use_mult=True) tgt = om.IndepVarComp(name='y_tgt', val=4 * np.ones(shape)) mult_ivc = om.IndepVarComp(name='mult', val=2.0 * np.ones(shape)) exec_comp = om.ExecComp('y=x**2', x={'value': np.ones(shape)}, y={'value': np.ones(shape)}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='mult_comp', subsys=mult_ivc, promotes_outputs=['mult']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('mult', 'balance.mult:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(maxiter=100, iprint=0) prob.setup() prob['balance.x'] = np.random.random(shape) prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def test_vectorized_with_mult(self): n = 100 prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp() bal.add_balance('x', val=np.ones(n), use_mult=True) tgt = om.IndepVarComp(name='y_tgt', val=4 * np.ones(n)) mult_ivc = om.IndepVarComp(name='mult', val=2.0 * np.ones(n)) exec_comp = om.ExecComp('y=x**2', x={'val': np.ones(n)}, y={'val': np.ones(n)}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='mult_comp', subsys=mult_ivc, promotes_outputs=['mult']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('mult', 'balance.mult:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob['balance.x'] = np.random.rand(n) prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7) cpd = prob.check_partials(out_stream=None) assert_check_partials(cpd, atol=1e-5, rtol=1e-5)
def setup(self): thermo_data = self.options['thermo_data'] elements = self.options['elements'] self.add_subsystem('ambient', Ambient(), promotes=('alt', 'dTs')) # inputs conv = self.add_subsystem('conv', om.Group(), promotes=['*']) conv.add_subsystem('fs', FlowStart(thermo_data=thermo_data, elements=elements), promotes=['Fl_O:*', 'MN', 'W']) balance = conv.add_subsystem('balance', om.BalanceComp()) balance.add_balance('Tt', val=500.0, lower=1e-4, units='degR', desc='Total temperature', eq_units='degR') balance.add_balance('Pt', val=14.696, lower=1e-4, units='psi', desc='Total pressure', eq_units='psi') # sub.set_order(['fs','balance']) newton = conv.nonlinear_solver = om.NewtonSolver() newton.options['atol'] = 1e-10 newton.options['rtol'] = 1e-10 newton.options['maxiter'] = 10 newton.options['iprint'] = -1 newton.options['solve_subsystems'] = True newton.options['reraise_child_analysiserror'] = False newton.linesearch = om.BoundsEnforceLS() newton.linesearch.options['bound_enforcement'] = 'scalar' newton.linesearch.options['iprint'] = -1 # newton.linesearch.options['solve_subsystems'] = True conv.linear_solver = om.DirectSolver(assemble_jac=True) self.connect('ambient.Ps', 'balance.rhs:Pt') self.connect('ambient.Ts', 'balance.rhs:Tt') self.connect('balance.Pt', 'fs.P') self.connect('balance.Tt', 'fs.T') self.connect('Fl_O:stat:P', 'balance.lhs:Pt') self.connect('Fl_O:stat:T', 'balance.lhs:Tt')
def test_vectorized_with_default_mult(self): """ solve: 2 * x**2 = 4 expected solution: x=sqrt(2) """ n = 100 prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp('x', val=np.ones(n), use_mult=True, mult_val=2.0) tgt = om.IndepVarComp(name='y_tgt', val=4 * np.ones(n)) exec_comp = om.ExecComp('y=x**2', x={'value': np.ones(n)}, y={'value': np.ones(n)}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob['balance.x'] = np.random.rand(n) prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def test_multidimentional_shape_normalize(self): prob = om.Problem() bal = om.BalanceComp() bal.add_balance('x', use_mult=True, shape=(5, 3), normalize=True) bal.add_balance('z', val=4 * np.ones(5, ), shape=(5, ), normalize=True) exec_comp = om.ExecComp('y=x**2', x={ 'val': np.ones((5, 3)), 'shape': (5, 3) }, y={ 'val': np.ones((5, 3)), 'shape': (5, 3) }) exec_comp2 = om.ExecComp('y=x**2', x={ 'val': np.ones((5, )), 'shape': (5, ) }, y={ 'val': np.ones((5, )), 'shape': (5, ) }) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='exec2', subsys=exec_comp2) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.connect('balance.z', 'exec2.x') prob.model.connect('exec2.y', 'balance.rhs:z') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob.set_val('balance.rhs:x', np.ones((5, 3))) prob.set_val('balance.mult:x', np.ones((5, 3))) prob['balance.x'] = 1.0 prob.run_model()
def test_scalar_example(self): prob = om.Problem() bal = om.BalanceComp() bal.add_balance('x', val=1.0) tgt = om.IndepVarComp(name='y_tgt', val=2) exec_comp = om.ExecComp('y=x**2') prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') # do one test in an unconverged state, to capture accuracy of partials prob.setup() prob[ 'y_tgt'] = 100000 #set rhs and lhs to very different values. Trying to capture some derivatives wrt prob['exec.y'] = .001 prob.run_model() cpd = prob.check_partials(out_stream=None) assert_check_partials(cpd, atol=2e-5, rtol=2e-5) # set an actual solver, and re-setup. Then check derivatives at a converged point prob.model.linear_solver = om.DirectSolver() prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False) prob.setup() prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7) cpd = prob.check_partials(out_stream=None) assert_check_partials(cpd, atol=1e-5, rtol=1e-5)
def test_scalar_with_guess_func(self): n = 1 model = om.Group(assembled_jac_type='dense') def guess_function(inputs, outputs, residuals): outputs['x'] = np.sqrt(inputs['rhs:x']) bal = om.BalanceComp( 'x', guess_func=guess_function) # test guess_func as kwarg tgt = om.IndepVarComp(name='y_tgt', val=4) exec_comp = om.ExecComp('y=x**2', x={'value': 1}, y={'value': 1}) model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) model.add_subsystem(name='exec', subsys=exec_comp) model.add_subsystem(name='balance', subsys=bal) model.connect('y_tgt', 'balance.rhs:x') model.connect('balance.x', 'exec.x') model.connect('exec.y', 'balance.lhs:x') model.linear_solver = om.DirectSolver(assemble_jac=True) model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob = om.Problem(model) prob.setup() prob['balance.x'] = np.random.rand(n) prob.run_model() assert_almost_equal(prob['balance.x'], 2.0, decimal=7) # should converge with no iteration due to the guess function self.assertEqual(model.nonlinear_solver._iter_count, 1) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def setup(self): nn = self.options['num_nodes'] quasi_steady = self.options['quasi_steady'] self.add_subsystem( 'hex', BandolierCoolingSystem( num_nodes=nn, coolant_specific_heat=self.options['coolant_specific_heat'], fluid_k=self.options['fluid_k'], nusselt=self.options['nusselt'], cell_kr=self.options['cell_kr'], cell_diameter=self.options['cell_diameter'], cell_height=self.options['cell_height'], cell_mass=self.options['cell_mass'], cell_specific_heat=self.options['cell_specific_heat'], battery_weight_fraction=self.options['battery_weight_fraction'] ), promotes_inputs=[ 'q_in', 'mdot_coolant', 'T_in', ('T_battery', 'T'), 'battery_weight', 'n_cpb', 't_channel' ], promotes_outputs=['T_core', 'T_surface', 'T_out', 'dTdt']) if not quasi_steady: ode_integ = self.add_subsystem('ode_integ', Integrator(num_nodes=nn, diff_units='s', method='simpson', time_setup='duration'), promotes_outputs=['*'], promotes_inputs=['*']) ode_integ.add_integrand('T', rate_name='dTdt', units='K', lower=1e-10) else: self.add_subsystem('thermal_bal', om.BalanceComp('T', eq_units='K/s', lhs_name='dTdt', rhs_val=0.0, units='K', lower=1.0, val=299. * np.ones((nn, ))), promotes_inputs=['dTdt'], promotes_outputs=['T'])
def test_raise_error_on_singular_with_densejac(self): prob = om.Problem() model = prob.model comp = om.IndepVarComp() comp.add_output('dXdt:TAS', val=1.0) comp.add_output('accel_target', val=2.0) model.add_subsystem('des_vars', comp, promotes=['*']) teg = model.add_subsystem('thrust_equilibrium_group', subsys=om.Group()) teg.add_subsystem('dynamics', om.ExecComp('z = 2.0*thrust'), promotes=['*']) thrust_bal = om.BalanceComp() thrust_bal.add_balance(name='thrust', val=1207.1, lhs_name='dXdt:TAS', rhs_name='accel_target', eq_units='m/s**2', lower=-10.0, upper=10000.0) teg.add_subsystem(name='thrust_bal', subsys=thrust_bal, promotes_inputs=['dXdt:TAS', 'accel_target'], promotes_outputs=['thrust']) teg.linear_solver = om.DirectSolver(assemble_jac=True) teg.options['assembled_jac_type'] = 'dense' teg.nonlinear_solver = om.NewtonSolver() teg.nonlinear_solver.options['solve_subsystems'] = True teg.nonlinear_solver.options['max_sub_solves'] = 1 teg.nonlinear_solver.options['atol'] = 1e-4 prob.setup() prob.set_solver_print(level=0) with self.assertRaises(RuntimeError) as cm: prob.run_model() expected_msg = "Singular entry found in 'thrust_equilibrium_group' for column associated with state/residual 'thrust'." self.assertEqual(expected_msg, str(cm.exception))
def test_scalar(self): n = 1 prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp() bal.add_balance('x') tgt = om.IndepVarComp(name='y_tgt', val=4) exec_comp = om.ExecComp('y=x**2', x={'value': 1}, y={'value': 1}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob['balance.x'] = np.random.rand(n) prob.run_model() assert_almost_equal(prob['balance.x'], 2.0, decimal=7) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def setup(self): nn = self.options['num_nodes'] self.add_subsystem('aero', subsys=AerodynamicsGroup(num_nodes=nn), promotes_inputs=['alt']) self.add_subsystem('thrust_eq_comp', subsys=ThrustEquilibriumComp(num_nodes=nn), promotes_inputs=['q', 'S', 'gam', 'alpha', 'W_total'], promotes_outputs=['CT']) self.add_subsystem('lift_eq_comp', subsys=LiftEquilibriumComp(num_nodes=nn), promotes_inputs=['q', 'S', 'gam', 'alpha', 'W_total', 'CT'], promotes_outputs=['CL_eq']) bal = self.add_subsystem(name='alpha_eta_balance', subsys=om.BalanceComp(), promotes_outputs=['alpha', 'eta']) self.connect('alpha', ('aero.alpha')) self.connect('eta', ('aero.eta')) bal.add_balance('alpha', units='rad', eq_units=None, lhs_name='CL_eq', rhs_name='CL', val=0.01*np.ones(nn), lower=-20, upper=30, res_ref=1.0) bal.add_balance('eta', units='rad', val=0.01*np.ones(nn), eq_units=None, lhs_name='CM', lower=-30, upper=30, res_ref=1.0) self.connect('aero.CL', 'alpha_eta_balance.CL') self.connect('aero.CD', 'thrust_eq_comp.CD') self.connect('aero.CM', 'alpha_eta_balance.CM') self.connect('CL_eq', ('alpha_eta_balance.CL_eq')) self.linear_solver = om.DirectSolver() self.nonlinear_solver = om.NewtonSolver() self.nonlinear_solver.options['atol'] = 1e-14 self.nonlinear_solver.options['rtol'] = 1e-14 self.nonlinear_solver.options['solve_subsystems'] = True self.nonlinear_solver.options['err_on_non_converge'] = True self.nonlinear_solver.options['max_sub_solves'] = 10 self.nonlinear_solver.options['maxiter'] = 150 self.nonlinear_solver.options['iprint'] = -1 self.nonlinear_solver.linesearch = om.BoundsEnforceLS() self.nonlinear_solver.linesearch.options['print_bound_enforce'] = True
def set_equal(self, lhs_var, rhs_var, solvefor, solveforval=1.): lhname, lhseq = find_output_eq(self.eqs, lhs_var) rhname, rhseq = find_output_eq(self.eqs, rhs_var) model = self.prob.model #eq = EqComp(solvefor=solvefor, lhseq=lhseq, rhseq=rhseq) equality_name = 'h_{}_{}_{}'.format(solvefor, lhs_var, rhs_var) bal = om.BalanceComp(solvefor, val=solveforval, rhs_val=solveforval, lhs_name=lhs_var, rhs_name=rhs_var) self.eqgroup.add_subsystem(name=equality_name, subsys=bal) #for inp_eq_name,eq in find_input_eqs(self.eqs, solvefor): model.connect('{}.{}'.format(equality_name, solvefor), '{}'.format(solvefor)) model.connect('{}'.format(lhs_var), '{}.{}'.format(equality_name, lhs_var)) model.connect('{}'.format(rhs_var), '{}.{}'.format(equality_name, rhs_var))
def test_complex_step(self): n = 1 prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp() bal.add_balance('x') tgt = om.IndepVarComp(name='y_tgt', val=4) exec_comp = om.ExecComp('y=x**2', x={'value': 1}, y={'value': 1}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(maxiter=100, iprint=0) prob.setup(force_alloc_complex=True) prob['balance.x'] = np.random.rand(n) prob.run_model() with warnings.catch_warnings(): warnings.filterwarnings(action="error", category=np.ComplexWarning) cpd = prob.check_partials(out_stream=None, method='cs') for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=10)
def test_feature_scalar(self): from numpy.testing import assert_almost_equal import openmdao.api as om prob = om.Problem() bal = om.BalanceComp() bal.add_balance('x', use_mult=True) tgt = om.IndepVarComp(name='y_tgt', val=4) mult_ivc = om.IndepVarComp(name='mult', val=2.0) exec_comp = om.ExecComp('y=x**2', x={'value': 1}, y={'value': 1}) prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='mult_comp', subsys=mult_ivc, promotes_outputs=['mult']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('mult', 'balance.mult:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() # A reasonable initial guess to find the positive root. prob['balance.x'] = 1.0 prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7)
def test_feature_vector(self): import numpy as np from numpy.testing import assert_almost_equal import openmdao.api as om n = 100 prob = om.Problem() exec_comp = om.ExecComp( 'y=b*x+c', b={'value': np.random.uniform(0.01, 100, size=n)}, c={'value': np.random.rand(n)}, x={'value': np.zeros(n)}, y={'value': np.ones(n)}) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=om.BalanceComp('x', val=np.ones(n))) prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob.set_val('balance.x', np.random.rand(n)) prob.run_model() b = prob.get_val('exec.b') c = prob.get_val('exec.c') assert_almost_equal(prob.get_val('balance.x'), -c / b, decimal=6) assert_almost_equal(-c / b, prob.get_val('balance.x'), decimal=6) # expected
def test_raise_no_error_on_singular(self): prob = om.Problem() model = prob.model comp = om.IndepVarComp() comp.add_output('dXdt:TAS', val=1.0) comp.add_output('accel_target', val=2.0) model.add_subsystem('des_vars', comp, promotes=['*']) teg = model.add_subsystem('thrust_equilibrium_group', subsys=om.Group()) teg.add_subsystem('dynamics', om.ExecComp('z = 2.0*thrust'), promotes=['*']) thrust_bal = om.BalanceComp() thrust_bal.add_balance(name='thrust', val=1207.1, lhs_name='dXdt:TAS', rhs_name='accel_target', eq_units='m/s**2', lower=-10.0, upper=10000.0) teg.add_subsystem(name='thrust_bal', subsys=thrust_bal, promotes_inputs=['dXdt:TAS', 'accel_target'], promotes_outputs=['thrust']) teg.linear_solver = om.DirectSolver(assemble_jac=False) teg.nonlinear_solver = om.NewtonSolver() teg.nonlinear_solver.options['solve_subsystems'] = True teg.nonlinear_solver.options['max_sub_solves'] = 1 teg.nonlinear_solver.options['atol'] = 1e-4 prob.setup() prob.set_solver_print(level=0) teg.linear_solver.options['err_on_singular'] = False prob.run_model()
def test_feature_stall_detection_broyden(self): prob = om.Problem() prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*']) balance = prob.model.add_subsystem('balance', om.BalanceComp(), promotes=['*']) balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y') nl_solver = prob.model.nonlinear_solver = om.BroydenSolver() nl_solver.options['stall_limit'] = 3 nl_solver.options['stall_tol'] = 1e-8 nl_solver.options['maxiter'] = 100 prob.model.linear_solver = om.DirectSolver() prob.setup() prob.set_solver_print() prob.run_model()
def test_create_on_init_no_normalization(self): prob = om.Problem() bal = om.BalanceComp('x', val=1.0, normalize=False) tgt = om.IndepVarComp(name='y_tgt', val=1.5) exec_comp = om.ExecComp('y=x**2') prob.model.add_subsystem(name='target', subsys=tgt, promotes_outputs=['y_tgt']) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('y_tgt', 'balance.rhs:x') prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver() prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, iprint=0) prob.setup() prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(1.5), decimal=7) assert_almost_equal(prob.model.balance._scale_factor, 1.0) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def setup(self): nn = self.options['num_nodes'] quasi_steady = self.options['quasi_steady'] self.add_subsystem( 'hex', MotorCoolingJacket( num_nodes=nn, coolant_specific_heat=self.options['coolant_specific_heat'], motor_specific_heat=self.options['motor_specific_heat'], case_cooling_coefficient=self. options['case_cooling_coefficient']), promotes_inputs=[ 'q_in', 'T_in', 'T', 'power_rating', 'mdot_coolant', 'motor_weight' ], promotes_outputs=['T_out', 'dTdt']) if not quasi_steady: ode_integ = self.add_subsystem('ode_integ', Integrator(num_nodes=nn, diff_units='s', method='simpson', time_setup='duration'), promotes_outputs=['*'], promotes_inputs=['*']) ode_integ.add_integrand('T', rate_name='dTdt', units='K', lower=1e-10) else: self.add_subsystem('thermal_bal', om.BalanceComp('T', eq_units='K/s', lhs_name='dTdt', rhs_val=0.0, units='K', lower=1.0, val=299. * np.ones((nn, ))), promotes_inputs=['dTdt'], promotes_outputs=['T'])
def test_rhs_val(self): """ Test solution with a default RHS value and no connected RHS variable. """ n = 1 prob = om.Problem(model=om.Group(assembled_jac_type='dense')) bal = om.BalanceComp('x', rhs_val=4.0) exec_comp = om.ExecComp('y=x**2', x={'value': 1}, y={'value': 1}) prob.model.add_subsystem(name='exec', subsys=exec_comp) prob.model.add_subsystem(name='balance', subsys=bal) prob.model.connect('balance.x', 'exec.x') prob.model.connect('exec.y', 'balance.lhs:x') prob.model.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) prob.setup() prob['balance.x'] = np.random.rand(n) prob.run_model() assert_almost_equal(prob['balance.x'], 2.0, decimal=7) cpd = prob.check_partials(out_stream=None) for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def test_nonlinear_solver_bounds_stall_warning(self): prob = om.Problem() prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*']) balance = prob.model.add_subsystem('balance', om.BalanceComp(), promotes=['*']) balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y') newton = prob.model.nonlinear_solver = om.NewtonSolver() newton.options['solve_subsystems'] = True newton.options['stall_limit'] = 5 newton.options['stall_tol'] = 1e-8 newton.options['maxiter'] = 100 newton.options['err_on_non_converge'] = False prob.model.linear_solver = om.DirectSolver() prob.setup() msg = ( f"Your model has stalled three times and may be violating the bounds. " f"In the future, turn on print_bound_enforce in your solver options " f"here: \nnonlinear_solver.linesearch.options" f"['print_bound_enforce']=True. " f"\nThe bound(s) being violated now are:\n") with assert_warning(UserWarning, msg): prob.run_model() newton.linesearch.options['print_bound_enforce'] = True prob.setup() with assert_no_warning(UserWarning, msg): prob.run_model()
def test_feature_stall_detection_newton(self): import openmdao.api as om prob = om.Problem() prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*']) balance = prob.model.add_subsystem('balance', om.BalanceComp(), promotes=['*']) balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y') newton = prob.model.nonlinear_solver = om.NewtonSolver() newton.options['solve_subsystems'] = True newton.options['stall_limit'] = 3 newton.options['stall_tol'] = 1e-8 newton.options['maxiter'] = 100 prob.model.linear_solver = om.DirectSolver() prob.setup() prob.set_solver_print() prob.run_model()
def test_balance_comp_record_options(self): prob = om.Problem() bal = om.BalanceComp() bal.add_balance('x', val=1.0) prob.model.add_subsystem(name='balance', subsys=bal) recorder = om.SqliteRecorder('cases.sql') prob.model.add_recorder(recorder) prob.model.recording_options['record_inputs'] = True prob.model.recording_options['record_outputs'] = True prob.model.recording_options['record_residuals'] = True prob.setup() # there should be no warnings wrt unpicklable 'guess_func' option, # since 'recordable' has been set to False with assert_no_warning(UserWarning): prob.run_model()
def test_nonlinear_solver_stall_detection(self): prob = om.Problem() prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*']) balance = prob.model.add_subsystem('balance', om.BalanceComp(), promotes=['*']) balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y') newton = prob.model.nonlinear_solver = om.NewtonSolver() newton.options['solve_subsystems'] = True newton.options['stall_limit'] = 3 newton.options['stall_tol'] = 1e-8 newton.options['maxiter'] = 100 newton.options['err_on_non_converge'] = True prob.model.linear_solver = om.DirectSolver() prob.setup() with self.assertRaises(om.AnalysisError) as context: prob.run_model() msg = "Solver 'NL: Newton' on system '' stalled after 4 iterations." self.assertEqual(str(context.exception), msg)
def setup(self): design = self.options['design'] thermo_data = self.options['thermo_data'] flow1_elements = self.options['Fl_I1_elements'] flow1_thermo = Thermo(thermo_data, init_reacts=flow1_elements) n_flow1_prods = len(flow1_thermo.products) in_flow = FlowIn(fl_name='Fl_I1', num_prods=n_flow1_prods) self.add_subsystem('in_flow1', in_flow, promotes=['Fl_I1:*']) flow2_elements = self.options['Fl_I2_elements'] flow2_thermo = Thermo(thermo_data, init_reacts=flow2_elements) n_flow2_prods = len(flow2_thermo.products) in_flow = FlowIn(fl_name='Fl_I2', num_prods=n_flow2_prods) self.add_subsystem('in_flow2', in_flow, promotes=['Fl_I2:*']) if design: # internal flow station to compute the area that is needed to match the static pressures if self.options['designed_stream'] == 1: Fl1_stat = SetStatic(mode="Ps", thermo_data=thermo_data, init_reacts=flow1_elements, fl_name="Fl_I1_calc:stat") self.add_subsystem('Fl_I1_stat_calc', Fl1_stat, promotes_inputs=[('init_prod_amounts', 'Fl_I1:stat:n'), ('S', 'Fl_I1:tot:S'), ('ht', 'Fl_I1:tot:h'), ('W', 'Fl_I1:stat:W'), ('Ps', 'Fl_I2:stat:P')], promotes_outputs=['Fl_I1_calc:stat*']) self.add_subsystem('area_calc', AreaSum(), promotes_inputs=['Fl_I2:stat:area'], promotes_outputs=[('area_sum', 'area')]) self.connect('Fl_I1_calc:stat:area', 'area_calc.Fl_I1:stat:area') else: Fl2_stat = SetStatic(mode="Ps", thermo_data=thermo_data, init_reacts=flow2_elements, fl_name="Fl_I2_calc:stat") self.add_subsystem('Fl_I2_stat_calc', Fl2_stat, promotes_inputs=[('init_prod_amounts', 'Fl_I2:tot:n'), ('S', 'Fl_I2:tot:S'), ('ht', 'Fl_I2:tot:h'), ('W', 'Fl_I2:stat:W'), ('Ps', 'Fl_I1:stat:P')], promotes_outputs=['Fl_I2_calc:stat:*']) self.add_subsystem('area_calc', AreaSum(), promotes_inputs=['Fl_I1:stat:area'], promotes_outputs=[('area_sum', 'area')]) self.connect('Fl_I2_calc:stat:area', 'area_calc.Fl_I2:stat:area') else: if self.options['designed_stream'] == 1: Fl1_stat = SetStatic(mode="area", thermo_data=thermo_data, init_reacts=flow1_elements, fl_name="Fl_I1_calc:stat") self.add_subsystem('Fl_I1_stat_calc', Fl1_stat, promotes_inputs=[('init_prod_amounts', 'Fl_I1:tot:n'), ('S', 'Fl_I1:tot:S'), ('ht', 'Fl_I1:tot:h'), ('W', 'Fl_I1:stat:W'), ('guess:Pt', 'Fl_I1:tot:P'), ('guess:gamt', 'Fl_I1:tot:gamma')], promotes_outputs=['Fl_I1_calc:stat*']) else: Fl2_stat = SetStatic(mode="area", thermo_data=thermo_data, init_reacts=flow2_elements, fl_name="Fl_I2_calc:stat") self.add_subsystem('Fl_I2_stat_calc', Fl2_stat, promotes_inputs=[('init_prod_amounts', 'Fl_I2:tot:n'), ('S', 'Fl_I2:tot:S'), ('ht', 'Fl_I2:tot:h'), ('W', 'Fl_I2:stat:W'), ('guess:Pt', 'Fl_I2:tot:P'), ('guess:gamt', 'Fl_I2:tot:gamma')], promotes_outputs=['Fl_I2_calc:stat*']) self.add_subsystem('extraction_ratio', om.ExecComp('ER=Pt1/Pt2', Pt1={'units':'Pa'}, Pt2={'units':'Pa'}), promotes_inputs=[('Pt1', 'Fl_I1:tot:P'), ('Pt2', 'Fl_I2:tot:P')], promotes_outputs=['ER']) mix_flow = MixFlow(thermo_data=thermo_data, Fl_I1_elements=self.options['Fl_I1_elements'], Fl_I2_elements=self.options['Fl_I2_elements']) if self.options['designed_stream'] == 1: self.add_subsystem('mix_flow', mix_flow, promotes_inputs=['Fl_I1:tot:h', 'Fl_I1:tot:n', ('Fl_I1:stat:W','Fl_I1_calc:stat:W'), ('Fl_I1:stat:P','Fl_I1_calc:stat:P'), ('Fl_I1:stat:V','Fl_I1_calc:stat:V'), ('Fl_I1:stat:area','Fl_I1_calc:stat:area'), 'Fl_I2:tot:h', 'Fl_I2:tot:n', 'Fl_I2:stat:W', 'Fl_I2:stat:P', 'Fl_I2:stat:V', 'Fl_I2:stat:area']) else: self.add_subsystem('mix_flow', mix_flow, promotes_inputs=['Fl_I1:tot:h', 'Fl_I1:tot:n', 'Fl_I1:stat:W', 'Fl_I1:stat:P', 'Fl_I1:stat:V', 'Fl_I1:stat:area', 'Fl_I2:tot:h', 'Fl_I2:tot:n', ('Fl_I2:stat:W','Fl_I2_calc:stat:W'), ('Fl_I2:stat:P','Fl_I2_calc:stat:P'), ('Fl_I2:stat:V','Fl_I2_calc:stat:V'), ('Fl_I2:stat:area','Fl_I2_calc:stat:area')]) # group to converge for the impulse balance conv = self.add_subsystem('impulse_converge', om.Group(), promotes=['*']) if self.options['internal_solver']: newton = conv.nonlinear_solver = om.NewtonSolver() newton.options['maxiter'] = 30 newton.options['atol'] = 1e-2 newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 20 newton.options['reraise_child_analysiserror'] = False newton.linesearch = om.BoundsEnforceLS() newton.linesearch.options['bound_enforcement'] = 'scalar' newton.linesearch.options['iprint'] = -1 conv.linear_solver = om.DirectSolver(assemble_jac=True) out_tot = SetTotal(thermo_data=thermo_data, mode='h', init_reacts=self.options['Fl_I1_elements'], fl_name="Fl_O:tot") conv.add_subsystem('out_tot', out_tot, promotes_outputs=['Fl_O:tot:*']) self.connect('mix_flow.n_mix', 'out_tot.init_prod_amounts') self.connect('mix_flow.ht_mix', 'out_tot.h') # note: gets Pt from the balance comp out_stat = SetStatic(mode="area", thermo_data=thermo_data, init_reacts=self.options['Fl_I1_elements'], fl_name="Fl_O:stat") conv.add_subsystem('out_stat', out_stat, promotes_outputs=['Fl_O:stat:*'], promotes_inputs=['area', ]) self.connect('mix_flow.n_mix', 'out_stat.init_prod_amounts') self.connect('mix_flow.W_mix','out_stat.W') conv.connect('Fl_O:tot:S', 'out_stat.S') self.connect('mix_flow.ht_mix', 'out_stat.ht') conv.connect('Fl_O:tot:P', 'out_stat.guess:Pt') conv.connect('Fl_O:tot:gamma', 'out_stat.guess:gamt') conv.add_subsystem('imp_out', Impulse()) conv.connect('Fl_O:stat:P', 'imp_out.P') conv.connect('Fl_O:stat:area', 'imp_out.area') conv.connect('Fl_O:stat:V', 'imp_out.V') conv.connect('Fl_O:stat:W', 'imp_out.W') balance = conv.add_subsystem('balance', om.BalanceComp()) balance.add_balance('P_tot', val=100, units='psi', eq_units='N', lower=1e-3, upper=10000) conv.connect('balance.P_tot', 'out_tot.P') conv.connect('imp_out.impulse', 'balance.lhs:P_tot') self.connect('mix_flow.impulse_mix', 'balance.rhs:P_tot') #note that this connection comes from outside the convergence group
def setup(self): thermo_spec = pyc.species_data.janaf design = self.options['design'] # Add engine elements self.add_subsystem( 'fc', pyc.FlightConditions(thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.add_subsystem( 'inlet', pyc.Inlet(design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.add_subsystem('comp', pyc.Compressor( map_data=pyc.AXI5, design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX, ), promotes_inputs=['Nmech']) self.add_subsystem( 'burner', pyc.Combustor(design=design, thermo_data=thermo_spec, inflow_elements=pyc.AIR_MIX, air_fuel_elements=pyc.AIR_FUEL_MIX, fuel_type='JP-7')) self.add_subsystem('turb', pyc.Turbine( map_data=pyc.LPT2269, design=design, thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX, ), promotes_inputs=['Nmech']) self.add_subsystem( 'nozz', pyc.Nozzle(nozzType='CD', lossCoef='Cv', thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX)) self.add_subsystem('shaft', pyc.Shaft(num_ports=2), promotes_inputs=['Nmech']) self.add_subsystem('perf', pyc.Performance(num_nozzles=1, num_burners=1)) # Connect flow stations pyc.connect_flow(self, 'fc.Fl_O', 'inlet.Fl_I', connect_w=False) pyc.connect_flow(self, 'inlet.Fl_O', 'comp.Fl_I') pyc.connect_flow(self, 'comp.Fl_O', 'burner.Fl_I') pyc.connect_flow(self, 'burner.Fl_O', 'turb.Fl_I') pyc.connect_flow(self, 'turb.Fl_O', 'nozz.Fl_I') # Connect turbomachinery elements to shaft self.connect('comp.trq', 'shaft.trq_0') self.connect('turb.trq', 'shaft.trq_1') # Connnect nozzle exhaust to freestream static conditions self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust') # Connect outputs to pefromance element self.connect('inlet.Fl_O:tot:P', 'perf.Pt2') self.connect('comp.Fl_O:tot:P', 'perf.Pt3') self.connect('burner.Wfuel', 'perf.Wfuel_0') self.connect('inlet.F_ram', 'perf.ram_drag') self.connect('nozz.Fg', 'perf.Fg_0') # Add balances for design and off-design balance = self.add_subsystem('balance', om.BalanceComp()) if design: balance.add_balance('W', units='lbm/s', eq_units='lbf') self.connect('balance.W', 'inlet.Fl_I:stat:W') self.connect('perf.Fn', 'balance.lhs:W') balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017) self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR') balance.add_balance('turb_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.) self.connect('balance.turb_PR', 'turb.PR') self.connect('shaft.pwr_net', 'balance.lhs:turb_PR') else: balance.add_balance('FAR', eq_units='lbf', lower=1e-4, val=.3) self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('perf.Fn', 'balance.lhs:FAR') balance.add_balance('Nmech', val=1.5, units='rpm', lower=500., eq_units='hp', rhs_val=0.) self.connect('balance.Nmech', 'Nmech') self.connect('shaft.pwr_net', 'balance.lhs:Nmech') balance.add_balance('W', val=168.0, units='lbm/s', eq_units='inch**2') self.connect('balance.W', 'inlet.Fl_I:stat:W') self.connect('nozz.Throat:stat:area', 'balance.lhs:W') # Setup solver to converge engine self.set_order([ 'balance', 'fc', 'inlet', 'comp', 'burner', 'turb', 'nozz', 'shaft', 'perf' ]) newton = self.nonlinear_solver = om.NewtonSolver() newton.options['atol'] = 1e-6 newton.options['rtol'] = 1e-6 newton.options['iprint'] = 2 newton.options['maxiter'] = 15 newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 100 newton.linesearch = om.BoundsEnforceLS() # newton.linesearch = ArmijoGoldsteinLS() # newton.linesearch.options['c'] = .0001 newton.linesearch.options['bound_enforcement'] = 'scalar' newton.linesearch.options['iprint'] = -1 self.linear_solver = om.DirectSolver(assemble_jac=True)
self.nonlinear_solver.options['maxiter'] = 20 self.linear_solver = om.DirectSolver() if __name__ == "__main__": import openmdao.api as om p = om.Problem() model = p.model model.add_subsystem('ground', om.IndepVarComp('V', 0., units='V')) # replacing the fixed current source with a BalanceComp to represent a fixed Voltage source # model.add_subsystem('source', IndepVarComp('I', 0.1, units='A')) model.add_subsystem('batt', om.IndepVarComp('V', 1.5, units='V')) bal = model.add_subsystem('batt_balance', om.BalanceComp()) bal.add_balance('I', units='A', eq_units='V') model.add_subsystem('circuit', Circuit()) model.add_subsystem( 'batt_deltaV', om.ExecComp('dV = V1 - V2', V1={'units': 'V'}, V2={'units': 'V'}, dV={'units': 'V'})) # current into the circuit is now the output state from the batt_balance comp model.connect('batt_balance.I', 'circuit.I_in') model.connect('ground.V', ['circuit.Vg', 'batt_deltaV.V2']) model.connect('circuit.n1.V', 'batt_deltaV.V1')
def setup(self): thermo_spec = pyc.species_data.janaf design = self.options['design'] cooling = self.options['cooling'] self.pyc_add_element( 'fc', pyc.FlightConditions(thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element( 'inlet', pyc.Inlet(design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element('fan', pyc.Compressor(map_data=FanMap, design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX, map_extrap=True, bleed_names=[]), promotes_inputs=[('Nmech', 'Fan_Nmech')]) self.pyc_add_element( 'splitter', pyc.Splitter(design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element( 'duct2', pyc.Duct(design=design, expMN=2.0, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element('lpc', pyc.Compressor(map_data=LPCMap, design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX, map_extrap=True), promotes_inputs=[('Nmech', 'LP_Nmech')]) self.pyc_add_element('bld25', pyc.BleedOut(design=design, bleed_names=['sbv'])) self.pyc_add_element( 'duct25', pyc.Duct(design=design, expMN=2.0, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element( 'hpc', pyc.Compressor(map_data=HPCMap, design=design, thermo_data=thermo_spec, elements=pyc.AIR_MIX, map_extrap=True, bleed_names=['bld_inlet', 'bld_exit', 'cust']), promotes_inputs=[('Nmech', 'HP_Nmech')]) self.pyc_add_element( 'bld3', pyc.BleedOut(design=design, bleed_names=['bld_inlet', 'bld_exit'])) self.pyc_add_element( 'burner', pyc.Combustor(design=design, thermo_data=thermo_spec, inflow_elements=pyc.AIR_MIX, air_fuel_elements=pyc.AIR_FUEL_MIX, fuel_type='Jet-A(g)')) self.pyc_add_element('hpt', pyc.Turbine(map_data=HPTMap, design=design, thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX, map_extrap=True, bleed_names=['bld_inlet', 'bld_exit']), promotes_inputs=[('Nmech', 'HP_Nmech')]) self.pyc_add_element( 'duct45', pyc.Duct(design=design, expMN=2.0, thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX)) self.pyc_add_element('lpt', pyc.Turbine(map_data=LPTMap, design=design, thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX, map_extrap=True, bleed_names=['bld_inlet', 'bld_exit']), promotes_inputs=[('Nmech', 'LP_Nmech')]) self.pyc_add_element( 'duct5', pyc.Duct(design=design, expMN=2.0, thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX)) self.pyc_add_element( 'core_nozz', pyc.Nozzle(nozzType='CV', lossCoef='Cv', thermo_data=thermo_spec, elements=pyc.AIR_FUEL_MIX)) self.pyc_add_element( 'byp_bld', pyc.BleedOut(design=design, bleed_names=['bypBld'])) self.pyc_add_element( 'duct17', pyc.Duct(design=design, expMN=2.0, thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element( 'byp_nozz', pyc.Nozzle(nozzType='CV', lossCoef='Cv', thermo_data=thermo_spec, elements=pyc.AIR_MIX)) self.pyc_add_element('fan_shaft', pyc.Shaft(num_ports=2), promotes_inputs=[('Nmech', 'Fan_Nmech')]) self.pyc_add_element('gearbox', pyc.Gearbox(design=design), promotes_inputs=[('N_in', 'LP_Nmech'), ('N_out', 'Fan_Nmech')]) self.pyc_add_element('lp_shaft', pyc.Shaft(num_ports=3), promotes_inputs=[('Nmech', 'LP_Nmech')]) self.pyc_add_element('hp_shaft', pyc.Shaft(num_ports=2), promotes_inputs=[('Nmech', 'HP_Nmech')]) self.pyc_add_element('perf', pyc.Performance(num_nozzles=2, num_burners=1)) self.connect('inlet.Fl_O:tot:P', 'perf.Pt2') self.connect('hpc.Fl_O:tot:P', 'perf.Pt3') self.connect('burner.Wfuel', 'perf.Wfuel_0') self.connect('inlet.F_ram', 'perf.ram_drag') self.connect('core_nozz.Fg', 'perf.Fg_0') self.connect('byp_nozz.Fg', 'perf.Fg_1') self.connect('fan.trq', 'fan_shaft.trq_0') self.connect('gearbox.trq_out', 'fan_shaft.trq_1') self.connect('gearbox.trq_in', 'lp_shaft.trq_0') self.connect('lpc.trq', 'lp_shaft.trq_1') self.connect('lpt.trq', 'lp_shaft.trq_2') self.connect('hpc.trq', 'hp_shaft.trq_0') self.connect('hpt.trq', 'hp_shaft.trq_1') self.connect('fc.Fl_O:stat:P', 'core_nozz.Ps_exhaust') self.connect('fc.Fl_O:stat:P', 'byp_nozz.Ps_exhaust') self.add_subsystem( 'ext_ratio', om.ExecComp( 'ER = core_V_ideal * core_Cv / ( byp_V_ideal * byp_Cv )', core_V_ideal={ 'value': 1000.0, 'units': 'ft/s' }, core_Cv={ 'value': 0.98, 'units': None }, byp_V_ideal={ 'value': 1000.0, 'units': 'ft/s' }, byp_Cv={ 'value': 0.98, 'units': None }, ER={ 'value': 1.4, 'units': None })) self.connect('core_nozz.ideal_flow.V', 'ext_ratio.core_V_ideal') self.connect('byp_nozz.ideal_flow.V', 'ext_ratio.byp_V_ideal') main_order = [ 'fc', 'inlet', 'fan', 'splitter', 'duct2', 'lpc', 'bld25', 'duct25', 'hpc', 'bld3', 'burner', 'hpt', 'duct45', 'lpt', 'duct5', 'core_nozz', 'byp_bld', 'duct17', 'byp_nozz', 'gearbox', 'fan_shaft', 'lp_shaft', 'hp_shaft', 'perf', 'ext_ratio' ] balance = self.add_subsystem('balance', om.BalanceComp()) if design: balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017) self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR') balance.add_balance('lpt_PR', val=10.937, lower=1.001, upper=20, eq_units='hp', rhs_val=0., res_ref=1e4) self.connect('balance.lpt_PR', 'lpt.PR') self.connect('lp_shaft.pwr_net', 'balance.lhs:lpt_PR') balance.add_balance('hpt_PR', val=4.185, lower=1.001, upper=8, eq_units='hp', rhs_val=0., res_ref=1e4) self.connect('balance.hpt_PR', 'hpt.PR') self.connect('hp_shaft.pwr_net', 'balance.lhs:hpt_PR') balance.add_balance('gb_trq', val=23928.0, units='ft*lbf', eq_units='hp', rhs_val=0.0) self.connect('balance.gb_trq', 'gearbox.trq_base') self.connect('fan_shaft.pwr_net', 'balance.lhs:gb_trq') balance.add_balance('hpc_PR', val=14.0, units=None, eq_units=None) self.connect('balance.hpc_PR', ['hpc.PR', 'opr_calc.HPCPR']) # self.connect('perf.OPR', 'balance.lhs:hpc_PR') self.connect('opr_calc.OPR_simple', 'balance.lhs:hpc_PR') balance.add_balance('fan_eff', val=0.9689, units=None, eq_units=None) self.connect('balance.fan_eff', 'fan.eff') self.connect('fan.eff_poly', 'balance.lhs:fan_eff') balance.add_balance('lpc_eff', val=0.8895, units=None, eq_units=None) self.connect('balance.lpc_eff', 'lpc.eff') self.connect('lpc.eff_poly', 'balance.lhs:lpc_eff') # balance.add_balance('hpc_eff', val=0.8470, units=None, eq_units=None) # self.connect('balance.hpc_eff', 'hpc.eff') # self.connect('hpc.eff_poly', 'balance.lhs:hpc_eff') balance.add_balance('hpt_eff', val=0.9226, units=None, eq_units=None) self.connect('balance.hpt_eff', 'hpt.eff') self.connect('hpt.eff_poly', 'balance.lhs:hpt_eff') balance.add_balance('lpt_eff', val=0.9401, units=None, eq_units=None) self.connect('balance.lpt_eff', 'lpt.eff') self.connect('lpt.eff_poly', 'balance.lhs:lpt_eff') self.add_subsystem( 'hpc_CS', om.ExecComp('CS = Win *(pow(Tout/518.67,0.5)/(Pout/14.696))', Win={ 'value': 10.0, 'units': 'lbm/s' }, Tout={ 'value': 14.696, 'units': 'degR' }, Pout={ 'value': 518.67, 'units': 'psi' }, CS={ 'value': 10.0, 'units': 'lbm/s' })) self.connect('duct25.Fl_O:stat:W', 'hpc_CS.Win') self.connect('hpc.Fl_O:tot:T', 'hpc_CS.Tout') self.connect('hpc.Fl_O:tot:P', 'hpc_CS.Pout') self.add_subsystem( 'hpc_EtaBalance', SmallCoreEffBalance(eng_type='large', tech_level=0)) self.connect('hpc_CS.CS', 'hpc_EtaBalance.CS') self.connect('hpc.eff_poly', 'hpc_EtaBalance.eta_p') self.connect('hpc_EtaBalance.eta_a', 'hpc.eff') self.add_subsystem( 'fan_dia', om.ExecComp('FanDia = 2.0*(area/(pi*(1.0-hub_tip**2.0)))**0.5', area={ 'value': 7000.0, 'units': 'inch**2' }, hub_tip={ 'value': 0.3125, 'units': None }, FanDia={ 'value': 100.0, 'units': 'inch' })) self.connect('inlet.Fl_O:stat:area', 'fan_dia.area') self.add_subsystem( 'opr_calc', om.ExecComp('OPR_simple = FPR*LPCPR*HPCPR', FPR={ 'value': 1.3, 'units': None }, LPCPR={ 'value': 3.0, 'units': None }, HPCPR={ 'value': 14.0, 'units': None }, OPR_simple={ 'value': 55.0, 'units': None })) # order_add = ['hpc_CS', 'fan_dia', 'opr_calc'] order_add = ['hpc_CS', 'hpc_EtaBalance', 'fan_dia', 'opr_calc'] else: balance.add_balance('FAR', val=0.017, lower=1e-4, eq_units='lbf') self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('perf.Fn', 'balance.lhs:FAR') # self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR') balance.add_balance('W', units='lbm/s', lower=10., upper=2500., eq_units='inch**2') self.connect('balance.W', 'fc.W') self.connect('core_nozz.Throat:stat:area', 'balance.lhs:W') balance.add_balance('BPR', lower=15., upper=40.) self.connect('balance.BPR', 'splitter.BPR') self.connect('fan.map.RlineMap', 'balance.lhs:BPR') balance.add_balance('fan_Nmech', val=2000.0, units='rpm', lower=500., eq_units='hp', rhs_val=0., res_ref=1e2) self.connect('balance.fan_Nmech', 'Fan_Nmech') self.connect('fan_shaft.pwr_net', 'balance.lhs:fan_Nmech') balance.add_balance('lp_Nmech', val=6000.0, units='rpm', lower=500., eq_units='hp', rhs_val=0., res_ref=1e2) self.connect('balance.lp_Nmech', 'LP_Nmech') self.connect('lp_shaft.pwr_net', 'balance.lhs:lp_Nmech') balance.add_balance('hp_Nmech', val=20000.0, units='rpm', lower=500., eq_units='hp', rhs_val=0., res_ref=1e2) self.connect('balance.hp_Nmech', 'HP_Nmech') self.connect('hp_shaft.pwr_net', 'balance.lhs:hp_Nmech') order_add = [] if cooling: self.add_subsystem( 'hpt_cooling', pyc.TurbineCooling(n_stages=2, thermo_data=pyc.species_data.janaf, T_metal=2460.)) self.add_subsystem('hpt_chargable', pyc.CombineCooling(n_ins=3)) self.pyc_connect_flow('bld3.bld_inlet', 'hpt_cooling.Fl_cool', connect_stat=False) self.pyc_connect_flow('burner.Fl_O', 'hpt_cooling.Fl_turb_I') self.pyc_connect_flow('hpt.Fl_O', 'hpt_cooling.Fl_turb_O') self.connect('hpt_cooling.row_1.W_cool', 'hpt_chargable.W_1') self.connect('hpt_cooling.row_2.W_cool', 'hpt_chargable.W_2') self.connect('hpt_cooling.row_3.W_cool', 'hpt_chargable.W_3') self.connect('hpt.power', 'hpt_cooling.turb_pwr') balance.add_balance('hpt_nochrg_cool_frac', val=0.063660111, lower=0.02, upper=.15, eq_units='lbm/s') self.connect('balance.hpt_nochrg_cool_frac', 'bld3.bld_inlet:frac_W') self.connect('bld3.bld_inlet:stat:W', 'balance.lhs:hpt_nochrg_cool_frac') self.connect('hpt_cooling.row_0.W_cool', 'balance.rhs:hpt_nochrg_cool_frac') balance.add_balance('hpt_chrg_cool_frac', val=0.07037185, lower=0.02, upper=.15, eq_units='lbm/s') self.connect('balance.hpt_chrg_cool_frac', 'bld3.bld_exit:frac_W') self.connect('bld3.bld_exit:stat:W', 'balance.lhs:hpt_chrg_cool_frac') self.connect('hpt_chargable.W_cool', 'balance.rhs:hpt_chrg_cool_frac') order_add = ['hpt_cooling', 'hpt_chargable'] self.set_order(main_order + order_add + ['balance']) self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I') self.pyc_connect_flow('inlet.Fl_O', 'fan.Fl_I') self.pyc_connect_flow('fan.Fl_O', 'splitter.Fl_I') self.pyc_connect_flow('splitter.Fl_O1', 'duct2.Fl_I') self.pyc_connect_flow('duct2.Fl_O', 'lpc.Fl_I') self.pyc_connect_flow('lpc.Fl_O', 'bld25.Fl_I') self.pyc_connect_flow('bld25.Fl_O', 'duct25.Fl_I') self.pyc_connect_flow('duct25.Fl_O', 'hpc.Fl_I') self.pyc_connect_flow('hpc.Fl_O', 'bld3.Fl_I') self.pyc_connect_flow('bld3.Fl_O', 'burner.Fl_I') self.pyc_connect_flow('burner.Fl_O', 'hpt.Fl_I') self.pyc_connect_flow('hpt.Fl_O', 'duct45.Fl_I') self.pyc_connect_flow('duct45.Fl_O', 'lpt.Fl_I') self.pyc_connect_flow('lpt.Fl_O', 'duct5.Fl_I') self.pyc_connect_flow('duct5.Fl_O', 'core_nozz.Fl_I') self.pyc_connect_flow('splitter.Fl_O2', 'byp_bld.Fl_I') self.pyc_connect_flow('byp_bld.Fl_O', 'duct17.Fl_I') self.pyc_connect_flow('duct17.Fl_O', 'byp_nozz.Fl_I') self.pyc_connect_flow('hpc.bld_inlet', 'lpt.bld_inlet', connect_stat=False) self.pyc_connect_flow('hpc.bld_exit', 'lpt.bld_exit', connect_stat=False) self.pyc_connect_flow('bld3.bld_inlet', 'hpt.bld_inlet', connect_stat=False) self.pyc_connect_flow('bld3.bld_exit', 'hpt.bld_exit', connect_stat=False) newton = self.nonlinear_solver = om.NewtonSolver() newton.options['atol'] = 1e-4 newton.options['rtol'] = 1e-4 newton.options['iprint'] = 2 newton.options['maxiter'] = 10 newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 10 newton.options['reraise_child_analysiserror'] = False # newton.linesearch = om.BoundsEnforceLS() newton.linesearch = om.ArmijoGoldsteinLS() # newton.linesearch.options['maxiter'] = 2 newton.linesearch.options['bound_enforcement'] = 'scalar' newton.linesearch.options['iprint'] = -1 # if design: # newton.linesearch.options['print_bound_enforce'] = True # newton.options['debug_print'] = True self.linear_solver = om.DirectSolver(assemble_jac=True)
def test_result(self): import numpy as np from numpy.testing import assert_almost_equal import openmdao.api as om prob = om.Problem() bal = om.BalanceComp() bal.add_balance(name='E', val=0.0, units='rad', eq_units='rad', rhs_name='M') # Use M (mean anomaly) as the initial guess for E (eccentric anomaly) def guess_function(inputs, outputs, residuals): if np.abs(residuals['E']) > 1.0E-2: outputs['E'] = inputs['M'] bal.options['guess_func'] = guess_function # ExecComp used to compute the LHS of Kepler's equation. lhs_comp = om.ExecComp('lhs=E - ecc * sin(E)', lhs={ 'value': 0.0, 'units': 'rad' }, E={ 'value': 0.0, 'units': 'rad' }, ecc={'value': 0.0}) prob.model.add_subsystem(name='balance', subsys=bal, promotes_inputs=['M'], promotes_outputs=['E']) prob.model.set_input_defaults('M', 85.0, units='deg') prob.model.add_subsystem(name='lhs_comp', subsys=lhs_comp, promotes_inputs=['E', 'ecc']) # Explicit connections prob.model.connect('lhs_comp.lhs', 'balance.lhs:E') # Set up solvers prob.model.linear_solver = om.DirectSolver() prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=2) prob.setup() prob.set_val('ecc', 0.6) prob.run_model() assert_almost_equal(np.degrees(prob.get_val('E')), 115.9, decimal=1)
def test_scalar_guess_func_using_outputs(self): model = om.Group() ind = om.IndepVarComp() ind.add_output('a', 1) ind.add_output('b', -4) ind.add_output('c', 3) lhs = om.ExecComp('lhs=-(a*x**2+b*x)') bal = om.BalanceComp(name='x', rhs_name='c') model.add_subsystem('ind_comp', ind, promotes_outputs=['a', 'b', 'c']) model.add_subsystem('lhs_comp', lhs, promotes_inputs=['a', 'b', 'x']) model.add_subsystem('bal_comp', bal, promotes_inputs=['c'], promotes_outputs=['x']) model.connect('lhs_comp.lhs', 'bal_comp.lhs:x') model.linear_solver = om.DirectSolver() model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0) # first verify behavior of the balance comp without the guess function # at initial conditions x=5, x=0 and x=-1 prob = om.Problem(model) prob.setup() # default solution with initial value of 5 is x=3. prob['x'] = 5 prob.run_model() assert_almost_equal(prob['x'], 3.0, decimal=7) # default solution with initial value of 0 is x=1. prob['x'] = 0 prob.run_model() assert_almost_equal(prob['x'], 1.0, decimal=7) # default solution with initial value of -1 is x=1. prob['x'] = -1 prob.run_model() assert_almost_equal(prob['x'], 1.0, decimal=7) # now use a guess function that steers us to the x=3 solution only # if the initial value of x is less than zero def guess_function(inputs, outputs, residuals): if outputs['x'] < 0: outputs['x'] = 3. bal.options['guess_func'] = guess_function # solution with initial value of 5 is still x=3. prob['x'] = 5 prob.run_model() assert_almost_equal(prob['x'], 3.0, decimal=7) # solution with initial value of 0 is still x=1. prob['x'] = 0 prob.run_model() assert_almost_equal(prob['x'], 1.0, decimal=7) # solution with initial value of -1 is now x=3. prob['x'] = -1 prob.run_model() assert_almost_equal(prob['x'], 3.0, decimal=7)