コード例 #1
0
    def test_linesearch_vector_bound_enforcement(self):
        top = self.top

        ls = top.model.nonlinear_solver.linesearch = om.BoundsEnforceLS(bound_enforcement='vector')
        ls.options['print_bound_enforce'] = True

        # Setup again because we assigned a new linesearch
        top.setup()

        # Test lower bounds: should go to the lower bound and stall
        top['px.x'] = 2.0
        top['comp.y'] = 0.
        top['comp.z'] = 1.6
        top.run_model()
        for ind in range(3):
            assert_rel_error(self, top['comp.z'][ind], [1.5], 1e-8)

        # Test upper bounds: should go to the minimum upper bound and stall
        top['px.x'] = 0.5
        top['comp.y'] = 0.
        top['comp.z'] = 2.4

        stdout = sys.stdout
        strout = StringIO()

        sys.stdout = strout
        try:
            top.run_model()
        finally:
            sys.stdout = stdout

        txt = strout.getvalue()

        self.assertTrue("'comp.z' exceeds upper bound" in txt)

        for ind in range(3):
            assert_rel_error(self, top['comp.z'][ind], [2.5], 1e-8)
コード例 #2
0
ファイル: set_total.py プロジェクト: will214/pyCycle
    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 = om.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
            newton.options['reraise_child_analysiserror'] = False

            self.options['assembled_jac_type'] = 'dense'
            newton.linear_solver = om.DirectSolver(assemble_jac=True)

            ln_bt = newton.linesearch = om.BoundsEnforceLS()
            ln_bt.options['bound_enforcement'] = 'scalar'
            ln_bt.options['iprint'] = -1
コード例 #3
0
ファイル: test_backtracking.py プロジェクト: ovidner/OpenMDAO
    def test_linesearch_wall_bound_enforcement_wall(self):
        top = self.top

        top.model.nonlinear_solver.linesearch = om.BoundsEnforceLS(
            bound_enforcement='wall')

        # Setup again because we assigned a new linesearch
        top.setup()

        # Test lower bounds: should go to the lower bound and stall
        top['px.x'] = 2.0
        top['comp.y'] = 0.
        top['comp.z'] = 1.6
        top.run_model()
        for ind in range(3):
            assert_rel_error(self, top['comp.z'][ind], [1.5], 1e-8)

        # Test upper bounds: should go to the upper bound and stall
        top['px.x'] = 0.5
        top['comp.y'] = 0.
        top['comp.z'] = 2.4
        top.run_model()
        for ind in range(3):
            assert_rel_error(self, top['comp.z'][ind], [self.ub[ind]], 1e-8)
コード例 #4
0
    def test_feature_boundscheck_vector(self):

        top = om.Problem()
        top.model.add_subsystem('comp',
                                ImplCompTwoStatesArrays(),
                                promotes_inputs=['x'])

        top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
        top.model.nonlinear_solver.options['maxiter'] = 10
        top.model.linear_solver = om.ScipyKrylov()

        top.model.nonlinear_solver.linesearch = om.BoundsEnforceLS(
            bound_enforcement='vector')

        top.setup()
        top.set_val('x', np.array([2., 2, 2]).reshape(3, 1))

        # Test lower bounds: should go to the lower bound and stall
        top.set_val('comp.y', 0.)
        top.set_val('comp.z', 1.6)
        top.run_model()

        for ind in range(3):
            assert_near_equal(top.get_val('comp.z', indices=ind), [1.5], 1e-8)
コード例 #5
0
    def test_linesearch_wall_bound_enforcement_scalar(self):
        top = self.top

        top.model.nonlinear_solver.linesearch = om.BoundsEnforceLS(bound_enforcement='scalar')

        # Setup again because we assigned a new linesearch
        top.setup()

        # Test lower bounds: should stop just short of the lower bound
        top['px.x'] = 2.0
        top['comp.y'] = 0.
        top['comp.z'] = 1.6
        top.run_model()
        for ind in range(3):
            self.assertGreaterEqual(top['comp.z'][ind], 1.5)
            self.assertLessEqual(top['comp.z'][ind], 1.6)

        # Test upper bounds: should stop just short of the minimum upper bound
        top['px.x'] = 0.5
        top['comp.y'] = 0.
        top['comp.z'] = 2.4
        top.run_model()
        for ind in range(3):
            self.assertTrue(2.4 <= top['comp.z'][ind] <= self.ub[ind])
コード例 #6
0
ファイル: chem_eq.py プロジェクト: eshendricks/pyCycle
    def setup(self):

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['maxiter'] = 100
        newton.options['iprint'] = 2
        newton.options['atol'] = 1e-7
        newton.options['rtol'] = 1e-7
        newton.options['stall_limit'] = 4
        newton.options['stall_tol'] = 1e-10
        newton.options['solve_subsystems'] = True
        newton.options['reraise_child_analysiserror'] = False

        self.options['assembled_jac_type'] = 'dense'
        self.linear_solver = om.DirectSolver(assemble_jac=True)

        ln_bt = newton.linesearch = om.BoundsEnforceLS()
        # ln_bt = newton.linesearch = om.ArmijoGoldsteinLS()
        # ln_bt.options['maxiter'] = 2
        ln_bt.options['iprint'] = -1
        # ln_bt.options['print_bound_enforce'] = True

        # Once the concentration of a species reaches its minimum, we
        # can essentially remove it from the problem. This switch controls
        # whether to do this.
        self.remove_trace_species = False

        # multiply a damping function that scales down the residual for trace species
        self.use_trace_damping = True

        thermo = self.options['thermo']
        mode = self.options['mode']

        num_prod = thermo.num_prod
        num_element = thermo.num_element

        # Input vars
        self.add_input('composition',
                       val=thermo.b0,
                       desc='moles of atoms present in mixture')

        self.add_input('P', val=1.0, units="bar", desc="Pressure")

        if mode == "T":  # T is an input
            self.add_input('T', val=400., units="degK", desc="Temperature")
        elif mode == "h" or mode == "S":  # T becomes another state variable
            if mode == "h":  # hP solve
                self.add_input('h', val=0., units="cal/g", desc="Enthalpy")
            elif mode == "S":  # SP solve
                self.add_input('S',
                               val=0.,
                               units="cal/(g*degK)",
                               desc="Entropy")

            self.T_idx = num_prod + num_element
            self.add_output('T',
                            val=400.,
                            units="degK",
                            desc="Temperature",
                            lower=1.,
                            res_ref=100)

        # State vars
        self.n_init = np.ones(num_prod) / num_prod / 10  # initial guess for n

        self.add_output('n',
                        shape=num_prod,
                        val=self.n_init,
                        desc="mole fractions of the mixture",
                        lower=MIN_VALID_CONCENTRATION,
                        upper=1e2,
                        res_ref=10000.)

        self.add_output(
            'pi',
            val=np.ones(num_element),
            desc="modified lagrange multipliers from the Gibbs lagrangian")

        # Explicit Outputs
        self.add_output('n_moles',
                        lower=1e-10,
                        val=0.034,
                        shape=1,
                        desc="1/molecular weight of gas")

        # allocate the newton Jacobian
        self.size = size = num_prod + num_element
        if mode != "T":
            size += 1  # added T as a state variable

        self._dRdy = np.zeros((size, size))
        self._rhs = np.zeros(size)  # used for solve_linear

        # Cached stuff for speed
        self.H0_T = None
        self.S0_T = None
        self.dH0_dT = None
        self.dS0_dT = None
        self.sum_n_H0_T = None

        # self.deriv_options['check_type'] = 'cs'
        # self.deriv_options['check_step_size'] = 1e-50
        # self.deriv_options['type'] = 'fd'
        # self.deriv_options['step_size'] = 1e-5

        self.declare_partials('n', ['n', 'pi', 'P', 'T'])
        self.declare_partials('pi', ['n', 'composition'])
        self.declare_partials('n_moles', 'n')
        self.declare_partials('n_moles', 'n_moles', val=-1)

        if mode == 'h':
            self.declare_partials('T', ['n', 'h', 'T'])
        elif mode == 'S':
            self.declare_partials('T', ['n', 'S', 'T', 'P'])
コード例 #7
0
    def setup(self):

        thermo_spec = pyc.species_data.janaf
        design = self.options['design']

        self.add_subsystem(
            'fc',
            pyc.FlightConditions(thermo_data=thermo_spec,
                                 elements=pyc.AIR_MIX))

        self.add_subsystem(
            'inlet',
            pyc.Inlet(design=design,
                      thermo_data=thermo_spec,
                      elements=pyc.AIR_MIX))
        self.add_subsystem(
            'fan',
            pyc.Compressor(thermo_data=thermo_spec,
                           elements=pyc.AIR_MIX,
                           design=design,
                           map_data=pyc.FanMap,
                           map_extrap=True))
        self.add_subsystem(
            'nozz', pyc.Nozzle(thermo_data=thermo_spec, elements=pyc.AIR_MIX))
        self.add_subsystem('perf', pyc.Performance(num_nozzles=1,
                                                   num_burners=0))

        balance = om.BalanceComp()
        if design:
            self.add_subsystem('shaft',
                               om.IndepVarComp('Nmech', 1., units='rpm'))
            self.connect('shaft.Nmech', 'fan.Nmech')

            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='hp',
                                val=50.,
                                lower=1.,
                                upper=500.)
            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:W', 'pwr_target')])
            self.connect('fan.power', 'balance.lhs:W')

        else:
            # vary mass flow till the nozzle area matches the design values
            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='inch**2',
                                val=50,
                                lower=1.,
                                upper=500.)
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

            balance.add_balance('Nmech',
                                val=1.,
                                units='rpm',
                                lower=0.1,
                                upper=2.0,
                                eq_units='hp')
            self.connect('balance.Nmech', 'fan.Nmech')
            self.connect('fan.power', 'balance.lhs:Nmech')

            # self.add_subsystem('shaft', om.IndepVarComp('Nmech', 1., units='rpm'))
            # self.connect('shaft.Nmech', 'fan.Nmech')

            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:Nmech', 'pwr_target')])

        pyc.connect_flow(self, 'fc.Fl_O', 'inlet.Fl_I')
        pyc.connect_flow(self, 'inlet.Fl_O', 'fan.Fl_I')
        pyc.connect_flow(self, 'fan.Fl_O', 'nozz.Fl_I')

        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('fan.Fl_O:tot:P', 'perf.Pt3')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        self.connect('balance.W', 'fc.W')

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-12
        newton.options['rtol'] = 1e-12
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 10
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 10
        #
        # newton.linesearch = om.ArmijoGoldsteinLS()
        # newton.linesearch.options['maxiter'] = 3
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        # newton.linesearch.options['print_bound_enforce'] = True
        # newton.linesearch.options['iprint'] = -1
        #
        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #8
