Skip to content

Commit 50ddf69

Browse files
authored
Merge branch 'develop' into claude/julia-tests-github-workflows-9axlpa
2 parents f72b79f + df85167 commit 50ddf69

9 files changed

Lines changed: 635 additions & 600 deletions

File tree

.claude/agents/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Agent Team
2+
3+
This repo ships a small team of specialized Claude Code subagents in `.claude/agents/`. They are **stateless reviewers**: each runs in its own context, is handed a specific deliverable, and returns its findings to the main session — they do not talk to each other. **The main session is the integrator.** You drive them; you do not delegate the whole task and walk away.
4+
5+
**Invoke an agent by name** for the matching job — e.g. *"review this with the fortran-physics-reviewer"* or *"run the regression-guardian against develop"*. Do **not** "consult all the agents" reflexively: that burns the token budget and produces noise. Pick the agent whose job matches the change.
6+
7+
## Roster
8+
9+
| Agent | Model | Role — invoke when… |
10+
|---|---|---|
11+
| `fortran-physics-reviewer` | opus | A physics kernel, numerical method, derivative, integral, or quadrature was written/changed. Audits fidelity to the reference papers and the Fortran GPEC source. Carries project memory (correspondence map + per-domain audit checklists for KineticForces and InnerLayer), so its reviews compound — let it record findings. |
12+
| `clean-code-reviewer` | opus | A logical chunk of code is ready and you want readability/maintainability review for a fusion physicist audience (naming, magic numbers, docstrings, structure). |
13+
| `julia-performance-optimizer` | opus | A specific function/hotspot is slow or perf-sensitive (type stability, allocations, hot-loop work in ODE/kinetic/resistive-layer paths). |
14+
| `fast-interpolations-optimizer` | opus | Code uses FastInterpolations.jl and you want allocation-free / optimal-search-type review. |
15+
| `regression-guardian` | sonnet | **Before merging any substantive change** (mandatory per the Regression Harness policy — see `docs/development/regression-harness.md`), or when you need to know whether a tracked numerical quantity moved. Runs the harness, reports the table, flags non-OK rows, proposes new cases. |
16+
17+
## Recommended review pipeline for a substantive change
18+
19+
Run sequentially, reading each agent's findings before launching the next:
20+
21+
1. **`fortran-physics-reviewer`** — physics fidelity first; a fast-but-wrong result is worthless.
22+
2. **`clean-code-reviewer`** — readability and maintainability.
23+
3. **`julia-performance-optimizer`** and/or **`fast-interpolations-optimizer`** — only if the change is performance-relevant.
24+
4. **`regression-guardian`** — always, last, before merge. Confirms the numbers didn't silently move.
25+
26+
Not every change needs all four. A docs-only change needs none; a pure perf refactor still needs the physics reviewer (to confirm no numerical change) and the regression-guardian.
27+
28+
## Budget
29+
30+
Every consultation is bounded — see **Subagent Consultations** in `/CLAUDE.md` (≤30 tool uses, ≤10 min, one concrete deliverable, never re-launch a runaway). The agent bodies now self-enforce this, but state the budget in your prompt anyway and always hand the agent the specific file paths to act on.

CLAUDE.md

Lines changed: 15 additions & 600 deletions
Large diffs are not rendered by default.

