From da3b5e32a76a684e0206b007b450c3ac9a5969ac Mon Sep 17 00:00:00 2001 From: Kenneth-T-Moore Date: Wed, 20 May 2026 13:09:11 -0400 Subject: [PATCH 1/3] Modernize CI to use pixi envs from OM. Also, fix tests to pass with more recent OM --- .github/workflows/pycycle_test_workflow.yml | 216 +++++--------------- .github/workflows/release_workflow.yml | 4 +- pycycle/elements/test/test_bleed_out.py | 7 +- 3 files changed, 55 insertions(+), 172 deletions(-) diff --git a/.github/workflows/pycycle_test_workflow.yml b/.github/workflows/pycycle_test_workflow.yml index e0d9cdd5..05dd4157 100644 --- a/.github/workflows/pycycle_test_workflow.yml +++ b/.github/workflows/pycycle_test_workflow.yml @@ -11,77 +11,64 @@ on: # Allow running the workflow manually from the Actions tab workflow_dispatch: - inputs: - - run_name: - type: string - description: 'Name of workflow run as it will appear under Actions tab:' - required: false - default: "" - - Ubuntu_Baseline: - type: boolean - description: 'Include Ubuntu Baseline test in the test matrix' - required: false - default: true - - MacOS_Baseline: - type: boolean - description: 'Include MacOS Baseline test in the test matrix' - required: false - default: true - - Windows_Baseline: - type: boolean - description: 'Include Windows Baseline test in the test matrix' - required: false - default: true - - OpenMDAO_Dev: - type: boolean - description: 'Include latest/development test in the test matrix' - required: false - default: true - -run-name: ${{ inputs.run_name }} +concurrency: + # Cancel any existing CI runs if we push to this branch + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - tests: + test_pycycle: - timeout-minutes: 120 + timeout-minutes: 90 strategy: fail-fast: false matrix: include: + # test baseline versions on Ubuntu - NAME: Ubuntu Baseline - OS: ubuntu-latest - PY: '3.12' - NUMPY: '1.26' - SCIPY: '1.14' - OPENMDAO: 'latest' - EXCLUDE: ${{ github.event_name == 'workflow_dispatch' && ! inputs.Ubuntu_Baseline }} + OS: ubuntu-24.04 + OPENMDAO_PIXI_ENVIRONMENT: 'py314' + OPENMDAO_INSTALL_FROM: 'pypi' + OPENMDAO: '' + COVERAGE: true - # test baseline versions on MacOS + # latest versions of openmdao/dymos - NAME: MacOS Baseline OS: macos-latest - PY: '3.12' - NUMPY: '1.26' - SCIPY: '1.14' - OPENMDAO: 'latest' - EXCLUDE: ${{ github.event_name == 'workflow_dispatch' && ! inputs.MacOS_Baseline }} + OPENMDAO_PIXI_ENVIRONMENT: 'py314' + OPENMDAO_INSTALL_FROM: 'pypi' + OPENMDAO: '' + COVERAGE: true + + # latest versions of openmdao/dymos + # Coverage currently has some problems in windows, according to the openmdao workflows. + - NAME: Windows Baseline + OS: windows-latest + OPENMDAO_PIXI_ENVIRONMENT: 'py314' + OPENMDAO_INSTALL_FROM: 'pypi' + OPENMDAO: '' + COVERAGE: false + + # oldest supported versions of openmdao/dymos + # Note: bugfixes sometimes require incrementing the minimal version of openmdao or dymos. + - NAME: Ubuntu Oldest + OS: ubuntu-24.04 + OPENMDAO_PIXI_ENVIRONMENT: 'py311' + OPENMDAO_INSTALL_FROM: 'pypi' + OPENMDAO: '3.41.0' + COVERAGE: true # test with latest/development versions # only run when selected via workflow_dispatch - NAME: OpenMDAO Dev - OS: ubuntu-latest - PY: 3 - NUMPY: 2 - SCIPY: 1 - OPENMDAO: 'dev' - EXCLUDE: ${{ github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && ! inputs.OpenMDAO_Dev) }} + OS: ubuntu-24.04 + OPENMDAO_PIXI_ENVIRONMENT: 'py314' + OPENMDAO_INSTALL_FROM: 'github' + OPENMDAO: '' + runs-on: ${{ matrix.OS }} @@ -100,41 +87,20 @@ jobs: echo "Testing: ${GITHUB_REPOSITORY}" echo "Triggered by: ${GITHUB_EVENT_NAME}" echo "Initiated by: ${GITHUB_ACTOR}" - echo "Excluded: ${{ matrix.EXCLUDE }}" echo "=============================================================" - - name: Checkout code - if: ${{ ! matrix.EXCLUDE }} - uses: actions/checkout@v3 + - name: Checkout Aviary + uses: actions/checkout@v6 - - name: Setup conda - if: ${{ ! matrix.EXCLUDE }} - uses: conda-incubator/setup-miniconda@v3 + - name: 'Setup OpenMDAO pixi Environment' + id: setup_pixi_environment + uses: OpenMDAO/OpenMDAO/.github/actions/setup_openmdao_pixi@master with: - python-version: ${{ matrix.PY }} - miniforge-version: "latest" - - - name: Install OpenMDAO - if: ${{ ! matrix.EXCLUDE }} - shell: bash -l {0} - run: | - conda install numpy=${{ matrix.NUMPY }} scipy=${{ matrix.SCIPY }} -q -y - - python -m pip install --upgrade pip - - echo "=============================================================" - echo "Install OpenMDAO" - echo "=============================================================" - if [[ "${{ matrix.OPENMDAO }}" == "dev" ]]; then - pip install git+https://github.com/OpenMDAO/OpenMDAO - elif [[ "${{ matrix.OPENMDAO }}" == "latest" ]]; then - echo "The latest release of OpenMDAO will be installed from pypi per the pyCycle dependency" - else - pip install openmdao==${{ matrix.OPENMDAO }} - fi + environment: '${{ inputs.OPENMDAO_PIXI_ENVIRONMENT }}' + openmdao_install_from: '${{ inputs.OPENMDAO_INSTALL_FROM }}' + openmdao_version: '${{ inputs.OPENMDAO }}' - name: Install pyCycle - if: ${{ ! matrix.EXCLUDE }} run: | echo "=============================================================" echo "Install pyCycle" @@ -142,13 +108,11 @@ jobs: python -m pip install -e .[all] - name: Display environment info - if: ${{ ! matrix.EXCLUDE }} run: | conda info conda list - name: Run tests - if: ${{ ! matrix.EXCLUDE }} id: run_tests run: | echo "=============================================================" @@ -160,7 +124,6 @@ jobs: testflo -n 1 pycycle --timeout=240 --show_skipped --deprecations_report=$RPT_FILE --coverage --coverpkg pycycle --durations=20 - name: Deprecations Report - if: ${{ ! matrix.EXCLUDE }} id: deprecations_report continue-on-error: true run: | @@ -176,7 +139,6 @@ jobs: grep '^0 unique deprecation warnings' $RPT_FILE - name: Check NumPy 2.0 Compatibility - if: ${{ ! matrix.EXCLUDE }} run: | echo "=============================================================" echo "Check code for NumPy 2.0 compatibility" @@ -206,85 +168,3 @@ jobs: `pyCycle`: Deprecations were detected on `${{ matrix.NAME }}` build. ```${{ steps.deprecations_report.outputs.summary }}``` ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - - windows_tests: - runs-on: windows-latest - - timeout-minutes: 60 - - strategy: - fail-fast: false - matrix: - include: - # baseline versions - - NAME: Windows Baseline - PY: '3.12' - NUMPY: '1.26' - SCIPY: '1.14' - EXCLUDE: ${{ github.event_name == 'workflow_dispatch' && ! inputs.Windows_Baseline }} - - name: ${{ matrix.NAME }} - - defaults: - run: - shell: pwsh - - steps: - - name: Display run details - run: | - echo "=============================================================" - echo "Run #$env:GITHUB_RUN_NUMBER" - echo "Run ID: $env:GITHUB_RUN_ID" - echo "Testing: $env:GITHUB_REPOSITORY" - echo "Triggered by: $env:GITHUB_EVENT_NAME" - echo "Initiated by: $env:GITHUB_ACTOR" - echo "Excluded: ${{ matrix.EXCLUDE }}" - echo "=============================================================" - - - name: Checkout code - if: ${{ ! matrix.EXCLUDE }} - uses: actions/checkout@v3 - - - name: Setup conda - if: ${{ ! matrix.EXCLUDE }} - uses: conda-incubator/setup-miniconda@v3 - with: - python-version: ${{ matrix.PY }} - miniforge-version: "latest" - - - name: Install pyCycle - if: ${{ ! matrix.EXCLUDE }} - run: | - conda install numpy=${{ matrix.NUMPY }} scipy=${{ matrix.SCIPY }} -q -y - - python -m pip install --upgrade pip - - echo "=============================================================" - echo "Install pyCycle" - echo "=============================================================" - python -m pip install -e .[all] - - - name: Display environment info - if: ${{ ! matrix.EXCLUDE }} - run: | - conda info - conda list - - - name: Run tests - if: ${{ ! matrix.EXCLUDE }} - id: run_tests - run: | - echo "=============================================================" - echo "Run tests with coverage" - echo "=============================================================" - testflo -n 1 pycycle --timeout=240 --show_skipped --coverage --coverpkg pycycle --durations=20 - - - name: Slack unit test failure - if: failure() - uses: act10ns/slack@v2.0.0 - with: - webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }} - status: ${{ steps.run_tests.outcome }} - message: | - `pyCycle`: Unit testing failed on `${{ matrix.NAME }}` build. - ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/release_workflow.yml b/.github/workflows/release_workflow.yml index 7bdb76f4..d9525987 100644 --- a/.github/workflows/release_workflow.yml +++ b/.github/workflows/release_workflow.yml @@ -22,9 +22,9 @@ jobs: id-token: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v6 with: python-version: "3.x" diff --git a/pycycle/elements/test/test_bleed_out.py b/pycycle/elements/test/test_bleed_out.py index 529ae044..ec50aed0 100644 --- a/pycycle/elements/test/test_bleed_out.py +++ b/pycycle/elements/test/test_bleed_out.py @@ -36,6 +36,9 @@ def test_case1(self): cycle.set_input_defaults('T', 500., units='degR') cycle.set_input_defaults('flow_start.W', 500., units='lbm/s') + cycle.set_input_defaults('bleed.Fl_I:tot:T', units='degR') + cycle.set_input_defaults('bleed.Fl_I:tot:P', units='psi') + self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_solver_print(level=-1) @@ -46,7 +49,7 @@ def test_case1(self): Tt_in = self.prob.get_val('bleed.Fl_I:tot:T', units='degR') Pt_in = self.prob.get_val('bleed.Fl_I:tot:P', units='psi') W_in = self.prob['bleed.Fl_I:stat:W'] - + assert_near_equal(self.prob['bleed.Fl_O:tot:T'], Tt_in, tol) assert_near_equal(self.prob['bleed.bld1:tot:T'], Tt_in, tol) assert_near_equal(self.prob['bleed.bld2:tot:T'], Tt_in, tol) @@ -59,7 +62,7 @@ def test_case1(self): assert_near_equal(self.prob['bleed.bld1:stat:W'], W_in*0.1, tol) assert_near_equal(self.prob['bleed.bld2:stat:W'], W_in*0.1, tol) - partial_data = self.prob.check_partials(out_stream=None, method='cs', + partial_data = self.prob.check_partials(out_stream=None, method='cs', includes=['bleed.*'], excludes=['*.base_thermo.*',]) assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) From 15f7def1ad16a778e68a2931f65332b0acb92c6e Mon Sep 17 00:00:00 2001 From: Kenneth-T-Moore Date: Wed, 20 May 2026 13:14:24 -0400 Subject: [PATCH 2/3] Modernize CI to use pixi envs from OM. Also, fix tests to pass with more recent OM --- .github/workflows/pycycle_test_workflow.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pycycle_test_workflow.yml b/.github/workflows/pycycle_test_workflow.yml index 05dd4157..f91f76fd 100644 --- a/.github/workflows/pycycle_test_workflow.yml +++ b/.github/workflows/pycycle_test_workflow.yml @@ -96,25 +96,22 @@ jobs: id: setup_pixi_environment uses: OpenMDAO/OpenMDAO/.github/actions/setup_openmdao_pixi@master with: - environment: '${{ inputs.OPENMDAO_PIXI_ENVIRONMENT }}' - openmdao_install_from: '${{ inputs.OPENMDAO_INSTALL_FROM }}' - openmdao_version: '${{ inputs.OPENMDAO }}' + environment: '${{ matrix.OPENMDAO_PIXI_ENVIRONMENT }}' + openmdao_install_from: '${{ matrix.OPENMDAO_INSTALL_FROM }}' + openmdao_version: '${{ matrix.OPENMDAO }}' - name: Install pyCycle run: | + eval "$(pixi shell-hook -e ${{ matrix.OPENMDAO_PIXI_ENVIRONMENT }} --manifest-path=${{ env.PIXI_MANIFEST }})" echo "=============================================================" echo "Install pyCycle" echo "=============================================================" python -m pip install -e .[all] - - name: Display environment info - run: | - conda info - conda list - - name: Run tests id: run_tests run: | + eval "$(pixi shell-hook -e ${{ matrix.OPENMDAO_PIXI_ENVIRONMENT }} --manifest-path=${{ env.PIXI_MANIFEST }})" echo "=============================================================" echo "Run tests (from directory other than repo root)" echo "=============================================================" @@ -127,6 +124,7 @@ jobs: id: deprecations_report continue-on-error: true run: | + eval "$(pixi shell-hook -e ${{ matrix.OPENMDAO_PIXI_ENVIRONMENT }} --manifest-path=${{ env.PIXI_MANIFEST }})" echo "=============================================================" echo "Display deprecations report" echo "=============================================================" @@ -140,6 +138,7 @@ jobs: - name: Check NumPy 2.0 Compatibility run: | + eval "$(pixi shell-hook -e ${{ matrix.OPENMDAO_PIXI_ENVIRONMENT }} --manifest-path=${{ env.PIXI_MANIFEST }})" echo "=============================================================" echo "Check code for NumPy 2.0 compatibility" echo "See: https://numpy.org/devdocs/numpy_2_0_migration_guide.html" From 69703dd260d811733c374b350fe96d19639c0167 Mon Sep 17 00:00:00 2001 From: Kenneth-T-Moore Date: Wed, 20 May 2026 13:30:57 -0400 Subject: [PATCH 3/3] Some fixes for numpy 2 --- example_cycles/simple_turbojet.py | 18 ++++----- pycycle/thermo/cea/props_calcs.py | 4 +- pycycle/thermo/cea/props_rhs.py | 2 +- pycycle/thermo/tabular/thermo_add.py | 56 ++++++++++++++-------------- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/example_cycles/simple_turbojet.py b/example_cycles/simple_turbojet.py index f77387ea..70cffdd6 100644 --- a/example_cycles/simple_turbojet.py +++ b/example_cycles/simple_turbojet.py @@ -11,11 +11,11 @@ def setup(self): USE_TABULAR = True - if USE_TABULAR: + if USE_TABULAR: self.options['thermo_method'] = 'TABULAR' self.options['thermo_data'] = pyc.AIR_JETA_TAB_SPEC FUEL_TYPE = "FAR" - else: + else: self.options['thermo_method'] = 'CEA' self.options['thermo_data'] = pyc.species_data.janaf FUEL_TYPE = "Jet-A(g)" @@ -86,7 +86,7 @@ def setup(self): self.connect('balance.W', 'inlet.Fl_I:stat:W') self.connect('nozz.Throat:stat:area', 'balance.lhs:W') - + newton = self.nonlinear_solver = om.NewtonSolver() newton.options['atol'] = 1e-6 newton.options['rtol'] = 1e-6 @@ -95,7 +95,7 @@ def setup(self): newton.options['solve_subsystems'] = True newton.options['max_sub_solves'] = 100 newton.options['reraise_child_analysiserror'] = False - + self.linear_solver = om.DirectSolver() super().setup() @@ -105,7 +105,7 @@ def viewer(prob, pt, file=sys.stdout): print a report of all the relevant cycle properties """ - summary_data = (prob[pt+'.fc.Fl_O:stat:MN'], prob[pt+'.fc.alt'], prob[pt+'.inlet.Fl_O:stat:W'], + summary_data = (prob[pt+'.fc.Fl_O:stat:MN'], prob[pt+'.fc.alt'], prob[pt+'.inlet.Fl_O:stat:W'], prob[pt+'.perf.Fn'], prob[pt+'.perf.Fg'], prob[pt+'.inlet.F_ram'], prob[pt+'.perf.OPR'], prob[pt+'.perf.TSFC']) @@ -172,7 +172,7 @@ def setup(self): self.pyc_add_cycle_param('burner.dPqP', 0.03) self.pyc_add_cycle_param('nozz.Cv', 0.99) - + # define the off-design conditions we want to run self.od_pts = ['OD0', 'OD1'] self.od_MNs = [0.000001, 0.2] @@ -184,7 +184,7 @@ def setup(self): self.set_input_defaults(pt+'.fc.MN', val=self.od_MNs[i]) self.set_input_defaults(pt+'.fc.alt', self.od_alts[i], units='ft') - self.set_input_defaults(pt+'.balance.Fn_target', self.od_Fns[i], units='lbf') + self.set_input_defaults(pt+'.balance.Fn_target', self.od_Fns[i], units='lbf') self.pyc_use_default_des_od_conns() @@ -209,8 +209,8 @@ def setup(self): prob.set_val('DESIGN.fc.alt', 0, units='ft') prob.set_val('DESIGN.fc.MN', 0.000001) prob.set_val('DESIGN.balance.Fn_target', 11800.0, units='lbf') - prob.set_val('DESIGN.balance.T4_target', 2370.0, units='degR') - prob.set_val('DESIGN.comp.PR', 13.5) + prob.set_val('DESIGN.balance.T4_target', 2370.0, units='degR') + prob.set_val('DESIGN.comp.PR', 13.5) prob.set_val('DESIGN.comp.eff', 0.83) prob.set_val('DESIGN.turb.eff', 0.86) diff --git a/pycycle/thermo/cea/props_calcs.py b/pycycle/thermo/cea/props_calcs.py index a71842a1..912fb4fc 100644 --- a/pycycle/thermo/cea/props_calcs.py +++ b/pycycle/thermo/cea/props_calcs.py @@ -60,7 +60,7 @@ def compute(self, inputs, outputs): nj = inputs['n'][:num_prod] # nj[nj<0] = 1e-10 # ensure all concentrations stay non-zero - n_moles = inputs['n_moles'] + n_moles = inputs['n_moles'][0] self.dlnVqdlnP = dlnVqdlnP = -1 + inputs['result_P'][num_element] self.dlnVqdlnT = dlnVqdlnT = 1 - result_T[num_element] @@ -109,7 +109,7 @@ def compute_partials(self, inputs, J): T = inputs['T'] P = inputs['P'] nj = inputs['n'] - n_moles = inputs['n_moles'] + n_moles = inputs['n_moles'][0] result_T = inputs['result_T'] result_T_last = result_T[num_element] result_T_rest = result_T[:num_element] diff --git a/pycycle/thermo/cea/props_rhs.py b/pycycle/thermo/cea/props_rhs.py index fe68e0df..d8049b67 100644 --- a/pycycle/thermo/cea/props_rhs.py +++ b/pycycle/thermo/cea/props_rhs.py @@ -96,7 +96,7 @@ def compute(self, inputs, outputs): # rhs for P outputs['rhs_P'][:num_element] = b0 - outputs['rhs_P'][num_element] = inputs['n_moles'] + outputs['rhs_P'][num_element] = inputs['n_moles'][0] # rhs for T self.H0_T = H0_T = thermo.H0(T) diff --git a/pycycle/thermo/tabular/thermo_add.py b/pycycle/thermo/tabular/thermo_add.py index b2c19c34..9b890ed5 100644 --- a/pycycle/thermo/tabular/thermo_add.py +++ b/pycycle/thermo/tabular/thermo_add.py @@ -6,33 +6,33 @@ class ThermoAdd(om.ExplicitComponent): """ - ThermoAdd calculates a new composition given inflow, + ThermoAdd calculates a new composition given inflow, a reactant to add, and a mix ratio. - When in `reactant` mode you can only mix one reactant type per instance. - You may have as many mix ports as you like, but all must use the same reactant. + When in `reactant` mode you can only mix one reactant type per instance. + You may have as many mix ports as you like, but all must use the same reactant. - If you want to mix multiple reactants, use two separate instances. + If you want to mix multiple reactants, use two separate instances. """ def initialize(self): self.options.declare('spec', default=AIR_JETA_TAB_SPEC, recordable=False) - self.options.declare('inflow_composition', default=None, + self.options.declare('inflow_composition', default=None, desc='composition present in the inflow') self.options.declare('mix_mode', values=['reactant', 'flow'], default='reactant') - self.options.declare('mix_composition', default=None, - desc='name of the mixing reactant; must match one of the keys from the inflow composition dictionary', + self.options.declare('mix_composition', default=None, + desc='name of the mixing reactant; must match one of the keys from the inflow composition dictionary', types=(dict, str, list, tuple), allow_none=True) self.options.declare('mix_names', default='mix', types=(str, list, tuple)) def output_port_data(self): spec = self.options['spec'] - + inflow_composition = self.options['inflow_composition'] - if inflow_composition is None: + if inflow_composition is None: inflow_composition = TAB_AIR_FUEL_COMPOSITION mix_mode = self.options['mix_mode'] @@ -49,12 +49,12 @@ def setup(self): mix_mode = self.options['mix_mode'] mix_names = self.options['mix_names'] - if isinstance(mix_names, str): # cast it to tuple - mix_names = (mix_names,) + if isinstance(mix_names, str): # cast it to tuple + mix_names = (mix_names,) self.mix_names = mix_names inflow_composition = self.options['inflow_composition'] - if inflow_composition is None: + if inflow_composition is None: inflow_composition = TAB_AIR_FUEL_COMPOSITION inflow_composition_vec = list(inflow_composition.values()) @@ -64,17 +64,17 @@ def setup(self): # inputs self.add_input('Fl_I:stat:W', val=0.0, desc='weight flow', units='lbm/s') self.add_input('Fl_I:tot:h', val=0.0, desc='total enthalpy', units='Btu/lbm') - self.add_input('Fl_I:tot:composition', val=inflow_composition_vec, + self.add_input('Fl_I:tot:composition', val=inflow_composition_vec, desc='incoming flow composition') - - for name in mix_names: + + for name in mix_names: self.add_input(f'{name}:h', val=0.0, units='Btu/lbm', desc="reactant enthalpy") - if mix_mode == 'reactant': + if mix_mode == 'reactant': self.add_input(f'{name}:ratio', val=0.0, desc='reactant to air mass ratio') self.add_output(f'{name}:W', shape=1, units="lbm/s", desc="mix input massflow") - else: + else: self.add_input(f'{name}:composition', val=inflow_composition_vec, desc='mix flow composition' ) self.add_input(f'{name}:W', shape=1, units="lbm/s", desc="mix input massflow") @@ -87,20 +87,18 @@ def setup(self): self.declare_partials('*', '*', method='cs') - def compute(self, inputs, outputs): + def compute(self, inputs, outputs): mix_mode = self.options['mix_mode'] compo_in = inputs['Fl_I:tot:composition'] - n_compo = len(compo_in) - W_in = inputs['Fl_I:stat:W'] # composition vector is always given as vector of -to-air ratios W_air_in = W_in/(1+np.sum(compo_in)) W_other_in = W_air_in * compo_in - W_out = 0 + W_out = 0 W_out += W_in W_other_out = np.zeros_like(compo_in) @@ -110,15 +108,15 @@ def compute(self, inputs, outputs): W_times_h = W_in*inputs['Fl_I:tot:h'] - if mix_mode == "reactant": + if mix_mode == "reactant": - for mix_name in self.mix_names: + for mix_name in self.mix_names: ratio = inputs[f'{mix_name}:ratio'] # scalar for reactant mode W_air_mix = W_air_in # for reactant mode, we reference from the incoming air - W_other_mix = W_air_mix * ratio - outputs[f'{mix_name}:W'] = W_other_mix - W_other_out[self.idx_compo] += W_other_mix + W_other_mix = W_air_mix * ratio + outputs[f'{mix_name}:W'] = W_other_mix[0] + W_other_out[self.idx_compo] += W_other_mix[0] W_out += W_other_mix W_times_h += W_other_mix*inputs[f'{mix_name}:h'] @@ -126,9 +124,9 @@ def compute(self, inputs, outputs): outputs['Wout'] = W_out outputs['mass_avg_h'] = W_times_h/W_out - else: + else: - for mix_name in self.mix_names: + for mix_name in self.mix_names: compo_mix = inputs[f'{mix_name}:composition'] # potentially a vector W_mix = inputs[f'{mix_name}:W'] @@ -145,4 +143,4 @@ def compute(self, inputs, outputs): - +