0
ファイル: nozzle.py プロジェクト: lamkina/pyCycle
    def setup(self):
        thermo_method = self.options['thermo_method']
        thermo_data = self.options['thermo_data']
        nozzType = self.options['nozzType']
        lossCoef = self.options['lossCoef']

        # elements = self.options['elements']
        composition = self.Fl_I_data['Fl_I']

        self.add_subsystem('mach_choked', om.IndepVarComp(
            'MN',
            1.000,
        ))

        # Create inlet flow station
        in_flow = FlowIn(fl_name="Fl_I")
        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 = Thermo(mode='total_hP',
                              fl_name='Fl_O:tot',
                              method=thermo_method,
                              thermo_kwargs={
                                  'composition': composition,
                                  'spec': thermo_data
                              })
        prom_in = [('h', 'Fl_I:tot:h'),
                   ('composition', 'Fl_I:tot:composition')]
        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
        throat_static_MN = Thermo(mode='static_MN',
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'composition': composition,
                                      'spec': thermo_data
                                  })
        prom_in = [('ht', 'Fl_I:tot:h'), ('W', 'Fl_I:stat:W'),
                   ('composition', 'Fl_I:tot:composition')]
        self.add_subsystem('staticMN',
                           throat_static_MN,
                           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
        throat_static_Ps = Thermo(mode='static_Ps',
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'composition': composition,
                                      'spec': thermo_data
                                  })
        prom_in = [('ht', 'Fl_I:tot:h'), ('W', 'Fl_I:stat:W'),
                   ('Ps', 'Ps_calc'), ('composition', 'Fl_I:tot:composition')]
        self.add_subsystem('staticPs',
                           throat_static_Ps,
                           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
        ideal_flow = Thermo(mode='static_Ps',
                            method=thermo_method,
                            thermo_kwargs={
                                'composition': composition,
                                'spec': thermo_data
                            })
        prom_in = [('ht', 'Fl_I:tot:h'), ('S', 'Fl_I:tot:S'),
                   ('W', 'Fl_I:stat:W'), ('Ps', 'Ps_calc'),
                   ('composition', 'Fl_I:tot:composition')]
        self.add_subsystem('ideal_flow', ideal_flow, 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 = om.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.options['reraise_child_analysiserror'] = False
            newton.linesearch = om.BoundsEnforceLS()
            newton.linesearch.options['bound_enforcement'] = 'scalar'

            newton.linesearch.options['iprint'] = -1
            self.linear_solver = om.DirectSolver(assemble_jac=True)

        super().setup()
コード例 #9
0
ファイル: test_ducts.py プロジェクト: eytanadler/openconcept
            def setup(self):
                design = self.options['design']

                USE_TABULAR = False
                if USE_TABULAR:
                    self.options['thermo_method'] = 'TABULAR'
                    self.options['thermo_data'] = pyc.AIR_JETA_TAB_SPEC
                else:
                    self.options['thermo_method'] = 'CEA'
                    self.options['thermo_data'] = pyc.species_data.janaf
                    FUEL_TYPE = 'JP-7'

                self.add_subsystem('fc', pyc.FlightConditions())
                # ram_recovery | ram_recovery
                # MN | area
                self.add_subsystem('inlet', pyc.Inlet())
                # dPqP | s_dPqP
                # Q_dot | Q_dot
                # MN | area
                self.add_subsystem('duct', pyc.Duct())
                # Ps_exhaust
                # dPqP
                self.add_subsystem('nozz', pyc.Nozzle(lossCoef='Cfg'))
                self.add_subsystem(
                    'perf', pyc.Performance(num_nozzles=1, num_burners=0))

                balance = om.BalanceComp()
                if design:
                    self.add_subsystem(
                        'iv',
                        om.IndepVarComp('nozzle_area', 60., units='inch**2'))
                    balance.add_balance('W',
                                        units='kg/s',
                                        eq_units='inch**2',
                                        val=2.,
                                        lower=0.05,
                                        upper=10.)
                    self.add_subsystem('balance', balance)
                    self.connect('iv.nozzle_area', 'balance.rhs:W')
                    self.connect('nozz.Throat:stat:area', 'balance.lhs:W')
                else:
                    balance.add_balance('W',
                                        units='kg/s',
                                        eq_units='inch**2',
                                        val=2.,
                                        lower=0.05,
                                        upper=10.)
                    self.add_subsystem('balance', balance)
                    self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

                self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I')
                self.pyc_connect_flow('inlet.Fl_O', 'duct.Fl_I')
                self.pyc_connect_flow('duct.Fl_O', 'nozz.Fl_I')

                self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')
                self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
                self.connect('duct.Fl_O:tot:P', 'perf.Pt3')
                self.connect('inlet.F_ram', 'perf.ram_drag')
                self.connect('nozz.Fg', 'perf.Fg_0')

                self.connect('balance.W', 'fc.W')

                newton = self.nonlinear_solver = om.NewtonSolver()
                newton.options['atol'] = 1e-12
                newton.options['rtol'] = 1e-12
                newton.options['iprint'] = 2
                newton.options['maxiter'] = 10
                newton.options['solve_subsystems'] = True
                newton.options['max_sub_solves'] = 10
                newton.options['reraise_child_analysiserror'] = False

                newton.linesearch = om.BoundsEnforceLS()
                newton.linesearch.options['bound_enforcement'] = 'scalar'
                # newton.linesearch.options['print_bound_enforce'] = True
                # newton.linesearch.options['iprint'] = -1
                self.linear_solver = om.DirectSolver(assemble_jac=True)
                super().setup()
コード例 #10
0
    def setup(self):

        thermo_spec = pyc.species_data.janaf
        design = self.options['design']

        # Add engine elements
        self.add_subsystem(
            'fc',
            pyc.FlightConditions(thermo_data=thermo_spec,
                                 elements=pyc.AIR_MIX))
        self.add_subsystem(
            'inlet',
            pyc.Inlet(design=design,
                      thermo_data=thermo_spec,
                      elements=pyc.AIR_MIX))
        self.add_subsystem('comp',
                           pyc.Compressor(
                               map_data=pyc.AXI5,
                               design=design,
                               thermo_data=thermo_spec,
                               elements=pyc.AIR_MIX,
                           ),
                           promotes_inputs=['Nmech'])
        self.add_subsystem(
            'burner',
            pyc.Combustor(design=design,
                          thermo_data=thermo_spec,
                          inflow_elements=pyc.AIR_MIX,
                          air_fuel_elements=pyc.AIR_FUEL_MIX,
                          fuel_type='JP-7'))
        self.add_subsystem('turb',
                           pyc.Turbine(
                               map_data=pyc.LPT2269,
                               design=design,
                               thermo_data=thermo_spec,
                               elements=pyc.AIR_FUEL_MIX,
                           ),
                           promotes_inputs=['Nmech'])
        self.add_subsystem(
            'nozz',
            pyc.Nozzle(nozzType='CD',
                       lossCoef='Cv',
                       thermo_data=thermo_spec,
                       elements=pyc.AIR_FUEL_MIX))
        self.add_subsystem('shaft',
                           pyc.Shaft(num_ports=2),
                           promotes_inputs=['Nmech'])
        self.add_subsystem('perf', pyc.Performance(num_nozzles=1,
                                                   num_burners=1))

        # Connect flow stations
        pyc.connect_flow(self, 'fc.Fl_O', 'inlet.Fl_I', connect_w=False)
        pyc.connect_flow(self, 'inlet.Fl_O', 'comp.Fl_I')
        pyc.connect_flow(self, 'comp.Fl_O', 'burner.Fl_I')
        pyc.connect_flow(self, 'burner.Fl_O', 'turb.Fl_I')
        pyc.connect_flow(self, 'turb.Fl_O', 'nozz.Fl_I')

        # Connect turbomachinery elements to shaft
        self.connect('comp.trq', 'shaft.trq_0')
        self.connect('turb.trq', 'shaft.trq_1')

        # Connnect nozzle exhaust to freestream static conditions
        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')

        # Connect outputs to pefromance element
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('comp.Fl_O:tot:P', 'perf.Pt3')
        self.connect('burner.Wfuel', 'perf.Wfuel_0')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        # Add balances for design and off-design
        balance = self.add_subsystem('balance', om.BalanceComp())
        if design:

            balance.add_balance('W', units='lbm/s', eq_units='lbf')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('perf.Fn', 'balance.lhs:W')

            balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR')

            balance.add_balance('turb_PR',
                                val=1.5,
                                lower=1.001,
                                upper=8,
                                eq_units='hp',
                                rhs_val=0.)
            self.connect('balance.turb_PR', 'turb.PR')
            self.connect('shaft.pwr_net', 'balance.lhs:turb_PR')

        else:

            balance.add_balance('FAR', eq_units='lbf', lower=1e-4, val=.3)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('perf.Fn', 'balance.lhs:FAR')

            balance.add_balance('Nmech',
                                val=1.5,
                                units='rpm',
                                lower=500.,
                                eq_units='hp',
                                rhs_val=0.)
            self.connect('balance.Nmech', 'Nmech')
            self.connect('shaft.pwr_net', 'balance.lhs:Nmech')

            balance.add_balance('W',
                                val=168.0,
                                units='lbm/s',
                                eq_units='inch**2')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

        # Setup solver to converge engine
        self.set_order([
            'balance', 'fc', 'inlet', 'comp', 'burner', 'turb', 'nozz',
            'shaft', 'perf'
        ])

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-6
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 15
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 100
        newton.linesearch = om.BoundsEnforceLS()
        # newton.linesearch = ArmijoGoldsteinLS()
        # newton.linesearch.options['c'] = .0001
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #11
0
    def setup(self):

        thermo_method = self.options['thermo_method']
        design = self.options['design']
        thermo_data = self.options['thermo_data']

        flow1_elements = self.options['Fl_I1_elements']
        in_flow = FlowIn(fl_name='Fl_I1')
        self.add_subsystem('in_flow1', in_flow, promotes=['Fl_I1:*'])

        flow2_elements = self.options['Fl_I2_elements']
        in_flow = FlowIn(fl_name='Fl_I2')
        self.add_subsystem('in_flow2', in_flow, promotes=['Fl_I2:*'])

        if design:
            # internal flow station to compute the area that is needed to match the static pressures
            if self.options['designed_stream'] == 1:
                Fl1_stat = Thermo(mode='static_Ps',
                                  fl_name="Fl_I1_calc:stat",
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'elements': flow1_elements,
                                      'spec': thermo_data
                                  })
                self.add_subsystem('Fl_I1_stat_calc',
                                   Fl1_stat,
                                   promotes_inputs=[('composition',
                                                     'Fl_I1:tot:composition'),
                                                    ('S', 'Fl_I1:tot:S'),
                                                    ('ht', 'Fl_I1:tot:h'),
                                                    ('W', 'Fl_I1:stat:W'),
                                                    ('Ps', 'Fl_I2:stat:P')],
                                   promotes_outputs=['Fl_I1_calc:stat*'])

                self.add_subsystem('area_calc',
                                   AreaSum(),
                                   promotes_inputs=['Fl_I2:stat:area'],
                                   promotes_outputs=[('area_sum', 'area')])
                self.connect('Fl_I1_calc:stat:area',
                             'area_calc.Fl_I1:stat:area')

            else:
                Fl2_stat = Thermo(mode='static_Ps',
                                  fl_name="Fl_I2_calc:stat",
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'elements': flow2_elements,
                                      'spec': thermo_data
                                  })
                self.add_subsystem('Fl_I2_stat_calc',
                                   Fl2_stat,
                                   promotes_inputs=[('composition',
                                                     'Fl_I2:tot:composition'),
                                                    ('S', 'Fl_I2:tot:S'),
                                                    ('ht', 'Fl_I2:tot:h'),
                                                    ('W', 'Fl_I2:stat:W'),
                                                    ('Ps', 'Fl_I1:stat:P')],
                                   promotes_outputs=['Fl_I2_calc:stat:*'])

                self.add_subsystem('area_calc',
                                   AreaSum(),
                                   promotes_inputs=['Fl_I1:stat:area'],
                                   promotes_outputs=[('area_sum', 'area')])
                self.connect('Fl_I2_calc:stat:area',
                             'area_calc.Fl_I2:stat:area')

        else:
            if self.options['designed_stream'] == 1:
                Fl1_stat = Thermo(mode='static_A',
                                  fl_name="Fl_I1_calc:stat",
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'elements': flow1_elements,
                                      'spec': thermo_data
                                  })
                self.add_subsystem('Fl_I1_stat_calc',
                                   Fl1_stat,
                                   promotes_inputs=[
                                       ('composition',
                                        'Fl_I1:tot:composition'),
                                       ('S', 'Fl_I1:tot:S'),
                                       ('ht', 'Fl_I1:tot:h'),
                                       ('W', 'Fl_I1:stat:W'),
                                       ('guess:Pt', 'Fl_I1:tot:P'),
                                       ('guess:gamt', 'Fl_I1:tot:gamma')
                                   ],
                                   promotes_outputs=['Fl_I1_calc:stat*'])

            else:
                Fl2_stat = Thermo(mode='static_A',
                                  fl_name="Fl_I2_calc:stat",
                                  method=thermo_method,
                                  thermo_kwargs={
                                      'elements': flow2_elements,
                                      'spec': thermo_data
                                  })
                self.add_subsystem('Fl_I2_stat_calc',
                                   Fl2_stat,
                                   promotes_inputs=[
                                       ('composition',
                                        'Fl_I2:tot:composition'),
                                       ('S', 'Fl_I2:tot:S'),
                                       ('ht', 'Fl_I2:tot:h'),
                                       ('W', 'Fl_I2:stat:W'),
                                       ('guess:Pt', 'Fl_I2:tot:P'),
                                       ('guess:gamt', 'Fl_I2:tot:gamma')
                                   ],
                                   promotes_outputs=['Fl_I2_calc:stat*'])

        self.add_subsystem('extraction_ratio',
                           om.ExecComp('ER=Pt1/Pt2',
                                       Pt1={'units': 'Pa'},
                                       Pt2={'units': 'Pa'}),
                           promotes_inputs=[('Pt1', 'Fl_I1:tot:P'),
                                            ('Pt2', 'Fl_I2:tot:P')],
                           promotes_outputs=['ER'])

        self.add_subsystem('mix_flow',
                           ThermoAdd(mix_thermo_data=thermo_data,
                                     mix_mode='flow',
                                     mix_names='mix',
                                     inflow_elements=flow1_elements,
                                     mix_elements=flow2_elements),
                           promotes_inputs=[('Fl_I:stat:W', 'Fl_I1:stat:W'),
                                            ('Fl_I:tot:composition',
                                             'Fl_I1:tot:composition'),
                                            ('Fl_I:tot:h', 'Fl_I1:tot:h'),
                                            ('mix:W', 'Fl_I2:stat:W'),
                                            ('mix:composition',
                                             'Fl_I2:tot:composition'),
                                            ('mix:h', 'Fl_I2:tot:h')])

        if self.options['designed_stream'] == 1:
            self.add_subsystem('impulse_mix',
                               MixImpulse(),
                               promotes_inputs=[
                                   ('Fl_I1:stat:W', 'Fl_I1_calc:stat:W'),
                                   ('Fl_I1:stat:P', 'Fl_I1_calc:stat:P'),
                                   ('Fl_I1:stat:V', 'Fl_I1_calc:stat:V'),
                                   ('Fl_I1:stat:area', 'Fl_I1_calc:stat:area'),
                                   'Fl_I2:stat:W', 'Fl_I2:stat:P',
                                   'Fl_I2:stat:V', 'Fl_I2:stat:area'
                               ])
        else:
            self.add_subsystem('impulse_mix',
                               MixImpulse(),
                               promotes_inputs=[
                                   'Fl_I1:stat:W', 'Fl_I1:stat:P',
                                   'Fl_I1:stat:V', 'Fl_I1:stat:area',
                                   ('Fl_I2:stat:W', 'Fl_I2_calc:stat:W'),
                                   ('Fl_I2:stat:P', 'Fl_I2_calc:stat:P'),
                                   ('Fl_I2:stat:V', 'Fl_I2_calc:stat:V'),
                                   ('Fl_I2:stat:area', 'Fl_I2_calc:stat:area')
                               ])

        # group to converge for the impulse balance
        conv = self.add_subsystem('impulse_converge',
                                  om.Group(),
                                  promotes=['*'])

        if self.options['internal_solver']:
            newton = conv.nonlinear_solver = om.NewtonSolver()
            newton.options['maxiter'] = 30
            newton.options['atol'] = 1e-2
            newton.options['solve_subsystems'] = True
            newton.options['max_sub_solves'] = 20
            newton.options['reraise_child_analysiserror'] = False
            newton.linesearch = om.BoundsEnforceLS()
            newton.linesearch.options['bound_enforcement'] = 'scalar'
            newton.linesearch.options['iprint'] = -1
            conv.linear_solver = om.DirectSolver(assemble_jac=True)

        out_tot = Thermo(mode='total_hP',
                         fl_name='Fl_O:tot',
                         method=thermo_method,
                         thermo_kwargs={
                             'elements': self.options['Fl_I1_elements'],
                             'spec': thermo_data
                         })
        conv.add_subsystem('out_tot', out_tot, promotes_outputs=['Fl_O:tot:*'])
        self.connect('mix_flow.composition_out', 'out_tot.composition')
        self.connect('mix_flow.mass_avg_h', 'out_tot.h')
        # note: gets Pt from the balance comp

        out_stat = Thermo(mode='static_A',
                          fl_name='Fl_O:stat',
                          method=thermo_method,
                          thermo_kwargs={
                              'elements': self.options['Fl_I1_elements'],
                              'spec': thermo_data
                          })
        conv.add_subsystem('out_stat',
                           out_stat,
                           promotes_outputs=['Fl_O:stat:*'],
                           promotes_inputs=[
                               'area',
                           ])
        self.connect('mix_flow.composition_out', 'out_stat.composition')
        self.connect('mix_flow.Wout', 'out_stat.W')
        conv.connect('Fl_O:tot:S', 'out_stat.S')
        self.connect('mix_flow.mass_avg_h', 'out_stat.ht')
        conv.connect('Fl_O:tot:P', 'out_stat.guess:Pt')
        conv.connect('Fl_O:tot:gamma', 'out_stat.guess:gamt')

        conv.add_subsystem('imp_out', Impulse())
        conv.connect('Fl_O:stat:P', 'imp_out.P')
        conv.connect('Fl_O:stat:area', 'imp_out.area')
        conv.connect('Fl_O:stat:V', 'imp_out.V')
        conv.connect('Fl_O:stat:W', 'imp_out.W')

        balance = conv.add_subsystem('balance', om.BalanceComp())
        balance.add_balance('P_tot',
                            val=100,
                            units='psi',
                            eq_units='N',
                            lower=1e-3,
                            upper=10000)
        conv.connect('balance.P_tot', 'out_tot.P')
        conv.connect('imp_out.impulse', 'balance.lhs:P_tot')
        self.connect(
            'impulse_mix.impulse_mix', 'balance.rhs:P_tot'
        )  #note that this connection comes from outside the convergence group
