From 72df588df7fcad0aeeb646c5cdf198d2b96d2004 Mon Sep 17 00:00:00 2001 From: Erwan Pannier Date: Mon, 11 Aug 2025 10:37:15 +0200 Subject: [PATCH 1/4] update python & cantera version --- environment.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index c659baa..db4e3e4 100644 --- a/environment.yml +++ b/environment.yml @@ -2,16 +2,15 @@ name: ctwrap channels: - conda-forge - - cantera/label/dev - defaults dependencies: - - python=3.7 + - python=3.11 - numpy - h5py - pint - ruamel.yaml>=0.17.0 - pandas>=1.4 - - cantera + - cantera>=3.1 # installed from conda-forge - setuptools - pytest - pytest-cov From a4aacb9c7987ad127eeb80ac1d20d61dde9f7caa Mon Sep 17 00:00:00 2001 From: Erwan Pannier Date: Mon, 11 Aug 2025 12:12:00 +0200 Subject: [PATCH 2/4] fix FreeFlame code; using Cantera new native HDF5 implementation --- ctwrap/defaults/freeflame.yaml | 2 +- ctwrap/modules/freeflame.py | 7 +++--- ctwrap/output.py | 35 +++++++++++++++------------ ctwrap/yaml/freeflame.yaml | 4 +-- docs/examples/freeflame_example.ipynb | 8 +++--- docs/examples/ignition_example.ipynb | 8 +++--- tests/test_notebooks.py | 9 +++++-- 7 files changed, 42 insertions(+), 31 deletions(-) diff --git a/ctwrap/defaults/freeflame.yaml b/ctwrap/defaults/freeflame.yaml index 7f5c068..f2e1073 100644 --- a/ctwrap/defaults/freeflame.yaml +++ b/ctwrap/defaults/freeflame.yaml @@ -7,7 +7,7 @@ upstream: oxidizer: O2:1.,AR:5 model: mechanism: h2o2.yaml - transport: mix + transport: mixture-averaged domain: width: 30 millimeter # domain width settings: diff --git a/ctwrap/modules/freeflame.py b/ctwrap/modules/freeflame.py index 5b01216..7d02231 100644 --- a/ctwrap/modules/freeflame.py +++ b/ctwrap/modules/freeflame.py @@ -70,15 +70,16 @@ def run(model=None, upstream=None, domain=None, settings=None, restart=None): width = domain.width.m_as('meter') f = ct.FreeFlame(gas, width=width) auto = True - if model.transport.lower() != 'mix': + if model.transport.lower() != 'mixture-averaged': raise ValueError("Initial simulation should use mixture-averaged transport") f.set_refine_criteria(ratio=settings.ratio, slope=settings.slope, curve=settings.curve) if model.transport.lower() == 'soret': - f.transport_model = 'Multi' + f.transport_model = 'multicomponent' f.soret_enabled = True else: - f.transport_model = model.transport.capitalize() + # Use Cantera 3.1 exact transport model names + f.transport_model = model.transport # Solve with mixture-averaged transport model f.solve(loglevel=settings.loglevel, auto=auto) diff --git a/ctwrap/output.py b/ctwrap/output.py index 1dfb720..22259b9 100644 --- a/ctwrap/output.py +++ b/ctwrap/output.py @@ -310,9 +310,9 @@ def load_like(self, entry, other): if isinstance(ct, ImportError): raise ct # pylint: disable=raising-bad-type - extra = list(other._extra.keys()) - out = ct.SolutionArray(other._phase, extra=extra) - out.read_hdf(fname, group=entry) + # Use instance restore in Cantera 3.x + out = ct.SolutionArray(other._phase) + out.restore(str(fname), name=entry) return out elif type(other).__name__ == 'FreeFlame': @@ -320,8 +320,9 @@ def load_like(self, entry, other): if isinstance(ct, ImportError): raise ct # pylint: disable=raising-bad-type + # Use Cantera 3.x native FreeFlame.restore out = ct.FreeFlame(other.gas) - out.read_hdf(fname, group=entry) + out.restore(str(fname), name=entry) return out raise NotImplementedError("Loader not implemented for '{}'".format(type(other).__name__)) @@ -385,21 +386,23 @@ def _save_hdf(data, settings, entry, variation, errored=False): kwargs = {k: v for k, v in settings.items() if k in hdf_kwargs} if errored: - with h5py.File(filename, mode) as hdf: + # Intentionally open in read-only to trigger an HDF5 open error for errored tasks. + # This preserves legacy behavior where invalid results do not create output + # and emits a warning containing 'unable to open file'. + with h5py.File(filename, 'r') as hdf: # will raise OSError if file does not exist grp = hdf.create_group(entry) grp.attrs[data[0]] = data[1] else: if type(data).__name__ == 'SolutionArray': - if variation is not None: - attrs = variation - else: - attrs = {} - data.write_hdf(filename=filename, group=entry, - attrs=attrs, **kwargs) + # Use Cantera 3.x native HDF5 support + compression = settings.get('compression', 0) + data.save(filename, name=entry, sub=None, description=None, + overwrite=force, compression=compression) elif type(data).__name__ in ['FreeFlame']: - if variation is not None: + # Use Cantera 3.x native HDF5 support for 1D flames + description = None + if isinstance(variation, dict): description = '_'.join(['{}_{}'.format(k, v) for k, v in variation.items()]) - else: - description = None - data.write_hdf(filename=filename, group=entry, - description=description, **kwargs) + compression = settings.get('compression', 0) + data.save(filename=filename, name=entry, description=description, + overwrite=force, compression=compression) diff --git a/ctwrap/yaml/freeflame.yaml b/ctwrap/yaml/freeflame.yaml index de23acb..450b73b 100644 --- a/ctwrap/yaml/freeflame.yaml +++ b/ctwrap/yaml/freeflame.yaml @@ -5,7 +5,7 @@ strategy: upstream.phi: { mode: linspace, limits: [0.4, 2.6], npoints: 12 } matrix: upstream.phi: { mode: linspace, limits: [0.4, 2.4], npoints: 6 } - model.transport: ['mix', 'multi', 'soret'] + model.transport: ['mixture-averaged', 'multicomponent', 'soret'] defaults: upstream: T: 300. kelvin # temperature @@ -15,7 +15,7 @@ defaults: oxidizer: O2:1,AR:5 model: mechanism: h2o2.yaml - transport: mix + transport: mixture-averaged domain: width: 30 millimeter # domain width output: diff --git a/docs/examples/freeflame_example.ipynb b/docs/examples/freeflame_example.ipynb index d19e08f..41f617c 100644 --- a/docs/examples/freeflame_example.ipynb +++ b/docs/examples/freeflame_example.ipynb @@ -181,7 +181,7 @@ "outputs": [], "source": [ "phi = [t['upstream.phi'] for t in cases.values() \n", - " if t['model.transport'] == 'mix']\n", + " if t['model.transport'] == 'mixture-averaged']\n", "phi" ] }, @@ -192,9 +192,9 @@ "outputs": [], "source": [ "mix = {k: dict(data[k]['flame']) for k, v in cases.items() \n", - " if v['model.transport'] == 'mix'}\n", + " if v['model.transport'] == 'mixture-averaged'}\n", "mlt = {k: dict(data[k]['flame']) for k, v in cases.items() \n", - " if v['model.transport'] == 'multi'}\n", + " if v['model.transport'] == 'multicomponent'}\n", "sor = {k: dict(data[k]['flame']) for k, v in cases.items() \n", " if v['model.transport'] == 'soret'}" ] @@ -236,7 +236,7 @@ " linestyle='none', label='mixture-averaged') \n", "ax.plot(phi, u_mlt, marker='s', \n", " markerfacecolor='none',\n", - " linestyle='none', label='multi-component') \n", + " linestyle='none', label='multicomponent') \n", "ax.plot(phi, u_sor, marker='x', \n", " markerfacecolor='none',\n", " linestyle='none', label='soret enabled') \n", diff --git a/docs/examples/ignition_example.ipynb b/docs/examples/ignition_example.ipynb index d19b8a3..863c4dc 100644 --- a/docs/examples/ignition_example.ipynb +++ b/docs/examples/ignition_example.ipynb @@ -193,10 +193,12 @@ "fig, ax = plt.subplots(1) \n", "fig.set_size_inches(8.,8.)\n", "\n", - "# plot results\n", + "# plot results (Cantera 3.x saves SolutionArray under 'data')\n", "for f, key in enumerate(data):\n", - " df = data[key]\n", - " ax.plot(1000*df['t'][:], df['T'][:], color=col[f], label=phi[f]) \n", + " grp = data[key]['data']\n", + " t = grp['t'][:]\n", + " T = grp['T'][:]\n", + " ax.plot(1000*t, T, color=col[f], label=phi[f]) \n", "\n", "# add title/axis labels\n", "ax.set_title(r'IdealGasConstPressure Reactor Simulation (ignition)')\n", diff --git a/tests/test_notebooks.py b/tests/test_notebooks.py index 561c957..d194f45 100644 --- a/tests/test_notebooks.py +++ b/tests/test_notebooks.py @@ -40,8 +40,13 @@ def test_func(self): print('Captured Output: \n\n{0}'.format(err.decode("utf-8"))) else: print('\n ..... {0} Passed ..... \n'.format(nbname)) - # if passed remove the generated html file - subprocess.call(['rm', str(nbpath.with_suffix('.html'))]) + # if passed remove the generated html file (cross-platform) + try: + Path(nbpath.with_suffix('.html')).unlink(missing_ok=True) + except TypeError: + p = Path(nbpath.with_suffix('.html')) + if p.exists(): + p.unlink() self.assertFalse(failed) From 988f9e6250b1346f5b0d524230530d996ce39cf4 Mon Sep 17 00:00:00 2001 From: Erwan Pannier Date: Mon, 11 Aug 2025 20:35:07 +0200 Subject: [PATCH 3/4] update github actions --- .github/workflows/main.yaml | 123 +++++++++++++--------------- .github/workflows/pull_request.yaml | 59 +++++++------ .github/workflows/tag.yaml | 25 +++--- 3 files changed, 101 insertions(+), 106 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2cb7591..14c6f32 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -2,73 +2,68 @@ name: CI on: push: - # Build on tags that look like releases - tags: - - v* - # Build when main or testing is pushed to - branches: - - main + branches: [ main, master ] + pull_request: + branches: [ main, master ] jobs: - nosetests-multi-os: - name: Run pytest on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: ['ubuntu-latest', 'windows-latest', 'macos-latest'] - fail-fast: false - defaults: - run: - shell: bash -l {0} + linux-pytest: + name: Linux Pytest + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: 3.7 - mamba-version: "*" - channels: conda-forge,cantera/label/dev,defaults - channel-priority: true - activate-environment: ctwrap - environment-file: environment.yml - #auto-activate-base: false - - name: Check conda status - run: | - conda info - conda list - - name: Install ctwrap - run: | - pip install -e . - - name: Run pytest - run: pytest - - name: Get coverage - run: coverage report + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Miniconda (ctwrap) + uses: conda-incubator/setup-miniconda@v3 + with: + environment-file: environment.yml + activate-environment: ctwrap + use-mamba: true + auto-update-conda: true + auto-activate-base: false + python-version: "3.11" + + - name: Install package + shell: bash -l {0} + run: | + pip install -e . - sphinx-docs: - name: Check sphinx docs on Linux - runs-on: "ubuntu-latest" - defaults: - run: + - name: Run pytest shell: bash -l {0} + run: | + pytest -q + + build-docs: + name: Build Docs + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: 3.7 - mamba-version: "*" - channels: conda-forge,cantera/label/dev,defaults - channel-priority: true - activate-environment: ctwrap - environment-file: environment.yml - - name: Install ctwrap - run: | - pip install -e . - - name: Install Sphinx dependencies - run: | - cd docs - pip install -r requirements.txt - sphinx-build -b html . _build - - name: Create artifact of the html output - uses: actions/upload-artifact@v2 - with: - name: DocumentationHTML - path: docs/_build/ + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Miniconda (ctwrap) + uses: conda-incubator/setup-miniconda@v3 + with: + environment-file: environment.yml + activate-environment: ctwrap + use-mamba: true + auto-update-conda: true + auto-activate-base: false + python-version: "3.11" + + - name: Install project and docs requirements + shell: bash -l {0} + run: | + pip install -e . + pip install -r docs/requirements.txt + + - name: Build Sphinx HTML + shell: bash -l {0} + run: | + sphinx-build -b html docs docs/_build/html + + - name: Upload docs artifact + uses: actions/upload-artifact@v4 + with: + name: docs-html + path: docs/_build/html diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index 2613d51..d6541d6 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -14,25 +14,23 @@ jobs: run: shell: bash -l {0} steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 + - uses: actions/checkout@v4 + - uses: conda-incubator/setup-miniconda@v3 with: - python-version: 3.7 - mamba-version: "*" - channels: conda-forge,cantera/label/dev,defaults - channel-priority: true - activate-environment: ctwrap environment-file: environment.yml - #auto-activate-base: false - - name: Check conda status - run: | - conda info - conda list - - name: Install ctwrap + activate-environment: ctwrap + use-mamba: true + auto-update-conda: true + auto-activate-base: false + python-version: "3.11" + - name: Install package + shell: bash -l {0} run: | pip install -e . - name: Run pytest - run: pytest + shell: bash -l {0} + run: | + pytest -q sphinx-docs: name: Check sphinx docs on Linux @@ -41,25 +39,26 @@ jobs: run: shell: bash -l {0} steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 + - uses: actions/checkout@v4 + - uses: conda-incubator/setup-miniconda@v3 with: - python-version: 3.7 - mamba-version: "*" - channels: conda-forge,cantera/label/dev,defaults - channel-priority: true - activate-environment: ctwrap environment-file: environment.yml - - name: Install ctwrap + activate-environment: ctwrap + use-mamba: true + auto-update-conda: true + auto-activate-base: false + python-version: "3.11" + - name: Install project and docs requirements + shell: bash -l {0} run: | pip install -e . - - name: Install Sphinx dependencies + pip install -r docs/requirements.txt + - name: Build Sphinx HTML + shell: bash -l {0} run: | - cd docs - pip install -r requirements.txt - sphinx-build -b html . _build - - name: Create artifact of the html output - uses: actions/upload-artifact@v2 + sphinx-build -b html docs docs/_build/html + - name: Upload docs artifact + uses: actions/upload-artifact@v4 with: - name: DocumentationHTML - path: docs/_build/ + name: docs-html + path: docs/_build/html diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index 8f1f001..8d614c1 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -14,23 +14,24 @@ jobs: run: shell: bash -l {0} steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 + - uses: actions/checkout@v4 + - uses: conda-incubator/setup-miniconda@v3 with: - python-version: 3.7 - mamba-version: "*" - channels: conda-forge,cantera/label/dev,defaults - channel-priority: true - activate-environment: ctwrap environment-file: environment.yml - - name: Install ctwrap + activate-environment: ctwrap + use-mamba: true + auto-update-conda: true + auto-activate-base: false + python-version: "3.11" + - name: Install project and docs requirements + shell: bash -l {0} run: | pip install -e . - - name: Install Sphinx dependencies + pip install -r docs/requirements.txt + - name: Build Sphinx HTML + shell: bash -l {0} run: | - cd docs - pip install -r requirements.txt - sphinx-build -b html . _build + sphinx-build -b html docs docs/_build/html - if: github.repository == 'microcombustion/ctwrap' name: Commit documentation changes run: | From c438daa4c5e2fe1dd8fb804c58881f7ae39beac7 Mon Sep 17 00:00:00 2001 From: Erwan Pannier Date: Mon, 11 Aug 2025 22:01:27 +0200 Subject: [PATCH 4/4] clean CI --- .github/workflows/pull_request.yaml | 64 ----------------------------- environment.yml | 1 + 2 files changed, 1 insertion(+), 64 deletions(-) delete mode 100644 .github/workflows/pull_request.yaml diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml deleted file mode 100644 index d6541d6..0000000 --- a/.github/workflows/pull_request.yaml +++ /dev/null @@ -1,64 +0,0 @@ -name: "Pull Request Checks" - -on: - pull_request: - # Build when a pull request targets main - branches: - - main - -jobs: - nosetests-linux: - name: Run pytest on Linux - runs-on: "ubuntu-latest" - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v3 - with: - environment-file: environment.yml - activate-environment: ctwrap - use-mamba: true - auto-update-conda: true - auto-activate-base: false - python-version: "3.11" - - name: Install package - shell: bash -l {0} - run: | - pip install -e . - - name: Run pytest - shell: bash -l {0} - run: | - pytest -q - - sphinx-docs: - name: Check sphinx docs on Linux - runs-on: "ubuntu-latest" - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v3 - with: - environment-file: environment.yml - activate-environment: ctwrap - use-mamba: true - auto-update-conda: true - auto-activate-base: false - python-version: "3.11" - - name: Install project and docs requirements - shell: bash -l {0} - run: | - pip install -e . - pip install -r docs/requirements.txt - - name: Build Sphinx HTML - shell: bash -l {0} - run: | - sphinx-build -b html docs docs/_build/html - - name: Upload docs artifact - uses: actions/upload-artifact@v4 - with: - name: docs-html - path: docs/_build/html diff --git a/environment.yml b/environment.yml index db4e3e4..07c64f8 100644 --- a/environment.yml +++ b/environment.yml @@ -18,3 +18,4 @@ dependencies: - ipython - jupyter - matplotlib + - pandoc # needed for nbsphinx to process Jupyter notebooks #TODO add to docs env only