def setUp(self): p = Problem() p.model = Group() p.model.cite = "foobar model" p.model.nonlinear_solver.cite = "foobar nonlinear_solver" p.model.linear_solver.cite = "foobar linear_solver" indeps = p.model.add_subsystem('indeps', IndepVarComp('x', 10), promotes=['*']) indeps.linear_solver = LinearRunOnce() par = p.model.add_subsystem('par', ParallelGroup(), promotes=['*']) ec = par.add_subsystem('ec', ExecComp('y = 2+3*x'), promotes=['*']) # note using newton here makes no sense in reality, but its fine for this test since we never run the model ec.nonlinear_solver = NewtonSolver() ec.cite = "foobar exec comp" c2 = par.add_subsystem('c2', ExecComp('y2=x'), promotes=['*']) c2.cite = 'foobar exec comp' self.prob = p
def _baseline(mode): p = Problem() dv = p.model.add_subsystem('dv', IndepVarComp(), promotes=['*']) dv.add_output('z', [1., 1.]) p.model.add_subsystem('double_sellar', DoubleSellar()) p.model.connect('z', ['double_sellar.g1.z', 'double_sellar.g2.z']) p.model.add_design_var('z', lower=-10, upper=10) p.model.add_objective('double_sellar.g1.y1') p.setup(mode=mode) p.model.nonlinear_solver = NewtonSolver() p.model.nonlinear_solver.options['solve_subsystems'] = True p.run_model() objective = p['double_sellar.g1.y1'] jac = p.compute_totals() return objective, jac
def test_implicit_cycle_precon(self): prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('d1', SellarImplicitDis1()) model.add_subsystem('d2', SellarImplicitDis2()) model.connect('d1.y1', 'd2.y1') model.connect('d2.y2', 'd1.y2') model.nonlinear_solver = NewtonSolver() model.nonlinear_solver.options['maxiter'] = 5 model.linear_solver = ScipyKrylov() model.linear_solver.precon = self.linear_solver_class() prob.setup(check=False) prob.set_solver_print(level=0) prob.run_model() res = model._residuals.get_norm() # Newton is kinda slow on this for some reason, this is how far it gets with directsolver too. self.assertLess(res, 2.0e-2)
def configure(self): for_statics = self.options['for_statics'] if for_statics and for_statics != 'Ps': self.ceq.nonlinear_solver.options['atol'] = 1e-10 self.ceq.nonlinear_solver.options['rtol'] = 1e-6 # statics need an newton solver to converge the outer loop with Ps newton = self.nonlinear_solver = NewtonSolver() newton.options['atol'] = 1e-10 newton.options['rtol'] = 1e-10 newton.options['maxiter'] = 50 newton.options['iprint'] = 2 newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 50 self.options['assembled_jac_type'] = 'dense' newton.linear_solver = DirectSolver(assemble_jac=True) ln_bt = newton.linesearch = BoundsEnforceLS() ln_bt.options['bound_enforcement'] = 'scalar' ln_bt.options['iprint'] = -1
def runs_successfully(use_scal, coeffs): prob = Problem(model=Group()) prob.model.add_subsystem( 'row1', ScalingTestComp(row=1, coeffs=coeffs, use_scal=use_scal)) prob.model.add_subsystem( 'row2', ScalingTestComp(row=2, coeffs=coeffs, use_scal=use_scal)) prob.model.connect('row1.y', 'row2.x') prob.model.connect('row2.y', 'row1.x') prob.model.nonlinear_solver = NewtonSolver(maxiter=2, atol=1e-5, rtol=0) prob.model.nonlinear_solver.linear_solver = ScipyKrylov(maxiter=1) prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() return np.linalg.norm(prob.model._residuals._data) < 1e-5
def define_analysis(n_int_per_seg): """ This function sets up the problem with all DVs and constraints necessary to perform analysis only (drives throttle residuals and BFL residuals to zero). This does NOT ensure that the airplane has enough fuel capacity or gross weight to fly the mission. """ prob = Problem() prob.model= TotalAnalysis(n_int_per_seg=n_int_per_seg) nn = n_int_per_seg*2+1 nn_tot_m = 3*(n_int_per_seg*2+1) nn_tot_to = 3*(n_int_per_seg*2+1)+2 nn_tot = 6*(n_int_per_seg*2+1)+2 prob.model.options['assembled_jac_type'] = 'csc' prob.model.nonlinear_solver=NewtonSolver() prob.model.linear_solver = DirectSolver(assemble_jac=True) prob.model.nonlinear_solver.options['solve_subsystems'] = True prob.model.nonlinear_solver.options['maxiter'] = 10 prob.model.nonlinear_solver.options['atol'] = 1e-6 prob.model.nonlinear_solver.options['rtol'] = 1e-6 prob.driver = ScipyOptimizeDriver() return prob, nn_tot, nn_tot_m, nn_tot_to
def test_record_solver_linear_block_gs(self, m): self.setup_endpoints(m) recorder = WebRecorder(self._accepted_token, suppress_output=True) self.setup_sellar_model() self.prob.model.nonlinear_solver = NewtonSolver() # used for analytic derivatives self.prob.model.nonlinear_solver.linear_solver = LinearBlockGS() linear_solver = self.prob.model.nonlinear_solver.linear_solver linear_solver.recording_options['record_abs_error'] = True linear_solver.recording_options['record_rel_error'] = True linear_solver.recording_options['record_solver_residuals'] = True self.prob.model.nonlinear_solver.linear_solver.add_recorder(recorder) self.prob.setup(check=False) t0, t1 = run_driver(self.prob) solver_iteration = json.loads(self.solver_iterations) expected_abs_error = 9.109083208861876e-11 expected_rel_error = 9.114367543620551e-12 expected_solver_output = [ {'name': 'px.x', 'values': [0.0]}, {'name': 'pz.z', 'values': [0.0, 0.0]}, {'name': 'd1.y1', 'values': [0.00045069]}, {'name': 'd2.y2', 'values': [-0.00225346]}, {'name': 'obj_cmp.obj', 'values': [0.00045646]}, {'name': 'con_cmp1.con1', 'values': [-0.00045069]}, {'name': 'con_cmp2.con2', 'values': [-0.00225346]}, ] self.assertAlmostEqual(expected_abs_error, solver_iteration['abs_err']) self.assertAlmostEqual(expected_rel_error, solver_iteration['rel_err']) for o in expected_solver_output: self.assert_array_close(o, solver_iteration['solver_output'])
def test_record_solver_linear_block_jac(self, m): self.setup_endpoints(m) recorder = WebRecorder(self._accepted_token, suppress_output=True) self.setup_sellar_model() self.prob.model.nonlinear_solver = NewtonSolver() # used for analytic derivatives self.prob.model.nonlinear_solver.linear_solver = LinearBlockJac() linear_solver = self.prob.model.nonlinear_solver.linear_solver linear_solver.recording_options['record_abs_error'] = True linear_solver.recording_options['record_rel_error'] = True linear_solver.recording_options['record_solver_residuals'] = True self.prob.model.nonlinear_solver.linear_solver.add_recorder(recorder) self.prob.setup(check=False) t0, t1 = run_driver(self.prob) solver_iteration = json.loads(self.solver_iterations) expected_abs_error = 9.947388408259769e-11 expected_rel_error = 4.330301334141486e-08 expected_solver_output = [ {'name': 'px.x', 'values': [0.0]}, {'name': 'pz.z', 'values': [0.0, 0.0]}, {'name': 'd1.y1', 'values': [4.55485639e-09]}, {'name': 'd2.y2', 'values': [-2.27783334e-08]}, {'name': 'obj_cmp.obj', 'values': [-2.28447051e-07]}, {'name': 'con_cmp1.con1', 'values': [2.28461863e-07]}, {'name': 'con_cmp2.con2', 'values': [-2.27742837e-08]}, ] self.assertAlmostEqual(expected_abs_error, solver_iteration['abs_err']) self.assertAlmostEqual(expected_rel_error, solver_iteration['rel_err']) for o in expected_solver_output: self.assert_array_close(o, solver_iteration['solver_output'])
def test_guess_nonlinear_transfer(self): # Test that data is transfered to a component before calling guess_nonlinear. class ImpWithInitial(ImplicitComponent): def setup(self): self.add_input('x', 3.0) self.add_output('y', 4.0) def solve_nonlinear(self, inputs, outputs): """ Do nothing. """ pass def apply_nonlinear(self, inputs, outputs, resids): """ Do nothing. """ pass def guess_nonlinear(self, inputs, outputs, resids): # Passthrough outputs['y'] = inputs['x'] group = Group() group.add_subsystem('px', IndepVarComp('x', 77.0)) group.add_subsystem('comp1', ImpWithInitial()) group.add_subsystem('comp2', ImpWithInitial()) group.connect('px.x', 'comp1.x') group.connect('comp1.y', 'comp2.x') group.nonlinear_solver = NewtonSolver() group.nonlinear_solver.options['maxiter'] = 1 prob = Problem(model=group) prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() assert_rel_error(self, prob['comp2.y'], 77., 1e-5)
def test_feature_vector(self): import numpy as np from numpy.testing import assert_almost_equal from openmdao.api import Problem, Group, ExecComp, NewtonSolver, DirectSolver, BalanceComp n = 100 prob = Problem() exec_comp = 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=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 = DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = NewtonSolver(maxiter=100, iprint=0) prob.setup(check=False) prob['balance.x'] = np.random.rand(n) prob.run_model() b = prob['exec.b'] c = prob['exec.c'] assert_almost_equal(prob['balance.x'], -c / b, decimal=6) assert_almost_equal(-c / b, prob['balance.x'], decimal=6) # expected
def test_create_on_init(self): prob = Problem(model=Group()) bal = BalanceComp('x', val=1.0) tgt = IndepVarComp(name='y_tgt', val=2) exec_comp = 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 = DirectSolver() prob.model.nonlinear_solver = NewtonSolver() prob.setup() prob.run_model() assert_almost_equal(prob['balance.x'], np.sqrt(2), decimal=7) # Assert that normalization is happening assert_almost_equal(prob.model.balance._scale_factor, 1.0 / np.abs(2)) with printoptions(linewidth=1024): cpd = prob.check_partials() for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def test_load_solver_cases(self): prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) model.linear_solver = LinearBlockGS() model.nonlinear_solver = NewtonSolver() model.linear_solver.add_recorder(self.recorder) prob.setup() prob.run_model() prob.cleanup() cr = CaseReader(self.filename) case = cr.solver_cases.get_case(0) # Add one to all the inputs just to change the model # so we can see if loading the case values really changes the model for name in prob.model._inputs: prob.model._inputs[name] += 1.0 for name in prob.model._outputs: prob.model._outputs[name] += 1.0 # Now load in the case we recorded prob.load_case(case) _assert_model_matches_case(case, model)
def test_record_solver_linear_linear_run_once(self, m): self.setup_endpoints(m) # raise unittest.SkipTest("Linear Solver recording not working yet") self.setup_sellar_model() self.prob.model.nonlinear_solver = NewtonSolver() # used for analytic derivatives self.prob.model.nonlinear_solver.linear_solver = LinearRunOnce() self.prob.model.nonlinear_solver.linear_solver.recording_options['record_abs_error'] = True self.prob.model.nonlinear_solver.linear_solver.recording_options['record_rel_error'] = True self.prob.model.nonlinear_solver.linear_solver.recording_options['record_solver_residuals'] = True self.prob.model.nonlinear_solver.linear_solver.add_recorder(self.recorder) self.prob.setup(check=False) t0, t1 = run_driver(self.prob) upload(self.filename, self._accepted_token) solver_iteration = json.loads(self.solver_iterations) expected_abs_error = 0.0 expected_rel_error = 0.0 expected_solver_output = [ {'name': 'px.x', 'values': [0.0]}, {'name': 'pz.z', 'values': [0.0, 0.0]}, {'name': 'd1.y1', 'values': [-4.15366975e-05]}, {'name': 'd2.y2', 'values': [-4.10568454e-06]}, {'name': 'obj_cmp.obj', 'values': [-4.15366737e-05]}, {'name': 'con_cmp1.con1', 'values': [4.15366975e-05]}, {'name': 'con_cmp2.con2', 'values': [-4.10568454e-06]}, ] self.assertAlmostEqual(expected_abs_error, solver_iteration['abs_err']) self.assertAlmostEqual(expected_rel_error, solver_iteration['rel_err']) for o in expected_solver_output: self.assert_array_close(o, solver_iteration['solver_output'])
def test_raise_error_on_singular_with_densejac(self): prob = Problem() model = prob.model comp = 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=Group()) teg.add_subsystem('dynamics', ExecComp('z = 2.0*thrust'), promotes=['*']) thrust_bal = 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 = DirectSolver(assemble_jac=True) teg.options['assembled_jac_type'] = 'dense' teg.nonlinear_solver = 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(check=False) 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_list_residuals_with_tol(self): from openmdao.test_suite.components.sellar import SellarImplicitDis1, SellarImplicitDis2 from openmdao.api import Problem, Group, IndepVarComp, NewtonSolver, ScipyKrylov, LinearBlockGS prob = Problem() model = prob.model = Group() model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('d1', SellarImplicitDis1()) model.add_subsystem('d2', SellarImplicitDis2()) model.connect('d1.y1', 'd2.y1') model.connect('d2.y2', 'd1.y2') model.nonlinear_solver = NewtonSolver() model.nonlinear_solver.options['maxiter'] = 5 model.linear_solver = ScipyKrylov() model.linear_solver.precon = LinearBlockGS() prob.setup(check=False) prob.set_solver_print(level=-1) prob.run_model() resids = model.list_residuals(tol=0.01, values=False) self.assertEqual(sorted(resids), ['d2.y2',])
def setup(self): self._mpi_proc_allocator.parallel = self.parallel if self.parallel: self.nonlinear_solver = NewtonSolver() self.linear_solver = PETScKrylov() else: self.nonlinear_solver = NonlinearBlockGS() self.linear_solver = LinearBlockGS() self.add_subsystem('C1', ExecComp('z = 1 / 3. * y + x0'), promotes=['x0']) self.add_subsystem('C2', ExecComp('z = 1 / 4. * y + x1'), promotes=['x1']) if self.parallel: self.connect('C1.z', 'C2.y') self.connect('C2.z', 'C1.y') else: self.connect('C1.z', 'C2.y', src_indices=[self.comm.rank]) self.connect('C2.z', 'C1.y', src_indices=[self.comm.rank]) self.parallel = not self.parallel
def test_feature_linear_solver(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, NewtonSolver, LinearBlockGS, \ ExecComp, DirectSolver from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, \ SellarDis2withDerivatives prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) model.linear_solver = LinearBlockGS() nlgbs = model.nonlinear_solver = NewtonSolver() nlgbs.linear_solver = DirectSolver() prob.setup() prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001)
def test_rhs_val(self): """ Test solution with a default RHS value and no connected RHS variable. """ n = 1 prob = Problem(model=Group(assembled_jac_type='dense')) bal = BalanceComp('x', rhs_val=4.0) exec_comp = 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 = DirectSolver(assemble_jac=True) prob.model.nonlinear_solver = NewtonSolver(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) with printoptions(linewidth=1024): cpd = prob.check_partials() for (of, wrt) in cpd['balance']: assert_almost_equal(cpd['balance'][of, wrt]['abs error'], 0.0, decimal=5)
def test_specify_precon_left(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, DirectSolver, PETScKrylov, \ NewtonSolver, ExecComp from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, \ SellarDis2withDerivatives prob = Problem() model = prob.model = Group() model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) model.nonlinear_solver = NewtonSolver() model.linear_solver = PETScKrylov() model.linear_solver.precon = DirectSolver() model.linear_solver.options['precon_side'] = 'left' model.linear_solver.options['ksp_type'] = 'richardson' prob.setup() prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001)
def test_comp(self): num_nodes = 3 prob = Problem() prob.model.nonlinear_solver = NewtonSolver() prob.model.linear_solver = DirectSolver() prob.model.nonlinear_solver.options['solve_subsystems'] = True prob.model.add_subsystem('test', thermal.LiquidCooledComp(num_nodes=num_nodes), promotes=['*']) prob.setup(check=True, force_alloc_complex=True) # Set the values prob.set_val('q_in', np.array([1000., 1400., 4000.]), units='W') prob.set_val('mdot_coolant', np.array([9., 14., 12.]), units='kg/s') prob.set_val('T_in', np.array([300., 350., 290.]), units='K') prob.set_val('mass', 10., units='kg') prob.set_val('T_initial', 400., units='K') prob.set_val('duration', 2., units='min') prob.set_val('channel_length', 7., units='mm') prob.set_val('channel_width', 1., units='mm') prob.set_val('channel_height', .5, units='mm') prob.set_val('n_parallel', 5) prob.run_model() assert_near_equal(prob.get_val('T', units='K'), np.array([400., 406.40945984, 422.53992837]), tolerance=1e-9) assert_near_equal(prob.get_val('T_out', units='K'), np.array([300.00140593, 350.00050984, 290.00139757]), tolerance=1e-9) partials = prob.check_partials(method='cs', compact_print=True, step=1e-50) assert_check_partials(partials)
def setup(self): self.add_subsystem('n1', Node(n_in=1, n_out=2), promotes_inputs=[('I_in:0', 'I_in')]) self.add_subsystem('n2', Node()) # leaving defaults self.add_subsystem('R1', Resistor(R=100.), promotes_inputs=[('V_out', 'Vg')]) self.add_subsystem('R2', Resistor(R=10000.)) self.add_subsystem('D1', Diode(), promotes_inputs=[('V_out', 'Vg')]) self.connect('n1.V', ['R1.V_in', 'R2.V_in']) self.connect('R1.I', 'n1.I_out:0') self.connect('R2.I', 'n1.I_out:1') self.connect('n2.V', ['R2.V_out', 'D1.V_in']) self.connect('R2.I', 'n2.I_in:0') self.connect('D1.I', 'n2.I_out:0') self.nonlinear_solver = NewtonSolver() self.nonlinear_solver.options['iprint'] = 2 self.nonlinear_solver.options['maxiter'] = 20 self.linear_solver = DirectSolver()
def test_solve_subsystems_internals(self): # Here we test that this feature is doing what it should do by counting the # number of calls in various places. class CountNewton(NewtonSolver): """ This version of Newton also counts how many times it runs in total.""" def __init__(self, **kwargs): super(CountNewton, self).__init__(**kwargs) self.total_count = 0 def _iter_execute(self): super(CountNewton, self)._iter_execute() self.total_count += 1 class CountDS(DirectSolver): """ This version of Newton also counts how many times it linearizes""" def __init__(self, **kwargs): super(CountDS, self).__init__(**kwargs) self.lin_count = 0 def _linearize(self): super(CountDS, self)._linearize() self.lin_count += 1 prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enfore behavior: max_sub_solves = 0 means we run once during init model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 0 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 2) self.assertEqual(g2.nonlinear_solver.total_count, 2) self.assertEqual(g1.linear_solver.lin_count, 2) prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enforce Behavior: baseline model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 5 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 5) self.assertEqual(g2.nonlinear_solver.total_count, 5) self.assertEqual(g1.linear_solver.lin_count, 5) prob = Problem(model=DoubleSellar()) model = prob.model # each SubSellar group converges itself g1 = model.g1 g1.nonlinear_solver = CountNewton() g1.nonlinear_solver.options['rtol'] = 1.0e-5 g1.linear_solver = CountDS() # used for derivatives g2 = model.g2 g2.nonlinear_solver = CountNewton() g2.nonlinear_solver.options['rtol'] = 1.0e-5 g2.linear_solver = DirectSolver() # Converge the outer loop with Gauss Seidel, with a looser tolerance. model.nonlinear_solver = NewtonSolver() model.linear_solver = ScipyKrylov() # Enfore behavior: max_sub_solves = 1 means we run during init and first iteration of iter_execute model.nonlinear_solver.options['maxiter'] = 5 model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 1 prob.set_solver_print(level=0) prob.setup() prob.run_model() # Verifying subsolvers ran self.assertEqual(g1.nonlinear_solver.total_count, 4) self.assertEqual(g2.nonlinear_solver.total_count, 4) self.assertEqual(g1.linear_solver.lin_count, 4)
def test_sellar_specify_linear_direct_solver(self): prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) proms = [ 'x', 'z', 'y1', 'state_eq.y2_actual', 'state_eq.y2_command', 'd1.y2', 'd2.y2' ] sub = model.add_subsystem('sub', Group(), promotes=proms) subgrp = sub.add_subsystem( 'state_eq_group', Group(), promotes=['state_eq.y2_actual', 'state_eq.y2_command']) subgrp.linear_solver = ScipyKrylov() subgrp.add_subsystem('state_eq', StateConnection()) sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1']) sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1']) model.connect('state_eq.y2_command', 'd1.y2') model.connect('d2.y2', 'state_eq.y2_actual') model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0), promotes=['x', 'z', 'y1', 'obj']) model.connect('d2.y2', 'obj_cmp.y2') model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2']) model.connect('d2.y2', 'con_cmp2.y2') model.nonlinear_solver = NewtonSolver() # Use bad settings for this one so that problem doesn't converge. # That way, we test that we are really using Newton's Lin Solver # instead. sub.linear_solver = ScipyKrylov() sub.linear_solver.options['maxiter'] = 1 # The good solver model.nonlinear_solver.linear_solver = DirectSolver() prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['state_eq.y2_command'], 12.05848819, .00001) # Make sure we aren't iterating like crazy self.assertLess(model.nonlinear_solver._iter_count, 8) self.assertEqual(model.linear_solver._iter_count, 0)
def configure(self): # This will solve it. self.sub.nonlinear_solver = NewtonSolver() self.sub.linear_solver = ScipyIterativeSolver()
def test_result(self): import numpy as np from numpy.testing import assert_almost_equal from openmdao.api import Problem, Group, IndepVarComp, BalanceComp, \ ExecComp, DirectSolver, NewtonSolver, DenseJacobian prob = Problem(model=Group()) ivc = IndepVarComp() ivc.add_output(name='M', val=0.0, units='deg', desc='Mean anomaly') ivc.add_output(name='ecc', val=0.0, units=None, desc='orbit eccentricity') bal = BalanceComp() bal.add_balance(name='E', val=0.0, units='rad', eq_units='rad', rhs_name='M') # Override the guess_nonlinear method, always initialize E to the value of M def guess_func(inputs, outputs, residuals): outputs['E'] = inputs['M'] bal.guess_nonlinear = guess_func # ExecComp used to compute the LHS of Kepler's equation. lhs_comp = 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='ivc', subsys=ivc, promotes_outputs=['M', 'ecc']) prob.model.add_subsystem(name='balance', subsys=bal, promotes_inputs=['M'], promotes_outputs=['E']) 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') # Setup solvers prob.model.linear_solver = DirectSolver() prob.model.nonlinear_solver = NewtonSolver() prob.model.nonlinear_solver.options['maxiter'] = 100 prob.model.nonlinear_solver.options['iprint'] = 0 prob.setup() prob['M'] = 85.0 prob['ecc'] = 0.6 prob.run_model() assert_almost_equal(np.degrees(prob['E']), 115.9, decimal=1) print('E (deg) = ', np.degrees(prob['E'][0]))
# Run a full mission analysis including takeoff, climb, cruise, and descent analysis = self.add_subsystem('analysis', FullMissionAnalysis( num_nodes=nn, aircraft_model=KingAirC90GTModel, extra_states=extra_states_tuple), promotes_inputs=['*'], promotes_outputs=['*']) if __name__ == "__main__": num_nodes = 11 prob = Problem() prob.model = KingAirAnalysisGroup() prob.model.nonlinear_solver = NewtonSolver(iprint=2) prob.model.options['assembled_jac_type'] = 'csc' prob.model.linear_solver = DirectSolver(assemble_jac=True) prob.model.nonlinear_solver.options['solve_subsystems'] = True prob.model.nonlinear_solver.options['maxiter'] = 10 prob.model.nonlinear_solver.options['atol'] = 1e-6 prob.model.nonlinear_solver.options['rtol'] = 1e-6 prob.model.nonlinear_solver.linesearch = BoundsEnforceLS( bound_enforcement='scalar', print_bound_enforce=True) prob.setup(check=True, mode='fwd') # set some (required) mission parameters. Each pahse needs a vertical and air-speed # the entire mission needs a cruise altitude and range prob.set_val('climb.fltcond|vs', np.ones((num_nodes, )) * 1500, units='ft/min')
def test_circuit_voltage_source(self): from openmdao.api import ArmijoGoldsteinLS, Problem, IndepVarComp, BalanceComp, ExecComp from openmdao.api import NewtonSolver, DirectSolver, NonlinearRunOnce, LinearRunOnce from openmdao.test_suite.scripts.circuit_analysis import Circuit p = Problem() model = p.model model.add_subsystem('ground', 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', IndepVarComp('V', 1.5, units='V')) bal = model.add_subsystem('batt_balance', BalanceComp()) bal.add_balance('I', units='A', eq_units='V') model.add_subsystem('circuit', Circuit()) model.add_subsystem( 'batt_deltaV', 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') # set the lhs and rhs for the battery residual model.connect('batt.V', 'batt_balance.rhs:I') model.connect('batt_deltaV.dV', 'batt_balance.lhs:I') p.setup() ################### # Solver Setup ################### # change the circuit solver to RunOnce because we're # going to converge at the top level of the model with newton instead p.model.circuit.nonlinear_solver = NonlinearRunOnce() p.model.circuit.linear_solver = LinearRunOnce() # Put Newton at the top so it can also converge the new BalanceComp residual newton = p.model.nonlinear_solver = NewtonSolver() p.model.linear_solver = DirectSolver() newton.options['iprint'] = 2 newton.options['maxiter'] = 20 newton.options['solve_subsystems'] = True newton.linesearch = ArmijoGoldsteinLS() newton.linesearch.options['maxiter'] = 10 newton.linesearch.options['iprint'] = 2 # set initial guesses from the current source problem p['circuit.n1.V'] = 9.8 p['circuit.n2.V'] = .7 p.run_model() assert_rel_error(self, p['circuit.n1.V'], 1.5, 1e-5) assert_rel_error(self, p['circuit.n2.V'], 0.676232, 1e-5) assert_rel_error(self, p['circuit.R1.I'], 0.015, 1e-5) assert_rel_error(self, p['circuit.R2.I'], 8.23767999e-05, 1e-5) assert_rel_error(self, p['circuit.D1.I'], 8.23767999e-05, 1e-5)
def test_record_solver_linear_direct_solver(self, m): self.setup_endpoints(m) recorder = WebRecorder(self._accepted_token, suppress_output=True) self.setup_sellar_model() self.prob.model.nonlinear_solver = NewtonSolver() # used for analytic derivatives self.prob.model.nonlinear_solver.linear_solver = DirectSolver() recorder.options['record_abs_error'] = True recorder.options['record_rel_error'] = True recorder.options['record_solver_output'] = True recorder.options['record_solver_residuals'] = True self.prob.model.nonlinear_solver.linear_solver.add_recorder(recorder) self.prob.setup(check=False) t0, t1 = run_driver(self.prob) expected_solver_output = [ { 'name': 'px.x', 'values': [0.0] }, { 'name': 'pz.z', 'values': [0.0, 0.0] }, { 'name': 'd1.y1', 'values': [0.00045069] }, { 'name': 'd2.y2', 'values': [-0.00225346] }, { 'name': 'obj_cmp.obj', 'values': [0.00045646] }, { 'name': 'con_cmp1.con1', 'values': [-0.00045069] }, { 'name': 'con_cmp2.con2', 'values': [-0.00225346] }, ] expected_solver_residuals = [ { 'name': 'px.x', 'values': [0.0] }, { 'name': 'pz.z', 'values': [-0., -0.] }, { 'name': 'd1.y1', 'values': [0.0] }, { 'name': 'd2.y2', 'values': [-0.00229801] }, { 'name': 'obj_cmp.obj', 'values': [5.75455956e-06] }, { 'name': 'con_cmp1.con1', 'values': [-0.] }, { 'name': 'con_cmp2.con2', 'values': [-0.] }, ] solver_iteration = json.loads(self.solver_iterations) self.assertAlmostEqual(0.0, solver_iteration['abs_err']) self.assertAlmostEqual(0.0, solver_iteration['rel_err']) for o in expected_solver_output: self.assert_array_close(o, solver_iteration['solver_output']) for r in expected_solver_residuals: self.assert_array_close(r, solver_iteration['solver_residuals'])
def setup(self): thermo_data = self.options['thermo_data'] elements = self.options['elements'] nozzType = self.options['nozzType'] lossCoef = self.options['lossCoef'] gas_thermo = species_data.Thermo(thermo_data, init_reacts=elements) self.gas_prods = gas_thermo.products num_prod = len(self.gas_prods) self.add_subsystem('mach_choked', IndepVarComp( 'MN', 1.000, )) # Create inlet flow station in_flow = FlowIn(fl_name="Fl_I", num_prods=num_prod) self.add_subsystem('in_flow', in_flow, promotes_inputs=['Fl_I:*']) # PR_bal = self.add_subsystem('PR_bal', BalanceComp()) # PR_bal.add_balance('PR', units=None, eq_units='lbf/inch**2', lower=1.001) # self.connect('PR_bal.PR', 'PR') # self.connect('Ps_exhaust', 'PR_bal.lhs:PR') # self.connect('Ps_calc', 'PR_bal.rhs:PR') self.add_subsystem('PR_bal', PR_bal(), promotes_inputs=['*'], promotes_outputs=['*']) # Calculate pressure at the throat prom_in = [('Pt_in', 'Fl_I:tot:P'), 'PR', 'dPqP'] self.add_subsystem('press_calcs', PressureCalcs(), promotes_inputs=prom_in, promotes_outputs=['Ps_calc']) # Calculate throat total flow properties throat_total = SetTotal(thermo_data=thermo_data, mode="h", init_reacts=elements, fl_name="Fl_O:tot") prom_in = [('h', 'Fl_I:tot:h'), ('init_prod_amounts', 'Fl_I:tot:n')] self.add_subsystem('throat_total', throat_total, promotes_inputs=prom_in, promotes_outputs=['Fl_O:*']) self.connect('press_calcs.Pt_th', 'throat_total.P') # Calculate static properties for sonic flow prom_in = [('ht', 'Fl_I:tot:h'), ('W', 'Fl_I:stat:W'), ('init_prod_amounts', 'Fl_I:tot:n')] self.add_subsystem('staticMN', SetStatic(mode="MN", thermo_data=thermo_data, init_reacts=elements), promotes_inputs=prom_in) self.connect('throat_total.S', 'staticMN.S') self.connect('mach_choked.MN', 'staticMN.MN') self.connect('press_calcs.Pt_th', 'staticMN.guess:Pt') self.connect('throat_total.gamma', 'staticMN.guess:gamt') # self.connect('Fl_I.flow:flow_products','staticMN.init_prod_amounts') # Calculate static properties based on exit static pressure prom_in = [('ht', 'Fl_I:tot:h'), ('W', 'Fl_I:stat:W'), ('Ps', 'Ps_calc'), ('init_prod_amounts', 'Fl_I:tot:n')] self.add_subsystem('staticPs', SetStatic(mode="Ps", thermo_data=thermo_data, init_reacts=elements), promotes_inputs=prom_in) self.connect('throat_total.S', 'staticPs.S') # self.connect('press_calcs.Ps_calc', 'staticPs.Ps') # self.connect('Fl_I.flow:flow_products','staticPs.init_prod_amounts') # Calculate ideal exit flow properties prom_in = [('ht', 'Fl_I:tot:h'), ('S', 'Fl_I:tot:S'), ('W', 'Fl_I:stat:W'), ('Ps', 'Ps_calc'), ('init_prod_amounts', 'Fl_I:tot:n')] self.add_subsystem('ideal_flow', SetStatic(mode="Ps", thermo_data=thermo_data, init_reacts=elements), promotes_inputs=prom_in) # self.connect('press_calcs.Ps_calc', 'ideal_flow.Ps') # self.connect('Fl_I.flow:flow_products','ideal_flow.init_prod_amounts') # Determine throat and exit flow properties based on nozzle type and exit static pressure mux = Mux(nozzType=nozzType, fl_out_name='Fl_O') prom_in = [('Ps:W', 'Fl_I:stat:W'), ('MN:W', 'Fl_I:stat:W'), ('Ps:P', 'Ps_calc'), 'Ps_calc'] self.add_subsystem('mux', mux, promotes_inputs=prom_in, promotes_outputs=['*:stat:*']) self.connect('throat_total.S', 'mux.S') self.connect('staticPs.h', 'mux.Ps:h') self.connect('staticPs.T', 'mux.Ps:T') self.connect('staticPs.rho', 'mux.Ps:rho') self.connect('staticPs.gamma', 'mux.Ps:gamma') self.connect('staticPs.Cp', 'mux.Ps:Cp') self.connect('staticPs.Cv', 'mux.Ps:Cv') self.connect('staticPs.V', 'mux.Ps:V') self.connect('staticPs.Vsonic', 'mux.Ps:Vsonic') self.connect('staticPs.MN', 'mux.Ps:MN') self.connect('staticPs.area', 'mux.Ps:area') self.connect('staticMN.h', 'mux.MN:h') self.connect('staticMN.T', 'mux.MN:T') self.connect('staticMN.Ps', 'mux.MN:P') self.connect('staticMN.rho', 'mux.MN:rho') self.connect('staticMN.gamma', 'mux.MN:gamma') self.connect('staticMN.Cp', 'mux.MN:Cp') self.connect('staticMN.Cv', 'mux.MN:Cv') self.connect('staticMN.V', 'mux.MN:V') self.connect('staticMN.Vsonic', 'mux.MN:Vsonic') self.connect('mach_choked.MN', 'mux.MN:MN') self.connect('staticMN.area', 'mux.MN:area') # Calculate nozzle performance paramters based on perf_calcs = PerformanceCalcs(lossCoef=lossCoef) if lossCoef == "Cv": other_inputs = ['Cv', 'Ps_calc'] else: other_inputs = ['Cfg', 'Ps_calc'] prom_in = [('W_in', 'Fl_I:stat:W')] + other_inputs self.add_subsystem('perf_calcs', perf_calcs, promotes_inputs=prom_in, promotes_outputs=['Fg']) self.connect('ideal_flow.V', 'perf_calcs.V_ideal') # self.connect('ideal_flow.area', 'perf_calcs.A_ideal') if lossCoef == 'Cv': self.connect('Fl_O:stat:V', 'perf_calcs.V_actual') self.connect('Fl_O:stat:area', 'perf_calcs.A_actual') self.connect('Fl_O:stat:P', 'perf_calcs.Ps_actual') if self.options['internal_solver']: newton = self.nonlinear_solver = NewtonSolver() newton.options['atol'] = 1e-10 newton.options['rtol'] = 1e-10 newton.options['maxiter'] = 20 newton.options['iprint'] = 2 newton.options['solve_subsystems'] = True newton.linesearch = BoundsEnforceLS() newton.linesearch.options['bound_enforcement'] = 'scalar' newton.linesearch.options['iprint'] = -1 self.linear_solver = DirectSolver(assemble_jac=True)
def setup(self): thermo_spec = species_data.janaf design = self.options['design'] ########################################## # Elements ########################################## self.add_subsystem( 'fc', FlightConditions(thermo_data=thermo_spec, elements=AIR_MIX)) # Inlet Components self.add_subsystem('mil_spec', MilSpecRecovery()) self.add_subsystem( 'inlet', Inlet(design=design, thermo_data=thermo_spec, elements=AIR_MIX)) # Fan Components - Split here for CFD integration Add a CFDStart Compomponent self.add_subsystem('fan', Compressor(map_data=AXI5, design=design, thermo_data=thermo_spec, elements=AIR_MIX, map_extrap=True), promotes_inputs=[('Nmech', 'LP_Nmech')]) self.add_subsystem( 'splitter', Splitter(design=design, thermo_data=thermo_spec, elements=AIR_MIX)) # Bypass Stream ################### self.add_subsystem( 'bypass_duct', Duct(design=design, thermo_data=thermo_spec, elements=AIR_MIX)) # Core Stream ############## self.add_subsystem( 'ic_duct', Duct(design=design, thermo_data=thermo_spec, elements=AIR_MIX)) self.add_subsystem('hpc', Compressor(map_data=HPCmap, design=design, thermo_data=thermo_spec, elements=AIR_MIX, bleed_names=['cool1', 'cool2'], map_extrap=True), promotes_inputs=[('Nmech', 'HP_Nmech')]) self.add_subsystem( 'duct_3', Duct(design=design, thermo_data=thermo_spec, elements=AIR_MIX)) self.add_subsystem('bleed_3', BleedOut(design=design, bleed_names=['cust_bleed'])) self.add_subsystem( 'burner', Combustor(design=design, thermo_data=thermo_spec, inflow_elements=AIR_MIX, air_fuel_elements=AIR_FUEL_MIX, fuel_type='Jet-A(g)')) self.add_subsystem('hpt', Turbine(map_data=HPTmap, design=design, thermo_data=thermo_spec, elements=AIR_FUEL_MIX, bleed_names=['chargable', 'non_chargable'], map_extrap=True), promotes_inputs=[('Nmech', 'HP_Nmech')]) self.add_subsystem( 'it_duct', Duct(design=design, thermo_data=thermo_spec, elements=AIR_FUEL_MIX)) # uncooled lpt self.add_subsystem('lpt', Turbine(map_data=LPTmap, design=design, thermo_data=thermo_spec, elements=AIR_FUEL_MIX, map_extrap=True), promotes_inputs=[('Nmech', 'LP_Nmech')]) if not design: self.add_subsystem( 'vabi', ExecComp('Fl1_area = Fl1_area_des*fact', Fl1_area_des={'units': 'inch**2'}, Fl1_area={ 'units': 'inch**2', 'value': 164. })) self.add_subsystem( 'mixer', Mixer(design=design, designed_stream=1, Fl_I1_elements=AIR_FUEL_MIX, Fl_I2_elements=AIR_MIX)) # augmentor Components self.add_subsystem( 'augmentor', Combustor(design=design, thermo_data=thermo_spec, inflow_elements=AIR_FUEL_MIX, air_fuel_elements=AIR_FUEL_MIX, fuel_type='Jet-A(g)')) # End CFD HERE # Nozzle self.add_subsystem( 'nozzle', Nozzle(nozzType='CD', lossCoef='Cfg', thermo_data=thermo_spec, elements=AIR_FUEL_MIX)) # Mechanical components self.add_subsystem('lp_shaft', Shaft(num_ports=2), promotes_inputs=[('Nmech', 'LP_Nmech')]) self.add_subsystem('hp_shaft', Shaft(num_ports=2), promotes_inputs=[('Nmech', 'HP_Nmech')]) # Aggregating component self.add_subsystem('perf', Performance(num_nozzles=1, num_burners=2)) ########################################## # Connecting the Flow Path ########################################## connect_flow(self, 'fc.Fl_O', 'inlet.Fl_I') connect_flow(self, 'inlet.Fl_O', 'fan.Fl_I') connect_flow(self, 'fan.Fl_O', 'splitter.Fl_I') # Bypass Connections connect_flow(self, 'splitter.Fl_O2', 'bypass_duct.Fl_I') connect_flow(self, 'bypass_duct.Fl_O', 'mixer.Fl_I2') # Core connections connect_flow(self, 'splitter.Fl_O1', 'ic_duct.Fl_I') connect_flow(self, 'ic_duct.Fl_O', 'hpc.Fl_I') connect_flow(self, 'hpc.Fl_O', 'duct_3.Fl_I') connect_flow(self, 'duct_3.Fl_O', 'bleed_3.Fl_I') connect_flow(self, 'bleed_3.Fl_O', 'burner.Fl_I') connect_flow(self, 'burner.Fl_O', 'hpt.Fl_I') connect_flow(self, 'hpt.Fl_O', 'it_duct.Fl_I') connect_flow(self, 'it_duct.Fl_O', 'lpt.Fl_I') connect_flow(self, 'lpt.Fl_O', 'mixer.Fl_I1') connect_flow(self, 'mixer.Fl_O', 'augmentor.Fl_I') connect_flow(self, 'augmentor.Fl_O', 'nozzle.Fl_I') # Connect cooling flows connect_flow(self, 'hpc.cool1', 'hpt.non_chargable', connect_stat=False) connect_flow(self, 'hpc.cool2', 'hpt.chargable', connect_stat=False) ########################################## # Additional Connections ########################################## # Make additional model connections self.connect('fc.Fl_O:stat:MN', 'mil_spec.MN') self.connect('mil_spec.ram_recovery', 'inlet.ram_recovery') 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('augmentor.Wfuel', 'perf.Wfuel_1') self.connect('inlet.F_ram', 'perf.ram_drag') self.connect('nozzle.Fg', 'perf.Fg_0') self.connect('fan.trq', 'lp_shaft.trq_0') self.connect('lpt.trq', 'lp_shaft.trq_1') self.connect('hpc.trq', 'hp_shaft.trq_0') self.connect('hpt.trq', 'hp_shaft.trq_1') self.connect('fc.Fl_O:stat:P', 'nozzle.Ps_exhaust') if not design: self.connect('vabi.Fl1_area', 'mixer.Fl_I1_stat_calc.area') ########################################## # Balances to define cycle convergence ########################################## balance = self.add_subsystem('balance', BalanceComp()) if design: balance.add_balance('W', lower=1e-3, upper=200., units='lbm/s', eq_units='lbf') self.connect('balance.W', 'fc.fs.W') self.connect('perf.Fn', 'balance.lhs:W') # self.add_subsystem('wDV',IndepVarComp('wDes',100,units='lbm/s')) # self.connect('wDV.wDes','fc.fs.W') balance.add_balance('BPR', eq_units=None, lower=0.25, val=5.0) self.connect('balance.BPR', 'splitter.BPR') self.connect('mixer.ER', 'balance.lhs:BPR') balance.add_balance('FAR_core', eq_units='degR', lower=1e-4, val=.017) self.connect('balance.FAR_core', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR_core') balance.add_balance('FAR_ab', eq_units='degR', lower=1e-4, val=.017) self.connect('balance.FAR_ab', 'augmentor.Fl_I:FAR') self.connect('augmentor.Fl_O:tot:T', 'balance.lhs:FAR_ab') balance.add_balance('lpt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', use_mult=True, mult_val=-1) self.connect('balance.lpt_PR', 'lpt.PR') self.connect('lp_shaft.pwr_in', 'balance.lhs:lpt_PR') self.connect('lp_shaft.pwr_out', 'balance.rhs:lpt_PR') balance.add_balance('hpt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', use_mult=True, mult_val=-1) self.connect('balance.hpt_PR', 'hpt.PR') self.connect('hp_shaft.pwr_in', 'balance.lhs:hpt_PR') self.connect('hp_shaft.pwr_out', 'balance.rhs:hpt_PR') else: # off design balance.add_balance('W', lower=1e-3, upper=400., units='lbm/s', eq_units='inch**2') self.connect('balance.W', 'fc.fs.W') self.connect('nozzle.Throat:stat:area', 'balance.lhs:W') balance.add_balance('BPR', lower=0.25, upper=3.0, eq_units='psi') self.connect('balance.BPR', 'splitter.BPR') self.connect('mixer.Fl_I1_calc:stat:P', 'balance.lhs:BPR') self.connect('bypass_duct.Fl_O:stat:P', 'balance.rhs:BPR') # balance.add_balance('FAR_core', eq_units='degR', lower=1e-4, upper=.045, val=.017) # self.connect('balance.FAR_core', 'burner.Fl_I:FAR') # self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR_core') balance.add_balance('FAR_ab', eq_units='degR', lower=1e-4, upper=.045, val=.017) self.connect('balance.FAR_ab', 'augmentor.Fl_I:FAR') self.connect('augmentor.Fl_O:tot:T', 'balance.lhs:FAR_ab') far_core_bal = ConstrainedTempBalance() self.add_subsystem('far_core_bal', far_core_bal) self.connect('far_core_bal.FAR', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'far_core_bal.T_computed') self.connect('fan.map.shaftNc.NcMap', 'far_core_bal.Nc_computed') balance.add_balance('LP_Nmech', val=1., units='rpm', lower=0.5, upper=2., eq_units='hp', use_mult=True, mult_val=-1) self.connect('balance.LP_Nmech', 'LP_Nmech') self.connect('lp_shaft.pwr_in', 'balance.lhs:LP_Nmech') self.connect('lp_shaft.pwr_out', 'balance.rhs:LP_Nmech') balance.add_balance('HP_Nmech', val=1., units='rpm', lower=0.5, upper=2., eq_units='hp', use_mult=True, mult_val=-1) self.connect('balance.HP_Nmech', 'HP_Nmech') self.connect('hp_shaft.pwr_in', 'balance.lhs:HP_Nmech') self.connect('hp_shaft.pwr_out', 'balance.rhs:HP_Nmech') newton = self.nonlinear_solver = NewtonSolver() newton.options['atol'] = 1e-6 newton.options['rtol'] = 1e-10 newton.options['iprint'] = 2 newton.options['maxiter'] = 30 newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 10 newton.linesearch = BoundsEnforceLS() newton.linesearch.options['bound_enforcement'] = 'scalar' # newton.linesearch.options['print_bound_enforce'] = True newton.linesearch.options['iprint'] = -1 # newton.linesearch = ArmijoGoldsteinLS() # newton.linesearch.options['c'] = -.1 self.linear_solver = DirectSolver(assemble_jac=True) # TODO: re-factor pycycle so this block isn't needed in default use case!!! if design: ########################################## # Model Parameters ########################################## element_params = self.add_subsystem('element_params', IndepVarComp(), promotes=["*"]) # element_params.add_output('inlet:ram_recovery', 0.9990) element_params.add_output('inlet:MN_out', 0.65) # self.connect('inlet:ram_recovery', 'inlet.ram_recovery') self.connect('inlet:MN_out', 'inlet.MN') element_params.add_output('fan:effDes', 0.8700) element_params.add_output('fan:MN_out', 0.4578) self.connect('fan:effDes', 'fan.map.effDes') self.connect('fan:MN_out', 'fan.MN') element_params.add_output('splitter:MN_out1', 0.3104) element_params.add_output('splitter:MN_out2', 0.4518) self.connect('splitter:MN_out1', 'splitter.MN1') self.connect('splitter:MN_out2', 'splitter.MN2') element_params.add_output('ic_duct:dPqP', 0.0048) element_params.add_output('ic_duct:MN_out', 0.3121) self.connect('ic_duct:dPqP', 'ic_duct.dPqP') self.connect('ic_duct:MN_out', 'ic_duct.MN') element_params.add_output('hpc:effDes', 0.8707) element_params.add_output('hpc:MN_out', 0.2442) self.connect('hpc:effDes', 'hpc.map.effDes') self.connect('hpc:MN_out', 'hpc.MN') element_params.add_output('hpc:cool1:frac_W', 0.09) element_params.add_output('hpc:cool1:frac_P', 1.0) element_params.add_output('hpc:cool1:frac_work', 1.0) self.connect('hpc:cool1:frac_W', 'hpc.cool1:frac_W') self.connect('hpc:cool1:frac_P', 'hpc.cool1:frac_P') self.connect('hpc:cool1:frac_work', 'hpc.cool1:frac_work') element_params.add_output('hpc:cool2:frac_W', 0.07) element_params.add_output('hpc:cool2:frac_P', 0.5) element_params.add_output('hpc:cool2:frac_work', 0.5) self.connect('hpc:cool2:frac_W', 'hpc.cool2:frac_W') self.connect('hpc:cool2:frac_P', 'hpc.cool2:frac_P') self.connect('hpc:cool2:frac_work', 'hpc.cool2:frac_work') element_params.add_output('duct_3:dPqP', 0.0048) element_params.add_output('duct_3:MN_out', 0.2) self.connect('duct_3:dPqP', 'duct_3.dPqP') self.connect('duct_3:MN_out', 'duct_3.MN') element_params.add_output('bleed_3:MN_out', 0.3000) element_params.add_output('bleed_3:cust_bleed:frac_W', 0.07) self.connect('bleed_3:MN_out', 'bleed_3.MN') self.connect('bleed_3:cust_bleed:frac_W', 'bleed_3.cust_bleed:frac_W') element_params.add_output('burner:dPqP', 0.0540) element_params.add_output('burner:MN_out', 0.1025) self.connect('burner:dPqP', 'burner.dPqP') self.connect('burner:MN_out', 'burner.MN') element_params.add_output('hpt:effDes', 0.8888) element_params.add_output('hpt:MN_out', 0.3650) element_params.add_output('hpt:chargable:frac_P', 0.0) element_params.add_output('hpt:non_chargable:frac_P', 1.0) self.connect('hpt:effDes', 'hpt.map.effDes') self.connect('hpt:MN_out', 'hpt.MN') self.connect('hpt:chargable:frac_P', 'hpt.chargable:frac_P') self.connect('hpt:non_chargable:frac_P', 'hpt.non_chargable:frac_P') element_params.add_output('it_duct:dPqP', 0.0051) element_params.add_output('it_duct:MN_out', 0.3063) self.connect('it_duct:dPqP', 'it_duct.dPqP') self.connect('it_duct:MN_out', 'it_duct.MN') element_params.add_output('lpt:effDes', 0.8996) element_params.add_output('lpt:MN_out', 0.4127) self.connect('lpt:effDes', 'lpt.map.effDes') self.connect('lpt:MN_out', 'lpt.MN') element_params.add_output('bypass_duct:dPqP', 0.0107) element_params.add_output('bypass_duct:MN_out', 0.4463) self.connect('bypass_duct:dPqP', 'bypass_duct.dPqP') self.connect('bypass_duct:MN_out', 'bypass_duct.MN') # No params for mixer element_params.add_output('augmentor:dPqP', 0.0540) element_params.add_output('augmentor:MN_out', 0.1025) self.connect('augmentor:dPqP', 'augmentor.dPqP') self.connect('augmentor:MN_out', 'augmentor.MN') element_params.add_output('nozzle:Cfg', 0.9933) self.connect('nozzle:Cfg', 'nozzle.Cfg') element_params.add_output('lp_shaft:Nmech', 1, units='rpm') element_params.add_output('hp_shaft:Nmech', 1, units='rpm') element_params.add_output('hp_shaft:HPX', 250.0, units='hp') self.connect('lp_shaft:Nmech', 'LP_Nmech') self.connect('hp_shaft:Nmech', 'HP_Nmech') self.connect('hp_shaft:HPX', 'hp_shaft.HPX')