コード例 #12
0
    def setup(self):
        thermo_spec = pyc.species_data.janaf
        design = self.options['design']

        self.pyc_add_element(
            'fc',
            pyc.FlightConditions(thermo_data=thermo_spec,
                                 elements=pyc.AIR_ELEMENTS))
        # Inlet Components
        self.pyc_add_element(
            'inlet',
            pyc.Inlet(design=design,
                      thermo_data=thermo_spec,
                      elements=pyc.AIR_ELEMENTS))
        self.pyc_add_element(
            'inlet_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_ELEMENTS))
        # Fan Components - Split here for CFD integration Add a CFDStart Compomponent
        self.pyc_add_element('fan',
                             pyc.Compressor(map_data=pyc.AXI5,
                                            design=design,
                                            thermo_data=thermo_spec,
                                            elements=pyc.AIR_ELEMENTS,
                                            map_extrap=True),
                             promotes_inputs=[('Nmech', 'LP_Nmech')])
        self.pyc_add_element(
            'splitter',
            pyc.Splitter(design=design,
                         thermo_data=thermo_spec,
                         elements=pyc.AIR_ELEMENTS))
        # Core Stream components
        self.pyc_add_element(
            'splitter_core_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_ELEMENTS))
        self.pyc_add_element('lpc',
                             pyc.Compressor(map_data=pyc.LPCMap,
                                            design=design,
                                            thermo_data=thermo_spec,
                                            elements=pyc.AIR_ELEMENTS,
                                            map_extrap=True),
                             promotes_inputs=[('Nmech', 'LP_Nmech')])
        self.pyc_add_element(
            'lpc_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_ELEMENTS))
        self.pyc_add_element('hpc',
                             pyc.Compressor(map_data=pyc.HPCMap,
                                            design=design,
                                            thermo_data=thermo_spec,
                                            elements=pyc.AIR_ELEMENTS,
                                            bleed_names=['cool1'],
                                            map_extrap=True),
                             promotes_inputs=[('Nmech', 'HP_Nmech')])
        self.pyc_add_element(
            'bld3', pyc.BleedOut(design=design, bleed_names=['cool3']))
        self.pyc_add_element(
            'burner',
            pyc.Combustor(design=design,
                          thermo_data=thermo_spec,
                          inflow_elements=pyc.AIR_ELEMENTS,
                          air_fuel_elements=pyc.AIR_FUEL_ELEMENTS,
                          fuel_type='Jet-A(g)'))
        self.pyc_add_element('hpt',
                             pyc.Turbine(map_data=pyc.HPTMap,
                                         design=design,
                                         thermo_data=thermo_spec,
                                         elements=pyc.AIR_FUEL_ELEMENTS,
                                         bleed_names=['cool3'],
                                         map_extrap=True),
                             promotes_inputs=[('Nmech', 'HP_Nmech')])
        self.pyc_add_element(
            'hpt_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_FUEL_ELEMENTS))
        self.pyc_add_element('lpt',
                             pyc.Turbine(map_data=pyc.LPTMap,
                                         design=design,
                                         thermo_data=thermo_spec,
                                         elements=pyc.AIR_FUEL_ELEMENTS,
                                         bleed_names=['cool1'],
                                         map_extrap=True),
                             promotes_inputs=[('Nmech', 'LP_Nmech')])
        self.pyc_add_element(
            'lpt_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_FUEL_ELEMENTS))
        # Bypass Components
        self.pyc_add_element(
            'bypass_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_ELEMENTS))
        # Mixer component
        self.pyc_add_element(
            'mixer',
            pyc.Mixer(design=design,
                      designed_stream=1,
                      Fl_I1_elements=pyc.AIR_FUEL_ELEMENTS,
                      Fl_I2_elements=pyc.AIR_ELEMENTS))
        self.pyc_add_element(
            'mixer_duct',
            pyc.Duct(design=design,
                     thermo_data=thermo_spec,
                     elements=pyc.AIR_FUEL_ELEMENTS))
        # Afterburner Components
        self.pyc_add_element(
            'afterburner',
            pyc.Combustor(design=design,
                          thermo_data=thermo_spec,
                          inflow_elements=pyc.AIR_FUEL_ELEMENTS,
                          air_fuel_elements=pyc.AIR_FUEL_ELEMENTS,
                          fuel_type='Jet-A(g)'))
        # End CFD HERE
        # Nozzle
        self.pyc_add_element(
            'mixed_nozz',
            pyc.Nozzle(nozzType='CD',
                       lossCoef='Cfg',
                       thermo_data=thermo_spec,
                       elements=pyc.AIR_FUEL_ELEMENTS))

        # Mechanical components
        self.pyc_add_element('lp_shaft',
                             pyc.Shaft(num_ports=3),
                             promotes_inputs=[('Nmech', 'LP_Nmech')])
        self.pyc_add_element('hp_shaft',
                             pyc.Shaft(num_ports=2),
                             promotes_inputs=[('Nmech', 'HP_Nmech')])

        # Aggregating component
        self.pyc_add_element('perf',
                             pyc.Performance(num_nozzles=1, num_burners=2))

        # Connnect flow path
        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I')
        self.pyc_connect_flow('inlet.Fl_O', 'inlet_duct.Fl_I')
        self.pyc_connect_flow('inlet_duct.Fl_O', 'fan.Fl_I')
        self.pyc_connect_flow('fan.Fl_O', 'splitter.Fl_I')
        # Core connections
        self.pyc_connect_flow('splitter.Fl_O1', 'splitter_core_duct.Fl_I')
        self.pyc_connect_flow('splitter_core_duct.Fl_O', 'lpc.Fl_I')
        self.pyc_connect_flow('lpc.Fl_O', 'lpc_duct.Fl_I')
        self.pyc_connect_flow('lpc_duct.Fl_O', 'hpc.Fl_I')
        self.pyc_connect_flow('hpc.Fl_O', 'bld3.Fl_I')
        self.pyc_connect_flow('bld3.Fl_O', 'burner.Fl_I')
        self.pyc_connect_flow('burner.Fl_O', 'hpt.Fl_I')
        self.pyc_connect_flow('hpt.Fl_O', 'hpt_duct.Fl_I')
        self.pyc_connect_flow('hpt_duct.Fl_O', 'lpt.Fl_I')
        self.pyc_connect_flow('lpt.Fl_O', 'lpt_duct.Fl_I')
        self.pyc_connect_flow('lpt_duct.Fl_O', 'mixer.Fl_I1')
        # Bypass Connections
        self.pyc_connect_flow('splitter.Fl_O2', 'bypass_duct.Fl_I')
        self.pyc_connect_flow('bypass_duct.Fl_O', 'mixer.Fl_I2')

        #Mixer Connections
        self.pyc_connect_flow('mixer.Fl_O', 'mixer_duct.Fl_I')
        # After Burner
        self.pyc_connect_flow('mixer_duct.Fl_O', 'afterburner.Fl_I')

        # Nozzle
        self.pyc_connect_flow('afterburner.Fl_O', 'mixed_nozz.Fl_I')

        # Connect cooling flows
        self.pyc_connect_flow('hpc.cool1', 'lpt.cool1', connect_stat=False)
        self.pyc_connect_flow('bld3.cool3', 'hpt.cool3', connect_stat=False)

        # Make additional model connections
        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('afterburner.Wfuel', 'perf.Wfuel_1')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('mixed_nozz.Fg', 'perf.Fg_0')

        self.connect('fan.trq', 'lp_shaft.trq_0')
        self.connect('lpc.trq', 'lp_shaft.trq_1')
        self.connect('lpt.trq', 'lp_shaft.trq_2')
        self.connect('hpc.trq', 'hp_shaft.trq_0')
        self.connect('hpt.trq', 'hp_shaft.trq_1')
        self.connect('fc.Fl_O:stat:P', 'mixed_nozz.Ps_exhaust')

        # Add balence components to close the implicit components
        balance = self.add_subsystem('balance', om.BalanceComp())
        if design:
            balance.add_balance('W',
                                lower=1e-3,
                                upper=200.,
                                units='lbm/s',
                                eq_units='lbf')
            self.connect('balance.W', 'fc.W')
            self.connect('perf.Fn', 'balance.lhs:W')
            # self.add_subsystem('wDV',IndepVarComp('wDes',100,units='lbm/s'))
            # self.connect('wDV.wDes','fc.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', 'afterburner.Fl_I:FAR')
            self.connect('afterburner.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:

            balance.add_balance('W',
                                lower=1e-3,
                                upper=200.,
                                units='lbm/s',
                                eq_units='inch**2')
            self.connect('balance.W', 'fc.W')
            self.connect('mixed_nozz.Throat:stat:area', 'balance.lhs:W')

            balance.add_balance('BPR', lower=0.25, upper=5.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=.06,
                                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=.06,
                                val=.017)
            self.connect('balance.FAR_ab', 'afterburner.Fl_I:FAR')
            self.connect('afterburner.Fl_O:tot:T', 'balance.lhs:FAR_ab')

            balance.add_balance('LP_Nmech',
                                val=1.,
                                units='rpm',
                                lower=500.,
                                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=500.,
                                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')

        # Off design
        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-10
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 10
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 100
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #13
0
    def setup(self):

        design = self.options['design']

        # NOTE: DEFAULT TABULAR thermo doesn't include WAR, so must use CEA here
        # (or build your own thermo tables)
        self.options['thermo_method'] = 'CEA'
        self.options['thermo_data'] = pyc.species_data.wet_air

        self.add_subsystem(
            'fc',
            pyc.FlightConditions(composition=pyc.CEA_AIR_COMPOSITION,
                                 reactant='Water',
                                 mix_ratio_name='WAR'))

        self.add_subsystem('inlet', pyc.Inlet())
        self.add_subsystem(
            'fan', pyc.Compressor(map_data=pyc.FanMap, map_extrap=True))
        self.add_subsystem('nozz', pyc.Nozzle())
        self.add_subsystem('perf', pyc.Performance(num_nozzles=1,
                                                   num_burners=0))

        balance = om.BalanceComp()
        if design:
            self.add_subsystem('shaft',
                               om.IndepVarComp('Nmech', 1., units='rpm'))
            self.connect('shaft.Nmech', 'fan.Nmech')

            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='hp',
                                val=50.,
                                lower=1.,
                                upper=500.)
            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:W', 'pwr_target')])
            self.connect('fan.power', 'balance.lhs:W')

        else:
            # vary mass flow till the nozzle area matches the design values
            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='inch**2',
                                val=50,
                                lower=1.,
                                upper=500.)
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

            balance.add_balance('Nmech',
                                val=1.,
                                units='rpm',
                                lower=0.1,
                                upper=2.0,
                                eq_units='hp')
            self.connect('balance.Nmech', 'fan.Nmech')
            self.connect('fan.power', 'balance.lhs:Nmech')

            # self.add_subsystem('shaft', om.IndepVarComp('Nmech', 1., units='rpm'))
            # self.connect('shaft.Nmech', 'fan.Nmech')

            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:Nmech', 'pwr_target')])

        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I')
        self.pyc_connect_flow('inlet.Fl_O', 'fan.Fl_I')
        self.pyc_connect_flow('fan.Fl_O', 'nozz.Fl_I')

        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('fan.Fl_O:tot:P', 'perf.Pt3')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        self.connect('balance.W', 'fc.W')

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-12
        newton.options['rtol'] = 1e-12
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 10
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 10
        newton.options['reraise_child_analysiserror'] = False
        #
        # newton.linesearch = om.ArmijoGoldsteinLS()
        # newton.linesearch.options['maxiter'] = 3
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        # newton.linesearch.options['print_bound_enforce'] = True
        # newton.linesearch.options['iprint'] = -1
        #
        self.linear_solver = om.DirectSolver(assemble_jac=True)

        # base_class setup should be called as the last thing in your setup
        super().setup()
コード例 #14
0
    def setup(self):

        design = self.options['design']

        # NOTE: DEFAULT TABULAR thermo doesn't include WAR, so must use CEA here
        # (or build your own thermo tables)

        self.options['thermo_method'] = 'CEA'
        self.options['thermo_data'] = pyc.species_data.wet_air

        # Add engine elements
        self.add_subsystem('fc', pyc.FlightConditions(composition=pyc.CEA_AIR_COMPOSITION, 
                                                      reactant='Water',
                                                      mix_ratio_name='WAR')) 

        self.add_subsystem('inlet', pyc.Inlet())
        self.add_subsystem('comp', pyc.Compressor(map_data=pyc.AXI5),
                                    promotes_inputs=['Nmech'])

        self.add_subsystem('burner', pyc.Combustor(fuel_type='JP-7'))
        self.add_subsystem('turb', pyc.Turbine(map_data=pyc.LPT2269),
                                    promotes_inputs=['Nmech'])
        self.add_subsystem('nozz', pyc.Nozzle(nozzType='CD', lossCoef='Cv'))
        self.add_subsystem('shaft', pyc.Shaft(num_ports=2), promotes_inputs=['Nmech'])
        self.add_subsystem('perf', pyc.Performance(num_nozzles=1, num_burners=1))

        # Connect flow stations
        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I', connect_w=False)
        self.pyc_connect_flow('inlet.Fl_O', 'comp.Fl_I')
        self.pyc_connect_flow('comp.Fl_O', 'burner.Fl_I')
        self.pyc_connect_flow('burner.Fl_O', 'turb.Fl_I')
        self.pyc_connect_flow('turb.Fl_O', 'nozz.Fl_I')

        # Connect turbomachinery elements to shaft
        self.connect('comp.trq', 'shaft.trq_0')
        self.connect('turb.trq', 'shaft.trq_1')

        # Connnect nozzle exhaust to freestream static conditions
        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')

        # Connect outputs to pefromance element
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('comp.Fl_O:tot:P', 'perf.Pt3')
        self.connect('burner.Wfuel', 'perf.Wfuel_0')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        # Add balances for design and off-design
        balance = self.add_subsystem('balance', om.BalanceComp())
        if design:

            balance.add_balance('W', units='lbm/s', eq_units='lbf')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('perf.Fn', 'balance.lhs:W')

            balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR')

            balance.add_balance('turb_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.)
            self.connect('balance.turb_PR', 'turb.PR')
            self.connect('shaft.pwr_net', 'balance.lhs:turb_PR')

        else:

            balance.add_balance('FAR', eq_units='lbf', lower=1e-4, val=.3)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('perf.Fn', 'balance.lhs:FAR')

            balance.add_balance('Nmech', val=1.5, units='rpm', lower=500., eq_units='hp', rhs_val=0.)
            self.connect('balance.Nmech', 'Nmech')
            self.connect('shaft.pwr_net', 'balance.lhs:Nmech')

            balance.add_balance('W', val=168.0, units='lbm/s', eq_units='inch**2')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

        # Setup solver to converge engine
        self.set_order(['balance', 'fc', 'inlet', 'comp', 'burner', 'turb', 'nozz', 'shaft', 'perf'])

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-6
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 15
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 100
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        # newton.linesearch = ArmijoGoldsteinLS()
        # newton.linesearch.options['c'] = .0001
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver(assemble_jac=True)

        super().setup()
コード例 #15
0
    def setup(self):
        thermo_method = self.options['thermo_method']
        thermo_data = self.options['thermo_data']
        reactant = self.options['reactant']
        mix_ratio_name = self.options['mix_ratio_name']

        # composition = self.Fl_O_data['Fl_O']
        composition = self.options['composition']

        self.add_subsystem('ambient', Ambient(),
                           promotes=('alt', 'dTs'))  # inputs

        conv = self.add_subsystem('conv', om.Group(), promotes=['*'])
        if reactant is not False:
            proms = ['Fl_O:*', 'MN', 'W', mix_ratio_name]
        else:
            proms = ['Fl_O:*', 'MN', 'W']
        fs_start = conv.add_subsystem('fs',
                                      FlowStart(thermo_method=thermo_method,
                                                thermo_data=thermo_data,
                                                composition=composition,
                                                reactant=reactant,
                                                mix_ratio_name=mix_ratio_name),
                                      promotes=proms)

        # need to manually call this in this setup, because we have an element within an element
        fs_start.pyc_setup_output_ports()

        balance = conv.add_subsystem('balance', om.BalanceComp())
        balance.add_balance('Tt',
                            val=500.0,
                            lower=1e-4,
                            units='degR',
                            desc='Total temperature',
                            eq_units='degR')
        balance.add_balance('Pt',
                            val=14.696,
                            lower=1e-4,
                            units='psi',
                            desc='Total pressure',
                            eq_units='psi')
        # sub.set_order(['fs','balance'])

        newton = conv.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-10
        newton.options['rtol'] = 1e-10
        newton.options['maxiter'] = 10
        newton.options['iprint'] = -1
        newton.options['solve_subsystems'] = True
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'

        newton.linesearch.options['iprint'] = -1
        # newton.linesearch.options['solve_subsystems'] = True

        conv.linear_solver = om.DirectSolver(assemble_jac=True)

        self.connect('ambient.Ps', 'balance.rhs:Pt')
        self.connect('ambient.Ts', 'balance.rhs:Tt')

        self.connect('balance.Pt', 'fs.P')
        self.connect('balance.Tt', 'fs.T')

        self.connect('Fl_O:stat:P', 'balance.lhs:Pt')
        self.connect('Fl_O:stat:T', 'balance.lhs:Tt')

        # self.set_order(['ambient', 'subgroup'])

        super().setup()
コード例 #16
0
    def setup(self):

        thermo_spec = pyc.species_data.wet_air  #special species library is called that allows for using initial compositions that include both H and C
        design = self.options['design']

        self.pyc_add_element(
            'fc',
            pyc.FlightConditions(thermo_data=thermo_spec,
                                 use_WAR=True,
                                 elements=pyc.WET_AIR_ELEMENTS)
        )  #WET_AIR_ELEMENTS contains standard dry air compounds as well as H2O

        self.pyc_add_element(
            'inlet',
            pyc.Inlet(design=design,
                      thermo_data=thermo_spec,
                      elements=pyc.WET_AIR_ELEMENTS))
        self.pyc_add_element(
            'fan',
            pyc.Compressor(thermo_data=thermo_spec,
                           elements=pyc.WET_AIR_ELEMENTS,
                           design=design,
                           map_data=pyc.FanMap,
                           map_extrap=True))
        self.pyc_add_element(
            'nozz',
            pyc.Nozzle(thermo_data=thermo_spec, elements=pyc.WET_AIR_ELEMENTS))
        self.pyc_add_element('perf',
                             pyc.Performance(num_nozzles=1, num_burners=0))

        balance = om.BalanceComp()
        if design:
            self.add_subsystem('shaft',
                               om.IndepVarComp('Nmech', 1., units='rpm'))
            self.connect('shaft.Nmech', 'fan.Nmech')

            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='hp',
                                val=50.,
                                lower=1.,
                                upper=500.)
            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:W', 'pwr_target')])
            self.connect('fan.power', 'balance.lhs:W')

        else:
            # vary mass flow till the nozzle area matches the design values
            balance.add_balance('W',
                                units='lbm/s',
                                eq_units='inch**2',
                                val=50,
                                lower=1.,
                                upper=500.)
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

            balance.add_balance('Nmech',
                                val=1.,
                                units='rpm',
                                lower=0.1,
                                upper=2.0,
                                eq_units='hp')
            self.connect('balance.Nmech', 'fan.Nmech')
            self.connect('fan.power', 'balance.lhs:Nmech')

            # self.add_subsystem('shaft', om.IndepVarComp('Nmech', 1., units='rpm'))
            # self.connect('shaft.Nmech', 'fan.Nmech')

            self.add_subsystem('balance',
                               balance,
                               promotes_inputs=[('rhs:Nmech', 'pwr_target')])

        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I')
        self.pyc_connect_flow('inlet.Fl_O', 'fan.Fl_I')
        self.pyc_connect_flow('fan.Fl_O', 'nozz.Fl_I')

        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('fan.Fl_O:tot:P', 'perf.Pt3')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        self.connect('balance.W', 'fc.W')

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-12
        newton.options['rtol'] = 1e-12
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 10
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 10
        newton.options['reraise_child_analysiserror'] = False
        #
        # newton.linesearch = om.ArmijoGoldsteinLS()
        # newton.linesearch.options['maxiter'] = 3
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        # newton.linesearch.options['print_bound_enforce'] = True
        # newton.linesearch.options['iprint'] = -1
        #
        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #17
0
ファイル: test_ducts.py プロジェクト: eytanadler/openconcept
def run_problem(ram_recovery=1.0,
                dPqP=0.0,
                heat_in=0.0,
                cfg=0.98,
                oc_use_dpqp=False,
                list_output=True,
                oc_areas=None,
                oc_delta_p=0.0):
    prob = om.Problem()
    model = prob.model = om.Group()

    iv = model.add_subsystem('iv', om.IndepVarComp())
    iv.add_output('area_2', val=408, units='inch**2')

    # add the pycycle duct
    if HAS_PYCYCLE:
        mp_duct = model.add_subsystem('pyduct', MPDuct())
        prob.model.connect('pyduct.design.fc.Fl_O:stat:T', 'fltcond|T')
        prob.model.connect('pyduct.design.fc.Fl_O:stat:P', 'fltcond|p')
        prob.model.connect('pyduct.design.fc.Fl_O:stat:V', 'fltcond|Utrue')
    else:
        iv.add_output('fltcond|T', val=223.15013852435118, units='K')
        iv.add_output('fltcond|p', val=26436.23048846425, units='Pa')
        iv.add_output('fltcond|Utrue',
                      val=0.8 * 299.57996571373235,
                      units='m/s')
        prob.model.connect('iv.fltcond|T', 'fltcond|T')
        prob.model.connect('iv.fltcond|p', 'fltcond|p')
        prob.model.connect('iv.fltcond|Utrue', 'fltcond|Utrue')

    # add the openconcept duct
    oc = model.add_subsystem('oc',
                             ImplicitCompressibleDuct_ExternalHX(num_nodes=1,
                                                                 cfg=cfg),
                             promotes_inputs=[('p_inf', 'fltcond|p'),
                                              ('T_inf', 'fltcond|T'),
                                              ('Utrue', 'fltcond|Utrue')])

    newton = oc.nonlinear_solver = om.NewtonSolver()
    newton.options['atol'] = 1e-12
    newton.options['rtol'] = 1e-12
    newton.options['iprint'] = -1
    newton.options['maxiter'] = 10
    newton.options['solve_subsystems'] = True
    newton.options['max_sub_solves'] = 10
    newton.options['reraise_child_analysiserror'] = False
    newton.linesearch = om.BoundsEnforceLS()
    newton.linesearch.options['bound_enforcement'] = 'scalar'
    oc.linear_solver = om.DirectSolver(assemble_jac=True)

    prob.model.connect('iv.area_2', ['oc.area_2', 'oc.area_3'])

    # iv.add_output('cp', val=1002.93, units='J/kg/K')
    # iv.add_output('pressure_recovery_1', val=np.ones((nn,)))
    # iv.add_output('loss_factor_1', val=0.0)
    # iv.add_output('delta_p_2', val=np.ones((nn,))*0., units='Pa')
    # iv.add_output('heat_in_2', val=np.ones((nn,))*0., units='W')
    # iv.add_output('pressure_recovery_2', val=np.ones((nn,)))
    # iv.add_output('pressure_recovery_3', val=np.ones((nn,)))

    prob.setup()
    prob.set_val('oc.area_1', val=64, units='inch**2')
    prob.set_val('oc.convergence_hack', val=0.0, units='Pa')
    prob.set_val('oc.area_nozzle_in', val=60.0, units='inch**2')
    prob.set_val('oc.inlet.totalpressure.eta_ram', val=ram_recovery)

    if HAS_PYCYCLE:
        #Define the design point
        prob.set_val('pyduct.design.fc.alt', 10000, units='m')
        prob.set_val('pyduct.design.fc.MN', 0.8)
        prob.set_val('pyduct.design.inlet.MN', 0.6)
        prob.set_val('pyduct.design.inlet.ram_recovery', ram_recovery)
        prob.set_val('pyduct.design.duct.MN', 0.08)
        prob.set_val('pyduct.design.duct.dPqP', dPqP)
        prob.set_val('pyduct.design.duct.Q_dot', heat_in, units='kW')
        prob.set_val('pyduct.design.nozz.Cfg', cfg, units=None)

        # Set initial guesses for balances
        prob['pyduct.design.balance.W'] = 8.
        prob.model.pyduct.design.nonlinear_solver.options['atol'] = 1e-6
        prob.model.pyduct.design.nonlinear_solver.options['rtol'] = 1e-6

    prob.set_solver_print(level=-1)
    prob.set_solver_print(level=-1, depth=2)

    # do a first run to get the duct areas from pycycle
    prob.run_model()

    if HAS_PYCYCLE:
        # set areas based on pycycle design point
        prob.set_val('oc.area_1',
                     val=prob.get_val('pyduct.design.inlet.Fl_O:stat:area',
                                      units='inch**2'),
                     units='inch**2')
        prob.set_val('iv.area_2',
                     val=prob.get_val('pyduct.design.duct.Fl_O:stat:area',
                                      units='inch**2'),
                     units='inch**2')
    else:
        prob.set_val('oc.area_1', val=oc_areas[0], units='inch**2')
        prob.set_val('iv.area_2', val=oc_areas[1], units='inch**2')

    prob.set_val('oc.sta3.heat_in', val=heat_in, units='kW')
    if oc_use_dpqp:
        prob.set_val('oc.sta3.pressure_recovery', val=(1 - dPqP), units=None)
    else:
        if HAS_PYCYCLE:
            delta_p = prob.get_val(
                'pyduct.design.inlet.Fl_O:tot:P', units='Pa') - prob.get_val(
                    'pyduct.design.nozz.Fl_O:tot:P', units='Pa')
        else:
            delta_p = oc_delta_p
        prob.set_val('oc.sta3.delta_p', -delta_p, units='Pa')

    prob.run_model()

    if list_output and HAS_PYCYCLE:
        prob.model.list_outputs(units=True, excludes=['*chem_eq*', '*props*'])
        # prob.model.list_outputs(includes=['*oc.*force*','*perf*','*mdot*'], units=True)
        print(prob.get_val('pyduct.design.inlet.Fl_O:stat:W', units='kg/s'))
        print(prob.get_val('pyduct.design.perf.Fn', units='N'))

        for pt in ['design'] + mp_duct.od_pts:
            print('\n', '#' * 10, pt, '#' * 10)
            viewer(prob, 'pyduct.' + pt)
    elif list_output:
        prob.model.list_outputs(units=True)
    return prob
コード例 #18
0
ファイル: N3_MDP_Opt.py プロジェクト: DriesVerstraete/pyCycle
prob.model.connect('RTO:T4max', 'T4_ratio.RTO_T4')
prob.model.connect('T4_ratio.TOC_T4', 'TOC.balance.rhs:FAR')
prob.model.connect('TR', 'T4_ratio.TR')
prob.model.set_order(
    ['des_vars', 'T4_ratio', 'TOC', 'RTO', 'SLS', 'CRZ', 'bal'])

newton = prob.model.nonlinear_solver = om.NewtonSolver()
newton.options['atol'] = 1e-6
newton.options['rtol'] = 1e-6
newton.options['iprint'] = 2
newton.options['maxiter'] = 20
newton.options['solve_subsystems'] = True
newton.options['max_sub_solves'] = 10
newton.options['err_on_maxiter'] = True
# newton.linesearch =  om.ArmijoGoldsteinLS()
newton.linesearch = om.BoundsEnforceLS()
# newton.linesearch.options['maxiter'] = 2
newton.linesearch.options['bound_enforcement'] = 'scalar'
# newton.linesearch.options['print_bound_enforce'] = True
newton.linesearch.options['iprint'] = -1
# newton.linesearch.options['print_bound_enforce'] = False
# newton.linesearch.options['alpha'] = 0.5

prob.model.linear_solver = om.DirectSolver(assemble_jac=True)
# prob.model.jacobian = CSCJacobian()

# recorder = SqliteRecorder('N3_MDP.sql')

# setup the optimization
prob.driver = om.pyOptSparseDriver()
prob.driver.options['optimizer'] = 'SNOPT'
コード例 #19
0
    def setup(self):

        wet_thermo_spec = pyc.species_data.wet_air #special species library is called that allows for using initial compositions that include both H and C
        janaf_thermo_spec = pyc.species_data.janaf #standard species library is called for use in and after burner
        design = self.options['design']

        # Add engine elements
        self.pyc_add_element('fc', pyc.FlightConditions(thermo_data=wet_thermo_spec, use_WAR=True,
                                    elements=pyc.WET_AIR_ELEMENTS))#WET_AIR_ELEMENTS contains standard dry air compounds as well as H2O
        self.pyc_add_element('inlet', pyc.Inlet(design=design, thermo_data=wet_thermo_spec,
                                    elements=pyc.WET_AIR_ELEMENTS))
        self.pyc_add_element('comp', pyc.Compressor(map_data=pyc.AXI5, design=design,
                                    thermo_data=wet_thermo_spec, elements=pyc.WET_AIR_ELEMENTS,),
                                    promotes_inputs=['Nmech'])

        ###Note###
        #The Combustor element automatically assumes that the thermo data to use for both the inflowing air 
        #and the outflowing mixed air and fuel is the data specified by the thermo_data option
        #unless the inflow_thermo_data option is set. If the inflow_thermo_data option is set,
        #the Combustor element will use the thermo data specified by inflow_thermo_data for the inflowing air
        #to the burner, and it will use the thermo data specified by thermo_data for the outflowing mixed
        #air and fuel. This is necessary to do if the airflow upstream of the burner contains both C and H
        #within its compounds, because without the addition of the hydrocarbons from fuel, the solver has
        #a difficult time converging the trace amount of hydrocarbons "present" in the original flow.

        self.pyc_add_element('burner', pyc.Combustor(design=design,inflow_thermo_data=wet_thermo_spec,
                                    thermo_data=janaf_thermo_spec, inflow_elements=pyc.WET_AIR_ELEMENTS,
                                    air_fuel_elements=pyc.AIR_FUEL_ELEMENTS,
                                    fuel_type='JP-7'))
        self.pyc_add_element('turb', pyc.Turbine(map_data=pyc.LPT2269, design=design,
                                    thermo_data=janaf_thermo_spec, elements=pyc.AIR_FUEL_ELEMENTS,),
                                    promotes_inputs=['Nmech'])
        self.pyc_add_element('nozz', pyc.Nozzle(nozzType='CD', lossCoef='Cv',
                                    thermo_data=janaf_thermo_spec, elements=pyc.AIR_FUEL_ELEMENTS))
        self.pyc_add_element('shaft', pyc.Shaft(num_ports=2),promotes_inputs=['Nmech'])
        self.pyc_add_element('perf', pyc.Performance(num_nozzles=1, num_burners=1))

        # Connect flow stations
        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I', connect_w=False)
        self.pyc_connect_flow('inlet.Fl_O', 'comp.Fl_I')
        self.pyc_connect_flow('comp.Fl_O', 'burner.Fl_I')
        self.pyc_connect_flow('burner.Fl_O', 'turb.Fl_I')
        self.pyc_connect_flow('turb.Fl_O', 'nozz.Fl_I')

        # Connect turbomachinery elements to shaft
        self.connect('comp.trq', 'shaft.trq_0')
        self.connect('turb.trq', 'shaft.trq_1')

        # Connnect nozzle exhaust to freestream static conditions
        self.connect('fc.Fl_O:stat:P', 'nozz.Ps_exhaust')

        # Connect outputs to pefromance element
        self.connect('inlet.Fl_O:tot:P', 'perf.Pt2')
        self.connect('comp.Fl_O:tot:P', 'perf.Pt3')
        self.connect('burner.Wfuel', 'perf.Wfuel_0')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozz.Fg', 'perf.Fg_0')

        # Add balances for design and off-design
        balance = self.add_subsystem('balance', om.BalanceComp())
        if design:

            balance.add_balance('W', units='lbm/s', eq_units='lbf')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('perf.Fn', 'balance.lhs:W')

            balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR')

            balance.add_balance('turb_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.)
            self.connect('balance.turb_PR', 'turb.PR')
            self.connect('shaft.pwr_net', 'balance.lhs:turb_PR')

        else:

            balance.add_balance('FAR', eq_units='lbf', lower=1e-4, val=.3)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('perf.Fn', 'balance.lhs:FAR')

            balance.add_balance('Nmech', val=1.5, units='rpm', lower=500., eq_units='hp', rhs_val=0.)
            self.connect('balance.Nmech', 'Nmech')
            self.connect('shaft.pwr_net', 'balance.lhs:Nmech')

            balance.add_balance('W', val=168.0, units='lbm/s', eq_units='inch**2')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('nozz.Throat:stat:area', 'balance.lhs:W')

        # Setup solver to converge engine
        self.set_order(['balance', 'fc', 'inlet', 'comp', 'burner', 'turb', 'nozz', 'shaft', 'perf'])

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-6
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 15
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 100
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        # newton.linesearch = ArmijoGoldsteinLS()
        # newton.linesearch.options['c'] = .0001
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #20
0
    def setup(self):

        # TOC POINT (DESIGN)
        self.pyc_add_pnt('TOC',
                         N3(),
                         promotes_inputs=[('fan.PR', 'fan:PRdes'),
                                          ('lpc.PR', 'lpc:PRdes'),
                                          ('opr_calc.FPR', 'fan:PRdes'),
                                          ('opr_calc.LPCPR', 'lpc:PRdes')])

        # POINT 1: Top-of-climb (TOC)
        self.set_input_defaults('TOC.fc.alt', 35000., units='ft'),
        self.set_input_defaults('TOC.fc.MN', 0.8),
        self.set_input_defaults('TOC.inlet.ram_recovery', 0.9980),

        self.set_input_defaults('TOC.balance.rhs:fan_eff', 0.97)
        self.set_input_defaults('TOC.duct2.dPqP', 0.0100)
        self.set_input_defaults('TOC.balance.rhs:lpc_eff', 0.905),
        self.set_input_defaults('TOC.duct25.dPqP', 0.0150),
        self.set_input_defaults('TOC.balance.rhs:hpt_eff', 0.91),
        self.set_input_defaults('TOC.duct45.dPqP', 0.0050),
        self.set_input_defaults('TOC.balance.rhs:lpt_eff', 0.92),
        self.set_input_defaults('TOC.duct5.dPqP', 0.0100),
        self.set_input_defaults('TOC.duct17.dPqP', 0.0150),
        self.set_input_defaults('TOC.Fan_Nmech', 2184.5, units='rpm'),
        self.set_input_defaults('TOC.LP_Nmech', 6772.0, units='rpm'),
        self.set_input_defaults('TOC.HP_Nmech', 20871.0, units='rpm'),

        self.set_input_defaults('TOC.inlet.MN', 0.625),
        self.set_input_defaults('TOC.fan.MN', 0.45)
        self.set_input_defaults('TOC.splitter.MN1', 0.45)
        self.set_input_defaults('TOC.splitter.MN2', 0.45)
        self.set_input_defaults('TOC.duct2.MN', 0.45),
        self.set_input_defaults('TOC.lpc.MN', 0.45),
        self.set_input_defaults('TOC.bld25.MN', 0.45),
        self.set_input_defaults('TOC.duct25.MN', 0.45),
        self.set_input_defaults('TOC.hpc.MN', 0.30),
        self.set_input_defaults('TOC.bld3.MN', 0.30)
        self.set_input_defaults('TOC.burner.MN', 0.10),
        self.set_input_defaults('TOC.hpt.MN', 0.30),
        self.set_input_defaults('TOC.duct45.MN', 0.45),
        self.set_input_defaults('TOC.lpt.MN', 0.35),
        self.set_input_defaults('TOC.duct5.MN', 0.25),
        self.set_input_defaults('TOC.byp_bld.MN', 0.45),
        self.set_input_defaults('TOC.duct17.MN', 0.45),

        self.pyc_add_cycle_param('burner.dPqP', 0.0400),
        self.pyc_add_cycle_param('core_nozz.Cv', 0.9999),
        self.pyc_add_cycle_param('byp_nozz.Cv', 0.9975),
        self.pyc_add_cycle_param('lp_shaft.fracLoss', 0.01)
        self.pyc_add_cycle_param('hp_shaft.HPX', 350.0, units='hp'),
        self.pyc_add_cycle_param('bld25.sbv:frac_W', 0.0),
        self.pyc_add_cycle_param('hpc.bld_inlet:frac_W', 0.0),
        self.pyc_add_cycle_param('hpc.bld_inlet:frac_P', 0.1465),
        self.pyc_add_cycle_param('hpc.bld_inlet:frac_work', 0.5),
        self.pyc_add_cycle_param('hpc.bld_exit:frac_W', 0.02),
        self.pyc_add_cycle_param('hpc.bld_exit:frac_P', 0.1465),
        self.pyc_add_cycle_param('hpc.bld_exit:frac_work', 0.5),
        self.pyc_add_cycle_param('hpc.cust:frac_W', 0.0),
        self.pyc_add_cycle_param('hpc.cust:frac_P', 0.1465),
        self.pyc_add_cycle_param('hpc.cust:frac_work', 0.35),
        self.pyc_add_cycle_param('hpt.bld_inlet:frac_P', 1.0),
        self.pyc_add_cycle_param('hpt.bld_exit:frac_P', 0.0),
        self.pyc_add_cycle_param('lpt.bld_inlet:frac_P', 1.0),
        self.pyc_add_cycle_param('lpt.bld_exit:frac_P', 0.0),
        self.pyc_add_cycle_param('byp_bld.bypBld:frac_W', 0.0),

        # OTHER POINTS (OFF-DESIGN)
        self.od_pts = ['RTO', 'SLS', 'CRZ']
        self.cooling = [True, False, False]
        self.od_MNs = [0.25, 0.000001, 0.8]
        self.od_alts = [0.0, 0.0, 35000.0]
        self.od_dTs = [27.0, 27.0, 0.0]
        self.od_BPRs = [1.75, 1.75, 1.9397]
        self.od_recoveries = [0.9970, 0.9950, 0.9980]

        for i, pt in enumerate(self.od_pts):
            self.pyc_add_pnt(pt, N3(design=False, cooling=self.cooling[i]))

            self.set_input_defaults(pt + '.fc.MN', val=self.od_MNs[i])
            self.set_input_defaults(pt + '.fc.alt',
                                    val=self.od_alts[i],
                                    units='ft')
            self.set_input_defaults(pt + '.fc.dTs',
                                    val=self.od_dTs[i],
                                    units='degR')
            self.set_input_defaults(pt + '.balance.rhs:BPR',
                                    val=self.od_BPRs[i])
            self.set_input_defaults(pt + '.inlet.ram_recovery',
                                    val=self.od_recoveries[i])

        # Extra set input for Rolling Takeoff
        self.set_input_defaults('RTO.balance.rhs:FAR', 22800.0, units='lbf'),

        self.pyc_connect_des_od('fan.s_PR', 'fan.s_PR')
        self.pyc_connect_des_od('fan.s_Wc', 'fan.s_Wc')
        self.pyc_connect_des_od('fan.s_eff', 'fan.s_eff')
        self.pyc_connect_des_od('fan.s_Nc', 'fan.s_Nc')
        self.pyc_connect_des_od('lpc.s_PR', 'lpc.s_PR')
        self.pyc_connect_des_od('lpc.s_Wc', 'lpc.s_Wc')
        self.pyc_connect_des_od('lpc.s_eff', 'lpc.s_eff')
        self.pyc_connect_des_od('lpc.s_Nc', 'lpc.s_Nc')
        self.pyc_connect_des_od('hpc.s_PR', 'hpc.s_PR')
        self.pyc_connect_des_od('hpc.s_Wc', 'hpc.s_Wc')
        self.pyc_connect_des_od('hpc.s_eff', 'hpc.s_eff')
        self.pyc_connect_des_od('hpc.s_Nc', 'hpc.s_Nc')
        self.pyc_connect_des_od('hpt.s_PR', 'hpt.s_PR')
        self.pyc_connect_des_od('hpt.s_Wp', 'hpt.s_Wp')
        self.pyc_connect_des_od('hpt.s_eff', 'hpt.s_eff')
        self.pyc_connect_des_od('hpt.s_Np', 'hpt.s_Np')
        self.pyc_connect_des_od('lpt.s_PR', 'lpt.s_PR')
        self.pyc_connect_des_od('lpt.s_Wp', 'lpt.s_Wp')
        self.pyc_connect_des_od('lpt.s_eff', 'lpt.s_eff')
        self.pyc_connect_des_od('lpt.s_Np', 'lpt.s_Np')

        self.pyc_connect_des_od('gearbox.gear_ratio', 'gearbox.gear_ratio')
        self.pyc_connect_des_od('core_nozz.Throat:stat:area', 'balance.rhs:W')

        if self.options['statics'] is True:
            self.pyc_connect_des_od('inlet.Fl_O:stat:area', 'inlet.area')
            self.pyc_connect_des_od('fan.Fl_O:stat:area', 'fan.area')
            self.pyc_connect_des_od('splitter.Fl_O1:stat:area',
                                    'splitter.area1')
            self.pyc_connect_des_od('splitter.Fl_O2:stat:area',
                                    'splitter.area2')
            self.pyc_connect_des_od('duct2.Fl_O:stat:area', 'duct2.area')
            self.pyc_connect_des_od('lpc.Fl_O:stat:area', 'lpc.area')
            self.pyc_connect_des_od('bld25.Fl_O:stat:area', 'bld25.area')
            self.pyc_connect_des_od('duct25.Fl_O:stat:area', 'duct25.area')
            self.pyc_connect_des_od('hpc.Fl_O:stat:area', 'hpc.area')
            self.pyc_connect_des_od('bld3.Fl_O:stat:area', 'bld3.area')
            self.pyc_connect_des_od('burner.Fl_O:stat:area', 'burner.area')
            self.pyc_connect_des_od('hpt.Fl_O:stat:area', 'hpt.area')
            self.pyc_connect_des_od('duct45.Fl_O:stat:area', 'duct45.area')
            self.pyc_connect_des_od('lpt.Fl_O:stat:area', 'lpt.area')
            self.pyc_connect_des_od('duct5.Fl_O:stat:area', 'duct5.area')
            self.pyc_connect_des_od('byp_bld.Fl_O:stat:area', 'byp_bld.area')
            self.pyc_connect_des_od('duct17.Fl_O:stat:area', 'duct17.area')

        self.pyc_connect_des_od('duct2.s_dPqP', 'duct2.s_dPqP')
        self.pyc_connect_des_od('duct25.s_dPqP', 'duct25.s_dPqP')
        self.pyc_connect_des_od('duct45.s_dPqP', 'duct45.s_dPqP')
        self.pyc_connect_des_od('duct5.s_dPqP', 'duct5.s_dPqP')
        self.pyc_connect_des_od('duct17.s_dPqP', 'duct17.s_dPqP')

        self.connect('RTO.balance.hpt_chrg_cool_frac',
                     'TOC.bld3.bld_exit:frac_W')
        self.connect('RTO.balance.hpt_nochrg_cool_frac',
                     'TOC.bld3.bld_inlet:frac_W')

        self.connect('RTO.balance.hpt_chrg_cool_frac',
                     'SLS.bld3.bld_exit:frac_W')
        self.connect('RTO.balance.hpt_nochrg_cool_frac',
                     'SLS.bld3.bld_inlet:frac_W')

        self.connect('RTO.balance.hpt_chrg_cool_frac',
                     'CRZ.bld3.bld_exit:frac_W')
        self.connect('RTO.balance.hpt_nochrg_cool_frac',
                     'CRZ.bld3.bld_inlet:frac_W')

        self.add_subsystem('T4_ratio',
                           om.ExecComp('TOC_T4 = RTO_T4*TR',
                                       RTO_T4={
                                           'value': 3400.0,
                                           'units': 'degR'
                                       },
                                       TOC_T4={
                                           'value': 3150.0,
                                           'units': 'degR'
                                       },
                                       TR={
                                           'value': 0.926470588,
                                           'units': None
                                       }),
                           promotes_inputs=[
                               'RTO_T4',
                           ])
        self.connect('T4_ratio.TOC_T4', 'TOC.balance.rhs:FAR')
        initial_order = ['T4_ratio', 'TOC', 'RTO', 'SLS', 'CRZ']
        self.set_order(self.options['order_start'] + initial_order +
                       self.options['order_add'])

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-6
        newton.options['iprint'] = 2
        newton.options['maxiter'] = 20
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 10
        newton.options['err_on_non_converge'] = True
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver(assemble_jac=True)
コード例 #21
0
    def setup(self):

        design = self.options['design']
        maxiter = self.options['maxiter']
        self.options['thermo_method'] = 'CEA'
        self.options['thermo_data'] = pyc.species_data.janaf

        self.add_subsystem('fc', pyc.FlightConditions())
        self.add_subsystem('inlet', pyc.Inlet())
        self.add_subsystem('duct1', pyc.Duct())
        self.add_subsystem('lpc', pyc.Compressor(map_data=pyc.LPCMap),
                           promotes_inputs=[('Nmech','IP_Nmech')])
        self.add_subsystem('icduct', pyc.Duct())
        self.add_subsystem('hpc_axi', pyc.Compressor(map_data=pyc.HPCMap),
                           promotes_inputs=[('Nmech','HP_Nmech')])
        self.add_subsystem('bld25', pyc.BleedOut(bleed_names=['cool1','cool2']))
        self.add_subsystem('hpc_centri', pyc.Compressor(map_data=pyc.HPCMap),
                           promotes_inputs=[('Nmech','HP_Nmech')])
        self.add_subsystem('bld3', pyc.BleedOut(bleed_names=['cool3','cool4']))
        self.add_subsystem('duct6', pyc.Duct())
        self.add_subsystem('burner', pyc.Combustor(fuel_type='Jet-A(g)'))
        self.add_subsystem('hpt', pyc.Turbine(map_data=pyc.HPTMap, bleed_names=['cool3','cool4']),
                           promotes_inputs=[('Nmech','HP_Nmech')])
        self.add_subsystem('duct43', pyc.Duct())
        self.add_subsystem('lpt', pyc.Turbine(map_data=pyc.LPTMap, bleed_names=['cool1','cool2']),
                           promotes_inputs=[('Nmech','IP_Nmech')])
        self.add_subsystem('itduct', pyc.Duct())
        self.add_subsystem('pt', pyc.Turbine(map_data=pyc.LPTMap),
                           promotes_inputs=[('Nmech','LP_Nmech')])
        self.add_subsystem('duct12', pyc.Duct())
        self.add_subsystem('nozzle', pyc.Nozzle(nozzType='CV', lossCoef='Cv'))

        self.add_subsystem('lp_shaft', pyc.Shaft(num_ports=1),promotes_inputs=[('Nmech','LP_Nmech')])
        self.add_subsystem('ip_shaft', pyc.Shaft(num_ports=2),promotes_inputs=[('Nmech','IP_Nmech')])
        self.add_subsystem('hp_shaft', pyc.Shaft(num_ports=3),promotes_inputs=[('Nmech','HP_Nmech')])
        self.add_subsystem('perf', pyc.Performance(num_nozzles=1, num_burners=1))

        self.connect('duct1.Fl_O:tot:P', 'perf.Pt2')
        self.connect('hpc_centri.Fl_O:tot:P', 'perf.Pt3')
        self.connect('burner.Wfuel', 'perf.Wfuel_0')
        self.connect('inlet.F_ram', 'perf.ram_drag')
        self.connect('nozzle.Fg', 'perf.Fg_0')
        self.connect('lp_shaft.pwr_in', 'perf.power')

        self.connect('pt.trq', 'lp_shaft.trq_0')
        self.connect('lpc.trq', 'ip_shaft.trq_0')
        self.connect('lpt.trq', 'ip_shaft.trq_1')
        self.connect('hpc_axi.trq', 'hp_shaft.trq_0')
        self.connect('hpc_centri.trq', 'hp_shaft.trq_1')
        self.connect('hpt.trq', 'hp_shaft.trq_2')
        self.connect('fc.Fl_O:stat:P', 'nozzle.Ps_exhaust')

        balance = self.add_subsystem('balance', om.BalanceComp())
        if design:

            balance.add_balance('W', units='lbm/s', eq_units=None)
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('nozzle.PR', 'balance.lhs:W')

            balance.add_balance('FAR', eq_units='degR', lower=1e-4, val=.017)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR')

            balance.add_balance('lpt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.)
            self.connect('balance.lpt_PR', 'lpt.PR')
            self.connect('ip_shaft.pwr_net', 'balance.lhs:lpt_PR')

            balance.add_balance('hpt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.)
            self.connect('balance.hpt_PR', 'hpt.PR')
            self.connect('hp_shaft.pwr_net', 'balance.lhs:hpt_PR')

            balance.add_balance('pt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', rhs_val=0.)
            self.connect('balance.pt_PR', 'pt.PR')
            self.connect('lp_shaft.pwr_net', 'balance.lhs:pt_PR')


        else:
            balance.add_balance('FAR', eq_units='hp', lower=1e-4, val=.017)
            self.connect('balance.FAR', 'burner.Fl_I:FAR')
            self.connect('lp_shaft.pwr_net', 'balance.lhs:FAR')

            balance.add_balance('W', units='lbm/s', eq_units='inch**2')
            self.connect('balance.W', 'inlet.Fl_I:stat:W')
            self.connect('nozzle.Throat:stat:area', 'balance.lhs:W')

            balance.add_balance('IP_Nmech', val=12000.0, units='rpm', lower=1.001, eq_units='hp', rhs_val=0.)
            self.connect('balance.IP_Nmech', 'IP_Nmech')
            self.connect('ip_shaft.pwr_net', 'balance.lhs:IP_Nmech')

            balance.add_balance('HP_Nmech', val=14800.0, units='rpm', lower=1.001, eq_units='hp', rhs_val=0.)
            self.connect('balance.HP_Nmech', 'HP_Nmech')
            self.connect('hp_shaft.pwr_net', 'balance.lhs:HP_Nmech')

        self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I', connect_w=False)
        self.pyc_connect_flow('inlet.Fl_O', 'duct1.Fl_I')
        self.pyc_connect_flow('duct1.Fl_O', 'lpc.Fl_I')
        self.pyc_connect_flow('lpc.Fl_O', 'icduct.Fl_I')
        self.pyc_connect_flow('icduct.Fl_O', 'hpc_axi.Fl_I')
        self.pyc_connect_flow('hpc_axi.Fl_O', 'bld25.Fl_I')
        self.pyc_connect_flow('bld25.Fl_O', 'hpc_centri.Fl_I')
        self.pyc_connect_flow('hpc_centri.Fl_O', 'bld3.Fl_I')
        self.pyc_connect_flow('bld3.Fl_O', 'duct6.Fl_I')
        self.pyc_connect_flow('duct6.Fl_O', 'burner.Fl_I')
        self.pyc_connect_flow('burner.Fl_O', 'hpt.Fl_I')
        self.pyc_connect_flow('hpt.Fl_O', 'duct43.Fl_I')
        self.pyc_connect_flow('duct43.Fl_O', 'lpt.Fl_I')
        self.pyc_connect_flow('lpt.Fl_O', 'itduct.Fl_I')
        self.pyc_connect_flow('itduct.Fl_O', 'pt.Fl_I')
        self.pyc_connect_flow('pt.Fl_O', 'duct12.Fl_I')
        self.pyc_connect_flow('duct12.Fl_O', 'nozzle.Fl_I')

        self.pyc_connect_flow('bld25.cool1', 'lpt.cool1', connect_stat=False)
        self.pyc_connect_flow('bld25.cool2', 'lpt.cool2', connect_stat=False)
        self.pyc_connect_flow('bld3.cool3', 'hpt.cool3', connect_stat=False)
        self.pyc_connect_flow('bld3.cool4', 'hpt.cool4', connect_stat=False)

        newton = self.nonlinear_solver = om.NewtonSolver()
        newton.options['atol'] = 1e-6
        newton.options['rtol'] = 1e-6
        newton.options['iprint'] = 2
        newton.options['maxiter'] = maxiter
        newton.options['solve_subsystems'] = True
        newton.options['max_sub_solves'] = 100
        newton.options['reraise_child_analysiserror'] = False
        newton.linesearch = om.BoundsEnforceLS()
        newton.linesearch.options['bound_enforcement'] = 'scalar'
        newton.linesearch.options['iprint'] = -1

        self.linear_solver = om.DirectSolver()

        super().setup()
コード例 #22
0
    def setup(self):

        design = self.options['design']
        thermo_data = self.options['thermo_data']

        flow1_elements = self.options['Fl_I1_elements']
        flow1_thermo = Thermo(thermo_data, init_reacts=flow1_elements)
        n_flow1_prods = len(flow1_thermo.products)
        in_flow = FlowIn(fl_name='Fl_I1', num_prods=n_flow1_prods)
        self.add_subsystem('in_flow1', in_flow, promotes=['Fl_I1:*'])

        flow2_elements = self.options['Fl_I2_elements']
        flow2_thermo = Thermo(thermo_data, init_reacts=flow2_elements)
        n_flow2_prods = len(flow2_thermo.products)
        in_flow = FlowIn(fl_name='Fl_I2', num_prods=n_flow2_prods)
        self.add_subsystem('in_flow2', in_flow, promotes=['Fl_I2:*'])


        if design:
            # internal flow station to compute the area that is needed to match the static pressures
            if self.options['designed_stream'] == 1:
                Fl1_stat = SetStatic(mode="Ps", thermo_data=thermo_data,
                                    init_reacts=flow1_elements,
                                    fl_name="Fl_I1_calc:stat")
                self.add_subsystem('Fl_I1_stat_calc', Fl1_stat,
                                   promotes_inputs=[('init_prod_amounts', 'Fl_I1:stat:n'), ('S', 'Fl_I1:tot:S'),
                                                    ('ht', 'Fl_I1:tot:h'), ('W', 'Fl_I1:stat:W'), ('Ps', 'Fl_I2:stat:P')],
                                   promotes_outputs=['Fl_I1_calc:stat*'])

                self.add_subsystem('area_calc', AreaSum(), promotes_inputs=['Fl_I2:stat:area'],
                                   promotes_outputs=[('area_sum', 'area')])
                self.connect('Fl_I1_calc:stat:area', 'area_calc.Fl_I1:stat:area')
            else:
                Fl2_stat = SetStatic(mode="Ps", thermo_data=thermo_data,
                                    init_reacts=flow2_elements,
                                    fl_name="Fl_I2_calc:stat")
                self.add_subsystem('Fl_I2_stat_calc', Fl2_stat,
                                   promotes_inputs=[('init_prod_amounts', 'Fl_I2:tot:n'), ('S', 'Fl_I2:tot:S'),
                                                    ('ht', 'Fl_I2:tot:h'), ('W', 'Fl_I2:stat:W'), ('Ps', 'Fl_I1:stat:P')],
                                   promotes_outputs=['Fl_I2_calc:stat:*'])

                self.add_subsystem('area_calc', AreaSum(), promotes_inputs=['Fl_I1:stat:area'],
                                   promotes_outputs=[('area_sum', 'area')])
                self.connect('Fl_I2_calc:stat:area', 'area_calc.Fl_I2:stat:area')

        else:
            if self.options['designed_stream'] == 1:
                Fl1_stat = SetStatic(mode="area", thermo_data=thermo_data,
                                        init_reacts=flow1_elements,
                                        fl_name="Fl_I1_calc:stat")
                self.add_subsystem('Fl_I1_stat_calc', Fl1_stat,
                                    promotes_inputs=[('init_prod_amounts', 'Fl_I1:tot:n'), ('S', 'Fl_I1:tot:S'),
                                                     ('ht', 'Fl_I1:tot:h'), ('W', 'Fl_I1:stat:W'),
                                                     ('guess:Pt', 'Fl_I1:tot:P'), ('guess:gamt', 'Fl_I1:tot:gamma')],
                                    promotes_outputs=['Fl_I1_calc:stat*'])
            else:
                Fl2_stat = SetStatic(mode="area", thermo_data=thermo_data,
                                        init_reacts=flow2_elements,
                                        fl_name="Fl_I2_calc:stat")
                self.add_subsystem('Fl_I2_stat_calc', Fl2_stat,
                                    promotes_inputs=[('init_prod_amounts', 'Fl_I2:tot:n'), ('S', 'Fl_I2:tot:S'),
                                                     ('ht', 'Fl_I2:tot:h'), ('W', 'Fl_I2:stat:W'),
                                                     ('guess:Pt', 'Fl_I2:tot:P'), ('guess:gamt', 'Fl_I2:tot:gamma')],
                                    promotes_outputs=['Fl_I2_calc:stat*'])

        self.add_subsystem('extraction_ratio', om.ExecComp('ER=Pt1/Pt2', Pt1={'units':'Pa'}, Pt2={'units':'Pa'}),
                            promotes_inputs=[('Pt1', 'Fl_I1:tot:P'), ('Pt2', 'Fl_I2:tot:P')],
                            promotes_outputs=['ER'])

        mix_flow = MixFlow(thermo_data=thermo_data,
                   Fl_I1_elements=self.options['Fl_I1_elements'],
                   Fl_I2_elements=self.options['Fl_I2_elements'])
        if self.options['designed_stream'] == 1:
            self.add_subsystem('mix_flow', mix_flow,
                               promotes_inputs=['Fl_I1:tot:h', 'Fl_I1:tot:n', ('Fl_I1:stat:W','Fl_I1_calc:stat:W'), ('Fl_I1:stat:P','Fl_I1_calc:stat:P'),
                                                ('Fl_I1:stat:V','Fl_I1_calc:stat:V'), ('Fl_I1:stat:area','Fl_I1_calc:stat:area'),
                                                'Fl_I2:tot:h', 'Fl_I2:tot:n', 'Fl_I2:stat:W', 'Fl_I2:stat:P', 'Fl_I2:stat:V', 'Fl_I2:stat:area'])
        else:
            self.add_subsystem('mix_flow', mix_flow,
                               promotes_inputs=['Fl_I1:tot:h', 'Fl_I1:tot:n', 'Fl_I1:stat:W', 'Fl_I1:stat:P', 'Fl_I1:stat:V', 'Fl_I1:stat:area',
                                                'Fl_I2:tot:h', 'Fl_I2:tot:n', ('Fl_I2:stat:W','Fl_I2_calc:stat:W'), ('Fl_I2:stat:P','Fl_I2_calc:stat:P'),
                                                ('Fl_I2:stat:V','Fl_I2_calc:stat:V'), ('Fl_I2:stat:area','Fl_I2_calc:stat:area')])


        # group to converge for the impulse balance
        conv = self.add_subsystem('impulse_converge', om.Group(), promotes=['*'])

        if self.options['internal_solver']:
            newton = conv.nonlinear_solver = om.NewtonSolver()
            newton.options['maxiter'] = 30
            newton.options['atol'] = 1e-2
            newton.options['solve_subsystems'] = True
            newton.options['max_sub_solves'] = 20
            newton.options['reraise_child_analysiserror'] = False
            newton.linesearch = om.BoundsEnforceLS()
            newton.linesearch.options['bound_enforcement'] = 'scalar'
            newton.linesearch.options['iprint'] = -1
            conv.linear_solver = om.DirectSolver(assemble_jac=True)

        out_tot = SetTotal(thermo_data=thermo_data, mode='h', init_reacts=self.options['Fl_I1_elements'],
                        fl_name="Fl_O:tot")
        conv.add_subsystem('out_tot', out_tot, promotes_outputs=['Fl_O:tot:*'])
        self.connect('mix_flow.n_mix', 'out_tot.init_prod_amounts')
        self.connect('mix_flow.ht_mix', 'out_tot.h')
        # note: gets Pt from the balance comp

        out_stat = SetStatic(mode="area", thermo_data=thermo_data,
                             init_reacts=self.options['Fl_I1_elements'],
                             fl_name="Fl_O:stat")
        conv.add_subsystem('out_stat', out_stat, promotes_outputs=['Fl_O:stat:*'], promotes_inputs=['area', ])
        self.connect('mix_flow.n_mix', 'out_stat.init_prod_amounts')
        self.connect('mix_flow.W_mix','out_stat.W')
        conv.connect('Fl_O:tot:S', 'out_stat.S')
        self.connect('mix_flow.ht_mix', 'out_stat.ht')
        conv.connect('Fl_O:tot:P', 'out_stat.guess:Pt')
        conv.connect('Fl_O:tot:gamma', 'out_stat.guess:gamt')

        conv.add_subsystem('imp_out', Impulse())
        conv.connect('Fl_O:stat:P', 'imp_out.P')
        conv.connect('Fl_O:stat:area', 'imp_out.area')
        conv.connect('Fl_O:stat:V', 'imp_out.V')
        conv.connect('Fl_O:stat:W', 'imp_out.W')

        balance = conv.add_subsystem('balance', om.BalanceComp())
        balance.add_balance('P_tot', val=100, units='psi', eq_units='N', lower=1e-3, upper=10000)
        conv.connect('balance.P_tot', 'out_tot.P')
        conv.connect('imp_out.impulse', 'balance.lhs:P_tot')
        self.connect('mix_flow.impulse_mix', 'balance.rhs:P_tot') #note that this connection comes from outside the convergence group
コード例 #23
0
    def setup(self):
        nn = self.options['num_nodes']

        self.add_subsystem('thermal_properties',
                           ThermalGroup(num_nodes=nn),
                           promotes_inputs=[
                               'B_pk', 'alpha_stein', 'beta_stein', 'k_stein',
                               'rpm', 'sta_mass', 'resistivity_wire',
                               'stack_length', 'n_slots', 'n_strands', 'n_m',
                               'mu_o', 'f_e', 'n_turns', 'T_coeff_cu', 'I',
                               'T_windings', 'r_strand', 'mu_r'
                           ],
                           promotes_outputs=[
                               'A_cu', 'r_litz', 'P_steinmetz', 'P_dc', 'P_ac',
                               'P_wire', 'L_wire', 'R_dc', 'skin_depth',
                               'temp_resistivity', 'f_e'
                           ])

        self.add_subsystem(
            'em_properties',
            EmGroup(num_nodes=nn),
            promotes_inputs=[
                'w_slot', 'w_t', 'T_coef_rem_mag', 'T_mag', 'gap',
                'carters_coef', 'k_sat', 'stack_length', 'Br', 'Br_20', 'mu_r',
                'g_eq', 't_mag', 'B_g', 'n_m', 'n_turns', 'I', 'rot_or', 'rpm',
                'P_wire', 'P_steinmetz', 'P_shaft', 'Tq_shaft', 'omega'
            ],  #  'l_slot_opening',  
            promotes_outputs=[
                'Br', 'carters_coef', 'Tq_shaft', 'Tq_max', 'g_eq', 'omega',
                'P_in', 'Eff', 'B_g'
            ])  # 'mech_angle', 't_1',

        if self.options['design']:

            self.add_subsystem('geometry',
                               SizeGroup(),
                               promotes_inputs=[
                                   'gap', 'B_g', 'k', 'b_ry', 'n_m', 'b_sy',
                                   'b_t', 'n_turns', 'I', 'k_wb', 'rho',
                                   'radius_motor', 'n_slots', 'sta_ir', 'w_t',
                                   'stack_length', 's_d', 'rot_or', 'rot_ir',
                                   't_mag', 'rho_mag'
                               ],
                               promotes_outputs=[
                                   'J', 'w_ry', 'w_sy', 'w_t', 'sta_ir',
                                   'rot_ir', 's_d', 'mag_mass', 'sta_mass',
                                   'rot_mass', 'slot_area', 'w_slot'
                               ])

            bal = om.BalanceComp(num_nodes=nn)
            bal.add_balance('rot_or',
                            val=0.05,
                            units='cm',
                            eq_units='A/mm**2',
                            lower=1e-4)  #, use_mult=True, mult_val=0.5)
            tgt = om.IndepVarComp(name='J_tgt', val=10.47, units='A/mm**2')

            self.add_subsystem(name='target',
                               subsys=tgt,
                               promotes_outputs=['J_tgt'])
            self.add_subsystem(name='balance',
                               subsys=bal,
                               promotes_outputs=['rot_or'])

            self.connect('J_tgt', 'balance.rhs:rot_or')
            self.connect('J', 'balance.lhs:rot_or')

            self.linear_solver = om.DirectSolver()

            newton = self.nonlinear_solver = om.NewtonSolver()
            newton.options['maxiter'] = 50
            newton.options['iprint'] = 2
            newton.options['solve_subsystems'] = True

            # ls = newton.linesearch = om.ArmijoGoldsteinLS()
            # ls.options['maxiter'] = 3
            # ls.options['iprint'] = 2
            # ls.options['print_bound_enforce'] = True

            ls = newton.linesearch = om.BoundsEnforceLS()
            ls.options['print_bound_enforce'] = True