예제 #1
0
    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
예제 #2
0
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
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
        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
예제 #6
0
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'])
예제 #9
0
    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)
예제 #10
0
    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
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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'])
예제 #14
0
    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
예제 #17
0
    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)
예제 #18
0
    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)
예제 #19
0
    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)
예제 #20
0
    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)
예제 #21
0
    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()
예제 #22
0
    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)
예제 #23
0
    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)
예제 #24
0
 def configure(self):
     # This will solve it.
     self.sub.nonlinear_solver = NewtonSolver()
     self.sub.linear_solver = ScipyIterativeSolver()
예제 #25
0
    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]))
예제 #26
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')
예제 #27
0
    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)
예제 #28
0
    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'])
예제 #29
0
파일: nozzle.py 프로젝트: friedenhe/pyCycle
    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')