From 20cf05510a7fb7cd99fa30a505f870f1d4aa17a7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 11 Jun 2025 11:17:44 +0100 Subject: [PATCH 01/10] Replace 'boututils' with 'boutdata' The 'boututils' module was merged into the 'boutdata' package, so we need to depend on 'boutdata' instead of 'boututils' now. Also need the latest version for a bugfix. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8da003e8..a76c1bc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ requires-python = ">=3.10" dependencies = [ - "boututils~=0.1.7", + "boutdata~=0.3.0", "dill~=0.3,!=0.3.5,!=0.3.5.1", "func_timeout~=4.3", "matplotlib~=3.7", From 3a7295f586df3f250d502568cdd9440c0c06762c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 9 Jun 2025 21:07:51 +0100 Subject: [PATCH 02/10] Set the dimension for R_closed_wall and Z_closed_wall to 'closed_wall' xBOUT detects grid files by checking that they do not have a "t" dimension. However, boututils.Datafile defaults to writing a 1d array with a "t" dimension, so the "R_closed_wall" and "Z_closed_wall" variables were previously written with a "t" dimension, which made xBOUT try to load the grid files as if they were dump files (which fails). Fix this by specifying the name of the dimension as "closed_wall". --- doc/whats-new.md | 8 ++++++++ hypnotoad/core/mesh.py | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/whats-new.md b/doc/whats-new.md index 1c65d9b9..374e903e 100644 --- a/doc/whats-new.md +++ b/doc/whats-new.md @@ -4,6 +4,10 @@ Release history ### Bug fixes - When using the GUI, if there is an error in `TokamakEquilibrium` object creation, still plot the equilibrium data (#186). + By [John Omotani](https://github.com/johnomotani) +- Set the dimension for R_closed_wall and Z_closed_wall to 'closed_wall'. Fixes + loading of grid files by xBOUT (#190). + By [John Omotani](https://github.com/johnomotani) ### New features @@ -11,12 +15,16 @@ Release history - Radial grid line construction can recover from failure and generate a rough grid to help visual inspection when option `follow_perpendicular_recover` is set to True (#175) + By [Ben Dudson](https://github.com/bendudson) - A `View` menu enables the grid plot to be customised, with cell edges, corners, grid lines and other components (#176). + By [Ben Dudson](https://github.com/bendudson) - `penalty_mask` is calculated and written to the grid file, based on intersection of the grid with the wall. This enables immersed boundary conditions. + By [Ben Dudson](https://github.com/bendudson) - Wall coordinates are written to output grid as `closed_wall_R` and `closed_wall_Z` (#176) + By [Ben Dudson](https://github.com/bendudson) 0.5.2 (13th March 2023) ------------------------- diff --git a/hypnotoad/core/mesh.py b/hypnotoad/core/mesh.py index 8f1c1c38..d303a350 100644 --- a/hypnotoad/core/mesh.py +++ b/hypnotoad/core/mesh.py @@ -3728,8 +3728,16 @@ def writeGridfile(self, filename): f.write("psi_bdry_gfile", self.equilibrium.psi_bdry_gfile) if hasattr(self.equilibrium, "closed_wallarray"): - f.write("closed_wall_R", self.equilibrium.closed_wallarray[:, 0]) - f.write("closed_wall_Z", self.equilibrium.closed_wallarray[:, 1]) + f.write( + "closed_wall_R", + self.equilibrium.closed_wallarray[:, 0], + dims=("closed_wall",), + ) + f.write( + "closed_wall_Z", + self.equilibrium.closed_wallarray[:, 1], + dims=("closed_wall",), + ) # write the 2d fields for name in self.fields_to_output: From f8b3599fbc133e4fb4e77701622644a65556af3e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 11 Jun 2025 14:56:29 +0100 Subject: [PATCH 03/10] Update Python versions used in CI Python-3.8 is no longer available on Github Actions runners, so remove. Add more recent versions of Python to the tests, and for the examples, etc. that run on a single version, just use the default (presumably the latest version). --- .github/workflows/pythonpackage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index fc2163d8..bb45edfd 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -18,7 +18,7 @@ jobs: if: always() strategy: matrix: - python-version: ['3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12', '3.13'] fail-fast: false steps: @@ -42,7 +42,7 @@ jobs: if: always() strategy: matrix: - python-version: ['3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12', '3.13'] fail-fast: false steps: From ecf24f28a36adacc9c5c75d5b1eb8238c51cf6f2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 11 Jun 2025 15:25:39 +0100 Subject: [PATCH 04/10] Avoid xarray-2025.6.0 in CI There seems to be a bug in xarray's imports, which is causing some CI jobs to fail. --- .github/workflows/pythonpackage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bb45edfd..811a7948 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -59,7 +59,7 @@ jobs: pip install .[tests] - name: Integrated tests run: | - pip install pytest xarray + pip install pytest "xarray!=2025.6.0" cd integrated_tests/ ./test_suite.py @@ -120,6 +120,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip + pip install pytest "xarray!=2025.6.0" # Install explicitly so we can avoid this buggy version pip install xbout pip install -e . - name: Utilities From 9cf96c0221aaa51c409e3c87714d293553603fa2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 11 Jun 2025 18:48:54 +0100 Subject: [PATCH 05/10] Add rounding-error tolerances to fix test failures under Python-3.13 Something (presumably changed rounding errors) was making some conditionals evaluate to the wrong result for a separatrix segment around the core. For these segments, the first and last points of the FineContour and PsiContour are in the same place, so the FineContour should not need to be extended, but without the tolerance introduced in this commit, one was being extended, causing errors in poloidal_distance_xlow. Also increase tolerances in 'with rounding errors' test, as Python-3.13 has changed things slightly (maybe different random-number generation?). --- hypnotoad/core/equilibrium.py | 28 ++++++++++++++----- .../runtest.py | 4 +-- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/hypnotoad/core/equilibrium.py b/hypnotoad/core/equilibrium.py index 81716d6b..d9171da0 100644 --- a/hypnotoad/core/equilibrium.py +++ b/hypnotoad/core/equilibrium.py @@ -1854,11 +1854,18 @@ def checkFineContourExtend(self, *, psi): minind = numpy.argmin(distances) # if minind > 0, or the distance to point 1 is less than the distance between # point 0 and point 1 of the fine_contour, then fine_contour extends past p so - # does not need to be extended - if minind == 0 and distances[1] > numpy.sqrt( - numpy.sum( - (fine_contour.positions[1, :] - fine_contour.positions[0, :]) ** 2 + # does not need to be extended. + # Include some tolerance to allow for rounding errors when the first point on + # the FineContour and the first point on the PsiContour are in 'the same place'. + if ( + minind == 0 + and distances[1] + - numpy.sqrt( + numpy.sum( + (fine_contour.positions[1, :] - fine_contour.positions[0, :]) ** 2 + ) ) + > 1.0e-13 ): ds = fine_contour.distance[1] - fine_contour.distance[0] n_extend_lower = max(int(numpy.ceil(distances[0] / ds)), 1) @@ -1874,10 +1881,17 @@ def checkFineContourExtend(self, *, psi): # if minind < len(distances)-1, or the distance to the last point is less than # the distance between the last and second-last of the fine_contour, then # fine_contour extends past p so does not need to be extended - if minind == len(distances) - 1 and distances[-2] > numpy.sqrt( - numpy.sum( - (fine_contour.positions[-1, :] - fine_contour.positions[-2, :]) ** 2 + # Include some tolerance to allow for rounding errors when the last point on + # the FineContour and the last point on the PsiContour are in 'the same place'. + if ( + minind == len(distances) - 1 + and distances[-2] + - numpy.sqrt( + numpy.sum( + (fine_contour.positions[-1, :] - fine_contour.positions[-2, :]) ** 2 + ) ) + > 1.0e-13 ): ds = fine_contour.distance[-1] - fine_contour.distance[-2] n_extend_upper = max(int(numpy.ceil(distances[-1] / ds)), 1) diff --git a/integrated_tests/connected_doublenull_with_rounding_error_nonorthogonal/runtest.py b/integrated_tests/connected_doublenull_with_rounding_error_nonorthogonal/runtest.py index bfe677a0..c56d3533 100755 --- a/integrated_tests/connected_doublenull_with_rounding_error_nonorthogonal/runtest.py +++ b/integrated_tests/connected_doublenull_with_rounding_error_nonorthogonal/runtest.py @@ -10,8 +10,8 @@ diagnose = False -rtol = 1.0e-9 -atol = 5.0e-10 +rtol = 2.0e-9 +atol = 2.0e-9 # make sure we are in the test directory os.chdir(Path(__file__).parent) From 3e39be63c4f57dae71b5d21bbbde7e0d2d1b3d2d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 11 Jun 2025 21:37:00 +0100 Subject: [PATCH 06/10] Update `scatter()`, variable names, for recent xarray/xBOUT versions --- .../scripts/hypnotoad_plot_grid_cells.py | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/hypnotoad/scripts/hypnotoad_plot_grid_cells.py b/hypnotoad/scripts/hypnotoad_plot_grid_cells.py index 3ce2918c..d709eee5 100755 --- a/hypnotoad/scripts/hypnotoad_plot_grid_cells.py +++ b/hypnotoad/scripts/hypnotoad_plot_grid_cells.py @@ -137,14 +137,14 @@ def main(): # kwarg for something else. ds_region.isel( x=slice(xin, xout_centre), theta=slice(ylow, yup_centre) - ).plot.scatter("R", "Z", marker=".", color="k", s=1) + ).plot.scatter(x="R", y="Z", marker=".", color="k", s=1) # plot radial grid lines plt.plot( - ds_region["Rxy_corners"].isel( + ds_region["Rxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=slice(ylow, yup_corner) ), - ds_region["Zxy_corners"].isel( + ds_region["Zxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=slice(ylow, yup_corner) ), color="k", @@ -152,10 +152,10 @@ def main(): # plot poloidal grid lines plt.plot( - ds_region["Rxy_corners"] + ds_region["Rxy_lower_left_corners"] .isel(x=slice(xin_pol, xout_corner_pol), theta=slice(ylow, yup_corner)) .T, - ds_region["Zxy_corners"] + ds_region["Zxy_lower_left_corners"] .isel(x=slice(xin_pol, xout_corner_pol), theta=slice(ylow, yup_corner)) .T, color="k", @@ -175,8 +175,12 @@ def main(): # neighbouring in the global grid, because if they are the boundary between # regions is not (or 'not really') a branch cut. plt.plot( - ds_region["Rxy_corners"].isel(x=slice(xin, xout_corner_rad), theta=-1), - ds_region["Zxy_corners"].isel(x=slice(xin, xout_corner_rad), theta=-1), + ds_region["Rxy_lower_left_corners"].isel( + x=slice(xin, xout_corner_rad), theta=-1 + ), + ds_region["Zxy_lower_left_corners"].isel( + x=slice(xin, xout_corner_rad), theta=-1 + ), color="r", linewidth=3, zorder=1000, @@ -187,8 +191,12 @@ def main(): # By arbitrary choice, plot from the region(s) inside the separatrix, so # highlight the outer edge. plt.plot( - ds_region["Rxy_corners"].isel(x=-1, theta=slice(ylow, yup_corner)), - ds_region["Zxy_corners"].isel(x=-1, theta=slice(ylow, yup_corner)), + ds_region["Rxy_lower_left_corners"].isel( + x=-1, theta=slice(ylow, yup_corner) + ), + ds_region["Zxy_lower_left_corners"].isel( + x=-1, theta=slice(ylow, yup_corner) + ), color="b", linewidth=3, zorder=999, @@ -197,10 +205,10 @@ def main(): if targets: if ds_region.regions[r].connection_lower_y is None: plt.plot( - ds_region["Rxy_corners"].isel( + ds_region["Rxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=ylow ), - ds_region["Zxy_corners"].isel( + ds_region["Zxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=ylow ), color="k", @@ -210,10 +218,10 @@ def main(): if ds_region.regions[r].connection_upper_y is None: yval = -1 if yup_corner is None else yup_corner plt.plot( - ds_region["Rxy_corners"].isel( + ds_region["Rxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=yval ), - ds_region["Zxy_corners"].isel( + ds_region["Zxy_lower_left_corners"].isel( x=slice(xin, xout_corner_rad), theta=yval ), color="k", From ae0889475598a661c4ade830d1e69dd7235d4134 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 13 Jun 2025 12:19:13 +0100 Subject: [PATCH 07/10] Add scheduled CI runs once a month Hope to catch bugs caused by updates in dependencies, etc. --- .github/workflows/pythonpackage.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 811a7948..bb87b79c 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -4,7 +4,10 @@ name: Python package on: - [push, pull_request] + push: + pull_request: + schedule: + - cron: 25 1 3 * * concurrency: group: ${{ github.workflow}}-${{ github.ref }} From 7a6e5a02dd6d316a3d83fefc1afff098ed13c774 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 13 Jun 2025 13:20:33 +0100 Subject: [PATCH 08/10] Fix PR number in 'whats-new.md' --- doc/whats-new.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.md b/doc/whats-new.md index 374e903e..b2e376a4 100644 --- a/doc/whats-new.md +++ b/doc/whats-new.md @@ -6,7 +6,7 @@ Release history creation, still plot the equilibrium data (#186). By [John Omotani](https://github.com/johnomotani) - Set the dimension for R_closed_wall and Z_closed_wall to 'closed_wall'. Fixes - loading of grid files by xBOUT (#190). + loading of grid files by xBOUT (#191). By [John Omotani](https://github.com/johnomotani) From a692cd229e6376fc2d426370e0027de7c6e68ae6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 13 Jun 2025 13:46:42 +0100 Subject: [PATCH 09/10] Quotes around cron string in pythonpackage.yml Probably needed to avoid problems due to YAML interpreting special characters. Co-authored-by: Timothy <75321887+timothy-nunn@users.noreply.github.com> --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bb87b79c..dfeac2fb 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -7,7 +7,7 @@ on: push: pull_request: schedule: - - cron: 25 1 3 * * + - cron: '25 1 3 * *' concurrency: group: ${{ github.workflow}}-${{ github.ref }} From 0f1759d727d110336453cae9ebd51474561e8dd0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 13 Jun 2025 13:47:11 +0100 Subject: [PATCH 10/10] Remove version restricions on xarray in CI config xarray has made a bugfix release, so we can just use the latest version again. --- .github/workflows/pythonpackage.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index dfeac2fb..998d5f69 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -62,7 +62,7 @@ jobs: pip install .[tests] - name: Integrated tests run: | - pip install pytest "xarray!=2025.6.0" + pip install pytest xarray cd integrated_tests/ ./test_suite.py @@ -123,7 +123,6 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest "xarray!=2025.6.0" # Install explicitly so we can avoid this buggy version pip install xbout pip install -e . - name: Utilities