Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
622592b
Merge branch 'develop' into 'master'
kripnerl Jun 5, 2026
c973f79
Merge phd-thesis work to the master
kripnerl Jun 5, 2026
8894688
Merge branch 'phd-thesis' into 'master'
kripnerl Jun 5, 2026
69b75ef
Bump version to 0.0.10 and update release documentation
kripnerl Jun 5, 2026
9cd0831
Merge branch 'release/0.0.10' into 'master'
kripnerl Jun 5, 2026
b2ea707
Refactor: clean up code structure (Groups 1 & 2)
claude Jun 7, 2026
3fdeacc
Refactor: remove dead code and improve module exports (Groups 3 & 4)
claude Jun 7, 2026
bd2569b
Refactor: split Equilibrium.__init__ into focused private helpers (Gr…
claude Jun 7, 2026
e4d66bc
Merge pull request #69 from kripnerl/claude/refactor-code-structure-E…
kripnerl Jun 7, 2026
3a7402a
Add ruff and ty linting; replace flake8/pylint; add CI workflows
claude Jun 7, 2026
798beba
Add ty typecheck job to GitLab CI
claude Jun 8, 2026
87c0cc1
Update poetry.lock: replace pylint/flake8 with ruff and ty
claude Jun 8, 2026
f000310
Fix circular import in pleque/core/__init__.py
claude Jun 8, 2026
d397326
Suppress I001 for pleque/core/__init__.py: import order is load-order…
claude Jun 8, 2026
d35d191
Merge origin/develop into claude/ruff-ty-linting-types-em4iT
claude Jun 10, 2026
a771a65
Merge pull request #70 from kripnerl/claude/ruff-ty-linting-types-em4iT
kripnerl Jun 10, 2026
22deeb6
Add CLAUDE.md with codebase guidance for AI assistants
claude Jun 10, 2026
43ba94d
Merge pull request #72 from kripnerl/claude/claude-md-docs-433xo7
kripnerl Jun 10, 2026
42b3264
ci: store pytest results as artifacts in GitLab and GitHub CI
claude Jun 10, 2026
6f26a62
ci: add pytest coverage reporting to GitLab and GitHub CI
claude Jun 10, 2026
a848b61
Merge branch 'develop' into claude/ci-test-results-artifacts-ayr3rk
kripnerl Jun 10, 2026
f80af8a
chore: update poetry.lock with pytest-cov, ruff, and ty dependencies
claude Jun 10, 2026
9e3f43f
Merge pull request #73 from kripnerl/claude/ci-test-results-artifacts…
kripnerl Jun 10, 2026
3cfd298
Centralize algorithm parameters in grouped Settings with config-file …
claude Jun 10, 2026
f0ed539
Merge pull request #74 from kripnerl/claude/settings-parametrization-…
kripnerl Jun 11, 2026
ba543cb
Bump pytest from 7.4.4 to 9.0.3
dependabot[bot] Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PWD=/home/kripner/Projects/pleque
OLDPWD=/home/kripner
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CI

on:
push:
branches: ["master", "develop", "claude/**"]
pull_request:
branches: ["master", "develop"]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Install dependencies
run: poetry install --without compass

- name: Run tests
run: poetry run pytest

lint:
runs-on: ubuntu-latest
needs: test

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install ruff
run: pip install ruff

- name: Run ruff
run: ruff check pleque/ tests/

typecheck:
runs-on: ubuntu-latest
needs: test

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Install dependencies
run: poetry install --without compass

- name: Run ty
run: poetry run ty check pleque/
continue-on-error: true # ty is new; don't fail CI until annotations are complete
75 changes: 75 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Tests

on:
push:
branches: [master, main]
pull_request:
branches: [master, main]

jobs:
test:
runs-on: ubuntu-latest

permissions:
checks: write
pull-requests: write

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
echo "$HOME/.local/bin" >> $GITHUB_PATH

- name: Cache Poetry dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
restore-keys: |
${{ runner.os }}-poetry-

- name: Install dependencies
run: poetry install --without compass

- name: Run tests
run: poetry run pytest --junitxml=report.xml --cov=pleque --cov-report=xml:coverage.xml --cov-report=term-missing

- name: Upload test results artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: |
report.xml
coverage.xml

- name: Publish test results
uses: dorny/test-reporter@v1
if: always()
with:
name: pytest results
path: report.xml
reporter: java-junit

- name: Publish coverage summary
uses: irongut/CodeCoverageSummary@v1.3.0
if: always()
with:
filename: coverage.xml
badge: true
format: markdown
output: both

- name: Add coverage comment to PR
uses: marocchino/sticky-pull-request-comment@v2
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md
27 changes: 27 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,31 @@ before_script:

test:pytest:
script:
- pytest --junitxml=report.xml --cov=pleque --cov-report=xml:coverage.xml --cov-report=term-missing
artifacts:
when: always
reports:
junit: report.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
paths:
- report.xml
- coverage.xml
expire_in: 1 week
- pytest

lint:ruff:
stage: test
script:
- pip install ruff
- ruff check pleque/ tests/
needs: ["test:pytest"]

typecheck:ty:
stage: test
script:
- pip install ty
- ty check pleque/
needs: ["test:pytest"]
allow_failure: true # ty is new; don't block pipeline until annotations are complete
100 changes: 100 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

PLEQUE (**PL**asma **EQU**ilibrium **E**njoyment module) is a Python library for visualisation and
manipulation of tokamak plasma equilibria. Its central abstraction is the `Equilibrium` class,
typically constructed by reading an equilibrium file (e.g. G-EQDSK) via `pleque.io.readers`.

## Commands

The project uses Poetry. The `compass` dependency group pulls `pycdb-compass` from an internal
IPP git repository that is not reachable outside the COMPASS network — always exclude it:

```bash
poetry install --without compass # install dependencies (this is what CI does)

poetry run pytest # run the whole test suite
poetry run pytest tests/test_equilibria.py # run one test file
poetry run pytest tests/test_equilibria.py::test_name # run a single test

ruff check pleque/ tests/ # lint (CI runs exactly this)
ruff format pleque/ tests/ # format (line-length 120, double quotes)

poetry run ty check pleque/ # type check (advisory: CI runs it with continue-on-error
# because the legacy codebase is largely un-annotated)
```

Tests that need unavailable optional dependencies (e.g. `pyCDB` in `tests/test_cdb.py`) skip
themselves via `pytest.importorskip` — they are not failures.

Docs are Sphinx-based in `docs/` (built on Read the Docs): `make -C docs html`.

## Branches and releases

- `develop` is the main development branch; `master` holds releases.
- CI (`.github/workflows/ci.yml`) runs tests on Python 3.10 and 3.11 for pushes to `master`,
`develop`, and `claude/**` branches, then lint (ruff) and type check (ty).
- The version string lives in `pleque/__init__.py` (`__version__`), with the minor version also
in `docs/source/conf.py`. The release process is documented in `how_to_publish_release.md`.

## Architecture

### Core (`pleque/core/`)

- `equilibrium.py` — `Equilibrium`, the heart of the package (~2000 lines). Wraps an
`xarray.Dataset` of poloidal flux on an (R, Z) grid plus 1D profiles, builds 2D/1D splines
(`RectBivariateSpline` / `UnivariateSpline`), finds the magnetic axis, X-points, LCFS and
strike points, and exposes evaluation methods (`B_R`, `B_Z`, `B_tor`, `B_abs`, `psi`, `q`, ...),
flux-surface generation, mapping, and plotting helpers.
- `coordinates.py` — `Coordinates`, the universal coordinate container. Nearly every public
`Equilibrium` method accepts flexible coordinate input (1D `psi_n`, 2D `(R, Z)`, 3D
`(R, Z, phi)`, arrays, grids, other `Coordinates`) and normalises it through this class.
- `fluxsurface.py` — `Surface` / `FluxSurface` (closed/open contours, built on `shapely`),
with geometry properties (area, volume, geometric averages).
- `fluxfunctions.py` / `surfacefunctions.py` — containers for 1D profile functions attached to
an equilibrium.
- `cocos.py` — COCOS (tokamak COordinate COnventionS, Sauter & Medvedev) coefficient handling.
Readers take a `cocos` argument; `Coordinates` carries cocos through transformations.

**Import-order caveat:** `pleque/core/__init__.py` has a load-order-dependent import sequence
due to circular imports (`Equilibrium` must be imported last). Ruff `I001`/`F401` are suppressed
for it in `pyproject.toml` — do not let an auto-formatter reorder those imports.

### IO (`pleque/io/`)

- `readers.py` — high-level entry points (`read_geqdsk`, ...) that return `Equilibrium` instances.
- `geqdsk.py` is the public G-EQDSK read/write API; `_geqdsk.py` contains the low-level format
routines (vendored from FreeGS, LGPL — keep its license header intact).
- Per-source readers: `compass.py` (CDB / FIESTA / EFIT HDF5), `omas.py` (OMAS/IMAS),
`metis.py`, `jet/`. Optional heavy dependencies are imported inside functions so the package
works without them.
- `io/__init__.py` files re-export the public API (`F401` suppressed for them).

### Supporting packages

- `pleque/utils/` — numerics behind `Equilibrium`: `surfaces.py` (contour finding, boundary
tracking), `field_line_tracers.py`, `flux_expansions.py`, `equi_tools.py`, `plotting.py`, and
`decorators.py` (see array convention below).
- `pleque/config/settings.py` — `pydantic-settings` based `Settings`; access via the
`lru_cache`d `get_settings()`, so settings are effectively process-global.
- `pleque/spatran/` — affine transformations and reference frames for spatial transforms.
- `pleque/resources/` — bundled test equilibria (eqdsk/gfile/netCDF files).
- `pleque/tests/utils.py` — loads the bundled equilibria (`load_testing_equilibrium(case)`);
used by `tests/conftest.py`, whose module-scoped `equilibrium` fixture parametrizes most tests
over six bundled test cases.

### Array convention (important for any new evaluation function)

Public evaluation functions follow a component-first convention, enforced via decorators in
`pleque/utils/decorators.py` (`scalar_function`, `vector_function`,
`ordered_path_scalar_function`):

- Scalars at paired points return `[n_elements]`; on a grid (`grid=True`) return `[n_z, n_r]`,
matching `np.meshgrid(R, Z)`.
- Vectors return `[n_dim, ...]` (e.g. `[n_dim, n_z, n_r]` for grids).
- SciPy's `RectBivariateSpline` returns grids as `(n_R, n_Z)`;
`Equilibrium._shape_spline_result` transposes to the public `(n_Z, n_R)` layout — use it when
adding spline-backed methods.
38 changes: 33 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ For more information see the documentation at https://pleque.readthedocs.io.
The following packages are required to install `pleque`:

```
python>=3.5
python>=3.11
numpy
scipy
shapely
Expand Down Expand Up @@ -59,12 +59,13 @@ pip install --user .
The following example shows how to load an equilibrium saved in the `eqdsk` format. The equilibrium used here comes from a FIESTA simulation of the COMPASS-Upgrade tokamak.

```python
from importlib import resources

from pleque.io import readers
import pkg_resources
import matplotlib as plt

#Locate a test equilibrium
filepath = pkg_resources.resource_filename('pleque', 'resources/baseline_eqdsk')
filepath = resources.files('pleque').joinpath('resources', 'baseline_eqdsk')
```
The heart of `pleque` is its `Equilibrium` class, which contains all the equilibrium information (and much more). Typically its instances are called `eq`.

Expand All @@ -89,9 +90,35 @@ B = eq.B_abs(R, Z)

Equilibria may be visualised in many different ways; they may be used for mapping or field line tracing; the possibilities are virtually endless. If there's a caveat you find missing from `pleque`, write to us! Further examples can be found as notebooks in the `notebooks` folder or in the `examples` directory.

## Version
## Array convention

Public evaluation functions use a component-first convention for vector quantities and
the same spatial shape as the requested coordinates for scalar quantities.

* Scalar functions evaluated at paired points return `[n_elements]`.
* Scalar functions evaluated on a grid return `[n_z, n_r]`, matching `np.meshgrid(R, Z)`.
* Vector functions return `[n_dim, ...]`, for example `[n_dim, n_elements]` for paired points
and `[n_dim, n_z, n_r]` for grids.
* Passing mesh-shaped `R` and `Z` arrays with `grid=False` is treated as elementwise evaluation
and preserves the mesh shape.

## Configuration

All tunable algorithm parameters (grid resolutions, solver tolerances, search heuristics, ...)
have built-in defaults that can be overridden by a `pleque.toml` file — in the working
directory, in the user config directory (`~/.config/pleque/` or `%APPDATA%\pleque\`), or as a
`[tool.pleque]` table in `pyproject.toml` — or by `PLEQUE_`-prefixed environment variables:

```toml
[flux_surfaces]
n_psi = 300

[lcfs]
search_grid_nr = 1000
```

0.0.9
See the [configuration documentation](https://pleque.readthedocs.io/en/latest/configuration.html)
for the file lookup order and the full settings reference.

## Authors

Expand All @@ -116,6 +143,7 @@ Although the systematic development of the project was intended, it endup bit or

* 0.0.8 - Tagged master branch with the last change from 19-08-2024.
* 0.0.9 - Tagged develop branch with maintained back compatibility with 0.0.8.
* 0.0.10 All the phd-related work merged the master + update of array ordering. This version may thus introduce breaking changes!


## Related projects
Expand Down
6 changes: 6 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@
'Lukas Kripner', 'manual'),
]

# DEBUG temporal fix

from logging import getLogger
getLogger('nbsphinx').warning("nbsphinx allow errors enabled in conf.py")
nbsphinx_allow_errors = True

# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
Expand Down
Loading
Loading