docs/development/architecture.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Architecture
2+
3+
## Computational Workflow
4+
5+
GPEC follows a three-stage analysis pipeline:
6+
7+
1. **Equilibrium** → Solve Grad-Shafranov equation, compute flux surfaces, safety factor q-profile
8+
2. **Stability Analysis** → Solve ideal MHD eigenvalue problem (DCON-style), identify singular surfaces
9+
3. **Perturbed Equilibrium** → Compute plasma response to external fields, analyze singular coupling and island formation
10+
11+
This workflow is reflected in the modular structure and data flow.
12+
13+
## Module Structure
14+
15+
GPEC consists of **seven main modules** organized in `src/`:
16+
17+
### Foundation Modules
18+
19+
1. **Splines** (`src/Splines/`) - Numerical interpolation library
20+
- `CubicSpline.jl` - 1D cubic spline interpolation
21+
- `BicubicSpline.jl` - 2D bicubic spline interpolation
22+
- `FourierSpline.jl` - Fourier-based spline interpolation
23+
- Status: Mature, pure Julia implementation
24+
25+
2. **Utilities** (`src/Utilities/`) - Shared computational tools
26+
- `FourierTransforms.jl` - Efficient Fourier transform utilities with pre-computed basis functions
27+
- Provides type-stable functor pattern for repeated transforms
28+
- Used by Vacuum and PerturbedEquilibrium modules
29+
30+
### Core Physics Modules
31+
32+
3. **Equilibrium** (`src/Equilibrium/`) - MHD equilibrium solvers
33+
- Main entry point: `setup_equilibrium(path)` or `setup_equilibrium(config)`
34+
- Supports multiple equilibrium types:
35+
- `efit` - EFIT g-file format
36+
- `chease`, `chease2` - CHEASE equilibrium code formats
37+
- `lar` - Large Aspect Ratio analytical model
38+
- `sol` - Solovev analytical equilibrium
39+
- Key files:
40+
- `EquilibriumTypes.jl` - Core data structures
41+
- `ReadEquilibrium.jl` - Parsing equilibrium files
42+
- `DirectEquilibrium.jl` - Direct Grad-Shafranov solver
43+
- `InverseEquilibrium.jl` - Inverse equilibrium solver
44+
- `AnalyticEquilibrium.jl` - Analytical solutions
45+
- Status: Stable and feature-complete
46+
47+
4. **Vacuum** (`src/Vacuum/`) - Vacuum field calculations and Green's functions
48+
- Computes vacuum response matrices for ideal MHD analysis
49+
- Calculates both **interior** (grri) and **exterior** (grre) Green's functions
50+
- Main functions:
51+
- `compute_vacuum_response()` - Pure Julia implementation
52+
- Key files:
53+
- `VacuumStructs.jl` - Data structures
54+
- `VacuumInternals.jl` - Core algorithms
55+
- `VacuumFromEquilibrium.jl` - Integration with equilibrium data
56+
- Status: **Pure Julia implementation complete and available**
57+
58+
5. **ForceFreeStates** (`src/ForceFreeStates/`) - Ideal MHD stability analysis (DCON-style)
59+
- Solves ideal MHD eigenvalue problem with force-free boundary conditions
60+
- Identifies singular surfaces where ξ·∇ψ = 0
61+
- Key files:
62+
- `ForceFreeStatesStructs.jl` - Core data structures
63+
- `Ode.jl` - ODE solver for Euler-Lagrange equations
64+
- `Sing.jl` - Singular point handling and layer analysis
65+
- `Fourfit.jl` - Fourier fitting routines
66+
- `FixedBoundaryStability.jl` - Fixed boundary analysis
67+
- `Free.jl` - Free boundary stability
68+
- `Ballooning.jl` - Local stability scan: Mercier D_I, resistive interchange D_R, and high-n ballooning Δ' (s–α). Replaces the former standalone `Mercier.jl`.
69+
- Status: Stable, core DCON functionality implemented
70+
71+
### Perturbed Equilibrium Modules
72+
73+
6. **ForcingTerms** (`src/ForcingTerms/`) - External field specification
74+
- Handles external magnetic field perturbations (coils, RMP, etc.)
75+
- Supports ASCII and HDF5 forcing data formats
76+
- `ForcingMode` data structure specifies amplitude and phase for each (m,n) component
77+
- Status: Complete and functional
78+
79+
7. **PerturbedEquilibrium** (`src/PerturbedEquilibrium/`) - **GPEC-style plasma response**
80+
- Computes plasma response to external forcing
81+
- Calculates singular coupling metrics at rational surfaces
82+
- Key files:
83+
- `PerturbedEquilibrium.jl` - Main entry point
84+
- `PerturbedEquilibriumStructs.jl` - Data structures
85+
- `ResponseMatrices.jl` - Permeability matrix calculation
86+
- `FieldReconstruction.jl` - Mode-space field reconstruction
87+
- `Response.jl` - Plasma response computation
88+
- `SingularCoupling.jl` - **Singular surface analysis** including:
89+
- Delta prime (Δ') tearing stability parameter
90+
- Resonant flux and currents at rational surfaces
91+
- Island half-widths and Chirikov parameters
92+
- Green's functions at interior flux surfaces
93+
- Surface inductance for singular surfaces
94+
- `Utils.jl` - Helper functions
95+
- Status: Core plasma response and singular coupling calculations implemented; active area of development
96+
97+
## Configuration
98+
99+
**Unified Configuration File**: `gpec.toml`
100+
101+
All GPEC modules are configured via a single TOML file with the following sections:
102+
103+
- `[Equilibrium]` - Equilibrium solver settings
104+
- `[Wall]` - Wall geometry and vacuum region
105+
- `[ForceFreeStates]` - Stability analysis parameters
106+
- `[PerturbedEquilibrium]` - Perturbed equilibrium settings
107+
- `[ForcingTerms]` - External field specification
108+
109+
Key parameters:
110+
- `force_termination` - Set to `true` to exit after equilibrium/stability (skip perturbed equilibrium)
111+
- `output_file` - Output filename (default: `gpec.h5`)
112+
113+
Example configuration files are provided in:
114+
- `examples/Solovev_ideal_example/gpec.toml`
115+
- `examples/DIIID-like_ideal_example/gpec.toml`
116+
117+
**Note**: Legacy configuration files (`equil.toml`, `vac.in`) are deprecated.
118+
119+
## Data Flow
120+
121+
The complete GPEC analysis pipeline:
122+
123+
1. **Equilibrium Setup**:
124+
- `setup_equilibrium(config)` reads configuration from `gpec.toml`
125+
- Parses equilibrium data (EFIT, CHEASE, or analytical)
126+
- Runs Grad-Shafranov solver (direct or inverse)
127+
- Computes global parameters: q-profile, pressure, current density, β
128+
- Creates bicubic splines for (ψ, θ, φ) → (R, Z, Φ) mapping
129+
- Outputs: `PlasmaEquilibrium` object
130+
131+
2. **Vacuum Response**:
132+
- Initialize plasma and wall surfaces from equilibrium
133+
- Compute vacuum response matrices (wv, grri, grre)
134+
- Calculate both interior and exterior Green's functions
135+
- Pure Julia implementation
136+
137+
3. **Stability Analysis** (ForceFreeStates):
138+
- Solve ideal MHD Euler-Lagrange equations via ODE integration
139+
- Identify singular surfaces where q = m/n
140+
- Compute Δ' at each singular surface
141+
- Calculate potential and kinetic energies
142+
- Check Mercier and ballooning stability criteria
143+
- Outputs: Eigenmode structure ξ(ψ,θ)
144+
145+
4. **Perturbed Equilibrium** (GPEC-style):
146+
- Load external forcing data (coil fields, RMP configuration)
147+
- Compute plasma response using permeability matrices
148+
- Reconstruct mode-space fields (ξ_modes, b_modes)
149+
- Calculate singular coupling metrics at rational surfaces:
150+
- Δ' (tearing stability parameter)
151+
- Island half-widths
152+
- Chirikov overlap parameter
153+
- Resonant flux and currents
154+
- Outputs: `PerturbedEquilibriumState` with response fields and diagnostics
155+
156+
5. **Output**:
157+
- All results saved to single HDF5 file (default: `gpec.h5`)
158+
- HDF5 groups: `input/`, `info/`, `equil/`, `splines/`, `locstab/`, `integration/`, `singular/`, `vacuum/`, and perturbed equilibrium data
159+
160+
## Key Data Structures
161+
162+
### Equilibrium
163+
- `PlasmaEquilibrium` - Main equilibrium container with bicubic splines (rzphi), 1D profiles (sq), and global parameters
164+
- `EquilibriumConfig` - Configuration loaded from TOML files
165+
166+
### Vacuum
167+
- `VacuumInput` - Input parameters for vacuum calculations
168+
- `WallShapeSettings` - Wall geometry configuration
169+
170+
### Stability
171+
- `SingType` - Singular surface data including:
172+
- Rational surface location (ψ, q = m/n)
173+
- Δ' (tearing stability parameter)
174+
- Eigenmode structure at singular surface
175+
- Green's functions (grri, grre) at interior singular surfaces
176+
- Surface inductance
177+
178+
### Perturbed Equilibrium
179+
- `PerturbedEquilibriumControl` - User-facing TOML configuration parameters
180+
- `PerturbedEquilibriumInternal` - Internal state with mode arrays
181+
- `PerturbedEquilibriumState` - Results including:
182+
- Response fields (ξ_modes, b_modes) in mode space
183+
- Singular coupling matrices [msing × numpert_total]
184+
- Island diagnostics (half-widths, Chirikov parameters)
185+
- `ForcingMode` - External forcing specification (m, n, amplitude, phase)
186+
187+
## Module Dependencies
188+
189+
```
190+
GeneralizedPerturbedEquilibrium
191+
├── Splines (foundation)
192+
├── Utilities (shared tools)
193+
│ └── FourierTransforms
194+
├── Equilibrium (uses Splines)
195+
├── Vacuum (uses Splines, Equilibrium, Utilities)
196+
├── ForcingTerms (data I/O)
197+
├── ForceFreeStates (uses Equilibrium, Vacuum, Splines)
198+
└── PerturbedEquilibrium (uses ForceFreeStates, Vacuum, ForcingTerms, Utilities)
199+
```

docs/development/benchmarking.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Benchmarking
2+
3+
Use the generic benchmarking tool at `benchmarks/benchmark_git_branches.jl` to compare performance between branches or commits.
4+
5+
**Tool usage:**
6+
7+
```bash
8+
# Compare feature branch against develop
9+
julia benchmarks/benchmark_git_branches.jl \
10+
--example examples/DIIID-like_ideal_example \
11+
--branch1 develop \
12+
--branch2 feature-branch
13+
14+
# Compare specific commits
15+
julia benchmarks/benchmark_git_branches.jl \
16+
--example examples/DIIID-like_ideal_example \
17+
--commit1 abc123 \
18+
--commit2 def456
19+
20+
# Compare current develop vs develop from 1 month ago
21+
julia benchmarks/benchmark_git_branches.jl \
22+
--example examples/DIIID-like_ideal_example \
23+
--branch1 develop \
24+
--commit1 HEAD~10 \
25+
--branch2 develop
26+
```
27+
28+
**Default benchmark case:** `examples/DIIID-like_ideal_example`
29+
30+
**Reported metrics:**
31+
1. **Eigenmode energy (`et[1]`)** - First eigenvalue; verifies calculation correctness
32+
2. **Integration steps** - Total ODE solver steps
33+
3. **Runtime (warmed)** - Wall-clock time averaged over multiple warm runs (JIT warmup handled automatically)
34+
4. **Commit hash** - Git commit of code tested
35+
36+
**The tool automatically:**
37+
- Handles JIT warmup (runs example 3 times, averages last 2)
38+
- Switches between branches/commits
39+
- Stashes uncommitted changes if necessary
40+
- Restores original branch when done
41+
- Reports comparison with percentage differences
42+
43+
**Important notes:**
44+
- Working directory should be clean or changes will be stashed during branch switching
45+
- Tool requires HDF5.jl for reading `gpec.h5` output
46+
- Each benchmark run takes several minutes per branch (includes compilation + warm runs)
47+
48+
**Benchmark script conventions:**
49+
- Benchmark scripts must reference input data from `examples/` (e.g., `joinpath(@__DIR__, "..", "examples", "DIIID-like_ideal_example")`). Never duplicate example inputs into `benchmarks/`.
50+
- If a benchmark needs modified TOML settings or a parameter scan, copy inputs to a temporary local directory at runtime — do not commit these copies.
51+
- All outputs (figures, CSVs, HDF5 files) must be saved into `benchmarks/` itself (or a self-described subdirectory within it, e.g., `benchmarks/coil_scan_results/`). Output files are not committed.

docs/development/git-workflow.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Git Workflow
2+
3+
This project uses GitFlow (http://nvie.com/posts/a-successful-git-branching-model):
4+
5+
- Two permanent branches: `main` and `develop`
6+
- `main` is updated only at release-ready stages via pull request from `develop`
7+
- `develop` is the integration branch — all feature branches merge here
8+
9+
**IMPORTANT**: All development must be done on feature branches. No commits should be made directly to `develop` or `main`. Always create a branch from `develop`, do all work there, and open a pull request back into `develop`.
10+
11+
## Branch Naming
12+
13+
Branches use a typed prefix and a lowercase hyphen-separated description:
14+
15+
| Prefix | Purpose | Branches from | Merges into |
16+
|---|---|---|---|
17+
| `feature/` | New functionality | `develop` | `develop` |
18+
| `bugfix/` | Non-critical bug fixes | `develop` | `develop` |
19+
| `hotfix/` | Critical production fix | `main` | `main` + `develop` |
20+
| `performance/` | Performance improvements | `develop` | `develop` |
21+
| `refactor/` | Refactoring without behavior change | `develop` | `develop` |
22+
| `docs/` | Documentation only | `develop` | `develop` |
23+
| `test/` | Test additions/improvements | `develop` | `develop` |
24+
| `experiment/` | Exploratory work, may not merge | `develop` ||
25+
26+
Examples: `bugfix/sing-lim-bounds-error`, `feature/kinetic-damping`, `performance/green-function-prefactor`
27+
28+
Author-named branches (e.g. `jmh/`, `nlogan/`) are not used — git history already records authorship on every commit.
29+
30+
## Hotfix Workflow
31+
32+
Hotfixes address critical bugs in production (`main`) that cannot wait for the next release cycle:
33+
34+
1. Branch `hotfix/description` from the current tagged `main` commit
35+
2. Fix the bug with one or more commits
36+
3. Merge into `main` via pull request; tag the merge commit with a new patch version (e.g. `v0.1.1`)
37+
4. Merge the same branch into `develop` so the fix is not lost in the next release
38+
39+
## Versioning
40+
41+
This project uses semantic versioning: `v{major}.{minor}.{patch}`
42+
43+
- **major**: breaking API or file-format changes
44+
- **minor**: new features, backward-compatible
45+
- **patch**: bug fixes (typically via hotfix branches)
46+
47+
Tags are applied to merge commits on `main`.
48+
49+
## Commit Message Format
50+
51+
```
52+
CODE - TAG - Detailed message
53+
```
54+
55+
Where:
56+
- **CODE**: Module name (EQUIL, VAC, VACUUM, ForceFreeStates, PERTURBED EQUILIBRIUM, etc.)
57+
- **TAG**: Type descriptor (WIP, MINOR, IMPROVEMENT, BUG FIX, NEW FEATURE, REFACTOR, CLEANUP, etc.)
58+
59+
Examples:
60+
- `PERTURBED EQUILIBRIUM - NEW FEATURE - Implement singular coupling diagnostics`
61+
- `VAC - IMPROVEMENT - Add dual Green's function computation`
62+
- `EQUIL - BUG FIX - Fixed separatrix finding for high kappa`
63+
- `ForceFreeStates - REFACTOR - Unified singular surface data structure`
64+
65+
This format is used for compiling release notes, so tags should be human-readable and descriptive.
66+
67+
## Merge Conflict Resolution Policy
68+
69+
- When resolving git conflicts, do not simply accept one side.
70+
- Analyze what each side changed and WHY before producing a resolution.
71+
- Produce a merged version incorporating both sets of changes.
72+
- If both sides renamed the same symbol differently, prefer the current (ours) branch convention.
73+
- When a rename on one side conflicts with a logic change on the other, apply the logic change using the renamed symbol.
74+
- If a conflict involves changes to numerical parameters (tolerances, boundary conditions, grid sizes), flag for human review rather than guessing.
75+
- Flag any conflicts where the combination is ambiguous for human review.

docs/development/plotting.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Plotting Conventions
2+
3+
## Spectrum plots
4+
5+
Any plot with discrete mode numbers m or n on the x-axis must use `seriestype=:steppre` with a `step_series` helper that pads zeros on both ends. Pattern from `benchmarks/benchmark_coil_ForcingTerms_against_fortran.jl`:
6+
7+
```julia
8+
function step_series(m_vals, amps)
9+
m_ext = [m_vals[1] - 1; m_vals; m_vals[end] + 1]
10+
amp_ext = [0.0; amps; 0.0]
11+
return m_ext, amp_ext
12+
end
13+
# Usage:
14+
m_ext, a_ext = step_series(m_vals, amplitudes)
15+
plot!(p, m_ext, a_ext; seriestype=:steppre, lw=2, label="...")
16+
```
17+
18+
## Figures and plots
19+
20+
- Always print the full absolute path of any figure or plot file you save, so the user can open it directly without searching the filesystem.
21+
- Always check that axis labels are not clipped. In Plots.jl there is no `tight_layout()` equivalent; use explicit margins instead: `left_margin=12Plots.mm`, `bottom_margin=4Plots.mm`, etc. When in doubt, add a generous `left_margin` to prevent y-axis label cutoff.

0 commit comments

Comments
 (0)