From 3ea0fcaede4bb50d081fca1638c4aae5dd108899 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Wed, 12 Aug 2026 16:52:26 +0200 Subject: [PATCH 01/12] =?UTF-8?q?=F0=9F=94=A7=20Update=20dependabot=20conf?= =?UTF-8?q?iguration=20for=20GitHub=20Actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e38985c..52e9319 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,9 @@ updates: github-actions: patterns: - "*" + allow: + - dependency-type: all + labels: + - "tool: github actions" + commit-message: + prefix: "โฌ†๏ธ " From 91f126456481de5e888bed8bc914b16a2385fb46 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Thu, 13 Aug 2026 10:44:15 +0200 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8=20Enhance=20triangulated=20mesh?= =?UTF-8?q?=20plotting=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 14 ++++ .../imas/ggd/unstruct_2d_extend_mesh.py | 5 +- src/cherab/imas/ggd/unstruct_2d_mesh.py | 50 +++++++------ .../imas/ids/radiation/load_radiation.py | 3 + tests/ggd/test_unstruct_2d_mesh.py | 73 +++++++++++++++++++ typos.toml | 1 + 6 files changed, 121 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1491f..962aea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Add `UnstructGrid2D.plot_tri_mesh()` for plotting cell data on the triangulated mesh with Matplotlib's `tripcolor()` + +### Changed + +- Use explicit triangle face colors in the `plot_tri_mesh()` implementations of the 2D and 2D-extended unstructured grids + +### Removed + +- **Breaking:** Remove the redundant `UnstructGrid2D.plot_triangle_mesh()` method in favor of `plot_tri_mesh()` + ## [0.6.0] - 2026-08-12 ### Added diff --git a/src/cherab/imas/ggd/unstruct_2d_extend_mesh.py b/src/cherab/imas/ggd/unstruct_2d_extend_mesh.py index 93d2d8f..bdfd0d7 100644 --- a/src/cherab/imas/ggd/unstruct_2d_extend_mesh.py +++ b/src/cherab/imas/ggd/unstruct_2d_extend_mesh.py @@ -126,14 +126,13 @@ def __init__( self._num_faces = num_faces self._num_poloidal = num_poloidal self._num_toroidal = num_toroidal - self._triangulation = None # matplotlib's triangulation at the poloidal plane for plotting - super().__init__(name, 3, coordinate_system) @override def _initial_setup(self) -> None: self._scalar_interpolator = None self._vector_interpolator = None + self._triangulation: Triangulation | None = None self._num_cell: int = self._cells.shape[0] @@ -713,7 +712,7 @@ def plot_tri_mesh( _, ax = plt.subplots(layout="constrained") ax.set_aspect(1) - ax.tripcolor(self._triangulation, data, cmap=cmap, **kwargs) + ax.tripcolor(self._triangulation, facecolors=data, cmap=cmap, **kwargs) ax.set_xlim(self._mesh_extent["rmin"], self._mesh_extent["rmax"]) ax.set_ylim(self._mesh_extent["zmin"], self._mesh_extent["zmax"]) diff --git a/src/cherab/imas/ggd/unstruct_2d_mesh.py b/src/cherab/imas/ggd/unstruct_2d_mesh.py index 3ac278c..624573b 100755 --- a/src/cherab/imas/ggd/unstruct_2d_mesh.py +++ b/src/cherab/imas/ggd/unstruct_2d_mesh.py @@ -33,6 +33,7 @@ import matplotlib.pyplot as plt import numpy as np from matplotlib.collections import PolyCollection +from matplotlib.tri import Triangulation from numpy.typing import ArrayLike, NDArray from raysect.core.math.polygon import triangulate2d from raysect.core.math.vector import Vector3D @@ -170,6 +171,7 @@ def __init__( def _initial_setup(self) -> None: self._scalar_interpolator = None self._vector_interpolator = None + self._triangulation: Triangulation | None = None self._num_cell: int = len(self._cells) @@ -321,6 +323,7 @@ def subset( grid._dimension = self._dimension grid._scalar_interpolator = None grid._vector_interpolator = None + grid._triangulation = None grid._valid_data_mask = np.array(valid_data_mask, dtype=np.bool_, copy=True) grid._valid_data_mask.setflags(write=False) @@ -543,47 +546,50 @@ def __setstate__(self, state): self._initial_setup() - def plot_triangle_mesh( + def plot_tri_mesh( self, - data: CellData | None = None, + data: CellData, ax: matplotlib.axes.Axes | None = None, - **grid_styles, + cmap: str = "viridis", + **kwargs, ) -> matplotlib.axes.Axes: - """Plot the triangle mesh grid geometry to a matplotlib figure. + """Plot cell data on the triangular mesh using Matplotlib's tripcolor. Parameters ---------- data - Data array defined on the polygonal mesh. + Data array defined on the polygonal mesh. Each cell value is assigned to all + triangles forming that cell. ax Matplotlib axes to plot on. If None, a new figure and axes are created. - **grid_styles - Styles for the grid lines and faces, - by default ``{"facecolor": "none", "edgecolor": "b", "linewidth": 0.25}``. + cmap + Colormap to use for the data, by default ``"viridis"``. + **kwargs + Additional keyword arguments passed to `~matplotlib.axes.Axes.tripcolor`. Returns ------- `~matplotlib.axes.Axes` The matplotlib axes with the plotted mesh. """ + data_array = _as_cell_data(data, self._valid_data_mask) + triangle_data = data_array[self._triangle_to_cell_map] + + if self._triangulation is None: + self._triangulation = Triangulation( + self._vertices[:, 0], self._vertices[:, 1], self._triangles + ) + if ax is None: _, ax = plt.subplots(constrained_layout=True) - # Set default grid line styles if not provided - grid_styles.setdefault("facecolor", "none") - grid_styles.setdefault("edgecolor", "b") - grid_styles.setdefault("linewidth", 0.25) - - verts = self._vertices[self._triangles] - polygons = cast(Sequence[ArrayLike], verts) - if data is None: - collection_mesh = PolyCollection(polygons, **grid_styles) - else: - data_array = _as_cell_data(data, self._valid_data_mask) - collection_mesh = PolyCollection(polygons) - collection_mesh.set_array(data_array[self._triangle_to_cell_map]) - ax.add_collection(collection_mesh) ax.set_aspect(1) + ax.tripcolor( + self._triangulation, + facecolors=triangle_data, + cmap=cmap, + **kwargs, + ) ax.set_xlim(self._mesh_extent["xmin"], self._mesh_extent["xmax"]) ax.set_ylim(self._mesh_extent["ymin"], self._mesh_extent["ymax"]) diff --git a/src/cherab/imas/ids/radiation/load_radiation.py b/src/cherab/imas/ids/radiation/load_radiation.py index 2bb17ee..a1ef7f3 100644 --- a/src/cherab/imas/ids/radiation/load_radiation.py +++ b/src/cherab/imas/ids/radiation/load_radiation.py @@ -90,6 +90,9 @@ def _sum_ggd_species_emissivity( ) -> NDArray[np.float64] | None: """Sum ``(:)/emissivity(:)/(:)`` for one GGD structure. + For example, this sums ``ggd.ion(i)/emissivity(grid_subset_index)/values(:)`` across all ion + species entries. + Returns ------- `NDArray[numpy.float64]` or None diff --git a/tests/ggd/test_unstruct_2d_mesh.py b/tests/ggd/test_unstruct_2d_mesh.py index 36b64bd..54ed7bb 100644 --- a/tests/ggd/test_unstruct_2d_mesh.py +++ b/tests/ggd/test_unstruct_2d_mesh.py @@ -1,6 +1,8 @@ +import matplotlib.pyplot as plt import numpy as np import pytest +from cherab.imas.ggd.unstruct_2d_extend_mesh import UnstructGrid2DExtended from cherab.imas.ggd.unstruct_2d_mesh import UnstructGrid2D from cherab.imas.math.polygon import calculate_2d_cell_geometry @@ -67,3 +69,74 @@ def test_large_geometry_calculation_openmp_path(): np.testing.assert_allclose(centres[:, 0], 2.0 / 3.0) np.testing.assert_allclose(centres[:, 1], 1.0 / 3.0) np.testing.assert_allclose(areas, 1.0) + + +def test_plot_tri_mesh_maps_source_cell_data_to_triangles(): + vertices = np.array( + [ + [0.0, 0.0], + [1.0, 0.0], + [1.0, 1.0], + [0.0, 1.0], + [2.0, 0.0], + [3.0, 0.0], + [2.0, 1.0], + ] + ) + grid = UnstructGrid2D( + vertices, + [[0, 1, 2, 3], [4, 5, 6]], + valid_data_mask=np.array([True, False, True]), + coordinate_system="cartesian", + ) + + ax = grid.plot_tri_mesh([2.0, 99.0, 5.0], cmap="magma") + + arr = ax.collections[0].get_array() + assert arr is not None + np.testing.assert_allclose(arr, [2.0, 2.0, 5.0]) + assert ax.collections[0].get_cmap().name == "magma" + assert grid._triangulation is not None + assert not hasattr(grid, "plot_triangle_mesh") + fig = ax.get_figure() + assert isinstance(fig, plt.Figure) + plt.close(fig) + + +def test_extended_plot_tri_mesh_uses_triangle_face_data(): + vertices = np.array( + [ + [1.0, 0.0, 0.0], + [2.0, 0.0, 0.0], + [2.0, 0.0, 1.0], + [1.0, 0.0, 1.0], + [0.0, 1.0, 0.0], + [0.0, 2.0, 0.0], + [0.0, 2.0, 1.0], + [0.0, 1.0, 1.0], + ] + ) + cells = np.array( + [ + [0, 1, 2, 3, 4, 5, 6, 7], + [4, 5, 6, 7, 0, 1, 2, 3], + ] + ) + grid = UnstructGrid2DExtended( + vertices, + cells, + num_faces=1, + num_poloidal=4, + num_toroidal=2, + ) + + ax = grid.plot_tri_mesh([3.0], cmap="plasma") + + arr = ax.collections[0].get_array() + assert arr is not None + np.testing.assert_allclose(arr, [3.0, 3.0]) + assert ax.collections[0].get_cmap().name == "plasma" + assert grid._triangulation is not None + fig = ax.get_figure() + assert isinstance(fig, plt.Figure) + plt.close(fig) diff --git a/typos.toml b/typos.toml index dac3a3f..4a851e7 100644 --- a/typos.toml +++ b/typos.toml @@ -1,3 +1,4 @@ [default.extend-words] ist = "ist" arange = "arange" +writeable = "writeable" From 6ea2f83ffc48c2e126af06079ce90708f11acec3 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Fri, 14 Aug 2026 19:13:03 +0200 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9E=95=20Add=20cherab=20type=20stubs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently it is available through koyo-forge channel --- .lefthook.yaml | 2 -- pixi.toml | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.lefthook.yaml b/.lefthook.yaml index 696776a..6ac01a2 100644 --- a/.lefthook.yaml +++ b/.lefthook.yaml @@ -43,8 +43,6 @@ pre-commit: - name: pyrefly glob: "*.{py,pyi}" - skip: # Skip until raysect/cherab-stubs are released - - run: test ${CI:-false} = true run: pixi {run} pyrefly-check {staged_files} - name: actionlint diff --git a/pixi.toml b/pixi.toml index d148d73..a1335f1 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,5 +1,5 @@ [workspace] -channels = ["conda-forge"] +channels = ["conda-forge", "https://prefix.dev/koyo-forge"] platforms = ["linux-64", "osx-arm64", "osx-64"] preview = ["pixi-build"] @@ -39,6 +39,9 @@ typing-extensions = ">=4.5" cherab-imas = { path = "." } ipython = "*" +# Type stubs for static type checking +cherab-stubs = "*" + # Publication-quality plot ultraplot = ">=1.72.0" From 11858b0ca8f0333d0eb100be7d4cc6d951bbf562 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Mon, 24 Aug 2026 15:31:39 +0200 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=94=A7=20Update=20TOML=20formatting?= =?UTF-8?q?=20tool;=20use=20`tombi`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add/update corresponding files --- .lefthook.yaml | 4 +- .tombi.toml | 1 + pixi.toml | 105 +++++++++++++++++++++++++++---------------------- 3 files changed, 62 insertions(+), 48 deletions(-) create mode 100644 .tombi.toml diff --git a/.lefthook.yaml b/.lefthook.yaml index 6ac01a2..2c27561 100644 --- a/.lefthook.yaml +++ b/.lefthook.yaml @@ -24,10 +24,10 @@ pre-commit: stage_fixed: true run: pixi {run} dprint {staged_files} - - name: taplo + - name: toml format glob: "*.toml" stage_fixed: true - run: pixi {run} taplo {staged_files} + run: pixi {run} toml-format {staged_files} - name: ruff check glob: "*.{py,pyi}" diff --git a/.tombi.toml b/.tombi.toml new file mode 100644 index 0000000..b4b218b --- /dev/null +++ b/.tombi.toml @@ -0,0 +1 @@ +toml-version = "v1.1.0" diff --git a/pixi.toml b/pixi.toml index a1335f1..97d6912 100644 --- a/pixi.toml +++ b/pixi.toml @@ -3,11 +3,14 @@ channels = ["conda-forge", "https://prefix.dev/koyo-forge"] platforms = ["linux-64", "osx-arm64", "osx-64"] preview = ["pixi-build"] +[workspace.build-variants] +python = ["3.10.*", "3.11.*", "3.12.*", "3.13.*", "3.14.*"] + # ------------------------------- # === Packaging Configuration === # ------------------------------- [package] -version = "dynamic" # Until pixi recommends something else +version = "dynamic" # Until pixi recommends something else [package.build] backend = { name = "pixi-build-python", version = "*" } @@ -15,9 +18,6 @@ backend = { name = "pixi-build-python", version = "*" } [package.build.config] noarch = false -[workspace.build-variants] -python = ["3.10.*", "3.11.*", "3.12.*", "3.13.*", "3.14.*"] - [package.host-dependencies] python = "*" hatch-cython = ">=0.6.0" @@ -80,27 +80,37 @@ sphinx-github-style = "*" sphinx-api-relink = "*" [feature.docs.tasks] -doc-build = { cmd = [ - "sphinx-build", - "-b", - "{{ target }}", - "-j", - "auto", - "source", - "build/{{ target }}", -], cwd = "docs", args = [ - { arg = "target", default = "html" }, -], description = "๐Ÿ“ Build the docs" } -doc-serve = { args = [ - { arg = "port", default = "8000" }, -], cmd = [ - "python", - "-m", - "http.server", - "{{ port }}", - "--directory", - "build/html", -], cwd = "docs", description = "๐Ÿš€ Start a local server for the docs" } +doc-build = { + cmd = [ + "sphinx-build", + "-b", + "{{ target }}", + "-j", + "auto", + "source", + "build/{{ target }}", + ], + cwd = "docs", + args = [ + { arg = "target", default = "html" }, + ], + description = "๐Ÿ“ Build the docs", +} +doc-serve = { + cmd = [ + "python", + "-m", + "http.server", + "{{ port }}", + "--directory", + "build/html", + ], + cwd = "docs", + args = [ + { arg = "port", default = "8000" }, + ], + description = "๐Ÿš€ Start a local server for the docs", +} # === Linting feature === [feature.lint.dependencies] @@ -115,7 +125,7 @@ shellcheck = "*" validate-pyproject = "*" cython-lint = "*" blacken-docs = "*" -taplo = "*" +tombi = "*" nbstripout = ">=0.9.1,<0.10" [feature.lint.tasks] @@ -126,9 +136,9 @@ mypy = { cmd = "mypy", description = "Type check with mypy" } pyrefly-check = { cmd = "pyrefly check", description = "Type check with pyrefly" } ruff-check = { cmd = "ruff check --fix", description = "Lint with ruff" } ruff-format = { cmd = "ruff format", description = "Format with ruff" } +toml-format = { cmd = "tombi format", description = "Format TOML files" } dprint = { cmd = "dprint fmt", description = "Format with dprint" } typos = { cmd = "typos --write-changes --force-exclude", description = "Fix typos" } -taplo = { cmd = "taplo fmt", description = "Format toml files with taplo" } actionlint = { cmd = "actionlint", description = "Lint actions with actionlint" } blacken-docs = { cmd = "blacken-docs", description = "Format Python markdown blocks with Black" } validate-pyproject = { cmd = "validate-pyproject pyproject.toml", description = "Validate pyproject.toml" } @@ -137,29 +147,32 @@ lint = { cmd = "lefthook run pre-commit --all-files --force", description = " # Clean build artifacts [feature.tools.tasks] -clean = { cmd = "find src -type f \\( -name '*.c' -o -name '*.so' -o -name '*.pyd' -o -name '*.dll' \\) -delete", description = "๐Ÿงน Clean build artifacts" } -clean-c = { cmd = "find src -type f -name '*.c' -delete", description = "๐Ÿงน Clean C source files" } -doc-clean = { cmd = [ - "rm", - "-rf", - "build", - "source/_api", -], cwd = "docs", description = "๐Ÿ”ฅ Clean the docs build & api directory" } +clean = { + cmd = "find src -type f \\( -name '*.c' -o -name '*.so' -o -name '*.pyd' -o -name '*.dll' -o -name '*.html' \\) -delete", + description = "๐Ÿงน Clean build artifacts", +} +clean-c = { + cmd = "find src -type f -name '*.c' -delete", + description = "๐Ÿงน Clean C source files", +} +doc-clean = { + cmd = ["rm", "-rf", "build", "source/_api"], + cwd = "docs", + description = "๐Ÿ”ฅ Clean the docs build & api directory", +} # === Python environment features === -[feature.py310.dependencies] +[feature.py-oldest.dependencies] python = "3.10.*" -[feature.py314.dependencies] + +[feature.py-latest.dependencies] python = "3.14.*" [environments] -default = { features = ["py314"], solve-group = "py314" } -docs = { features = ["py314", "docs"], solve-group = "py314" } -test = { features = ["py314", "test"], solve-group = "py314" } -test-py314 = { features = [ - "py314", - "test", -], solve-group = "py314" } # alias of test -test-py310 = ["py310", "test"] -lint = { features = ["lint", "test"], solve-group = "py314" } +default = { features = ["py-latest"], solve-group = "py-latest" } +docs = { features = ["py-latest", "docs"], solve-group = "py-latest" } +test = { features = ["py-latest", "test"], solve-group = "py-latest" } +test-pylatest = { features = ["py-latest", "test"], solve-group = "py-latest" } # alias of test +test-pyoldest = ["py-oldest", "test"] +lint = { features = ["lint", "test"], solve-group = "py-latest" } tools = { features = ["tools"], no-default-feature = true } From e9f76b0ef72f0e74f11a970835c8472c4f839a5e Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Mon, 24 Aug 2026 15:32:58 +0200 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=94=A7=20Update=20CI=20environment?= =?UTF-8?q?=20matrix=20for=20Python=20versions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3a16b6a..8bd5eaf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - environment: [test-py310, test-py314] + environment: [test-pyoldest, test-pylatest] runs-on: ${{ matrix.os }} steps: From 031d143b057de0a264b62119d62dffa77951b63a Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Thu, 27 Aug 2026 16:14:34 +0200 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=94=A7=20Remove=20unused=20TOML=20c?= =?UTF-8?q?onfiguration=20files=20and=20reorganize=20pyproject.toml=20stru?= =?UTF-8?q?cture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .tombi.toml | 1 - pyproject.toml | 159 +++++++++++++++++++++++-------------------------- typos.toml | 4 -- 3 files changed, 75 insertions(+), 89 deletions(-) delete mode 100644 .tombi.toml delete mode 100644 typos.toml diff --git a/.tombi.toml b/.tombi.toml deleted file mode 100644 index b4b218b..0000000 --- a/.tombi.toml +++ /dev/null @@ -1 +0,0 @@ -toml-version = "v1.1.0" diff --git a/pyproject.toml b/pyproject.toml index d9c4e53..bfac220 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,15 @@ -[build-system] -requires = ["hatch-vcs", "hatch-cython>=0.6.0", "cherab==1.5.*"] -build-backend = "hatchling.build" - [project] name = "cherab-imas" description = "Cherab spectroscopy framework: IMAS submodule" +readme = "README.md" +requires-python = ">=3.10" +license = "EUPL-1.1" authors = [ { name = "munechika-koyo", email = "munechika.koyo@gmail.com" }, { name = "vsnever" }, { name = "jacklovell" }, ] -readme = "README.md" -requires-python = ">=3.10" -license = "EUPL-1.1" -keywords = ["cherab", "IMAS", "imas", "tokamak", "fusion", "plasma"] +keywords = ["IMAS", "cherab", "fusion", "imas", "plasma", "tokamak"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -21,12 +17,12 @@ classifiers = [ "Intended Audience :: Science/Research", "Natural Language :: English", "Operating System :: Unix", + "Programming Language :: Cython", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", - "Programming Language :: Cython", "Topic :: Scientific/Engineering :: Physics", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", @@ -34,32 +30,57 @@ classifiers = [ dependencies = [ "cherab==1.5.*", "imas-python[netcdf]", - "rich", "pooch", + "rich", "typing-extensions; python_version < '3.12'", ] dynamic = ["version"] -[project.optional-dependencies] -test = ["pytest", "pytest-cov", "plotly"] - [project.urls] -Homepage = "https://github.com/cherab" Documentation = "https://cherab.github.io/imas/" -Repository = "https://github.com/cherab/imas" +Homepage = "https://github.com/cherab" Issues = "https://github.com/cherab/imas/issues" +Repository = "https://github.com/cherab/imas" + +[project.optional-dependencies] +test = ["pytest", "pytest-cov", "plotly"] + +[build-system] +requires = ["cherab==1.5.*", "hatch-cython>=0.6.0", "hatch-vcs"] +build-backend = "hatchling.build" + +[tool.cibuildwheel] +skip = "pp* *_ppc64le *_i686 *_s390x *-musllinux* cp313* cp314* cp315*" # TODO: Suppport latest CPython after cherab supports it +build-frontend = "build[uv]" +test-extras = ["test"] +test-command = "pytest {project}/tests" + +[tool.cibuildwheel.macos] +repair-wheel-command = """\ +DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel \ +--require-archs {delocate_archs} -w {dest_dir} -v {wheel}\ +""" + +[tool.coverage.run] +source_pkgs = ["cherab.imas"] +branch = true +parallel = true + +[tool.coverage.paths] +test = ["src/test", "*/test/src/test"] +tests = ["tests", "*/test/tests"] + +[tool.coverage.report] +exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] + +[tool.cython-lint] +max-line-length = 100 -# ---------------------- -# === Version config === -# ---------------------- [tool.hatch.version] source = "vcs" [tool.hatch.metadata.hooks.vcs] -# ---------------------------- -# === Build/Package config === -# ---------------------------- [tool.hatch.build.targets.wheel] packages = ["src/cherab"] artifacts = ["*.so", "*.pyd", "*.dylib"] @@ -86,68 +107,46 @@ env = [ ], merges = true }, ] define_macros = [["NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"]] +files = { targets = ["**/*.pyx"] } -[tool.hatch.build.targets.wheel.hooks.cython.options.files] -targets = ["**/*.pyx"] - -[tool.cibuildwheel] -skip = "pp* *_ppc64le *_i686 *_s390x *-musllinux* cp313* cp314* cp315*" # TODO: Suppport latest CPython after cherab supports it -build-frontend = "build[uv]" -test-extras = ["test"] -test-command = "pytest {project}/tests" - -[tool.cibuildwheel.macos] -repair-wheel-command = """\ -DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel \ ---require-archs {delocate_archs} -w {dest_dir} -v {wheel}\ -""" - -# ----------------------- -# === Cov/Test config === -# ----------------------- -[tool.coverage.run] -source_pkgs = ["cherab.imas"] -branch = true -parallel = true - -[tool.coverage.paths] -test = ["src/test", "*/test/src/test"] -tests = ["tests", "*/test/tests"] +[tool.mypy] +files = ["src"] +warn_unused_configs = true +strict = true +enable_error_code = ["ignore-without-code", "truthy-bool"] +disable_error_code = ["no-any-return"] +plugins = ["numpy.typing.mypy_plugin"] -[tool.coverage.report] -exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] +[tool.pyrefly] +project-includes = ["src"] [tool.pytest.ini_options] -minversion = "6.0" addopts = "--cov='cherab.imas' --cov-report term-missing --no-cov-on-fail" +minversion = "6.0" - -# ------------------------------ -# === Lint & Format settings === -# ------------------------------ [tool.ruff] line-length = 100 [tool.ruff.lint] select = [ - "E", # pycodestyle - "B", # flake8-bugbear - "F", # pyflakes - "I", # isort (import order) - "N", # pep8-naming - "W", # Warning + "E", # pycodestyle + "B", # flake8-bugbear + "F", # pyflakes + "I", # isort (import order) + "N", # pep8-naming + "W", # Warning "UP", # pyupgrade - "NPY", # numpy specific rules - "D", # pydocstyle - "DOC", # pydoclint + "NPY", # numpy specific rules + "D", # pydocstyle + "DOC", # pydoclint ] preview = true ignore = [ # Recommended ignores by ruff when using formatter - "E501", # line too long - "N803", # argument name should be lowercase - "N806", # variable in function should be lowercase - "D107", # missing docstring in __init__ + "E501", # line too long + "N803", # argument name should be lowercase + "N806", # variable in function should be lowercase + "D107", # missing docstring in __init__ ] [tool.ruff.lint.isort] @@ -158,8 +157,8 @@ known-first-party = ["cherab"] "W292", "D", "DOC", -] # no newline at end of file and skip docstring checks -"tests/**" = ["D", "DOC"] # skip docstring checks in tests +] # no newline at end of file and skip docstring checks +"tests/**" = ["D", "DOC"] # skip docstring checks in tests [tool.ruff.lint.pydocstyle] convention = "numpy" @@ -167,19 +166,11 @@ convention = "numpy" [tool.ruff.format] docstring-code-format = true -[tool.cython-lint] -max-line-length = 100 - -# ------------------------------ -# === Type checking settings === -# ------------------------------ -[tool.mypy] -files = ["src"] -warn_unused_configs = true -strict = true -enable_error_code = ["ignore-without-code", "truthy-bool"] -disable_error_code = ["no-any-return"] -plugins = ["numpy.typing.mypy_plugin"] +[tool.tombi] +toml-version = "v1.1.0" +format.rules.line-width = 100 -[tool.pyrefly] -project-includes = ["src"] +[tool.typos.default.extend-words] +ist = "ist" +arange = "arange" +writeable = "writeable" diff --git a/typos.toml b/typos.toml deleted file mode 100644 index 4a851e7..0000000 --- a/typos.toml +++ /dev/null @@ -1,4 +0,0 @@ -[default.extend-words] -ist = "ist" -arange = "arange" -writeable = "writeable" From 49378b3269fd1d63dbb285619b795d4c3824ccac Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Thu, 27 Aug 2026 16:14:54 +0200 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8=20Add=20GitHub=20Actions=20work?= =?UTF-8?q?flows=20for=20documentation=20build,=20preview,=20and=20release?= =?UTF-8?q?;=20remove=20legacy=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docs-latest.yml | 71 ++++++++++++++++++++++++++ .github/workflows/docs-preview.yml | 80 ++++++++++++++++++++++++++++++ .github/workflows/docs-release.yml | 74 +++++++++++++++++++++++++++ .github/workflows/docs.yml | 48 ------------------ docs/pages-root/.nojekyll | 1 + 5 files changed, 226 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/docs-latest.yml create mode 100644 .github/workflows/docs-preview.yml create mode 100644 .github/workflows/docs-release.yml delete mode 100644 .github/workflows/docs.yml create mode 100644 docs/pages-root/.nojekyll diff --git a/.github/workflows/docs-latest.yml b/.github/workflows/docs-latest.yml new file mode 100644 index 0000000..0ff7655 --- /dev/null +++ b/.github/workflows/docs-latest.yml @@ -0,0 +1,71 @@ +name: ๐Ÿ“š Latest documentation + +on: + workflow_dispatch: + push: + branches: + - master + +permissions: + contents: read + +concurrency: + group: docs-latest + cancel-in-progress: true + +jobs: + build: + name: Build documentation + runs-on: ubuntu-latest + steps: + - name: Check out repo + uses: actions/checkout@v7 + + - name: ๐ŸŸจ Set up Pixi + uses: prefix-dev/setup-pixi@v0.10.1 + with: + environments: docs + + - name: ๐Ÿ“ Build docs + run: pixi run -e docs doc-build + + - name: ๐Ÿ“ฆ Upload documentation + uses: actions/upload-artifact@v7 + with: + name: docs-html + path: docs/build/html + retention-days: 1 + + deploy: + name: Deploy latest documentation + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out repo + uses: actions/checkout@v7 + + - name: ๐Ÿ“ฅ Download documentation + uses: actions/download-artifact@v8 + with: + name: docs-html + path: docs/build/html + + - name: Initialize GitHub Pages branch + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/pages-root + clean: false + force: false + attempt-limit: 5 + + - name: ๐Ÿš€ Deploy latest documentation + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/build/html + target-folder: latest + force: false + attempt-limit: 5 diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml new file mode 100644 index 0000000..e794d90 --- /dev/null +++ b/.github/workflows/docs-preview.yml @@ -0,0 +1,80 @@ +name: ๐Ÿ“š Documentation preview + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - closed + +permissions: + contents: read + +concurrency: + group: docs-preview-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + name: Build documentation + if: github.event.action != 'closed' + runs-on: ubuntu-latest + steps: + - name: Check out repo + uses: actions/checkout@v7 + + - name: ๐ŸŸจ Set up Pixi + uses: prefix-dev/setup-pixi@v0.10.1 + with: + environments: docs + + - name: ๐Ÿ“ Build docs + run: pixi run -e docs doc-build + + - name: ๐Ÿ“ฆ Upload documentation + uses: actions/upload-artifact@v7 + with: + name: docs-html + path: docs/build/html + retention-days: 1 + + preview: + name: Deploy PR preview + needs: build + # Fork PRs are built above, but cannot safely write previews to this repository. + if: >- + always() && + github.event.pull_request.head.repo.full_name == github.repository && + (github.event.action == 'closed' || needs.build.result == 'success') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Check out repo + uses: actions/checkout@v7 + + - name: ๐Ÿ“ฅ Download documentation + if: github.event.action != 'closed' + uses: actions/download-artifact@v8 + with: + name: docs-html + path: docs/build/html + + - name: Initialize GitHub Pages branch + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/pages-root + clean: false + force: false + attempt-limit: 5 + + - name: ๐Ÿš€ Deploy documentation preview + uses: rossjrw/pr-preview-action@v1 + with: + source-dir: docs/build/html + preview-branch: gh-pages + umbrella-dir: pr-preview + qr-code: false diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml new file mode 100644 index 0000000..0730a7e --- /dev/null +++ b/.github/workflows/docs-release.yml @@ -0,0 +1,74 @@ +name: ๐Ÿ“š Versioned documentation + +on: + release: + types: + - published + +permissions: + contents: read + +concurrency: + group: docs-release-${{ github.event.release.tag_name }} + cancel-in-progress: false + +jobs: + build: + name: Build documentation + runs-on: ubuntu-latest + steps: + - name: Check out release tag + uses: actions/checkout@v7 + with: + ref: ${{ github.event.release.tag_name }} + + - name: ๐ŸŸจ Set up Pixi + uses: prefix-dev/setup-pixi@v0.10.1 + with: + environments: docs + + - name: ๐Ÿ“ Build docs + run: pixi run -e docs doc-build + + - name: ๐Ÿ“ฆ Upload documentation + uses: actions/upload-artifact@v7 + with: + name: docs-html + path: docs/build/html + retention-days: 1 + + deploy: + name: Deploy versioned documentation + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out release tag + uses: actions/checkout@v7 + with: + ref: ${{ github.event.release.tag_name }} + + - name: ๐Ÿ“ฅ Download documentation + uses: actions/download-artifact@v8 + with: + name: docs-html + path: docs/build/html + + - name: Initialize GitHub Pages branch + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/pages-root + clean: false + force: false + attempt-limit: 5 + + - name: ๐Ÿš€ Deploy versioned documentation + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: docs/build/html + target-folder: versions/${{ github.event.release.tag_name }} + force: false + attempt-limit: 5 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 2ff9a49..0000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: ๐Ÿ“š Docs - -permissions: - contents: read - pages: write - id-token: write - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - # release: - # types: - # - published - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@v7 - - - name: ๐ŸŸจ Set up Pixi - uses: prefix-dev/setup-pixi@v0.10.1 - with: - environments: docs - - - name: ๐Ÿ“ Build docs - run: pixi run -e docs doc-build - - - name: ๐Ÿ“ฆ Upload artifact - uses: actions/upload-pages-artifact@v5 - with: - path: docs/build/html - - deploy: - needs: build - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - steps: - - name: ๐Ÿš€ Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v5 diff --git a/docs/pages-root/.nojekyll b/docs/pages-root/.nojekyll new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/pages-root/.nojekyll @@ -0,0 +1 @@ + From 5b37c91f3784404d2d8b42176b1221c1870afa53 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Thu, 27 Aug 2026 16:27:30 +0200 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=94=A7=20Update=20documentation=20w?= =?UTF-8?q?orkflows=20and=20links=20in=20README=20and=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +++- README.md | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 962aea8..8419664 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.7.0] - 2026-08-28 ### Added - Add `UnstructGrid2D.plot_tri_mesh()` for plotting cell data on the triangulated mesh with Matplotlib's `tripcolor()` +- Add GitHub Pages workflows for pull request previews, versioned release documentation, and + continuously updated `master` branch documentation under `latest/` ### Changed diff --git a/README.md b/README.md index db46d2d..3364ee3 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ [codecov-badge]: https://img.shields.io/codecov/c/github/cherab/imas?token=05LZGWUUXA&style=flat-square&logo=codecov [conda]: https://prefix.dev/channels/conda-forge/packages/cherab-imas [conda-badge]: https://img.shields.io/conda/vn/conda-forge/cherab-imas?logo=conda-forge&style=flat-square -[docs]: https://github.com/cherab/imas/actions/workflows/docs.yml -[docs-badge]: https://img.shields.io/github/actions/workflow/status/cherab/imas/docs.yml?style=flat-square&logo=GitHub&label=Docs +[docs]: https://github.com/cherab/imas/actions/workflows/docs-latest.yml +[docs-badge]: https://img.shields.io/github/actions/workflow/status/cherab/imas/docs-latest.yml?style=flat-square&logo=GitHub&label=Docs [license]: https://opensource.org/licenses/EUPL-1.1 [license-badge]: https://img.shields.io/badge/license-EUPL_1.1%20-blue?style=flat-square [pixi-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json&style=flat-square From 6bb7c3a994a63d8a48478711d473e819a563c097 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Thu, 27 Aug 2026 16:56:58 +0200 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=93=9D=20Update=20edge=20docs=20to?= =?UTF-8?q?=20use=20`plot=5Ftri=5Fmesh`=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/notebooks/plasma/2_edge_plasma.ipynb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/notebooks/plasma/2_edge_plasma.ipynb b/docs/notebooks/plasma/2_edge_plasma.ipynb index d8c069f..3a2f9a8 100644 --- a/docs/notebooks/plasma/2_edge_plasma.ipynb +++ b/docs/notebooks/plasma/2_edge_plasma.ipynb @@ -20,6 +20,8 @@ "metadata": {}, "outputs": [], "source": [ + "from typing import TYPE_CHECKING\n", + "\n", "import numpy as np\n", "import ultraplot as uplt\n", "from imas import DBEntry\n", @@ -27,11 +29,13 @@ "from rich import print as rprint\n", "\n", "from cherab.imas.datasets import iter_jintrac, iter_solps\n", - "from cherab.imas.ggd import GGDGrid\n", "from cherab.imas.ids.common import get_ids_time_slice\n", "from cherab.imas.ids.common.ggd import load_grid\n", "from cherab.imas.ids.edge_profiles import load_edge_species\n", "\n", + "if TYPE_CHECKING:\n", + " from cherab.imas.ggd import UnstructGrid2D\n", + "\n", "# Set dark background for plots\n", "uplt.rc.style = \"dark_background\"" ] @@ -53,7 +57,7 @@ "source": [ "def plot_grid_quantity(\n", " ax: uplt.axes.Axes,\n", - " grid: GGDGrid,\n", + " grid: UnstructGrid2D,\n", " quantity: np.ndarray,\n", " title: str = \"\",\n", " title_center: str = \"\",\n", @@ -63,7 +67,7 @@ " cbar_kwargs: dict = None,\n", ") -> uplt.axes.Axes:\n", " \"\"\"Plot a quantity defined on a grid.\"\"\"\n", - " ax = grid.plot_mesh(data=quantity, ax=ax)\n", + " ax = grid.plot_tri_mesh(data=quantity, ax=ax)\n", "\n", " if logscale:\n", " # Plot lowest values (mainly 0's) on linear map, as log(0) = -inf.\n", @@ -562,7 +566,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.14.6" + "version": "3.14.7" } }, "nbformat": 4, From 99bea0a20a14deaefc34c0c87975c9853bef890d Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Mon, 31 Aug 2026 09:22:59 +0200 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Convert=20charge?= =?UTF-8?q?=5Fstates=20to=20list=20to=20optimize=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cherab/imas/ids/core_profiles/load_profiles.py | 2 +- src/cherab/imas/ids/edge_profiles/load_profiles.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cherab/imas/ids/core_profiles/load_profiles.py b/src/cherab/imas/ids/core_profiles/load_profiles.py index c92c0d9..02860df 100644 --- a/src/cherab/imas/ids/core_profiles/load_profiles.py +++ b/src/cherab/imas/ids/core_profiles/load_profiles.py @@ -245,7 +245,7 @@ def load_core_species( charge_states = np.arange( species_data.z_min, species_data.z_max + 1, dtype=int - ) + ).tolist() for i_charge, charge in enumerate(charge_states): species = SpeciesData( diff --git a/src/cherab/imas/ids/edge_profiles/load_profiles.py b/src/cherab/imas/ids/edge_profiles/load_profiles.py index 46d45d0..ad591df 100644 --- a/src/cherab/imas/ids/edge_profiles/load_profiles.py +++ b/src/cherab/imas/ids/edge_profiles/load_profiles.py @@ -270,7 +270,7 @@ def load_edge_species( charge_states = np.arange( species_data.z_min, species_data.z_max + 1, dtype=int - ) + ).tolist() for i_charge, charge in enumerate(charge_states): species = SpeciesData( From 9b20b7a652b4d10f92a84c8d91303aeaf9610063 Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Mon, 31 Aug 2026 10:22:19 +0200 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=90=9B=20Fix=20Type=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cherab/imas/plasma/edge.py | 63 ++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/src/cherab/imas/plasma/edge.py b/src/cherab/imas/plasma/edge.py index bfe399f..56cd902 100644 --- a/src/cherab/imas/plasma/edge.py +++ b/src/cherab/imas/plasma/edge.py @@ -22,7 +22,7 @@ import numpy as np from numpy.typing import NDArray from raysect.core.math import Vector3D, translate -from raysect.core.math.function.float import Constant2D, Constant3D, Function2D +from raysect.core.math.function.float import Constant2D, Constant3D, Function2D, Function3D from raysect.core.math.function.vector3d import Constant2D as ConstantVector2D from raysect.core.math.function.vector3d import Constant3D as ConstantVector3D from raysect.core.math.function.vector3d import Function2D as VectorFunction2D @@ -424,19 +424,23 @@ def _get_parallel_velocity_interpolators( return ConstantVector3D(Vector3D(0, 1.0e-16, 0)) # avoid zero-length vectors for blending - const_func = Constant2D if grid.dimension == 2 else Constant3D - - vpar_i = const_func(0) if vpar is None else grid.interpolator(vpar) - vrad_i = const_func(0) if vrad is None else grid.interpolator(vrad) - parallel_vector = UnitVector2D(b_field) surface_normal = FluxSurfaceNormal(b_field) - if grid.dimension == 3: # 3D case - parallel_vector = VectorAxisymmetricMapper(parallel_vector) - surface_normal = VectorAxisymmetricMapper(surface_normal) + if grid.dimension == 2: + vpar_i = Constant2D(0) if vpar is None else grid.interpolator(vpar) + vrad_i = Constant2D(0) if vrad is None else grid.interpolator(vrad) + assert isinstance(vpar_i, Function2D) + assert isinstance(vrad_i, Function2D) + return vpar_i * parallel_vector + vrad_i * surface_normal - return vpar_i * parallel_vector + vrad_i * surface_normal + vpar_i = Constant3D(0) if vpar is None else grid.interpolator(vpar) + vrad_i = Constant3D(0) if vrad is None else grid.interpolator(vrad) + assert isinstance(vpar_i, Function3D) + assert isinstance(vrad_i, Function3D) + parallel_vector_3d = VectorAxisymmetricMapper(parallel_vector) + surface_normal_3d = VectorAxisymmetricMapper(surface_normal) + return vpar_i * parallel_vector_3d + vrad_i * surface_normal_3d def _get_poloidal_velocity_interpolators( @@ -454,22 +458,29 @@ def _get_poloidal_velocity_interpolators( return ConstantVector3D(Vector3D(0, 1.0e-16, 0)) # avoid zero-length vectors for blending - const_func = Constant2D if grid.dimension == 2 else Constant3D - - vpol_i = const_func(0) if vpol is None else grid.interpolator(vpol) - vrad_i = const_func(0) if vrad is None else grid.interpolator(vrad) - vtor_i = const_func(0) if vtor is None else grid.interpolator(vtor) - poloidal_vector = PoloidalFieldVector(b_field) surface_normal = FluxSurfaceNormal(b_field) toroidal_vector = ConstantVector2D(Vector3D(0, 1, 0)) - if grid.dimension == 3: # 3D case - poloidal_vector = VectorAxisymmetricMapper(poloidal_vector) - surface_normal = VectorAxisymmetricMapper(surface_normal) - toroidal_vector = VectorAxisymmetricMapper(toroidal_vector) - - return vpol_i * poloidal_vector + vrad_i * surface_normal + vtor_i * toroidal_vector + if grid.dimension == 2: + vpol_i = Constant2D(0) if vpol is None else grid.interpolator(vpol) + vrad_i = Constant2D(0) if vrad is None else grid.interpolator(vrad) + vtor_i = Constant2D(0) if vtor is None else grid.interpolator(vtor) + assert isinstance(vpol_i, Function2D) + assert isinstance(vrad_i, Function2D) + assert isinstance(vtor_i, Function2D) + return vpol_i * poloidal_vector + vrad_i * surface_normal + vtor_i * toroidal_vector + + vpol_i = Constant3D(0) if vpol is None else grid.interpolator(vpol) + vrad_i = Constant3D(0) if vrad is None else grid.interpolator(vrad) + vtor_i = Constant3D(0) if vtor is None else grid.interpolator(vtor) + assert isinstance(vpol_i, Function3D) + assert isinstance(vrad_i, Function3D) + assert isinstance(vtor_i, Function3D) + poloidal_vector_3d = VectorAxisymmetricMapper(poloidal_vector) + surface_normal_3d = VectorAxisymmetricMapper(surface_normal) + toroidal_vector_3d = VectorAxisymmetricMapper(toroidal_vector) + return vpol_i * poloidal_vector_3d + vrad_i * surface_normal_3d + vtor_i * toroidal_vector_3d def _get_components_from_vpar(grid: GGDGrid, vpar: NDArray[np.float64], b_field: VectorFunction2D): @@ -486,9 +497,11 @@ def _get_components_from_vpar(grid: GGDGrid, vpar: NDArray[np.float64], b_field: else: r, _, z = cell_centre try: - b_field = b_field(r, z) - vpol[i] = np.sqrt(b_field.x**2 + b_field.z**2) * (vpar[i] / b_field.length) - vtor[i] = vpar[i] * b_field.y / b_field.length + field_vector = b_field(r, z) + vpol[i] = np.sqrt(field_vector.x**2 + field_vector.z**2) * ( + vpar[i] / field_vector.length + ) + vtor[i] = vpar[i] * field_vector.y / field_vector.length except ValueError: # Outside equilibrium grid continue From b48b0679b3a8720f2d24f60f3b470dfc3b0f530b Mon Sep 17 00:00:00 2001 From: munechika-koyo Date: Mon, 31 Aug 2026 10:23:36 +0200 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=94=A7=20Remove=20unnecessary=20cha?= =?UTF-8?q?nnel=20from=20pixi.toml=20and=20format=20python=20versions=20fo?= =?UTF-8?q?r=20clarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pixi.toml | 10 ++++++++-- pyproject.toml | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pixi.toml b/pixi.toml index 97d6912..6c32591 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,10 +1,16 @@ [workspace] -channels = ["conda-forge", "https://prefix.dev/koyo-forge"] +channels = ["conda-forge"] platforms = ["linux-64", "osx-arm64", "osx-64"] preview = ["pixi-build"] [workspace.build-variants] -python = ["3.10.*", "3.11.*", "3.12.*", "3.13.*", "3.14.*"] +python = [ + "3.10.*", + "3.11.*", + "3.12.*", + "3.13.*", + "3.14.*", +] # ------------------------------- # === Packaging Configuration === diff --git a/pyproject.toml b/pyproject.toml index bfac220..8fd6b15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,7 +168,6 @@ docstring-code-format = true [tool.tombi] toml-version = "v1.1.0" -format.rules.line-width = 100 [tool.typos.default.extend-words] ist = "ist"