diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index efe0566..5447704 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,15 @@ name: tests (fast) # Fast unit suite — runs on every push and PR. No OpenFUSIONToolkit / live -# solver needed (those are the `solver`-marked tests, gated to the merge queue; -# see solver.yml). `pytest` is fast-by-default via `addopts = -m "not solver"` -# in pyproject.toml. +# solver needed (those are the `solver`-marked tests; see solver.yml). +# `pytest` is fast-by-default via `addopts = -m "not solver"` in pyproject.toml. +# +# Two dependency sets so an upstream numpy/scipy release surfaces as its own +# signal instead of failing unrelated feature PRs (e.g. scipy 1.18 changed +# RectBivariateSpline.ev scalar returns; numpy 2.5 made float(shape-(1,)) +# a TypeError): +# * pinned — the validated floor (bump deliberately when adopting new deps) +# * latest — whatever pip resolves today (the early-warning canary) on: push: pull_request: @@ -15,14 +21,22 @@ concurrency: jobs: fast: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + deps: [pinned, latest] + name: fast (${{ matrix.deps }}) steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.13" - - name: Install package + pytest + - name: Install package + pytest (${{ matrix.deps }} deps) run: | python -m pip install --upgrade pip + if [ "${{ matrix.deps }}" = "pinned" ]; then + pip install "numpy==2.4.*" "scipy==1.17.*" + fi pip install -e . pytest - name: Run fast suite (solver tests deselected by default) run: pytest -q diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..9b47ce0 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,28 @@ +cff-version: 1.2.0 +message: "If you use bouquet in your research, please cite it as below." +title: "bouquet: BOotstrap Uncertainty QUantified Equilibrium Toolkit" +type: software +authors: + - family-names: Burgess + given-names: Daniel + - family-names: Hansen + given-names: Chris +version: 0.2.0 +doi: 10.5281/zenodo.19398541 +date-released: 2026-07-02 +license: LGPL-3.0 +repository-code: "https://github.com/d-burg/bouquet" +url: "https://d-burg.github.io/bouquet/" +abstract: >- + GP-sampled perturbed tokamak equilibria for uncertainty quantification + with OpenFUSIONToolkit/TokaMaker. bouquet generates families ("bouquets") + of perturbed equilibria from a baseline kinetic equilibrium by drawing + correlated profile perturbations from Gaussian-process regression + posteriors, solving the Grad-Shafranov equation for each sample, and + archiving all results to a single self-describing HDF5 database. +keywords: + - tokamak + - plasma physics + - equilibrium + - uncertainty quantification + - Grad-Shafranov diff --git a/README.md b/README.md index da45384..752bb2d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # bouquet [![DOI](https://zenodo.org/badge/1162850908.svg)](https://doi.org/10.5281/zenodo.19398541) +[![tests](https://github.com/d-burg/bouquet/actions/workflows/tests.yml/badge.svg)](https://github.com/d-burg/bouquet/actions/workflows/tests.yml) +![Python 3.9+](https://img.shields.io/badge/python-%E2%89%A53.9-blue) **BO**otstrap **U**ncertainty **QU**antified **E**quilibrium **T**oolkit @@ -9,7 +11,8 @@ GP-sampled perturbed equilibria for uncertainty quantification with TokaMaker. Bouquet generates families ("bouquets") of perturbed tokamak equilibria from a baseline kinetic equilibrium by drawing correlated profile perturbations from Gaussian process regression posteriors, solving the Grad–Shafranov equation for -each sample, and archiving all results to a single HDF5 database. +each sample, and archiving all results to a single self-describing HDF5 +database. Two baseline sources are supported through one class-based API (`bouquet.Bouquet`): @@ -21,18 +24,28 @@ Two baseline sources are supported through one class-based API carries the separated currents (`j_ohmic` / `j_bootstrap`), kinetic profiles, and fast-ion pressure; no reconstruction step is needed. -

-Python 3.9+ -v0.2.0 -

- --- ## Citation -If you use Bouquet in your research, please cite: +If you use Bouquet in your research, please cite (see also +[`CITATION.cff`](CITATION.cff) / the "Cite this repository" button): + +> Burgess, D., Hansen, C. (2026). Bouquet (v0.2.0). Zenodo. https://doi.org/10.5281/zenodo.19398541 + + +## Workflow at a glance + +The physics workflow — what happens to the profiles and equilibrium +quantities from inputs to the archived ensemble: + +[![physics workflow](docs/flowchart/physics_workflow.svg)](https://d-burg.github.io/bouquet/flowchart/) -> Burgess, D., Hansen, C. (2025). Bouquet (v0.1.0). Zenodo. https://doi.org/10.5281/zenodo.19398542 +The same page also hosts the **full logic map** — every config knob, decision +gate, and artifact (550+ nodes), extracted from the code with a `file:line` +anchor on every node: +**[→ explore interactively](https://d-burg.github.io/bouquet/flowchart/)** +([source + regeneration](docs/flowchart/)). ## Contents @@ -43,7 +56,9 @@ If you use Bouquet in your research, please cite: - [Workflow Overview](#workflow-overview) - [IO Modules](#io-modules) - [Plotting](#plotting) -- [HDF5 Database](#hdf5-database) +- [HDF5 Archive](#hdf5-archive) +- [Parallel Generation](#parallel-generation) +- [Timeseries Sweeps](#timeseries-sweeps) - [Examples](#examples) - [Testing](#testing) - [Coil Constraint Handling](#coil-constraint-handling) @@ -57,6 +72,10 @@ If you use Bouquet in your research, please cite: - **Gaussian Process perturbation** of kinetic profiles (n_e, T_e, n_i, T_i) with user-supplied uncertainty envelopes and spatially-varying correlation lengths (Gibbs non-stationary kernels). +- **Z_eff-consistent density scheme**: each draw perturbs {n_e, T_e, T_i, + Z_eff} and *derives* the main-ion density from quasi-neutrality with a + single effective impurity charge, so n_i / n_z / Z_eff stay mutually + consistent in every sample. - **Dual-grid kinetic profiles**: kinetic profiles can be specified on a separate grid (`psi_N_kinetic`) that extends past ψ_N = 1 into the SOL. GPR sampling includes the SOL; equilibrium solving uses the confined region. @@ -75,6 +94,10 @@ If you use Bouquet in your research, please cite: (separated currents, kinetic profiles, fast-ion pressure, rotation) with parallel→toroidal current conversion and anisotropic fast-pressure reduction (`bouquet.physics`). +- **Validated workflow presets**: `from_geqdsk` / `from_imas` auto-apply the + workflow validated for each source path (`geqdsk-standard` / + `imas-diff-c`), and a guard raises on known-bad knob combinations + (`GenerationConfig.workflow="custom"` opts out for experiments). - **Recon-anchor + adaptive l_i gate**: at sigma -> 0 the pipeline reproduces the reconstructed equilibrium to within recon's own residual (l_i within ~0.5% of target, X-pt within ~2 mm, bnd_RMS ~3-4 mm vs eqdsk). See @@ -91,6 +114,16 @@ If you use Bouquet in your research, please cite: - **Reconstruction quality metrics**: each reconstruction reports jphi_mode, spike alignment, core/edge j_phi RMS, l_i error, Ip error, and LCFS boundary RMS/max deviation. +- **Self-describing HDF5 archive (schema v2)**: bare dataset names with units + in attrs, byte-perfect g-file/p-file payloads, filter flags, and full + provenance — schema version, package version, and the exact JSON-serialized + `BouquetConfig` that produced the file. See + [`docs/archive-schema.md`](docs/archive-schema.md). +- **High-level archive reader** (`BouquetArchive`): walk scans, draws, + profiles, and stored equilibria without hand-rolling any h5 traversal. +- **Process-parallel generation**: laptop `ProcessPoolExecutor` and SLURM + job-array backends over one shard runner, with cross-worker baseline + verification and slice-decorrelated seeding. - **COCOS-aware GEQDSK reader** with full flux-surface geometry (κ, δ, squareness), safety factor, current density, and exact outboard-midplane profiles — all computed independently of external tools. @@ -100,10 +133,8 @@ If you use Bouquet in your research, please cite: support. Verified field-by-field against OMFIT's `OMFITgeqdsk`. - **P-file reader/writer** supporting the Osborne format with 24+ profile types, diamagnetic rotation computation, E×B decomposition, and radial - electric field. -- **Self-contained HDF5 archive**: raw g-file and p-file bytes, 1-D profiles, - scalar diagnostics, and coil currents — everything needed to reconstruct and - visualise each equilibrium. + electric field; plus an impurity-CER reader and radial-force-balance E_r + (`read_ida_cer` / `radial_field_from_cer`). - **Comprehensive plotting**: multi-panel kinetic, current, geometry, and rotation diagnostics from a single function call. @@ -134,6 +165,12 @@ TokaMaker must be installed separately following the [OpenFUSIONToolkit instructions](https://github.com/hansec/OpenFUSIONToolkit). The IO and plotting modules work without TokaMaker. +Two helpers make setups portable across machines: `bq.add_oft_to_path()` +resolves the OFT install (`OFT_PYTHONPATH` env var → known locations → +walk-up) and `bq.find_mesh()` locates the TokaMaker mesh (`BOUQUET_MESH` env +var → walk-up → the bundled example mesh). Both raise with the full list of +locations tried, so failures are actionable on a new machine. + --- ## Quick Start @@ -161,10 +198,11 @@ print(f"Elongation at boundary: {geo['kappa'][-1]:.2f}") mid = eq.midplane print(f"R_mid at boundary: {mid['R'][-1]:.4f} m") -# Load a p-file +# Load a p-file (profiles are attributes; grids/derivatives via helpers) pf = read_pfile("p123456.01000") -ne = pf.get("ne") # returns (psinorm, values, derivatives) tuple -Te = pf.get("te") +ne = pf.ne # profile values +psi = pf.psinorm_for("ne") # its psi_N grid +dne = pf.derivative_for("ne") # its stored derivative ``` ### COCOS conversion and Bt/Ip flip @@ -187,7 +225,7 @@ eq2 = GEQDSKEquilibrium.from_bytes(raw_bytes, cocos=1) # reconstruct The `Bouquet` class drives the full pipeline: solver setup → baseline → perturbed draws → filtering → export. TokaMaker must be importable -(`PYTHONPATH` to your OpenFUSIONToolkit build, or `pip`-installed OFT). +(`bq.add_oft_to_path()`, or `PYTHONPATH` to your OpenFUSIONToolkit build). ```python import bouquet as bq @@ -196,7 +234,7 @@ import bouquet as bq b = bq.Bouquet.from_geqdsk( "g123456.01000", profiles="p123456.01000", # p-file or IDA .cdf (auto-detected) - mesh="DIIID_mesh.h5", + mesh=bq.find_mesh(), n_draws=20, header="my_run", ) b.reconstruct() # GS reconstruction + quality summary @@ -206,13 +244,16 @@ b.export() # my_run_selected.h5 # --- IMAS/OMAS source: FUSE dd_sim.json (already-separated currents) b = bq.Bouquet.from_imas( - "dd_sim.json", mesh="DIIID_mesh.h5", + "dd_sim.json", mesh=bq.find_mesh(), time=2.1, n_draws=20, header="my_imas_run", ) b.run() # setup -> baseline -> generate -> filter -> export ``` -Tune knobs through the config sub-objects before `generate()`: +`b.prepare()` is the source-agnostic form of the baseline stage +(`reconstruct()` is its alias on the reconstruction path), and +`b.describe()` prints the current configuration showing only non-default +knobs. Tune knobs through the config sub-objects before `generate()`: ```python b.uncertainty.ne_scalar_sigma = 0.05 # flat 5% envelope when no IDA sigmas @@ -223,17 +264,35 @@ b.generation.seed = 1234 ``` Full control (every knob, both sources) goes through `bq.BouquetConfig` — -see the dataclass docstrings in `bouquet/config.py`. The legacy functional -API (`reconstruct_equilibrium` / `generate_bouquet`) remains available for -existing scripts; its parameters are documented in their docstrings. -Note all tolerance arguments are **fractions** (e.g. `l_i_tolerance=0.01`), -not percentages. +see the dataclass docstrings in `bouquet/config.py`. Configs serialize to +JSON (`cfg.to_dict()` / `BouquetConfig.from_dict()`) and every archive +stores the exact config that produced it (`bq.load_config("my_run")`). +The legacy functional API (`reconstruct_equilibrium` / `generate_bouquet`) +remains available for existing scripts. Note all tolerance arguments are +**fractions** (e.g. `l_i_tolerance=0.01`), not percentages. ```python # Visualise any run from its HDF5 archive from bouquet import plot_bouquet, plot_traces -plot_bouquet("my_run.h5", scan_value=0, mode="all") -plot_traces("my_run", scan_value="all") +plot_bouquet("my_run.h5", scan_key=0, mode="all") +plot_traces("my_run.h5", scan_key=0) +# ...or hand the run object itself to any reader/plotter: +plot_bouquet(b) +``` + +### Reading an archive back + +```python +ar = bq.BouquetArchive("my_run.h5") # or bq.BouquetArchive(b) +ar.scan_keys # e.g. ['0'] +sc = ar["0"] +sc.indices, sc.baseline # draw indices (gap-tolerant), baseline dict +for d in sc.selected: # DrawViews passing the filters + print(d.count, d.li1, d.flags) +eq = sc[3].equilibrium() # parsed GEQDSKEquilibrium from stored bytes +sc[3].extract("out/", formats=("geqdsk", "pfile")) # write the raw files + +cfg = bq.load_config("my_run") # the exact BouquetConfig that made it ``` --- @@ -245,34 +304,33 @@ Baseline: g-file + profiles (p-file / IDA), or IMAS/OMAS JSON │ ▼ ┌───────────────────────┐ -│ Define uncertainties │ new_uncertainty_profiles() -│ σ_ne, σ_Te, σ_ni, … │ or user-supplied arrays +│ Define uncertainties │ IDA sigmas / synthetic_ida_sigma() +│ σ_ne, σ_Te, σ_Zeff, … │ or flat fractional envelopes └───────────┬───────────┘ ▼ ┌───────────────────────┐ │ Draw GPR perturbation │ GPRProfilePerturber -│ ne±δne, Te±δTe, … │ (Gibbs kernel, monotonicity enforced) +│ ne±δne, Te±δTe, Zeff… │ (Gibbs kernel, monotonicity enforced) └───────────┬───────────┘ ▼ ┌───────────────────────┐ -│ Match pressure & li │ Pressure rescaling + secant iteration -│ Decompose j = jBS+jI │ on inductive amplitude +│ Derive n_i (quasi- │ Z_eff-primary density scheme +│ neutrality) + p_total │ + fixed p_fast / j_NBI / j_RF └───────────┬───────────┘ ▼ ┌───────────────────────┐ -│ Solve Grad–Shafranov │ TokaMaker -│ Export g-file bytes │ +│ Rebuild j_phi │ j_ind (GPR) + j_BS (Sauter, per-draw) +│ Match pressure & li │ + fixed anchors; secant li iteration └───────────┬───────────┘ ▼ ┌───────────────────────┐ -│ Build perturbed p-file│ Recompute ptot, diamagnetic, -│ Export p-file bytes │ Er, ω_HB from perturbed profiles +│ Solve Grad–Shafranov │ TokaMaker + coil-bound homotopy +│ Export g-file bytes │ └───────────┬───────────┘ ▼ ┌───────────────────────┐ -│ Store to HDF5 │ store_equilibrium() -│ (g-file + p-file raw │ -│ bytes + diagnostics) │ +│ Store to HDF5 (v2) │ profiles + raw bytes + diagnostics +│ + provenance │ + config_json / schema_version └───────────────────────┘ ``` @@ -280,16 +338,16 @@ Baseline: g-file + profiles (p-file / IDA), or IMAS/OMAS JSON | Quantity | Perturbed? | Notes | |----------|:----------:|-------| -| n_e, T_e, n_i, T_i | ✓ | Drawn from GPR posterior | +| n_e, T_e, T_i | ✓ | Drawn from GPR posterior | +| Z_eff | ✓ | Active channel (default on via `zeff_scalar_sigma`) | +| n_i, n_z (impurity) | derived | Quasi-neutrality with the drawn Z_eff (`impurity_Z`) | | Total pressure (p_tot) | ✓ | Recomputed from perturbed kinetics | -| Bootstrap current (j_BS) | ✓ | Sauter model (optional) | -| Inductive current (j_ind) | ✓ | Scaled to match l_i | -| Coil currents | ✓ | Adjusted by TokaMaker to match I_p | -| Diamagnetic rotations | ✓ | Recomputed from perturbed n, T | -| E_r, ω_HB | ✓ | Recomputed using exact midplane B-fields | -| n_z1 (impurity density) | ✗ | Preserved from baseline | -| n_b, p_b (beam) | ✗ | Preserved from baseline | -| Toroidal/poloidal rotation | ✗ | Preserved from baseline | +| Bootstrap current (j_BS) | ✓ | Sauter model recomputed per draw (`recalculate_j_BS`) | +| Inductive current (j_ind) | ✓ | GPR-perturbed + scaled to match l_i | +| Coil currents | ✓ | Adjusted by TokaMaker within homotopy bounds | +| Aux channels (ω_tor, E_r, χ_e, χ_i) | optional | Switchboard: perturbed + stored when sigmas supplied (passive) | +| p_fast, j_NBI, j_RF | ✗ | Fixed additive components, never perturbed | +| Equilibrium anchors (p_diff, jphi_diff, jBS_diff) | ✗ | Fixed offsets applied to baseline AND every draw | ### Scope of the in-spec ensemble (what it is, and isn't) @@ -361,9 +419,10 @@ from bouquet import PFile, read_pfile pf = read_pfile("p123456.01000") -# Access profiles -psi, ne, dne = pf.get("ne") # (psinorm, values, derivatives) -psi_grid = pf.psinorm_for("ne") # just the grid +# Access profiles (attributes), grids and derivatives (helpers) +ne = pf.ne +psi_grid = pf.psinorm_for("ne") +dne = pf.derivative_for("ne") # Modify profiles pf.set_profile("ne", new_psi, new_ne) @@ -382,26 +441,33 @@ Supported profiles: `ne`, `te`, `ni`, `ti`, `nb`, `pb`, `ptot`, `nz1`, `omeg`, `omegp`, `omgvb`, `omgpp`, `omgeb`, `er`, `ommvb`, `ommpp`, `omevb`, `omepp`, `kpol`, `omghb`, `vtor1`, `vpol1`, and more. +### IDA netCDF reader + +`read_ida()` loads IDA `.cdf` kinetic fits (both the direct `*_err` and +ensemble posterior layouts) as an `IDAProfiles` bundle — the same file +supplies the sigma envelopes when used as an uncertainty source. +`read_ida_cer()` loads impurity CER channels, and +`radial_field_from_cer()` evaluates the impurity radial force balance +E_r (with propagated uncertainty) from them. + --- ## Plotting -All plotting functions return `(fig, axes)` and work in two modes: - -1. **File mode** — pass file paths directly -2. **HDF5 mode** — pass `h5path` to load from a bouquet database +All plotting functions return `(fig, axes)` and accept a `Bouquet`, a +`BouquetArchive`, a bare header, or a `.h5` path interchangeably. ### Available functions ```python from bouquet import ( - plot_bouquet, # Full overview (kinetics + jphi + coils) + plot_bouquet, # Full overview (dispatches on stored source kind) plot_traces, # l_i, Ip, boundary deviation traces plot_geqdsk_bouquet, # 3×3 grid: pressure, current, q, geometry, li, flux surfaces plot_pfile_bouquet, # Multi-panel: densities, temperatures, rotations plot_coil_currents, # Bar chart of coil currents plot_tokamaker_comparison, # TokaMaker vs source geqdsk comparison - classify_jphi_profile, # Edge current profile classifier + plot_input_vs_recon, # Baseline-vs-reconstruction gate figure draw_kinetic_profiles, # ne, Te, ni, Ti on existing axes draw_pressure_profiles, # Pressure + perturbed ensemble draw_jphi_total, # j_phi with uncertainty band @@ -409,21 +475,25 @@ from bouquet import ( ) ``` -### Filtering by scan value +### Selecting scans and draws -When an HDF5 database contains multiple scan values, use `scan_val` and -`count` to select subsets: +Archives are organised by `scan_key` (a user-chosen label per bouquet — +a time in ms, a beta value, …). Passing a `scan_key` that does not exist +raises a `KeyError` listing the available keys. ```python -# All perturbations for scan_val=0 (+ baseline in black) -plot_pfile_bouquet(h5path="run.h5", scan_val=0, x_coord="psi_N") +# All draws for scan_key=0 (+ baseline in black) +plot_pfile_bouquet(h5path="run.h5", scan_key=0, x_coord="psi_N") # A single specific equilibrium -plot_pfile_bouquet(h5path="run.h5", scan_val=0, count=3, x_coord="psi_N") +plot_pfile_bouquet(h5path="run.h5", scan_key=0, count=3, x_coord="psi_N") + +# Discover available scan keys +from bouquet import discover_scan_keys +discover_scan_keys("run.h5") # e.g. ['0', '2000', '2200'] -# Discover available scan values -from bouquet import discover_scan_values -discover_scan_values("run.h5") # e.g. ['0', '1', '2'] +# Plot only the filter-selected subset +plot_bouquet("run.h5", scan_key=0, selection="selected") ``` ### Styling @@ -435,50 +505,98 @@ colormap uniformly. --- -## HDF5 Database +## HDF5 Archive -### Schema +Bouquet writes a **schema-v2** self-describing archive — bare dataset names +with units in attrs, fixed `eqdsk`/`pfile` byte payloads, non-destructive +filter flags, and full provenance (`schema_version`, `bouquet_version`, and +the exact `config_json` per scan). The complete layout is documented in +[`docs/archive-schema.md`](docs/archive-schema.md); the code-level source of +truth is [`bouquet/schema.py`](bouquet/schema.py). ``` -run.h5 -├── scan/ -│ └── {scan_val}/ -│ ├── _baseline/ -│ │ ├── baseline.eqdsk # raw geqdsk bytes -│ │ ├── baseline.pfile # raw p-file bytes -│ │ ├── ne, te, ni, ti, … # baseline 1-D profiles -│ │ └── sigma_ne, sigma_te … # uncertainty envelopes -│ ├── 0/ -│ │ ├── header_sv_0.eqdsk # perturbed geqdsk bytes -│ │ ├── header_sv_0.pfile # perturbed p-file bytes -│ │ ├── psi_N, j_phi, ne, … # perturbed 1-D profiles -│ │ └── li1, li3, Zeff # scalar diagnostics -│ ├── 1/ … -│ └── N/ … -└── (flat layout also supported without scan/ prefix) +run.h5 attrs: schema_version=2, bouquet_version, created +└── scan// one group per scan point (+ config_json) + ├── _baseline/ profiles, sigmas, raw eqdsk/pfile bytes, targets + └── / one group per accepted draw (gaps = rejections): + profiles, eqdsk/pfile bytes, coil currents, + l_i(1)/l_i(3), in-spec metrics, filter flags ``` -### Utilities +Prefer `BouquetArchive` (see [Quick Start](#reading-an-archive-back)) or the +functional readers over raw `h5py`: ```python from bouquet import ( - initialize_equilibrium_database, - store_equilibrium, - load_equilibrium, - store_baseline_profiles, - load_baseline_profiles, - discover_scan_values, - count_equilibria, + load_equilibrium, load_baseline_profiles, + discover_scan_keys, count_equilibria, list_equilibrium_indices, + select_indices, read_filter_flags, export_filtered, + write_provenance, load_config, ) -# Inspect a database -svs = discover_scan_values("run.h5") -for sv in svs: - n = count_equilibria("run.h5", scan_value=sv) - print(f"scan_val={sv}: {n} equilibria") +for sk in discover_scan_keys("run.h5"): + n = count_equilibria("run.h5", scan_key=sk) + print(f"scan_key={sk}: {n} equilibria") -# Load a specific equilibrium -data = load_equilibrium("run.h5", scan_value="0", count=0) +data = load_equilibrium("run", count=0, scan_key="0") +cfg = load_config("run", scan_key="0") # reproduce the run +``` + +Pre-v2 archives (written before 2026-07) are detected by the missing +`schema_version` attr: `BouquetArchive` opens them with a warning and +`load_equilibrium` raises a clear error — regenerate them with the current +package. + +--- + +## Parallel Generation + +Draws are embarrassingly parallel, and `OFT_env` is a per-process singleton — +so parallelism is across **processes**, one single-threaded TokaMaker per +physical core (`nthreads=1` is the validated regime: bit-reproducible +baselines, no OpenMP li jitter, no DLSODE hangs). + +```python +import bouquet as bq + +cfg = b.config # any BouquetConfig +summary = bq.parallel_generate( # laptop: ProcessPoolExecutor (spawn) + cfg, n_workers=None, # None -> physical core count + threads_per_worker=1, seed=1234, + backend="laptop", +) + +paths = bq.parallel_generate( # cluster: emit SLURM job-array + merge + cfg, n_workers=32, seed=1234, threads_per_worker=1, + backend="slurm", + slurm=dict(out_dir="slurm_jobs", job_name="my_run", + setup=["export OFT_PYTHONPATH=/path/to/OFT/python"]), +) +# then: bash slurm_jobs/my_run_submit.sh (works from any CWD) +``` + +Each worker runs the ordinary serial pipeline on its shard and writes +`{header}_w{i}.h5`; the merge concatenates them into `{header}.h5`, +**verifying every shard converged to the same baseline** before copying, and +stamps the run-level config provenance. Worker seeds derive from +`SeedSequence(seed, worker_id, scan_key)`, so timeseries slices swept with +one seed are decorrelated. Parallel draws are statistically equivalent to — +but not bit-identical with — a serial run of the same seed. + +--- + +## Timeseries Sweeps + +One IMAS/OMAS file often holds many time slices. `run_slices` sweeps them +into a single archive, one `scan_key` per slice, reusing the solver: + +```python +b = bq.Bouquet.from_imas("dd_sim.json", mesh=bq.find_mesh(), n_draws=20, + header="my_sweep") +b.setup_solver() +metrics = b.run_slices(times=[2.10, 2.20, 2.30], + scan_keys=[2100, 2200, 2300]) +# -> {2100: {n_all, n_selected, li, Ip, ...}, ...} all in my_sweep.h5 ``` --- @@ -490,7 +608,9 @@ Example notebooks are in the `examples/` directory: | Notebook | Description | |----------|-------------| | `D3D-like/bouquet_D3Dlike_geqdsk_example.ipynb` | Class-API walkthrough on the synthetic D3D-like g-file + p-file baseline | -| `D3D-like/bouquet_D3Dlike_omas_example.ipynb` | Class-API walkthrough on the synthetic IMAS/OMAS (FUSE-style) baseline | +| `D3D-like/bouquet_D3Dlike_omas_example.ipynb` | Class-API walkthrough on the synthetic IMAS/OMAS (FUSE-style) baseline, incl. a timeseries sweep | +| `D3D-like/bouquet_D3Dlike_parallel_IMAS_example.ipynb` | Process-parallel generation (laptop pool + SLURM emission) over the OMAS timeseries | +| `D3D-like/bouquet_D3Dlike_systematics.ipynb` | Backend systematics: replaying draws through the solve pipeline to decompose pressure- vs current-driven responses | | `D3D-like/` | The synthetic, shareable D3D-like fixtures (g-file, p-file, OMAS JSON, mesh) + generation recipe | | `COCOS_Bt_Ip/cocos_and_save_example.ipynb` | COCOS conversion, Bt/Ip flip, save to disk/HDF5 | | `COCOS_Bt_Ip/omfit_cocos_comparison.ipynb` | Field-by-field validation against OMFIT (requires `omfit_classes`) | @@ -513,15 +633,21 @@ Tests cover: geometry, current density, safety factor - **`test_pfile.py`** — P-file parsing, rotation decomposition, byte serialisation round-trip -- **`test_physics.py`** — Parallel→toroidal current conversion (ratio + - analytic methods) and fast-pressure isotropization +- **`test_physics.py`** — Parallel→toroidal current conversion, fast-pressure + isotropization, radial-force-balance E_r +- **`test_config.py`** — Config JSON round-trip + archive provenance +- **`test_archive.py`** — `BouquetArchive` reader, schema-v2 + legacy-name + resolution +- **`test_ida.py`** — IDA netCDF reader (direct + ensemble layouts), CER - **`test_golden_bouquet.py`** — Golden-fixture replay of filtering, boundary extraction, and HDF5 round-trips - **`test_systematics.py`** — Solver-marked integration tests (excluded by default; run with `pytest -m solver` and a working TokaMaker) Test data (sample g-files and p-files) is in `tests/data/`; golden HDF5 -fixtures are in `tests/golden/`. +fixtures are in `tests/golden/`. CI runs the fast suite on two dependency +sets (pinned floor + latest) so upstream numpy/scipy changes surface as +their own signal — see [`docs/CI.md`](docs/CI.md). --- @@ -610,6 +736,10 @@ amp budget directly — same structure, different number. ### Progressive homotopy +The class API drives the homotopy through `GenerationConfig` +(`homotopy_passes`, `coil_drift`, `coil_drift_hard_factor`, `inspec_F_max`, +`inspec_VSC_max`); the equivalent functional-API call is: + ```python diagnostics = generate_bouquet( mygs, psi_N, n_equils, "my_run", @@ -661,7 +791,7 @@ coordinate conventions, known limitations, and planned future work is maintained in [`architecture.md`](architecture.md). Key topics include: - COCOS sign conventions -- Quasi-neutrality handling (baseline n_z1 preserved, not recomputed) +- Quasi-neutrality handling (Z_eff-primary density scheme) - Current decomposition (Sauter bootstrap model) - Rotation profile computation (exact midplane, Savitzky–Golay smoothing for ω_HB) - Numerical floors for axis/edge singularities @@ -677,14 +807,31 @@ in [`architecture.md`](architecture.md). Key topics include: | Class / Function | Description | |------------------|-------------| -| `Bouquet` | Stateful driver: `setup_solver` → `prepare_baseline`/`reconstruct` → `generate` → `filter` → `export` (or just `.run()`) | -| `Bouquet.from_geqdsk()` / `Bouquet.from_imas()` | Minimal constructors for the two baseline sources | -| `BouquetConfig` | Top-level typed config (`SolverConfig`, `UncertaintyConfig`, `GenerationConfig`, `FilterConfig`, `FixedComponentsConfig`) | +| `Bouquet` | Stateful driver: `setup_solver` → `prepare`/`reconstruct` → `generate` → `filter` → `export` (or just `.run()`) | +| `Bouquet.from_geqdsk()` / `Bouquet.from_imas()` | Minimal constructors for the two baseline sources (auto-apply the validated workflow preset) | +| `Bouquet.describe()` | Print the configuration (non-default knobs only) | +| `Bouquet.run_slices()` | Multi-slice IMAS sweep into one archive (one `scan_key` per slice) | +| `Bouquet.archive` | The run's `BouquetArchive` | +| `BouquetConfig` | Top-level typed config (`SolverConfig`, `UncertaintyConfig`, `GenerationConfig`, `FilterConfig`, `FixedComponentsConfig`); JSON-serializable via `to_dict`/`from_dict` | | `ReconstructionSource` / `ImasSource` | Baseline source definitions (g-file + profiles, or IMAS/OMAS JSON) | | `Baseline` / `resolve_baseline()` | The common separated-current product every source resolves to | | `read_ida()` / `read_imas_baseline()` | Standalone readers for IDA `.cdf` and FUSE `dd_sim.json` | | `parallel_to_toroidal()` / `isotropize_fast_pressure()` | Current-convention and fast-pressure physics reductions | +| `read_ida_cer()` / `radial_field_from_cer()` | Impurity CER channels + radial-force-balance E_r | | `filter_coil_currents()` / `filter_boundaries()` / `export_filtered()` | Post-generation selection of the machine-realizable subset | +| `parallel_generate()` / `emit_slurm_script()` / `merge_archives()` | Process-parallel generation (laptop pool / SLURM job-array) | + +### Archive + +| Class / Function | Description | +|------------------|-------------| +| `BouquetArchive` | High-level reader: `ar[scan_key]` → `ScanView` → `DrawView` (profiles, flags, parsed equilibria, extraction) | +| `write_provenance()` / `load_config()` | Stamp / recover the exact `BouquetConfig` stored in an archive | +| `initialize_equilibrium_database()` | Create/open an archive (stamps `schema_version`) | +| `store_equilibrium()` / `load_equilibrium()` | Write / read one draw | +| `store_baseline_profiles()` / `load_baseline_profiles()` | Write / read the per-scan baseline | +| `discover_scan_keys()` / `count_equilibria()` / `list_equilibrium_indices()` | Archive introspection | +| `select_indices()` / `read_filter_flags()` | Filter-flag queries | ### Core Workflow (functional API) @@ -711,6 +858,7 @@ in [`architecture.md`](architecture.md). Key topics include: | Function | Description | |----------|-------------| | `new_uncertainty_profiles()` | Build 1-D uncertainty envelopes (power-law or flat+tail) | +| `synthetic_ida_sigma()` | IDA-shaped fractional sigma envelopes for synthetic studies | ### IO @@ -721,29 +869,26 @@ in [`architecture.md`](architecture.md). Key topics include: | `bouquet.io.write_geqdsk()` | Write a raw g-file dict to disk (import from `bouquet.io`) | | `PFile` | P-file reader/writer with rotation computation | | `read_pfile()` | Parse a p-file (returns PFile object) | +| `IDAProfiles` / `IDACERProfiles` | IDA kinetic-fit and impurity-CER bundles | -### Database +### Environment | Function | Description | |----------|-------------| -| `initialize_equilibrium_database()` | Create/open HDF5 database | -| `store_equilibrium()` | Write one perturbed equilibrium to HDF5 | -| `load_equilibrium()` | Retrieve one equilibrium from HDF5 | -| `store_baseline_profiles()` | Store baseline profiles and uncertainties | -| `load_baseline_profiles()` | Load baseline profiles from HDF5 | -| `discover_scan_values()` | List all scan values in a database | -| `count_equilibria()` | Count equilibria for a given scan value | +| `add_oft_to_path()` | Make OpenFUSIONToolkit importable (`OFT_PYTHONPATH` → candidates → walk-up) | +| `find_mesh()` | Locate the TokaMaker mesh (`BOUQUET_MESH` → walk-up → bundled example) | ### Plotting | Function | Description | |----------|-------------| -| `plot_bouquet()` | Notebook-friendly overview plot | +| `plot_bouquet()` | Notebook-friendly overview plot (dispatches on stored source kind) | | `plot_traces()` | l_i, Ip, and boundary deviation traces across equilibria | | `plot_geqdsk_bouquet()` | GEQDSK multi-panel (9 panels: pressure, current, q, geometry, …) | | `plot_pfile_bouquet()` | P-file multi-panel (densities, temperatures, rotations) | | `plot_coil_currents()` | Coil current bar chart | | `plot_tokamaker_comparison()` | TokaMaker reconstruction comparison | +| `plot_input_vs_recon()` | Baseline-vs-reconstruction gate figure | --- diff --git a/docs/CHANGES_SUMMARY.md b/docs/CHANGES_SUMMARY.md index aa8814f..a14f920 100644 --- a/docs/CHANGES_SUMMARY.md +++ b/docs/CHANGES_SUMMARY.md @@ -1,3 +1,52 @@ +# Bouquet — change summaries + +## Class API + HDF5 schema v2 round (2026-07, PR #8) + +Decisions and outcomes folded from the (deleted) working document +`docs/ux-review-feat-bouquet-class-api.md`: + +1. **Config serialization + provenance**: `BouquetConfig.to_dict/from_dict` + (JSON); every archive stores `schema_version` / `bouquet_version` / + `created` (stamped at file creation) + per-scan `config_json` + (`write_provenance` / `load_config`). +2. **`BouquetArchive`** reader class (ScanView/DrawView, lazy, cached attrs, + fixed-name + legacy suffix-scan eqdsk/pfile lookup) — replaces downstream + hand-rolled h5 traversal. +3. **De-threaded readers**: module-level plot/filter/select functions accept a + `Bouquet` / `BouquetArchive` / header / path uniformly; a missing explicit + `scan_key` raises listing available keys (was silent-empty). +4. **Schema v2 — clean break, no legacy readers** (decision: no external users + yet): bare dataset names + `units` attrs, fixed `eqdsk`/`pfile` names, + coil names as a string dataset everywhere, `scan//` layout only. + Legacy files: `BouquetArchive` warns, `load_equilibrium` raises clearly. + Spec: `docs/archive-schema.md`; source of truth: `bouquet/schema.py`. +5. **Config/API simplifications**: `run.describe()` (non-default knobs), + `workflow` preset enum (`auto` / `geqdsk-standard` / `imas-diff-c` / + `custom`), source-agnostic `run.prepare()`. +6. **Sweeps + plotting**: `run.run_slices()` (one archive, one scan_key per + slice); `plot_bouquet` dispatches on stored `source_kind` + (`plot_imas_bouquet` demoted from `__all__`). +7. **Parallel hardening**: fresh shards, merge-side baseline guard + + expected-shard accounting (`--allow-missing`), nthreads=1 doctrine warning, + `SeedSequence(seed, worker, scan_key)` slice-decorrelated seeding, JSON + SLURM bundles, CWD-independent submit scripts, physical-core default. +8. **Post-review fixes** (8-angle adversarial review of the final diff): + solver-marked tests un-broken (coil_names dataset read), merged archives + get run-level `config_json`, multi-scan `load_config` disambiguation, + `DrawView` O(N) flags + cached attrs, `schema.find_bytes_dataset` + consolidation (8 duplicated lookups), unique eqdsk extraction filenames, + legacy-archive warnings/errors. +9. **Won't-do (user decisions)**: `jphi_scalar_sigma` default stays 0.10; + IDA_run per-shot notebooks stay split (no templating). +10. **Deferred**: example-notebook rewrite to run-object idioms; + reconstruction-style IMAS baseline summary block. + +Also in this round: scipy≥1.18/numpy≥2.5 compatibility (`.item()` at the +axis-point `.ev()` call), and the CER/E_r feature (`read_ida_cer`, +`radial_field_from_cer`). + +--- + # Bouquet + OFT — change summary (golden suite, filtering, Ip-secant removal, systematics) > **Historical document** (2026-05): a snapshot of the coil-bounds/golden-suite diff --git a/docs/CI.md b/docs/CI.md index 9b7c0c5..04545b9 100644 --- a/docs/CI.md +++ b/docs/CI.md @@ -18,7 +18,12 @@ PR-controlled code on lab infrastructure. So until OFT publishes to PyPI we kee the comprehensive suite off automated CI and run it deliberately. ## Workflows -- `.github/workflows/tests.yml` — **fast** suite on `push`/`pull_request` (automated). +- `.github/workflows/tests.yml` — **fast** suite on `push`/`pull_request` + (automated), run on a 2-way dependency matrix: **pinned** (the validated + numpy/scipy floor — bump deliberately) and **latest** (unpinned canary). + An upstream numpy/scipy release then breaks only the `latest` leg, as its + own signal, instead of failing unrelated feature PRs (this bit us when + scipy 1.18 + numpy 2.5 changed scalar-conversion semantics). - `.github/workflows/solver.yml` — **solver** suite, `workflow_dispatch` only (manual "Run workflow" button / `gh workflow run solver.yml`). Not a required check, so it never blocks a merge. It already contains the `runs-on`, env, and @@ -32,8 +37,9 @@ Before merging a branch that touches the perturbation/solve pipeline into `main` 3. The automated `fast` check must also be green. ## Branch protection (`main`) -Require the **`fast`** status check + a review. **Do not** require `solver` -while it's manual — a required check with no runner would block merges forever. +Require the **`fast (pinned)`** status check (+ optionally `fast (latest)` and +a review). **Do not** require `solver` while it's manual — a required check +with no runner would block merges forever. ## Future: automate the solver gate Once the OFT Ip fixes are merged upstream **and** OpenFUSIONToolkit publishes to diff --git a/docs/archive-schema.md b/docs/archive-schema.md new file mode 100644 index 0000000..d13bb1d --- /dev/null +++ b/docs/archive-schema.md @@ -0,0 +1,76 @@ +# The bouquet HDF5 archive — schema v2 + +Authoritative description of the on-disk layout written by bouquet ≥ 0.2.0. +The single source of truth in code is [`bouquet/schema.py`](../bouquet/schema.py) +(`SCHEMA_VERSION`, `PROFILE_UNITS`, fixed dataset names, `write_profile` / +`find_bytes_dataset`); this document mirrors it for human readers. Prefer +reading archives through [`bouquet.BouquetArchive`](../bouquet/archive.py) or +the functional readers (`load_equilibrium`, `load_baseline_profiles`, +`select_indices`, `load_config`) rather than raw `h5py`. + +## Layout + +``` +{header}.h5 file attrs: schema_version (=2), +│ bouquet_version, created, updated +├── config_json JSON dump of the run BouquetConfig +│ (root copy = most recent write; the +│ per-scan copies below are authoritative) +└── scan// one group per scan point / time slice + ├── config_json this slice's exact config + ├── _baseline/ written once per scan point + │ ├── eqdsk, [pfile] raw byte-perfect g-file / p-file + │ ├── psi_N, psi_N_kinetic + │ ├── n_e, T_e, n_i, T_i kinetic profiles + │ ├── pressure[, pressure_thermal] + │ ├── j_phi[, j_BS, j_inductive] separated toroidal currents + │ ├── sigma_ne/te/ni/ti/jphi the uncertainty envelope used + │ ├── [aux_, sigma_aux_] switchboard channels + │ ├── [recon_lcfs_ref] 10k-pt LCFS reference (boundary metric) + │ ├── [x_points], [coil_currents, coil_names] + │ └── attrs: Ip_target, l_i_target, source_kind, [diverted] + └── / one group per accepted draw + │ (integer; gaps = rejected draws) + ├── eqdsk, [pfile] raw bytes, fixed names + ├── psi_N[, psi_N_kinetic] + ├── j_phi, j_BS, j_inductive[, j_BS,edge] + ├── n_e, T_e, n_i, T_i, w_ExB[, Zeff] + ├── [pressure, pressure_thermal] + ├── [aux_] perturbed switchboard channels + ├── [coil_currents, coil_names] + ├── [perturbed_lcfs_ref], [x_points] + └── attrs: l_i(1), l_i(3), count, homotopy_*, max_F_drift_pct, + max_VSC_drift_pct, in_spec, inspec_*, l_i_target_used, + [diverted], [passes_coil_filter, passes_boundary_filter, + selected] ← filter flags, written post-hoc +``` + +## Conventions + +- **Bare dataset names, units in attrs.** Profile datasets carry plain names + (`j_phi`, `n_e`, …) with the unit string in `ds.attrs["units"]` + (`PROFILE_UNITS` in `schema.py`). v1 archives embedded units in the name + (`"j_phi [A m^-2]"`). +- **Fixed byte-blob names.** The g-file / p-file bytes are stored as `eqdsk` / + `pfile` inside each group — the group path carries the coordinates. Bytes + are stored opaque (`np.void`) and round-trip bit-perfect. +- **Always `scan//`.** The scan key is a user-chosen label + (`GenerationConfig.scan_key`, default `0`) — a time in ms, a beta value, … + Several bouquets can share one file under different keys. +- **Gap-tolerant indices.** Rejected draws leave gaps; iterate with + `list_equilibrium_indices` / `BouquetArchive`, never `range(n)`. +- **Filtering is non-destructive.** Filters write boolean attrs + (`passes_*`, `selected` = AND of applied flags); `export_filtered` produces + a pruned copy, the source is never modified. +- **Provenance.** `schema_version` / `bouquet_version` / `created` are stamped + at file creation; `config_json` is added by `write_provenance` (called from + `Bouquet.generate`, `run_shard`, and `merge_archives`). Recover the exact + run configuration with `bq.load_config(path, scan_key=...)`. + +## Legacy (pre-v2) archives + +Schema v2 was a clean break (2026-07). Files without the `schema_version` +attr are pre-v2: `BouquetArchive` opens them with a warning (byte blobs still +resolve via a suffix scan; profile keys keep their v1 bracketed names), and +`load_equilibrium` raises a clear error. Regenerate old archives with the +current package for full support. diff --git a/docs/flowchart/README.md b/docs/flowchart/README.md new file mode 100644 index 0000000..9046480 --- /dev/null +++ b/docs/flowchart/README.md @@ -0,0 +1,40 @@ +# bouquet workflow & logic map + +Two layers, one page (`index.html`, fully self-contained): + +1. **The physics workflow** (`physics_workflow.svg` / `.pdf`) — the + user-facing diagram: only physics quantities and equilibrium/profile + variables, complete across the perturbation, matching, and solve steps. + Embedded in the top-level README; the PDF is paper-figure quality. +2. **The full logic map** (`l1_full.svg` + interactive pan/zoom/search) — + every config knob, decision gate, and stored artifact (550+ nodes), each + with a `file:line` anchor. + +- **View**: (GitHub Pages), or + open `index.html` locally. +- **Regenerate everything**: + + ```bash + python docs/flowchart/build.py # needs graphviz `dot` on PATH + ``` + +## Editing the physics workflow (new diagnostics / data sources) + +The physics diagram is hand-authored DATA in `build.py`: `PHYS_NODES` (one +dict per box: `id`, `cluster`, `kind`, `lines`) and `PHYS_EDGES` (one tuple +per arrow). To add e.g. MSE q-profile constraints: add one node dict to the +`inputs` cluster, one edge tuple, rerun `build.py` — there is a commented +MSE example in place. Labels are graphviz HTML-like markup; use the +`V("n","e")` helper for italic variables with subscripts. + +## Editing the full logic map + +Source of truth is `graph.json` (extracted from the code by a fleet of +agents, adversarially spot-verified, then hand-patched). Edit it (keep +`file:line` anchors honest) and rerun `build.py`. It is a descriptive +snapshot of the commit stamped in the page footer — regenerate (or +re-extract) after significant refactors. + +The map is a descriptive snapshot of the commit stamped in the page footer — +it can drift from the code across refactors; regenerate (or re-extract) when +it does. diff --git a/docs/flowchart/build.py b/docs/flowchart/build.py new file mode 100644 index 0000000..f805759 --- /dev/null +++ b/docs/flowchart/build.py @@ -0,0 +1,592 @@ +#!/usr/bin/env python3 +"""Render the bouquet logic-flow map from graph.json. + +graph.json is the source of truth (extracted from the code with file:line +anchors on every node). This script renders it with graphviz `dot`: + + * l0_overview.svg — one node per pipeline stage (README-embeddable) + * l1_full.svg — the full quantity/decision graph, clustered by stage + * index.html — self-contained zoomable page (inline SVG + vendored + svg-pan-zoom + a node search box) + +Regenerate after editing graph.json: python docs/flowchart/build.py +Requires the `dot` binary (graphviz) on PATH. +""" +import html +import json +import os +import subprocess +from collections import Counter, defaultdict + +HERE = os.path.dirname(os.path.abspath(__file__)) +GRAPH = os.path.join(HERE, "graph.json") + +# stage ordering (roughly upstream -> downstream) and cluster colors +STAGE_ORDER = [ + "Configuration", + "Input readers (g-file / p-file / IDA)", + "IMAS/OMAS reader", + "Baseline & uncertainty resolution", + "GS reconstruction", + "Bouquet orchestrator / IMAS forward solve", + "Draw loop (GPR sampling)", + "Per-draw solve (SWB / l_i / homotopy)", + "Archive, filtering & plotting", + "Process-parallel path", + "Shared quantities", +] +STAGE_FILL = { + "Configuration": "#eef4fb", + "Input readers (g-file / p-file / IDA)": "#f0f7ee", + "IMAS/OMAS reader": "#f0f7ee", + "Baseline & uncertainty resolution": "#fdf6ec", + "GS reconstruction": "#fdf0f0", + "Bouquet orchestrator / IMAS forward solve": "#f3eefb", + "Draw loop (GPR sampling)": "#fff8e7", + "Per-draw solve (SWB / l_i / homotopy)": "#fdf0f0", + "Archive, filtering & plotting": "#eefbf4", + "Process-parallel path": "#f4f4f4", +} +TYPE_STYLE = { # type -> (shape, fillcolor) + "input": ("parallelogram", "#e9edc9"), + "knob": ("note", "#8ecae6"), + "quantity": ("ellipse", "#ffd166"), + "transform": ("box", "#a7c957"), + "decision": ("diamond", "#f28482"), + "artifact": ("cylinder", "#cdb4db"), +} + + +def esc(s): + return str(s or "").replace("\\", "\\\\").replace('"', '\\"') + + +def load(): + with open(GRAPH) as fh: + return json.load(fh) + + +def node_dot(n): + shape, fill = TYPE_STYLE[n["type"]] + anchor = f'{n.get("file", "")}:{n.get("line", "")}' if n.get("file") else "" + tip = " — ".join(x for x in (anchor, n.get("desc", "")) if x) or n["id"] + return (f'"{esc(n["id"])}" [label="{esc(n.get("label") or n["id"])}", ' + f'shape={shape}, style="filled", fillcolor="{fill}", ' + f'tooltip="{esc(tip)}", href="#", fontsize=10];') + + +def render_l1(g): + by_stage = defaultdict(list) + for n in g["nodes"]: + by_stage[n.get("subsystem", "Shared quantities")].append(n) + lines = [ + "digraph bouquet {", + ' graph [rankdir=LR, fontname="Helvetica", fontsize=18, ', + ' ranksep=0.7, nodesep=0.25, concentrate=true, ', + ' tooltip="bouquet logic flow"];', + ' node [fontname="Helvetica"];', + ' edge [fontname="Helvetica", fontsize=8, color="#666666", ' + ' arrowsize=0.6];', + ] + for i, stage in enumerate(STAGE_ORDER): + nodes = by_stage.get(stage, []) + if not nodes: + continue + if stage == "Shared quantities": # unclustered: dot places them + for n in nodes: # near their consumers + lines.append(" " + node_dot(n)) + continue + lines.append(f' subgraph cluster_{i} {{') + lines.append(f' label="{esc(stage)}"; labeljust=l; fontsize=16;') + lines.append(f' style="filled,rounded"; fillcolor="{STAGE_FILL[stage]}";' + f' color="#999999";') + for n in nodes: + lines.append(" " + node_dot(n)) + lines.append(" }") + for e in g["edges"]: + style = ', style=dashed, color="#b56576"' if e.get("kind") == "control" else "" + tip = esc(e.get("desc") or f'{e["src"]} -> {e["dst"]}') + lines.append(f' "{esc(e["src"])}" -> "{esc(e["dst"])}" ' + f'[tooltip="{tip}", edgetooltip="{tip}"{style}];') + lines.append("}") + return "\n".join(lines) + + +def render_l0(g): + """Stage overview: collapse hops through shared quantities into direct + stage->stage edges (stage A writes qty q, stage B reads q => A -> B).""" + SHARED = "Shared quantities" + sub_of = {n["id"]: n.get("subsystem", SHARED) for n in g["nodes"]} + direct = Counter() + derived = Counter() + writers = defaultdict(set) # shared qty id -> stages writing it + readers = defaultdict(set) # shared qty id -> stages reading it + for e in g["edges"]: + a, b = sub_of.get(e["src"]), sub_of.get(e["dst"]) + if not a or not b or a == b: + continue + if a != SHARED and b != SHARED: + direct[(a, b)] += 1 + elif b == SHARED and a != SHARED: + writers[e["dst"]].add(a) + elif a == SHARED and b != SHARED: + readers[e["src"]].add(b) + for q in set(writers) & set(readers): + for wa in writers[q]: + for rb in readers[q]: + if wa != rb: + derived[(wa, rb)] += 1 + # keep every direct stage->stage edge; keep derived (via shared + # quantities) only when substantial, so the overview stays readable + counts = Counter(direct) + for k, c in derived.items(): + if c >= 4 and k not in counts: + counts[k] = c + n_in = Counter(n.get("subsystem") for n in g["nodes"]) + lines = [ + "digraph bouquet_overview {", + ' graph [rankdir=LR, fontname="Helvetica", ranksep=0.55, ' + ' nodesep=0.35, tooltip="bouquet pipeline overview"];', + ' node [fontname="Helvetica", shape=box, style="filled,rounded", ' + ' fontsize=13, margin="0.22,0.12"];', + ' edge [fontname="Helvetica", fontsize=10, color="#666666"];', + ] + for stage in STAGE_ORDER: + if stage == "Shared quantities" or not n_in.get(stage): + continue + fill = STAGE_FILL[stage] + lines.append(f' "{esc(stage)}" [fillcolor="{fill}", ' + f'label="{esc(stage)}\\n({n_in[stage]} nodes)", href="#"];') + # invisible spine pins the canonical pipeline order left-to-right; real + # edges are drawn constraint=false so they overlay without re-ranking + spine = [s for s in STAGE_ORDER if s != "Shared quantities" and n_in.get(s)] + for a, b in zip(spine, spine[1:]): + lines.append(f' "{esc(a)}" -> "{esc(b)}" [style=invis, weight=100];') + order = {s: i for i, s in enumerate(spine)} + for (a, b), c in sorted(counts.items(), key=lambda kv: -kv[1]): + back = order.get(a, 0) >= order.get(b, 0) # against the pipeline + extra = ', constraint=false, color="#b56576"' if back else "" + lines.append(f' "{esc(a)}" -> "{esc(b)}" [label="{c}"{extra}, ' + f'penwidth={min(1 + c / 8, 5):.1f}];') + lines.append("}") + return "\n".join(lines) + + +# =========================================================================== +# The physics workflow (the new-user view) +# +# Hand-authored (NOT extracted from code): only physics quantities and +# equilibrium/profile variables, but complete across the perturbation, +# matching, and solve steps. Style follows the bouquet paper's workflow +# figure (required/optional inputs, iterate loops, repeat x N_ens bracket). +# +# TO EXTEND (new diagnostic, data source, constraint): add one dict to +# PHYS_NODES and its arrows to PHYS_EDGES — the renderer does the rest. +# Labels are graphviz HTML-like markup; use V("n","e") for italic +# variables with subscripts and SUP() for superscripts. +# =========================================================================== + +def V(base, sub=None): + """Italic math variable with optional subscript: V('n','e') -> n_e.""" + s = f"{base}" + return f"{s}{sub}" if sub else s + + +def SUP(base, sup): + return f"{base}{sup}" + + +# node kinds -> graphviz style +_PHYS_KIND = { + "required": 'style="filled,rounded", fillcolor="#dbeefc", color="#4da3dd", penwidth=1.6', + "optional": 'style="filled,rounded,dashed", fillcolor="#f2f2f2", color="#888888"', + "baseline": 'style="filled,rounded", fillcolor="#e8f4fd", color="#2779b0", penwidth=1.6', + "derived": 'style="filled,rounded", fillcolor="#eef7ea", color="#4c8c3f", penwidth=1.6', + "sample": 'style="filled,rounded", fillcolor="#cfe6f5", color="#1f6699", penwidth=1.6', + "compute": 'style="filled,rounded", fillcolor="#fdf3d8", color="#c99b2f", penwidth=1.6', + "solve": 'style="filled,rounded", fillcolor="#fbe8d9", color="#c06722", penwidth=1.6', + "tag": 'style="filled,rounded", fillcolor="#efe9f7", color="#7a5ba8", penwidth=1.6', + "output": 'style="filled,rounded", fillcolor="#fbe4f0", color="#b3487f", penwidth=1.6', + "gate": 'shape=diamond, style="filled", fillcolor="#fbe3e0", color="#c9524a"', +} + +# clusters: id -> (title, graphviz cluster style) +_PHYS_CLUSTERS = { + "inputs": ("Inputs (solid blue = required for its path, dashed = optional)", + 'style="rounded"; color="#bbbbbb";'), + "baseline": ("Baseline (once per slice)", + 'style="filled,rounded"; fillcolor="#f6fbf4"; color="#999999";'), + "loop": (f'repeat × {V("N", "ens")} (each draw independent)', + 'style="rounded,dashed"; color="#777777";'), +} + +PHYS_NODES = [ + # ---- inputs ---------------------------------------------------------- + dict(id="gfile", cluster="inputs", kind="required", lines=[ + "geqdsk", + f'{V("ψ")}(R,Z), {V("p")}, {V("q")}, {V("j","φ")}, separatrix']), + dict(id="kin", cluster="inputs", kind="required", lines=[ + f'kinetic profiles + σ({V("ψ","N")}) envelopes', + f'{V("n","e")}, {V("T","e")}, {V("T","i")} (, {V("n","i")}, {V("ω","tor")})', + "p-file or kinetic-fit netCDF"]), + dict(id="ids", cluster="inputs", kind="required", lines=[ + "IMAS/OMAS IDS", + f'{V("n","e")}, {V("T","e")}, {V("T","i")}, {V("Z","eff")}; ' + f'{V("j","ohmic")}, {V("j","BS")}, {V("j","NBI")};', + f'{V("p","fast")}; equilibrium anchors']), + dict(id="lcfs", cluster="inputs", kind="optional", lines=[ + "magnetics-only LCFS", + "(separatrix target override)"]), + dict(id="fixed", cluster="inputs", kind="optional", lines=[ + "fixed arrays", + f'{V("j","NBI")}, {V("j","RF")}, {V("p","fast")}({V("ψ","N")})']), + dict(id="sigmas", cluster="inputs", kind="optional", lines=[ + "explicit σ profiles", + "or diagnostic σ source"]), + # future example (uncomment + add edges when MSE constraints land): + # dict(id="mse", cluster="inputs", kind="optional", lines=[ + # "MSE", f'{V("q")}-profile constraints']), + + # ---- baseline -------------------------------------------------------- + dict(id="recon", cluster="baseline", kind="baseline", lines=[ + "GS reconstruction (geqdsk path)", + f'fit inductive spline, full-Sauter {V("j","BS")}', + f'{V("j","φ")} = {V("j","ind")} + {V("j","BS")} ; ' + f'match {V("ℓ","i")}(1) by secant', + f'targets: {V("I","p")}, {V("ℓ","i")}']), + dict(id="fsolve", cluster="baseline", kind="baseline", lines=[ + "forward solve (IMAS/OMAS path)", + f'keep IDS {V("j","ohmic")}; Sauter {V("j","BS")} reconciliation', + f'(diff: {V("j","BS,diff")} = {SUP(V("j","BS"), "IDS")} − ' + f'{SUP(V("j","BS"), "Sauter")} | rescale)', + f'anchors: {V("p","diff")}, {V("j","φ,diff")} ; ' + f'{V("ℓ","i")} target = solved {V("ℓ","i")}(1)']), + dict(id="quasi", cluster="baseline", kind="derived", lines=[ + "quasineutral densities", + f'{V("n","i")} = {V("n","e")} ({V("Z","imp")} − {V("Z","eff")}) / ' + f'({V("Z","imp")} − 1)']), + dict(id="envel", cluster="baseline", kind="derived", lines=[ + "uncertainty envelope", + f'{V("σ","n")}, {V("σ","T")}, {V("σ","Zeff")}, {V("σ","jφ")} + ' + f'GP length scales {V("ℓ","n")}, {V("ℓ","T")}, {V("ℓ","j")}']), + + # ---- per-draw loop --------------------------------------------------- + dict(id="gp", cluster="loop", kind="sample", lines=[ + "GP profile sampling (Gibbs kernel)", + f'draw {V("n","e")}, {V("T","e")}, {V("T","i")}, {V("Z","eff")}, ' + f'{V("j","ind")} ~ GP(baseline, σ, ℓ)', + f'within envelopes; SOL included via {V("ψ","N,kin")} grid']), + dict(id="derive", cluster="loop", kind="compute", lines=[ + "recompute derived", + f'{V("n","i")} from drawn {V("Z","eff")} (quasineutrality)', + f'{V("p","tot")} = Σa {V("e")} {V("n","a")} {V("T","a")} + ' + f'{V("p","imp")} + {V("p","fast")} (+ {V("p","diff")})']), + dict(id="pgate", cluster="loop", kind="gate", lines=[ + f'⟨{V("P")}⟩ within 5%', "of baseline?"]), + dict(id="boot", cluster="loop", kind="compute", lines=[ + "bootstrap recompute (Sauter)", + f'{V("j","BS")} = f({V("n")}, {V("T")}, {V("Z","eff")}) ' + "(3 self-consistent iterations)", + f'parallel→toroidal: {V("c")} = 1 / (⟨{V("R")}⟩⟨1/{V("R")}⟩)', + f'scale {V("s")} ~ U(0.99, 1.01) · {V("s","0")}']), + dict(id="rebuild", cluster="loop", kind="compute", lines=[ + "rebuild total current", + f'{V("j","φ")} = {V("j","ind")} + {V("s")}·{V("j","BS")} ' + f'(+ {V("j","BS,diff")}) + {V("j","NBI")} + {V("j","RF")} ' + f'(+ {V("j","φ,diff")})']), + dict(id="limatch", cluster="loop", kind="solve", lines=[ + f'{V("ℓ","i")} matching', + f'(optionally sample target ~ N({V("ℓ","i")}, {V("σ","ℓi")}))', + f'scale {V("j","ind")} + corrective iteration', + f'until |{V("ℓ","i")} − target| ≤ 5%']), + dict(id="gssolve", cluster="loop", kind="solve", lines=[ + "TokaMaker free-boundary GS solve", + f'isoflux separatrix + {V("I","p")} target', + "coil homotopy: bounds ±5% → ±2% → ±1% (warm-started)", + "VSC pair handles vertical control"]), + dict(id="agate", cluster="loop", kind="gate", lines=[ + "accepted?", + f'converged, {V("ℓ","i")} in band,', + f'{V("q","0")} ≥ 1 (optional)']), + dict(id="inspec", cluster="loop", kind="tag", lines=[ + "in-spec tag", + "coil drift ≤ 2%; VSC via quadrature-propagated σ"]), + + # ---- outputs --------------------------------------------------------- + dict(id="archive", cluster=None, kind="output", lines=[ + "HDF5 ensemble archive (schema v2)", + f'profiles, {V("j")} components, g-/p-file bytes,', + "coil currents, targets, provenance (config)"]), + dict(id="filter", cluster=None, kind="output", lines=[ + "post-filtering (non-destructive)", + "boundary RMS ≤ 5 mm; coil spec", + "⇒ selected (machine-realizable) sub-ensemble"]), +] + +# (src, dst, kind, label) — kinds: main | optional | yes | loop | reject +PHYS_EDGES = [ + ("gfile", "recon", "main", None), ("kin", "recon", "main", None), + ("ids", "fsolve", "main", None), ("lcfs", "fsolve", "optional", None), + ("kin", "envel", "main", None), ("sigmas", "envel", "optional", None), + ("fixed", "rebuild", "optional", None), + ("recon", "quasi", "main", None), ("fsolve", "quasi", "main", None), + ("quasi", "envel", "main", None), ("envel", "gp", "main", None), + ("gp", "derive", "main", None), ("derive", "pgate", "main", None), + ("pgate", "boot", "yes", "yes"), + ("pgate", "gp", "reject", "resample"), + ("boot", "rebuild", "main", None), ("rebuild", "limatch", "main", None), + ("limatch", "gssolve", "main", None), + ("limatch", "limatch", "loop", " iterate"), + ("gssolve", "gssolve", "loop", " homotopy\n passes"), + ("gssolve", "agate", "main", None), + ("agate", "inspec", "yes", "yes"), + ("agate", "gp", "reject", "reject draw"), + ("inspec", "archive", "main", None), ("archive", "filter", "main", None), +] + +_PHYS_EDGE_STYLE = { + "main": "", + "yes": "", + "optional": ', style=dashed, color="#888888"', + "loop": ', color="#c06722", fontcolor="#c06722"', + "reject": (', style=dashed, color="#c9524a", fontcolor="#c9524a", ' + "constraint=false"), +} + + +def render_physics(): + """Render PHYS_NODES/PHYS_EDGES to DOT (HTML-like labels: italics + subs).""" + lines = [ + "digraph bouquet_physics {", + ' graph [rankdir=TB, fontname="Helvetica", fontsize=16, ' + ' ranksep=0.45, nodesep=0.35, ' + ' tooltip="bouquet physics workflow"];', + ' node [fontname="Helvetica", fontsize=12, shape=box, ' + ' margin="0.18,0.10"];', + ' edge [fontname="Helvetica", fontsize=10, color="#333333", ' + ' arrowsize=0.8];', + ] + by_cluster = defaultdict(list) + for n in PHYS_NODES: + by_cluster[n.get("cluster")].append(n) + + def node_line(n): + label = "<" + "
".join(n["lines"]) + ">" + return f' {n["id"]} [label={label}, {_PHYS_KIND[n["kind"]]}];' + + for i, (cid, (title, style)) in enumerate(_PHYS_CLUSTERS.items()): + lines.append(f" subgraph cluster_p{i} {{") + lines.append(f" label=<{title}>; labeljust=l; fontsize=15; {style}") + for n in by_cluster.get(cid, []): + lines.append(node_line(n)) + lines.append(" }") + for n in by_cluster.get(None, []): + lines.append(node_line(n)[2:]) + + for src, dst, kind, lbl in PHYS_EDGES: + attrs = _PHYS_EDGE_STYLE[kind] + if lbl: + attrs = f'label="{esc(lbl)}"' + (", " + attrs.lstrip(", ") if attrs else "") + lines.append(f" {src} -> {dst} [{attrs.strip(', ')}];") + lines.append("}") + return "\n".join(lines) + + +def _fix_baseline_shift(svg): + """Make graphviz sub/superscripts portable across browsers. + + dot emits `baseline-shift="sub|super"` on absolutely-positioned + elements at FULL font size; browser support for baseline-shift on + is inconsistent, so subscripts collide with the next line. Bake the + shift into the y coordinate and use a proper 70% glyph size instead + (cairo-rendered PNG/PDF outputs are unaffected — they handle it fine). + """ + import re + + def fix(m): + tag = m.group(0) + kind = m.group("kind") + fs = float(re.search(r'font-size="([\d.]+)"', tag).group(1)) + y = float(re.search(r'y="(-?[\d.]+)"', tag).group(1)) + dy = 0.25 * fs if kind == "sub" else -0.35 * fs + tag = re.sub(r'\s*baseline-shift="(sub|super)"', "", tag) + tag = re.sub(r'font-size="[\d.]+"', f'font-size="{fs * 0.7:.2f}"', tag) + tag = re.sub(r'y="(-?[\d.]+)"', f'y="{y + dy:.2f}"', tag) + return tag + + return re.sub(r']*baseline-shift="(?Psub|super)"[^>]*>', + fix, svg) + + +def dot_to_svg(dot_src, out_name): + out = os.path.join(HERE, out_name) + res = subprocess.run(["dot", "-Tsvg", "-o", out], input=dot_src.encode(), + capture_output=True) + if res.returncode != 0: + raise RuntimeError(f"dot failed for {out_name}:\n" + + res.stderr.decode()[:2000]) + with open(out) as fh: + svg = fh.read() + fixed = _fix_baseline_shift(svg) + if fixed != svg: + with open(out, "w") as fh: + fh.write(fixed) + return out + + +def build_html(g, phys_svg, l0_svg, l1_svg, stamp): + with open(os.path.join(HERE, "svg-pan-zoom.min.js")) as fh: + panzoom_js = fh.read() + + def inline(path, svg_id): + import re + with open(path) as fh: + svg = fh.read() + svg = svg[svg.index(" zeroed viewport matrix) + head, rest = svg.split(">", 1) + head = re.sub(r'\s(width|height)="[^"]*"', "", head) + return f'{head} id="{svg_id}">{rest}' + + counts = Counter(n["type"] for n in g["nodes"]) + legend = " ".join( + f'{t} ({counts.get(t, 0)})' + for t, (_s, fill) in TYPE_STYLE.items()) + page = f""" + + + + +bouquet — logic flow map + + + +
+

bouquet — workflow & logic map

+
Start with the physics workflow (what happens to the + profiles and equilibrium quantities); open the full logic map below to + see every config knob, decision gate, and artifact, each anchored to + file:line (hover). Scroll to zoom, drag to pan the full map. + {stamp}
+
+
+ The physics workflow — GP perturbation → derived quantities → + bootstrap → ℓ_i matching → GS solve → archive +
+ {inline(phys_svg, "svgp")} +
+
+
+ Stage overview of the code ({len(g["nodes"])} nodes, {len(g["edges"])} + edges in the full map below) + {inline(l0_svg, "svg0")} +
+
+ + + {legend} + dashed edge = control flow +
+
+ {inline(l1_svg, "svg1")} +
+
Generated by docs/flowchart/build.py from +docs/flowchart/graph.json. Edges/nodes are a descriptive snapshot +and may drift from the code; regenerate after refactors.
+ + + + +""" + with open(os.path.join(HERE, "index.html"), "w") as fh: + fh.write(page) + + +def main(): + g = load() + try: + commit = subprocess.run(["git", "rev-parse", "--short", "HEAD"], + capture_output=True, text=True, + cwd=HERE).stdout.strip() + except Exception: + commit = "unknown" + stamp = f"Snapshot of commit {commit or 'unknown'}." + phys = dot_to_svg(render_physics(), "physics_workflow.svg") + # PDF export of the physics diagram (paper-figure candidate) + subprocess.run(["dot", "-Tpdf", "-o", + os.path.join(HERE, "physics_workflow.pdf")], + input=render_physics().encode(), check=True) + l0 = dot_to_svg(render_l0(g), "l0_overview.svg") + l1 = dot_to_svg(render_l1(g), "l1_full.svg") + build_html(g, phys, l0, l1, stamp) + print(f"rendered physics workflow + {len(g['nodes'])} nodes /" + f" {len(g['edges'])} edges -> physics_workflow.svg/.pdf," + f" l0_overview.svg, l1_full.svg, index.html") + + +if __name__ == "__main__": + main() diff --git a/docs/flowchart/graph.json b/docs/flowchart/graph.json new file mode 100644 index 0000000..a381226 --- /dev/null +++ b/docs/flowchart/graph.json @@ -0,0 +1,10270 @@ +{ + "nodes": [ + { + "id": "art.eqdsk_bytes", + "type": "artifact", + "label": "EQDSK file (per-draw)", + "desc": "Written by caller (generate_bouquet); contains Ip, q, geometry, coils", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "art.h5.aux", + "type": "artifact", + "label": "aux_* profiles", + "file": "bouquet/utils.py", + "line": 512, + "desc": "aux_ datasets from switchboard; on psi_N_kinetic grid", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.baseline", + "type": "artifact", + "label": "baseline group (_baseline)", + "file": "bouquet/utils.py", + "line": 759, + "desc": "scan//_baseline or /_baseline: baseline profiles + sigmas", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.coil_currents", + "type": "artifact", + "label": "coil_currents + coil_names", + "file": "bouquet/schema.py", + "line": 50, + "desc": "Values array + string dataset; schema-v2 fixed names", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.config_json", + "type": "artifact", + "label": "config_json dataset", + "file": "bouquet/utils.py", + "line": 319, + "desc": "BouquetConfig serialized at root + per-scan levels", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.eqdsk", + "type": "artifact", + "label": "eqdsk dataset", + "file": "bouquet/schema.py", + "line": 48, + "desc": "Stored as raw bytes under fixed name 'eqdsk' per draw+baseline", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.filter_flags", + "type": "artifact", + "label": "filter flags (group attrs)", + "file": "bouquet/filtering.py", + "line": 49, + "desc": "passes_coil_filter, passes_boundary_filter, selected + drift metrics", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.perturbed_lcfs_ref", + "type": "artifact", + "label": "perturbed_lcfs_ref", + "file": "bouquet/utils.py", + "line": 577, + "desc": "High-res LCFS boundary (~10k pts) from perturb draw via trace_surf", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.pfile", + "type": "artifact", + "label": "pfile dataset", + "file": "bouquet/schema.py", + "line": 49, + "desc": "Optional: stored as raw bytes under fixed name 'pfile' per draw+baseline", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.profiles", + "type": "artifact", + "label": "profiles (psi_N, j_phi, j_BS, ...)", + "file": "bouquet/utils.py", + "line": 366, + "desc": "1-D arrays: bare names + units attrs (schema v2); _PROFILE_KEYS list", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5.x_points", + "type": "artifact", + "label": "x_points", + "file": "bouquet/utils.py", + "line": 590, + "desc": "X-point nulls (N, 2) shape; TokaMaker.get_xpoints() per draw+baseline", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "art.h5_archive", + "type": "artifact", + "label": "HDF5 archive {header}.h5", + "file": "bouquet/run.py", + "line": 857, + "desc": "Output archive: per-draw quantities + baseline + metadata. Written by generate(). Filtered by filter(), subset exported by export().", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "art.perturbed_lcfs_ref", + "type": "artifact", + "label": "LCFS trace (perturbed)", + "desc": "Updated per draw; used for boundary RMS diagnostics", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "art.sbatch_scripts", + "type": "artifact", + "label": "{job_name}_array.sbatch, {job_name}_merge.sbatch, {job_name}_submit.sh", + "file": "bouquet/parallel.py", + "line": "546", + "desc": "SLURM scripts: array[0-n_workers-1] runs shard cmd, merge runs with afterany dependency; submit.sh chains them", + "subsystem": "Process-parallel path" + }, + { + "id": "art.shard_h5", + "type": "artifact", + "label": "{out_header}_w{worker_id}.h5", + "file": "bouquet/parallel.py", + "line": "169", + "desc": "Per-worker archive: fresh file (pre-existing removed), holds draw groups + _baseline metadata (l_i_target, Ip_target attrs)", + "subsystem": "Process-parallel path" + }, + { + "id": "art.slurm_bundle", + "type": "artifact", + "label": "{job_name}_bundle.json", + "file": "bouquet/parallel.py", + "line": "504", + "desc": "JSON serialization: config.to_dict(), n_workers, seed, threads_per_worker, n_equils_total, scan_key, out_header", + "subsystem": "Process-parallel path" + }, + { + "id": "art.x_points", + "type": "artifact", + "label": "X-point locations", + "desc": "From eq_stats; diagnostic", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "artifact.baseline", + "type": "artifact", + "label": "Baseline (output)", + "file": "bouquet/io/imas.py", + "line": 417, + "desc": "Fully-separated Baseline object: psi_N, j_phi, j_inductive, j_BS, kinetics, targets, anchors", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "artifact.geometry", + "type": "artifact", + "label": "Geometry tuple (output)", + "file": "bouquet/io/imas.py", + "line": 130, + "desc": "(F0, boundary_RZ) returned by read_imas_geometry()", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "artifact.imas_draw_json", + "type": "artifact", + "label": "Perturbed draw JSON", + "file": "bouquet/io/imas.py", + "line": 607, + "desc": "write_imas_draw(): equilibrium+core_profiles IDS from h5 eqdsk + kinetics", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.FixedComponentsConfig.j_NBI", + "type": "knob", + "label": "FixedComponentsConfig.j_NBI", + "file": "bouquet/config.py", + "line": 169, + "desc": "Beam-driven current array (optional, fixed per draw)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.FixedComponentsConfig.j_RF", + "type": "knob", + "label": "FixedComponentsConfig.j_RF", + "file": "bouquet/config.py", + "line": 170, + "desc": "RF-driven current array (optional, fixed per draw)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.FixedComponentsConfig.p_fast", + "type": "knob", + "label": "FixedComponentsConfig.p_fast", + "file": "bouquet/config.py", + "line": 168, + "desc": "Fast-ion pressure array (optional, fixed per draw)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.FixedComponentsConfig.psi_N", + "type": "knob", + "label": "FixedComponentsConfig.psi_N", + "file": "bouquet/config.py", + "line": 171, + "desc": "Grid for fixed components; triggers resampling via _resolve_fixed", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.GenerationConfig.recalculate_j_BS", + "type": "knob", + "label": "GenerationConfig.recalculate_j_BS", + "file": "bouquet/config.py", + "line": 276, + "desc": "When True, recompute j_BS per draw via TokaMaker (default True)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.ReconstructionSource.impurity_Z", + "type": "knob", + "label": "ReconstructionSource.impurity_Z", + "file": "bouquet/config.py", + "line": 95, + "desc": "Effective impurity charge (carbon=6.0 default, set per machine)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.aux_baselines", + "type": "knob", + "label": "UncertaintyConfig.aux_baselines", + "file": "bouquet/config.py", + "line": 254, + "desc": "Dict {name: baseline(psi_N)}; manual override over source-provided", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.aux_length_scales", + "type": "knob", + "label": "UncertaintyConfig.aux_length_scales", + "file": "bouquet/config.py", + "line": 255, + "desc": "Dict {name: GPR_length_scale}; per-channel override over default 0.4", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.aux_sigmas", + "type": "knob", + "label": "UncertaintyConfig.aux_sigmas", + "file": "bouquet/config.py", + "line": 253, + "desc": "Dict {name: sigma(psi_N)}; enabling auxiliary channel requires a sigma", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.ida_path", + "type": "knob", + "label": "UncertaintyConfig.ida_path", + "file": "bouquet/config.py", + "line": 209, + "desc": "Explicit IDA path; fallback from ReconstructionSource.profiles_path if .cdf", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.jphi_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.jphi_scalar_sigma", + "file": "bouquet/config.py", + "line": 225, + "desc": "Fractional envelope on |j_phi| (default 0.10)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.ne_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.ne_scalar_sigma", + "file": "bouquet/config.py", + "line": 216, + "desc": "Flat fractional envelope on ne (default 0.05)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.ni_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.ni_scalar_sigma", + "file": "bouquet/config.py", + "line": 218, + "desc": "Flat fractional envelope on ni (default 0.10, wider)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.sigma_ni_from_ne", + "type": "knob", + "label": "UncertaintyConfig.sigma_ni_from_ne", + "file": "bouquet/config.py", + "line": 212, + "desc": "IDA path only: when True, sigma_ni = sigma_ne (default True)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.sigma_profiles", + "type": "knob", + "label": "UncertaintyConfig.sigma_profiles", + "file": "bouquet/config.py", + "line": 222, + "desc": "Dict {ne/te/ni/ti: sigma_array}; explicit profiles override IDA/scalar", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.te_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.te_scalar_sigma", + "file": "bouquet/config.py", + "line": 217, + "desc": "Flat fractional envelope on te (default 0.05)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.ti_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.ti_scalar_sigma", + "file": "bouquet/config.py", + "line": 219, + "desc": "Flat fractional envelope on ti (default 0.10, wider)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.UncertaintyConfig.zeff_scalar_sigma", + "type": "knob", + "label": "UncertaintyConfig.zeff_scalar_sigma", + "file": "bouquet/config.py", + "line": 236, + "desc": "Fractional envelope on Zeff that enables zeff channel by default (default 0.05)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "cfg.accept_anchor_inband", + "type": "knob", + "label": "accept_anchor_inband (Fix-B path)", + "desc": "If True, accept recon-anchor when l_i already in-band", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.coil_drift", + "type": "knob", + "label": "coil_drift", + "file": "bouquet/TokaMaker_interface.py", + "line": 2290, + "desc": "Symmetric \u00b1coil_drift*|I_baseline| hard bounds on coils; None disables", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.constrain_sawteeth", + "type": "knob", + "label": "constrain_sawteeth", + "file": "bouquet/TokaMaker_interface.py", + "line": 2265, + "desc": "Reject equilibria with q0 < 1; auto-override if baseline has q0 < 1", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.filterconfig.inspec_F_max", + "type": "knob", + "label": "inspec_F_max: float = 0.02", + "file": "bouquet/config.py", + "line": 383, + "desc": "+/-2% DIII-D coil-current spec", + "subsystem": "Configuration" + }, + { + "id": "cfg.filterconfig.inspec_VSC_max", + "type": "knob", + "label": "inspec_VSC_max: float = 0.02", + "file": "bouquet/config.py", + "line": 384, + "desc": "VSC coil-current spec", + "subsystem": "Configuration" + }, + { + "id": "cfg.filterconfig.rms_max_mm", + "type": "knob", + "label": "rms_max_mm: float = 5.0", + "file": "bouquet/config.py", + "line": 382, + "desc": "Max RMS coil-position error [mm]", + "subsystem": "Configuration" + }, + { + "id": "cfg.filtering.F_max_pct", + "type": "knob", + "label": "F_max_pct", + "file": "bouquet/filtering.py", + "line": 260, + "desc": "Coil-spec threshold for max F-coil drift (percent)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "cfg.filtering.VSC_max_pct", + "type": "knob", + "label": "VSC_max_pct", + "file": "bouquet/filtering.py", + "line": 260, + "desc": "Coil-spec threshold for max VSC drift (percent)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "cfg.filtering.max_max_mm", + "type": "knob", + "label": "max_max_mm", + "file": "bouquet/filtering.py", + "line": 324, + "desc": "Boundary-filter max threshold (millimetres)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "cfg.filtering.rms_max_mm", + "type": "knob", + "label": "rms_max_mm", + "file": "bouquet/filtering.py", + "line": 324, + "desc": "Boundary-filter RMS threshold (millimetres)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "cfg.fixed.j_NBI", + "type": "knob", + "label": "user override: j_NBI", + "file": "bouquet/io/imas.py", + "line": 366, + "desc": "FixedComponentsConfig.j_NBI override array on user psi_N grid", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.fixed.j_RF", + "type": "knob", + "label": "user override: j_RF", + "file": "bouquet/io/imas.py", + "line": 368, + "desc": "FixedComponentsConfig.j_RF override array on user psi_N grid", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.fixed.p_fast", + "type": "knob", + "label": "user override: p_fast", + "file": "bouquet/io/imas.py", + "line": 364, + "desc": "FixedComponentsConfig.p_fast override array on user psi_N grid", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.fixedcomponentsconfig.j_NBI", + "type": "knob", + "label": "j_NBI: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 169, + "desc": "Beam-driven toroidal current density [A/m^2]", + "subsystem": "Configuration" + }, + { + "id": "cfg.fixedcomponentsconfig.j_RF", + "type": "knob", + "label": "j_RF: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 170, + "desc": "RF-driven toroidal current density [A/m^2]", + "subsystem": "Configuration" + }, + { + "id": "cfg.fixedcomponentsconfig.p_fast", + "type": "knob", + "label": "p_fast: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 168, + "desc": "Fast/beam pressure on psi_N", + "subsystem": "Configuration" + }, + { + "id": "cfg.fixedcomponentsconfig.p_fast_reduction", + "type": "knob", + "label": "p_fast_reduction: str = \"trace\"", + "file": "bouquet/config.py", + "line": 179, + "desc": "Collapse anisotropic fast pressure: trace/mean/perp", + "subsystem": "Configuration" + }, + { + "id": "cfg.fixedcomponentsconfig.psi_N", + "type": "knob", + "label": "psi_N: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 171, + "desc": "Grid for p_fast/j_NBI/j_RF arrays", + "subsystem": "Configuration" + }, + { + "id": "cfg.floor_j_BS", + "type": "knob", + "label": "floor_j_BS (negative bootstrap clipping)", + "desc": "If True, clip spike_profile to [0, \u221e)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.generation.allow_incomplete_pressure", + "type": "knob", + "label": "allow incomplete pressure validation", + "file": "bouquet/io/imas.py", + "line": 247, + "desc": "False (default, raise on thermal/fast gap >2% or missing channel)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.generation.anchor_jtor_to_equilibrium", + "type": "knob", + "label": "j_tor anchor to equilibrium", + "file": "bouquet/io/imas.py", + "line": 248, + "desc": "True (default): jphi_diff = equilibrium.j_tor - core_profiles.j_tor", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.generation.anchor_pressure_to_equilibrium", + "type": "knob", + "label": "pressure anchor to equilibrium", + "file": "bouquet/io/imas.py", + "line": 250, + "desc": "False (default): omit p_diff, trust IDA thermal if present", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.generation.floor_j_BS", + "type": "knob", + "label": "config.generation.floor_j_BS", + "file": "bouquet/run.py", + "line": 643, + "desc": "Control: clip j_BS_swb at 0 (True, drops inner negative lobe) or keep signed (False)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "cfg.generation.isolate_edge_jBS", + "type": "knob", + "label": "config.generation.isolate_edge_jBS", + "file": "bouquet/run.py", + "line": 631, + "desc": "Control: isolate edge j_BS spike (True, reconstruction) or use full profile (False, IMAS). Defaults: False for both paths (full Sauter).", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "cfg.generation.jBS_baseline_mode", + "type": "knob", + "label": "config.generation.jBS_baseline_mode", + "file": "bouquet/run.py", + "line": 631, + "desc": "Control: 'diff' (default IMAS) or 'rescale' (self-consistent bootstrap rebuild)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "cfg.generation.kinetic_source", + "type": "knob", + "label": "kinetic profile source", + "file": "bouquet/io/imas.py", + "line": 249, + "desc": "'fuse' (default) | 'ida_hybrid' (swap ne/Te/Ti from IDA, keep Zeff/pressure anchors)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.generation.p_fast_reduction", + "type": "knob", + "label": "p_fast isotropization method", + "file": "bouquet/io/imas.py", + "line": 246, + "desc": "'trace' (default, 2*p_perp+p_par)/3 | 'mean' (p_perp+p_par)/2 | 'perp' p_perp", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "cfg.generation.recalculate_j_BS", + "type": "knob", + "label": "config.generation.recalculate_j_BS", + "file": "bouquet/run.py", + "line": 623, + "desc": "Control: recompute j_BS via SWB (True) or use source j_BS as-is (False)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "cfg.generationconfig.accept_anchor_inband", + "type": "knob", + "label": "accept_anchor_inband: bool = False", + "file": "bouquet/config.py", + "line": 294, + "desc": "Accept anchor if l_i already in band", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.allow_incomplete_pressure", + "type": "knob", + "label": "allow_incomplete_pressure: bool = False", + "file": "bouquet/config.py", + "line": 329, + "desc": "Allow missing pressure components in IMAS", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.allow_unsafe_workflow", + "type": "knob", + "label": "allow_unsafe_workflow: bool = False", + "file": "bouquet/config.py", + "line": 315, + "desc": "Bypass workflow validation guard", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.anchor_jtor_to_equilibrium", + "type": "knob", + "label": "anchor_jtor_to_equilibrium: bool = True", + "file": "bouquet/config.py", + "line": 337, + "desc": "Anchor total j_phi to equilibrium.j_tor", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.anchor_pressure_to_equilibrium", + "type": "knob", + "label": "anchor_pressure_to_equilibrium: bool = False", + "file": "bouquet/config.py", + "line": 350, + "desc": "Anchor solve pressure to equilibrium.pressure", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.coil_drift", + "type": "knob", + "label": "coil_drift: float = 0.01", + "file": "bouquet/config.py", + "line": 366, + "desc": "Coil drift tolerance for homotopy", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.coil_drift_hard_factor", + "type": "knob", + "label": "coil_drift_hard_factor: Optional[float] = None", + "file": "bouquet/config.py", + "line": 371, + "desc": "Hard inequality bounds on coil drift", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.constrain_sawteeth", + "type": "knob", + "label": "constrain_sawteeth: bool = False", + "file": "bouquet/config.py", + "line": 272, + "desc": "Constrain q0 \u2265 1 to suppress sawteeth", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.diagnostic_plots", + "type": "knob", + "label": "diagnostic_plots: bool = False", + "file": "bouquet/config.py", + "line": 375, + "desc": "Enable diagnostic plots during generation", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.floor_j_BS", + "type": "knob", + "label": "floor_j_BS: bool = False", + "file": "bouquet/config.py", + "line": 357, + "desc": "Floor SWB bootstrap at 0", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.homotopy_passes", + "type": "knob", + "label": "homotopy_passes: list = [(0.05,0.10),(0.02,0.05),(0.01,0.01)]", + "file": "bouquet/config.py", + "line": 372, + "desc": "Homotopy schedule: list of (F_tol, VSC_tol)", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.isolate_edge_jBS", + "type": "knob", + "label": "isolate_edge_jBS: bool = True", + "file": "bouquet/config.py", + "line": 282, + "desc": "Isolate edge j_BS spike from inner negative lobe", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.jBS_baseline_mode", + "type": "knob", + "label": "jBS_baseline_mode: str = \"diff\"", + "file": "bouquet/config.py", + "line": 290, + "desc": "SWB reconciliation on IMAS: diff/rescale", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.jBS_scale_range", + "type": "knob", + "label": "jBS_scale_range: tuple = (0.99, 1.01)", + "file": "bouquet/config.py", + "line": 277, + "desc": "Bootstrap multiplicative spread", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.kinetic_source", + "type": "knob", + "label": "kinetic_source: str = \"fuse\"", + "file": "bouquet/config.py", + "line": 343, + "desc": "Baseline kinetics on IMAS: fuse/ida_hybrid", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.l_i_tolerance", + "type": "knob", + "label": "l_i_tolerance: float = 0.05", + "file": "bouquet/config.py", + "line": 271, + "desc": "l_i acceptance band (fraction of target)", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.n_equils", + "type": "knob", + "label": "n_equils: int = 20", + "file": "bouquet/config.py", + "line": 265, + "desc": "Number of perturbed equilibria to generate", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.perturb_jind_in_anchor", + "type": "knob", + "label": "perturb_jind_in_anchor: bool = False", + "file": "bouquet/config.py", + "line": 308, + "desc": "GPR-perturb j_inductive in anchor (Fix C)", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.recalculate_j_BS", + "type": "knob", + "label": "recalculate_j_BS: bool = True", + "file": "bouquet/config.py", + "line": 276, + "desc": "Recompute bootstrap each draw via solve_with_bootstrap", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.scan_key", + "type": "knob", + "label": "scan_key: float = 0", + "file": "bouquet/config.py", + "line": 270, + "desc": "HDF5 scan// label", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.seed", + "type": "knob", + "label": "seed: Optional[int] = None", + "file": "bouquet/config.py", + "line": 266, + "desc": "Random seed for reproducibility", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.swb_iterations", + "type": "knob", + "label": "swb_iterations: int = 3", + "file": "bouquet/config.py", + "line": 360, + "desc": "solve_with_bootstrap self-consistency iterations", + "subsystem": "Configuration" + }, + { + "id": "cfg.generationconfig.workflow", + "type": "knob", + "label": "workflow: str = \"auto\"", + "file": "bouquet/config.py", + "line": 323, + "desc": "Workflow preset: auto/geqdsk-standard/imas-diff-c/custom", + "subsystem": "Configuration" + }, + { + "id": "cfg.imassource.efit01_geqdsk", + "type": "knob", + "label": "efit01_geqdsk: Optional[str] = None", + "file": "bouquet/config.py", + "line": 131, + "desc": "Magnetics-only EFIT01 g-file for LCFS boundary", + "subsystem": "Configuration" + }, + { + "id": "cfg.imassource.ida_path", + "type": "knob", + "label": "ida_path: Optional[str] = None", + "file": "bouquet/config.py", + "line": 126, + "desc": "IDA-hybrid kinetics: IDA .cdf for baseline ne/Te/Ti", + "subsystem": "Configuration" + }, + { + "id": "cfg.imassource.ids_path", + "type": "knob", + "label": "ids_path: str = None", + "file": "bouquet/config.py", + "line": 116, + "desc": "Path to FUSE IMAS/OMAS IDS file", + "subsystem": "Configuration" + }, + { + "id": "cfg.imassource.impurity_Z", + "type": "knob", + "label": "impurity_Z: float = 6.0", + "file": "bouquet/config.py", + "line": 127, + "desc": "Machine impurity charge (carbon); ni dilution", + "subsystem": "Configuration" + }, + { + "id": "cfg.imassource.time", + "type": "knob", + "label": "time: Optional[float] = None", + "file": "bouquet/config.py", + "line": 117, + "desc": "Time slice [s]; None->first/single", + "subsystem": "Configuration" + }, + { + "id": "cfg.isolate_edge_jBS", + "type": "knob", + "label": "isolate_edge_jBS", + "file": "bouquet/config.py", + "line": 282, + "desc": "Separate edge bootstrap spike from core; False=full Sauter (default True)", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.jBS_scale_range", + "type": "knob", + "label": "jBS_scale_range", + "file": "bouquet/TokaMaker_interface.py", + "line": 2280, + "desc": "[lo, hi] bounds for uniform jBS multiplicative scale factor per draw; None \u2192 all 1.0", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.l_i_tolerance", + "type": "knob", + "label": "l_i_tolerance", + "file": "bouquet/TokaMaker_interface.py", + "line": 2263, + "desc": "Fraction of l_i_target for band acceptance (e.g. 0.01 = \u00b11%)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.l_i_uncertainty", + "type": "knob", + "label": "l_i_uncertainty", + "file": "bouquet/TokaMaker_interface.py", + "line": 2308, + "desc": "Fractional uncertainty (e.g. 0.05 = 5%) for per-draw l_i target sampling; 0 \u2192 pin to recon", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.max_li_iter", + "type": "knob", + "label": "max_li_iter (l_i loop cap)", + "desc": "Safety limit on GPR resamples in band-conditioning", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.max_pressure_iter", + "type": "knob", + "label": "max_pressure_iter (pressure loop cap)", + "desc": "Safety limit on GPR resamples in pressure match", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.max_proxy_draws", + "type": "knob", + "label": "max_proxy_draws (proxy-draw cap)", + "desc": "Max attempts to pass pre-screen per li_iter", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.mygs", + "type": "input", + "label": "mygs (TokaMaker solver)", + "desc": "Grad-Shafranov solver object; mutated per solve", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.n_equils", + "type": "knob", + "label": "n_equils", + "file": "bouquet/TokaMaker_interface.py", + "line": 2251, + "desc": "Number of perturbed equilibria to generate", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.n_k", + "type": "knob", + "label": "n_k (spline order)", + "file": "bouquet/config.py", + "line": 99, + "desc": "Spline order for fit_inductive_profile (default k=3)", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.npsi", + "type": "input", + "label": "npsi (grid size)", + "desc": "Normalized poloidal flux grid point count", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.p_thresh", + "type": "knob", + "label": "p_thresh (pressure match tolerance)", + "desc": "Fraction (e.g., 0.005 = 0.5%)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.perturb_jind_in_anchor", + "type": "knob", + "label": "perturb_jind_in_anchor (Fix-C path)", + "desc": "If True, GPR-perturb j_ind in anchor, accept always", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.pin_jphi", + "type": "knob", + "label": "pin_jphi (PIN_JPHI diagnostic)", + "desc": "If True, fix j_phi to recon, only pressure varies", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.proxy_bias_warmstart", + "type": "knob", + "label": "proxy_bias_warmstart (cross-draw cache)", + "desc": "proxy/l_i ratio from previous draw; ~7% bias", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.psi_bridge", + "type": "knob", + "label": "psi_bridge", + "file": "bouquet/config.py", + "line": 100, + "desc": "psi_N above which edge data replaced by zero anchor (default 0.99)", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.psi_pad", + "type": "knob", + "label": "psi_pad", + "file": "bouquet/config.py", + "line": 98, + "desc": "Padding inside LCFS for li proxy calculation", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.recalculate_j_BS", + "type": "knob", + "label": "recalculate_j_BS", + "file": "bouquet/TokaMaker_interface.py", + "line": 2266, + "desc": "Recompute bootstrap current via solve_with_bootstrap per draw", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.recon_eq_snapshot", + "type": "knob", + "label": "recon_eq_snapshot (DIFF_BS cache)", + "desc": "TokaMaker state snapshot for differential bootstrap", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.reconstructionsource.cocos", + "type": "knob", + "label": "cocos: int = 1", + "file": "bouquet/config.py", + "line": 93, + "desc": "Flux-coordinate convention", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.geqdsk_path", + "type": "knob", + "label": "geqdsk_path: str = None", + "file": "bouquet/config.py", + "line": 91, + "desc": "Path to g-file (EFIT equilibrium)", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.impurity_Z", + "type": "knob", + "label": "impurity_Z: float = 6.0", + "file": "bouquet/config.py", + "line": 95, + "desc": "Effective impurity charge (carbon)", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.n_k", + "type": "knob", + "label": "n_k: int = 5", + "file": "bouquet/config.py", + "line": 99, + "desc": "Inductive-spline knots for reconstruction", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.profile_overrides", + "type": "knob", + "label": "profile_overrides: dict = {}", + "file": "bouquet/config.py", + "line": 96, + "desc": "Manual profile overrides by name", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.profiles_path", + "type": "knob", + "label": "profiles_path: str = None", + "file": "bouquet/config.py", + "line": 92, + "desc": "Path to IDA .cdf or p-file (kinetic profiles)", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.psi_bridge", + "type": "knob", + "label": "psi_bridge: float = 0.99", + "file": "bouquet/config.py", + "line": 100, + "desc": "Hermite edge-bridge location for psi", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.psi_pad", + "type": "knob", + "label": "psi_pad: float = 1e-3", + "file": "bouquet/config.py", + "line": 98, + "desc": "Reconstruction padding for psi range", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.rescale_j_BS", + "type": "knob", + "label": "rescale_j_BS: bool = False", + "file": "bouquet/config.py", + "line": 101, + "desc": "Whether to rescale bootstrap current", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.shelf_psi_N", + "type": "knob", + "label": "shelf_psi_N: float = 0.0", + "file": "bouquet/config.py", + "line": 102, + "desc": "Shelf location for inductive smoothing", + "subsystem": "Configuration" + }, + { + "id": "cfg.reconstructionsource.time", + "type": "knob", + "label": "time: Optional[float] = None", + "file": "bouquet/config.py", + "line": 94, + "desc": "IDA time slice [s] for multi-time .cdf", + "subsystem": "Configuration" + }, + { + "id": "cfg.rescale_j_BS", + "type": "knob", + "label": "rescale_j_BS", + "file": "bouquet/config.py", + "line": 101, + "desc": "Jointly optimize bootstrap rescaling in fit_inductive_profile", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.scale_jBS", + "type": "knob", + "label": "scale_jBS (bootstrap scale factor)", + "desc": "Multiplicative; 1.0=no scaling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.seed", + "type": "knob", + "label": "seed (RNG)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2340, + "desc": "Optional seed for reproducible np.random draws; None leaves RNG untouched", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "cfg.shelf_psi_N", + "type": "knob", + "label": "shelf_psi_N", + "file": "bouquet/config.py", + "line": 102, + "desc": "Apply flat shelf to j_BS for psi_N < shelf_psi_N (default 0.0)", + "subsystem": "GS reconstruction" + }, + { + "id": "cfg.solverconfig.F0", + "type": "knob", + "label": "F0: Optional[float] = None", + "file": "bouquet/config.py", + "line": 55, + "desc": "Vacuum R*Bt; defaults to g-file/IDS if None", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.coil_reg", + "type": "knob", + "label": "coil_reg: list = []", + "file": "bouquet/config.py", + "line": 59, + "desc": "Coil regularization (not directly used)", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.coil_vsc", + "type": "knob", + "label": "coil_vsc: dict = {\"F9A\": 1.0, \"F9B\": -1.0}", + "file": "bouquet/config.py", + "line": 58, + "desc": "Vertical stabilization coil configuration", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.isoflux_pts", + "type": "knob", + "label": "isoflux_pts: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 56, + "desc": "(N,2) boundary isoflux constraints", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.isoflux_weights", + "type": "knob", + "label": "isoflux_weights: Optional[np.ndarray] = None", + "file": "bouquet/config.py", + "line": 57, + "desc": "(N,) isoflux weights", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.mesh_path", + "type": "knob", + "label": "mesh_path: str = None", + "file": "bouquet/config.py", + "line": 44, + "desc": "Mesh file path for GS solver setup", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.nthreads", + "type": "knob", + "label": "nthreads: int = 1", + "file": "bouquet/config.py", + "line": 53, + "desc": "OpenMP threads (=1 for determinism, see comment)", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.order", + "type": "knob", + "label": "order: int = 3", + "file": "bouquet/config.py", + "line": 54, + "desc": "Spline order for GS solver", + "subsystem": "Configuration" + }, + { + "id": "cfg.solverconfig.region_overrides", + "type": "knob", + "label": "region_overrides: Optional[dict] = None", + "file": "bouquet/config.py", + "line": 60, + "desc": "Special-case mesh region dict overrides", + "subsystem": "Configuration" + }, + { + "id": "cfg.source.efit01_geqdsk", + "type": "knob", + "label": "efit01_geqdsk", + "file": "bouquet/config.py", + "line": 131, + "desc": "magnetics-only EFIT01 g-file whose LCFS replaces the IDS boundary", + "subsystem": "Configuration" + }, + { + "id": "cfg.source.type", + "type": "knob", + "label": "source type", + "file": "bouquet/run.py", + "line": 304, + "desc": "Control: ReconstructionSource (g-file path) or ImasSource (IDS path). Determines baseline pipeline.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "cfg.spike_profile_recon_cached", + "type": "knob", + "label": "spike_profile_recon_cached (DIFF_BS cache)", + "desc": "Pre-computed isolated_j_BS from SWB(recon kinetics)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.swb_iterations", + "type": "knob", + "label": "swb_iterations (SWB self-consistency)", + "desc": "H-mode bootstrap-iteration count inside SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "cfg.uncertaintyconfig.aux_baselines", + "type": "knob", + "label": "aux_baselines: dict = {}", + "file": "bouquet/config.py", + "line": 254, + "desc": "Baseline values for auxiliary profiles", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.aux_length_scales", + "type": "knob", + "label": "aux_length_scales: dict = {}", + "file": "bouquet/config.py", + "line": 255, + "desc": "Per-auxiliary GPR length scale (default 0.4)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.aux_sigmas", + "type": "knob", + "label": "aux_sigmas: dict = {}", + "file": "bouquet/config.py", + "line": 253, + "desc": "Named auxiliary perturbed profiles (omega_tor, e_r, chi_e, chi_i)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.ida_path", + "type": "knob", + "label": "ida_path: Optional[str] = None", + "file": "bouquet/config.py", + "line": 209, + "desc": "IDA .cdf for kinetic sigma profiles", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.j_ls", + "type": "knob", + "label": "j_ls: float = 0.25", + "file": "bouquet/config.py", + "line": 241, + "desc": "GPR correlation length (current)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.jphi_scalar_sigma", + "type": "knob", + "label": "jphi_scalar_sigma: float = 0.1", + "file": "bouquet/config.py", + "line": 225, + "desc": "Flat fractional j_phi sigma envelope", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.n_ls", + "type": "knob", + "label": "n_ls: float = 0.5", + "file": "bouquet/config.py", + "line": 239, + "desc": "GPR correlation length (density)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.ne_scalar_sigma", + "type": "knob", + "label": "ne_scalar_sigma: float = 0.05", + "file": "bouquet/config.py", + "line": 216, + "desc": "Flat fractional ne sigma (fallback)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.ni_scalar_sigma", + "type": "knob", + "label": "ni_scalar_sigma: float = 0.1", + "file": "bouquet/config.py", + "line": 218, + "desc": "Flat fractional ni sigma (fallback)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.sigma_method", + "type": "knob", + "label": "sigma_method: str = \"percentile\"", + "file": "bouquet/config.py", + "line": 211, + "desc": "Ensemble sigma reduction: percentile/std", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.sigma_mode", + "type": "knob", + "label": "sigma_mode: str = \"auto\"", + "file": "bouquet/config.py", + "line": 210, + "desc": "Sigma extraction mode: auto/direct/ensemble", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.sigma_ni_from_ne", + "type": "knob", + "label": "sigma_ni_from_ne: bool = True", + "file": "bouquet/config.py", + "line": 212, + "desc": "IDA path only: sigma_ni = sigma_ne", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.sigma_profiles", + "type": "knob", + "label": "sigma_profiles: dict = {}", + "file": "bouquet/config.py", + "line": 222, + "desc": "Explicit psi_N-dependent absolute sigma profiles", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.t_ls", + "type": "knob", + "label": "t_ls: float = 0.4", + "file": "bouquet/config.py", + "line": 240, + "desc": "GPR correlation length (temperature)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.te_scalar_sigma", + "type": "knob", + "label": "te_scalar_sigma: float = 0.05", + "file": "bouquet/config.py", + "line": 217, + "desc": "Flat fractional Te sigma (fallback)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.ti_scalar_sigma", + "type": "knob", + "label": "ti_scalar_sigma: float = 0.1", + "file": "bouquet/config.py", + "line": 219, + "desc": "Flat fractional Ti sigma (fallback)", + "subsystem": "Configuration" + }, + { + "id": "cfg.uncertaintyconfig.zeff_scalar_sigma", + "type": "knob", + "label": "zeff_scalar_sigma: float = 0.05", + "file": "bouquet/config.py", + "line": 236, + "desc": "Flat fractional Zeff sigma (enables zeff channel)", + "subsystem": "Configuration" + }, + { + "id": "cls.FilterConfig", + "type": "input", + "label": "FilterConfig", + "file": "bouquet/config.py", + "line": 379, + "desc": "FilterConfig dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.FixedComponentsConfig", + "type": "input", + "label": "FixedComponentsConfig", + "file": "bouquet/config.py", + "line": 141, + "desc": "FixedComponentsConfig dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.GenerationConfig", + "type": "input", + "label": "GenerationConfig", + "file": "bouquet/config.py", + "line": 262, + "desc": "GenerationConfig dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.ImasSource", + "type": "input", + "label": "ImasSource", + "file": "bouquet/config.py", + "line": 107, + "desc": "ImasSource dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.ReconstructionSource", + "type": "input", + "label": "ReconstructionSource", + "file": "bouquet/config.py", + "line": 67, + "desc": "ReconstructionSource dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.SolverConfig", + "type": "input", + "label": "SolverConfig", + "file": "bouquet/config.py", + "line": 35, + "desc": "SolverConfig dataclass", + "subsystem": "Configuration" + }, + { + "id": "cls.UncertaintyConfig", + "type": "input", + "label": "UncertaintyConfig", + "file": "bouquet/config.py", + "line": 186, + "desc": "UncertaintyConfig dataclass", + "subsystem": "Configuration" + }, + { + "id": "env.blas_pinning", + "type": "quantity", + "label": "BLAS/OpenMP env pinning", + "file": "bouquet/parallel.py", + "line": "366", + "desc": "Set OMP_NUM_THREADS, OPENBLAS_NUM_THREADS, MKL_NUM_THREADS, etc. to threads_per_worker before worker spawn to prevent BLAS oversubscription", + "subsystem": "Process-parallel path" + }, + { + "id": "env.fd_suppression", + "type": "quantity", + "label": "fd-level stdout/stderr suppression", + "file": "bouquet/parallel.py", + "line": "147", + "desc": "At run_shard entry: dup fd 1,2 to /dev/null BEFORE OFT import (caches fd); restores in finally block; skipped if verbose=True", + "subsystem": "Process-parallel path" + }, + { + "id": "ext.corrective_jphi_iteration", + "type": "transform", + "label": "_corrective_jphi_iteration", + "file": "bouquet/TokaMaker_interface.py", + "line": 51, + "desc": "Newton-style iteration: drive TokaMaker output j_phi toward target", + "subsystem": "GS reconstruction" + }, + { + "id": "ext.generate_bouquet", + "type": "transform", + "label": "generate_bouquet()", + "file": "bouquet/run.py", + "line": 894, + "desc": "Per-draw solver loop: perturb kinetics + jphi via GPR, apply jBS_diff offset, solve with TokaMaker, compute l_i + coil currents + boundary. Yields diagnostics.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "ext.scipy_interp1d", + "type": "input", + "label": "interp1d (kinetic\u2194equilibrium grid)", + "desc": "Linear interpolation between dual grids", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "ext.solve_with_bootstrap", + "type": "transform", + "label": "solve_with_bootstrap()", + "file": "bouquet/run.py", + "line": 637, + "desc": "OFT SWB solver: takes kinetics + Ip_target, returns j_BS_swb on psi_N (after floor_j_BS clipping)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "ext.tokamaker_get_stats", + "type": "input", + "label": "mygs.get_stats (extract equilibrium state)", + "desc": "Returns l_i, Ip, axis, separatrix position, etc.", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "ext.tokamaker_replace_eq", + "type": "input", + "label": "mygs.replace_eq (state restore for DIFF_BS)", + "desc": "Restore cached snapshot; used in DIFF_BS branch", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "ext.tokamaker_set_profiles", + "type": "input", + "label": "mygs.set_profiles (pressure/current assignment)", + "desc": "Set PP' and FF' from linterp profiles", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "ext.tokamaker_solve", + "type": "input", + "label": "mygs.solve() (GS forward solve)", + "desc": "External TokaMaker solve; mutates mygs.psi, mygs.coil currents", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.TokaMaker_interface.GPRPerturber", + "type": "transform", + "label": "GPRPerturber", + "file": "bouquet/TokaMaker_interface.py", + "line": 3160, + "desc": "gp_density = GPRPerturber(length_scale=unc.n_ls)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None", + "type": "transform", + "label": "coil_drift * config.generation.coil_drift_hard_factor if ... else None", + "file": "bouquet/TokaMaker_interface.py", + "line": 3245, + "desc": "hard_bounds = coil_drift * config.generation.coil_drift_hard", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.config.generation.coil_drift", + "type": "transform", + "label": "config.generation.coil_drift", + "file": "bouquet/TokaMaker_interface.py", + "line": 3240, + "desc": "coil_drift_spec = config.generation.coil_drift", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.config.uncertainty.aux_baselines.get", + "type": "transform", + "label": "config.uncertainty.aux_baselines.get", + "file": "bouquet/TokaMaker_interface.py", + "line": 3285, + "desc": "baseline = config.uncertainty.aux_baselines.get(name) or com", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get", + "type": "transform", + "label": "config.uncertainty.aux_length_scales.get", + "file": "bouquet/TokaMaker_interface.py", + "line": 3290, + "desc": "ls = config.uncertainty.aux_length_scales.get(name, 0.4)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs", + "type": "transform", + "label": "config.uncertainty.jphi_scalar_sigma * abs", + "file": "bouquet/TokaMaker_interface.py", + "line": 3180, + "desc": "sigma_jphi = config.uncertainty.jphi_scalar_sigma * abs(j_ph", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ...", + "type": "transform", + "label": "for F_tol, VSC_tol in config.generation.homotopy_passes: ...", + "file": "bouquet/TokaMaker_interface.py", + "line": 3250, + "desc": "for F_tol, VSC_tol in config.generation.homotopy_passes: ...", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.for i_eq in _tqdm", + "type": "transform", + "label": "for i_eq in _tqdm", + "file": "bouquet/TokaMaker_interface.py", + "line": 3338, + "desc": "for i_eq in _tqdm(range(n_equils), ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items", + "type": "transform", + "label": "for name, sigma in config.uncertainty.aux_sigmas.items", + "file": "bouquet/TokaMaker_interface.py", + "line": 3280, + "desc": "for name, sigma in config.uncertainty.aux_sigmas.items(): ..", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band", + "type": "transform", + "label": "if gc.accept_anchor_inband and in_band", + "file": "bouquet/TokaMaker_interface.py", + "line": 3420, + "desc": "if gc.accept_anchor_inband and in_band(l_i, target): accept_", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject", + "type": "transform", + "label": "if gc.constrain_sawteeth and q0 < 1.0: reject", + "file": "bouquet/TokaMaker_interface.py", + "line": 3410, + "desc": "if gc.constrain_sawteeth and q0 < 1.0: reject()", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.if not abs", + "type": "transform", + "label": "if not abs", + "file": "bouquet/TokaMaker_interface.py", + "line": 3400, + "desc": "if not abs(l_i - l_i_target) <= gc.l_i_tolerance * l_i_targe", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff", + "type": "transform", + "label": "if unc.zeff_scalar_sigma > 0: perturb_zeff", + "file": "bouquet/TokaMaker_interface.py", + "line": 3210, + "desc": "if unc.zeff_scalar_sigma > 0: perturb_zeff(unc.zeff_scalar_s", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.mygs.solve", + "type": "transform", + "label": "mygs.solve", + "file": "bouquet/TokaMaker_interface.py", + "line": 3234, + "desc": "mygs.solve(..., nthreads=nthreads)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.np.random.seed", + "type": "transform", + "label": "np.random.seed", + "file": "bouquet/TokaMaker_interface.py", + "line": 3100, + "desc": "np.random.seed(config.generation.seed)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.np.random.uniform", + "type": "transform", + "label": "np.random.uniform", + "file": "bouquet/TokaMaker_interface.py", + "line": 3095, + "desc": "jBS_scales = np.random.uniform(lo, hi, size=n_equils)", + "subsystem": "Configuration" + }, + { + "id": "fn.TokaMaker_interface.solve_with_bootstrap", + "type": "transform", + "label": "solve_with_bootstrap", + "file": "bouquet/TokaMaker_interface.py", + "line": 3230, + "desc": "solve_with_bootstrap(..., n_iterations=config.generation.swb", + "subsystem": "Configuration" + }, + { + "id": "fn.archive.BouquetArchive", + "type": "artifact", + "label": "BouquetArchive(ref)", + "file": "bouquet/archive.py", + "line": 243, + "desc": "High-level reader: .path, .scan_keys, .provenance; supports pre-v2 eqdsk suffix scan", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.archive.DrawView", + "type": "artifact", + "label": "DrawView(archive, scan_key, count)", + "file": "bouquet/archive.py", + "line": 60, + "desc": "Lazy view of one draw: .attrs, .li1, .li3, .flags, .selected, .profiles, .equilibrium(), .pfile()", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.archive.ScanView", + "type": "artifact", + "label": "ScanView(archive, scan_key)", + "file": "bouquet/archive.py", + "line": 194, + "desc": "View of scan/: .indices, .baseline, .selected/.excluded/.all DrawViews", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.baseline....", + "type": "transform", + "label": "...", + "file": "bouquet/baseline.py", + "line": 415, + "desc": "if field in profile_overrides: profiles[field] = ...", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline._load_kinetic_profiles", + "type": "transform", + "label": "_load_kinetic_profiles(source)", + "file": "bouquet/baseline.py", + "line": 303, + "desc": "Dispatch on profiles_path file type (.cdf|.pfile), return ne/te/ni/ti/Zeff/raw_bytes", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline._resolve_fixed", + "type": "transform", + "label": "_resolve_fixed(comp, src_psi, dst_psi)", + "file": "bouquet/baseline.py", + "line": 286, + "desc": "Fixed additive component resampling/zeros; raise if shape mismatch without psi_N", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline._resolve_reconstruction", + "type": "transform", + "label": "_resolve_reconstruction(source, config, mygs)", + "file": "bouquet/baseline.py", + "line": 350, + "desc": "Reconstruction path: read g-file + kinetics, run GS solve, extract currents", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline._sigma_zeff_baseline", + "type": "transform", + "label": "resolve zeff baseline (aux or baseline.Zeff)", + "file": "bouquet/baseline.py", + "line": 259, + "desc": "Zeff baseline: src_aux['zeff'] (IMAS) or baseline.Zeff (reconstruction)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline.compute_psi_bounds", + "type": "transform", + "label": "compute_psi_bounds", + "file": "bouquet/baseline.py", + "line": 480, + "desc": "psi_bounds = compute_psi_bounds(eqdsk, psi_pad=source.psi_pa", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.hermite_edge_bridge", + "type": "transform", + "label": "hermite_edge_bridge", + "file": "bouquet/baseline.py", + "line": 515, + "desc": "hermite_edge_bridge(psi_bridge=source.psi_bridge)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.percentile_or_std", + "type": "transform", + "label": "percentile_or_std", + "file": "bouquet/baseline.py", + "line": 215, + "desc": "if unc.sigma_mode==\"ensemble\": sigmas = percentile_or_std(me", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.profiles.compute_ni", + "type": "transform", + "label": "profiles.compute_ni", + "file": "bouquet/baseline.py", + "line": 400, + "desc": "profiles.compute_ni(impurity_Z=source.impurity_Z)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.read_geqdsk", + "type": "transform", + "label": "read_geqdsk", + "file": "bouquet/baseline.py", + "line": 376, + "desc": "eqdsk = read_geqdsk(source.geqdsk_path)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.read_profiles", + "type": "transform", + "label": "read_profiles", + "file": "bouquet/baseline.py", + "line": 380, + "desc": "profiles = read_profiles(source.profiles_path, ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.resolve_baseline", + "type": "decision", + "label": "resolve_baseline(config, mygs)", + "file": "bouquet/baseline.py", + "line": 139, + "desc": "Dispatch on config.source type (ImasSource | ReconstructionSource)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline.resolve_ida_sigmas", + "type": "transform", + "label": "resolve_ida_sigmas", + "file": "bouquet/baseline.py", + "line": 210, + "desc": "sigmas = resolve_ida_sigmas(ida_path, mode=unc.sigma_mode)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.resolve_uncertainty", + "type": "transform", + "label": "resolve_uncertainty(config, baseline)", + "file": "bouquet/baseline.py", + "line": 179, + "desc": "Resolve kinetic + j_phi + aux sigmas with per-channel priority chains", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.baseline.scaling_factor", + "type": "transform", + "label": "scaling_factor", + "file": "bouquet/baseline.py", + "line": 520, + "desc": "if source.rescale_j_BS: j_BS *= scaling_factor", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.sigma_ne", + "type": "transform", + "label": "sigma_ne", + "file": "bouquet/baseline.py", + "line": 220, + "desc": "if unc.sigma_ni_from_ne: sigma_ni = sigma_ne", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline", + "type": "transform", + "label": "sigma_ne or unc.ne_scalar_sigma * ne_baseline", + "file": "bouquet/baseline.py", + "line": 235, + "desc": "sigma_ne = sigma_ne or unc.ne_scalar_sigma * ne_baseline", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline", + "type": "transform", + "label": "sigma_ni or unc.ni_scalar_sigma * ni_baseline", + "file": "bouquet/baseline.py", + "line": 245, + "desc": "sigma_ni = sigma_ni or unc.ni_scalar_sigma * ni_baseline", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline", + "type": "transform", + "label": "sigma_te or unc.te_scalar_sigma * te_baseline", + "file": "bouquet/baseline.py", + "line": 240, + "desc": "sigma_te = sigma_te or unc.te_scalar_sigma * te_baseline", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline", + "type": "transform", + "label": "sigma_ti or unc.ti_scalar_sigma * ti_baseline", + "file": "bouquet/baseline.py", + "line": 250, + "desc": "sigma_ti = sigma_ti or unc.ti_scalar_sigma * ti_baseline", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.source.shelf_psi_N", + "type": "transform", + "label": "source.shelf_psi_N", + "file": "bouquet/baseline.py", + "line": 525, + "desc": "shelf_psi_N=source.shelf_psi_N", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.spline_fit", + "type": "transform", + "label": "spline_fit", + "file": "bouquet/baseline.py", + "line": 510, + "desc": "guess_jinductive = spline_fit(..., n_knots=source.n_k)", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.unc.ida_path or source.profiles_path", + "type": "transform", + "label": "unc.ida_path or source.profiles_path", + "file": "bouquet/baseline.py", + "line": 199, + "desc": "ida_path = unc.ida_path or source.profiles_path", + "subsystem": "Configuration" + }, + { + "id": "fn.baseline.unc.sigma_profiles.get", + "type": "transform", + "label": "unc.sigma_profiles.get", + "file": "bouquet/baseline.py", + "line": 225, + "desc": "explicit_sigma = unc.sigma_profiles.get(channel)", + "subsystem": "Configuration" + }, + { + "id": "fn.filtering._baseline_boundary", + "type": "transform", + "label": "filtering._baseline_boundary", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "fn.filtering._boundary_devs", + "type": "transform", + "label": "_boundary_devs(bl_boundary, grp)", + "file": "bouquet/filtering.py", + "line": 140, + "desc": "Compute (rms_mm, max_mm) from perturbed_lcfs_ref or eqdsk boundary vs baseline", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.filtering.export_filtered", + "type": "transform", + "label": "export_filtered(h5path, out_path, scan_key, selection, overwrite)", + "file": "bouquet/filtering.py", + "line": 386, + "desc": "Copy archive and delete excluded draws (based on selection)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.filtering.filter_boundaries", + "type": "transform", + "label": "filter_boundaries(h5path, scan_key, rms_max_mm, max_max_mm, apply, plot)", + "file": "bouquet/filtering.py", + "line": 323, + "desc": "Compute RMS/max LCFS deviation vs recon baseline via KDTree; write passes_boundary_filter flag", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.filtering.filter_coil_currents", + "type": "transform", + "label": "filter_coil_currents(h5path, scan_key, F_max_pct, VSC_max_pct, apply, plot)", + "file": "bouquet/filtering.py", + "line": 259, + "desc": "Check per-draw max_F_drift_pct & max_VSC_drift_pct vs thresholds; write passes_coil_filter flag", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.filtering.if abs", + "type": "transform", + "label": "if abs", + "file": "bouquet/filtering.py", + "line": 50, + "desc": "if abs(coil_error) > config.filtering.inspec_F_max * coil_cu", + "subsystem": "Configuration" + }, + { + "id": "fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject", + "type": "transform", + "label": "if rms_error_mm > config.filtering.rms_max_mm: reject", + "file": "bouquet/filtering.py", + "line": 45, + "desc": "if rms_error_mm > config.filtering.rms_max_mm: reject()", + "subsystem": "Configuration" + }, + { + "id": "fn.filtering.read_filter_flags", + "type": "transform", + "label": "read_filter_flags(h5path, scan_key)", + "file": "bouquet/filtering.py", + "line": 177, + "desc": "Read per-draw filter flags + drift metrics from group attrs", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.filtering.select_indices", + "type": "transform", + "label": "select_indices(h5path, scan_key, selection)", + "file": "bouquet/filtering.py", + "line": 210, + "desc": "Return draw indices filtered by 'all'|'selected'|'excluded' based on attrs", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.gui.EquilibriumBrowser", + "type": "artifact", + "label": "EquilibriumBrowser(h5path)", + "file": "bouquet/gui.py", + "line": 88, + "desc": "Interactive matplotlib tabs: kinetic/pressure/j_phi profiles via load_baseline + _load_all_perturbations", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.ida.read_ida", + "type": "transform", + "label": "read_ida() [IDA-hybrid only]", + "file": "bouquet/io/imas.py", + "line": 232, + "desc": "External reader from bouquet/io/ida.py; extracts ne/Te/Ti onto external psi_N grid", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.imas._merge_ida_kinetics", + "type": "transform", + "label": "_merge_ida_kinetics() [IDA-hybrid only]", + "file": "bouquet/io/imas.py", + "line": 223, + "desc": "Replaces FUSE ne/Te/Ti with IDA fits (resampled onto psi_N), derives ni from FUSE Zeff", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.imas._override", + "type": "transform", + "label": "_override()", + "file": "bouquet/io/imas.py", + "line": 82, + "desc": "Resamples user-supplied fixed-component arrays onto baseline psi_N grid", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.imas._validate_pressure_completeness", + "type": "transform", + "label": "_validate_pressure_completeness()", + "file": "bouquet/io/imas.py", + "line": 133, + "desc": "Guards: fail/warn on dropped thermal species or fast channel (unless allow_incomplete_pressure)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.imas.read_imas_baseline", + "type": "transform", + "label": "read_imas_baseline()", + "file": "bouquet/io/imas.py", + "line": 243, + "desc": "Main reader: IMAS IDS \u2192 separated Baseline (currents, targets, kinetics)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.imas.read_imas_geometry", + "type": "transform", + "label": "read_imas_geometry()", + "file": "bouquet/io/imas.py", + "line": 95, + "desc": "Extract F0 + LCFS boundary from IDS for TokaMaker setup", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.io.ida.read_ida", + "type": "transform", + "label": "read_ida", + "file": "bouquet/io/ida.py", + "line": 45, + "desc": "read_ida(path, time=self.time, ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check", + "type": "transform", + "label": "if config.generation.allow_incomplete_pressure: skip_pressure_check", + "file": "bouquet/io/imas.py", + "line": 180, + "desc": "if config.generation.allow_incomplete_pressure: skip_pressur", + "subsystem": "Configuration" + }, + { + "id": "fn.io.imas.profiles.compute_ni", + "type": "transform", + "label": "profiles.compute_ni", + "file": "bouquet/io/imas.py", + "line": 140, + "desc": "profiles.compute_ni(impurity_Z=source.impurity_Z)", + "subsystem": "Configuration" + }, + { + "id": "fn.io.imas.read_imas", + "type": "transform", + "label": "read_imas", + "file": "bouquet/io/imas.py", + "line": 120, + "desc": "imas_tree = read_imas(source.ids_path, ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.io.imas.read_imas_baseline", + "type": "transform", + "label": "read_imas_baseline(source, fixed, ...)", + "file": "bouquet/io/imas.py", + "line": 1, + "desc": "IMAS path: read j_ohmic/j_BS/Ip/l_i from FUSE dd, convert parallel\u2192toroidal", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.io.pfile.read_pfile", + "type": "transform", + "label": "read_pfile(path) + compute_quasineutrality/compute_zeff", + "file": "bouquet/baseline.py", + "line": 331, + "desc": "Osborne p-file: read ne/ni/te/ti [1e20 m^-3, keV], convert SI, compute Zeff from ion mix", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "fn.parallel._cli", + "type": "transform", + "label": "_cli(argv)", + "file": "bouquet/parallel.py", + "line": "559", + "desc": "CLI dispatcher: load bundle.json, route shard/merge commands with expected-worker accounting and --allow-missing", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel._derive_seed", + "type": "transform", + "label": "_derive_seed(seed_base, worker_id, scan_key)", + "file": "bouquet/parallel.py", + "line": "48", + "desc": "SeedSequence entropy tuple to well-separated 32-bit seed; decorrelates workers and time slices", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel._physical_cores", + "type": "transform", + "label": "_physical_cores()", + "file": "bouquet/parallel.py", + "line": "71", + "desc": "Detect physical core count (psutil, macOS sysctl, fallback os.cpu_count)", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel._shard_size", + "type": "transform", + "label": "_shard_size(total, n_workers, worker_id)", + "file": "bouquet/parallel.py", + "line": "42", + "desc": "Compute shard size: base + 1 if worker_id < remainder", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel._warn_multithreaded", + "type": "transform", + "label": "_warn_multithreaded(threads_per_worker)", + "file": "bouquet/parallel.py", + "line": "96", + "desc": "Warn on threads_per_worker > 1; triggers gate.threads_warn", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel.emit_slurm_script", + "type": "transform", + "label": "emit_slurm_script(config, ...)", + "file": "bouquet/parallel.py", + "line": "465", + "desc": "Serialize config to JSON bundle, emit array.sbatch + merge.sbatch + submit.sh with afterany dependency", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel.merge_archives", + "type": "transform", + "label": "merge_archives(shard_paths, out_header, ...)", + "file": "bouquet/parallel.py", + "line": "200", + "desc": "Concatenate per-worker shards, renumber group indices, copy _baseline once, write provenance config_json, optional cleanup", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel.parallel_generate", + "type": "transform", + "label": "parallel_generate(config, ...)", + "file": "bouquet/parallel.py", + "line": "323", + "desc": "Orchestrate full run: compute n_workers, choose backend, spawn pool or emit SLURM, run shards, cross-worker baseline check, merge", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.parallel.run_shard", + "type": "transform", + "label": "run_shard(config, worker_id, n_workers, ...)", + "file": "bouquet/parallel.py", + "line": "121", + "desc": "Per-worker main: fresh shard h5, suppress fd output, setup_solver -> prepare_baseline -> generate with per-worker config/seed; returns metadata dict + path", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.physics.effective_impurity_charge", + "type": "transform", + "label": "effective_impurity_charge()", + "file": "bouquet/physics.py", + "line": 1, + "desc": "Derives Z_eff from ne/ni/Zeff under single-impurity model", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.physics.impurity_pressure", + "type": "transform", + "label": "impurity_pressure()", + "file": "bouquet/physics.py", + "line": 1, + "desc": "Computes e*nz*Ti for carbon impurity (single-impurity dilution)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.physics.isotropize_fast_pressure", + "type": "transform", + "label": "isotropize_fast_pressure", + "file": "bouquet/physics.py", + "line": 420, + "desc": "isotropize_fast_pressure(p_perp, p_par, mode=config.p_fast_r", + "subsystem": "Configuration" + }, + { + "id": "fn.physics.main_ion_density_from_zeff", + "type": "transform", + "label": "main_ion_density_from_zeff()", + "file": "bouquet/physics.py", + "line": 1, + "desc": "Recovers ni from ne/Zeff under single-impurity quasineutrality (IDA-hybrid path)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.physics.parallel_to_toroidal", + "type": "transform", + "label": "parallel_to_toroidal()", + "file": "bouquet/physics.py", + "line": 67, + "desc": "Converts /B0 parallel to /<1/R> toroidal via c(psi)=j_tor/j_parallel", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "fn.plotting.plot_bouquet", + "type": "transform", + "label": "plot_bouquet(h5path, scan_key, mode, ...)", + "file": "bouquet/plotting.py", + "line": 1261, + "desc": "Composite kinetic + j_phi + auxiliary plot family from perturbed + baseline", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.plotting.plot_coil_currents", + "type": "transform", + "label": "plot_coil_currents(h5path, scan_key, vsc_coils, ...)", + "file": "bouquet/plotting.py", + "line": 2164, + "desc": "Coil-current trace plot: perturbed vs baseline coil_currents", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.plotting.plot_geqdsk_bouquet", + "type": "transform", + "label": "plot_geqdsk_bouquet(geqdsk_path_or_eq, ...)", + "file": "bouquet/plotting.py", + "line": 1652, + "desc": "Flux diagram + limits from equilibrium (parsed from eqdsk bytes)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.plotting.plot_pfile_bouquet", + "type": "transform", + "label": "plot_pfile_bouquet(pfile_path_or_pf, ...)", + "file": "bouquet/plotting.py", + "line": 1902, + "desc": "P-file profile plots from stored pfile bytes", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.plotting.plot_traces", + "type": "transform", + "label": "plot_traces(h5path, scan_key, li_band, rms_max_mm)", + "file": "bouquet/plotting.py", + "line": 2714, + "desc": "LCFS boundary evolution: perturbed_lcfs_ref vs recon_lcfs_ref or eqdsk RBBBS", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.read_geqdsk", + "type": "transform", + "label": "read_geqdsk()", + "file": "bouquet/io/geqdsk.py", + "line": 1803, + "desc": "Parse g-file into GEQDSKEquilibrium object with lazy flux-surface tracing", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "fn.read_ida", + "type": "transform", + "label": "read_ida()", + "file": "bouquet/io/ida.py", + "line": 101, + "desc": "Read IDA .cdf at selected time_index; dispatch direct vs ensemble layout; derive ni from (ne, Zeff)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "fn.read_ida_cer", + "type": "transform", + "label": "read_ida_cer()", + "file": "bouquet/io/ida.py", + "line": 213, + "desc": "Read CER channels (carbon density/temperature, rotations); handle both file layouts", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "fn.read_pfile", + "type": "transform", + "label": "read_pfile()", + "file": "bouquet/io/pfile.py", + "line": 825, + "desc": "Parse p-file into PFile object with profile dict + optional N Z A block", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "fn.reconstruct_equilibrium", + "type": "transform", + "label": "reconstruct_equilibrium() [geqdsk.py]", + "file": "bouquet/run.py", + "line": 301, + "desc": "Read g-file \u2192 GEQDSKEquilibrium; compute flux-surface averages (psi_N, j_phi, li)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "fn.run.\"ida_hybrid\": resample_ida_profiles", + "type": "transform", + "label": "\"ida_hybrid\": resample_ida_profiles", + "file": "bouquet/run.py", + "line": 800, + "desc": "if config.generation.kinetic_source == \"ida_hybrid\": resampl", + "subsystem": "Configuration" + }, + { + "id": "fn.run....", + "type": "transform", + "label": "...", + "file": "bouquet/run.py", + "line": 610, + "desc": "if config.generation.jBS_baseline_mode == \"diff\": j_BS_diff ", + "subsystem": "Configuration" + }, + { + "id": "fn.run.Bouquet_pipeline", + "type": "transform", + "label": "Bouquet.setup_solver -> prepare_baseline -> generate", + "file": "stub", + "line": "183", + "desc": "Per-worker: TokaMaker init, baseline forward-solve, draw generation with optional progress callback", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.run.F0 or eqdsk.F0_ref or ...", + "type": "transform", + "label": "F0 or eqdsk.F0_ref or ...", + "file": "bouquet/run.py", + "line": 320, + "desc": "F0 = F0 or eqdsk.F0_ref or ...", + "subsystem": "Configuration" + }, + { + "id": "fn.run.GsHandle", + "type": "transform", + "label": "GsHandle", + "file": "bouquet/run.py", + "line": 310, + "desc": "gs_handle = GsHandle(mesh_pts, ..., order=order, ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.run._forward_solve_imas_baseline", + "type": "transform", + "label": "_forward_solve_imas_baseline()", + "file": "bouquet/run.py", + "line": 519, + "desc": "IMAS forward GS solve: jphi-linterp + thermal/fast pressure. Recompute j_BS via SWB. Apply jBS_baseline_mode logic (diff vs rescale). Set l_i_target to TokaMaker li_1.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run._repoint_imas_geometry", + "type": "transform", + "label": "_repoint_imas_geometry()", + "file": "bouquet/run.py", + "line": 390, + "desc": "Multi-slice IMAS: re-read THIS slice's boundary, re-point solver isoflux, reset coil reg/bounds. Called per slice via set_slice+prepare_baseline.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run._resolve_workflow_preset", + "type": "transform", + "label": "resolve workflow preset", + "file": "bouquet/run.py", + "line": 788, + "desc": "map workflow auto/geqdsk-standard/imas-diff-c/custom to per-path flags", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run._validate_workflow", + "type": "decision", + "label": "_validate_workflow()", + "file": "bouquet/run.py", + "line": 771, + "desc": "Guard: enforce validated per-path workflow. Geqdsk path: no Fix C (perturb_jind_in_anchor=False). IMAS path: Fix C required (True) + jBS_baseline_mode in ('diff','rescale').", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.coil_vsc dict unpacked into solve_with_bootstrap", + "type": "transform", + "label": "coil_vsc dict unpacked into solve_with_bootstrap", + "file": "bouquet/run.py", + "line": 325, + "desc": "coil_vsc dict unpacked into solve_with_bootstrap", + "subsystem": "Configuration" + }, + { + "id": "fn.run.compute_via_swb", + "type": "transform", + "label": "compute_via_swb", + "file": "bouquet/run.py", + "line": 600, + "desc": "if config.generation.recalculate_j_BS: j_BS = compute_via_sw", + "subsystem": "Configuration" + }, + { + "id": "fn.run.eq.j_tor - cp.j_tor", + "type": "transform", + "label": "eq.j_tor - cp.j_tor", + "file": "bouquet/run.py", + "line": 650, + "desc": "if config.generation.anchor_jtor_to_equilibrium: jphi_diff =", + "subsystem": "Configuration" + }, + { + "id": "fn.run.eq.pressure - p_recon", + "type": "transform", + "label": "eq.pressure - p_recon", + "file": "bouquet/run.py", + "line": 820, + "desc": "if config.generation.anchor_pressure_to_equilibrium: p_diff ", + "subsystem": "Configuration" + }, + { + "id": "fn.run.export", + "type": "transform", + "label": "export()", + "file": "bouquet/run.py", + "line": 1071, + "desc": "Write pruned HDF5 with selected draws only (default {header}_selected.h5).", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.fc.j_NBI or zeros_on_psi_N", + "type": "transform", + "label": "fc.j_NBI or zeros_on_psi_N", + "file": "bouquet/run.py", + "line": 550, + "desc": "j_NBI = fc.j_NBI or zeros_on_psi_N", + "subsystem": "Configuration" + }, + { + "id": "fn.run.fc.j_RF or zeros_on_psi_N", + "type": "transform", + "label": "fc.j_RF or zeros_on_psi_N", + "file": "bouquet/run.py", + "line": 551, + "desc": "j_RF = fc.j_RF or zeros_on_psi_N", + "subsystem": "Configuration" + }, + { + "id": "fn.run.fc.p_fast or compute_p_fast_from_source", + "type": "transform", + "label": "fc.p_fast or compute_p_fast_from_source", + "file": "bouquet/run.py", + "line": 545, + "desc": "p_fast = fc.p_fast or compute_p_fast_from_source(...)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.fc.psi_N or source_psi_N", + "type": "transform", + "label": "fc.psi_N or source_psi_N", + "file": "bouquet/run.py", + "line": 555, + "desc": "psi_N_kinetic = fc.psi_N or source_psi_N", + "subsystem": "Configuration" + }, + { + "id": "fn.run.filter", + "type": "transform", + "label": "filter()", + "file": "bouquet/run.py", + "line": 1007, + "desc": "Apply coil + boundary filters. Non-destructive: writes pass flags into HDF5. Returns summary dict.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.generate", + "type": "transform", + "label": "generate()", + "file": "bouquet/run.py", + "line": 826, + "desc": "Main generation loop: call generate_bouquet with baseline + uncertainty envelope. Auto-center jBS_scale_range by bs_scale. Write HDF5 archive + provenance.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.ida_path", + "type": "transform", + "label": "ida_path", + "file": "bouquet/run.py", + "line": 132, + "desc": "cfg.uncertainty.ida_path = ida_path", + "subsystem": "Configuration" + }, + { + "id": "fn.run.if config.generation.diagnostic_plots: plot_diagnostics", + "type": "transform", + "label": "if config.generation.diagnostic_plots: plot_diagnostics", + "file": "bouquet/run.py", + "line": 900, + "desc": "if config.generation.diagnostic_plots: plot_diagnostics(...)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind", + "type": "transform", + "label": "if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind", + "file": "bouquet/run.py", + "line": 640, + "desc": "if config.generation.perturb_jind_in_anchor: apply_gpr_to_an", + "subsystem": "Configuration" + }, + { + "id": "fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow", + "type": "transform", + "label": "if not config.generation.allow_unsafe_workflow: validate_workflow", + "file": "bouquet/run.py", + "line": 750, + "desc": "if not config.generation.allow_unsafe_workflow: validate_wor", + "subsystem": "Configuration" + }, + { + "id": "fn.run.int", + "type": "transform", + "label": "int", + "file": "bouquet/run.py", + "line": 851, + "desc": "n_equils = int(n if n is not None else gc.n_equils)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.isoflux_pts or eqdsk.isoflux_pts", + "type": "transform", + "label": "isoflux_pts or eqdsk.isoflux_pts", + "file": "bouquet/run.py", + "line": 322, + "desc": "isoflux_pts or eqdsk.isoflux_pts", + "subsystem": "Configuration" + }, + { + "id": "fn.run.isoflux_weights or np.ones", + "type": "transform", + "label": "isoflux_weights or np.ones", + "file": "bouquet/run.py", + "line": 323, + "desc": "isoflux_weights or np.ones(len(isoflux_pts))", + "subsystem": "Configuration" + }, + { + "id": "fn.run.isolate_edge_jBS", + "type": "transform", + "label": "isolate_edge_jBS", + "file": "bouquet/run.py", + "line": 605, + "desc": "j_BS = isolate_edge_jBS(j_BS, mode=config.generation.isolate", + "subsystem": "Configuration" + }, + { + "id": "fn.run.load_gs_mesh", + "type": "transform", + "label": "load_gs_mesh", + "file": "bouquet/run.py", + "line": 309, + "desc": "load_gs_mesh(sc.mesh_path)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.np.maximum", + "type": "transform", + "label": "np.maximum", + "file": "bouquet/run.py", + "line": 615, + "desc": "if config.generation.floor_j_BS: j_BS = np.maximum(j_BS, 0)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.prepare_baseline", + "type": "transform", + "label": "prepare_baseline()", + "file": "bouquet/run.py", + "line": 426, + "desc": "Delegate to resolve_baseline (dispatch on source type). For IMAS: call _forward_solve_imas_baseline. Returns Baseline (j_phi, j_ind, j_BS, Ip_target, l_i_target, kinetics).", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.read_geqdsk", + "type": "transform", + "label": "read_geqdsk", + "file": "bouquet/run.py", + "line": 319, + "desc": "eqdsk_ref = read_geqdsk(src.geqdsk_path, cocos=src.cocos)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.resolve_workflow_from_preset", + "type": "transform", + "label": "resolve_workflow_from_preset", + "file": "bouquet/run.py", + "line": 745, + "desc": "resolve_workflow_from_preset(config.generation.workflow)", + "subsystem": "Configuration" + }, + { + "id": "fn.run.run", + "type": "transform", + "label": "run() [convenience]", + "file": "bouquet/run.py", + "line": 1084, + "desc": "Orchestrator: setup_solver \u2192 prepare_baseline \u2192 generate \u2192 filter \u2192 export. Idempotent on early stages.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.run_slices", + "type": "transform", + "label": "run_slices()", + "file": "bouquet/run.py", + "line": 1102, + "desc": "IMAS sweep: setup_solver once, then for each time: set_slice \u2192 prepare_baseline \u2192 generate \u2192 filter. One archive, one scan_key per slice.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.set_slice", + "type": "transform", + "label": "set_slice()", + "file": "bouquet/run.py", + "line": 249, + "desc": "Multi-slice IMAS: re-point time, clear baseline/uncertainty/diagnostics cache. Next prepare_baseline calls _repoint_imas_geometry for the new slice.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.setup_solver", + "type": "transform", + "label": "setup_solver()", + "file": "bouquet/run.py", + "line": 283, + "desc": "Read mesh, build regions, stand up mygs, set isoflux + VSC + coil reg. Idempotent. Captures pristine post-setup equilibrium for multi-slice reset. Sets F0 from g-file or IDS.", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "fn.run.store_equilibrium", + "type": "transform", + "label": "store_equilibrium", + "file": "bouquet/run.py", + "line": 890, + "desc": "store_equilibrium(..., scan_key=gc.scan_key, ...)", + "subsystem": "Configuration" + }, + { + "id": "fn.sampling.calc_cylindrical_li_proxy", + "type": "transform", + "label": "calc_cylindrical_li_proxy", + "file": "bouquet/sampling.py", + "line": 527, + "desc": "Compute cylindrical li proxy from j_phi profile", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.sampling.generate_perturbed_GPR", + "type": "transform", + "label": "generate_perturbed_GPR (GPR sampling)", + "file": "bouquet/sampling.py", + "line": 253, + "desc": "Draw one GPR sample from N(baseline, Cov) where Cov depends on length_scale; returns 1-D profile matching input grid/magnitude", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "fn.schema.find_bytes_dataset", + "type": "transform", + "label": "find_bytes_dataset(grp, kind)", + "file": "bouquet/schema.py", + "line": 54, + "desc": "Locate eqdsk/pfile bytes by schema-v2 fixed name or pre-v2 suffix scan", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.schema.write_profile", + "type": "transform", + "label": "write_profile(grp, name, data)", + "file": "bouquet/schema.py", + "line": 72, + "desc": "Create dataset with unit attr from PROFILE_UNITS dict", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.tmi.Ip_flux_integral_vs_target", + "type": "transform", + "label": "Ip_flux_integral_vs_target (root-find target)", + "desc": "Function argument for scipy root_scalar; returns Ip(scale) - Ip_target", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.tmi._corrective_jphi_iteration", + "type": "transform", + "label": "_corrective_jphi_iteration (residual refinement)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2050, + "desc": "Iterate TokaMaker forward solves until output j_phi matches intended target_jphi", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "fn.tmi._kin_to_eq", + "type": "transform", + "label": "_kin_to_eq (kinetic grid \u2192 equilibrium grid)", + "line": 898, + "desc": "Inline helper; interpolates profiles from psi_kin to psi_N", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.tmi._shelf_blend_decompose", + "type": "transform", + "label": "_shelf_blend_decompose", + "file": "bouquet/TokaMaker_interface.py", + "line": 319, + "desc": "Decompose j_phi into j_ind + spike via Hermite edge bridge", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.tmi._swb_jbs_to_toroidal", + "type": "transform", + "label": "_swb_jbs_to_toroidal", + "file": "bouquet/TokaMaker_interface.py", + "line": 660, + "desc": "Convert solve_with_bootstrap parallel j_BS to toroidal convention", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.tmi._vsc_channel_drift_pct", + "type": "transform", + "label": "VSC drift (common-mode + differential, quadrature sigma)", + "file": "bouquet/TokaMaker_interface.py", + "line": 283, + "desc": "F9A/F9B in-spec drift %% via error-propagated sigma; robust to near-zero coil or channel baseline", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "fn.tmi.calc_cylindrical_li_proxy", + "type": "transform", + "label": "calc_cylindrical_li_proxy (fast proxy)", + "line": 1163, + "desc": "Cheap cylindrical l_i estimate; adaptive proxy-target feedback", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.tmi.calc_realgeom_li_proxy_fast", + "type": "transform", + "label": "calc_realgeom_li_proxy_fast (real-geom pre-screen)", + "line": 1949, + "desc": "Real-geometry l_i proxy for draw pre-screening", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.tmi.classify_jphi_profile", + "type": "transform", + "label": "classify_jphi_profile", + "file": "bouquet/TokaMaker_interface.py", + "line": 145, + "desc": "Classify j_phi edge profile (H/L mode) by spike detection", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.tmi.find_optimal_scale", + "type": "transform", + "label": "find_optimal_scale (SWB OFT import)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1990, + "desc": "Inverse GS solve to scale j0 and output j_phi to match Ip target", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "fn.tmi.fit_inductive_profile", + "type": "transform", + "label": "fit_inductive_profile", + "file": "bouquet/TokaMaker_interface.py", + "line": 474, + "desc": "Fit smooth inductive profile with spline, scale for li proxy match", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.tmi.generate_bouquet", + "type": "transform", + "label": "generate_bouquet (batch driver)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2248, + "desc": "Batch orchestrator for perturbed-equilibrium draws; manages RNG seed, baseline solve, coil bounds, DIFF_BS cache, draw loop, storage", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "fn.tmi.generate_perturbed_GPR", + "type": "transform", + "label": "generate_perturbed_GPR (external import)", + "desc": "GPR sampling on kinetic grid; returns perturbed profile", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "fn.tmi.get_li_proxy_geometry", + "type": "transform", + "label": "get_li_proxy_geometry (real-geom prescreen)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1815, + "desc": "Build real-geometry l_i proxy (L_p) from flux-surface perimeters", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "fn.tmi.perturb_kinetic_equilibrium", + "type": "transform", + "label": "perturb_kinetic_equilibrium (core loop)", + "file": "bouquet/TokaMaker_interface.py", + "line": 698, + "desc": "Iterative kinetic profile perturbation \u2192 pressure matching \u2192 (optional SWB/PIN_JPHI/DIFF_BS) \u2192 l_i band-conditioning loop \u2192 return perturbed kinetics + j_phi", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "fn.tmi.recon_anchor_solve", + "type": "transform", + "label": "recon-anchor forward solve", + "file": "bouquet/TokaMaker_interface.py", + "line": 1616, + "desc": "Set perturbed pressure + pinned/delta/standard j_phi, solve GS to establish baseline geometry", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "fn.tmi.reconstruct_equilibrium", + "type": "transform", + "label": "reconstruct_equilibrium", + "file": "bouquet/TokaMaker_interface.py", + "line": 4320, + "desc": "Main driver: orchestrates full GS reconstruction workflow", + "subsystem": "GS reconstruction" + }, + { + "id": "fn.utils.capture_native_output", + "type": "transform", + "label": "capture_native_output (fd redirect)", + "file": "bouquet/utils.py", + "line": 17, + "desc": "suppress native solver stdout/stderr via os.dup2; used by generate() and run_shard", + "subsystem": "Process-parallel path" + }, + { + "id": "fn.utils.discover_scan_keys", + "type": "transform", + "label": "discover_scan_keys(h5path_or_header)", + "file": "bouquet/utils.py", + "line": 854, + "desc": "List all scan-point keys or None if flat layout", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.initialize_equilibrium_database", + "type": "transform", + "label": "initialize_equilibrium_database(header)", + "file": "bouquet/utils.py", + "line": 251, + "desc": "Create HDF5 file, stamp schema_version/bouquet_version/created attrs", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.list_equilibrium_indices", + "type": "transform", + "label": "list_equilibrium_indices(h5path, scan_key)", + "file": "bouquet/utils.py", + "line": 902, + "desc": "Return sorted list of stored draw indices (gap-tolerant)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.load_baseline_profiles", + "type": "transform", + "label": "load_baseline_profiles(h5path, scan_key)", + "file": "bouquet/utils.py", + "line": 932, + "desc": "Read baseline dict: all stored profiles, sigmas, scalars (Ip_target, l_i_target)", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.load_config", + "type": "transform", + "label": "load_config(h5path, scan_key)", + "file": "bouquet/utils.py", + "line": 322, + "desc": "Read config_json from archive, prioritize per-scan copy", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.load_equilibrium", + "type": "transform", + "label": "load_equilibrium(header, count, scan_key, eqdsk_out_dir)", + "file": "bouquet/utils.py", + "line": 598, + "desc": "Read one perturbed draw: eqdsk_bytes, profiles, l_i*, optional coil_currents/Zeff", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "fn.utils.store_baseline_profiles", + "type": "transform", + "label": "store_baseline_profiles (baseline save)", + "file": "bouquet/utils.py", + "line": 1, + "desc": "Archive baseline (recon) profiles, uncertainties, equilibrium reference to HDF5 _baseline group (once per generate_bouquet)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "fn.utils.store_equilibrium", + "type": "transform", + "label": "store_equilibrium (per-draw save)", + "file": "bouquet/utils.py", + "line": 1, + "desc": "Archive accepted draw to HDF5: perturbed profiles, j_phi, diagnostics (l_i, Ip, boundary, coil currents)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "fn.utils.write_provenance", + "type": "transform", + "label": "write_provenance(h5path, config, scan_key)", + "file": "bouquet/utils.py", + "line": 287, + "desc": "Stamp file-level attrs (updated) and config_json dataset at root/scan level", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "gate.anchor_jtor", + "type": "decision", + "label": "j_tor anchor decision", + "file": "bouquet/io/imas.py", + "line": 412, + "desc": "if anchor_jtor_to_equilibrium=True: compute jphi_diff; else jphi_diff=None", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "gate.anchor_pressure", + "type": "decision", + "label": "Pressure anchor decision", + "file": "bouquet/io/imas.py", + "line": 395, + "desc": "if anchor_pressure_to_equilibrium=True: compute p_diff; else p_diff=None", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "gate.backend", + "type": "decision", + "label": "backend decision", + "file": "bouquet/parallel.py", + "line": "349", + "desc": "Route to laptop/slurm based on backend param", + "subsystem": "Process-parallel path" + }, + { + "id": "gate.baseline_match_laptop", + "type": "decision", + "label": "baseline consistency check (laptop)", + "file": "bouquet/parallel.py", + "line": "440", + "desc": "Cross-worker check: all workers converge to same li/Ip targets within rtol", + "subsystem": "Process-parallel path" + }, + { + "id": "gate.baseline_match_merge", + "type": "decision", + "label": "baseline consistency check (merge)", + "file": "bouquet/parallel.py", + "line": "236", + "desc": "Pre-pass in merge_archives: shard existence + cross-shard baseline drift detection", + "subsystem": "Process-parallel path" + }, + { + "id": "gate.boundary_rms", + "type": "decision", + "label": "Boundary RMS/max pass/fail", + "file": "bouquet/filtering.py", + "line": 352, + "desc": "ok_rms && ok_max: RMS <= rms_thr && max <= max_thr", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "gate.coil_spec", + "type": "decision", + "label": "Coil-spec pass/fail", + "file": "bouquet/filtering.py", + "line": 308, + "desc": "ok_F && ok_V: F <= fthr && V <= vthr", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "gate.constrain_sawteeth_post", + "type": "decision", + "label": "Post-check q_0 < 1 (final reject)", + "line": 2018, + "desc": "After corrective iteration", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.constrain_sawteeth_pre", + "type": "decision", + "label": "Pre-check q_0 < 1 (early reject)", + "line": 2000, + "desc": "Before more expensive Ip scaling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.diff_bs_branch", + "type": "decision", + "label": "DIFF_BS differential-bootstrap branch", + "line": 1227, + "desc": "Restore snapshot, call SWB on perturbed, subtract cache, add delta to input_j_phi", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.draw_accepted", + "type": "decision", + "label": "gate.draw_accepted (final acceptance)", + "file": "bouquet/TokaMaker_interface.py", + "line": 3354, + "desc": "Draw passes all gates (li_band, sawteeth_q0, solve_failed) \u2192 increment accepted count, store_equilibrium, update proxy_bias", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "gate.fixed_components", + "type": "decision", + "label": "Fixed component overrides", + "file": "bouquet/io/imas.py", + "line": 363, + "desc": "if fixed is not None: apply overrides to p_fast, j_NBI, j_RF", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "gate.homotopy_early_stop", + "type": "decision", + "label": "next pass already infeasible?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3928, + "desc": "skip tighter pass when natural drift exceeds its bound (avoids futile maxits solve)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.homotopy_feasible", + "type": "decision", + "label": "homotopy pass converged?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3826, + "desc": "per tighter pass: snapshot psi/coils on success; rollback to last good on infeasibility", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.ida_layout", + "type": "decision", + "label": "IDA layout (direct vs ensemble)?", + "file": "bouquet/io/ida.py", + "line": 159, + "desc": "Inspect f['n_e'].shape.size: 2 -> direct (2-D + *_err); 3 -> ensemble (posterior samples)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "gate.in_spec_verdict", + "type": "decision", + "label": "in-spec verdict", + "file": "bouquet/TokaMaker_interface.py", + "line": 3995, + "desc": "max_F_drift<=inspec_F_max AND VSC drift (via _vsc_channel_drift_pct) <= inspec_VSC_max", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.incomplete_pressure", + "type": "decision", + "label": "Pressure completeness check", + "file": "bouquet/io/imas.py", + "line": 398, + "desc": "Skip validation if kinetic_source='ida_hybrid'; else validate thermal+fast", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "gate.ip_sanity", + "type": "decision", + "label": "Ip convergence check", + "file": "bouquet/run.py", + "line": 684, + "desc": "Verify forward solve landed within 1% of Ip_target; warn if not (li_target may be unreliable)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "gate.iso_update", + "type": "decision", + "label": "re-point isoflux to perturbed LCFS?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3677, + "desc": "after Ip alignment, trace LCFS at 1-psi_pad and update isoflux targets (unless SKIP_ISO)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.jBS_baseline_mode", + "type": "decision", + "label": "jBS_baseline_mode (diff vs rescale)", + "file": "bouquet/run.py", + "line": 647, + "desc": "Branch: reconcile FUSE/source bootstrap vs OFT SWB. 'diff' = fixed FUSE total + SWB delta. 'rescale' = rescale SWB to match FUSE l_i (self-consistent)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "gate.j_inductive_decomposition", + "type": "decision", + "label": "j_inductive storage logic (isolate_edge_jBS)", + "line": 2158, + "desc": "True=closing_decomp (spike+shelf blend); False=residual", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.jphi_classified", + "type": "decision", + "label": "gate.jphi_classified", + "file": "bouquet/TokaMaker_interface.py", + "line": 4713, + "desc": "Branch on jphi_mode (H_mode, Lmode_like_jphi, L_mode)", + "subsystem": "GS reconstruction" + }, + { + "id": "gate.kinetic_source", + "type": "decision", + "label": "Kinetic source selection", + "file": "bouquet/io/imas.py", + "line": 355, + "desc": "if kinetic_source='ida_hybrid': swap ne/Te/Ti from IDA; else use FUSE", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "gate.li_acceptance", + "type": "decision", + "label": "l_i band acceptance gate", + "line": 1896, + "desc": "Accept draw if |l_i - l_i_target| / l_i_target <= tolerance", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.li_band", + "type": "decision", + "label": "gate.li_band (l_i acceptance)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1896, + "desc": "Accept draw iff |l_i - l_i_target_draw| / l_i_target_draw <= l_i_tolerance; reject triggers rejection sampling", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "gate.li_band_loop", + "type": "decision", + "label": "l_i band-conditioning loop (rejection sampling)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1893, + "desc": "Iterate: GPR-draw j_phi, pre-screen, find_optimal_scale, corrective, accept if l_i in band", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.li_converged", + "type": "decision", + "label": "gate.li_converged", + "file": "bouquet/TokaMaker_interface.py", + "line": 4612, + "desc": "Test |li_current - li_target| < li_tol; loop control for secant iteration", + "subsystem": "GS reconstruction" + }, + { + "id": "gate.li_loop_variant", + "type": "decision", + "label": "l_i match strategy gate", + "line": 1750, + "desc": "PIN_JPHI/DIFF_BS short-circuit | perturb_jind_in_anchor accept | standard band-conditioning loop", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.li_target_sample", + "type": "decision", + "label": "sample per-draw l_i target?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3361, + "desc": "l_i_uncertainty>0: draw target from N(l_i_target, sigma); else use recon target exactly", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "gate.missing_shards", + "type": "decision", + "label": "missing shards handling (CLI)", + "file": "bouquet/parallel.py", + "line": "587", + "desc": "Check expected shards exist; abort or allow-missing per flag", + "subsystem": "Process-parallel path" + }, + { + "id": "gate.perturb_jind_in_anchor_loop", + "type": "decision", + "label": "Fix-C resample loop (perturb_jind_in_anchor)", + "line": 1652, + "desc": "If enabled, GPR-resample j_ind until anchor l_i in band", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.pin_jphi_branch", + "type": "decision", + "label": "PIN_JPHI diagnostic branch", + "line": 1153, + "desc": "Bypass SWB entirely, use recon j_phi as fixed FF' shape", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.post_align_failed", + "type": "decision", + "label": "post-alignment failure?", + "file": "bouquet/TokaMaker_interface.py", + "line": 4007, + "desc": "iso-update/homotopy/in-spec exception -> reset to baseline, reject draw", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.pressure_match", + "type": "decision", + "label": "pressure-match loop", + "file": "bouquet/TokaMaker_interface.py", + "line": 959, + "desc": "Iterate GPR-perturbed kinetics until

error within tolerance", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.profile_file_type", + "type": "decision", + "label": "Profile file type?", + "file": "bouquet/config.py", + "line": -1, + "desc": "Dispatch: IDA .cdf vs p-file based on file extension or explicit config.kinetic_source", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "gate.qp_saturation", + "type": "decision", + "label": "QP saturated at coil bound?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3864, + "desc": "max coil drift >= 0.99x bound = active constraint -> treat as infeasible (rollback/reject)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.recalculate_jBS", + "type": "decision", + "label": "Bootstrap recalculation gate", + "line": 1153, + "desc": "PIN_JPHI | DIFF_BS | standard SWB branch", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.sawteeth_q0", + "type": "decision", + "label": "gate.sawteeth_q0 (q0 constraint)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2020, + "desc": "If constrain_sawteeth=True: reject draw iff q0 < 1.0 after find_optimal_scale (pre-check at line 2002)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "gate.selected", + "type": "decision", + "label": "selected (AND of filters)", + "file": "bouquet/filtering.py", + "line": 100, + "desc": "AND of passes_coil_filter & passes_boundary_filter; True if no filter applied", + "subsystem": "Archive, filtering & plotting" + }, + { + "id": "gate.sigma_priority_ne", + "type": "decision", + "label": "ne sigma priority: explicit | IDA | scalar", + "file": "bouquet/baseline.py", + "line": 220, + "desc": "Resolve ne sigma: sigma_profiles['ne'] > IDA read_ida > ne_scalar_sigma*|ne|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.sigma_priority_ni", + "type": "decision", + "label": "ni sigma priority: explicit | IDA | scalar", + "file": "bouquet/baseline.py", + "line": 220, + "desc": "Resolve ni sigma: sigma_profiles['ni'] > IDA read_ida > ni_scalar_sigma*|ni|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.sigma_priority_te", + "type": "decision", + "label": "te sigma priority: explicit | IDA | scalar", + "file": "bouquet/baseline.py", + "line": 220, + "desc": "Resolve te sigma: sigma_profiles['te'] > IDA read_ida > te_scalar_sigma*|te|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.sigma_priority_ti", + "type": "decision", + "label": "ti sigma priority: explicit | IDA | scalar", + "file": "bouquet/baseline.py", + "line": 220, + "desc": "Resolve ti sigma: sigma_profiles['ti'] > IDA read_ida > ti_scalar_sigma*|ti|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.sigma_priority_zeff", + "type": "decision", + "label": "zeff sigma priority: explicit | default auto-inject", + "file": "bouquet/baseline.py", + "line": 257, + "desc": "Zeff auto-enabled (consistency density scheme): aux_sigmas['zeff'] > zeff_scalar_sigma*|Zeff|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.skip_hard_bounds_env", + "type": "decision", + "label": "SKIP_HARD env?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3645, + "desc": "diagnostic: skip iso-update + homotopy entirely (recon isoflux kept)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.skip_homotopy_env", + "type": "decision", + "label": "SKIP_HOMOTOPY env?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3653, + "desc": "diagnostic: bypass coil-bound tightening (iso-update still runs)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.skip_iso_env", + "type": "decision", + "label": "SKIP_ISO env?", + "file": "bouquet/TokaMaker_interface.py", + "line": 3648, + "desc": "diagnostic: disable iso-update under hard bounds (isolates iso-shift effect)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "id": "gate.solve_failed", + "type": "decision", + "label": "gate.solve_failed (solver convergence)", + "file": "bouquet/TokaMaker_interface.py", + "line": 3354, + "desc": "Catch-all try/except at per-draw level: solver maxits, other RuntimeError \u2192 skip draw, increment failed count", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "gate.source_type", + "type": "decision", + "label": "source type: ImasSource | ReconstructionSource", + "file": "bouquet/baseline.py", + "line": 159, + "desc": "Branch on isinstance(source, ImasSource|ReconstructionSource)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "gate.standard_swb_branch", + "type": "decision", + "label": "Standard SWB branch", + "line": 1308, + "desc": "Full solve_with_bootstrap + recon-anchor + l_i loop", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.threads_warn", + "type": "decision", + "label": "threads_per_worker > 1 warning", + "file": "bouquet/parallel.py", + "line": "96", + "desc": "Emit warning if nthreads > 1 (breaks determinism, risks DLSODE hangs)", + "subsystem": "Process-parallel path" + }, + { + "id": "gate.time_index", + "type": "decision", + "label": "Select time slice", + "file": "bouquet/io/ida.py", + "line": 88, + "desc": "If IDA file has multiple time slices, find nearest to requested time_s", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "gate.workflow_guard", + "type": "decision", + "label": "workflow validation gate", + "file": "bouquet/run.py", + "line": 815, + "desc": "Enforces jBS_baseline_mode + perturb_jind_in_anchor consistency per source type. Raises unless allow_unsafe_workflow=True (warns instead).", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "id": "gate.zeff_active", + "type": "decision", + "label": "Zeff-primary channel active", + "line": 942, + "desc": "aux_sigmas and aux_baselines carry 'zeff' entry", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "gate.zeff_channel_enable", + "type": "decision", + "label": "zeff channel enabled (when zeff_scalar_sigma>0)", + "file": "bouquet/baseline.py", + "line": 258, + "desc": "Zeff channel enabled by default for EVERY source (consistent density); user can disable", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "id": "input.config", + "type": "input", + "label": "BouquetConfig", + "file": "bouquet/parallel.py", + "line": "323", + "desc": "Run-level configuration passed to parallel_generate; defines n_equils, seed, source, output header", + "subsystem": "Process-parallel path" + }, + { + "id": "input.efit01_gfile", + "type": "input", + "label": "EFIT01 g-file (optional)", + "file": "bouquet/io/imas.py", + "line": 118, + "desc": "Magnetics-only LCFS boundary, preferred over FUSE dd boundary outline", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "input.eqdsk", + "type": "input", + "label": "EQDSK geqdsk equilibrium", + "file": "bouquet/TokaMaker_interface.py", + "line": 4320, + "desc": "geqdsk reference with j_tor, Ip, li(1), psi_N, boundary", + "subsystem": "GS reconstruction" + }, + { + "id": "input.gfile", + "type": "input", + "label": "G-file (GEQDSK)", + "file": "bouquet/io/geqdsk.py", + "line": 64, + "desc": "EFIT equilibrium: PSIRZ grid, FPOL, PRES, PPRIME, FFPRIM, QPSI, boundary RBBBS/ZBBBS, limiter", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "input.ida_cdf", + "type": "input", + "label": "IDA .cdf (netCDF/HDF5)", + "file": "bouquet/io/ida.py", + "line": 101, + "desc": "2-D (n_time, n_radial) or 3-D (n_time, n_samples, n_radial) kinetic profiles + *_err uncertainty", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "input.ida_cer", + "type": "input", + "label": "IDA CER channels (carbon)", + "file": "bouquet/io/ida.py", + "line": 213, + "desc": "Impurity n_12C6, T_12C6, omega_tor, v_pol + Bpol/Rmaj geometry for E_r balance", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "input.imas_ids", + "type": "input", + "label": "IMAS IDS (dd_sim.json)", + "file": "bouquet/io/imas.py", + "line": 259, + "desc": "FUSE-written IMAS data dictionary JSON (equilibrium + core_profiles + core_sources)", + "subsystem": "IMAS/OMAS reader" + }, + { + "id": "input.isoflux", + "type": "input", + "label": "Isoflux constraint points & weights", + "file": "bouquet/TokaMaker_interface.py", + "line": 4359, + "desc": "(R,Z) coordinates and weights for LCFS boundary", + "subsystem": "GS reconstruction" + }, + { + "id": "input.kinetics", + "type": "input", + "label": "Kinetic profiles (ne, te, ni, ti, Zeff)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4349, + "desc": "Electron/ion density & temperature on eqdsk.psi_N", + "subsystem": "GS reconstruction" + }, + { + "id": "input.mygs", + "type": "input", + "label": "TokaMaker GS solver", + "file": "bouquet/TokaMaker_interface.py", + "line": 4344, + "desc": "Initialized with mesh, regions, coils", + "subsystem": "GS reconstruction" + }, + { + "id": "input.pfile", + "type": "input", + "label": "P-file (Osborne profiles)", + "file": "bouquet/io/pfile.py", + "line": 96, + "desc": "Kinetic profiles on psinorm: ne, te, ni, ti, omeg, optional ion species (N Z A)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "input.user_args", + "type": "input", + "label": "CLI/user args", + "file": "bouquet/parallel.py", + "line": "559", + "desc": "User invokes via parallel_generate() or CLI (_cli); specifies backend, n_workers, seed, threads_per_worker", + "subsystem": "Process-parallel path" + }, + { + "id": "knob.backend", + "type": "knob", + "label": "backend", + "file": "bouquet/parallel.py", + "line": "349", + "desc": "Either 'laptop' (ProcessPoolExecutor) or 'slurm' (emit scripts)", + "subsystem": "Process-parallel path" + }, + { + "id": "knob.n_workers", + "type": "knob", + "label": "n_workers", + "file": "bouquet/parallel.py", + "line": "345", + "desc": "Defaults to _physical_cores(); capped to min(n_workers, n_equils)", + "subsystem": "Process-parallel path" + }, + { + "id": "knob.scan_key", + "type": "knob", + "label": "scan_key", + "file": "bouquet/parallel.py", + "line": "159", + "desc": "Optional slice identifier; folds into SeedSequence to decorrelate multi-slice draws", + "subsystem": "Process-parallel path" + }, + { + "id": "knob.seed", + "type": "knob", + "label": "seed", + "file": "bouquet/parallel.py", + "line": "416", + "desc": "Entropy seed passed to _derive_seed(seed_base, worker_id, scan_key)", + "subsystem": "Process-parallel path" + }, + { + "id": "knob.threads_per_worker", + "type": "knob", + "label": "threads_per_worker", + "file": "bouquet/parallel.py", + "line": "357", + "desc": "Solver nthreads per worker; must be 1 for determinism (bit-identical baseline)", + "subsystem": "Process-parallel path" + }, + { + "id": "obj.GEQDSKEquilibrium", + "type": "artifact", + "label": "GEQDSKEquilibrium object", + "file": "bouquet/io/geqdsk.py", + "line": 770, + "desc": "Lazy-cached equilibrium: psi grid, fields, contours, averages, geometry, inductance", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "obj.IDACERProfiles", + "type": "artifact", + "label": "IDACERProfiles dataclass", + "file": "bouquet/io/ida.py", + "line": 60, + "desc": "Carbon density/temperature, omega_tor, v_pol, Bpol, Rmaj, dpsiN_dR, time; for E_r analysis", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "obj.IDAProfiles", + "type": "artifact", + "label": "IDAProfiles dataclass", + "file": "bouquet/io/ida.py", + "line": 35, + "desc": "psi_N, ne/te/ni/ti/Zeff, sigma_* envelopes, time [s]; read-only SI units", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "obj.PFile", + "type": "artifact", + "label": "PFile object", + "file": "bouquet/io/pfile.py", + "line": 211, + "desc": "Profile dict + N Z A block; accessor methods for ne/te/ni/ti/omeg/etc", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "id": "progress_callback", + "type": "transform", + "label": "progress_callback (per-draw tick)", + "file": "bouquet/TokaMaker_interface.py", + "line": 3297, + "desc": "Optional per-draw progress callback (used in process-parallel path for aggregate tqdm bar)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "id": "qty.F0", + "type": "quantity", + "label": "F0 (R*Bt poloidal function)", + "file": "bouquet/io/geqdsk.py", + "line": 920, + "desc": "FPOL profile from g-file on psi_N; defines toroidal field via Bt = F0 / R", + "subsystem": "Shared quantities" + }, + { + "id": "qty.FUSE_tot", + "type": "quantity", + "label": "FUSE_tot", + "file": "bouquet/run.py", + "line": 634, + "desc": "FUSE's total toroidal current j_tor; reference value anchored in diff mode", + "subsystem": "Shared quantities" + }, + { + "id": "qty.F_prof", + "type": "quantity", + "label": "F (flux function)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4683, + "desc": "R*B_phi from GS solution", + "subsystem": "Shared quantities" + }, + { + "id": "qty.Ip", + "type": "quantity", + "label": "Ip (plasma current)", + "line": 2086, + "desc": "From eq_stats; diagnostic", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.Ip_scales", + "type": "quantity", + "label": "Ip_scales", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.Ip_target", + "type": "quantity", + "label": "Ip_target (plasma current)", + "file": "bouquet/io/geqdsk.py", + "line": 945, + "desc": "CURRENT from g-file [A]; target for GS solver in baseline", + "subsystem": "Shared quantities" + }, + { + "id": "qty.Ip_tokamaker", + "type": "quantity", + "label": "Ip (TokaMaker output)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4683, + "desc": "Plasma current from li-matched GS solution", + "subsystem": "Shared quantities" + }, + { + "id": "qty.Z_imp", + "type": "quantity", + "label": "effective impurity charge", + "file": "bouquet/io/imas.py", + "line": 389, + "desc": "effective_impurity_charge(ne, ni, Zeff); single-impurity model (carbon Z=6)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.Zeff", + "type": "input", + "label": "Zeff (effective charge profile)", + "desc": "Scalar or array on psi_N; drawn per draw if aux_sigmas active", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.Zeff_eq", + "type": "quantity", + "label": "Zeff_eq", + "file": "bouquet/run.py", + "line": 869, + "desc": "Zeff interpolated to equilibrium grid psi_N (from psi_N_kinetic); clipped >= 1; consumed by solve_with_bootstrap in draws", + "subsystem": "Shared quantities" + }, + { + "id": "qty.a_optimal", + "type": "quantity", + "label": "a_optimal (Ip scale factor)", + "line": 1945, + "desc": "Root of Ip_flux_integral_vs_target; scales jphi_perturb to match Ip", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.aux.E_r", + "type": "quantity", + "label": "radial electric field", + "file": "bouquet/io/imas.py", + "line": 338, + "desc": "core_profiles.e_field.radial [V/m]; optional", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux.chi_e", + "type": "quantity", + "label": "electron thermal diffusivity", + "file": "bouquet/io/imas.py", + "line": 348, + "desc": "core_transport.model[0].profiles_1d.electrons.energy.d [m^2/s]; optional", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux.chi_i", + "type": "quantity", + "label": "ion thermal diffusivity", + "file": "bouquet/io/imas.py", + "line": 350, + "desc": "core_transport.model[0].profiles_1d.total_ion_energy.d [m^2/s]; optional", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux_baselines", + "type": "quantity", + "label": "aux_baselines dict", + "file": "bouquet/baseline.py", + "line": 281, + "desc": "Auxiliary channel baselines (on psi_N_kinetic)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux_length_scales", + "type": "quantity", + "label": "aux_length_scales (auxiliary GPR scales)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2319, + "desc": "Dict of GPR length scales for auxiliary channels {name \u2192 scalar or 1-D array}", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux_out", + "type": "quantity", + "label": "aux_out (per-draw auxiliary)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1036, + "desc": "Dict of per-draw auxiliary profiles {name \u2192 1-D perturbed profile}; includes active zeff or passive omega_tor/e_r/chi", + "subsystem": "Shared quantities" + }, + { + "id": "qty.aux_sigmas", + "type": "quantity", + "label": "aux_sigmas dict", + "file": "bouquet/baseline.py", + "line": 280, + "desc": "Auxiliary channel uncertainties (zeff, omega_tor, chi_e, chi_i, e_r, ...)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.avg_B2", + "type": "quantity", + "label": " (FSA)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4687, + "desc": "Flux-surface average of B\u00b2 from sauter_fc", + "subsystem": "Shared quantities" + }, + { + "id": "qty.avg_inv_R", + "type": "quantity", + "label": "<1/R> (FSA)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4686, + "desc": "Flux-surface average from get_q", + "subsystem": "Shared quantities" + }, + { + "id": "qty.baseline_j_BS_with_diff", + "type": "quantity", + "label": "baseline_j_BS (+ jBS_diff)", + "file": "bouquet/run.py", + "line": 903, + "desc": "Baseline bootstrap passed to generate_bouquet: j_BS + jBS_diff (diff mode) or j_BS alone (rescale/raw)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.baseline_li_proxy", + "type": "quantity", + "label": "baseline_li_proxy (cylindrical proxy l_i)", + "line": 1163, + "desc": "Cheap pre-screen for l_i in band-conditioning loop", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.boundary_lcfs", + "type": "quantity", + "label": "boundary_lcfs (separatrix contour)", + "file": "bouquet/io/geqdsk.py", + "line": 970, + "desc": "RBBBS/ZBBBS from g-file; last-closed-flux-surface polygon", + "subsystem": "Shared quantities" + }, + { + "id": "qty.bs_scale", + "type": "quantity", + "label": "bootstrap scaling factor", + "file": "bouquet/TokaMaker_interface.py", + "line": 4452, + "desc": "Optional bootstrap rescaling (1.0 if rescale_j_BS=False)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.chi_e", + "type": "quantity", + "label": "chi_e [m^2/s] (electron transport)", + "file": "bouquet/baseline.py", + "line": 111, + "desc": "Auxiliary passive profile, from user aux_baselines (FUSE lacks it)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.chi_i", + "type": "quantity", + "label": "chi_i [m^2/s] (ion transport)", + "file": "bouquet/baseline.py", + "line": 111, + "desc": "Auxiliary passive profile, from user aux_baselines (FUSE lacks it)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.coil_currents", + "type": "artifact", + "label": "Coil currents (per-draw)", + "desc": "From mygs.get_coil_currents(); stored in H5", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.diagnostics", + "type": "quantity", + "label": "diagnostics (per-draw metrics)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2089, + "desc": "Dict of per-draw observables: l_i(1), Ip, boundary, coil currents, l_i iteration count, j0_scales, Ip_scales, LCFS shift from recon", + "subsystem": "Shared quantities" + }, + { + "id": "qty.e_r", + "type": "quantity", + "label": "e_r [V/m] (radial electric field)", + "file": "bouquet/baseline.py", + "line": 111, + "desc": "Auxiliary passive profile, from user aux_baselines (FUSE lacks it)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.e_r_cer", + "type": "quantity", + "label": "E_r (radial electric field)", + "file": "bouquet/io/ida.py", + "line": 64, + "desc": "Computed from carbon CER via radial force balance; optional input for physics", + "subsystem": "Shared quantities" + }, + { + "id": "qty.eq_stats", + "type": "quantity", + "label": "eq_stats (TokaMaker equilibrium stats)", + "line": 1644, + "desc": "l_i, Ip, axis position, separatrix, etc.", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.eqdsk_j_tor", + "type": "quantity", + "label": "eqdsk j_tor (baseline)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4407, + "desc": "Toroidal current density from geqdsk [A/m\u00b2]", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ffp_prof_corr", + "type": "quantity", + "label": "FFp for GS (corrective)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4730, + "desc": "j_phi profile dict for corrective iteration input", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ffp_prof_li", + "type": "quantity", + "label": "FFp for GS (li-match)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4562, + "desc": "j_phi profile dict with current ind_factor for li-matching solve", + "subsystem": "Shared quantities" + }, + { + "id": "qty.final_jphi", + "type": "quantity", + "label": "final_jphi (find_optimal_scale output)", + "line": 1990, + "desc": "Scaled j_phi after find_optimal_scale", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.final_li_proxy", + "type": "quantity", + "label": "final_li_proxy (diagnostic cylindrical proxy)", + "line": 2097, + "desc": "Reported but NOT used for acceptance; real l_i only", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.final_scale_j0", + "type": "quantity", + "label": "final_scale_j0 (core j0 scale factor)", + "line": 1990, + "desc": "Applied to matched_jphi_perturb; Ip held natively", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.full_j_BS", + "type": "quantity", + "label": "full_j_BS (full bootstrap, physical)", + "line": 1161, + "desc": "SWB j_BS (total Sauter) or spike in isolate mode; floored if floor_j_BS; diff-corrected if jBS_diff", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.guess_j_inductive", + "type": "quantity", + "label": "guess_j_inductive", + "file": "bouquet/TokaMaker_interface.py", + "line": 4366, + "desc": "Initial inductive j_phi shape for solve_with_bootstrap", + "subsystem": "Shared quantities" + }, + { + "id": "qty.in_spec_metrics", + "type": "artifact", + "label": "In-spec boundary metrics", + "desc": "LCFS RMS, x-point shift; used by post-perturb homotopy", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.ind_factor_opt", + "type": "quantity", + "label": "ind_factor (li-converged)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4692, + "desc": "Final inductive scale from secant iteration (ind_1)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ind_scale", + "type": "quantity", + "label": "inductive scaling factor", + "file": "bouquet/TokaMaker_interface.py", + "line": 4451, + "desc": "Scale factor applied to j_inductive_basis via li proxy match", + "subsystem": "Shared quantities" + }, + { + "id": "qty.input_j_phi", + "type": "input", + "label": "input_j_phi (total j_phi baseline)", + "desc": "Recon's converged profile [A/m\u00b2], may include bootstrap if recalculate_j_BS=False", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.input_jinductive", + "type": "input", + "label": "input_jinductive (inductive j_phi component)", + "desc": "Required if recalculate_j_BS=True; recon's j_inductive_fit", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.iteration_Ips", + "type": "quantity", + "label": "iteration_Ips", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.iteration_l_is", + "type": "quantity", + "label": "iteration_l_is", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j0_scales", + "type": "quantity", + "label": "j0_scales", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jBS_diff", + "type": "quantity", + "label": "jBS_diff [A/m^2] (bootstrap correction)", + "file": "bouquet/baseline.py", + "line": 75, + "desc": "IMAS Case-B: FUSE_jBS - SWB; added to anchor baseline+draws to FUSE bootstrap", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jBS_scale_range_centered", + "type": "quantity", + "label": "jBS_scale_range (centered)", + "file": "bouquet/run.py", + "line": 888, + "desc": "Perturbed bootstrap scale range for draws: (range[0]*bs_scale, range[1]*bs_scale); centers on calibrated bs_scale from prepare_baseline", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jBS_scales", + "type": "quantity", + "label": "jBS_scales (per-draw samples)", + "file": "bouquet/TokaMaker_interface.py", + "line": 3093, + "desc": "1-D array [n_equils] of uniform random jBS scale factors in [lo, hi] range; one per draw", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS", + "type": "quantity", + "label": "j_BS (bootstrap current)", + "file": "bouquet/baseline.py", + "line": -1, + "desc": "Sauter model with full core hump + edge; set via isolate_edge_jBS flag", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_final", + "type": "quantity", + "label": "j_BS_final", + "file": "bouquet/TokaMaker_interface.py", + "line": 4743, + "desc": "Final bootstrap component (unchanged from corrective)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_isolated", + "type": "quantity", + "label": "j_BS_isolated (toroidal)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4427, + "desc": "Isolated bootstrap current after parallel\u2192toroidal conversion", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_shelved", + "type": "quantity", + "label": "j_BS after optional shelf", + "file": "bouquet/TokaMaker_interface.py", + "line": 4534, + "desc": "j_BS_isolated with optional flat shelf applied if shelf_psi_N>0", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_smoothed", + "type": "quantity", + "label": "j_BS smoothed transition", + "file": "bouquet/TokaMaker_interface.py", + "line": 4478, + "desc": "Gaussian-filtered j_BS around shelf\u2192spike transition", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_src", + "type": "quantity", + "label": "j_BS_src", + "file": "bouquet/run.py", + "line": 633, + "desc": "Source bootstrap current [A/m^2] on psi_N from FUSE/source (saved for diff-mode offset)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_BS_swb", + "type": "quantity", + "label": "j_BS from solve_with_bootstrap (parallel)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4416, + "desc": "Bootstrap current (parallel convention) before conversion", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_NBI", + "type": "quantity", + "label": "j_NBI [A/m^2] (beam-driven)", + "file": "bouquet/baseline.py", + "line": 61, + "desc": "Neutral-beam-driven current (optional, fixed per draw)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_NBI_toroidal", + "type": "quantity", + "label": "j_NBI (toroidal)", + "file": "bouquet/io/imas.py", + "line": 304, + "desc": "j_NBI_parallel converted to toroidal", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_RF", + "type": "quantity", + "label": "j_RF (RF-driven current)", + "file": "bouquet/io/imas.py", + "line": 305, + "desc": "Always zeros (internal); user supplies via FixedComponentsConfig.j_RF", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_bootstrap_parallel", + "type": "quantity", + "label": "j_bootstrap (parallel)", + "file": "bouquet/io/imas.py", + "line": 287, + "desc": "core_profiles.j_bootstrap [A/m^2] on psi_N; parallel input", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_dot_B", + "type": "quantity", + "label": " (undo SWB projection)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4688, + "desc": "j_bs_swb * F / ravgs[0]; recovers parallel current before SWB's R_avg/F", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_fixed_eff", + "type": "quantity", + "label": "j_fixed_eff (fixed additive currents)", + "line": 917, + "desc": "j_NBI + j_RF + jphi_diff, rides under every j_phi build", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.j_ind_final", + "type": "quantity", + "label": "j_ind_final", + "file": "bouquet/TokaMaker_interface.py", + "line": 4750, + "desc": "Final inductive component (j_phi_final - j_BS)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_ind_li_matched", + "type": "quantity", + "label": "j_ind (li-matched)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4692, + "desc": "ind_factor_opt * j_inductive_fit", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_inductive", + "type": "quantity", + "label": "j_inductive (ohmic current)", + "file": "bouquet/baseline.py", + "line": -1, + "desc": "Pure ohmic contribution j_phi - j_BS - j_NBI; forward decomposition", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_inductive_basis", + "type": "quantity", + "label": "j_inductive_basis (spline fit)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4611, + "desc": "Fitted inductive component before scaling (PCHIP interpolant)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_inductive_consistent", + "type": "quantity", + "label": "j_inductive_consistent (stored inductive)", + "line": 2170, + "desc": "output_jphi - spike - j_fixed (with floor/cap logic)", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.j_inductive_fit", + "type": "quantity", + "label": "j_inductive_fit (scaled)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4611, + "desc": "ind_scale * j_inductive_basis", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_ls", + "type": "quantity", + "label": "j_ls (current length scale)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2266, + "desc": "GPR correlation length for j_phi (scalar or 1-D array for non-stationary Gibbs kernel)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_nbi_parallel", + "type": "quantity", + "label": "j_NBI (parallel, summed)", + "file": "bouquet/io/imas.py", + "line": 298, + "desc": "core_sources[NBI_SOURCE_INDEX].profiles_1d.j_parallel summed over source index 2", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_ohmic_parallel", + "type": "quantity", + "label": "j_ohmic (parallel, unused)", + "file": "bouquet/io/imas.py", + "line": 286, + "desc": "core_profiles.j_ohmic [A/m^2] on psi_N; baseline read but NOT used directly", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi", + "type": "quantity", + "label": "j_phi (toroidal current density)", + "file": "bouquet/io/geqdsk.py", + "line": 1622, + "desc": "Flux-surface-averaged Jt from GS equation via (p' + FF'/mu0); baseline current", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_corrective_target", + "type": "quantity", + "label": "j_phi_corrective_target", + "file": "bouquet/TokaMaker_interface.py", + "line": 4725, + "desc": "j_ind_li + j_BS_isolated for corrective iteration", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_diff_mode", + "type": "quantity", + "label": "j_phi (diff)", + "file": "bouquet/run.py", + "line": 650, + "desc": "diff mode: total anchored to FUSE; j_phi = FUSE_tot (unchanged)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_final", + "type": "quantity", + "label": "j_phi_final", + "file": "bouquet/TokaMaker_interface.py", + "line": 4742, + "desc": "Final toroidal current density output", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_fit_prelim", + "type": "quantity", + "label": "j_phi_fit (pre-li-match)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4612, + "desc": "j_inductive_fit + bs_scale*j_BS; target for li proxy", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_output_corr", + "type": "quantity", + "label": "j_phi_output (corrective)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4729, + "desc": "TokaMaker output j_phi after adaptive corrective iteration", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_phi_rescale_mode", + "type": "quantity", + "label": "j_phi (rescale)", + "file": "bouquet/run.py", + "line": 666, + "desc": "rescale mode: total rebuilt from rescaled SWB; j_phi = j_ind + scale*j_BS_swb + j_fixed", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_tor_parallel", + "type": "quantity", + "label": "j_tor (authoritative toroidal)", + "file": "bouquet/io/imas.py", + "line": 285, + "desc": "core_profiles.j_tor [A/m^2] on psi_N; the GS-consistent total", + "subsystem": "Shared quantities" + }, + { + "id": "qty.j_total_parallel", + "type": "quantity", + "label": "j_total (parallel)", + "file": "bouquet/io/imas.py", + "line": 284, + "desc": "core_profiles.j_total [A/m^2] on psi_N; parallel convention /B0", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jphi_diff", + "type": "quantity", + "label": "j_phi anchor offset", + "file": "bouquet/io/imas.py", + "line": 415, + "desc": "equilibrium.j_tor - core_profiles.j_tor; fixed offset when anchor_jtor_to_equilibrium=True", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jphi_mode", + "type": "quantity", + "label": "jphi_mode", + "file": "bouquet/TokaMaker_interface.py", + "line": 4430, + "desc": "Classification result: 'H_mode', 'Lmode_like_jphi', or 'L_mode'", + "subsystem": "Shared quantities" + }, + { + "id": "qty.jphi_perturb", + "type": "quantity", + "label": "jphi_perturb (GPR j_phi candidate)", + "line": 1929, + "desc": "One GPR sample on psi_N in li_iter", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.l_i", + "type": "quantity", + "label": "l_i (equilibrium internal inductance)", + "line": 2087, + "desc": "From eq_stats; acceptance criterion", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.l_i_target", + "type": "input", + "label": "l_i_target (internal inductance target)", + "desc": "Dimensionless", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)", + "file": "" + }, + { + "id": "qty.l_i_target_draw", + "type": "quantity", + "label": "l_i_target_draw (per-draw sample)", + "file": "bouquet/TokaMaker_interface.py", + "line": 3304, + "desc": "Per-draw internal inductance target, sampled from N(l_i_target, l_i_uncertainty*l_i_target) or pinned to l_i_target", + "subsystem": "Shared quantities" + }, + { + "id": "qty.li_current", + "type": "quantity", + "label": "li (TokaMaker output)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4577, + "desc": "Computed li(1) from GS solver for current ind_factor", + "subsystem": "Shared quantities" + }, + { + "id": "qty.li_final", + "type": "quantity", + "label": "li_final", + "file": "bouquet/TokaMaker_interface.py", + "line": 4682, + "desc": "Final internal inductance li(1) (corrective equilibrium)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.li_proxy_baseline", + "type": "quantity", + "label": "baseline li proxy", + "file": "bouquet/TokaMaker_interface.py", + "line": 4440, + "desc": "Cylindrical li(1) proxy from eqdsk_jtor", + "subsystem": "Shared quantities" + }, + { + "id": "qty.li_target", + "type": "quantity", + "label": "li_target (internal inductance)", + "file": "bouquet/io/geqdsk.py", + "line": 1679, + "desc": "Computed li(1) from flux-surface averaging; baseline internal inductance", + "subsystem": "Shared quantities" + }, + { + "id": "qty.matched_j_inductive", + "type": "quantity", + "label": "matched_j_inductive (Ip-scaled inductive)", + "line": 1718, + "desc": "input_jinductive or input_j_phi, scaled to match Ip target", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.matched_jphi_perturb", + "type": "quantity", + "label": "matched_jphi_perturb (Ip-matched j_phi candidate)", + "line": 1946, + "desc": "a_optimal * jphi_perturb + spike + j_fixed", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.n_ls", + "type": "quantity", + "label": "n_ls (density length scale)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2264, + "desc": "GPR correlation length for density profiles (scalar or 1-D Gibbs kernel)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ne", + "type": "quantity", + "label": "ne (electron density)", + "file": "bouquet/io/pfile.py", + "line": 329, + "desc": "From p-file or IDA; m^-3 (IDA) or 10^20/m^3 (p-file); on psinorm or psi_N", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ne_draw", + "type": "quantity", + "label": "ne_draw (per-draw perturb)", + "file": "bouquet/TokaMaker_interface.py", + "line": 968, + "desc": "Per-draw perturbed electron density; sampled via _draw_monotonic_perturbation(ne/ne[0], sigma_ne/ne[0], n_ls)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ne_perturb", + "type": "quantity", + "label": "ne_perturb (perturbed density)", + "file": "bouquet/TokaMaker_interface.py", + "line": 968, + "desc": "GPR-sampled electron density on psi_kin", + "subsystem": "Shared quantities" + }, + { + "id": "qty.new_jphi", + "type": "quantity", + "label": "new_jphi (total j_phi for anchor)", + "line": 1601, + "desc": "input_jinductive + spike + j_fixed (standard) or input_j_phi + delta (DIFF_BS) or pinned (PIN_JPHI)", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.ni", + "type": "quantity", + "label": "ni (main-ion density)", + "file": "bouquet/io/pfile.py", + "line": 339, + "desc": "From p-file directly or derived from (ne, Zeff) via quasineutrality in IDA", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ni_draw", + "type": "quantity", + "label": "ni_draw (per-draw perturb or derived)", + "file": "bouquet/TokaMaker_interface.py", + "line": 990, + "desc": "Per-draw ion density: DERIVED from (ne_draw, zeff_draw) via main_ion_density_from_zeff when Zeff-primary active; else sampled", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ni_perturb", + "type": "quantity", + "label": "ni_perturb (perturbed ion density)", + "line": 992, + "desc": "GPR-sampled or Zeff-derived (quasineutrality) on psi_kin", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.omega_tor", + "type": "quantity", + "label": "omega_tor (toroidal rotation)", + "file": "bouquet/io/pfile.py", + "line": 364, + "desc": "From p-file omeg or IDA omega_tor_12C6 (carbon); rad/s on kinetic grid", + "subsystem": "Shared quantities" + }, + { + "id": "qty.output_jphi", + "type": "quantity", + "label": "output_jphi (per-draw j_phi)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2050, + "desc": "Perturbed toroidal current density after corrective iteration (converged input to store_equilibrium)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_diff", + "type": "quantity", + "label": "pressure anchor offset", + "file": "bouquet/io/imas.py", + "line": 395, + "desc": "p_equilibrium - p_recon; added to baseline + every draw when anchor_pressure_to_equilibrium=True", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_equilibrium", + "type": "quantity", + "label": "equilibrium pressure", + "file": "bouquet/io/imas.py", + "line": 387, + "desc": "equilibrium.profiles_1d.pressure [Pa] interpolated onto psi_N (authoritative GS)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_fast", + "type": "quantity", + "label": "p_fast (fast-ion pressure)", + "file": "bouquet/io/pfile.py", + "line": 354, + "desc": "From p-file pb or IDA pb (if available); fast-ion contribution for fixed-component config", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_imp", + "type": "quantity", + "label": "impurity pressure", + "file": "bouquet/io/imas.py", + "line": 390, + "desc": "impurity_pressure(ne, ni, ti, Z_imp); e*nz*Ti under single-impurity quasineutrality", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_recon", + "type": "quantity", + "label": "reconstructed pressure", + "file": "bouquet/io/imas.py", + "line": 391, + "desc": "e*(ne*te + ni*ti) + p_imp + p_fast; summed thermal + impurity + fast", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_thermal", + "type": "quantity", + "label": "p_thermal (thermal pressure)", + "file": "bouquet/io/geqdsk.py", + "line": 925, + "desc": "PRES profile from g-file on psi_N; baseline thermal pressure", + "subsystem": "Shared quantities" + }, + { + "id": "qty.p_total", + "type": "quantity", + "label": "p_total", + "file": "bouquet/run.py", + "line": 555, + "desc": "Total pressure [Pa] on psi_N: e*(ne*Te + ni*Ti) + p_fast + p_diff (impurity carbon pressure added for IMAS)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.pprime", + "type": "quantity", + "label": "p' (pressure gradient)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4515, + "desc": "Gradient of pressure profile for GS equilibrium", + "subsystem": "Shared quantities" + }, + { + "id": "qty.pprime_gs", + "type": "quantity", + "label": "p' for GS", + "file": "bouquet/TokaMaker_interface.py", + "line": 4518, + "desc": "Pressure gradient dict for set_profiles", + "subsystem": "Shared quantities" + }, + { + "id": "qty.pres_tmp", + "type": "quantity", + "label": "pres_tmp (per-draw pressure)", + "file": "bouquet/TokaMaker_interface.py", + "line": 1006, + "desc": "Per-draw thermal pressure EC*(ne_eq*te_eq + ni_eq*ti_eq) + p_imp + p_fast + p_diff_anchor; target for

matching", + "subsystem": "Shared quantities" + }, + { + "id": "qty.pressure", + "type": "quantity", + "label": "pressure profile", + "file": "bouquet/TokaMaker_interface.py", + "line": 4513, + "desc": "pres_tmp = 1.6022e-19 * (ne*te + ni*ti) [Pa]", + "subsystem": "Shared quantities" + }, + { + "id": "qty.proxy_target", + "type": "quantity", + "label": "proxy_target (adaptive proxy target)", + "line": 1736, + "desc": "Corrected per iteration via Newton step on proxy-vs-equilibrium offset", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.proxy_vs_real", + "type": "quantity", + "label": "proxy_vs_real (proxy-equilibrium offset %)", + "line": 2098, + "desc": "Diagnostic; convergence aid via Newton correction", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.psi_N", + "type": "quantity", + "label": "psi_N (normalized flux)", + "file": "bouquet/io/geqdsk.py", + "line": 915, + "desc": "Uniform [0, 1] grid from g-file NW points; basis for all flux-surface averaging", + "subsystem": "Shared quantities" + }, + { + "id": "qty.psi_N_kinetic", + "type": "quantity", + "label": "psi_N_kinetic (kinetic grid)", + "file": "bouquet/io/ida.py", + "line": 43, + "desc": "IDA psi_N grid (extends past separatrix ~1.2); kinetic profiles on this grid", + "subsystem": "Shared quantities" + }, + { + "id": "qty.quality_metrics", + "type": "quantity", + "label": "quality metrics dict", + "file": "bouquet/TokaMaker_interface.py", + "line": 4781, + "desc": "Reconstruction quality: mode, core/edge RMS, li/Ip errors, boundary deviations", + "subsystem": "Shared quantities" + }, + { + "id": "qty.shelf_psi_value", + "type": "quantity", + "label": "shelf_psi (location)", + "file": "bouquet/TokaMaker_interface.py", + "line": 4435, + "desc": "psi_N where j_BS shelf transitions to spike", + "subsystem": "Shared quantities" + }, + { + "id": "qty.sigma_jphi", + "type": "quantity", + "label": "sigma_jphi [A/m^2]", + "file": "bouquet/baseline.py", + "line": 241, + "desc": "Fractional envelope on |j_phi_baseline|, on psi_N", + "subsystem": "Shared quantities" + }, + { + "id": "qty.sigma_ne", + "type": "quantity", + "label": "sigma_ne (density uncertainty)", + "file": "bouquet/io/ida.py", + "line": 50, + "desc": "1-sigma envelope from IDA *_err (direct) or percentile band (ensemble)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.sigma_ni", + "type": "quantity", + "label": "sigma_ni (ion density uncertainty)", + "file": "bouquet/io/ida.py", + "line": 52, + "desc": "Propagated from sigma_ne via fractional error when ni derived from Zeff", + "subsystem": "Shared quantities" + }, + { + "id": "qty.sigma_te", + "type": "quantity", + "label": "sigma_te (temperature uncertainty)", + "file": "bouquet/io/ida.py", + "line": 51, + "desc": "1-sigma envelope from IDA *_err (direct) or percentile band (ensemble)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.sigma_ti", + "type": "quantity", + "label": "sigma_ti (temperature uncertainty)", + "file": "bouquet/io/ida.py", + "line": 53, + "desc": "1-sigma envelope from IDA *_err (direct) or percentile band (ensemble)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.spike_metrics", + "type": "quantity", + "label": "spike_metrics", + "file": "bouquet/TokaMaker_interface.py", + "line": 4430, + "desc": "Edge spike detection metrics (heights, psi locations, ratios)", + "subsystem": "Shared quantities" + }, + { + "id": "qty.spike_profile", + "type": "quantity", + "label": "spike_profile (bootstrap spike)", + "line": 1160, + "desc": "Either input_j_phi - input_jinductive (PIN_JPHI), delta from DIFF_BS, or SWB isolated_j_BS", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.t_ls", + "type": "quantity", + "label": "t_ls (temperature length scale)", + "file": "bouquet/TokaMaker_interface.py", + "line": 2265, + "desc": "GPR correlation length for temperature profiles", + "subsystem": "Shared quantities" + }, + { + "id": "qty.target_jphi_perturb", + "type": "quantity", + "label": "target_jphi_perturb (corrective target)", + "line": 2046, + "desc": "matched_j_inductive * final_scale_j0 + spike + j_fixed", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.te", + "type": "quantity", + "label": "te (electron temperature)", + "file": "bouquet/io/pfile.py", + "line": 334, + "desc": "From p-file (keV) or IDA (eV); on psinorm or psi_N", + "subsystem": "Shared quantities" + }, + { + "id": "qty.te_draw", + "type": "quantity", + "label": "te_draw (per-draw perturb)", + "file": "bouquet/TokaMaker_interface.py", + "line": 972, + "desc": "Per-draw perturbed electron temperature; sampled monotonically", + "subsystem": "Shared quantities" + }, + { + "id": "qty.te_perturb", + "type": "quantity", + "label": "te_perturb (perturbed temperature)", + "line": 972, + "desc": "GPR-sampled electron temperature on psi_kin", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.ti", + "type": "quantity", + "label": "ti (ion temperature)", + "file": "bouquet/io/pfile.py", + "line": 344, + "desc": "From p-file (keV) or IDA T_12C6 for carbon (eV); on psinorm or psi_N", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ti_draw", + "type": "quantity", + "label": "ti_draw (per-draw perturb)", + "file": "bouquet/TokaMaker_interface.py", + "line": 996, + "desc": "Per-draw perturbed ion temperature; sampled monotonically", + "subsystem": "Shared quantities" + }, + { + "id": "qty.ti_perturb", + "type": "quantity", + "label": "ti_perturb (perturbed ion temperature)", + "line": 996, + "desc": "GPR-sampled on psi_kin", + "subsystem": "Shared quantities", + "file": "" + }, + { + "id": "qty.zeff", + "type": "quantity", + "label": "Zeff (effective charge)", + "file": "bouquet/io/ida.py", + "line": 48, + "desc": "From IDA directly (visible bremsstrahlung); controls ni derivation and pressure calculation", + "subsystem": "Shared quantities" + }, + { + "id": "qty.zeff_draw", + "type": "quantity", + "label": "zeff_draw (per-draw sample)", + "file": "bouquet/TokaMaker_interface.py", + "line": 983, + "desc": "Per-draw effective charge when zeff channel active; clipped to [1.0, Z_imp*(1-1e-9)]; triggers ni derivation", + "subsystem": "Shared quantities" + }, + { + "id": "quantity.eqdsk_j_tor", + "type": "transform", + "label": "eqdsk_j_tor", + "file": "", + "line": null, + "desc": "(referenced, not defined by any extractor)", + "subsystem": "Shared quantities" + }, + { + "id": "quantity.n_equils_per_worker", + "type": "quantity", + "label": "n_equils_per_worker", + "file": "bouquet/parallel.py", + "line": "135", + "desc": "Shard size for worker i: base + 1 if remainder, via _shard_size()", + "subsystem": "Process-parallel path" + }, + { + "id": "quantity.n_equils_total", + "type": "quantity", + "label": "n_equils_total", + "file": "bouquet/parallel.py", + "line": "342", + "desc": "Total draws: config.generation.n_equils", + "subsystem": "Process-parallel path" + }, + { + "id": "quantity.per_worker_seed", + "type": "quantity", + "label": "per_worker_seed", + "file": "bouquet/parallel.py", + "line": "158", + "desc": "SeedSequence(entropy=[seed_base, worker_id, scan_key_hash]) -> 32-bit seed", + "subsystem": "Process-parallel path" + } + ], + "edges": [ + { + "src": "art.h5.baseline", + "dst": "fn.filtering._baseline_boundary", + "kind": "data", + "desc": "Reads recon_lcfs_ref or baseline eqdsk boundary for deviation reference", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.baseline", + "dst": "fn.plotting.plot_bouquet", + "kind": "data", + "desc": "Reads baseline profiles for input bands", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.baseline", + "dst": "fn.plotting.plot_coil_currents", + "kind": "data", + "desc": "Reads baseline coil_currents for reference", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.baseline", + "dst": "fn.plotting.plot_traces", + "kind": "data", + "desc": "Reads recon_lcfs_ref or baseline eqdsk boundary for reference", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.coil_currents", + "dst": "fn.filtering.filter_coil_currents", + "kind": "data", + "desc": "Reads per-draw coil_currents for coil-spec check (stored thresholds)", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.coil_currents", + "dst": "fn.plotting.plot_coil_currents", + "kind": "data", + "desc": "Reads per-draw coil_currents for trace plot", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.eqdsk", + "dst": "fn.archive.DrawView", + "kind": "data", + "desc": "DrawView.eqdsk_bytes; uses find_bytes_dataset to locate it", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.eqdsk", + "dst": "fn.plotting.plot_geqdsk_bouquet", + "kind": "data", + "desc": "Parses eqdsk bytes (via read_geqdsk) to extract equilibrium", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.filter_flags", + "dst": "fn.filtering.filter_coil_currents", + "kind": "data", + "desc": "Reads max_F_drift_pct, max_VSC_drift_pct, inspec_F_max, inspec_VSC_max attrs", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.perturbed_lcfs_ref", + "dst": "fn.filtering._boundary_devs", + "kind": "data", + "desc": "Reads perturbed boundary; falls back to eqdsk RBBBS if absent", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.perturbed_lcfs_ref", + "dst": "fn.plotting.plot_traces", + "kind": "data", + "desc": "Reads high-res perturbed boundary for trace plot", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.pfile", + "dst": "fn.archive.DrawView", + "kind": "data", + "desc": "DrawView.pfile_bytes; optional, uses find_bytes_dataset", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.pfile", + "dst": "fn.plotting.plot_pfile_bouquet", + "kind": "data", + "desc": "Parses pfile bytes (via PFile) to extract profile data", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.profiles", + "dst": "fn.archive.DrawView", + "kind": "data", + "desc": "DrawView.profiles property; iterates group non-profile datasets excluded", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.profiles", + "dst": "fn.gui.EquilibriumBrowser", + "kind": "data", + "desc": "Reads perturbed draw profiles via _load_all_perturbations", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.profiles", + "dst": "fn.plotting.plot_bouquet", + "kind": "data", + "desc": "Reads psi_N, j_phi, j_BS (perturbed) + baseline via _load_all_perturbations", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5.x_points", + "dst": "fn.plotting.plot_traces", + "kind": "data", + "desc": "Reads per-draw X-points for boundary annotation", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.archive.BouquetArchive", + "kind": "data", + "desc": "Path passed to constructor; opened in lazy property accessors", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.run.export", + "kind": "data", + "desc": "export() reads filtered HDF5 and writes {header}_selected.h5", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "art.h5_archive", + "dst": "fn.utils.discover_scan_keys", + "kind": "data", + "desc": "Read scan/ group keys or return None if flat layout", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.utils.list_equilibrium_indices", + "kind": "data", + "desc": "List stored draw indices by scanning parent group for integer keys", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.utils.load_baseline_profiles", + "kind": "data", + "desc": "Read _baseline group: all profiles, sigmas, Ip_target, l_i_target", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.utils.load_config", + "kind": "data", + "desc": "Read config_json from archive root or scan/ level", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.h5_archive", + "dst": "fn.utils.load_equilibrium", + "kind": "data", + "desc": "Read scan// group: eqdsk_bytes, profiles, l_i*, optional coil_currents", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "art.shard_h5", + "dst": "fn.parallel.merge_archives", + "kind": "data", + "desc": "Shard paths list passed to merge_archives", + "subsystem": "Process-parallel path" + }, + { + "src": "art.slurm_bundle", + "dst": "fn.parallel._cli", + "kind": "data", + "desc": "SLURM shard/merge tasks load bundle.json via _cli argv[1]", + "subsystem": "Process-parallel path" + }, + { + "src": "artifact.baseline", + "dst": "artifact.imas_draw_json", + "kind": "data", + "desc": "write_imas_draw uses baseline equilibrium/core_profiles as template", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "artifact.baseline", + "dst": "fn.imas.read_imas_baseline", + "kind": "data", + "desc": "Output of main reader function", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.FixedComponentsConfig.j_NBI", + "dst": "fn.baseline._resolve_fixed", + "kind": "data", + "desc": "user-supplied j_NBI array", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.FixedComponentsConfig.j_RF", + "dst": "fn.baseline._resolve_fixed", + "kind": "data", + "desc": "user-supplied j_RF array", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.FixedComponentsConfig.p_fast", + "dst": "fn.baseline._resolve_fixed", + "kind": "data", + "desc": "user-supplied p_fast array", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.FixedComponentsConfig.psi_N", + "dst": "fn.baseline._resolve_fixed", + "kind": "control", + "desc": "triggers resampling logic", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.GenerationConfig.recalculate_j_BS", + "dst": "qty.j_BS", + "kind": "control", + "desc": "when True, j_BS recomputed per draw; when False, baseline kept", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.ReconstructionSource.impurity_Z", + "dst": "fn.baseline._load_kinetic_profiles", + "kind": "control", + "desc": "passed to IDA/p-file reader for ni derivation", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.aux_baselines", + "dst": "fn.baseline._sigma_zeff_baseline", + "kind": "data", + "desc": "manual zeff baseline override", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.aux_sigmas", + "dst": "gate.sigma_priority_zeff", + "kind": "control", + "desc": "explicit zeff sigma overrides default", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ida_path", + "dst": "gate.sigma_priority_ne", + "kind": "control", + "desc": "IDA fallback if no explicit profile", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ida_path", + "dst": "gate.sigma_priority_ni", + "kind": "control", + "desc": "IDA fallback if no explicit profile", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ida_path", + "dst": "gate.sigma_priority_te", + "kind": "control", + "desc": "IDA fallback if no explicit profile", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ida_path", + "dst": "gate.sigma_priority_ti", + "kind": "control", + "desc": "IDA fallback if no explicit profile", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.jphi_scalar_sigma", + "dst": "qty.sigma_jphi", + "kind": "data", + "desc": "applied to |j_phi|", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ne_scalar_sigma", + "dst": "gate.sigma_priority_ne", + "kind": "control", + "desc": "scalar fallback", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ni_scalar_sigma", + "dst": "gate.sigma_priority_ni", + "kind": "control", + "desc": "scalar fallback", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.sigma_ni_from_ne", + "dst": "gate.sigma_priority_ni", + "kind": "control", + "desc": "IDA path: when True, sigma_ni = sigma_ne", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.sigma_profiles", + "dst": "gate.sigma_priority_ne", + "kind": "control", + "desc": "explicit ne profile wins", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.sigma_profiles", + "dst": "gate.sigma_priority_ni", + "kind": "control", + "desc": "explicit ni profile wins", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.sigma_profiles", + "dst": "gate.sigma_priority_te", + "kind": "control", + "desc": "explicit te profile wins", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.sigma_profiles", + "dst": "gate.sigma_priority_ti", + "kind": "control", + "desc": "explicit ti profile wins", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.te_scalar_sigma", + "dst": "gate.sigma_priority_te", + "kind": "control", + "desc": "scalar fallback", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.ti_scalar_sigma", + "dst": "gate.sigma_priority_ti", + "kind": "control", + "desc": "scalar fallback", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.UncertaintyConfig.zeff_scalar_sigma", + "dst": "gate.zeff_channel_enable", + "kind": "control", + "desc": "enable gate (default 0.05)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "cfg.accept_anchor_inband", + "dst": "gate.li_loop_variant", + "kind": "control", + "desc": "Fix-B: conditional accept on in-band anchor", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.accept_anchor_inband", + "dst": "gate.perturb_jind_in_anchor_loop", + "kind": "control", + "desc": "Fix-B path: resample j_ind if anchor not in-band", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.constrain_sawteeth", + "dst": "gate.constrain_sawteeth_post", + "kind": "control", + "desc": "If True, reject draws with q_0 < 1", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.constrain_sawteeth", + "dst": "gate.constrain_sawteeth_pre", + "kind": "control", + "desc": "If True, reject draws with q_0 < 1 early", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.constrain_sawteeth", + "dst": "gate.sawteeth_q0", + "kind": "control", + "desc": "Gate active iff constrain_sawteeth=True; auto-override to False if baseline q0 < 1", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.filterconfig.inspec_F_max", + "dst": "fn.filtering.if abs", + "kind": "data", + "desc": "Controls inspec_F_max", + "subsystem": "Configuration" + }, + { + "src": "cfg.filterconfig.inspec_VSC_max", + "dst": "fn.filtering.if abs", + "kind": "data", + "desc": "Controls inspec_VSC_max", + "subsystem": "Configuration" + }, + { + "src": "cfg.filterconfig.rms_max_mm", + "dst": "fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject", + "kind": "data", + "desc": "Controls rms_max_mm", + "subsystem": "Configuration" + }, + { + "src": "cfg.filtering.F_max_pct", + "dst": "fn.filtering.filter_coil_currents", + "kind": "control", + "desc": "Threshold for max F-coil drift; defaults to stored inspec_F_max", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "cfg.filtering.VSC_max_pct", + "dst": "fn.filtering.filter_coil_currents", + "kind": "control", + "desc": "Threshold for max VSC drift; defaults to stored inspec_VSC_max", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "cfg.filtering.max_max_mm", + "dst": "fn.filtering.filter_boundaries", + "kind": "control", + "desc": "Max threshold for boundary deviation filter", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "cfg.filtering.rms_max_mm", + "dst": "fn.filtering.filter_boundaries", + "kind": "control", + "desc": "RMS threshold for boundary deviation filter", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "cfg.fixed.j_NBI", + "dst": "fn.imas._override", + "kind": "data", + "desc": "user override array (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.fixed.j_RF", + "dst": "fn.imas._override", + "kind": "data", + "desc": "user override array (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.fixed.p_fast", + "dst": "fn.imas._override", + "kind": "data", + "desc": "user override array (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.fixedcomponentsconfig.j_NBI", + "dst": "fn.run.fc.j_NBI or zeros_on_psi_N", + "kind": "data", + "desc": "Controls j_NBI", + "subsystem": "Configuration" + }, + { + "src": "cfg.fixedcomponentsconfig.j_RF", + "dst": "fn.run.fc.j_RF or zeros_on_psi_N", + "kind": "data", + "desc": "Controls j_RF", + "subsystem": "Configuration" + }, + { + "src": "cfg.fixedcomponentsconfig.p_fast", + "dst": "fn.run.fc.p_fast or compute_p_fast_from_source", + "kind": "data", + "desc": "Controls p_fast", + "subsystem": "Configuration" + }, + { + "src": "cfg.fixedcomponentsconfig.p_fast_reduction", + "dst": "fn.physics.isotropize_fast_pressure", + "kind": "data", + "desc": "Controls p_fast_reduction", + "subsystem": "Configuration" + }, + { + "src": "cfg.fixedcomponentsconfig.psi_N", + "dst": "fn.run.fc.psi_N or source_psi_N", + "kind": "data", + "desc": "Controls psi_N", + "subsystem": "Configuration" + }, + { + "src": "cfg.floor_j_BS", + "dst": "qty.spike_profile", + "kind": "control", + "desc": "If True, clip spike_profile to [0, \u221e)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.generation.allow_incomplete_pressure", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "control", + "desc": "allow_incomplete=True: warn instead of raise", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.generation.floor_j_BS", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "control", + "desc": "Gates clipping of j_BS_swb at 0", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "cfg.generation.jBS_baseline_mode", + "dst": "gate.jBS_baseline_mode", + "kind": "control", + "desc": "Config knob selects 'diff' or 'rescale' branch", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "cfg.generation.jBS_baseline_mode", + "dst": "gate.workflow_guard", + "kind": "control", + "desc": "IMAS path requires jBS_baseline_mode in ('diff', 'rescale')", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "cfg.generation.p_fast_reduction", + "dst": "fn.physics.isotropize_fast_pressure", + "kind": "control", + "desc": "method='trace'|'mean'|'perp'", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.generation.recalculate_j_BS", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "control", + "desc": "Gates SWB solve; if False, skip _forward_solve_imas_baseline (IMAS path only)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "cfg.generationconfig.accept_anchor_inband", + "dst": "fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band", + "kind": "data", + "desc": "Controls accept_anchor_inband", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.allow_incomplete_pressure", + "dst": "fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check", + "kind": "data", + "desc": "Controls allow_incomplete_pressure", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.allow_unsafe_workflow", + "dst": "fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow", + "kind": "data", + "desc": "Controls allow_unsafe_workflow", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.anchor_jtor_to_equilibrium", + "dst": "fn.run.eq.j_tor - cp.j_tor", + "kind": "data", + "desc": "Controls anchor_jtor_to_equilibrium", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.anchor_pressure_to_equilibrium", + "dst": "fn.run.eq.pressure - p_recon", + "kind": "data", + "desc": "Controls anchor_pressure_to_equilibrium", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.coil_drift", + "dst": "fn.TokaMaker_interface.config.generation.coil_drift", + "kind": "data", + "desc": "Controls coil_drift", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.coil_drift_hard_factor", + "dst": "fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None", + "kind": "data", + "desc": "Controls coil_drift_hard_factor", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.constrain_sawteeth", + "dst": "fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject", + "kind": "data", + "desc": "Controls constrain_sawteeth", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.diagnostic_plots", + "dst": "fn.run.if config.generation.diagnostic_plots: plot_diagnostics", + "kind": "data", + "desc": "Controls diagnostic_plots", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.floor_j_BS", + "dst": "fn.run.np.maximum", + "kind": "data", + "desc": "Controls floor_j_BS", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.homotopy_passes", + "dst": "fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ...", + "kind": "data", + "desc": "Controls homotopy_passes", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.isolate_edge_jBS", + "dst": "fn.run.isolate_edge_jBS", + "kind": "data", + "desc": "Controls isolate_edge_jBS", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.jBS_baseline_mode", + "dst": "fn.run....", + "kind": "data", + "desc": "Controls jBS_baseline_mode", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.jBS_scale_range", + "dst": "fn.TokaMaker_interface.np.random.uniform", + "kind": "data", + "desc": "Controls jBS_scale_range", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.kinetic_source", + "dst": "fn.run.\"ida_hybrid\": resample_ida_profiles", + "kind": "data", + "desc": "Controls kinetic_source", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.l_i_tolerance", + "dst": "fn.TokaMaker_interface.if not abs", + "kind": "data", + "desc": "Controls l_i_tolerance", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.n_equils", + "dst": "fn.TokaMaker_interface.for i_eq in _tqdm", + "kind": "data", + "desc": "Controls n_equils", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.n_equils", + "dst": "fn.run.int", + "kind": "data", + "desc": "Controls n_equils", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.perturb_jind_in_anchor", + "dst": "fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind", + "kind": "data", + "desc": "Controls perturb_jind_in_anchor", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.recalculate_j_BS", + "dst": "fn.run.compute_via_swb", + "kind": "data", + "desc": "Controls recalculate_j_BS", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.scan_key", + "dst": "fn.run.store_equilibrium", + "kind": "data", + "desc": "Controls scan_key", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.seed", + "dst": "fn.TokaMaker_interface.np.random.seed", + "kind": "data", + "desc": "Controls seed", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.swb_iterations", + "dst": "fn.TokaMaker_interface.solve_with_bootstrap", + "kind": "data", + "desc": "Controls swb_iterations", + "subsystem": "Configuration" + }, + { + "src": "cfg.generationconfig.workflow", + "dst": "fn.run.resolve_workflow_from_preset", + "kind": "data", + "desc": "Controls workflow", + "subsystem": "Configuration" + }, + { + "src": "cfg.imassource.efit01_geqdsk", + "dst": "fn.run.read_geqdsk", + "kind": "data", + "desc": "Controls efit01_geqdsk", + "subsystem": "Configuration" + }, + { + "src": "cfg.imassource.ida_path", + "dst": "fn.run.ida_path", + "kind": "data", + "desc": "Controls ida_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.imassource.ids_path", + "dst": "fn.io.imas.read_imas", + "kind": "data", + "desc": "Controls ids_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.imassource.impurity_Z", + "dst": "fn.io.imas.profiles.compute_ni", + "kind": "data", + "desc": "Controls impurity_Z", + "subsystem": "Configuration" + }, + { + "src": "cfg.imassource.time", + "dst": "fn.io.imas.read_imas", + "kind": "data", + "desc": "Controls time", + "subsystem": "Configuration" + }, + { + "src": "cfg.isolate_edge_jBS", + "dst": "ext.solve_with_bootstrap", + "kind": "control", + "desc": "Control whether to isolate edge spike", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.isolate_edge_jBS", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Edge-spike isolation flag", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.isolate_edge_jBS", + "dst": "gate.j_inductive_decomposition", + "kind": "control", + "desc": "True=closing decomp; False=residual", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.jBS_scale_range", + "dst": "qty.jBS_scales", + "kind": "data", + "desc": "np.random.uniform(lo, hi, size=n_equils) if range provided; else ones(n_equils)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.l_i_tolerance", + "dst": "gate.li_acceptance", + "kind": "data", + "desc": "Band width (fraction of l_i_target)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.l_i_tolerance", + "dst": "gate.li_band", + "kind": "data", + "desc": "Band width: 100.0 * abs(l_i - l_i_target_draw) / l_i_target_draw <= l_i_tolerance*100", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.l_i_uncertainty", + "dst": "qty.l_i_target_draw", + "kind": "data", + "desc": "l_i_target_draw ~ N(l_i_target, l_i_uncertainty*l_i_target) when l_i_uncertainty > 0 (line 3304-3312)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.n_equils", + "dst": "fn.tmi.generate_bouquet", + "kind": "control", + "desc": "Loop iteration range; length of jBS_scales, elapsed_times arrays", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.n_k", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "control", + "desc": "Spline order k", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.perturb_jind_in_anchor", + "dst": "gate.li_loop_variant", + "kind": "control", + "desc": "Fix-C: unconditional accept after resampled anchor", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.perturb_jind_in_anchor", + "dst": "gate.perturb_jind_in_anchor_loop", + "kind": "control", + "desc": "Fix-C path: always accept anchor after per-iter GPR resample", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.pin_jphi", + "dst": "gate.pin_jphi_branch", + "kind": "control", + "desc": "Diagnostic: bypass SWB, pin j_phi to recon", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.psi_bridge", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "control", + "desc": "Edge-anchor location for spline", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.psi_pad", + "dst": "fn.sampling.calc_cylindrical_li_proxy", + "kind": "data", + "desc": "Padding parameter", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.psi_pad", + "dst": "fn.tmi._swb_jbs_to_toroidal", + "kind": "control", + "desc": "Grid padding for get_q/get_profiles", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.recalculate_j_BS", + "dst": "gate.recalculate_jBS", + "kind": "control", + "desc": "Gate: PIN_JPHI | DIFF_BS | standard SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.recon_eq_snapshot", + "dst": "gate.diff_bs_branch", + "kind": "control", + "desc": "Differential bootstrap requires snapshot", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.reconstructionsource.cocos", + "dst": "fn.baseline.read_geqdsk", + "kind": "data", + "desc": "Controls cocos", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.geqdsk_path", + "dst": "fn.baseline.read_geqdsk", + "kind": "data", + "desc": "Controls geqdsk_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.geqdsk_path", + "dst": "fn.run.read_geqdsk", + "kind": "data", + "desc": "Controls geqdsk_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.impurity_Z", + "dst": "fn.baseline.profiles.compute_ni", + "kind": "data", + "desc": "Controls impurity_Z", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.n_k", + "dst": "fn.baseline.spline_fit", + "kind": "data", + "desc": "Controls n_k", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.profile_overrides", + "dst": "fn.baseline....", + "kind": "data", + "desc": "Controls profile_overrides", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.profiles_path", + "dst": "fn.baseline.read_profiles", + "kind": "data", + "desc": "Controls profiles_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.psi_bridge", + "dst": "fn.baseline.hermite_edge_bridge", + "kind": "data", + "desc": "Controls psi_bridge", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.psi_pad", + "dst": "fn.baseline.compute_psi_bounds", + "kind": "data", + "desc": "Controls psi_pad", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.rescale_j_BS", + "dst": "fn.baseline.scaling_factor", + "kind": "data", + "desc": "Controls rescale_j_BS", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.shelf_psi_N", + "dst": "fn.baseline.source.shelf_psi_N", + "kind": "data", + "desc": "Controls shelf_psi_N", + "subsystem": "Configuration" + }, + { + "src": "cfg.reconstructionsource.time", + "dst": "fn.io.ida.read_ida", + "kind": "data", + "desc": "Controls time", + "subsystem": "Configuration" + }, + { + "src": "cfg.rescale_j_BS", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "control", + "desc": "Joint vs inductive-only optimization", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.scale_jBS", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Bootstrap scale factor", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.seed", + "dst": "fn.tmi.generate_bouquet", + "kind": "control", + "desc": "np.random.seed(int(seed)) called at function entry (line 2434)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "cfg.shelf_psi_N", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "control", + "desc": "Apply shelf if > 0", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.shelf_psi_N", + "dst": "qty.j_BS_shelved", + "kind": "control", + "desc": "Shelf threshold", + "subsystem": "GS reconstruction" + }, + { + "src": "cfg.solverconfig.F0", + "dst": "fn.run.F0 or eqdsk.F0_ref or ...", + "kind": "data", + "desc": "Controls F0", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.coil_vsc", + "dst": "fn.run.coil_vsc dict unpacked into solve_with_bootstrap", + "kind": "data", + "desc": "Controls coil_vsc", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.isoflux_pts", + "dst": "fn.run.isoflux_pts or eqdsk.isoflux_pts", + "kind": "data", + "desc": "Controls isoflux_pts", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.isoflux_weights", + "dst": "fn.run.isoflux_weights or np.ones", + "kind": "data", + "desc": "Controls isoflux_weights", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.mesh_path", + "dst": "fn.run.load_gs_mesh", + "kind": "data", + "desc": "Controls mesh_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.nthreads", + "dst": "fn.TokaMaker_interface.mygs.solve", + "kind": "data", + "desc": "Controls nthreads", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.nthreads", + "dst": "fn.run.load_gs_mesh", + "kind": "data", + "desc": "Controls nthreads", + "subsystem": "Configuration" + }, + { + "src": "cfg.solverconfig.order", + "dst": "fn.run.GsHandle", + "kind": "data", + "desc": "Controls order", + "subsystem": "Configuration" + }, + { + "src": "cfg.source.efit01_geqdsk", + "dst": "fn.imas.read_imas_geometry", + "kind": "data", + "desc": "EFIT01 LCFS replaces IDS boundary as isoflux target (io/imas.py:117-120, via getattr)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "cfg.source.type", + "dst": "fn.run._validate_workflow", + "kind": "control", + "desc": "Workflow rules differ per source type (ReconstructionSource vs ImasSource)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "cfg.spike_profile_recon_cached", + "dst": "gate.diff_bs_branch", + "kind": "control", + "desc": "Differential bootstrap requires cache", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.swb_iterations", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "H-mode bootstrap-iteration count", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "cfg.uncertaintyconfig.aux_baselines", + "dst": "fn.TokaMaker_interface.config.uncertainty.aux_baselines.get", + "kind": "data", + "desc": "Controls aux_baselines", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.aux_length_scales", + "dst": "fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get", + "kind": "data", + "desc": "Controls aux_length_scales", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.aux_sigmas", + "dst": "fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items", + "kind": "data", + "desc": "Controls aux_sigmas", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.ida_path", + "dst": "fn.baseline.unc.ida_path or source.profiles_path", + "kind": "data", + "desc": "Controls ida_path", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.j_ls", + "dst": "fn.TokaMaker_interface.GPRPerturber", + "kind": "data", + "desc": "Controls j_ls", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.jphi_scalar_sigma", + "dst": "fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs", + "kind": "data", + "desc": "Controls jphi_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.n_ls", + "dst": "fn.TokaMaker_interface.GPRPerturber", + "kind": "data", + "desc": "Controls n_ls", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.ne_scalar_sigma", + "dst": "fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline", + "kind": "data", + "desc": "Controls ne_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.ni_scalar_sigma", + "dst": "fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline", + "kind": "data", + "desc": "Controls ni_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.sigma_method", + "dst": "fn.baseline.percentile_or_std", + "kind": "data", + "desc": "Controls sigma_method", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.sigma_mode", + "dst": "fn.baseline.resolve_ida_sigmas", + "kind": "data", + "desc": "Controls sigma_mode", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.sigma_ni_from_ne", + "dst": "fn.baseline.sigma_ne", + "kind": "data", + "desc": "Controls sigma_ni_from_ne", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.sigma_profiles", + "dst": "fn.baseline.unc.sigma_profiles.get", + "kind": "data", + "desc": "Controls sigma_profiles", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.t_ls", + "dst": "fn.TokaMaker_interface.GPRPerturber", + "kind": "data", + "desc": "Controls t_ls", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.te_scalar_sigma", + "dst": "fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline", + "kind": "data", + "desc": "Controls te_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.ti_scalar_sigma", + "dst": "fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline", + "kind": "data", + "desc": "Controls ti_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "cfg.uncertaintyconfig.zeff_scalar_sigma", + "dst": "fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff", + "kind": "data", + "desc": "Controls zeff_scalar_sigma", + "subsystem": "Configuration" + }, + { + "src": "env.blas_pinning", + "dst": "fn.run.Bouquet_pipeline", + "kind": "control", + "desc": "Workers inherit pinned BLAS env at spawn", + "subsystem": "Process-parallel path" + }, + { + "src": "env.fd_suppression", + "dst": "fn.parallel.run_shard", + "kind": "control", + "desc": "Suppress worker stdout/stderr at fd level unless verbose=True", + "subsystem": "Process-parallel path" + }, + { + "src": "ext.corrective_jphi_iteration", + "dst": "qty.j_phi_output_corr", + "kind": "data", + "desc": "Converged output j_phi", + "subsystem": "GS reconstruction" + }, + { + "src": "ext.solve_with_bootstrap", + "dst": "qty.full_j_BS", + "kind": "data", + "desc": "SWB j_BS (total Sauter) output", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "ext.solve_with_bootstrap", + "dst": "qty.j_BS_swb", + "kind": "data", + "desc": "Bootstrap current (parallel convention)", + "subsystem": "GS reconstruction" + }, + { + "src": "ext.solve_with_bootstrap", + "dst": "qty.spike_profile", + "kind": "data", + "desc": "SWB isolated_j_BS (edge spike or full, depending on mode)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "ext.tokamaker_solve", + "dst": "qty.F_prof", + "kind": "data", + "desc": "Extract F from get_profiles for output", + "subsystem": "GS reconstruction" + }, + { + "src": "ext.tokamaker_solve", + "dst": "qty.Ip_tokamaker", + "kind": "data", + "desc": "Get Ip from get_stats", + "subsystem": "GS reconstruction" + }, + { + "src": "ext.tokamaker_solve", + "dst": "qty.li_current", + "kind": "data", + "desc": "Compute li(1) via get_stats", + "subsystem": "GS reconstruction" + }, + { + "src": "ext.tokamaker_solve", + "dst": "qty.li_final", + "kind": "data", + "desc": "Get li(1) from get_stats (final equilibrium)", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.archive.BouquetArchive", + "dst": "fn.archive.ScanView", + "kind": "data", + "desc": "Archive passed to ScanView; used to access path for h5 reads", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.archive.ScanView", + "dst": "fn.archive.DrawView", + "kind": "data", + "desc": "ScanView._ar -> DrawView._ar; archive path", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.baseline._load_kinetic_profiles", + "dst": "gate.profile_file_type", + "kind": "control", + "desc": "dispatch on file extension", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_fixed", + "dst": "qty.j_NBI", + "kind": "data", + "desc": "resampled/zeros j_NBI", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_fixed", + "dst": "qty.j_RF", + "kind": "data", + "desc": "resampled/zeros j_RF", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_fixed", + "dst": "qty.p_fast", + "kind": "data", + "desc": "resampled/zeros p_fast", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "fn.baseline._load_kinetic_profiles", + "kind": "data", + "desc": "call to load kinetic profiles", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "fn.baseline._resolve_fixed", + "kind": "data", + "desc": "resample fixed components j_NBI/j_RF/p_fast", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.Ip_target", + "kind": "data", + "desc": "extract Ip from g-file", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.j_BS", + "kind": "data", + "desc": "result['j_BS_used'] from GS solve", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "derived as j_phi - j_BS - j_NBI - j_RF", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.j_phi", + "kind": "data", + "desc": "result['j_phi_fit'] from GS solve", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.li_target", + "kind": "data", + "desc": "solve l_i via TokaMaker.get_stats()", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._resolve_reconstruction", + "dst": "qty.psi_N", + "kind": "data", + "desc": "read g-file psi_N grid", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline._sigma_zeff_baseline", + "dst": "qty.aux_baselines", + "kind": "data", + "desc": "resolved zeff baseline", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_baseline", + "dst": "gate.source_type", + "kind": "control", + "desc": "dispatch on config.source type", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "gate.sigma_priority_ne", + "kind": "control", + "desc": "resolve ne sigma per channel", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "gate.sigma_priority_ni", + "kind": "control", + "desc": "resolve ni sigma per channel", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "gate.sigma_priority_te", + "kind": "control", + "desc": "resolve te sigma per channel", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "gate.sigma_priority_ti", + "kind": "control", + "desc": "resolve ti sigma per channel", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "gate.sigma_priority_zeff", + "kind": "control", + "desc": "resolve zeff sigma", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "qty.aux_baselines", + "kind": "data", + "desc": "auxiliary channel baselines", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "qty.aux_sigmas", + "kind": "data", + "desc": "auxiliary channel sigmas", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.baseline.resolve_uncertainty", + "dst": "qty.sigma_jphi", + "kind": "data", + "desc": "resolved jphi fractional sigma", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.filtering._boundary_devs", + "dst": "fn.filtering.filter_boundaries", + "kind": "control", + "desc": "Helper computes (rms_mm, max_mm) for each draw via KDTree", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.export_filtered", + "dst": "art.h5_archive", + "kind": "data", + "desc": "Produces filtered copy of archive (shutil.copy + delete excluded draws)", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.filter_boundaries", + "dst": "art.h5.filter_flags", + "kind": "data", + "desc": "Writes passes_boundary_filter attr to each draw group", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.filter_boundaries", + "dst": "gate.selected", + "kind": "control", + "desc": "passes_boundary_filter contributes to selected AND gate", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.filter_coil_currents", + "dst": "art.h5.filter_flags", + "kind": "data", + "desc": "Writes passes_coil_filter attr to each draw group", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.filter_coil_currents", + "dst": "gate.selected", + "kind": "control", + "desc": "passes_coil_filter contributes to selected AND gate", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.read_filter_flags", + "dst": "fn.filtering.select_indices", + "kind": "control", + "desc": "select_indices checks selected attr from read_filter_flags output", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.select_indices", + "dst": "fn.archive.ScanView", + "kind": "data", + "desc": "ScanView.selected/.excluded/.all properties call this with selection param", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.select_indices", + "dst": "fn.filtering.export_filtered", + "kind": "control", + "desc": "export_filtered calls select_indices to get keep set", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.filtering.select_indices", + "dst": "fn.plotting.plot_bouquet", + "kind": "control", + "desc": "Filters draws based on selection='selected'|'all'|'excluded'", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.imas._merge_ida_kinetics", + "dst": "qty.ne", + "kind": "data", + "desc": "IDA ne replaces FUSE (when kinetic_source='ida_hybrid')", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._merge_ida_kinetics", + "dst": "qty.omega_tor", + "kind": "data", + "desc": "IDA omega_tor (optional, replaces FUSE)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._merge_ida_kinetics", + "dst": "qty.te", + "kind": "data", + "desc": "IDA te replaces FUSE (when kinetic_source='ida_hybrid')", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._merge_ida_kinetics", + "dst": "qty.ti", + "kind": "data", + "desc": "IDA ti replaces FUSE (when kinetic_source='ida_hybrid')", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._override", + "dst": "qty.j_NBI_toroidal", + "kind": "data", + "desc": "override replaces j_NBI (if user provided)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._override", + "dst": "qty.j_RF", + "kind": "data", + "desc": "override replaces j_RF (if user provided)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas._override", + "dst": "qty.p_fast", + "kind": "data", + "desc": "override replaces p_fast (if user provided)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas.read_imas_geometry", + "dst": "artifact.geometry", + "kind": "data", + "desc": "(F0, boundary_RZ)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas.read_imas_geometry", + "dst": "qty.F0", + "kind": "data", + "desc": "F0 from vacuum_toroidal_field", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.imas.read_imas_geometry", + "dst": "qty.boundary_lcfs", + "kind": "data", + "desc": "LCFS from EFIT01 or dd outline", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.ne", + "kind": "data", + "desc": "ne [m^-3] from IDA", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.ni", + "kind": "data", + "desc": "ni from quasi-neutrality (IDA ne only case)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.psi_N_kinetic", + "kind": "data", + "desc": "native kinetic grid", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.te", + "kind": "data", + "desc": "te [eV] from IDA", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.ti", + "kind": "data", + "desc": "ti [eV] from IDA", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.ida.read_ida", + "dst": "qty.zeff", + "kind": "data", + "desc": "Zeff clipped \u22651", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.ne", + "kind": "data", + "desc": "ne [1e20 m^-3] \u2192 SI", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.ni", + "kind": "data", + "desc": "ni via compute_quasineutrality()", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.psi_N_kinetic", + "kind": "data", + "desc": "native kinetic grid", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.te", + "kind": "data", + "desc": "te [keV] \u2192 SI [eV]", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.ti", + "kind": "data", + "desc": "ti [keV] \u2192 SI [eV]", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.io.pfile.read_pfile", + "dst": "qty.zeff", + "kind": "data", + "desc": "Zeff from ion mix footer", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "fn.parallel._cli", + "dst": "fn.parallel.merge_archives", + "kind": "control", + "desc": "CLI 'merge' command builds shard_list with expected-worker accounting and calls merge_archives", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel._cli", + "dst": "fn.parallel.run_shard", + "kind": "control", + "desc": "CLI 'shard' command reconstructs config and calls run_shard with worker_id from argv[2]", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel._physical_cores", + "dst": "knob.n_workers", + "kind": "data", + "desc": "_physical_cores() result assigned to n_workers", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel._warn_multithreaded", + "dst": "gate.threads_warn", + "kind": "control", + "desc": "Emit warning if threads_per_worker > 1", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.emit_slurm_script", + "dst": "art.sbatch_scripts", + "kind": "data", + "desc": "emit_slurm_script writes array.sbatch, merge.sbatch, submit.sh", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.emit_slurm_script", + "dst": "art.slurm_bundle", + "kind": "data", + "desc": "emit_slurm_script writes {job_name}_bundle.json", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.merge_archives", + "dst": "art.h5.config_json", + "kind": "control", + "desc": "merge_archives calls write_provenance with config param", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.merge_archives", + "dst": "art.h5_archive", + "kind": "data", + "desc": "Merged output: fresh {out_header}.h5 created/initialized, draws copied and renumbered", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.merge_archives", + "dst": "fn.parallel.parallel_generate", + "kind": "data", + "desc": "Merge returns (out_path, n_merged) wrapped in result dict", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.merge_archives", + "dst": "gate.baseline_match_merge", + "kind": "control", + "desc": "Pre-pass: verify shard existence and cross-shard baseline consistency", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.parallel_generate", + "dst": "gate.baseline_match_laptop", + "kind": "control", + "desc": "After all workers complete, check all li_target/Ip_target agree within rtol", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.run_shard", + "dst": "art.shard_h5", + "kind": "data", + "desc": "SLURM shard task produces {out_header}_w{worker_id}.h5", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.run_shard", + "dst": "fn.parallel.parallel_generate", + "kind": "data", + "desc": "Worker result dict (path, n, li_target, Ip_target) collected in results", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.parallel.run_shard", + "dst": "fn.run.Bouquet_pipeline", + "kind": "control", + "desc": "run_shard orchestrates Bouquet.setup_solver -> prepare_baseline -> generate", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.physics.isotropize_fast_pressure", + "dst": "qty.p_fast", + "kind": "data", + "desc": "isotropized pressure from electrons + ions", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.physics.parallel_to_toroidal", + "dst": "qty.j_BS", + "kind": "data", + "desc": "j_BS_toroidal = j_bootstrap_parallel * c(psi)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.physics.parallel_to_toroidal", + "dst": "qty.j_BS_isolated", + "kind": "data", + "desc": "Converted toroidal bootstrap current", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.physics.parallel_to_toroidal", + "dst": "qty.j_NBI_toroidal", + "kind": "data", + "desc": "j_NBI_toroidal = j_nbi_parallel * c(psi)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "fn.read_geqdsk", + "dst": "obj.GEQDSKEquilibrium", + "kind": "data", + "desc": "Parsed equilibrium with lazy contour tracing", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "fn.read_ida", + "dst": "gate.ida_layout", + "kind": "control", + "desc": "Inspect dimensionality to dispatch direct vs ensemble", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "fn.read_ida_cer", + "dst": "obj.IDACERProfiles", + "kind": "data", + "desc": "Carbon profiles + geometry for E_r balance", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "fn.read_pfile", + "dst": "obj.PFile", + "kind": "data", + "desc": "Parsed p-file with profile dict", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "fn.run.Bouquet_pipeline", + "dst": "art.shard_h5", + "kind": "data", + "desc": "Bouquet.generate writes draws to {out_header}_w{worker_id}.h5 (fresh file)", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.run.Bouquet_pipeline", + "dst": "fn.parallel.run_shard", + "kind": "data", + "desc": "Baseline li_target/Ip_target extracted from b.baseline for metadata return", + "subsystem": "Process-parallel path" + }, + { + "src": "fn.run._forward_solve_imas_baseline", + "dst": "gate.ip_sanity", + "kind": "control", + "desc": "Forward solve converged; check Ip is within 1% of target", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run._forward_solve_imas_baseline", + "dst": "qty.li_target", + "kind": "data", + "desc": "Sets l_i_target to TokaMaker li_1 from converged forward solve", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run._repoint_imas_geometry", + "dst": "qty.boundary_lcfs", + "kind": "data", + "desc": "Re-reads LCFS boundary for THIS slice; updates isoflux constraint", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run._resolve_workflow_preset", + "dst": "gate.workflow_guard", + "kind": "control", + "desc": "resolved flags validated against the source type", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.run._validate_workflow", + "dst": "fn.run.generate", + "kind": "control", + "desc": "Workflow guard checked before generate(); raises if constraints violated", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.export", + "dst": "fn.run.run", + "kind": "control", + "desc": "run() calls export()", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.filter", + "dst": "fn.run.export", + "kind": "control", + "desc": "filter() writes pass flags; export() reads HDF5 and copies selected draws", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.filter", + "dst": "fn.run.run", + "kind": "control", + "desc": "run() calls filter()", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.filter", + "dst": "fn.run.run_slices", + "kind": "control", + "desc": "run_slices() calls filter() per slice", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.generate", + "dst": "art.h5_archive", + "kind": "data", + "desc": "generate_bouquet writes per-draw quantities to {header}.h5", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.generate", + "dst": "fn.run.filter", + "kind": "control", + "desc": "generate() populates HDF5; filter() reads it and applies spec checks", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.generate", + "dst": "fn.run.run", + "kind": "control", + "desc": "run() calls generate()", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.generate", + "dst": "fn.run.run_slices", + "kind": "control", + "desc": "run_slices() calls generate() per slice (one archive, one scan_key per slice)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "fn.run.run", + "kind": "control", + "desc": "run() calls prepare_baseline() (idempotent if already called)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "fn.run.run_slices", + "kind": "control", + "desc": "run_slices() calls prepare_baseline() per slice (calls _repoint_imas_geometry)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.Ip_target", + "kind": "data", + "desc": "resolve_baseline returns Baseline.Ip_target from g-file or IDS", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.j_BS_src", + "kind": "data", + "desc": "resolve_baseline returns Baseline.j_BS (will be recomputed if recalculate_j_BS=True)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "resolve_baseline returns Baseline.j_inductive on psi_N", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.j_phi", + "kind": "data", + "desc": "resolve_baseline returns Baseline.j_phi on psi_N (total current)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.ne", + "kind": "data", + "desc": "resolve_baseline returns Baseline.ne on psi_N_kinetic", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.ni", + "kind": "data", + "desc": "resolve_baseline returns Baseline.ni on psi_N_kinetic (derived from quasineutrality)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.psi_N", + "kind": "data", + "desc": "resolve_baseline returns Baseline with equilibrium grid psi_N", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.psi_N_kinetic", + "kind": "data", + "desc": "resolve_baseline returns Baseline with kinetic grid psi_N_kinetic", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.te", + "kind": "data", + "desc": "resolve_baseline returns Baseline.te on psi_N_kinetic", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.ti", + "kind": "data", + "desc": "resolve_baseline returns Baseline.ti on psi_N_kinetic", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.prepare_baseline", + "dst": "qty.zeff", + "kind": "data", + "desc": "resolve_baseline returns Baseline.Zeff on psi_N_kinetic (clipped >= 1)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.set_slice", + "dst": "fn.run._repoint_imas_geometry", + "kind": "control", + "desc": "set_slice() called before prepare_baseline; prepare_baseline calls _repoint_imas_geometry for IMAS", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.set_slice", + "dst": "fn.run.run_slices", + "kind": "control", + "desc": "run_slices() loops over set_slice(time=t) per time point", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.setup_solver", + "dst": "fn.run.prepare_baseline", + "kind": "control", + "desc": "setup_solver() idempotent prerequisite; must run before baseline resolution", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.setup_solver", + "dst": "fn.run.run", + "kind": "control", + "desc": "run() calls setup_solver() first (idempotent)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.setup_solver", + "dst": "fn.run.run_slices", + "kind": "control", + "desc": "run_slices() calls setup_solver() once (IMAS multi-slice)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.setup_solver", + "dst": "qty.F0", + "kind": "data", + "desc": "F0 extracted from g-file or IDS; set on mygs", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.run.setup_solver", + "dst": "qty.boundary_lcfs", + "kind": "data", + "desc": "LCFS boundary read from g-file or IDS; used for isoflux", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "fn.sampling.calc_cylindrical_li_proxy", + "dst": "qty.li_proxy_baseline", + "kind": "data", + "desc": "Baseline li proxy from geqdsk j_tor", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.aux_out", + "kind": "control", + "desc": "Per-channel GPR sampling inside auxiliary switchboard loop (line 1052-1054)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.ne_draw", + "kind": "control", + "desc": "Calls generate_perturbed_GPR via _draw_monotonic_perturbation wrapper", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.ni_draw", + "kind": "control", + "desc": "Calls generate_perturbed_GPR via _draw_monotonic_perturbation wrapper (when not Zeff-primary)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.te_draw", + "kind": "control", + "desc": "Calls generate_perturbed_GPR via _draw_monotonic_perturbation wrapper", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.ti_draw", + "kind": "control", + "desc": "Calls generate_perturbed_GPR via _draw_monotonic_perturbation wrapper", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.sampling.generate_perturbed_GPR", + "dst": "qty.zeff_draw", + "kind": "control", + "desc": "Direct generate_perturbed_GPR call for Zeff sampling (line 984-987)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.schema.find_bytes_dataset", + "dst": "fn.archive.DrawView", + "kind": "control", + "desc": "Used to locate eqdsk/pfile datasets by fixed name or pre-v2 suffix", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.schema.write_profile", + "dst": "fn.utils.store_baseline_profiles", + "kind": "control", + "desc": "Called to write baseline profiles + sigmas", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.schema.write_profile", + "dst": "fn.utils.store_equilibrium", + "kind": "control", + "desc": "Called to write each profile dataset + unit attr", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.tmi._corrective_jphi_iteration", + "dst": "gate.skip_hard_bounds_env", + "kind": "control", + "desc": "then the hard-bounds/homotopy stage (unless diagnostics skip it)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi._corrective_jphi_iteration", + "dst": "qty.output_jphi", + "kind": "data", + "desc": "Converged j_phi after residual iteration", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi._shelf_blend_decompose", + "dst": "qty.shelf_psi_value", + "kind": "data", + "desc": "Shelf transition location", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi._swb_jbs_to_toroidal", + "dst": "qty.full_j_BS", + "kind": "data", + "desc": "Toroidal-convention j_BS for storage and downstream solves", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi._swb_jbs_to_toroidal", + "dst": "qty.j_dot_B", + "kind": "data", + "desc": "Intermediate parallel current after undo", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi._swb_jbs_to_toroidal", + "dst": "qty.spike_profile", + "kind": "data", + "desc": "Toroidal-convention spike for j_phi assembly", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi._vsc_channel_drift_pct", + "dst": "gate.in_spec_verdict", + "kind": "data", + "desc": "VSC channel drift feeds the verdict", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi.classify_jphi_profile", + "dst": "qty.jphi_mode", + "kind": "data", + "desc": "Classification result", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi.classify_jphi_profile", + "dst": "qty.spike_metrics", + "kind": "data", + "desc": "Edge metrics dict", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi.find_optimal_scale", + "dst": "qty.final_jphi", + "kind": "data", + "desc": "Converged j_phi at optimal j0 scale", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi.find_optimal_scale", + "dst": "qty.final_scale_j0", + "kind": "data", + "desc": "Optimal j0 scale factor", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi.fit_inductive_profile", + "dst": "qty.bs_scale", + "kind": "data", + "desc": "Bootstrap scaling factor", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi.fit_inductive_profile", + "dst": "qty.ind_scale", + "kind": "data", + "desc": "Inductive scaling factor", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi.fit_inductive_profile", + "dst": "qty.j_inductive_basis", + "kind": "data", + "desc": "Fitted spline profile (unscaled)", + "subsystem": "GS reconstruction" + }, + { + "src": "fn.tmi.perturb_kinetic_equilibrium", + "dst": "gate.li_target_sample", + "kind": "control", + "desc": "sample the draw's l_i target before the li-band loop", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.tmi.perturb_kinetic_equilibrium", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Returns diagnostics dict: l_i(1), Ip, boundary, coil currents, l_i/Ip iteration histories, scale factors, LCFS shift", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.tmi.perturb_kinetic_equilibrium", + "dst": "qty.output_jphi", + "kind": "data", + "desc": "Returns jphi_perturb (or input_j_phi if PIN_JPHI/DIFF_BS) after corrective iteration", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "fn.tmi.recon_anchor_solve", + "dst": "qty.eq_stats", + "kind": "data", + "desc": "Extract l_i, Ip, axis from solved equilibrium", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.utils.capture_native_output", + "dst": "fn.parallel.run_shard", + "kind": "control", + "desc": "worker solver chatter suppressed at the fd level", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "fn.utils.discover_scan_keys", + "dst": "fn.archive.BouquetArchive", + "kind": "data", + "desc": "Populate BouquetArchive.scan_keys property", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.initialize_equilibrium_database", + "dst": "fn.utils.store_equilibrium", + "kind": "control", + "desc": "store_equilibrium requires database file exists; init creates it", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.list_equilibrium_indices", + "dst": "fn.archive.ScanView", + "kind": "data", + "desc": "ScanView.indices property calls this to list stored draws", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.load_baseline_profiles", + "dst": "fn.archive.ScanView", + "kind": "data", + "desc": "ScanView.baseline property reads via this helper", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.load_baseline_profiles", + "dst": "fn.gui.EquilibriumBrowser", + "kind": "data", + "desc": "Fetches baseline dict for all tabs (kinetic, pressure, j_phi)", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.load_baseline_profiles", + "dst": "fn.plotting.plot_bouquet", + "kind": "control", + "desc": "Fetches baseline dict internally", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_baseline_profiles", + "dst": "art.h5.baseline", + "kind": "data", + "desc": "Writes _baseline group: profiles, sigmas, Ip_target, l_i_target attrs", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_baseline_profiles", + "dst": "art.h5.coil_currents", + "kind": "data", + "desc": "Stores baseline coil_currents reference + coil_names", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_baseline_profiles", + "dst": "art.h5.eqdsk", + "kind": "data", + "desc": "Stores optional baseline eqdsk bytes", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_baseline_profiles", + "dst": "art.h5.x_points", + "kind": "data", + "desc": "Stores baseline X-points from recon", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.aux", + "kind": "data", + "desc": "Writes optional aux_* datasets from aux dict", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.coil_currents", + "kind": "data", + "desc": "Stores coil_currents dict as values + string dataset coil_names", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.eqdsk", + "kind": "data", + "desc": "Stores eqdsk_filepath bytes under EQDSK_DS fixed name", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.filter_flags", + "kind": "data", + "desc": "Writes group attrs: homotopy_pass, max_F_drift_pct, max_VSC_drift_pct, in_spec, etc.", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.perturbed_lcfs_ref", + "kind": "data", + "desc": "Stores optional perturbed LCFS high-res boundary", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.profiles", + "kind": "data", + "desc": "Writes all requested profiles via write_profile", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5.x_points", + "kind": "data", + "desc": "Stores optional X-point nulls array", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.store_equilibrium", + "dst": "art.h5_archive", + "kind": "data", + "desc": "Writes perturbed draw group: scan// or flat /", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "fn.utils.write_provenance", + "dst": "art.h5_archive", + "kind": "data", + "desc": "Writes file-level updated attr + config_json at root and/or scan/", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "gate.anchor_jtor", + "dst": "qty.jphi_diff", + "kind": "control", + "desc": "if anchor_jtor_to_equilibrium=True: compute; else jphi_diff=None", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "gate.anchor_pressure", + "dst": "qty.p_diff", + "kind": "control", + "desc": "if anchor_pressure_to_equilibrium=True: compute; else p_diff=None", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "gate.backend", + "dst": "fn.parallel.emit_slurm_script", + "kind": "control", + "desc": "If backend='slurm', call emit_slurm_script", + "subsystem": "Process-parallel path" + }, + { + "src": "gate.backend", + "dst": "fn.parallel.parallel_generate", + "kind": "control", + "desc": "If backend='laptop', continue with ProcessPoolExecutor path", + "subsystem": "Process-parallel path" + }, + { + "src": "gate.baseline_match_laptop", + "dst": "fn.parallel.merge_archives", + "kind": "control", + "desc": "Only proceed to merge if baseline check passes", + "subsystem": "Process-parallel path" + }, + { + "src": "gate.baseline_match_merge", + "dst": "fn.parallel.merge_archives", + "kind": "control", + "desc": "If baseline check passes, proceed to copy draws", + "subsystem": "Process-parallel path" + }, + { + "src": "gate.boundary_rms", + "dst": "fn.filtering.filter_boundaries", + "kind": "control", + "desc": "Decision gate: ok_rms && ok_max determines passes_boundary_filter", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "gate.coil_spec", + "dst": "fn.filtering.filter_coil_currents", + "kind": "control", + "desc": "Decision gate: ok_F && ok_V determines passes_coil_filter", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "gate.diff_bs_branch", + "dst": "ext.solve_with_bootstrap", + "kind": "control", + "desc": "DIFF_BS: call SWB on perturbed kinetics from snapshot", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.fixed_components", + "dst": "fn.imas._override", + "kind": "control", + "desc": "if fixed is not None: apply overrides", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "gate.homotopy_early_stop", + "dst": "gate.in_spec_verdict", + "kind": "control", + "desc": "compute final in-spec verdict", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.homotopy_feasible", + "dst": "gate.qp_saturation", + "kind": "control", + "desc": "check QP saturation each pass", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.ida_layout", + "dst": "obj.IDAProfiles", + "kind": "control", + "desc": "2-D direct: read *_err; 3-D ensemble: compute percentile bands", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "gate.in_spec_verdict", + "dst": "gate.post_align_failed", + "kind": "control", + "desc": "failures reset to baseline + reject", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.incomplete_pressure", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "control", + "desc": "skip validation if kinetic_source='ida_hybrid'; else validate", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "gate.ip_sanity", + "dst": "fn.run.generate", + "kind": "control", + "desc": "If Ip check passes (or warns), proceed to generation; otherwise fail", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "gate.iso_update", + "dst": "gate.skip_homotopy_env", + "kind": "control", + "desc": "then the homotopy stage", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.jBS_baseline_mode", + "dst": "qty.bs_scale", + "kind": "data", + "desc": "rescale mode output: scale factor from li proxy match (1.0 in diff mode)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "gate.jBS_baseline_mode", + "dst": "qty.jBS_diff", + "kind": "data", + "desc": "diff mode output: jBS_diff = FUSE_jBS - SWB (set to None in rescale)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "gate.jBS_baseline_mode", + "dst": "qty.j_phi_diff_mode", + "kind": "data", + "desc": "diff mode output: j_phi unchanged (FUSE total anchored)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "gate.jBS_baseline_mode", + "dst": "qty.j_phi_rescale_mode", + "kind": "data", + "desc": "rescale mode output: j_phi rebuilt from rescaled SWB", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "gate.j_inductive_decomposition", + "dst": "qty.j_inductive_consistent", + "kind": "control", + "desc": "Apply closing_decomp or residual logic with floor/cap", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.jphi_classified", + "dst": "qty.j_BS_final", + "kind": "control", + "desc": "Zero if L_mode, else j_BS_isolated", + "subsystem": "GS reconstruction" + }, + { + "src": "gate.jphi_classified", + "dst": "qty.j_phi_corrective_target", + "kind": "control", + "desc": "H/Lmode -> use j_ind_li+j_BS; L_mode -> use geqdsk", + "subsystem": "GS reconstruction" + }, + { + "src": "gate.kinetic_source", + "dst": "fn.imas._merge_ida_kinetics", + "kind": "control", + "desc": "if kinetic_source='ida_hybrid': execute", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "gate.li_acceptance", + "dst": "gate.li_band_loop", + "kind": "control", + "desc": "Break loop if in-band; else continue to next iteration", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.li_band", + "dst": "gate.draw_accepted", + "kind": "control", + "desc": "Draw must pass li_band (within tolerance) to reach draw_accepted", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "gate.li_band_loop", + "dst": "qty.jphi_perturb", + "kind": "control", + "desc": "Each li_iter: GPR-sample j_phi candidate", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.li_converged", + "dst": "fn.tmi.reconstruct_equilibrium", + "kind": "control", + "desc": "Exit secant loop if converged else update bracket & next ind_factor", + "subsystem": "GS reconstruction" + }, + { + "src": "gate.li_converged", + "dst": "qty.ind_factor_opt", + "kind": "control", + "desc": "Exit condition; ind_1 is final ind_factor", + "subsystem": "GS reconstruction" + }, + { + "src": "gate.li_loop_variant", + "dst": "gate.li_band_loop", + "kind": "control", + "desc": "Skip band loop if PIN_JPHI/DIFF_BS/accept-anchor branches taken", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.li_target_sample", + "dst": "fn.tmi._corrective_jphi_iteration", + "kind": "control", + "desc": "corrective j_phi iteration toward the sampled target", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.missing_shards", + "dst": "fn.parallel._cli", + "kind": "control", + "desc": "Check missing shards: abort or --allow-missing per flag", + "subsystem": "Process-parallel path" + }, + { + "src": "gate.perturb_jind_in_anchor_loop", + "dst": "qty.matched_j_inductive", + "kind": "control", + "desc": "GPR-resample j_ind within anchor block if enabled", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.pin_jphi_branch", + "dst": "qty.spike_profile", + "kind": "control", + "desc": "PIN_JPHI: spike = input_j_phi - input_jinductive (recon implied bootstrap)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.post_align_failed", + "dst": "gate.draw_accepted", + "kind": "control", + "desc": "final accept/reject", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.pressure_match", + "dst": "qty.ne_perturb", + "kind": "control", + "desc": "GPR-sample electron density on psi_kin", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.pressure_match", + "dst": "qty.ni_perturb", + "kind": "control", + "desc": "GPR-sample or derive ion density on psi_kin", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.pressure_match", + "dst": "qty.te_perturb", + "kind": "control", + "desc": "GPR-sample electron temperature on psi_kin", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.pressure_match", + "dst": "qty.ti_perturb", + "kind": "control", + "desc": "GPR-sample ion temperature on psi_kin", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.profile_file_type", + "dst": "fn.io.ida.read_ida", + "kind": "control", + "desc": ".cdf path", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.profile_file_type", + "dst": "fn.io.pfile.read_pfile", + "kind": "control", + "desc": ".pfile path", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.profile_file_type", + "dst": "fn.read_ida", + "kind": "control", + "desc": "Route: IDA .cdf detected", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "gate.profile_file_type", + "dst": "fn.read_pfile", + "kind": "control", + "desc": "Route: p-file detected", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "gate.qp_saturation", + "dst": "gate.homotopy_early_stop", + "kind": "control", + "desc": "check next-bound feasibility", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.sawteeth_q0", + "dst": "gate.draw_accepted", + "kind": "control", + "desc": "Draw must pass q0 check (q0 >= 1.0 when constrain_sawteeth=True) to reach draw_accepted", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "gate.selected", + "dst": "art.h5.filter_flags", + "kind": "data", + "desc": "selected attr = AND(passes_*); True if no filter applied", + "subsystem": "Archive, filtering & plotting" + }, + { + "src": "gate.sigma_priority_ne", + "dst": "qty.sigma_ne", + "kind": "data", + "desc": "resolved ne uncertainty", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.sigma_priority_ni", + "dst": "qty.sigma_ni", + "kind": "data", + "desc": "resolved ni uncertainty", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.sigma_priority_te", + "dst": "qty.sigma_te", + "kind": "data", + "desc": "resolved te uncertainty", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.sigma_priority_ti", + "dst": "qty.sigma_ti", + "kind": "data", + "desc": "resolved ti uncertainty", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.sigma_priority_zeff", + "dst": "qty.aux_sigmas", + "kind": "data", + "desc": "resolved zeff sigma (if enabled)", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.skip_hard_bounds_env", + "dst": "gate.iso_update", + "kind": "control", + "desc": "not skipped -> iso-update", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.skip_homotopy_env", + "dst": "gate.homotopy_feasible", + "kind": "control", + "desc": "run homotopy pass loop", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.solve_failed", + "dst": "gate.draw_accepted", + "kind": "control", + "desc": "Draw must not hit solver failure (RuntimeError, ValueError) to reach draw_accepted", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "gate.source_type", + "dst": "fn.baseline._resolve_reconstruction", + "kind": "control", + "desc": "ReconstructionSource path", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.source_type", + "dst": "fn.io.imas.read_imas_baseline", + "kind": "control", + "desc": "ImasSource path", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "gate.time_index", + "dst": "fn.read_ida", + "kind": "control", + "desc": "Selected time index", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "gate.zeff_active", + "dst": "qty.Z_imp", + "kind": "control", + "desc": "If active, compute impurity charge from ne, ni, Zeff baseline", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.zeff_active", + "dst": "qty.zeff_draw", + "kind": "control", + "desc": "If active, draw Zeff per iteration; derive ni via quasineutrality", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "gate.zeff_channel_enable", + "dst": "fn.baseline._sigma_zeff_baseline", + "kind": "control", + "desc": "zeff channel enabled when zeff_scalar_sigma>0", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "input.config", + "dst": "art.h5.config_json", + "kind": "data", + "desc": "Run-level config serialized and written to merged archive provenance (if config supplied)", + "subsystem": "Process-parallel path" + }, + { + "src": "input.config", + "dst": "fn.parallel.emit_slurm_script", + "kind": "data", + "desc": "Config serialized to bundle.json", + "subsystem": "Process-parallel path" + }, + { + "src": "input.config", + "dst": "fn.parallel.parallel_generate", + "kind": "data", + "desc": "Config passed to orchestrator", + "subsystem": "Process-parallel path" + }, + { + "src": "input.config", + "dst": "fn.parallel.run_shard", + "kind": "data", + "desc": "Config deepcopied and per-worker mutations applied", + "subsystem": "Process-parallel path" + }, + { + "src": "input.config", + "dst": "knob.scan_key", + "kind": "data", + "desc": "config.generation.scan_key -> scan_key", + "subsystem": "Process-parallel path" + }, + { + "src": "input.config", + "dst": "quantity.n_equils_total", + "kind": "data", + "desc": "config.generation.n_equils -> n_equils_total", + "subsystem": "Process-parallel path" + }, + { + "src": "input.efit01_gfile", + "dst": "fn.imas.read_imas_geometry", + "kind": "data", + "desc": "preferred LCFS source (magnetics-only)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.eqdsk", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Pass Ip, guess_j_inductive", + "subsystem": "GS reconstruction" + }, + { + "src": "input.eqdsk", + "dst": "qty.Ip_target", + "kind": "data", + "desc": "Extract abs(Ip)", + "subsystem": "GS reconstruction" + }, + { + "src": "input.eqdsk", + "dst": "qty.eqdsk_j_tor", + "kind": "data", + "desc": "Extract j_tor_averaged_direct", + "subsystem": "GS reconstruction" + }, + { + "src": "input.eqdsk", + "dst": "qty.li_target", + "kind": "data", + "desc": "Extract li['li(1)_EFIT']", + "subsystem": "GS reconstruction" + }, + { + "src": "input.eqdsk", + "dst": "qty.psi_N", + "kind": "data", + "desc": "Extract psi_N grid", + "subsystem": "GS reconstruction" + }, + { + "src": "input.gfile", + "dst": "fn.read_geqdsk", + "kind": "data", + "desc": "File path to g-file", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "input.ida_cdf", + "dst": "fn.imas._merge_ida_kinetics", + "kind": "data", + "desc": "IDA .cdf path from ImasSource.ida_path", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.ida_cdf", + "dst": "gate.time_index", + "kind": "data", + "desc": "File path and time selection", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "input.ida_cer", + "dst": "fn.read_ida_cer", + "kind": "data", + "desc": "File path and time selection", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "input.imas_ids", + "dst": "fn.imas.read_imas_geometry", + "kind": "data", + "desc": "load JSON, extract equilibrium.vacuum_toroidal_field + boundary", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.F0", + "kind": "data", + "desc": "equilibrium.vacuum_toroidal_field (r0, b0)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.Ip_target", + "kind": "data", + "desc": "equilibrium.global_quantities.ip", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.aux.E_r", + "kind": "data", + "desc": "core_profiles.e_field.radial (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.aux.chi_e", + "kind": "data", + "desc": "core_transport.model[0].electrons.energy.d (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.aux.chi_i", + "kind": "data", + "desc": "core_transport.model[0].total_ion_energy.d (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.boundary_lcfs", + "kind": "data", + "desc": "equilibrium.boundary.outline [r, z]", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.j_bootstrap_parallel", + "kind": "data", + "desc": "core_profiles.profiles_1d[ic].j_bootstrap", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.j_nbi_parallel", + "kind": "data", + "desc": "core_sources.source[NBI_SOURCE_INDEX].profiles_1d.j_parallel (summed)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.j_ohmic_parallel", + "kind": "data", + "desc": "core_profiles.profiles_1d[ic].j_ohmic (read, not used)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.j_tor_parallel", + "kind": "data", + "desc": "core_profiles.profiles_1d[ic].j_tor (authoritative)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.j_total_parallel", + "kind": "data", + "desc": "core_profiles.profiles_1d[ic].j_total", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.jphi_diff", + "kind": "data", + "desc": "equilibrium.profiles_1d.j_tor (for anchor)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.li_target", + "kind": "data", + "desc": "equilibrium.global_quantities.li_3", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.ne", + "kind": "data", + "desc": "core_profiles.electrons.density_thermal", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.ni", + "kind": "data", + "desc": "core_profiles.ion[Z=1].density_thermal", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.omega_tor", + "kind": "data", + "desc": "core_profiles.ion.rotation_frequency_tor (optional)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.p_equilibrium", + "kind": "data", + "desc": "equilibrium.profiles_1d.pressure (GS-consistent)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.psi_N", + "kind": "data", + "desc": "core_profiles.profiles_1d[ic].grid.psi \u2192 normalize", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.te", + "kind": "data", + "desc": "core_profiles.electrons.temperature", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.ti", + "kind": "data", + "desc": "core_profiles.ion[Z=1].temperature", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.imas_ids", + "dst": "qty.zeff", + "kind": "data", + "desc": "Sum_s(Z^2*n_s)/ne over all ions", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "input.isoflux", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Compute boundary deviation from LCFS contour", + "subsystem": "GS reconstruction" + }, + { + "src": "input.kinetics", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Pass ne, te, ni, ti, Zeff for bootstrap computation", + "subsystem": "GS reconstruction" + }, + { + "src": "input.kinetics", + "dst": "qty.pressure", + "kind": "data", + "desc": "Compute 1.6022e-19 * (ne*te + ni*ti)", + "subsystem": "GS reconstruction" + }, + { + "src": "input.mygs", + "dst": "fn.sampling.calc_cylindrical_li_proxy", + "kind": "data", + "desc": "TokaMaker solver for li calculation", + "subsystem": "GS reconstruction" + }, + { + "src": "input.mygs", + "dst": "fn.tmi._swb_jbs_to_toroidal", + "kind": "data", + "desc": "Pass mygs to extract F, ravgs, modb_avgs", + "subsystem": "GS reconstruction" + }, + { + "src": "input.pfile", + "dst": "fn.read_pfile", + "kind": "data", + "desc": "File path to p-file", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "input.user_args", + "dst": "knob.backend", + "kind": "control", + "desc": "User specifies backend='laptop'|'slurm'", + "subsystem": "Process-parallel path" + }, + { + "src": "input.user_args", + "dst": "knob.n_workers", + "kind": "control", + "desc": "User specifies n_workers (None defaults to _physical_cores)", + "subsystem": "Process-parallel path" + }, + { + "src": "input.user_args", + "dst": "knob.seed", + "kind": "control", + "desc": "User specifies seed (default 0)", + "subsystem": "Process-parallel path" + }, + { + "src": "input.user_args", + "dst": "knob.threads_per_worker", + "kind": "control", + "desc": "User specifies threads_per_worker (default 1)", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.backend", + "dst": "gate.backend", + "kind": "control", + "desc": "Backend parameter routes to laptop or slurm path", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.n_workers", + "dst": "fn.parallel._physical_cores", + "kind": "control", + "desc": "If n_workers is None, call _physical_cores()", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.n_workers", + "dst": "fn.parallel.emit_slurm_script", + "kind": "data", + "desc": "n_workers stored in bundle and SLURM array range", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.n_workers", + "dst": "quantity.n_equils_per_worker", + "kind": "data", + "desc": "n_workers used in _shard_size divisor", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.scan_key", + "dst": "quantity.per_worker_seed", + "kind": "data", + "desc": "Scan key folded into SeedSequence entropy", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.seed", + "dst": "fn.parallel.emit_slurm_script", + "kind": "data", + "desc": "Seed stored in bundle for SLURM worker recreation", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.seed", + "dst": "quantity.per_worker_seed", + "kind": "data", + "desc": "Seed (as seed_base) enters _derive_seed", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.threads_per_worker", + "dst": "env.blas_pinning", + "kind": "control", + "desc": "Threads value sets BLAS env vars", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.threads_per_worker", + "dst": "fn.parallel._warn_multithreaded", + "kind": "data", + "desc": "threads_per_worker checked in _warn_multithreaded", + "subsystem": "Process-parallel path" + }, + { + "src": "knob.threads_per_worker", + "dst": "fn.parallel.emit_slurm_script", + "kind": "data", + "desc": "threads_per_worker stored in bundle and embedded in sbatch env vars", + "subsystem": "Process-parallel path" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.F0", + "kind": "data", + "desc": "FPOL profile from raw g-file via .fpol property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.Ip_target", + "kind": "data", + "desc": "CURRENT from .Ip property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.boundary_lcfs", + "kind": "data", + "desc": "RBBBS/ZBBBS via .boundary_R, .boundary_Z properties", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.j_phi", + "kind": "data", + "desc": "Flux-surface-averaged Jt from j_tor_averaged property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.li_target", + "kind": "data", + "desc": "Computed li(1) from .li property (lazy-cached)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.p_thermal", + "kind": "data", + "desc": "PRES profile from raw g-file via .pres property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.GEQDSKEquilibrium", + "dst": "qty.psi_N", + "kind": "data", + "desc": "Normalized flux grid from GEQDSKEquilibrium.psi_N", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDACERProfiles", + "dst": "qty.e_r_cer", + "kind": "data", + "desc": "Derived from carbon force balance (optional)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.ne", + "kind": "data", + "desc": "Electron density in m^-3 from IDAProfiles.ne", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.ni", + "kind": "data", + "desc": "Main-ion density derived from (ne, Zeff) in IDAProfiles.ni", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.psi_N_kinetic", + "kind": "data", + "desc": "psi_N from IDA file (extends past separatrix)", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.sigma_ne", + "kind": "data", + "desc": "Electron density uncertainty from IDAProfiles.sigma_ne", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.sigma_ni", + "kind": "data", + "desc": "Ion density uncertainty from IDAProfiles.sigma_ni", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.sigma_te", + "kind": "data", + "desc": "Electron temperature uncertainty from IDAProfiles.sigma_te", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.sigma_ti", + "kind": "data", + "desc": "Ion temperature uncertainty from IDAProfiles.sigma_ti", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.te", + "kind": "data", + "desc": "Electron temperature in eV from IDAProfiles.te", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.ti", + "kind": "data", + "desc": "Ion temperature in eV from IDAProfiles.ti", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.IDAProfiles", + "dst": "qty.zeff", + "kind": "data", + "desc": "Effective charge from IDAProfiles.Zeff", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.PFile", + "dst": "qty.ne", + "kind": "data", + "desc": "Electron density from .ne property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.PFile", + "dst": "qty.ni", + "kind": "data", + "desc": "Ion density from .ni property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.PFile", + "dst": "qty.omega_tor", + "kind": "data", + "desc": "Toroidal rotation from .omeg property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.PFile", + "dst": "qty.te", + "kind": "data", + "desc": "Electron temperature from .te property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "obj.PFile", + "dst": "qty.ti", + "kind": "data", + "desc": "Ion temperature from .ti property", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "progress_callback", + "dst": "fn.tmi.generate_bouquet", + "kind": "control", + "desc": "Optional per-draw tick callback (line 3297; used for aggregate progress bar in parallel mode)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.F0", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Baseline F(psi) from g-file", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.FUSE_tot", + "dst": "gate.jBS_baseline_mode", + "kind": "data", + "desc": "FUSE total current reference for diff mode anchor", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.Ip", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final Ip stored in EQDSK", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_scales", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Iteration history of Ip scale factors", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.Ip_target", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.Ip_target", + "dst": "ext.corrective_jphi_iteration", + "kind": "data", + "desc": "Ip target for TokaMaker", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.Ip_target", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Plasma current target for SWB Ip scaling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Target Ip from g-file", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.Ip_target", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Plasma current target for forward solve", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.Ip_target", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Ip target passed to generate_bouquet; fixed across all draws", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.Ip_target", + "dst": "fn.tmi._corrective_jphi_iteration", + "kind": "data", + "desc": "Plasma current constraint", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "fn.tmi.find_optimal_scale", + "kind": "data", + "desc": "Plasma current constraint for j0 scaling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "fn.tmi.recon_anchor_solve", + "kind": "data", + "desc": "Plasma current target for GS solve", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "qty.a_optimal", + "kind": "data", + "desc": "Target for Ip_flux_integral_vs_target root find", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Ip_target", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Ip reference", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.Ip_tokamaker", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Ip_error_pct", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.Z_imp", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.Z_imp", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.Z_imp", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Impurity pressure added if Z_imp > 0", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Zeff", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Effective charge to SWB Sauter model", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Zeff", + "dst": "gate.zeff_active", + "kind": "data", + "desc": "Effective charge baseline/drawing source", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.Zeff_eq", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Zeff_eq on psi_N passed to generate_bouquet; used by SWB in draw loops", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.a_optimal", + "dst": "qty.matched_jphi_perturb", + "kind": "data", + "desc": "Scale factor applied to GPR draw", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.aux_baselines", + "dst": "gate.zeff_active", + "kind": "data", + "desc": "Zeff baseline for derivation", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.aux_baselines", + "dst": "qty.aux_out", + "kind": "data", + "desc": "Baseline profiles for auxiliary channels (omega_tor, e_r, chi_*, and/or zeff)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_baselines", + "dst": "qty.zeff_draw", + "kind": "data", + "desc": "Baseline Zeff from aux_baselines['zeff'] (line 980)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_length_scales", + "dst": "qty.aux_out", + "kind": "data", + "desc": "GPR length scales for auxiliary channel sampling", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_length_scales", + "dst": "qty.zeff_draw", + "kind": "data", + "desc": "GPR length scale for Zeff from aux_length_scales.get('zeff', 0.4)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_out", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Perturbed auxiliary profiles (zeff, omega_tor, e_r, chi_*) archived for each draw", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_out", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Store auxiliary profiles in diagnostics", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.aux_sigmas", + "dst": "gate.zeff_active", + "kind": "data", + "desc": "Enables Zeff channel if 'zeff' key present", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.aux_sigmas", + "dst": "qty.aux_out", + "kind": "control", + "desc": "Presence of keys gates which auxiliary channels are sampled (line 1038)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_sigmas", + "dst": "qty.zeff_draw", + "kind": "control", + "desc": "Zeff channel activated by presence of 'zeff' key in aux_sigmas dict", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.aux_sigmas", + "dst": "qty.zeff_draw", + "kind": "data", + "desc": "Sigma Zeff from aux_sigmas['zeff'] (line 981)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.baseline_j_BS_with_diff", + "dst": "fn.run.generate", + "kind": "data", + "desc": "baseline_j_BS (with diff applied if present) passed to generate_bouquet", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.baseline_li_proxy", + "dst": "qty.proxy_target", + "kind": "data", + "desc": "Initial proxy target before adaptive correction", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.boundary_lcfs", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Separatrix contour for geometry", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.bs_scale", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Scales jBS_scale_range centering in generate()", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.bs_scale", + "dst": "qty.j_phi_fit_prelim", + "kind": "control", + "desc": "Scale bootstrap if rescale_j_BS=True", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.coil_currents", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Coil currents from mygs post-solve", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.coil_currents", + "dst": "art.perturbed_lcfs_ref", + "kind": "data", + "desc": "LCFS geometry from final coil solution", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.diagnostics", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Per-draw observables (l_i, Ip, boundary, coils) archived in HDF5", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.eq_stats", + "dst": "qty.baseline_li_proxy", + "kind": "data", + "desc": "Proxy computed on anchor geometry for comparison", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.eqdsk_j_tor", + "dst": "fn.sampling.calc_cylindrical_li_proxy", + "kind": "data", + "desc": "Pass j_phi_profile", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.eqdsk_j_tor", + "dst": "fn.tmi._shelf_blend_decompose", + "kind": "data", + "desc": "Pass as j_phi_total", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.eqdsk_j_tor", + "dst": "fn.tmi.classify_jphi_profile", + "kind": "data", + "desc": "Pass eqdsk_jphi for edge peak detection", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.eqdsk_j_tor", + "dst": "qty.j_phi_corrective_target", + "kind": "data", + "desc": "Fallback for L_mode case", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.eqdsk_j_tor", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Reference for RMS calculation", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.ffp_prof_li", + "dst": "ext.tokamaker_solve", + "kind": "data", + "desc": "Current profiles via set_profiles", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.final_jphi", + "dst": "gate.constrain_sawteeth_pre", + "kind": "data", + "desc": "q-profile check after find_optimal_scale", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.final_jphi", + "dst": "qty.target_jphi_perturb", + "kind": "data", + "desc": "Incorporates j0 scale from find_optimal_scale", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.final_li_proxy", + "dst": "qty.proxy_vs_real", + "kind": "data", + "desc": "Proxy - real l_i offset for convergence feedback", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.final_scale_j0", + "dst": "qty.target_jphi_perturb", + "kind": "data", + "desc": "Scale factor applied to matched_j_inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.full_j_BS", + "dst": "fn.tmi._swb_jbs_to_toroidal", + "kind": "data", + "desc": "Convert SWB parallel projection to toroidal convention", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.full_j_BS", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Store j_BS (physical Sauter or delta)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ind_factor_opt", + "dst": "qty.j_ind_li_matched", + "kind": "data", + "desc": "ind_factor_opt * j_inductive_fit", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.ind_scale", + "dst": "qty.j_inductive_fit", + "kind": "data", + "desc": "Scale basis profile", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.input_j_phi", + "dst": "qty.spike_profile", + "kind": "data", + "desc": "Recon j_phi for PIN_JPHI spike extraction", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.input_jinductive", + "dst": "qty.jphi_perturb", + "kind": "data", + "desc": "Inductive shape baseline for GPR sampling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.input_jinductive", + "dst": "qty.new_jphi", + "kind": "data", + "desc": "Standard SWB: inductive baseline for anchor", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.input_jinductive", + "dst": "qty.spike_profile", + "kind": "data", + "desc": "Recon inductive for PIN_JPHI spike extraction", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.iteration_Ips", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Iteration history of equilibrium Ip", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.iteration_l_is", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Iteration history of equilibrium l_i", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j0_scales", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Iteration history of j0 scale factors", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.jBS_diff", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Passed to generate_bouquet for diff-mode anchoring (None in rescale)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.jBS_diff", + "dst": "qty.baseline_j_BS_with_diff", + "kind": "data", + "desc": "Additive offset for diff mode (None in rescale, treated as 0)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.jBS_diff", + "dst": "qty.spike_profile", + "kind": "data", + "desc": "Bootstrap correction anchor (Case-B differential)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.jBS_scale_range_centered", + "dst": "ext.generate_bouquet", + "kind": "data", + "desc": "Bootstrap scale range centered on bs_scale; perturbed per draw", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.jBS_scales", + "dst": "fn.tmi.perturb_kinetic_equilibrium", + "kind": "data", + "desc": "scale_jBS=jBS_scales[count] sampled per draw (line 3299)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.j_BS", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.j_BS", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_BS", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "subtracted to compute residual", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_BS_final", + "dst": "qty.j_ind_final", + "kind": "data", + "desc": "Subtracted to isolate inductive", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "fn.tmi._shelf_blend_decompose", + "kind": "data", + "desc": "Pass as spike_profile for decomposition", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "fn.tmi.classify_jphi_profile", + "kind": "data", + "desc": "Pass j_BS_isolated as spike_profile", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "data", + "desc": "Pass as j_BS_isolated", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "qty.ffp_prof_li", + "kind": "data", + "desc": "Bootstrap component", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "qty.j_BS_shelved", + "kind": "data", + "desc": "Optional shelf via searchsorted + assignment", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "qty.j_phi_corrective_target", + "kind": "data", + "desc": "Bootstrap component (H/Lmode case)", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_isolated", + "dst": "qty.j_phi_fit_prelim", + "kind": "data", + "desc": "Bootstrap component", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_shelved", + "dst": "qty.j_BS_smoothed", + "kind": "data", + "desc": "Gaussian filter transition zone", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_smoothed", + "dst": "qty.j_BS_isolated", + "kind": "data", + "desc": "Use smoothed profile for li matching", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_src", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "FUSE source j_BS; used as reference for diff calculation", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_BS_src", + "dst": "gate.jBS_baseline_mode", + "kind": "data", + "desc": "FUSE j_BS input to diff calculation (diff mode)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_BS_swb", + "dst": "fn.tmi._swb_jbs_to_toroidal", + "kind": "data", + "desc": "Pass j_bs_swb for conversion", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_BS_swb", + "dst": "gate.jBS_baseline_mode", + "kind": "data", + "desc": "SWB j_BS input to diff/rescale logic", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_BS_swb", + "dst": "qty.baseline_j_BS_with_diff", + "kind": "data", + "desc": "j_BS input; offset by jBS_diff (diff mode) or used as-is (rescale)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_NBI", + "dst": "qty.j_fixed_eff", + "kind": "data", + "desc": "NBI current contribution to fixed additive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_NBI_toroidal", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.j_NBI", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_NBI_toroidal", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "subtracted to compute residual", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_RF", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.j_RF", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_RF", + "dst": "qty.j_fixed_eff", + "kind": "data", + "desc": "RF current contribution to fixed additive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_RF", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "subtracted to compute residual", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_bootstrap_parallel", + "dst": "fn.physics.parallel_to_toroidal", + "kind": "data", + "desc": "input component to convert", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_fixed_eff", + "dst": "qty.a_optimal", + "kind": "data", + "desc": "Fixed additive (held constant)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_fixed_eff", + "dst": "qty.j_inductive_consistent", + "kind": "data", + "desc": "Subtract fixed to get inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_fixed_eff", + "dst": "qty.matched_jphi_perturb", + "kind": "data", + "desc": "Added to scaled inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_fixed_eff", + "dst": "qty.new_jphi", + "kind": "data", + "desc": "Fixed additive currents added to new_jphi", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_fixed_eff", + "dst": "qty.target_jphi_perturb", + "kind": "data", + "desc": "Added to scaled inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_ind_li_matched", + "dst": "qty.j_phi_corrective_target", + "kind": "data", + "desc": "Inductive component (H/Lmode case)", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_inductive", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.j_inductive", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_inductive", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "FUSE ohmic current (kept fixed in diff/rescale logic)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_inductive", + "dst": "fn.run.generate", + "kind": "data", + "desc": "input_jinductive passed to generate_bouquet (perturbed via l_i matching)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_inductive_basis", + "dst": "qty.j_inductive_fit", + "kind": "data", + "desc": "Apply ind_scale", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_inductive_consistent", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Store inductive component in diagnostics", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_inductive_fit", + "dst": "qty.ffp_prof_li", + "kind": "data", + "desc": "j_phi = ind_factor * j_ind_fit + j_BS", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_inductive_fit", + "dst": "qty.j_ind_li_matched", + "kind": "data", + "desc": "Base inductive profile", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_inductive_fit", + "dst": "qty.j_phi_fit_prelim", + "kind": "data", + "desc": "Add j_BS component", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_ls", + "dst": "qty.jphi_perturb", + "kind": "data", + "desc": "GPR correlation length for j_phi", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.j_nbi_parallel", + "dst": "fn.physics.parallel_to_toroidal", + "kind": "data", + "desc": "NBI component (parallel)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_phi", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.j_phi", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_phi", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Input to first jphi-linterp forward solve (baseline total current)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_phi", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Baseline j_phi passed to generate_bouquet (starting point for perturbations)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.j_phi", + "dst": "qty.j_inductive", + "kind": "data", + "desc": "j_inductive = j_phi - j_BS - j_NBI - j_RF (residual)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_phi", + "dst": "qty.jphi_diff", + "kind": "data", + "desc": "jphi_diff = eq_jtor - j_phi", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_phi", + "dst": "qty.sigma_jphi", + "kind": "data", + "desc": "baseline for sigma fraction", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.j_phi_corrective_target", + "dst": "ext.corrective_jphi_iteration", + "kind": "data", + "desc": "Target j_phi for Newton correction", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_phi_final", + "dst": "qty.j_ind_final", + "kind": "data", + "desc": "j_ind_final = j_phi_final - j_BS_final", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_phi_final", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Compute RMS vs eqdsk_jtor (core/edge)", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_phi_output_corr", + "dst": "qty.j_phi_final", + "kind": "data", + "desc": "Direct copy to final", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.j_tor_parallel", + "dst": "fn.physics.parallel_to_toroidal", + "kind": "data", + "desc": "ratio method: c(psi)=j_tor/j_total", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_tor_parallel", + "dst": "qty.j_phi", + "kind": "data", + "desc": "j_phi = j_tor (copy of authoritative total)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.j_total_parallel", + "dst": "fn.physics.parallel_to_toroidal", + "kind": "data", + "desc": "ratio method: c(psi)=j_tor/j_total", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.jphi_diff", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.jphi_diff", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.jphi_diff", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Fixed jphi offset (IMAS only); passed to generate_bouquet", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.jphi_diff", + "dst": "qty.j_fixed_eff", + "kind": "data", + "desc": "j_phi correction anchor absorbed into fixed", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.jphi_mode", + "dst": "gate.jphi_classified", + "kind": "control", + "desc": "Branch control", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.jphi_mode", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Store classification", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.jphi_perturb", + "dst": "qty.a_optimal", + "kind": "data", + "desc": "GPR draw to be Ip-normalized", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.jphi_perturb", + "dst": "qty.matched_jphi_perturb", + "kind": "data", + "desc": "Scaled by a_optimal", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.l_i", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final l_i stored in EQDSK metadata", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.l_i", + "dst": "gate.li_acceptance", + "kind": "data", + "desc": "Test: |l_i - l_i_target| / l_i_target vs tolerance", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.l_i", + "dst": "qty.proxy_vs_real", + "kind": "data", + "desc": "Real equilibrium l_i for offset computation", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.l_i_target", + "dst": "gate.li_acceptance", + "kind": "data", + "desc": "Target internal inductance", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.l_i_target_draw", + "dst": "gate.li_band", + "kind": "data", + "desc": "Target for acceptance: computed equilibrium l_i must land within band of this value", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.li_current", + "dst": "gate.li_converged", + "kind": "data", + "desc": "Check |li_current - li_target| < li_tol", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.li_final", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "li_error = |li_final - li_target|", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.li_proxy_baseline", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "data", + "desc": "Target li proxy for scaling", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.li_target", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.l_i_target", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.li_target", + "dst": "fn.run.generate", + "kind": "data", + "desc": "li_target passed to generate_bouquet; anchors l_i matching loop", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.li_target", + "dst": "gate.li_converged", + "kind": "data", + "desc": "Convergence threshold", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.matched_j_inductive", + "dst": "gate.li_loop_variant", + "kind": "data", + "desc": "Inductive baseline from anchor (Fix-B/C) or input (standard)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.matched_jphi_perturb", + "dst": "fn.tmi.find_optimal_scale", + "kind": "data", + "desc": "Target j_phi for j0-scaling inverse solve", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.n_ls", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "GPR length scale for density", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.n_ls", + "dst": "qty.ne_draw", + "kind": "data", + "desc": "GPR correlation length for density", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ne", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.ne", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ne", + "dst": "fn.imas._merge_ida_kinetics", + "kind": "data", + "desc": "FUSE baseline (fallback if IDA fails)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ne", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to thermal species completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ne", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Electron density for pinning coils / baseline", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.ne", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Electron density; input to solve_with_bootstrap SWB call", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ne", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Baseline ne passed to generate_bouquet (perturbed via sigma_ne)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ne", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Baseline density input to GPR sampling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ne", + "dst": "gate.sigma_priority_ne", + "kind": "data", + "desc": "baseline profile for scalar fraction", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.ne", + "dst": "qty.Z_imp", + "kind": "data", + "desc": "effective_impurity_charge(ne, ni, Zeff)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ne", + "dst": "qty.ne_draw", + "kind": "data", + "desc": "Baseline input to _draw_monotonic_perturbation (line 968-970)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ne", + "dst": "qty.zeff", + "kind": "data", + "desc": "denominator for Zeff normalization", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ne_draw", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Perturbed density profile archived in HDF5 (on psi_N_kinetic if dual-grid)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ne_draw", + "dst": "qty.ni_draw", + "kind": "data", + "desc": "Input to main_ion_density_from_zeff via quasineutrality (Zeff-primary mode)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ne_draw", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Interpolated to equilibrium grid (ne_eq), combined with te_eq in pressure formula (line 1006)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ne_perturb", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final perturbed kinetics stored in EQDSK region", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ne_perturb", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Perturbed electron density to SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ne_perturb", + "dst": "qty.p_thermal", + "kind": "data", + "desc": "Electron contribution to pressure; interpolate to psi_N", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.new_jphi", + "dst": "fn.tmi.recon_anchor_solve", + "kind": "data", + "desc": "j_phi shape for GS solve via linterp", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ni", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.ni", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ni", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to thermal species completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ni", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Ion density for pressure calculation", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.ni", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Ion density; input to SWB", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ni", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Baseline ni passed to generate_bouquet (perturbed via sigma_ni)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ni", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Baseline ion density or Zeff-derivation input", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ni", + "dst": "gate.sigma_priority_ni", + "kind": "data", + "desc": "baseline profile for scalar fraction", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.ni", + "dst": "qty.Z_imp", + "kind": "data", + "desc": "effective_impurity_charge(ne, ni, Zeff)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ni", + "dst": "qty.ni_draw", + "kind": "data", + "desc": "Baseline input when Zeff-primary inactive (sampled independently via _draw_monotonic_perturbation)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ni", + "dst": "qty.p_imp", + "kind": "data", + "desc": "impurity pressure (single-impurity model)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ni_draw", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Perturbed ion density (or derived from Zeff) archived", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ni_draw", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Interpolated to equilibrium grid (ni_eq), EC*ni_eq*ti_eq term", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ni_perturb", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final perturbed kinetics stored in EQDSK region", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ni_perturb", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Perturbed ion density to SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ni_perturb", + "dst": "qty.p_thermal", + "kind": "data", + "desc": "Ion contribution to pressure", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final j_phi stored in EQDSK", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Converged j_phi passed to store_equilibrium for per-draw archival", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.output_jphi", + "dst": "gate.constrain_sawteeth_post", + "kind": "data", + "desc": "q-profile check after corrective iteration", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "qty.Ip", + "kind": "data", + "desc": "Get equilibrium Ip after converged output_jphi is set", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "qty.final_li_proxy", + "kind": "data", + "desc": "Diagnostic proxy computed on converged state", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "qty.j_inductive_consistent", + "kind": "data", + "desc": "j_phi = j_ind + j_BS + j_fixed (close loop)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.output_jphi", + "dst": "qty.l_i", + "kind": "data", + "desc": "Get equilibrium l_i after converged output_jphi is set", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.p_diff", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.p_diff", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_diff", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Fixed pressure offset (IMAS only); passed to generate_bouquet", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.p_diff", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Pressure anchor correction added every draw", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.p_equilibrium", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.p_equilibrium", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_equilibrium", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "authoritative pressure for comparison", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_equilibrium", + "dst": "qty.p_diff", + "kind": "data", + "desc": "p_diff = p_equilibrium - p_recon", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_fast", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.p_fast", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_fast", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to fast-channel completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_fast", + "dst": "qty.p_recon", + "kind": "data", + "desc": "fast-ion pressure component", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_fast", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Fast-ion pressure (fixed, never perturbed)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.p_imp", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to thermal species completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_imp", + "dst": "qty.p_recon", + "kind": "data", + "desc": "impurity pressure component", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_recon", + "dst": "qty.p_diff", + "kind": "data", + "desc": "p_diff = p_equilibrium - p_recon", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.p_thermal", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Baseline pressure from g-file", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.p_thermal", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Thermal pressure base", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.p_total", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Total pressure (thermal + fast + p_diff); input to forward solve", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.pprime", + "dst": "qty.pprime_gs", + "kind": "data", + "desc": "Package into dict for set_profiles", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.pprime_gs", + "dst": "ext.corrective_jphi_iteration", + "kind": "data", + "desc": "Pressure gradient for each solve", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.pprime_gs", + "dst": "ext.tokamaker_solve", + "kind": "data", + "desc": "Set via set_profiles", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.pres_tmp", + "dst": "fn.tmi._corrective_jphi_iteration", + "kind": "data", + "desc": "Pressure profile for repeated GS solves", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.pres_tmp", + "dst": "fn.tmi.find_optimal_scale", + "kind": "data", + "desc": "Pressure profile for PP' + pax", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.pres_tmp", + "dst": "fn.tmi.perturb_kinetic_equilibrium", + "kind": "data", + "desc": "Passed as pres_tmp to pressure-matching loop, l_i matching, GS solves", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.pres_tmp", + "dst": "fn.tmi.recon_anchor_solve", + "kind": "data", + "desc": "Perturbed pressure profile for GS solve", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.pres_tmp", + "dst": "gate.recalculate_jBS", + "kind": "data", + "desc": "Perturbed total pressure for j_BS recalculation", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.pressure", + "dst": "fn.tmi.perturb_kinetic_equilibrium", + "kind": "data", + "desc": "Baseline

for pressure-matching loop convergence (flux_integral mismatch check)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.pressure", + "dst": "qty.pprime", + "kind": "data", + "desc": "Gradient via np.gradient / psi_range", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.proxy_target", + "dst": "gate.li_band_loop", + "kind": "data", + "desc": "Adaptive target for proxy-based draw pre-screen", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.proxy_vs_real", + "dst": "qty.proxy_target", + "kind": "control", + "desc": "Adaptive Newton correction: proxy_target *= l_i_target/l_i", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.psi_N", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.psi_N", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.psi_N", + "dst": "fn.imas._merge_ida_kinetics", + "kind": "data", + "desc": "resample IDA profiles onto FUSE psi_N", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.psi_N", + "dst": "fn.imas._override", + "kind": "data", + "desc": "destination psi_N grid for resampling", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.psi_N", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Flux-surface basis for averaging", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.psi_N", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "psi_N from baseline; used for jphi-linterp grid", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.psi_N", + "dst": "fn.tmi.classify_jphi_profile", + "kind": "data", + "desc": "Pass psi_N grid", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.psi_N", + "dst": "qty.Zeff_eq", + "kind": "data", + "desc": "Zeff interpolated from psi_N_kinetic to psi_N for generate()", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.psi_N_kinetic", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.psi_N_kinetic", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.psi_N_kinetic", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Kinetic grid; kinetics interpolated to psi_N for forward solve", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.sigma_jphi", + "dst": "qty.jphi_perturb", + "kind": "data", + "desc": "Current-profile uncertainty envelope", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.sigma_ne", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Density uncertainty envelope", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.sigma_ne", + "dst": "qty.ne_draw", + "kind": "data", + "desc": "GPR envelope for density perturbation", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.sigma_te", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Temperature uncertainty envelope", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.sigma_te", + "dst": "qty.te_draw", + "kind": "data", + "desc": "GPR envelope for temperature perturbation", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.sigma_ti", + "dst": "qty.ti_draw", + "kind": "data", + "desc": "GPR envelope for ion temperature perturbation", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.spike_metrics", + "dst": "qty.quality_metrics", + "kind": "data", + "desc": "Merge spike detection results", + "subsystem": "GS reconstruction" + }, + { + "src": "qty.spike_profile", + "dst": "fn.tmi._swb_jbs_to_toroidal", + "kind": "data", + "desc": "Convert SWB edge spike to toroidal convention", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.a_optimal", + "kind": "data", + "desc": "Bootstrap spike (fixed during Ip normalization)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.diagnostics", + "kind": "data", + "desc": "Store j_BS_edge if isolate_edge_jBS=True", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.j_inductive_consistent", + "kind": "data", + "desc": "Subtract spike to get inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.matched_jphi_perturb", + "kind": "data", + "desc": "Added to scaled inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.new_jphi", + "kind": "data", + "desc": "Bootstrap spike added to new_jphi", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.spike_profile", + "dst": "qty.target_jphi_perturb", + "kind": "data", + "desc": "Added to scaled inductive", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.t_ls", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "GPR length scale for temperature", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.t_ls", + "dst": "qty.te_draw", + "kind": "data", + "desc": "GPR correlation length for temperature", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.target_jphi_perturb", + "dst": "fn.tmi._corrective_jphi_iteration", + "kind": "data", + "desc": "Target for corrective iteration", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.te", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.te", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.te", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to thermal species completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.te", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Electron temperature for physics", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.te", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Electron temperature; input to SWB", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.te", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Baseline te passed to generate_bouquet (perturbed via sigma_te)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.te", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Baseline temperature input to GPR sampling", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.te", + "dst": "gate.sigma_priority_te", + "kind": "data", + "desc": "baseline profile for scalar fraction", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.te", + "dst": "qty.p_recon", + "kind": "data", + "desc": "e*ne*te (thermal electron pressure)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.te", + "dst": "qty.te_draw", + "kind": "data", + "desc": "Baseline input to _draw_monotonic_perturbation", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.te_draw", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Perturbed temperature profile archived", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.te_draw", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Interpolated to equilibrium grid (te_eq), EC*ne_eq*te_eq term", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.te_perturb", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final perturbed kinetics stored in EQDSK region", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.te_perturb", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Perturbed electron temperature to SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.te_perturb", + "dst": "qty.p_thermal", + "kind": "data", + "desc": "Electron temperature contribution", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ti", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.ti", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ti", + "dst": "fn.imas._validate_pressure_completeness", + "kind": "data", + "desc": "input to thermal species completeness check", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ti", + "dst": "fn.reconstruct_equilibrium", + "kind": "data", + "desc": "Ion temperature for pressure", + "subsystem": "Input readers (g-file / p-file / IDA)" + }, + { + "src": "qty.ti", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Ion temperature; input to SWB", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ti", + "dst": "fn.run.generate", + "kind": "data", + "desc": "Baseline ti passed to generate_bouquet (perturbed via sigma_ti)", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.ti", + "dst": "gate.pressure_match", + "kind": "data", + "desc": "Baseline ion temperature input to GPR", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ti", + "dst": "gate.sigma_priority_ti", + "kind": "data", + "desc": "baseline profile for scalar fraction", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.ti", + "dst": "qty.p_imp", + "kind": "data", + "desc": "impurity pressure uses main-ion Ti", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ti", + "dst": "qty.p_recon", + "kind": "data", + "desc": "e*ni*ti (thermal ion pressure)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.ti", + "dst": "qty.ti_draw", + "kind": "data", + "desc": "Baseline input to _draw_monotonic_perturbation", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ti_draw", + "dst": "fn.utils.store_equilibrium", + "kind": "data", + "desc": "Perturbed ion temperature archived", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ti_draw", + "dst": "qty.pres_tmp", + "kind": "data", + "desc": "Interpolated to equilibrium grid (ti_eq), EC*ni_eq*ti_eq term", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.ti_perturb", + "dst": "art.eqdsk_bytes", + "kind": "data", + "desc": "Final perturbed kinetics stored in EQDSK region", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ti_perturb", + "dst": "ext.solve_with_bootstrap", + "kind": "data", + "desc": "Perturbed ion temperature to SWB", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.ti_perturb", + "dst": "qty.p_thermal", + "kind": "data", + "desc": "Ion temperature contribution", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "qty.zeff", + "dst": "artifact.baseline", + "kind": "data", + "desc": "Baseline.Zeff", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.zeff", + "dst": "fn.run._forward_solve_imas_baseline", + "kind": "data", + "desc": "Zeff; input to SWB", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.zeff", + "dst": "gate.sigma_priority_zeff", + "kind": "data", + "desc": "baseline zeff for auto-injected sigma", + "subsystem": "Baseline & uncertainty resolution" + }, + { + "src": "qty.zeff", + "dst": "qty.Z_imp", + "kind": "data", + "desc": "effective_impurity_charge(ne, ni, Zeff)", + "subsystem": "IMAS/OMAS reader" + }, + { + "src": "qty.zeff", + "dst": "qty.Zeff_eq", + "kind": "data", + "desc": "Baseline Zeff on kinetic grid; interpolated to equilibrium grid", + "subsystem": "Bouquet orchestrator / IMAS forward solve" + }, + { + "src": "qty.zeff_draw", + "dst": "qty.ni_draw", + "kind": "data", + "desc": "When Zeff-primary active: ni = main_ion_density_from_zeff(ne_draw, zeff_draw, Z_imp) (line 990)", + "subsystem": "Draw loop (GPR sampling)" + }, + { + "src": "qty.zeff_draw", + "dst": "qty.ni_perturb", + "kind": "data", + "desc": "Zeff-primary channel: ni = ni(ne, Zeff, Z_imp)", + "subsystem": "Per-draw solve (SWB / l_i / homotopy)" + }, + { + "src": "quantity.eqdsk_j_tor", + "dst": "fn.tmi.fit_inductive_profile", + "kind": "data", + "desc": "Pass as eqdsk_jtor target", + "subsystem": "GS reconstruction" + }, + { + "src": "quantity.n_equils_per_worker", + "dst": "fn.parallel.run_shard", + "kind": "data", + "desc": "Shard size assigned to cfg.generation.n_equils", + "subsystem": "Process-parallel path" + }, + { + "src": "quantity.n_equils_total", + "dst": "quantity.n_equils_per_worker", + "kind": "data", + "desc": "Total draws -> per-worker shard size via _shard_size", + "subsystem": "Process-parallel path" + }, + { + "src": "quantity.per_worker_seed", + "dst": "fn.parallel.run_shard", + "kind": "data", + "desc": "Per-worker seed passed to run_shard as cfg.generation.seed", + "subsystem": "Process-parallel path" + } + ] +} \ No newline at end of file diff --git a/docs/flowchart/index.html b/docs/flowchart/index.html new file mode 100644 index 0000000..9e64e8e --- /dev/null +++ b/docs/flowchart/index.html @@ -0,0 +1,13289 @@ + + + + + +bouquet — logic flow map + + + +

+

bouquet — workflow & logic map

+
Start with the physics workflow (what happens to the + profiles and equilibrium quantities); open the full logic map below to + see every config knob, decision gate, and artifact, each anchored to + file:line (hover). Scroll to zoom, drag to pan the full map. + Snapshot of commit 8753c3a.
+
+
+ The physics workflow — GP perturbation → derived quantities → + bootstrap → ℓ_i matching → GS solve → archive +
+ + +bouquet_physics + + + + + +cluster_p0 + + +Inputs        (solid blue = required for its path, dashed = optional) + + + + +cluster_p1 + + +Baseline (once per slice) + + + + +cluster_p2 + + +repeat × +N +ens +   (each draw independent) + + + + + +gfile + +geqdsk +ψ +(R,Z), +p +, +q +, +j +φ +, separatrix + + + +recon + +GS reconstruction (geqdsk path) +fit inductive spline, full-Sauter +j +BS +j +φ + = +j +ind + + +j +BS + ;  match + +i +(1) by secant +targets: +I +p +, + +i + + + +gfile->recon + + + + + +kin + +kinetic profiles + σ( +ψ +N +) envelopes +n +e +, +T +e +, +T +i + (, +n +i +, +ω +tor +) +p-file or kinetic-fit netCDF + + + +kin->recon + + + + + +envel + +uncertainty envelope +σ +n +, +σ +T +, +σ +Zeff +, +σ + +  +  GP length scales + +n +, + +T +, + +j + + + +kin->envel + + + + + +ids + +IMAS/OMAS IDS +n +e +, +T +e +, +T +i +, +Z +eff +;   +j +ohmic +, +j +BS +, +j +NBI +; +p +fast +;  equilibrium anchors + + + +fsolve + +forward solve (IMAS/OMAS path) +keep IDS +j +ohmic +;  Sauter +j +BS + reconciliation +(diff: +j +BS,diff + = +j +BS +IDS + +j +BS +Sauter +  |  rescale) +anchors: +p +diff +, +j +φ,diff + ;   + +i + target = solved + +i +(1) + + + +ids->fsolve + + + + + +lcfs + +magnetics-only LCFS +(separatrix target override) + + + +lcfs->fsolve + + + + + +fixed + +fixed arrays +j +NBI +, +j +RF +, +p +fast +( +ψ +N +) + + + +rebuild + +rebuild total current +j +φ + = +j +ind + + +s +· +j +BS + (+ +j +BS,diff +) + +j +NBI + + +j +RF + (+ +j +φ,diff +) + + + +fixed->rebuild + + + + + +sigmas + +explicit σ profiles +or diagnostic σ source + + + +sigmas->envel + + + + + +quasi + +quasineutral densities +n +i + = +n +e + ( +Z +imp + +Z +eff +) / ( +Z +imp + − 1) + + + +recon->quasi + + + + + +fsolve->quasi + + + + + +quasi->envel + + + + + +gp + +GP profile sampling (Gibbs kernel) +draw +n +e +, +T +e +, +T +i +, +Z +eff +, +j +ind + ~ GP(baseline, σ, ℓ) +within envelopes; SOL included via +ψ +N,kin + grid + + + +envel->gp + + + + + +derive + +recompute derived +n +i + from drawn +Z +eff + (quasineutrality) +p +tot + = Σ +a + +e + +n +a + +T +a + + +p +imp + + +p +fast + (+ +p +diff +) + + + +gp->derive + + + + + +pgate + + +P +⟩ within 5% +of baseline? + + + +derive->pgate + + + + + +pgate->gp + + +resample + + + +boot + +bootstrap recompute (Sauter) +j +BS + = f( +n +, +T +, +Z +eff +)   (3 self-consistent iterations) +parallel→toroidal: +c + = 1 / (⟨ +R +⟩⟨1/ +R +⟩) +scale +s + ~ U(0.99, 1.01) · +s +0 + + + +pgate->boot + + +yes + + + +boot->rebuild + + + + + +limatch + + +i + matching +(optionally sample target ~ N( + +i +, +σ +ℓi +)) +scale +j +ind + + corrective iteration +until | + +i + − target| ≤ 5% + + + +rebuild->limatch + + + + + +limatch->limatch + + + iterate + + + +gssolve + +TokaMaker free-boundary GS solve +isoflux separatrix + +I +p + target +coil homotopy: bounds ±5% → ±2% → ±1% (warm-started) +VSC pair handles vertical control + + + +limatch->gssolve + + + + + +gssolve->gssolve + + + homotopy + passes + + + +agate + +accepted? +converged, + +i + in band, +q +0 + ≥ 1 (optional) + + + +gssolve->agate + + + + + +agate->gp + + +reject draw + + + +inspec + +in-spec tag +coil drift ≤ 2%;  VSC via quadrature-propagated σ + + + +agate->inspec + + +yes + + + +archive + +HDF5 ensemble archive (schema v2) +profiles, +j + components, g-/p-file bytes, +coil currents, targets, provenance (config) + + + +inspec->archive + + + + + +filter + +post-filtering (non-destructive) +boundary RMS ≤ 5 mm;  coil spec +⇒ selected (machine-realizable) sub-ensemble + + + +archive->filter + + + + + + +
+
+
+ Stage overview of the code (552 nodes, 761 + edges in the full map below) + + +bouquet_overview + + + + + + +Configuration + + +Configuration +(148 nodes) + + + + + +Input readers (g-file / p-file / IDA) + + +Input readers (g-file / p-file / IDA) +(16 nodes) + + + + + + +Configuration->Input readers (g-file / p-file / IDA) + + +4 + + + +IMAS/OMAS reader + + +IMAS/OMAS reader +(28 nodes) + + + + + +Configuration->IMAS/OMAS reader + + +1 + + + +Baseline & uncertainty resolution + + +Baseline & uncertainty resolution +(33 nodes) + + + + + +Configuration->Baseline & uncertainty resolution + + +5 + + + +Bouquet orchestrator / IMAS forward solve + + +Bouquet orchestrator / IMAS forward solve +(23 nodes) + + + + + +Configuration->Bouquet orchestrator / IMAS forward solve + + +6 + + + +Per-draw solve (SWB / l_i / homotopy) + + +Per-draw solve (SWB / l_i / homotopy) +(61 nodes) + + + + + +Configuration->Per-draw solve (SWB / l_i / homotopy) + + +4 + + + +Input readers (g-file / p-file / IDA)->Configuration + + +1 + + + + +Input readers (g-file / p-file / IDA)->IMAS/OMAS reader + + +1 + + + +Input readers (g-file / p-file / IDA)->Baseline & uncertainty resolution + + +1 + + + +Input readers (g-file / p-file / IDA)->Bouquet orchestrator / IMAS forward solve + + +10 + + + +Input readers (g-file / p-file / IDA)->Per-draw solve (SWB / l_i / homotopy) + + +7 + + + +IMAS/OMAS reader->Configuration + + +1 + + + +IMAS/OMAS reader->Input readers (g-file / p-file / IDA) + + +8 + + + + +IMAS/OMAS reader->Baseline & uncertainty resolution + + +5 + + + +GS reconstruction + + +GS reconstruction +(19 nodes) + + + + + +IMAS/OMAS reader->GS reconstruction + + +4 + + + +IMAS/OMAS reader->Bouquet orchestrator / IMAS forward solve + + +10 + + + +IMAS/OMAS reader->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Baseline & uncertainty resolution->Input readers (g-file / p-file / IDA) + + +1 + + + +Baseline & uncertainty resolution->IMAS/OMAS reader + + +14 + + + + +Baseline & uncertainty resolution->Bouquet orchestrator / IMAS forward solve + + +11 + + + +Baseline & uncertainty resolution->Per-draw solve (SWB / l_i / homotopy) + + +9 + + + + +GS reconstruction->Bouquet orchestrator / IMAS forward solve + + +4 + + + +GS reconstruction->Per-draw solve (SWB / l_i / homotopy) + + +1 + + + +Bouquet orchestrator / IMAS forward solve->Input readers (g-file / p-file / IDA) + + +8 + + + +Bouquet orchestrator / IMAS forward solve->IMAS/OMAS reader + + +11 + + + +Bouquet orchestrator / IMAS forward solve->Baseline & uncertainty resolution + + +5 + + + +Bouquet orchestrator / IMAS forward solve->GS reconstruction + + +6 + + + +Draw loop (GPR sampling) + + +Draw loop (GPR sampling) +(19 nodes) + + + + + + +Bouquet orchestrator / IMAS forward solve->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Archive, filtering & plotting + + +Archive, filtering & plotting +(41 nodes) + + + + + +Bouquet orchestrator / IMAS forward solve->Archive, filtering & plotting + + +6 + + + +Draw loop (GPR sampling)->Bouquet orchestrator / IMAS forward solve + + +1 + + + + +Draw loop (GPR sampling)->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Draw loop (GPR sampling)->Archive, filtering & plotting + + +11 + + + +Per-draw solve (SWB / l_i / homotopy)->Bouquet orchestrator / IMAS forward solve + + +4 + + + +Per-draw solve (SWB / l_i / homotopy)->Draw loop (GPR sampling) + + +1 + + + + +Archive, filtering & plotting->Bouquet orchestrator / IMAS forward solve + + +2 + + + +Archive, filtering & plotting->Draw loop (GPR sampling) + + +3 + + + +Process-parallel path + + +Process-parallel path +(31 nodes) + + + + + + +Process-parallel path->Bouquet orchestrator / IMAS forward solve + + +1 + + + +Process-parallel path->Archive, filtering & plotting + + +2 + + + + +
+
+ + + input (30) knob (141) quantity (136) transform (158) decision (57) artifact (30) + dashed edge = control flow +
+
+ + +bouquet + + + + + +cluster_0 + + +Configuration + + + + +cluster_1 + + +Input readers (g-file / p-file / IDA) + + + + +cluster_2 + + +IMAS/OMAS reader + + + + +cluster_3 + + +Baseline & uncertainty resolution + + + + +cluster_4 + + +GS reconstruction + + + + +cluster_5 + + +Bouquet orchestrator / IMAS forward solve + + + + +cluster_6 + + +Draw loop (GPR sampling) + + + + +cluster_7 + + +Per-draw solve (SWB / l_i / homotopy) + + + + +cluster_8 + + +Archive, filtering & plotting + + + + +cluster_9 + + +Process-parallel path + + + + + +cfg.filterconfig.inspec_F_max + + + + +inspec_F_max: float = 0.02 + + + + + +fn.filtering.if abs + + +if abs + + + + + +cfg.filterconfig.inspec_F_max->fn.filtering.if abs + + + + + + + + +cfg.filterconfig.inspec_VSC_max + + + + +inspec_VSC_max: float = 0.02 + + + + + +cfg.filterconfig.inspec_VSC_max->fn.filtering.if abs + + + + + + + + +cfg.filterconfig.rms_max_mm + + + + +rms_max_mm: float = 5.0 + + + + + +fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject + + +if rms_error_mm > config.filtering.rms_max_mm: reject + + + + + +cfg.filterconfig.rms_max_mm->fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject + + + + + + + + +cfg.fixedcomponentsconfig.j_NBI + + + + +j_NBI: Optional[np.ndarray] = None + + + + + +fn.run.fc.j_NBI or zeros_on_psi_N + + +fc.j_NBI or zeros_on_psi_N + + + + + +cfg.fixedcomponentsconfig.j_NBI->fn.run.fc.j_NBI or zeros_on_psi_N + + + + + + + + +cfg.fixedcomponentsconfig.j_RF + + + + +j_RF: Optional[np.ndarray] = None + + + + + +fn.run.fc.j_RF or zeros_on_psi_N + + +fc.j_RF or zeros_on_psi_N + + + + + +cfg.fixedcomponentsconfig.j_RF->fn.run.fc.j_RF or zeros_on_psi_N + + + + + + + + +cfg.fixedcomponentsconfig.p_fast + + + + +p_fast: Optional[np.ndarray] = None + + + + + +fn.run.fc.p_fast or compute_p_fast_from_source + + +fc.p_fast or compute_p_fast_from_source + + + + + +cfg.fixedcomponentsconfig.p_fast->fn.run.fc.p_fast or compute_p_fast_from_source + + + + + + + + +cfg.fixedcomponentsconfig.p_fast_reduction + + + + +p_fast_reduction: str = "trace" + + + + + +fn.physics.isotropize_fast_pressure + + +isotropize_fast_pressure + + + + + +cfg.fixedcomponentsconfig.p_fast_reduction->fn.physics.isotropize_fast_pressure + + + + + + + + +cfg.fixedcomponentsconfig.psi_N + + + + +psi_N: Optional[np.ndarray] = None + + + + + +fn.run.fc.psi_N or source_psi_N + + +fc.psi_N or source_psi_N + + + + + +cfg.fixedcomponentsconfig.psi_N->fn.run.fc.psi_N or source_psi_N + + + + + + + + +cfg.generationconfig.accept_anchor_inband + + + + +accept_anchor_inband: bool = False + + + + + +fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band + + +if gc.accept_anchor_inband and in_band + + + + + +cfg.generationconfig.accept_anchor_inband->fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band + + + + + + + + +cfg.generationconfig.allow_incomplete_pressure + + + + +allow_incomplete_pressure: bool = False + + + + + +fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check + + +if config.generation.allow_incomplete_pressure: skip_pressure_check + + + + + +cfg.generationconfig.allow_incomplete_pressure->fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check + + + + + + + + +cfg.generationconfig.allow_unsafe_workflow + + + + +allow_unsafe_workflow: bool = False + + + + + +fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow + + +if not config.generation.allow_unsafe_workflow: validate_workflow + + + + + +cfg.generationconfig.allow_unsafe_workflow->fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow + + + + + + + + +cfg.generationconfig.anchor_jtor_to_equilibrium + + + + +anchor_jtor_to_equilibrium: bool = True + + + + + +fn.run.eq.j_tor - cp.j_tor + + +eq.j_tor - cp.j_tor + + + + + +cfg.generationconfig.anchor_jtor_to_equilibrium->fn.run.eq.j_tor - cp.j_tor + + + + + + + + +cfg.generationconfig.anchor_pressure_to_equilibrium + + + + +anchor_pressure_to_equilibrium: bool = False + + + + + +fn.run.eq.pressure - p_recon + + +eq.pressure - p_recon + + + + + +cfg.generationconfig.anchor_pressure_to_equilibrium->fn.run.eq.pressure - p_recon + + + + + + + + +cfg.generationconfig.coil_drift + + + + +coil_drift: float = 0.01 + + + + + +fn.TokaMaker_interface.config.generation.coil_drift + + +config.generation.coil_drift + + + + + +cfg.generationconfig.coil_drift->fn.TokaMaker_interface.config.generation.coil_drift + + + + + + + + +cfg.generationconfig.coil_drift_hard_factor + + + + +coil_drift_hard_factor: Optional[float] = None + + + + + +fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None + + +coil_drift * config.generation.coil_drift_hard_factor if ... else None + + + + + +cfg.generationconfig.coil_drift_hard_factor->fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None + + + + + + + + +cfg.generationconfig.constrain_sawteeth + + + + +constrain_sawteeth: bool = False + + + + + +fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject + + +if gc.constrain_sawteeth and q0 < 1.0: reject + + + + + +cfg.generationconfig.constrain_sawteeth->fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject + + + + + + + + +cfg.generationconfig.diagnostic_plots + + + + +diagnostic_plots: bool = False + + + + + +fn.run.if config.generation.diagnostic_plots: plot_diagnostics + + +if config.generation.diagnostic_plots: plot_diagnostics + + + + + +cfg.generationconfig.diagnostic_plots->fn.run.if config.generation.diagnostic_plots: plot_diagnostics + + + + + + + + +cfg.generationconfig.floor_j_BS + + + + +floor_j_BS: bool = False + + + + + +fn.run.np.maximum + + +np.maximum + + + + + +cfg.generationconfig.floor_j_BS->fn.run.np.maximum + + + + + + + + +cfg.generationconfig.homotopy_passes + + + + +homotopy_passes: list = [(0.05,0.10),(0.02,0.05),(0.01,0.01)] + + + + + +fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + +for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + + + + +cfg.generationconfig.homotopy_passes->fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + + + + + + + +cfg.generationconfig.isolate_edge_jBS + + + + +isolate_edge_jBS: bool = True + + + + + +fn.run.isolate_edge_jBS + + +isolate_edge_jBS + + + + + +cfg.generationconfig.isolate_edge_jBS->fn.run.isolate_edge_jBS + + + + + + + + +cfg.generationconfig.jBS_baseline_mode + + + + +jBS_baseline_mode: str = "diff" + + + + + +fn.run.... + + +... + + + + + +cfg.generationconfig.jBS_baseline_mode->fn.run.... + + + + + + + + +cfg.generationconfig.jBS_scale_range + + + + +jBS_scale_range: tuple = (0.99, 1.01) + + + + + +fn.TokaMaker_interface.np.random.uniform + + +np.random.uniform + + + + + +cfg.generationconfig.jBS_scale_range->fn.TokaMaker_interface.np.random.uniform + + + + + + + + +cfg.generationconfig.kinetic_source + + + + +kinetic_source: str = "fuse" + + + + + +fn.run."ida_hybrid": resample_ida_profiles + + +"ida_hybrid": resample_ida_profiles + + + + + +cfg.generationconfig.kinetic_source->fn.run."ida_hybrid": resample_ida_profiles + + + + + + + + +cfg.generationconfig.l_i_tolerance + + + + +l_i_tolerance: float = 0.05 + + + + + +fn.TokaMaker_interface.if not abs + + +if not abs + + + + + +cfg.generationconfig.l_i_tolerance->fn.TokaMaker_interface.if not abs + + + + + + + + +cfg.generationconfig.n_equils + + + + +n_equils: int = 20 + + + + + +fn.TokaMaker_interface.for i_eq in _tqdm + + +for i_eq in _tqdm + + + + + +cfg.generationconfig.n_equils->fn.TokaMaker_interface.for i_eq in _tqdm + + + + + + + + +fn.run.int + + +int + + + + + +cfg.generationconfig.n_equils->fn.run.int + + + + + + + + +cfg.generationconfig.perturb_jind_in_anchor + + + + +perturb_jind_in_anchor: bool = False + + + + + +fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + +if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + + + + +cfg.generationconfig.perturb_jind_in_anchor->fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + + + + + + + +cfg.generationconfig.recalculate_j_BS + + + + +recalculate_j_BS: bool = True + + + + + +fn.run.compute_via_swb + + +compute_via_swb + + + + + +cfg.generationconfig.recalculate_j_BS->fn.run.compute_via_swb + + + + + + + + +cfg.generationconfig.scan_key + + + + +scan_key: float = 0 + + + + + +fn.run.store_equilibrium + + +store_equilibrium + + + + + +cfg.generationconfig.scan_key->fn.run.store_equilibrium + + + + + + + + +cfg.generationconfig.seed + + + + +seed: Optional[int] = None + + + + + +fn.TokaMaker_interface.np.random.seed + + +np.random.seed + + + + + +cfg.generationconfig.seed->fn.TokaMaker_interface.np.random.seed + + + + + + + + +cfg.generationconfig.swb_iterations + + + + +swb_iterations: int = 3 + + + + + +fn.TokaMaker_interface.solve_with_bootstrap + + +solve_with_bootstrap + + + + + +cfg.generationconfig.swb_iterations->fn.TokaMaker_interface.solve_with_bootstrap + + + + + + + + +cfg.generationconfig.workflow + + + + +workflow: str = "auto" + + + + + +fn.run.resolve_workflow_from_preset + + +resolve_workflow_from_preset + + + + + +cfg.generationconfig.workflow->fn.run.resolve_workflow_from_preset + + + + + + + + +cfg.imassource.efit01_geqdsk + + + + +efit01_geqdsk: Optional[str] = None + + + + + +fn.run.read_geqdsk + + +read_geqdsk + + + + + +cfg.imassource.efit01_geqdsk->fn.run.read_geqdsk + + + + + + + + +cfg.imassource.ida_path + + + + +ida_path: Optional[str] = None + + + + + +fn.run.ida_path + + +ida_path + + + + + +cfg.imassource.ida_path->fn.run.ida_path + + + + + + + + +cfg.imassource.ids_path + + + + +ids_path: str = None + + + + + +fn.io.imas.read_imas + + +read_imas + + + + + +cfg.imassource.ids_path->fn.io.imas.read_imas + + + + + + + + +cfg.imassource.impurity_Z + + + + +impurity_Z: float = 6.0 + + + + + +fn.io.imas.profiles.compute_ni + + +profiles.compute_ni + + + + + +cfg.imassource.impurity_Z->fn.io.imas.profiles.compute_ni + + + + + + + + +cfg.imassource.time + + + + +time: Optional[float] = None + + + + + +cfg.imassource.time->fn.io.imas.read_imas + + + + + + + + +cfg.reconstructionsource.cocos + + + + +cocos: int = 1 + + + + + +fn.baseline.read_geqdsk + + +read_geqdsk + + + + + +cfg.reconstructionsource.cocos->fn.baseline.read_geqdsk + + + + + + + + +cfg.reconstructionsource.geqdsk_path + + + + +geqdsk_path: str = None + + + + + +cfg.reconstructionsource.geqdsk_path->fn.baseline.read_geqdsk + + + + + + + + +cfg.reconstructionsource.geqdsk_path->fn.run.read_geqdsk + + + + + + + + +cfg.reconstructionsource.impurity_Z + + + + +impurity_Z: float = 6.0 + + + + + +fn.baseline.profiles.compute_ni + + +profiles.compute_ni + + + + + +cfg.reconstructionsource.impurity_Z->fn.baseline.profiles.compute_ni + + + + + + + + +cfg.reconstructionsource.n_k + + + + +n_k: int = 5 + + + + + +fn.baseline.spline_fit + + +spline_fit + + + + + +cfg.reconstructionsource.n_k->fn.baseline.spline_fit + + + + + + + + +cfg.reconstructionsource.profile_overrides + + + + +profile_overrides: dict = {} + + + + + +fn.baseline.... + + +... + + + + + +cfg.reconstructionsource.profile_overrides->fn.baseline.... + + + + + + + + +cfg.reconstructionsource.profiles_path + + + + +profiles_path: str = None + + + + + +fn.baseline.read_profiles + + +read_profiles + + + + + +cfg.reconstructionsource.profiles_path->fn.baseline.read_profiles + + + + + + + + +cfg.reconstructionsource.psi_bridge + + + + +psi_bridge: float = 0.99 + + + + + +fn.baseline.hermite_edge_bridge + + +hermite_edge_bridge + + + + + +cfg.reconstructionsource.psi_bridge->fn.baseline.hermite_edge_bridge + + + + + + + + +cfg.reconstructionsource.psi_pad + + + + +psi_pad: float = 1e-3 + + + + + +fn.baseline.compute_psi_bounds + + +compute_psi_bounds + + + + + +cfg.reconstructionsource.psi_pad->fn.baseline.compute_psi_bounds + + + + + + + + +cfg.reconstructionsource.rescale_j_BS + + + + +rescale_j_BS: bool = False + + + + + +fn.baseline.scaling_factor + + +scaling_factor + + + + + +cfg.reconstructionsource.rescale_j_BS->fn.baseline.scaling_factor + + + + + + + + +cfg.reconstructionsource.shelf_psi_N + + + + +shelf_psi_N: float = 0.0 + + + + + +fn.baseline.source.shelf_psi_N + + +source.shelf_psi_N + + + + + +cfg.reconstructionsource.shelf_psi_N->fn.baseline.source.shelf_psi_N + + + + + + + + +cfg.reconstructionsource.time + + + + +time: Optional[float] = None + + + + + +fn.io.ida.read_ida + + +read_ida + + + + + +cfg.reconstructionsource.time->fn.io.ida.read_ida + + + + + + + + +cfg.solverconfig.F0 + + + + +F0: Optional[float] = None + + + + + +fn.run.F0 or eqdsk.F0_ref or ... + + +F0 or eqdsk.F0_ref or ... + + + + + +cfg.solverconfig.F0->fn.run.F0 or eqdsk.F0_ref or ... + + + + + + + + +cfg.solverconfig.coil_reg + + + + +coil_reg: list = [] + + + + + +cfg.solverconfig.coil_vsc + + + + +coil_vsc: dict = {"F9A": 1.0, "F9B": -1.0} + + + + + +fn.run.coil_vsc dict unpacked into solve_with_bootstrap + + +coil_vsc dict unpacked into solve_with_bootstrap + + + + + +cfg.solverconfig.coil_vsc->fn.run.coil_vsc dict unpacked into solve_with_bootstrap + + + + + + + + +cfg.solverconfig.isoflux_pts + + + + +isoflux_pts: Optional[np.ndarray] = None + + + + + +fn.run.isoflux_pts or eqdsk.isoflux_pts + + +isoflux_pts or eqdsk.isoflux_pts + + + + + +cfg.solverconfig.isoflux_pts->fn.run.isoflux_pts or eqdsk.isoflux_pts + + + + + + + + +cfg.solverconfig.isoflux_weights + + + + +isoflux_weights: Optional[np.ndarray] = None + + + + + +fn.run.isoflux_weights or np.ones + + +isoflux_weights or np.ones + + + + + +cfg.solverconfig.isoflux_weights->fn.run.isoflux_weights or np.ones + + + + + + + + +cfg.solverconfig.mesh_path + + + + +mesh_path: str = None + + + + + +fn.run.load_gs_mesh + + +load_gs_mesh + + + + + +cfg.solverconfig.mesh_path->fn.run.load_gs_mesh + + + + + + + + +cfg.solverconfig.nthreads + + + + +nthreads: int = 1 + + + + + +fn.TokaMaker_interface.mygs.solve + + +mygs.solve + + + + + +cfg.solverconfig.nthreads->fn.TokaMaker_interface.mygs.solve + + + + + + + + +cfg.solverconfig.nthreads->fn.run.load_gs_mesh + + + + + + + + +cfg.solverconfig.order + + + + +order: int = 3 + + + + + +fn.run.GsHandle + + +GsHandle + + + + + +cfg.solverconfig.order->fn.run.GsHandle + + + + + + + + +cfg.solverconfig.region_overrides + + + + +region_overrides: Optional[dict] = None + + + + + +cfg.source.efit01_geqdsk + + + + +efit01_geqdsk + + + + + +fn.imas.read_imas_geometry + + +read_imas_geometry() + + + + + +cfg.source.efit01_geqdsk->fn.imas.read_imas_geometry + + + + + + + + +cfg.uncertaintyconfig.aux_baselines + + + + +aux_baselines: dict = {} + + + + + +fn.TokaMaker_interface.config.uncertainty.aux_baselines.get + + +config.uncertainty.aux_baselines.get + + + + + +cfg.uncertaintyconfig.aux_baselines->fn.TokaMaker_interface.config.uncertainty.aux_baselines.get + + + + + + + + +cfg.uncertaintyconfig.aux_length_scales + + + + +aux_length_scales: dict = {} + + + + + +fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get + + +config.uncertainty.aux_length_scales.get + + + + + +cfg.uncertaintyconfig.aux_length_scales->fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get + + + + + + + + +cfg.uncertaintyconfig.aux_sigmas + + + + +aux_sigmas: dict = {} + + + + + +fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items + + +for name, sigma in config.uncertainty.aux_sigmas.items + + + + + +cfg.uncertaintyconfig.aux_sigmas->fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items + + + + + + + + +cfg.uncertaintyconfig.ida_path + + + + +ida_path: Optional[str] = None + + + + + +fn.baseline.unc.ida_path or source.profiles_path + + +unc.ida_path or source.profiles_path + + + + + +cfg.uncertaintyconfig.ida_path->fn.baseline.unc.ida_path or source.profiles_path + + + + + + + + +cfg.uncertaintyconfig.j_ls + + + + +j_ls: float = 0.25 + + + + + +fn.TokaMaker_interface.GPRPerturber + + +GPRPerturber + + + + + +cfg.uncertaintyconfig.j_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.jphi_scalar_sigma + + + + +jphi_scalar_sigma: float = 0.1 + + + + + +fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs + + +config.uncertainty.jphi_scalar_sigma * abs + + + + + +cfg.uncertaintyconfig.jphi_scalar_sigma->fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs + + + + + + + + +cfg.uncertaintyconfig.n_ls + + + + +n_ls: float = 0.5 + + + + + +cfg.uncertaintyconfig.n_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.ne_scalar_sigma + + + + +ne_scalar_sigma: float = 0.05 + + + + + +fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline + + +sigma_ne or unc.ne_scalar_sigma * ne_baseline + + + + + +cfg.uncertaintyconfig.ne_scalar_sigma->fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline + + + + + + + + +cfg.uncertaintyconfig.ni_scalar_sigma + + + + +ni_scalar_sigma: float = 0.1 + + + + + +fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline + + +sigma_ni or unc.ni_scalar_sigma * ni_baseline + + + + + +cfg.uncertaintyconfig.ni_scalar_sigma->fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline + + + + + + + + +cfg.uncertaintyconfig.sigma_method + + + + +sigma_method: str = "percentile" + + + + + +fn.baseline.percentile_or_std + + +percentile_or_std + + + + + +cfg.uncertaintyconfig.sigma_method->fn.baseline.percentile_or_std + + + + + + + + +cfg.uncertaintyconfig.sigma_mode + + + + +sigma_mode: str = "auto" + + + + + +fn.baseline.resolve_ida_sigmas + + +resolve_ida_sigmas + + + + + +cfg.uncertaintyconfig.sigma_mode->fn.baseline.resolve_ida_sigmas + + + + + + + + +cfg.uncertaintyconfig.sigma_ni_from_ne + + + + +sigma_ni_from_ne: bool = True + + + + + +fn.baseline.sigma_ne + + +sigma_ne + + + + + +cfg.uncertaintyconfig.sigma_ni_from_ne->fn.baseline.sigma_ne + + + + + + + + +cfg.uncertaintyconfig.sigma_profiles + + + + +sigma_profiles: dict = {} + + + + + +fn.baseline.unc.sigma_profiles.get + + +unc.sigma_profiles.get + + + + + +cfg.uncertaintyconfig.sigma_profiles->fn.baseline.unc.sigma_profiles.get + + + + + + + + +cfg.uncertaintyconfig.t_ls + + + + +t_ls: float = 0.4 + + + + + +cfg.uncertaintyconfig.t_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.te_scalar_sigma + + + + +te_scalar_sigma: float = 0.05 + + + + + +fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline + + +sigma_te or unc.te_scalar_sigma * te_baseline + + + + + +cfg.uncertaintyconfig.te_scalar_sigma->fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline + + + + + + + + +cfg.uncertaintyconfig.ti_scalar_sigma + + + + +ti_scalar_sigma: float = 0.1 + + + + + +fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline + + +sigma_ti or unc.ti_scalar_sigma * ti_baseline + + + + + +cfg.uncertaintyconfig.ti_scalar_sigma->fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline + + + + + + + + +cfg.uncertaintyconfig.zeff_scalar_sigma + + + + +zeff_scalar_sigma: float = 0.05 + + + + + +fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff + + +if unc.zeff_scalar_sigma > 0: perturb_zeff + + + + + +cfg.uncertaintyconfig.zeff_scalar_sigma->fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff + + + + + + + + +cls.FilterConfig + + +FilterConfig + + + + + +cls.FixedComponentsConfig + + +FixedComponentsConfig + + + + + +cls.GenerationConfig + + +GenerationConfig + + + + + +cls.ImasSource + + +ImasSource + + + + + +cls.ReconstructionSource + + +ReconstructionSource + + + + + +cls.SolverConfig + + +SolverConfig + + + + + +cls.UncertaintyConfig + + +UncertaintyConfig + + + + + +qty.ne + + +ne (electron density) + + + + + +fn.io.ida.read_ida->qty.ne + + + + + + + + +qty.ni + + +ni (main-ion density) + + + + + +fn.io.ida.read_ida->qty.ni + + + + + + + + +qty.psi_N_kinetic + + +psi_N_kinetic (kinetic grid) + + + + + +fn.io.ida.read_ida->qty.psi_N_kinetic + + + + + + + + + +qty.te + + +te (electron temperature) + + + + + +fn.io.ida.read_ida->qty.te + + + + + + + + +qty.ti + + +ti (ion temperature) + + + + + +fn.io.ida.read_ida->qty.ti + + + + + + + + +qty.zeff + + +Zeff (effective charge) + + + + + +fn.io.ida.read_ida->qty.zeff + + + + + + + + +qty.p_fast + + +p_fast (fast-ion pressure) + + + + + +fn.physics.isotropize_fast_pressure->qty.p_fast + + + + + + + + +fn.read_geqdsk + + +read_geqdsk() + + + + + +obj.GEQDSKEquilibrium + + + +GEQDSKEquilibrium object + + + + + +fn.read_geqdsk->obj.GEQDSKEquilibrium + + + + + + + + +fn.read_ida + + +read_ida() + + + + + +gate.ida_layout + + +IDA layout (direct vs ensemble)? + + + + + +fn.read_ida->gate.ida_layout + + + + + + + + +fn.read_ida_cer + + +read_ida_cer() + + + + + +obj.IDACERProfiles + + + +IDACERProfiles dataclass + + + + + +fn.read_ida_cer->obj.IDACERProfiles + + + + + + + + +fn.read_pfile + + +read_pfile() + + + + + +obj.PFile + + + +PFile object + + + + + +fn.read_pfile->obj.PFile + + + + + + + + +fn.reconstruct_equilibrium + + +reconstruct_equilibrium() [geqdsk.py] + + + + + +obj.IDAProfiles + + + +IDAProfiles dataclass + + + + + +gate.ida_layout->obj.IDAProfiles + + + + + + + + +gate.profile_file_type + + +Profile file type? + + + + + +gate.profile_file_type->fn.io.ida.read_ida + + + + + + + + +gate.profile_file_type->fn.read_ida + + + + + + + + +gate.profile_file_type->fn.read_pfile + + + + + + + + +fn.io.pfile.read_pfile + + +read_pfile(path) + compute_quasineutrality/compute_zeff + + + + + +gate.profile_file_type->fn.io.pfile.read_pfile + + + + + + + + +gate.time_index + + +Select time slice + + + + + +gate.time_index->fn.read_ida + + + + + + + + +input.gfile + + +G-file (GEQDSK) + + + + + +input.gfile->fn.read_geqdsk + + + + + + + + +input.ida_cdf + + +IDA .cdf (netCDF/HDF5) + + + + + +input.ida_cdf->gate.time_index + + + + + + + + +fn.imas._merge_ida_kinetics + + +_merge_ida_kinetics() [IDA-hybrid only] + + + + + +input.ida_cdf->fn.imas._merge_ida_kinetics + + + + + + + + +input.ida_cer + + +IDA CER channels (carbon) + + + + + +input.ida_cer->fn.read_ida_cer + + + + + + + + +input.pfile + + +P-file (Osborne profiles) + + + + + +input.pfile->fn.read_pfile + + + + + + + + +qty.F0 + + +F0 (R*Bt poloidal function) + + + + + +obj.GEQDSKEquilibrium->qty.F0 + + + + + + + + +qty.Ip_target + + +Ip_target (plasma current) + + + + + +obj.GEQDSKEquilibrium->qty.Ip_target + + + + + + + + +qty.boundary_lcfs + + +boundary_lcfs (separatrix contour) + + + + + +obj.GEQDSKEquilibrium->qty.boundary_lcfs + + + + + + + +qty.j_phi + + +j_phi (toroidal current density) + + + + + +obj.GEQDSKEquilibrium->qty.j_phi + + + + + + + + +qty.li_target + + +li_target (internal inductance) + + + + + +obj.GEQDSKEquilibrium->qty.li_target + + + + + + + + + +qty.p_thermal + + +p_thermal (thermal pressure) + + + + + +obj.GEQDSKEquilibrium->qty.p_thermal + + + + + + + + +qty.psi_N + + +psi_N (normalized flux) + + + + + +obj.GEQDSKEquilibrium->qty.psi_N + + + + + + + + +qty.e_r_cer + + +E_r (radial electric field) + + + + + +obj.IDACERProfiles->qty.e_r_cer + + + + + + + + +obj.IDAProfiles->qty.ne + + + + + + + + +obj.IDAProfiles->qty.ni + + + + + + + + +obj.IDAProfiles->qty.psi_N_kinetic + + + + + + + + +qty.sigma_ne + + +sigma_ne (density uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ne + + + + + + + + +qty.sigma_ni + + +sigma_ni (ion density uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ni + + + + + + + + +qty.sigma_te + + +sigma_te (temperature uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_te + + + + + + + + +qty.sigma_ti + + +sigma_ti (temperature uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ti + + + + + + + + +obj.IDAProfiles->qty.te + + + + + + + + +obj.IDAProfiles->qty.ti + + + + + + + + +obj.IDAProfiles->qty.zeff + + + + + + + + +obj.PFile->qty.ne + + + + + + + + +obj.PFile->qty.ni + + + + + + + + +qty.omega_tor + + +omega_tor (toroidal rotation) + + + + + +obj.PFile->qty.omega_tor + + + + + + + + +obj.PFile->qty.te + + + + + + + + +obj.PFile->qty.ti + + + + + + + + +artifact.baseline + + + +Baseline (output) + + + + + +artifact.imas_draw_json + + + +Perturbed draw JSON + + + + + +artifact.baseline->artifact.imas_draw_json + + + + + + + + +fn.imas.read_imas_baseline + + +read_imas_baseline() + + + + + +artifact.baseline->fn.imas.read_imas_baseline + + + + + + + + +artifact.geometry + + + +Geometry tuple (output) + + + + + +cfg.fixed.j_NBI + + + + +user override: j_NBI + + + + + +fn.imas._override + + +_override() + + + + + +cfg.fixed.j_NBI->fn.imas._override + + + + + + + + +cfg.fixed.j_RF + + + + +user override: j_RF + + + + + +cfg.fixed.j_RF->fn.imas._override + + + + + + + + +cfg.fixed.p_fast + + + + +user override: p_fast + + + + + +cfg.fixed.p_fast->fn.imas._override + + + + + + + + +cfg.generation.allow_incomplete_pressure + + + + +allow incomplete pressure validation + + + + + +fn.imas._validate_pressure_completeness + + +_validate_pressure_completeness() + + + + + +cfg.generation.allow_incomplete_pressure->fn.imas._validate_pressure_completeness + + + + + + + + +cfg.generation.anchor_jtor_to_equilibrium + + + + +j_tor anchor to equilibrium + + + + + +cfg.generation.anchor_pressure_to_equilibrium + + + + +pressure anchor to equilibrium + + + + + +cfg.generation.kinetic_source + + + + +kinetic profile source + + + + + +cfg.generation.p_fast_reduction + + + + +p_fast isotropization method + + + + + +cfg.generation.p_fast_reduction->fn.physics.isotropize_fast_pressure + + + + + + + + +fn.ida.read_ida + + +read_ida() [IDA-hybrid only] + + + + + +fn.imas._merge_ida_kinetics->qty.ne + + + + + + + + +fn.imas._merge_ida_kinetics->qty.omega_tor + + + + + + + + +fn.imas._merge_ida_kinetics->qty.te + + + + + + + + +fn.imas._merge_ida_kinetics->qty.ti + + + + + + + + +qty.j_NBI_toroidal + + +j_NBI (toroidal) + + + + + +fn.imas._override->qty.j_NBI_toroidal + + + + + + + + +qty.j_RF + + +j_RF (RF-driven current) + + + + + +fn.imas._override->qty.j_RF + + + + + + + + +fn.imas._override->qty.p_fast + + + + + + + + +fn.imas.read_imas_geometry->artifact.geometry + + + + + + + + +fn.imas.read_imas_geometry->qty.F0 + + + + + + + + +fn.imas.read_imas_geometry->qty.boundary_lcfs + + + + + + + + + +fn.physics.effective_impurity_charge + + +effective_impurity_charge() + + + + + +fn.physics.impurity_pressure + + +impurity_pressure() + + + + + +fn.physics.main_ion_density_from_zeff + + +main_ion_density_from_zeff() + + + + + +fn.physics.parallel_to_toroidal + + +parallel_to_toroidal() + + + + + +qty.j_BS + + +j_BS (bootstrap current) + + + + + +fn.physics.parallel_to_toroidal->qty.j_BS + + + + + + + + +qty.j_BS_isolated + + +j_BS_isolated (toroidal) + + + + + +fn.physics.parallel_to_toroidal->qty.j_BS_isolated + + + + + + + + +fn.physics.parallel_to_toroidal->qty.j_NBI_toroidal + + + + + + + + +gate.anchor_jtor + + +j_tor anchor decision + + + + + +qty.jphi_diff + + +j_phi anchor offset + + + + + +gate.anchor_jtor->qty.jphi_diff + + + + + + + + +gate.anchor_pressure + + +Pressure anchor decision + + + + + +qty.p_diff + + +pressure anchor offset + + + + + +gate.anchor_pressure->qty.p_diff + + + + + + + + +gate.fixed_components + + +Fixed component overrides + + + + + +gate.fixed_components->fn.imas._override + + + + + + + + +gate.incomplete_pressure + + +Pressure completeness check + + + + + +gate.incomplete_pressure->fn.imas._validate_pressure_completeness + + + + + + + + +gate.kinetic_source + + +Kinetic source selection + + + + + +gate.kinetic_source->fn.imas._merge_ida_kinetics + + + + + + + + +input.efit01_gfile + + +EFIT01 g-file (optional) + + + + + +input.efit01_gfile->fn.imas.read_imas_geometry + + + + + + + + +input.imas_ids + + +IMAS IDS (dd_sim.json) + + + + + +input.imas_ids->fn.imas.read_imas_geometry + + + + + + + + +input.imas_ids->qty.F0 + + + + + + + + +input.imas_ids->qty.Ip_target + + + + + + + + +qty.aux.E_r + + +radial electric field + + + + + +input.imas_ids->qty.aux.E_r + + + + + + + + +qty.aux.chi_e + + +electron thermal diffusivity + + + + + +input.imas_ids->qty.aux.chi_e + + + + + + + + +qty.aux.chi_i + + +ion thermal diffusivity + + + + + +input.imas_ids->qty.aux.chi_i + + + + + + + + +input.imas_ids->qty.boundary_lcfs + + + + + + + + +qty.j_bootstrap_parallel + + +j_bootstrap (parallel) + + + + + +input.imas_ids->qty.j_bootstrap_parallel + + + + + + + + +qty.j_nbi_parallel + + +j_NBI (parallel, summed) + + + + + +input.imas_ids->qty.j_nbi_parallel + + + + + + + + +qty.j_ohmic_parallel + + +j_ohmic (parallel, unused) + + + + + +input.imas_ids->qty.j_ohmic_parallel + + + + + + + + +qty.j_tor_parallel + + +j_tor (authoritative toroidal) + + + + + +input.imas_ids->qty.j_tor_parallel + + + + + + + + +qty.j_total_parallel + + +j_total (parallel) + + + + + +input.imas_ids->qty.j_total_parallel + + + + + + + + +input.imas_ids->qty.jphi_diff + + + + + + + + +input.imas_ids->qty.li_target + + + + + + + + +input.imas_ids->qty.ne + + + + + + + + +input.imas_ids->qty.ni + + + + + + + + +input.imas_ids->qty.omega_tor + + + + + + + + +qty.p_equilibrium + + +equilibrium pressure + + + + + +input.imas_ids->qty.p_equilibrium + + + + + + + + +input.imas_ids->qty.psi_N + + + + + + + + +input.imas_ids->qty.te + + + + + + + + +input.imas_ids->qty.ti + + + + + + + + +input.imas_ids->qty.zeff + + + + + + + + +cfg.FixedComponentsConfig.j_NBI + + + + +FixedComponentsConfig.j_NBI + + + + + +fn.baseline._resolve_fixed + + +_resolve_fixed(comp, src_psi, dst_psi) + + + + + +cfg.FixedComponentsConfig.j_NBI->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.j_RF + + + + +FixedComponentsConfig.j_RF + + + + + +cfg.FixedComponentsConfig.j_RF->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.p_fast + + + + +FixedComponentsConfig.p_fast + + + + + +cfg.FixedComponentsConfig.p_fast->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.psi_N + + + + +FixedComponentsConfig.psi_N + + + + + +cfg.FixedComponentsConfig.psi_N->fn.baseline._resolve_fixed + + + + + + + + +cfg.GenerationConfig.recalculate_j_BS + + + + +GenerationConfig.recalculate_j_BS + + + + + +cfg.GenerationConfig.recalculate_j_BS->qty.j_BS + + + + + + + + +cfg.ReconstructionSource.impurity_Z + + + + +ReconstructionSource.impurity_Z + + + + + +fn.baseline._load_kinetic_profiles + + +_load_kinetic_profiles(source) + + + + + +cfg.ReconstructionSource.impurity_Z->fn.baseline._load_kinetic_profiles + + + + + + + + +cfg.UncertaintyConfig.aux_baselines + + + + +UncertaintyConfig.aux_baselines + + + + + +fn.baseline._sigma_zeff_baseline + + +resolve zeff baseline (aux or baseline.Zeff) + + + + + +cfg.UncertaintyConfig.aux_baselines->fn.baseline._sigma_zeff_baseline + + + + + + + + +cfg.UncertaintyConfig.aux_length_scales + + + + +UncertaintyConfig.aux_length_scales + + + + + +cfg.UncertaintyConfig.aux_sigmas + + + + +UncertaintyConfig.aux_sigmas + + + + + +gate.sigma_priority_zeff + + +zeff sigma priority: explicit | default auto-inject + + + + + +cfg.UncertaintyConfig.aux_sigmas->gate.sigma_priority_zeff + + + + + + + + +cfg.UncertaintyConfig.ida_path + + + + +UncertaintyConfig.ida_path + + + + + +gate.sigma_priority_ne + + +ne sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ne + + + + + + + + +gate.sigma_priority_ni + + +ni sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ni + + + + + + + + +gate.sigma_priority_te + + +te sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_te + + + + + + + + +gate.sigma_priority_ti + + +ti sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.jphi_scalar_sigma + + + + +UncertaintyConfig.jphi_scalar_sigma + + + + + +qty.sigma_jphi + + +sigma_jphi [A/m^2] + + + + + +cfg.UncertaintyConfig.jphi_scalar_sigma->qty.sigma_jphi + + + + + + + +cfg.UncertaintyConfig.ne_scalar_sigma + + + + +UncertaintyConfig.ne_scalar_sigma + + + + + +cfg.UncertaintyConfig.ne_scalar_sigma->gate.sigma_priority_ne + + + + + + + + +cfg.UncertaintyConfig.ni_scalar_sigma + + + + +UncertaintyConfig.ni_scalar_sigma + + + + + +cfg.UncertaintyConfig.ni_scalar_sigma->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_ni_from_ne + + + + +UncertaintyConfig.sigma_ni_from_ne + + + + + +cfg.UncertaintyConfig.sigma_ni_from_ne->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles + + + + +UncertaintyConfig.sigma_profiles + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ne + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_te + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.te_scalar_sigma + + + + +UncertaintyConfig.te_scalar_sigma + + + + + +cfg.UncertaintyConfig.te_scalar_sigma->gate.sigma_priority_te + + + + + + + + +cfg.UncertaintyConfig.ti_scalar_sigma + + + + +UncertaintyConfig.ti_scalar_sigma + + + + + +cfg.UncertaintyConfig.ti_scalar_sigma->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.zeff_scalar_sigma + + + + +UncertaintyConfig.zeff_scalar_sigma + + + + + +gate.zeff_channel_enable + + +zeff channel enabled (when zeff_scalar_sigma>0) + + + + + +cfg.UncertaintyConfig.zeff_scalar_sigma->gate.zeff_channel_enable + + + + + + + + +fn.baseline._load_kinetic_profiles->gate.profile_file_type + + + + + + + + +qty.j_NBI + + +j_NBI [A/m^2] (beam-driven) + + + + + +fn.baseline._resolve_fixed->qty.j_NBI + + + + + + + + +fn.baseline._resolve_fixed->qty.j_RF + + + + + + + + +fn.baseline._resolve_fixed->qty.p_fast + + + + + + + + +fn.baseline._resolve_reconstruction + + +_resolve_reconstruction(source, config, mygs) + + + + + +fn.baseline._resolve_reconstruction->fn.baseline._load_kinetic_profiles + + + + + + + + +fn.baseline._resolve_reconstruction->fn.baseline._resolve_fixed + + + + + + + + +fn.baseline._resolve_reconstruction->qty.Ip_target + + + + + + + + +fn.baseline._resolve_reconstruction->qty.j_BS + + + + + + + + +qty.j_inductive + + +j_inductive (ohmic current) + + + + + +fn.baseline._resolve_reconstruction->qty.j_inductive + + + + + + + + +fn.baseline._resolve_reconstruction->qty.j_phi + + + + + + + + +fn.baseline._resolve_reconstruction->qty.li_target + + + + + + + + +fn.baseline._resolve_reconstruction->qty.psi_N + + + + + + + + +qty.aux_baselines + + +aux_baselines dict + + + + + +fn.baseline._sigma_zeff_baseline->qty.aux_baselines + + + + + + + + +fn.baseline.resolve_baseline + + +resolve_baseline(config, mygs) + + + + + +gate.source_type + + +source type: ImasSource | ReconstructionSource + + + + + +fn.baseline.resolve_baseline->gate.source_type + + + + + + + + +fn.baseline.resolve_uncertainty + + +resolve_uncertainty(config, baseline) + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ne + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ni + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_te + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ti + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_zeff + + + + + + + + +fn.baseline.resolve_uncertainty->qty.aux_baselines + + + + + + + + +qty.aux_sigmas + + +aux_sigmas dict + + + + + +fn.baseline.resolve_uncertainty->qty.aux_sigmas + + + + + + + + + +fn.baseline.resolve_uncertainty->qty.sigma_jphi + + + + + + + + + +fn.io.imas.read_imas_baseline + + +read_imas_baseline(source, fixed, ...) + + + + + +fn.io.pfile.read_pfile->qty.ne + + + + + + + + + +fn.io.pfile.read_pfile->qty.ni + + + + + + + + + +fn.io.pfile.read_pfile->qty.psi_N_kinetic + + + + + + + + + +fn.io.pfile.read_pfile->qty.te + + + + + + + + +fn.io.pfile.read_pfile->qty.ti + + + + + + + + +fn.io.pfile.read_pfile->qty.zeff + + + + + + + + +gate.sigma_priority_ne->qty.sigma_ne + + + + + + + + +gate.sigma_priority_ni->qty.sigma_ni + + + + + + + + +gate.sigma_priority_te->qty.sigma_te + + + + + + + + +gate.sigma_priority_ti->qty.sigma_ti + + + + + + + + +gate.sigma_priority_zeff->qty.aux_sigmas + + + + + + + + +gate.source_type->fn.baseline._resolve_reconstruction + + + + + + + + +gate.source_type->fn.io.imas.read_imas_baseline + + + + + + + + +gate.zeff_channel_enable->fn.baseline._sigma_zeff_baseline + + + + + + + + +cfg.isolate_edge_jBS + + + + +isolate_edge_jBS + + + + + +ext.solve_with_bootstrap + + +solve_with_bootstrap() + + + + + +cfg.isolate_edge_jBS->ext.solve_with_bootstrap + + + + + + + + +cfg.isolate_edge_jBS->ext.solve_with_bootstrap + + + + + + + + +gate.j_inductive_decomposition + + +j_inductive storage logic (isolate_edge_jBS) + + + + + +cfg.isolate_edge_jBS->gate.j_inductive_decomposition + + + + + + + + +cfg.n_k + + + + +n_k (spline order) + + + + + +fn.tmi.fit_inductive_profile + + +fit_inductive_profile + + + + + +cfg.n_k->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.psi_bridge + + + + +psi_bridge + + + + + +cfg.psi_bridge->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.psi_pad + + + + +psi_pad + + + + + +fn.sampling.calc_cylindrical_li_proxy + + +calc_cylindrical_li_proxy + + + + + +cfg.psi_pad->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +fn.tmi._swb_jbs_to_toroidal + + +_swb_jbs_to_toroidal + + + + + +cfg.psi_pad->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +cfg.rescale_j_BS + + + + +rescale_j_BS + + + + + +cfg.rescale_j_BS->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.shelf_psi_N + + + + +shelf_psi_N + + + + + +cfg.shelf_psi_N->fn.tmi.fit_inductive_profile + + + + + + + + +qty.j_BS_shelved + + +j_BS after optional shelf + + + + + +cfg.shelf_psi_N->qty.j_BS_shelved + + + + + + + + +ext.corrective_jphi_iteration + + +_corrective_jphi_iteration + + + + + +qty.j_phi_output_corr + + +j_phi_output (corrective) + + + + + +ext.corrective_jphi_iteration->qty.j_phi_output_corr + + + + + + + + +qty.li_proxy_baseline + + +baseline li proxy + + + + + +fn.sampling.calc_cylindrical_li_proxy->qty.li_proxy_baseline + + + + + + + + +fn.tmi._shelf_blend_decompose + + +_shelf_blend_decompose + + + + + +qty.shelf_psi_value + + +shelf_psi (location) + + + + + +fn.tmi._shelf_blend_decompose->qty.shelf_psi_value + + + + + + + + +qty.full_j_BS + + +full_j_BS (full bootstrap, physical) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.full_j_BS + + + + + + + + +qty.j_dot_B + + +<j.B> (undo SWB projection) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.j_dot_B + + + + + + + + +qty.spike_profile + + +spike_profile (bootstrap spike) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.spike_profile + + + + + + + + +fn.tmi.classify_jphi_profile + + +classify_jphi_profile + + + + + +qty.jphi_mode + + +jphi_mode + + + + + +fn.tmi.classify_jphi_profile->qty.jphi_mode + + + + + + + + +qty.spike_metrics + + +spike_metrics + + + + + +fn.tmi.classify_jphi_profile->qty.spike_metrics + + + + + + + + +qty.bs_scale + + +bootstrap scaling factor + + + + + +fn.tmi.fit_inductive_profile->qty.bs_scale + + + + + + + + +qty.ind_scale + + +inductive scaling factor + + + + + +fn.tmi.fit_inductive_profile->qty.ind_scale + + + + + + + + +qty.j_inductive_basis + + +j_inductive_basis (spline fit) + + + + + +fn.tmi.fit_inductive_profile->qty.j_inductive_basis + + + + + + + + +fn.tmi.reconstruct_equilibrium + + +reconstruct_equilibrium + + + + + +gate.jphi_classified + + +gate.jphi_classified + + + + + +qty.j_BS_final + + +j_BS_final + + + + + +gate.jphi_classified->qty.j_BS_final + + + + + + + + +qty.j_phi_corrective_target + + +j_phi_corrective_target + + + + + +gate.jphi_classified->qty.j_phi_corrective_target + + + + + + + + +gate.li_converged + + +gate.li_converged + + + + + +gate.li_converged->fn.tmi.reconstruct_equilibrium + + + + + + + + +qty.ind_factor_opt + + +ind_factor (li-converged) + + + + + +gate.li_converged->qty.ind_factor_opt + + + + + + + + +input.eqdsk + + +EQDSK geqdsk equilibrium + + + + + +input.eqdsk->ext.solve_with_bootstrap + + + + + + + + +input.eqdsk->qty.Ip_target + + + + + + + + +qty.eqdsk_j_tor + + +eqdsk j_tor (baseline) + + + + + +input.eqdsk->qty.eqdsk_j_tor + + + + + + + + +input.eqdsk->qty.li_target + + + + + + + + +input.eqdsk->qty.psi_N + + + + + + + + +input.isoflux + + +Isoflux constraint points & weights + + + + + +qty.quality_metrics + + +quality metrics dict + + + + + +input.isoflux->qty.quality_metrics + + + + + + + +input.kinetics + + +Kinetic profiles (ne, te, ni, ti, Zeff) + + + + + +input.kinetics->ext.solve_with_bootstrap + + + + + + + + +qty.pressure + + +pressure profile + + + + + +input.kinetics->qty.pressure + + + + + + + + +input.mygs + + +TokaMaker GS solver + + + + + +input.mygs->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +input.mygs->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +art.h5_archive + + + +HDF5 archive {header}.h5 + + + + + +fn.run.export + + +export() + + + + + +art.h5_archive->fn.run.export + + + + + + + + +fn.archive.BouquetArchive + + + +BouquetArchive(ref) + + + + + +art.h5_archive->fn.archive.BouquetArchive + + + + + + + + +fn.utils.discover_scan_keys + + +discover_scan_keys(h5path_or_header) + + + + + +art.h5_archive->fn.utils.discover_scan_keys + + + + + + + + +fn.utils.list_equilibrium_indices + + +list_equilibrium_indices(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.list_equilibrium_indices + + + + + + + + +fn.utils.load_baseline_profiles + + +load_baseline_profiles(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.load_baseline_profiles + + + + + + + + +fn.utils.load_config + + +load_config(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.load_config + + + + + + + + +fn.utils.load_equilibrium + + +load_equilibrium(header, count, scan_key, eqdsk_out_dir) + + + + + +art.h5_archive->fn.utils.load_equilibrium + + + + + + + + +cfg.generation.floor_j_BS + + + + +config.generation.floor_j_BS + + + + + +fn.run._forward_solve_imas_baseline + + +_forward_solve_imas_baseline() + + + + + +cfg.generation.floor_j_BS->fn.run._forward_solve_imas_baseline + + + + + + + + +cfg.generation.isolate_edge_jBS + + + + +config.generation.isolate_edge_jBS + + + + + +cfg.generation.jBS_baseline_mode + + + + +config.generation.jBS_baseline_mode + + + + + +gate.jBS_baseline_mode + + +jBS_baseline_mode (diff vs rescale) + + + + + +cfg.generation.jBS_baseline_mode->gate.jBS_baseline_mode + + + + + + + + +gate.workflow_guard + + +workflow validation gate + + + + + +cfg.generation.jBS_baseline_mode->gate.workflow_guard + + + + + + + + +cfg.generation.recalculate_j_BS + + + + +config.generation.recalculate_j_BS + + + + + +cfg.generation.recalculate_j_BS->fn.run._forward_solve_imas_baseline + + + + + + + + +cfg.source.type + + + + +source type + + + + + +fn.run._validate_workflow + + +_validate_workflow() + + + + + +cfg.source.type->fn.run._validate_workflow + + + + + + + + +ext.generate_bouquet + + +generate_bouquet() + + + + + +ext.solve_with_bootstrap->qty.full_j_BS + + + + + + + + +qty.j_BS_swb + + +j_BS from solve_with_bootstrap (parallel) + + + + + +ext.solve_with_bootstrap->qty.j_BS_swb + + + + + + + + +ext.solve_with_bootstrap->qty.spike_profile + + + + + + + + +gate.ip_sanity + + +Ip convergence check + + + + + +fn.run._forward_solve_imas_baseline->gate.ip_sanity + + + + + + + + +fn.run._forward_solve_imas_baseline->qty.li_target + + + + + + + + +fn.run._repoint_imas_geometry + + +_repoint_imas_geometry() + + + + + +fn.run._repoint_imas_geometry->qty.boundary_lcfs + + + + + + + + +fn.run._resolve_workflow_preset + + +resolve workflow preset + + + + + +fn.run._resolve_workflow_preset->gate.workflow_guard + + + + + + + + +fn.run.generate + + +generate() + + + + + +fn.run._validate_workflow->fn.run.generate + + + + + + + + +fn.run.run + + +run() [convenience] + + + + + +fn.run.export->fn.run.run + + + + + + + + +fn.run.filter + + +filter() + + + + + +fn.run.filter->fn.run.export + + + + + + + + +fn.run.filter->fn.run.run + + + + + + + + + +fn.run.run_slices + + +run_slices() + + + + + +fn.run.filter->fn.run.run_slices + + + + + + + + +fn.run.generate->art.h5_archive + + + + + + + + +fn.run.generate->fn.run.filter + + + + + + + + +fn.run.generate->fn.run.run + + + + + + + + +fn.run.generate->fn.run.run_slices + + + + + + + + +fn.run.prepare_baseline + + +prepare_baseline() + + + + + +fn.run.prepare_baseline->fn.run.run + + + + + + + + +fn.run.prepare_baseline->fn.run.run_slices + + + + + + + + +fn.run.prepare_baseline->qty.Ip_target + + + + + + + + + +qty.j_BS_src + + +j_BS_src + + + + + +fn.run.prepare_baseline->qty.j_BS_src + + + + + + + +fn.run.prepare_baseline->qty.j_inductive + + + + + + + +fn.run.prepare_baseline->qty.j_phi + + + + + + + + + +fn.run.prepare_baseline->qty.ne + + + + + + + + +fn.run.prepare_baseline->qty.ni + + + + + + + +fn.run.prepare_baseline->qty.psi_N + + + + + + + + +fn.run.prepare_baseline->qty.psi_N_kinetic + + + + + + + + +fn.run.prepare_baseline->qty.te + + + + + + + + +fn.run.prepare_baseline->qty.ti + + + + + + + +fn.run.prepare_baseline->qty.zeff + + + + + + + +fn.run.set_slice + + +set_slice() + + + + + +fn.run.set_slice->fn.run._repoint_imas_geometry + + + + + + + + +fn.run.set_slice->fn.run.run_slices + + + + + + + + +fn.run.setup_solver + + +setup_solver() + + + + + +fn.run.setup_solver->fn.run.prepare_baseline + + + + + + + + +fn.run.setup_solver->fn.run.run + + + + + + + + +fn.run.setup_solver->fn.run.run_slices + + + + + + + + +fn.run.setup_solver->qty.F0 + + + + + + + + +fn.run.setup_solver->qty.boundary_lcfs + + + + + + + + +gate.ip_sanity->fn.run.generate + + + + + + + + +gate.jBS_baseline_mode->qty.bs_scale + + + + + + + + +qty.jBS_diff + + +jBS_diff [A/m^2] (bootstrap correction) + + + + + +gate.jBS_baseline_mode->qty.jBS_diff + + + + + + + + +qty.j_phi_diff_mode + + +j_phi (diff) + + + + + +gate.jBS_baseline_mode->qty.j_phi_diff_mode + + + + + + + + +qty.j_phi_rescale_mode + + +j_phi (rescale) + + + + + +gate.jBS_baseline_mode->qty.j_phi_rescale_mode + + + + + + + + +cfg.coil_drift + + + + +coil_drift + + + + + +cfg.constrain_sawteeth + + + + +constrain_sawteeth + + + + + +gate.sawteeth_q0 + + +gate.sawteeth_q0 (q0 constraint) + + + + + +cfg.constrain_sawteeth->gate.sawteeth_q0 + + + + + + + + +gate.constrain_sawteeth_post + + +Post-check q_0 < 1 (final reject) + + + + + +cfg.constrain_sawteeth->gate.constrain_sawteeth_post + + + + + + + + +gate.constrain_sawteeth_pre + + +Pre-check q_0 < 1 (early reject) + + + + + +cfg.constrain_sawteeth->gate.constrain_sawteeth_pre + + + + + + + + +cfg.jBS_scale_range + + + + +jBS_scale_range + + + + + +qty.jBS_scales + + +jBS_scales (per-draw samples) + + + + + +cfg.jBS_scale_range->qty.jBS_scales + + + + + + + + +cfg.l_i_tolerance + + + + +l_i_tolerance + + + + + +gate.li_band + + +gate.li_band (l_i acceptance) + + + + + +cfg.l_i_tolerance->gate.li_band + + + + + + + + +gate.li_acceptance + + +l_i band acceptance gate + + + + + +cfg.l_i_tolerance->gate.li_acceptance + + + + + + + + +cfg.l_i_uncertainty + + + + +l_i_uncertainty + + + + + +qty.l_i_target_draw + + +l_i_target_draw (per-draw sample) + + + + + +cfg.l_i_uncertainty->qty.l_i_target_draw + + + + + + + + +cfg.n_equils + + + + +n_equils + + + + + +fn.tmi.generate_bouquet + + +generate_bouquet (batch driver) + + + + + +cfg.n_equils->fn.tmi.generate_bouquet + + + + + + + + +cfg.recalculate_j_BS + + + + +recalculate_j_BS + + + + + +gate.recalculate_jBS + + +Bootstrap recalculation gate + + + + + +cfg.recalculate_j_BS->gate.recalculate_jBS + + + + + + + + +cfg.seed + + + + +seed (RNG) + + + + + +cfg.seed->fn.tmi.generate_bouquet + + + + + + + + +fn.sampling.generate_perturbed_GPR + + +generate_perturbed_GPR (GPR sampling) + + + + + +qty.aux_out + + +aux_out (per-draw auxiliary) + + + + + +fn.sampling.generate_perturbed_GPR->qty.aux_out + + + + + + + + +qty.ne_draw + + +ne_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ne_draw + + + + + + + + +qty.ni_draw + + +ni_draw (per-draw perturb or derived) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ni_draw + + + + + + + + +qty.te_draw + + +te_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.te_draw + + + + + + + + +qty.ti_draw + + +ti_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ti_draw + + + + + + + + +qty.zeff_draw + + +zeff_draw (per-draw sample) + + + + + +fn.sampling.generate_perturbed_GPR->qty.zeff_draw + + + + + + + + +fn.tmi.perturb_kinetic_equilibrium + + +perturb_kinetic_equilibrium (core loop) + + + + + +gate.li_target_sample + + +sample per-draw l_i target? + + + + + +fn.tmi.perturb_kinetic_equilibrium->gate.li_target_sample + + + + + + + + +qty.diagnostics + + +diagnostics (per-draw metrics) + + + + + +fn.tmi.perturb_kinetic_equilibrium->qty.diagnostics + + + + + + + + +qty.output_jphi + + +output_jphi (per-draw j_phi) + + + + + +fn.tmi.perturb_kinetic_equilibrium->qty.output_jphi + + + + + + + + +fn.utils.store_baseline_profiles + + +store_baseline_profiles (baseline save) + + + + + +art.h5.baseline + + + +baseline group (_baseline) + + + + + +fn.utils.store_baseline_profiles->art.h5.baseline + + + + + + + + +art.h5.coil_currents + + + +coil_currents + coil_names + + + + + +fn.utils.store_baseline_profiles->art.h5.coil_currents + + + + + + + + + +art.h5.eqdsk + + + +eqdsk dataset + + + + + +fn.utils.store_baseline_profiles->art.h5.eqdsk + + + + + + + + + + +art.h5.x_points + + + +x_points + + + + + +fn.utils.store_baseline_profiles->art.h5.x_points + + + + + + + + + +fn.utils.store_equilibrium + + +store_equilibrium (per-draw save) + + + + + +fn.utils.store_equilibrium->art.h5_archive + + + + + + + + +art.h5.aux + + + +aux_* profiles + + + + + +fn.utils.store_equilibrium->art.h5.aux + + + + + + + + +fn.utils.store_equilibrium->art.h5.coil_currents + + + + + + + +fn.utils.store_equilibrium->art.h5.eqdsk + + + + + + + +art.h5.filter_flags + + + +filter flags (group attrs) + + + + + +fn.utils.store_equilibrium->art.h5.filter_flags + + + + + + + +art.h5.perturbed_lcfs_ref + + + +perturbed_lcfs_ref + + + + + +fn.utils.store_equilibrium->art.h5.perturbed_lcfs_ref + + + + + + + + +art.h5.profiles + + + +profiles (psi_N, j_phi, j_BS, ...) + + + + + +fn.utils.store_equilibrium->art.h5.profiles + + + + + + + + + +fn.utils.store_equilibrium->art.h5.x_points + + + + + + + + +gate.draw_accepted + + +gate.draw_accepted (final acceptance) + + + + + +gate.li_band->gate.draw_accepted + + + + + + + + +fn.tmi._corrective_jphi_iteration + + +_corrective_jphi_iteration (residual refinement) + + + + + +gate.li_target_sample->fn.tmi._corrective_jphi_iteration + + + + + + + + +gate.sawteeth_q0->gate.draw_accepted + + + + + + + + +gate.solve_failed + + +gate.solve_failed (solver convergence) + + + + + +gate.solve_failed->gate.draw_accepted + + + + + + + + +progress_callback + + +progress_callback (per-draw tick) + + + + + +progress_callback->fn.tmi.generate_bouquet + + + + + + + + +art.eqdsk_bytes + + + +EQDSK file (per-draw) + + + + + +art.perturbed_lcfs_ref + + + +LCFS trace (perturbed) + + + + + +art.x_points + + + +X-point locations + + + + + +cfg.accept_anchor_inband + + + + +accept_anchor_inband (Fix-B path) + + + + + +gate.li_loop_variant + + +l_i match strategy gate + + + + + +cfg.accept_anchor_inband->gate.li_loop_variant + + + + + + + + +gate.perturb_jind_in_anchor_loop + + +Fix-C resample loop (perturb_jind_in_anchor) + + + + + +cfg.accept_anchor_inband->gate.perturb_jind_in_anchor_loop + + + + + + + + +cfg.floor_j_BS + + + + +floor_j_BS (negative bootstrap clipping) + + + + + +cfg.floor_j_BS->qty.spike_profile + + + + + + + + +cfg.max_li_iter + + + + +max_li_iter (l_i loop cap) + + + + + +cfg.max_pressure_iter + + + + +max_pressure_iter (pressure loop cap) + + + + + +cfg.max_proxy_draws + + + + +max_proxy_draws (proxy-draw cap) + + + + + +cfg.mygs + + +mygs (TokaMaker solver) + + + + + +cfg.npsi + + +npsi (grid size) + + + + + +cfg.p_thresh + + + + +p_thresh (pressure match tolerance) + + + + + +cfg.perturb_jind_in_anchor + + + + +perturb_jind_in_anchor (Fix-C path) + + + + + +cfg.perturb_jind_in_anchor->gate.li_loop_variant + + + + + + + + +cfg.perturb_jind_in_anchor->gate.perturb_jind_in_anchor_loop + + + + + + + + +cfg.pin_jphi + + + + +pin_jphi (PIN_JPHI diagnostic) + + + + + +gate.pin_jphi_branch + + +PIN_JPHI diagnostic branch + + + + + +cfg.pin_jphi->gate.pin_jphi_branch + + + + + + + + +cfg.proxy_bias_warmstart + + + + +proxy_bias_warmstart (cross-draw cache) + + + + + +cfg.recon_eq_snapshot + + + + +recon_eq_snapshot (DIFF_BS cache) + + + + + +gate.diff_bs_branch + + +DIFF_BS differential-bootstrap branch + + + + + +cfg.recon_eq_snapshot->gate.diff_bs_branch + + + + + + + + +cfg.scale_jBS + + + + +scale_jBS (bootstrap scale factor) + + + + + +cfg.scale_jBS->ext.solve_with_bootstrap + + + + + + + + +cfg.spike_profile_recon_cached + + + + +spike_profile_recon_cached (DIFF_BS cache) + + + + + +cfg.spike_profile_recon_cached->gate.diff_bs_branch + + + + + + + + +cfg.swb_iterations + + + + +swb_iterations (SWB self-consistency) + + + + + +cfg.swb_iterations->ext.solve_with_bootstrap + + + + + + + + +ext.scipy_interp1d + + +interp1d (kinetic↔equilibrium grid) + + + + + +ext.tokamaker_get_stats + + +mygs.get_stats (extract equilibrium state) + + + + + +ext.tokamaker_replace_eq + + +mygs.replace_eq (state restore for DIFF_BS) + + + + + +ext.tokamaker_set_profiles + + +mygs.set_profiles (pressure/current assignment) + + + + + +ext.tokamaker_solve + + +mygs.solve() (GS forward solve) + + + + + +qty.F_prof + + +F (flux function) + + + + + +ext.tokamaker_solve->qty.F_prof + + + + + + + + +qty.Ip_tokamaker + + +Ip (TokaMaker output) + + + + + +ext.tokamaker_solve->qty.Ip_tokamaker + + + + + + + + +qty.li_current + + +li (TokaMaker output) + + + + + +ext.tokamaker_solve->qty.li_current + + + + + + + + +qty.li_final + + +li_final + + + + + +ext.tokamaker_solve->qty.li_final + + + + + + + + +fn.tmi.Ip_flux_integral_vs_target + + +Ip_flux_integral_vs_target (root-find target) + + + + + +gate.skip_hard_bounds_env + + +SKIP_HARD env? + + + + + +fn.tmi._corrective_jphi_iteration->gate.skip_hard_bounds_env + + + + + + + + +fn.tmi._corrective_jphi_iteration->qty.output_jphi + + + + + + + + +fn.tmi._kin_to_eq + + +_kin_to_eq (kinetic grid → equilibrium grid) + + + + + +fn.tmi._vsc_channel_drift_pct + + +VSC drift (common-mode + differential, quadrature sigma) + + + + + +gate.in_spec_verdict + + +in-spec verdict + + + + + +fn.tmi._vsc_channel_drift_pct->gate.in_spec_verdict + + + + + + + + +fn.tmi.calc_cylindrical_li_proxy + + +calc_cylindrical_li_proxy (fast proxy) + + + + + +fn.tmi.calc_realgeom_li_proxy_fast + + +calc_realgeom_li_proxy_fast (real-geom pre-screen) + + + + + +fn.tmi.find_optimal_scale + + +find_optimal_scale (SWB OFT import) + + + + + +qty.final_jphi + + +final_jphi (find_optimal_scale output) + + + + + +fn.tmi.find_optimal_scale->qty.final_jphi + + + + + + + + +qty.final_scale_j0 + + +final_scale_j0 (core j0 scale factor) + + + + + +fn.tmi.find_optimal_scale->qty.final_scale_j0 + + + + + + + + +fn.tmi.generate_perturbed_GPR + + +generate_perturbed_GPR (external import) + + + + + +fn.tmi.get_li_proxy_geometry + + +get_li_proxy_geometry (real-geom prescreen) + + + + + +fn.tmi.recon_anchor_solve + + +recon-anchor forward solve + + + + + +qty.eq_stats + + +eq_stats (TokaMaker equilibrium stats) + + + + + +fn.tmi.recon_anchor_solve->qty.eq_stats + + + + + + + + +gate.diff_bs_branch->ext.solve_with_bootstrap + + + + + + + + +gate.homotopy_early_stop + + +next pass already infeasible? + + + + + +gate.homotopy_early_stop->gate.in_spec_verdict + + + + + + + + +gate.homotopy_feasible + + +homotopy pass converged? + + + + + +gate.qp_saturation + + +QP saturated at coil bound? + + + + + +gate.homotopy_feasible->gate.qp_saturation + + + + + + + + +gate.post_align_failed + + +post-alignment failure? + + + + + +gate.in_spec_verdict->gate.post_align_failed + + + + + + + + +gate.iso_update + + +re-point isoflux to perturbed LCFS? + + + + + +gate.skip_homotopy_env + + +SKIP_HOMOTOPY env? + + + + + +gate.iso_update->gate.skip_homotopy_env + + + + + + + + +qty.j_inductive_consistent + + +j_inductive_consistent (stored inductive) + + + + + +gate.j_inductive_decomposition->qty.j_inductive_consistent + + + + + + + + +gate.li_band_loop + + +l_i band-conditioning loop (rejection sampling) + + + + + +gate.li_acceptance->gate.li_band_loop + + + + + + + + +qty.jphi_perturb + + +jphi_perturb (GPR j_phi candidate) + + + + + +gate.li_band_loop->qty.jphi_perturb + + + + + + + + +gate.li_loop_variant->gate.li_band_loop + + + + + + + + +qty.matched_j_inductive + + +matched_j_inductive (Ip-scaled inductive) + + + + + +gate.perturb_jind_in_anchor_loop->qty.matched_j_inductive + + + + + + + + +gate.pin_jphi_branch->qty.spike_profile + + + + + + + + +gate.post_align_failed->gate.draw_accepted + + + + + + + + +gate.pressure_match + + +pressure-match loop + + + + + +qty.ne_perturb + + +ne_perturb (perturbed density) + + + + + +gate.pressure_match->qty.ne_perturb + + + + + + + + +qty.ni_perturb + + +ni_perturb (perturbed ion density) + + + + + +gate.pressure_match->qty.ni_perturb + + + + + + + + +qty.te_perturb + + +te_perturb (perturbed temperature) + + + + + +gate.pressure_match->qty.te_perturb + + + + + + + + +qty.ti_perturb + + +ti_perturb (perturbed ion temperature) + + + + + +gate.pressure_match->qty.ti_perturb + + + + + + + + +gate.qp_saturation->gate.homotopy_early_stop + + + + + + + + +gate.skip_hard_bounds_env->gate.iso_update + + + + + + + + +gate.skip_homotopy_env->gate.homotopy_feasible + + + + + + + + +gate.skip_iso_env + + +SKIP_ISO env? + + + + + +gate.standard_swb_branch + + +Standard SWB branch + + + + + +gate.zeff_active + + +Zeff-primary channel active + + + + + +qty.Z_imp + + +effective impurity charge + + + + + +gate.zeff_active->qty.Z_imp + + + + + + + + +gate.zeff_active->qty.zeff_draw + + + + + + + + +qty.Zeff + + +Zeff (effective charge profile) + + + + + +qty.Zeff->ext.solve_with_bootstrap + + + + + + + + +qty.Zeff->gate.zeff_active + + + + + + + + +qty.coil_currents + + + +Coil currents (per-draw) + + + + + +qty.coil_currents->art.eqdsk_bytes + + + + + + + + +qty.coil_currents->art.perturbed_lcfs_ref + + + + + + + + +qty.in_spec_metrics + + + +In-spec boundary metrics + + + + + +qty.input_j_phi + + +input_j_phi (total j_phi baseline) + + + + + +qty.input_j_phi->qty.spike_profile + + + + + + + + +qty.input_jinductive + + +input_jinductive (inductive j_phi component) + + + + + +qty.input_jinductive->qty.jphi_perturb + + + + + + + + +qty.new_jphi + + +new_jphi (total j_phi for anchor) + + + + + +qty.input_jinductive->qty.new_jphi + + + + + + + + +qty.input_jinductive->qty.spike_profile + + + + + + + + +qty.l_i_target + + +l_i_target (internal inductance target) + + + + + +qty.l_i_target->gate.li_acceptance + + + + + + + + +fn.plotting.plot_bouquet + + +plot_bouquet(h5path, scan_key, mode, ...) + + + + + +art.h5.baseline->fn.plotting.plot_bouquet + + + + + + + + +fn.plotting.plot_coil_currents + + +plot_coil_currents(h5path, scan_key, vsc_coils, ...) + + + + + +art.h5.baseline->fn.plotting.plot_coil_currents + + + + + + + + +fn.plotting.plot_traces + + +plot_traces(h5path, scan_key, li_band, rms_max_mm) + + + + + +art.h5.baseline->fn.plotting.plot_traces + + + + + + + + +fn.filtering._baseline_boundary + + +filtering._baseline_boundary + + + + + +art.h5.baseline->fn.filtering._baseline_boundary + + + + + + + + +fn.filtering.filter_coil_currents + + +filter_coil_currents(h5path, scan_key, F_max_pct, VSC_max_pct, apply, plot) + + + + + +art.h5.coil_currents->fn.filtering.filter_coil_currents + + + + + + + + +art.h5.coil_currents->fn.plotting.plot_coil_currents + + + + + + + + +art.h5.config_json + + + +config_json dataset + + + + + +fn.archive.DrawView + + + +DrawView(archive, scan_key, count) + + + + + +art.h5.eqdsk->fn.archive.DrawView + + + + + + + + +fn.plotting.plot_geqdsk_bouquet + + +plot_geqdsk_bouquet(geqdsk_path_or_eq, ...) + + + + + +art.h5.eqdsk->fn.plotting.plot_geqdsk_bouquet + + + + + + + + +fn.filtering._boundary_devs + + +_boundary_devs(bl_boundary, grp) + + + + + +art.h5.perturbed_lcfs_ref->fn.filtering._boundary_devs + + + + + + + + +art.h5.perturbed_lcfs_ref->fn.plotting.plot_traces + + + + + + + + +art.h5.pfile + + + +pfile dataset + + + + + +art.h5.pfile->fn.archive.DrawView + + + + + + + + +fn.plotting.plot_pfile_bouquet + + +plot_pfile_bouquet(pfile_path_or_pf, ...) + + + + + +art.h5.pfile->fn.plotting.plot_pfile_bouquet + + + + + + + + +art.h5.profiles->fn.archive.DrawView + + + + + + + + +fn.gui.EquilibriumBrowser + + + +EquilibriumBrowser(h5path) + + + + + +art.h5.profiles->fn.gui.EquilibriumBrowser + + + + + + + + +art.h5.profiles->fn.plotting.plot_bouquet + + + + + + + + +art.h5.x_points->fn.plotting.plot_traces + + + + + + + + +cfg.filtering.F_max_pct + + + + +F_max_pct + + + + + +cfg.filtering.F_max_pct->fn.filtering.filter_coil_currents + + + + + + + + +cfg.filtering.VSC_max_pct + + + + +VSC_max_pct + + + + + +cfg.filtering.VSC_max_pct->fn.filtering.filter_coil_currents + + + + + + + + +cfg.filtering.max_max_mm + + + + +max_max_mm + + + + + +fn.filtering.filter_boundaries + + +filter_boundaries(h5path, scan_key, rms_max_mm, max_max_mm, apply, plot) + + + + + +cfg.filtering.max_max_mm->fn.filtering.filter_boundaries + + + + + + + + +cfg.filtering.rms_max_mm + + + + +rms_max_mm + + + + + +cfg.filtering.rms_max_mm->fn.filtering.filter_boundaries + + + + + + + + +fn.archive.ScanView + + + +ScanView(archive, scan_key) + + + + + +fn.archive.BouquetArchive->fn.archive.ScanView + + + + + + + + +fn.archive.ScanView->fn.archive.DrawView + + + + + + + + +fn.filtering._boundary_devs->fn.filtering.filter_boundaries + + + + + + + + +fn.filtering.export_filtered + + +export_filtered(h5path, out_path, scan_key, selection, overwrite) + + + + + +fn.filtering.export_filtered->art.h5_archive + + + + + + + + +fn.filtering.filter_boundaries->art.h5.filter_flags + + + + + + + + + +gate.selected + + +selected (AND of filters) + + + + + +fn.filtering.filter_boundaries->gate.selected + + + + + + + + +fn.filtering.filter_coil_currents->art.h5.filter_flags + + + + + + + + + +fn.filtering.filter_coil_currents->gate.selected + + + + + + + + +fn.filtering.read_filter_flags + + +read_filter_flags(h5path, scan_key) + + + + + +fn.filtering.select_indices + + +select_indices(h5path, scan_key, selection) + + + + + +fn.filtering.read_filter_flags->fn.filtering.select_indices + + + + + + + + +fn.filtering.select_indices->fn.archive.ScanView + + + + + + + + +fn.filtering.select_indices->fn.filtering.export_filtered + + + + + + + + +fn.filtering.select_indices->fn.plotting.plot_bouquet + + + + + + + + +fn.schema.find_bytes_dataset + + +find_bytes_dataset(grp, kind) + + + + + +fn.schema.find_bytes_dataset->fn.archive.DrawView + + + + + + + + +fn.schema.write_profile + + +write_profile(grp, name, data) + + + + + +fn.schema.write_profile->fn.utils.store_baseline_profiles + + + + + + + + + +fn.schema.write_profile->fn.utils.store_equilibrium + + + + + + + +fn.utils.discover_scan_keys->fn.archive.BouquetArchive + + + + + + + + +fn.utils.initialize_equilibrium_database + + +initialize_equilibrium_database(header) + + + + + +fn.utils.initialize_equilibrium_database->fn.utils.store_equilibrium + + + + + + + + +fn.utils.list_equilibrium_indices->fn.archive.ScanView + + + + + + + + +fn.utils.load_baseline_profiles->fn.archive.ScanView + + + + + + + + +fn.utils.load_baseline_profiles->fn.gui.EquilibriumBrowser + + + + + + + + +fn.utils.load_baseline_profiles->fn.plotting.plot_bouquet + + + + + + + + +fn.utils.write_provenance + + +write_provenance(h5path, config, scan_key) + + + + + +fn.utils.write_provenance->art.h5_archive + + + + + + + + +gate.boundary_rms + + +Boundary RMS/max pass/fail + + + + + +gate.boundary_rms->fn.filtering.filter_boundaries + + + + + + + + +gate.coil_spec + + +Coil-spec pass/fail + + + + + +gate.coil_spec->fn.filtering.filter_coil_currents + + + + + + + + +gate.selected->art.h5.filter_flags + + + + + + + + +art.sbatch_scripts + + + +{job_name}_array.sbatch, {job_name}_merge.sbatch, {job_name}_submit.sh + + + + + +art.shard_h5 + + + +{out_header}_w{worker_id}.h5 + + + + + +fn.parallel.merge_archives + + +merge_archives(shard_paths, out_header, ...) + + + + + +art.shard_h5->fn.parallel.merge_archives + + + + + + + + +art.slurm_bundle + + + +{job_name}_bundle.json + + + + + +fn.parallel._cli + + +_cli(argv) + + + + + +art.slurm_bundle->fn.parallel._cli + + + + + + + + +env.blas_pinning + + +BLAS/OpenMP env pinning + + + + + +fn.run.Bouquet_pipeline + + +Bouquet.setup_solver -> prepare_baseline -> generate + + + + + +env.blas_pinning->fn.run.Bouquet_pipeline + + + + + + + + +env.fd_suppression + + +fd-level stdout/stderr suppression + + + + + +fn.parallel.run_shard + + +run_shard(config, worker_id, n_workers, ...) + + + + + +env.fd_suppression->fn.parallel.run_shard + + + + + + + + +fn.parallel._cli->fn.parallel.merge_archives + + + + + + + + +fn.parallel._cli->fn.parallel.run_shard + + + + + + + + +fn.parallel._derive_seed + + +_derive_seed(seed_base, worker_id, scan_key) + + + + + +fn.parallel._physical_cores + + +_physical_cores() + + + + + +knob.n_workers + + + + +n_workers + + + + + +fn.parallel._shard_size + + +_shard_size(total, n_workers, worker_id) + + + + + +fn.parallel._warn_multithreaded + + +_warn_multithreaded(threads_per_worker) + + + + + +gate.threads_warn + + +threads_per_worker > 1 warning + + + + + +fn.parallel._warn_multithreaded->gate.threads_warn + + + + + + + + +fn.parallel.emit_slurm_script + + +emit_slurm_script(config, ...) + + + + + +fn.parallel.emit_slurm_script->art.sbatch_scripts + + + + + + + + +fn.parallel.emit_slurm_script->art.slurm_bundle + + + + + + + + +fn.parallel.merge_archives->art.h5_archive + + + + + + + + +fn.parallel.merge_archives->art.h5.config_json + + + + + + + + +fn.parallel.parallel_generate + + +parallel_generate(config, ...) + + + + + +fn.parallel.merge_archives->fn.parallel.parallel_generate + + + + + + + + +gate.baseline_match_merge + + +baseline consistency check (merge) + + + + + +fn.parallel.merge_archives->gate.baseline_match_merge + + + + + + + + + +gate.baseline_match_laptop + + +baseline consistency check (laptop) + + + + + +fn.parallel.parallel_generate->gate.baseline_match_laptop + + + + + + + + +fn.parallel.run_shard->art.shard_h5 + + + + + + + + +fn.parallel.run_shard->fn.parallel.parallel_generate + + + + + + + + +fn.parallel.run_shard->fn.run.Bouquet_pipeline + + + + + + + + + +fn.run.Bouquet_pipeline->art.shard_h5 + + + + + + + + +fn.utils.capture_native_output + + +capture_native_output (fd redirect) + + + + + +fn.utils.capture_native_output->fn.parallel.run_shard + + + + + + + + +gate.backend + + +backend decision + + + + + +gate.backend->fn.parallel.emit_slurm_script + + + + + + + + +gate.backend->fn.parallel.parallel_generate + + + + + + + + + + +gate.baseline_match_laptop->fn.parallel.merge_archives + + + + + + + + +gate.missing_shards + + +missing shards handling (CLI) + + + + + +gate.missing_shards->fn.parallel._cli + + + + + + + + +input.config + + +BouquetConfig + + + + + +input.config->art.h5.config_json + + + + + + + + +input.config->fn.parallel.emit_slurm_script + + + + + + + + +input.config->fn.parallel.parallel_generate + + + + + + + +input.config->fn.parallel.run_shard + + + + + + + + +knob.scan_key + + + + +scan_key + + + + + +input.config->knob.scan_key + + + + + + + + +quantity.n_equils_total + + +n_equils_total + + + + + +input.config->quantity.n_equils_total + + + + + + + + +input.user_args + + +CLI/user args + + + + + +knob.backend + + + + +backend + + + + + +input.user_args->knob.backend + + + + + + + + +input.user_args->knob.n_workers + + + + + + + + +knob.seed + + + + +seed + + + + + +input.user_args->knob.seed + + + + + + + + + +knob.threads_per_worker + + + + +threads_per_worker + + + + + +input.user_args->knob.threads_per_worker + + + + + + + + +knob.backend->gate.backend + + + + + + + + +knob.n_workers->fn.parallel._physical_cores + + + + + + + + + +knob.n_workers->fn.parallel.emit_slurm_script + + + + + + + + +quantity.n_equils_per_worker + + +n_equils_per_worker + + + + + +knob.n_workers->quantity.n_equils_per_worker + + + + + + + + +quantity.per_worker_seed + + +per_worker_seed + + + + + +knob.scan_key->quantity.per_worker_seed + + + + + + + + +knob.seed->fn.parallel.emit_slurm_script + + + + + + + + +knob.seed->quantity.per_worker_seed + + + + + + + + +knob.threads_per_worker->env.blas_pinning + + + + + + + + +knob.threads_per_worker->fn.parallel._warn_multithreaded + + + + + + + + +knob.threads_per_worker->fn.parallel.emit_slurm_script + + + + + + + + +quantity.n_equils_per_worker->fn.parallel.run_shard + + + + + + + +quantity.n_equils_total->quantity.n_equils_per_worker + + + + + + + + +quantity.per_worker_seed->fn.parallel.run_shard + + + + + + + + + +qty.F0->fn.reconstruct_equilibrium + + + + + + + + + +qty.FUSE_tot + + +FUSE_tot + + + + + +qty.FUSE_tot->gate.jBS_baseline_mode + + + + + + + + +qty.Ip + + +Ip (plasma current) + + + + + +qty.Ip->art.eqdsk_bytes + + + + + + + + +qty.Ip_scales + + +Ip_scales + + + + + +qty.Ip_scales->qty.diagnostics + + + + + + + + +qty.Ip_target->fn.reconstruct_equilibrium + + + + + + + + + + +qty.Ip_target->artifact.baseline + + + + + + + + +qty.Ip_target->ext.corrective_jphi_iteration + + + + + + + + +qty.Ip_target->ext.solve_with_bootstrap + + + + + + + + +qty.Ip_target->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.Ip_target->fn.run.generate + + + + + + + + +qty.Ip_target->fn.tmi._corrective_jphi_iteration + + + + + + + + +qty.Ip_target->fn.tmi.find_optimal_scale + + + + + + + + +qty.Ip_target->fn.tmi.recon_anchor_solve + + + + + + + + +qty.a_optimal + + +a_optimal (Ip scale factor) + + + + + +qty.Ip_target->qty.a_optimal + + + + + + + + + +qty.Ip_target->qty.quality_metrics + + + + + + + + +qty.Ip_tokamaker->qty.quality_metrics + + + + + + + + +qty.Z_imp->artifact.baseline + + + + + + + + +qty.pres_tmp + + +pres_tmp (per-draw pressure) + + + + + +qty.Z_imp->qty.pres_tmp + + + + + + + + +qty.Zeff_eq + + +Zeff_eq + + + + + +qty.Zeff_eq->fn.run.generate + + + + + + + + +qty.matched_jphi_perturb + + +matched_jphi_perturb (Ip-matched j_phi candidate) + + + + + +qty.a_optimal->qty.matched_jphi_perturb + + + + + + + + +qty.aux_baselines->gate.zeff_active + + + + + + + +qty.aux_baselines->qty.aux_out + + + + + + + + +qty.aux_baselines->qty.zeff_draw + + + + + + + + +qty.aux_length_scales + + +aux_length_scales (auxiliary GPR scales) + + + + + +qty.aux_length_scales->qty.aux_out + + + + + + + + +qty.aux_length_scales->qty.zeff_draw + + + + + + + + +qty.aux_out->fn.utils.store_equilibrium + + + + + + + + +qty.aux_out->qty.diagnostics + + + + + + + + +qty.aux_sigmas->gate.zeff_active + + + + + + + + + +qty.aux_sigmas->qty.aux_out + + + + + + + + +qty.aux_sigmas->qty.zeff_draw + + + + + + + + +qty.avg_B2 + + +<B²> (FSA) + + + + + +qty.avg_inv_R + + +<1/R> (FSA) + + + + + +qty.baseline_j_BS_with_diff + + +baseline_j_BS (+ jBS_diff) + + + + + +qty.baseline_j_BS_with_diff->fn.run.generate + + + + + + + + +qty.baseline_li_proxy + + +baseline_li_proxy (cylindrical proxy l_i) + + + + + +qty.proxy_target + + +proxy_target (adaptive proxy target) + + + + + +qty.baseline_li_proxy->qty.proxy_target + + + + + + + + +qty.boundary_lcfs->fn.reconstruct_equilibrium + + + + + + + + +qty.bs_scale->fn.run.generate + + + + + + + + +qty.j_phi_fit_prelim + + +j_phi_fit (pre-li-match) + + + + + +qty.bs_scale->qty.j_phi_fit_prelim + + + + + + + + +qty.chi_e + + +chi_e [m^2/s] (electron transport) + + + + + +qty.chi_i + + +chi_i [m^2/s] (ion transport) + + + + + +qty.diagnostics->fn.utils.store_equilibrium + + + + + + + + +qty.e_r + + +e_r [V/m] (radial electric field) + + + + + +qty.eq_stats->qty.baseline_li_proxy + + + + + + + + +qty.eqdsk_j_tor->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +qty.eqdsk_j_tor->fn.tmi._shelf_blend_decompose + + + + + + + + +qty.eqdsk_j_tor->fn.tmi.classify_jphi_profile + + + + + + + + +qty.eqdsk_j_tor->qty.j_phi_corrective_target + + + + + + + + + +qty.eqdsk_j_tor->qty.quality_metrics + + + + + + + + +qty.ffp_prof_corr + + +FFp for GS (corrective) + + + + + +qty.ffp_prof_li + + +FFp for GS (li-match) + + + + + +qty.ffp_prof_li->ext.tokamaker_solve + + + + + + + + +qty.final_jphi->gate.constrain_sawteeth_pre + + + + + + + + +qty.target_jphi_perturb + + +target_jphi_perturb (corrective target) + + + + + +qty.final_jphi->qty.target_jphi_perturb + + + + + + + + +qty.final_li_proxy + + +final_li_proxy (diagnostic cylindrical proxy) + + + + + +qty.proxy_vs_real + + +proxy_vs_real (proxy-equilibrium offset %) + + + + + +qty.final_li_proxy->qty.proxy_vs_real + + + + + + + + +qty.final_scale_j0->qty.target_jphi_perturb + + + + + + + + +qty.full_j_BS->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.full_j_BS->qty.diagnostics + + + + + + + + +qty.guess_j_inductive + + +guess_j_inductive + + + + + +qty.j_ind_li_matched + + +j_ind (li-matched) + + + + + +qty.ind_factor_opt->qty.j_ind_li_matched + + + + + + + + +qty.j_inductive_fit + + +j_inductive_fit (scaled) + + + + + +qty.ind_scale->qty.j_inductive_fit + + + + + + + + +qty.iteration_Ips + + +iteration_Ips + + + + + +qty.iteration_Ips->qty.diagnostics + + + + + + + + +qty.iteration_l_is + + +iteration_l_is + + + + + +qty.iteration_l_is->qty.diagnostics + + + + + + + + +qty.j0_scales + + +j0_scales + + + + + +qty.j0_scales->qty.diagnostics + + + + + + + + +qty.jBS_diff->fn.run.generate + + + + + + + + +qty.jBS_diff->qty.baseline_j_BS_with_diff + + + + + + + + +qty.jBS_diff->qty.spike_profile + + + + + + + + +qty.jBS_scale_range_centered + + +jBS_scale_range (centered) + + + + + +qty.jBS_scale_range_centered->ext.generate_bouquet + + + + + + + + +qty.jBS_scales->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.j_BS->artifact.baseline + + + + + + + + +qty.j_BS->qty.j_inductive + + + + + + + + +qty.j_ind_final + + +j_ind_final + + + + + +qty.j_BS_final->qty.j_ind_final + + + + + + + + +qty.j_BS_isolated->fn.tmi._shelf_blend_decompose + + + + + + + + +qty.j_BS_isolated->fn.tmi.classify_jphi_profile + + + + + + + + +qty.j_BS_isolated->fn.tmi.fit_inductive_profile + + + + + + + + +qty.j_BS_isolated->qty.ffp_prof_li + + + + + + + + +qty.j_BS_isolated->qty.j_BS_shelved + + + + + + + + +qty.j_BS_isolated->qty.j_phi_corrective_target + + + + + + + +qty.j_BS_isolated->qty.j_phi_fit_prelim + + + + + + + + + +qty.j_BS_smoothed + + +j_BS smoothed transition + + + + + +qty.j_BS_shelved->qty.j_BS_smoothed + + + + + + + + +qty.j_BS_smoothed->qty.j_BS_isolated + + + + + + + + +qty.j_BS_src->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_BS_src->gate.jBS_baseline_mode + + + + + + + + +qty.j_BS_swb->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.j_BS_swb->gate.jBS_baseline_mode + + + + + + + + +qty.j_BS_swb->qty.baseline_j_BS_with_diff + + + + + + + + +qty.j_fixed_eff + + +j_fixed_eff (fixed additive currents) + + + + + +qty.j_NBI->qty.j_fixed_eff + + + + + + + + +qty.j_NBI_toroidal->artifact.baseline + + + + + + + + +qty.j_NBI_toroidal->qty.j_inductive + + + + + + + + +qty.j_RF->artifact.baseline + + + + + + + + +qty.j_RF->qty.j_fixed_eff + + + + + + + + +qty.j_RF->qty.j_inductive + + + + + + + + +qty.j_bootstrap_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_fixed_eff->qty.a_optimal + + + + + + + + +qty.j_fixed_eff->qty.j_inductive_consistent + + + + + + + + +qty.j_fixed_eff->qty.matched_jphi_perturb + + + + + + + + +qty.j_fixed_eff->qty.new_jphi + + + + + + + + +qty.j_fixed_eff->qty.target_jphi_perturb + + + + + + + + +qty.j_ind_li_matched->qty.j_phi_corrective_target + + + + + + + + +qty.j_inductive->artifact.baseline + + + + + + + + + +qty.j_inductive->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_inductive->fn.run.generate + + + + + + + + +qty.j_inductive_basis->qty.j_inductive_fit + + + + + + + + +qty.j_inductive_consistent->qty.diagnostics + + + + + + + + +qty.j_inductive_fit->qty.ffp_prof_li + + + + + + + + +qty.j_inductive_fit->qty.j_ind_li_matched + + + + + + + + +qty.j_inductive_fit->qty.j_phi_fit_prelim + + + + + + + + +qty.j_ls + + +j_ls (current length scale) + + + + + +qty.j_ls->qty.jphi_perturb + + + + + + + + +qty.j_nbi_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_phi->artifact.baseline + + + + + + + + +qty.j_phi->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_phi->fn.run.generate + + + + + + + + +qty.j_phi->qty.j_inductive + + + + + + + + +qty.j_phi->qty.jphi_diff + + + + + + + + +qty.j_phi->qty.sigma_jphi + + + + + + + + +qty.j_phi_corrective_target->ext.corrective_jphi_iteration + + + + + + + + +qty.j_phi_final + + +j_phi_final + + + + + +qty.j_phi_final->qty.j_ind_final + + + + + + + + +qty.j_phi_final->qty.quality_metrics + + + + + + + + +qty.j_phi_output_corr->qty.j_phi_final + + + + + + + + +qty.j_tor_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_tor_parallel->qty.j_phi + + + + + + + + +qty.j_total_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.jphi_diff->artifact.baseline + + + + + + + + +qty.jphi_diff->fn.run.generate + + + + + + + + +qty.jphi_diff->qty.j_fixed_eff + + + + + + + + +qty.jphi_mode->gate.jphi_classified + + + + + + + + +qty.jphi_mode->qty.quality_metrics + + + + + + + + + +qty.jphi_perturb->qty.a_optimal + + + + + + + + +qty.jphi_perturb->qty.matched_jphi_perturb + + + + + + + + +qty.l_i + + +l_i (equilibrium internal inductance) + + + + + +qty.l_i->art.eqdsk_bytes + + + + + + + + +qty.l_i->gate.li_acceptance + + + + + + + + +qty.l_i->qty.proxy_vs_real + + + + + + + + +qty.l_i_target_draw->gate.li_band + + + + + + + + +qty.li_current->gate.li_converged + + + + + + + + +qty.li_final->qty.quality_metrics + + + + + + + + +qty.li_proxy_baseline->fn.tmi.fit_inductive_profile + + + + + + + + +qty.li_target->artifact.baseline + + + + + + + + +qty.li_target->gate.li_converged + + + + + + + + +qty.li_target->fn.run.generate + + + + + + + +qty.matched_j_inductive->gate.li_loop_variant + + + + + + + + +qty.matched_jphi_perturb->fn.tmi.find_optimal_scale + + + + + + + + +qty.n_ls + + +n_ls (density length scale) + + + + + +qty.n_ls->gate.pressure_match + + + + + + + + +qty.n_ls->qty.ne_draw + + + + + + + + +qty.ne->fn.reconstruct_equilibrium + + + + + + + + +qty.ne->artifact.baseline + + + + + + + + +qty.ne->fn.imas._merge_ida_kinetics + + + + + + + + +qty.ne->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ne->gate.sigma_priority_ne + + + + + + + + +qty.ne->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ne->fn.run.generate + + + + + + + + +qty.ne->gate.pressure_match + + + + + + + + +qty.ne->qty.Z_imp + + + + + + + + +qty.ne->qty.ne_draw + + + + + + + + +qty.ne->qty.zeff + + + + + + + + +qty.ne_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ne_draw->qty.ni_draw + + + + + + + + +qty.ne_draw->qty.pres_tmp + + + + + + + +qty.ne_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ne_perturb->art.eqdsk_bytes + + + + + + + + +qty.ne_perturb->qty.p_thermal + + + + + + + + +qty.new_jphi->fn.tmi.recon_anchor_solve + + + + + + + + +qty.ni->fn.reconstruct_equilibrium + + + + + + + + + + +qty.ni->artifact.baseline + + + + + + + + +qty.ni->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ni->gate.sigma_priority_ni + + + + + + + + +qty.ni->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ni->fn.run.generate + + + + + + + + + +qty.ni->gate.pressure_match + + + + + + + + +qty.ni->qty.Z_imp + + + + + + + + + +qty.ni->qty.ni_draw + + + + + + + + +qty.p_imp + + +impurity pressure + + + + + +qty.ni->qty.p_imp + + + + + + + + +qty.ni_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ni_draw->qty.pres_tmp + + + + + + + + +qty.ni_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ni_perturb->art.eqdsk_bytes + + + + + + + + +qty.ni_perturb->qty.p_thermal + + + + + + + + +qty.output_jphi->fn.utils.store_equilibrium + + + + + + + + +qty.output_jphi->art.eqdsk_bytes + + + + + + + + +qty.output_jphi->gate.constrain_sawteeth_post + + + + + + + + +qty.output_jphi->qty.Ip + + + + + + + + +qty.output_jphi->qty.final_li_proxy + + + + + + + + +qty.output_jphi->qty.j_inductive_consistent + + + + + + + + +qty.output_jphi->qty.l_i + + + + + + + + +qty.p_diff->artifact.baseline + + + + + + + + +qty.p_diff->fn.run.generate + + + + + + + + +qty.p_diff->qty.pres_tmp + + + + + + + + +qty.p_equilibrium->artifact.baseline + + + + + + + + +qty.p_equilibrium->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_equilibrium->qty.p_diff + + + + + + + + +qty.p_fast->artifact.baseline + + + + + + + + +qty.p_fast->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_recon + + +reconstructed pressure + + + + + +qty.p_fast->qty.p_recon + + + + + + + + +qty.p_fast->qty.pres_tmp + + + + + + + + +qty.p_imp->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_imp->qty.p_recon + + + + + + + + +qty.p_recon->qty.p_diff + + + + + + + + +qty.p_thermal->fn.reconstruct_equilibrium + + + + + + + + +qty.p_thermal->qty.pres_tmp + + + + + + + + +qty.p_total + + +p_total + + + + + +qty.p_total->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.pprime + + +p' (pressure gradient) + + + + + +qty.pprime_gs + + +p' for GS + + + + + +qty.pprime->qty.pprime_gs + + + + + + + + +qty.pprime_gs->ext.corrective_jphi_iteration + + + + + + + + +qty.pprime_gs->ext.tokamaker_solve + + + + + + + + +qty.pres_tmp->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.pres_tmp->fn.tmi._corrective_jphi_iteration + + + + + + + +qty.pres_tmp->fn.tmi.find_optimal_scale + + + + + + + + + +qty.pres_tmp->fn.tmi.recon_anchor_solve + + + + + + + + +qty.pres_tmp->gate.recalculate_jBS + + + + + + + +qty.pressure->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.pressure->qty.pprime + + + + + + + + +qty.proxy_target->gate.li_band_loop + + + + + + + + +qty.proxy_vs_real->qty.proxy_target + + + + + + + + +qty.psi_N->fn.reconstruct_equilibrium + + + + + + + + +qty.psi_N->artifact.baseline + + + + + + + + +qty.psi_N->fn.imas._merge_ida_kinetics + + + + + + + + +qty.psi_N->fn.imas._override + + + + + + + + +qty.psi_N->fn.tmi.classify_jphi_profile + + + + + + + + +qty.psi_N->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.psi_N->qty.Zeff_eq + + + + + + + + +qty.psi_N_kinetic->artifact.baseline + + + + + + + + +qty.psi_N_kinetic->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.sigma_jphi->qty.jphi_perturb + + + + + + + + +qty.sigma_ne->gate.pressure_match + + + + + + + + +qty.sigma_ne->qty.ne_draw + + + + + + + + +qty.sigma_te->gate.pressure_match + + + + + + + + +qty.sigma_te->qty.te_draw + + + + + + + + +qty.sigma_ti->qty.ti_draw + + + + + + + + +qty.spike_metrics->qty.quality_metrics + + + + + + + +qty.spike_profile->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.spike_profile->qty.a_optimal + + + + + + + + +qty.spike_profile->qty.diagnostics + + + + + + + + + +qty.spike_profile->qty.j_inductive_consistent + + + + + + + + +qty.spike_profile->qty.matched_jphi_perturb + + + + + + + + +qty.spike_profile->qty.new_jphi + + + + + + + + +qty.spike_profile->qty.target_jphi_perturb + + + + + + + + +qty.t_ls + + +t_ls (temperature length scale) + + + + + +qty.t_ls->gate.pressure_match + + + + + + + + +qty.t_ls->qty.te_draw + + + + + + + + +qty.target_jphi_perturb->fn.tmi._corrective_jphi_iteration + + + + + + + + +qty.te->fn.reconstruct_equilibrium + + + + + + + + +qty.te->artifact.baseline + + + + + + + + +qty.te->fn.imas._validate_pressure_completeness + + + + + + + + +qty.te->gate.sigma_priority_te + + + + + + + + +qty.te->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.te->fn.run.generate + + + + + + + + +qty.te->gate.pressure_match + + + + + + + + +qty.te->qty.p_recon + + + + + + + + +qty.te->qty.te_draw + + + + + + + + +qty.te_draw->fn.utils.store_equilibrium + + + + + + + + +qty.te_draw->qty.pres_tmp + + + + + + + + + +qty.te_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.te_perturb->art.eqdsk_bytes + + + + + + + + +qty.te_perturb->qty.p_thermal + + + + + + + + +qty.ti->fn.reconstruct_equilibrium + + + + + + + + +qty.ti->artifact.baseline + + + + + + + + +qty.ti->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ti->gate.sigma_priority_ti + + + + + + + + +qty.ti->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ti->fn.run.generate + + + + + + + + +qty.ti->gate.pressure_match + + + + + + + + +qty.ti->qty.p_imp + + + + + + + + +qty.ti->qty.p_recon + + + + + + + + +qty.ti->qty.ti_draw + + + + + + + + +qty.ti_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ti_draw->qty.pres_tmp + + + + + + + + +qty.ti_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ti_perturb->art.eqdsk_bytes + + + + + + + + +qty.ti_perturb->qty.p_thermal + + + + + + + + +qty.zeff->artifact.baseline + + + + + + + + +qty.zeff->gate.sigma_priority_zeff + + + + + + + + +qty.zeff->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.zeff->qty.Z_imp + + + + + + + + +qty.zeff->qty.Zeff_eq + + + + + + + + +qty.zeff_draw->qty.ni_draw + + + + + + + + +qty.zeff_draw->qty.ni_perturb + + + + + + + + +quantity.eqdsk_j_tor + + +eqdsk_j_tor + + + + + +quantity.eqdsk_j_tor->fn.tmi.fit_inductive_profile + + + + + + + + + +
+
Generated by docs/flowchart/build.py from +docs/flowchart/graph.json. Edges/nodes are a descriptive snapshot +and may drift from the code; regenerate after refactors.
+ + + + diff --git a/docs/flowchart/l0_overview.svg b/docs/flowchart/l0_overview.svg new file mode 100644 index 0000000..c98a071 --- /dev/null +++ b/docs/flowchart/l0_overview.svg @@ -0,0 +1,384 @@ + + + + + + +bouquet_overview + + + + + + +Configuration + + +Configuration +(148 nodes) + + + + + +Input readers (g-file / p-file / IDA) + + +Input readers (g-file / p-file / IDA) +(16 nodes) + + + + + + +Configuration->Input readers (g-file / p-file / IDA) + + +4 + + + +IMAS/OMAS reader + + +IMAS/OMAS reader +(28 nodes) + + + + + +Configuration->IMAS/OMAS reader + + +1 + + + +Baseline & uncertainty resolution + + +Baseline & uncertainty resolution +(33 nodes) + + + + + +Configuration->Baseline & uncertainty resolution + + +5 + + + +Bouquet orchestrator / IMAS forward solve + + +Bouquet orchestrator / IMAS forward solve +(23 nodes) + + + + + +Configuration->Bouquet orchestrator / IMAS forward solve + + +6 + + + +Per-draw solve (SWB / l_i / homotopy) + + +Per-draw solve (SWB / l_i / homotopy) +(61 nodes) + + + + + +Configuration->Per-draw solve (SWB / l_i / homotopy) + + +4 + + + +Input readers (g-file / p-file / IDA)->Configuration + + +1 + + + + +Input readers (g-file / p-file / IDA)->IMAS/OMAS reader + + +1 + + + +Input readers (g-file / p-file / IDA)->Baseline & uncertainty resolution + + +1 + + + +Input readers (g-file / p-file / IDA)->Bouquet orchestrator / IMAS forward solve + + +10 + + + +Input readers (g-file / p-file / IDA)->Per-draw solve (SWB / l_i / homotopy) + + +7 + + + +IMAS/OMAS reader->Configuration + + +1 + + + +IMAS/OMAS reader->Input readers (g-file / p-file / IDA) + + +8 + + + + +IMAS/OMAS reader->Baseline & uncertainty resolution + + +5 + + + +GS reconstruction + + +GS reconstruction +(19 nodes) + + + + + +IMAS/OMAS reader->GS reconstruction + + +4 + + + +IMAS/OMAS reader->Bouquet orchestrator / IMAS forward solve + + +10 + + + +IMAS/OMAS reader->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Baseline & uncertainty resolution->Input readers (g-file / p-file / IDA) + + +1 + + + +Baseline & uncertainty resolution->IMAS/OMAS reader + + +14 + + + + +Baseline & uncertainty resolution->Bouquet orchestrator / IMAS forward solve + + +11 + + + +Baseline & uncertainty resolution->Per-draw solve (SWB / l_i / homotopy) + + +9 + + + + +GS reconstruction->Bouquet orchestrator / IMAS forward solve + + +4 + + + +GS reconstruction->Per-draw solve (SWB / l_i / homotopy) + + +1 + + + +Bouquet orchestrator / IMAS forward solve->Input readers (g-file / p-file / IDA) + + +8 + + + +Bouquet orchestrator / IMAS forward solve->IMAS/OMAS reader + + +11 + + + +Bouquet orchestrator / IMAS forward solve->Baseline & uncertainty resolution + + +5 + + + +Bouquet orchestrator / IMAS forward solve->GS reconstruction + + +6 + + + +Draw loop (GPR sampling) + + +Draw loop (GPR sampling) +(19 nodes) + + + + + + +Bouquet orchestrator / IMAS forward solve->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Archive, filtering & plotting + + +Archive, filtering & plotting +(41 nodes) + + + + + +Bouquet orchestrator / IMAS forward solve->Archive, filtering & plotting + + +6 + + + +Draw loop (GPR sampling)->Bouquet orchestrator / IMAS forward solve + + +1 + + + + +Draw loop (GPR sampling)->Per-draw solve (SWB / l_i / homotopy) + + +5 + + + +Draw loop (GPR sampling)->Archive, filtering & plotting + + +11 + + + +Per-draw solve (SWB / l_i / homotopy)->Bouquet orchestrator / IMAS forward solve + + +4 + + + +Per-draw solve (SWB / l_i / homotopy)->Draw loop (GPR sampling) + + +1 + + + + +Archive, filtering & plotting->Bouquet orchestrator / IMAS forward solve + + +2 + + + +Archive, filtering & plotting->Draw loop (GPR sampling) + + +3 + + + +Process-parallel path + + +Process-parallel path +(31 nodes) + + + + + + +Process-parallel path->Bouquet orchestrator / IMAS forward solve + + +1 + + + +Process-parallel path->Archive, filtering & plotting + + +2 + + + diff --git a/docs/flowchart/l1_full.svg b/docs/flowchart/l1_full.svg new file mode 100644 index 0000000..965ed72 --- /dev/null +++ b/docs/flowchart/l1_full.svg @@ -0,0 +1,12201 @@ + + + + + + +bouquet + + + + + +cluster_0 + + +Configuration + + + + +cluster_1 + + +Input readers (g-file / p-file / IDA) + + + + +cluster_2 + + +IMAS/OMAS reader + + + + +cluster_3 + + +Baseline & uncertainty resolution + + + + +cluster_4 + + +GS reconstruction + + + + +cluster_5 + + +Bouquet orchestrator / IMAS forward solve + + + + +cluster_6 + + +Draw loop (GPR sampling) + + + + +cluster_7 + + +Per-draw solve (SWB / l_i / homotopy) + + + + +cluster_8 + + +Archive, filtering & plotting + + + + +cluster_9 + + +Process-parallel path + + + + + +cfg.filterconfig.inspec_F_max + + + + +inspec_F_max: float = 0.02 + + + + + +fn.filtering.if abs + + +if abs + + + + + +cfg.filterconfig.inspec_F_max->fn.filtering.if abs + + + + + + + + +cfg.filterconfig.inspec_VSC_max + + + + +inspec_VSC_max: float = 0.02 + + + + + +cfg.filterconfig.inspec_VSC_max->fn.filtering.if abs + + + + + + + + +cfg.filterconfig.rms_max_mm + + + + +rms_max_mm: float = 5.0 + + + + + +fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject + + +if rms_error_mm > config.filtering.rms_max_mm: reject + + + + + +cfg.filterconfig.rms_max_mm->fn.filtering.if rms_error_mm > config.filtering.rms_max_mm: reject + + + + + + + + +cfg.fixedcomponentsconfig.j_NBI + + + + +j_NBI: Optional[np.ndarray] = None + + + + + +fn.run.fc.j_NBI or zeros_on_psi_N + + +fc.j_NBI or zeros_on_psi_N + + + + + +cfg.fixedcomponentsconfig.j_NBI->fn.run.fc.j_NBI or zeros_on_psi_N + + + + + + + + +cfg.fixedcomponentsconfig.j_RF + + + + +j_RF: Optional[np.ndarray] = None + + + + + +fn.run.fc.j_RF or zeros_on_psi_N + + +fc.j_RF or zeros_on_psi_N + + + + + +cfg.fixedcomponentsconfig.j_RF->fn.run.fc.j_RF or zeros_on_psi_N + + + + + + + + +cfg.fixedcomponentsconfig.p_fast + + + + +p_fast: Optional[np.ndarray] = None + + + + + +fn.run.fc.p_fast or compute_p_fast_from_source + + +fc.p_fast or compute_p_fast_from_source + + + + + +cfg.fixedcomponentsconfig.p_fast->fn.run.fc.p_fast or compute_p_fast_from_source + + + + + + + + +cfg.fixedcomponentsconfig.p_fast_reduction + + + + +p_fast_reduction: str = "trace" + + + + + +fn.physics.isotropize_fast_pressure + + +isotropize_fast_pressure + + + + + +cfg.fixedcomponentsconfig.p_fast_reduction->fn.physics.isotropize_fast_pressure + + + + + + + + +cfg.fixedcomponentsconfig.psi_N + + + + +psi_N: Optional[np.ndarray] = None + + + + + +fn.run.fc.psi_N or source_psi_N + + +fc.psi_N or source_psi_N + + + + + +cfg.fixedcomponentsconfig.psi_N->fn.run.fc.psi_N or source_psi_N + + + + + + + + +cfg.generationconfig.accept_anchor_inband + + + + +accept_anchor_inband: bool = False + + + + + +fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band + + +if gc.accept_anchor_inband and in_band + + + + + +cfg.generationconfig.accept_anchor_inband->fn.TokaMaker_interface.if gc.accept_anchor_inband and in_band + + + + + + + + +cfg.generationconfig.allow_incomplete_pressure + + + + +allow_incomplete_pressure: bool = False + + + + + +fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check + + +if config.generation.allow_incomplete_pressure: skip_pressure_check + + + + + +cfg.generationconfig.allow_incomplete_pressure->fn.io.imas.if config.generation.allow_incomplete_pressure: skip_pressure_check + + + + + + + + +cfg.generationconfig.allow_unsafe_workflow + + + + +allow_unsafe_workflow: bool = False + + + + + +fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow + + +if not config.generation.allow_unsafe_workflow: validate_workflow + + + + + +cfg.generationconfig.allow_unsafe_workflow->fn.run.if not config.generation.allow_unsafe_workflow: validate_workflow + + + + + + + + +cfg.generationconfig.anchor_jtor_to_equilibrium + + + + +anchor_jtor_to_equilibrium: bool = True + + + + + +fn.run.eq.j_tor - cp.j_tor + + +eq.j_tor - cp.j_tor + + + + + +cfg.generationconfig.anchor_jtor_to_equilibrium->fn.run.eq.j_tor - cp.j_tor + + + + + + + + +cfg.generationconfig.anchor_pressure_to_equilibrium + + + + +anchor_pressure_to_equilibrium: bool = False + + + + + +fn.run.eq.pressure - p_recon + + +eq.pressure - p_recon + + + + + +cfg.generationconfig.anchor_pressure_to_equilibrium->fn.run.eq.pressure - p_recon + + + + + + + + +cfg.generationconfig.coil_drift + + + + +coil_drift: float = 0.01 + + + + + +fn.TokaMaker_interface.config.generation.coil_drift + + +config.generation.coil_drift + + + + + +cfg.generationconfig.coil_drift->fn.TokaMaker_interface.config.generation.coil_drift + + + + + + + + +cfg.generationconfig.coil_drift_hard_factor + + + + +coil_drift_hard_factor: Optional[float] = None + + + + + +fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None + + +coil_drift * config.generation.coil_drift_hard_factor if ... else None + + + + + +cfg.generationconfig.coil_drift_hard_factor->fn.TokaMaker_interface.coil_drift * config.generation.coil_drift_hard_factor if ... else None + + + + + + + + +cfg.generationconfig.constrain_sawteeth + + + + +constrain_sawteeth: bool = False + + + + + +fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject + + +if gc.constrain_sawteeth and q0 < 1.0: reject + + + + + +cfg.generationconfig.constrain_sawteeth->fn.TokaMaker_interface.if gc.constrain_sawteeth and q0 < 1.0: reject + + + + + + + + +cfg.generationconfig.diagnostic_plots + + + + +diagnostic_plots: bool = False + + + + + +fn.run.if config.generation.diagnostic_plots: plot_diagnostics + + +if config.generation.diagnostic_plots: plot_diagnostics + + + + + +cfg.generationconfig.diagnostic_plots->fn.run.if config.generation.diagnostic_plots: plot_diagnostics + + + + + + + + +cfg.generationconfig.floor_j_BS + + + + +floor_j_BS: bool = False + + + + + +fn.run.np.maximum + + +np.maximum + + + + + +cfg.generationconfig.floor_j_BS->fn.run.np.maximum + + + + + + + + +cfg.generationconfig.homotopy_passes + + + + +homotopy_passes: list = [(0.05,0.10),(0.02,0.05),(0.01,0.01)] + + + + + +fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + +for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + + + + +cfg.generationconfig.homotopy_passes->fn.TokaMaker_interface.for F_tol, VSC_tol in config.generation.homotopy_passes: ... + + + + + + + + +cfg.generationconfig.isolate_edge_jBS + + + + +isolate_edge_jBS: bool = True + + + + + +fn.run.isolate_edge_jBS + + +isolate_edge_jBS + + + + + +cfg.generationconfig.isolate_edge_jBS->fn.run.isolate_edge_jBS + + + + + + + + +cfg.generationconfig.jBS_baseline_mode + + + + +jBS_baseline_mode: str = "diff" + + + + + +fn.run.... + + +... + + + + + +cfg.generationconfig.jBS_baseline_mode->fn.run.... + + + + + + + + +cfg.generationconfig.jBS_scale_range + + + + +jBS_scale_range: tuple = (0.99, 1.01) + + + + + +fn.TokaMaker_interface.np.random.uniform + + +np.random.uniform + + + + + +cfg.generationconfig.jBS_scale_range->fn.TokaMaker_interface.np.random.uniform + + + + + + + + +cfg.generationconfig.kinetic_source + + + + +kinetic_source: str = "fuse" + + + + + +fn.run."ida_hybrid": resample_ida_profiles + + +"ida_hybrid": resample_ida_profiles + + + + + +cfg.generationconfig.kinetic_source->fn.run."ida_hybrid": resample_ida_profiles + + + + + + + + +cfg.generationconfig.l_i_tolerance + + + + +l_i_tolerance: float = 0.05 + + + + + +fn.TokaMaker_interface.if not abs + + +if not abs + + + + + +cfg.generationconfig.l_i_tolerance->fn.TokaMaker_interface.if not abs + + + + + + + + +cfg.generationconfig.n_equils + + + + +n_equils: int = 20 + + + + + +fn.TokaMaker_interface.for i_eq in _tqdm + + +for i_eq in _tqdm + + + + + +cfg.generationconfig.n_equils->fn.TokaMaker_interface.for i_eq in _tqdm + + + + + + + + +fn.run.int + + +int + + + + + +cfg.generationconfig.n_equils->fn.run.int + + + + + + + + +cfg.generationconfig.perturb_jind_in_anchor + + + + +perturb_jind_in_anchor: bool = False + + + + + +fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + +if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + + + + +cfg.generationconfig.perturb_jind_in_anchor->fn.run.if config.generation.perturb_jind_in_anchor: apply_gpr_to_anchor_j_ind + + + + + + + + +cfg.generationconfig.recalculate_j_BS + + + + +recalculate_j_BS: bool = True + + + + + +fn.run.compute_via_swb + + +compute_via_swb + + + + + +cfg.generationconfig.recalculate_j_BS->fn.run.compute_via_swb + + + + + + + + +cfg.generationconfig.scan_key + + + + +scan_key: float = 0 + + + + + +fn.run.store_equilibrium + + +store_equilibrium + + + + + +cfg.generationconfig.scan_key->fn.run.store_equilibrium + + + + + + + + +cfg.generationconfig.seed + + + + +seed: Optional[int] = None + + + + + +fn.TokaMaker_interface.np.random.seed + + +np.random.seed + + + + + +cfg.generationconfig.seed->fn.TokaMaker_interface.np.random.seed + + + + + + + + +cfg.generationconfig.swb_iterations + + + + +swb_iterations: int = 3 + + + + + +fn.TokaMaker_interface.solve_with_bootstrap + + +solve_with_bootstrap + + + + + +cfg.generationconfig.swb_iterations->fn.TokaMaker_interface.solve_with_bootstrap + + + + + + + + +cfg.generationconfig.workflow + + + + +workflow: str = "auto" + + + + + +fn.run.resolve_workflow_from_preset + + +resolve_workflow_from_preset + + + + + +cfg.generationconfig.workflow->fn.run.resolve_workflow_from_preset + + + + + + + + +cfg.imassource.efit01_geqdsk + + + + +efit01_geqdsk: Optional[str] = None + + + + + +fn.run.read_geqdsk + + +read_geqdsk + + + + + +cfg.imassource.efit01_geqdsk->fn.run.read_geqdsk + + + + + + + + +cfg.imassource.ida_path + + + + +ida_path: Optional[str] = None + + + + + +fn.run.ida_path + + +ida_path + + + + + +cfg.imassource.ida_path->fn.run.ida_path + + + + + + + + +cfg.imassource.ids_path + + + + +ids_path: str = None + + + + + +fn.io.imas.read_imas + + +read_imas + + + + + +cfg.imassource.ids_path->fn.io.imas.read_imas + + + + + + + + +cfg.imassource.impurity_Z + + + + +impurity_Z: float = 6.0 + + + + + +fn.io.imas.profiles.compute_ni + + +profiles.compute_ni + + + + + +cfg.imassource.impurity_Z->fn.io.imas.profiles.compute_ni + + + + + + + + +cfg.imassource.time + + + + +time: Optional[float] = None + + + + + +cfg.imassource.time->fn.io.imas.read_imas + + + + + + + + +cfg.reconstructionsource.cocos + + + + +cocos: int = 1 + + + + + +fn.baseline.read_geqdsk + + +read_geqdsk + + + + + +cfg.reconstructionsource.cocos->fn.baseline.read_geqdsk + + + + + + + + +cfg.reconstructionsource.geqdsk_path + + + + +geqdsk_path: str = None + + + + + +cfg.reconstructionsource.geqdsk_path->fn.baseline.read_geqdsk + + + + + + + + +cfg.reconstructionsource.geqdsk_path->fn.run.read_geqdsk + + + + + + + + +cfg.reconstructionsource.impurity_Z + + + + +impurity_Z: float = 6.0 + + + + + +fn.baseline.profiles.compute_ni + + +profiles.compute_ni + + + + + +cfg.reconstructionsource.impurity_Z->fn.baseline.profiles.compute_ni + + + + + + + + +cfg.reconstructionsource.n_k + + + + +n_k: int = 5 + + + + + +fn.baseline.spline_fit + + +spline_fit + + + + + +cfg.reconstructionsource.n_k->fn.baseline.spline_fit + + + + + + + + +cfg.reconstructionsource.profile_overrides + + + + +profile_overrides: dict = {} + + + + + +fn.baseline.... + + +... + + + + + +cfg.reconstructionsource.profile_overrides->fn.baseline.... + + + + + + + + +cfg.reconstructionsource.profiles_path + + + + +profiles_path: str = None + + + + + +fn.baseline.read_profiles + + +read_profiles + + + + + +cfg.reconstructionsource.profiles_path->fn.baseline.read_profiles + + + + + + + + +cfg.reconstructionsource.psi_bridge + + + + +psi_bridge: float = 0.99 + + + + + +fn.baseline.hermite_edge_bridge + + +hermite_edge_bridge + + + + + +cfg.reconstructionsource.psi_bridge->fn.baseline.hermite_edge_bridge + + + + + + + + +cfg.reconstructionsource.psi_pad + + + + +psi_pad: float = 1e-3 + + + + + +fn.baseline.compute_psi_bounds + + +compute_psi_bounds + + + + + +cfg.reconstructionsource.psi_pad->fn.baseline.compute_psi_bounds + + + + + + + + +cfg.reconstructionsource.rescale_j_BS + + + + +rescale_j_BS: bool = False + + + + + +fn.baseline.scaling_factor + + +scaling_factor + + + + + +cfg.reconstructionsource.rescale_j_BS->fn.baseline.scaling_factor + + + + + + + + +cfg.reconstructionsource.shelf_psi_N + + + + +shelf_psi_N: float = 0.0 + + + + + +fn.baseline.source.shelf_psi_N + + +source.shelf_psi_N + + + + + +cfg.reconstructionsource.shelf_psi_N->fn.baseline.source.shelf_psi_N + + + + + + + + +cfg.reconstructionsource.time + + + + +time: Optional[float] = None + + + + + +fn.io.ida.read_ida + + +read_ida + + + + + +cfg.reconstructionsource.time->fn.io.ida.read_ida + + + + + + + + +cfg.solverconfig.F0 + + + + +F0: Optional[float] = None + + + + + +fn.run.F0 or eqdsk.F0_ref or ... + + +F0 or eqdsk.F0_ref or ... + + + + + +cfg.solverconfig.F0->fn.run.F0 or eqdsk.F0_ref or ... + + + + + + + + +cfg.solverconfig.coil_reg + + + + +coil_reg: list = [] + + + + + +cfg.solverconfig.coil_vsc + + + + +coil_vsc: dict = {"F9A": 1.0, "F9B": -1.0} + + + + + +fn.run.coil_vsc dict unpacked into solve_with_bootstrap + + +coil_vsc dict unpacked into solve_with_bootstrap + + + + + +cfg.solverconfig.coil_vsc->fn.run.coil_vsc dict unpacked into solve_with_bootstrap + + + + + + + + +cfg.solverconfig.isoflux_pts + + + + +isoflux_pts: Optional[np.ndarray] = None + + + + + +fn.run.isoflux_pts or eqdsk.isoflux_pts + + +isoflux_pts or eqdsk.isoflux_pts + + + + + +cfg.solverconfig.isoflux_pts->fn.run.isoflux_pts or eqdsk.isoflux_pts + + + + + + + + +cfg.solverconfig.isoflux_weights + + + + +isoflux_weights: Optional[np.ndarray] = None + + + + + +fn.run.isoflux_weights or np.ones + + +isoflux_weights or np.ones + + + + + +cfg.solverconfig.isoflux_weights->fn.run.isoflux_weights or np.ones + + + + + + + + +cfg.solverconfig.mesh_path + + + + +mesh_path: str = None + + + + + +fn.run.load_gs_mesh + + +load_gs_mesh + + + + + +cfg.solverconfig.mesh_path->fn.run.load_gs_mesh + + + + + + + + +cfg.solverconfig.nthreads + + + + +nthreads: int = 1 + + + + + +fn.TokaMaker_interface.mygs.solve + + +mygs.solve + + + + + +cfg.solverconfig.nthreads->fn.TokaMaker_interface.mygs.solve + + + + + + + + +cfg.solverconfig.nthreads->fn.run.load_gs_mesh + + + + + + + + +cfg.solverconfig.order + + + + +order: int = 3 + + + + + +fn.run.GsHandle + + +GsHandle + + + + + +cfg.solverconfig.order->fn.run.GsHandle + + + + + + + + +cfg.solverconfig.region_overrides + + + + +region_overrides: Optional[dict] = None + + + + + +cfg.source.efit01_geqdsk + + + + +efit01_geqdsk + + + + + +fn.imas.read_imas_geometry + + +read_imas_geometry() + + + + + +cfg.source.efit01_geqdsk->fn.imas.read_imas_geometry + + + + + + + + +cfg.uncertaintyconfig.aux_baselines + + + + +aux_baselines: dict = {} + + + + + +fn.TokaMaker_interface.config.uncertainty.aux_baselines.get + + +config.uncertainty.aux_baselines.get + + + + + +cfg.uncertaintyconfig.aux_baselines->fn.TokaMaker_interface.config.uncertainty.aux_baselines.get + + + + + + + + +cfg.uncertaintyconfig.aux_length_scales + + + + +aux_length_scales: dict = {} + + + + + +fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get + + +config.uncertainty.aux_length_scales.get + + + + + +cfg.uncertaintyconfig.aux_length_scales->fn.TokaMaker_interface.config.uncertainty.aux_length_scales.get + + + + + + + + +cfg.uncertaintyconfig.aux_sigmas + + + + +aux_sigmas: dict = {} + + + + + +fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items + + +for name, sigma in config.uncertainty.aux_sigmas.items + + + + + +cfg.uncertaintyconfig.aux_sigmas->fn.TokaMaker_interface.for name, sigma in config.uncertainty.aux_sigmas.items + + + + + + + + +cfg.uncertaintyconfig.ida_path + + + + +ida_path: Optional[str] = None + + + + + +fn.baseline.unc.ida_path or source.profiles_path + + +unc.ida_path or source.profiles_path + + + + + +cfg.uncertaintyconfig.ida_path->fn.baseline.unc.ida_path or source.profiles_path + + + + + + + + +cfg.uncertaintyconfig.j_ls + + + + +j_ls: float = 0.25 + + + + + +fn.TokaMaker_interface.GPRPerturber + + +GPRPerturber + + + + + +cfg.uncertaintyconfig.j_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.jphi_scalar_sigma + + + + +jphi_scalar_sigma: float = 0.1 + + + + + +fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs + + +config.uncertainty.jphi_scalar_sigma * abs + + + + + +cfg.uncertaintyconfig.jphi_scalar_sigma->fn.TokaMaker_interface.config.uncertainty.jphi_scalar_sigma * abs + + + + + + + + +cfg.uncertaintyconfig.n_ls + + + + +n_ls: float = 0.5 + + + + + +cfg.uncertaintyconfig.n_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.ne_scalar_sigma + + + + +ne_scalar_sigma: float = 0.05 + + + + + +fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline + + +sigma_ne or unc.ne_scalar_sigma * ne_baseline + + + + + +cfg.uncertaintyconfig.ne_scalar_sigma->fn.baseline.sigma_ne or unc.ne_scalar_sigma * ne_baseline + + + + + + + + +cfg.uncertaintyconfig.ni_scalar_sigma + + + + +ni_scalar_sigma: float = 0.1 + + + + + +fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline + + +sigma_ni or unc.ni_scalar_sigma * ni_baseline + + + + + +cfg.uncertaintyconfig.ni_scalar_sigma->fn.baseline.sigma_ni or unc.ni_scalar_sigma * ni_baseline + + + + + + + + +cfg.uncertaintyconfig.sigma_method + + + + +sigma_method: str = "percentile" + + + + + +fn.baseline.percentile_or_std + + +percentile_or_std + + + + + +cfg.uncertaintyconfig.sigma_method->fn.baseline.percentile_or_std + + + + + + + + +cfg.uncertaintyconfig.sigma_mode + + + + +sigma_mode: str = "auto" + + + + + +fn.baseline.resolve_ida_sigmas + + +resolve_ida_sigmas + + + + + +cfg.uncertaintyconfig.sigma_mode->fn.baseline.resolve_ida_sigmas + + + + + + + + +cfg.uncertaintyconfig.sigma_ni_from_ne + + + + +sigma_ni_from_ne: bool = True + + + + + +fn.baseline.sigma_ne + + +sigma_ne + + + + + +cfg.uncertaintyconfig.sigma_ni_from_ne->fn.baseline.sigma_ne + + + + + + + + +cfg.uncertaintyconfig.sigma_profiles + + + + +sigma_profiles: dict = {} + + + + + +fn.baseline.unc.sigma_profiles.get + + +unc.sigma_profiles.get + + + + + +cfg.uncertaintyconfig.sigma_profiles->fn.baseline.unc.sigma_profiles.get + + + + + + + + +cfg.uncertaintyconfig.t_ls + + + + +t_ls: float = 0.4 + + + + + +cfg.uncertaintyconfig.t_ls->fn.TokaMaker_interface.GPRPerturber + + + + + + + + +cfg.uncertaintyconfig.te_scalar_sigma + + + + +te_scalar_sigma: float = 0.05 + + + + + +fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline + + +sigma_te or unc.te_scalar_sigma * te_baseline + + + + + +cfg.uncertaintyconfig.te_scalar_sigma->fn.baseline.sigma_te or unc.te_scalar_sigma * te_baseline + + + + + + + + +cfg.uncertaintyconfig.ti_scalar_sigma + + + + +ti_scalar_sigma: float = 0.1 + + + + + +fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline + + +sigma_ti or unc.ti_scalar_sigma * ti_baseline + + + + + +cfg.uncertaintyconfig.ti_scalar_sigma->fn.baseline.sigma_ti or unc.ti_scalar_sigma * ti_baseline + + + + + + + + +cfg.uncertaintyconfig.zeff_scalar_sigma + + + + +zeff_scalar_sigma: float = 0.05 + + + + + +fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff + + +if unc.zeff_scalar_sigma > 0: perturb_zeff + + + + + +cfg.uncertaintyconfig.zeff_scalar_sigma->fn.TokaMaker_interface.if unc.zeff_scalar_sigma > 0: perturb_zeff + + + + + + + + +cls.FilterConfig + + +FilterConfig + + + + + +cls.FixedComponentsConfig + + +FixedComponentsConfig + + + + + +cls.GenerationConfig + + +GenerationConfig + + + + + +cls.ImasSource + + +ImasSource + + + + + +cls.ReconstructionSource + + +ReconstructionSource + + + + + +cls.SolverConfig + + +SolverConfig + + + + + +cls.UncertaintyConfig + + +UncertaintyConfig + + + + + +qty.ne + + +ne (electron density) + + + + + +fn.io.ida.read_ida->qty.ne + + + + + + + + +qty.ni + + +ni (main-ion density) + + + + + +fn.io.ida.read_ida->qty.ni + + + + + + + + +qty.psi_N_kinetic + + +psi_N_kinetic (kinetic grid) + + + + + +fn.io.ida.read_ida->qty.psi_N_kinetic + + + + + + + + + +qty.te + + +te (electron temperature) + + + + + +fn.io.ida.read_ida->qty.te + + + + + + + + +qty.ti + + +ti (ion temperature) + + + + + +fn.io.ida.read_ida->qty.ti + + + + + + + + +qty.zeff + + +Zeff (effective charge) + + + + + +fn.io.ida.read_ida->qty.zeff + + + + + + + + +qty.p_fast + + +p_fast (fast-ion pressure) + + + + + +fn.physics.isotropize_fast_pressure->qty.p_fast + + + + + + + + +fn.read_geqdsk + + +read_geqdsk() + + + + + +obj.GEQDSKEquilibrium + + + +GEQDSKEquilibrium object + + + + + +fn.read_geqdsk->obj.GEQDSKEquilibrium + + + + + + + + +fn.read_ida + + +read_ida() + + + + + +gate.ida_layout + + +IDA layout (direct vs ensemble)? + + + + + +fn.read_ida->gate.ida_layout + + + + + + + + +fn.read_ida_cer + + +read_ida_cer() + + + + + +obj.IDACERProfiles + + + +IDACERProfiles dataclass + + + + + +fn.read_ida_cer->obj.IDACERProfiles + + + + + + + + +fn.read_pfile + + +read_pfile() + + + + + +obj.PFile + + + +PFile object + + + + + +fn.read_pfile->obj.PFile + + + + + + + + +fn.reconstruct_equilibrium + + +reconstruct_equilibrium() [geqdsk.py] + + + + + +obj.IDAProfiles + + + +IDAProfiles dataclass + + + + + +gate.ida_layout->obj.IDAProfiles + + + + + + + + +gate.profile_file_type + + +Profile file type? + + + + + +gate.profile_file_type->fn.io.ida.read_ida + + + + + + + + +gate.profile_file_type->fn.read_ida + + + + + + + + +gate.profile_file_type->fn.read_pfile + + + + + + + + +fn.io.pfile.read_pfile + + +read_pfile(path) + compute_quasineutrality/compute_zeff + + + + + +gate.profile_file_type->fn.io.pfile.read_pfile + + + + + + + + +gate.time_index + + +Select time slice + + + + + +gate.time_index->fn.read_ida + + + + + + + + +input.gfile + + +G-file (GEQDSK) + + + + + +input.gfile->fn.read_geqdsk + + + + + + + + +input.ida_cdf + + +IDA .cdf (netCDF/HDF5) + + + + + +input.ida_cdf->gate.time_index + + + + + + + + +fn.imas._merge_ida_kinetics + + +_merge_ida_kinetics() [IDA-hybrid only] + + + + + +input.ida_cdf->fn.imas._merge_ida_kinetics + + + + + + + + +input.ida_cer + + +IDA CER channels (carbon) + + + + + +input.ida_cer->fn.read_ida_cer + + + + + + + + +input.pfile + + +P-file (Osborne profiles) + + + + + +input.pfile->fn.read_pfile + + + + + + + + +qty.F0 + + +F0 (R*Bt poloidal function) + + + + + +obj.GEQDSKEquilibrium->qty.F0 + + + + + + + + +qty.Ip_target + + +Ip_target (plasma current) + + + + + +obj.GEQDSKEquilibrium->qty.Ip_target + + + + + + + + +qty.boundary_lcfs + + +boundary_lcfs (separatrix contour) + + + + + +obj.GEQDSKEquilibrium->qty.boundary_lcfs + + + + + + + +qty.j_phi + + +j_phi (toroidal current density) + + + + + +obj.GEQDSKEquilibrium->qty.j_phi + + + + + + + + +qty.li_target + + +li_target (internal inductance) + + + + + +obj.GEQDSKEquilibrium->qty.li_target + + + + + + + + + +qty.p_thermal + + +p_thermal (thermal pressure) + + + + + +obj.GEQDSKEquilibrium->qty.p_thermal + + + + + + + + +qty.psi_N + + +psi_N (normalized flux) + + + + + +obj.GEQDSKEquilibrium->qty.psi_N + + + + + + + + +qty.e_r_cer + + +E_r (radial electric field) + + + + + +obj.IDACERProfiles->qty.e_r_cer + + + + + + + + +obj.IDAProfiles->qty.ne + + + + + + + + +obj.IDAProfiles->qty.ni + + + + + + + + +obj.IDAProfiles->qty.psi_N_kinetic + + + + + + + + +qty.sigma_ne + + +sigma_ne (density uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ne + + + + + + + + +qty.sigma_ni + + +sigma_ni (ion density uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ni + + + + + + + + +qty.sigma_te + + +sigma_te (temperature uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_te + + + + + + + + +qty.sigma_ti + + +sigma_ti (temperature uncertainty) + + + + + +obj.IDAProfiles->qty.sigma_ti + + + + + + + + +obj.IDAProfiles->qty.te + + + + + + + + +obj.IDAProfiles->qty.ti + + + + + + + + +obj.IDAProfiles->qty.zeff + + + + + + + + +obj.PFile->qty.ne + + + + + + + + +obj.PFile->qty.ni + + + + + + + + +qty.omega_tor + + +omega_tor (toroidal rotation) + + + + + +obj.PFile->qty.omega_tor + + + + + + + + +obj.PFile->qty.te + + + + + + + + +obj.PFile->qty.ti + + + + + + + + +artifact.baseline + + + +Baseline (output) + + + + + +artifact.imas_draw_json + + + +Perturbed draw JSON + + + + + +artifact.baseline->artifact.imas_draw_json + + + + + + + + +fn.imas.read_imas_baseline + + +read_imas_baseline() + + + + + +artifact.baseline->fn.imas.read_imas_baseline + + + + + + + + +artifact.geometry + + + +Geometry tuple (output) + + + + + +cfg.fixed.j_NBI + + + + +user override: j_NBI + + + + + +fn.imas._override + + +_override() + + + + + +cfg.fixed.j_NBI->fn.imas._override + + + + + + + + +cfg.fixed.j_RF + + + + +user override: j_RF + + + + + +cfg.fixed.j_RF->fn.imas._override + + + + + + + + +cfg.fixed.p_fast + + + + +user override: p_fast + + + + + +cfg.fixed.p_fast->fn.imas._override + + + + + + + + +cfg.generation.allow_incomplete_pressure + + + + +allow incomplete pressure validation + + + + + +fn.imas._validate_pressure_completeness + + +_validate_pressure_completeness() + + + + + +cfg.generation.allow_incomplete_pressure->fn.imas._validate_pressure_completeness + + + + + + + + +cfg.generation.anchor_jtor_to_equilibrium + + + + +j_tor anchor to equilibrium + + + + + +cfg.generation.anchor_pressure_to_equilibrium + + + + +pressure anchor to equilibrium + + + + + +cfg.generation.kinetic_source + + + + +kinetic profile source + + + + + +cfg.generation.p_fast_reduction + + + + +p_fast isotropization method + + + + + +cfg.generation.p_fast_reduction->fn.physics.isotropize_fast_pressure + + + + + + + + +fn.ida.read_ida + + +read_ida() [IDA-hybrid only] + + + + + +fn.imas._merge_ida_kinetics->qty.ne + + + + + + + + +fn.imas._merge_ida_kinetics->qty.omega_tor + + + + + + + + +fn.imas._merge_ida_kinetics->qty.te + + + + + + + + +fn.imas._merge_ida_kinetics->qty.ti + + + + + + + + +qty.j_NBI_toroidal + + +j_NBI (toroidal) + + + + + +fn.imas._override->qty.j_NBI_toroidal + + + + + + + + +qty.j_RF + + +j_RF (RF-driven current) + + + + + +fn.imas._override->qty.j_RF + + + + + + + + +fn.imas._override->qty.p_fast + + + + + + + + +fn.imas.read_imas_geometry->artifact.geometry + + + + + + + + +fn.imas.read_imas_geometry->qty.F0 + + + + + + + + +fn.imas.read_imas_geometry->qty.boundary_lcfs + + + + + + + + + +fn.physics.effective_impurity_charge + + +effective_impurity_charge() + + + + + +fn.physics.impurity_pressure + + +impurity_pressure() + + + + + +fn.physics.main_ion_density_from_zeff + + +main_ion_density_from_zeff() + + + + + +fn.physics.parallel_to_toroidal + + +parallel_to_toroidal() + + + + + +qty.j_BS + + +j_BS (bootstrap current) + + + + + +fn.physics.parallel_to_toroidal->qty.j_BS + + + + + + + + +qty.j_BS_isolated + + +j_BS_isolated (toroidal) + + + + + +fn.physics.parallel_to_toroidal->qty.j_BS_isolated + + + + + + + + +fn.physics.parallel_to_toroidal->qty.j_NBI_toroidal + + + + + + + + +gate.anchor_jtor + + +j_tor anchor decision + + + + + +qty.jphi_diff + + +j_phi anchor offset + + + + + +gate.anchor_jtor->qty.jphi_diff + + + + + + + + +gate.anchor_pressure + + +Pressure anchor decision + + + + + +qty.p_diff + + +pressure anchor offset + + + + + +gate.anchor_pressure->qty.p_diff + + + + + + + + +gate.fixed_components + + +Fixed component overrides + + + + + +gate.fixed_components->fn.imas._override + + + + + + + + +gate.incomplete_pressure + + +Pressure completeness check + + + + + +gate.incomplete_pressure->fn.imas._validate_pressure_completeness + + + + + + + + +gate.kinetic_source + + +Kinetic source selection + + + + + +gate.kinetic_source->fn.imas._merge_ida_kinetics + + + + + + + + +input.efit01_gfile + + +EFIT01 g-file (optional) + + + + + +input.efit01_gfile->fn.imas.read_imas_geometry + + + + + + + + +input.imas_ids + + +IMAS IDS (dd_sim.json) + + + + + +input.imas_ids->fn.imas.read_imas_geometry + + + + + + + + +input.imas_ids->qty.F0 + + + + + + + + +input.imas_ids->qty.Ip_target + + + + + + + + +qty.aux.E_r + + +radial electric field + + + + + +input.imas_ids->qty.aux.E_r + + + + + + + + +qty.aux.chi_e + + +electron thermal diffusivity + + + + + +input.imas_ids->qty.aux.chi_e + + + + + + + + +qty.aux.chi_i + + +ion thermal diffusivity + + + + + +input.imas_ids->qty.aux.chi_i + + + + + + + + +input.imas_ids->qty.boundary_lcfs + + + + + + + + +qty.j_bootstrap_parallel + + +j_bootstrap (parallel) + + + + + +input.imas_ids->qty.j_bootstrap_parallel + + + + + + + + +qty.j_nbi_parallel + + +j_NBI (parallel, summed) + + + + + +input.imas_ids->qty.j_nbi_parallel + + + + + + + + +qty.j_ohmic_parallel + + +j_ohmic (parallel, unused) + + + + + +input.imas_ids->qty.j_ohmic_parallel + + + + + + + + +qty.j_tor_parallel + + +j_tor (authoritative toroidal) + + + + + +input.imas_ids->qty.j_tor_parallel + + + + + + + + +qty.j_total_parallel + + +j_total (parallel) + + + + + +input.imas_ids->qty.j_total_parallel + + + + + + + + +input.imas_ids->qty.jphi_diff + + + + + + + + +input.imas_ids->qty.li_target + + + + + + + + +input.imas_ids->qty.ne + + + + + + + + +input.imas_ids->qty.ni + + + + + + + + +input.imas_ids->qty.omega_tor + + + + + + + + +qty.p_equilibrium + + +equilibrium pressure + + + + + +input.imas_ids->qty.p_equilibrium + + + + + + + + +input.imas_ids->qty.psi_N + + + + + + + + +input.imas_ids->qty.te + + + + + + + + +input.imas_ids->qty.ti + + + + + + + + +input.imas_ids->qty.zeff + + + + + + + + +cfg.FixedComponentsConfig.j_NBI + + + + +FixedComponentsConfig.j_NBI + + + + + +fn.baseline._resolve_fixed + + +_resolve_fixed(comp, src_psi, dst_psi) + + + + + +cfg.FixedComponentsConfig.j_NBI->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.j_RF + + + + +FixedComponentsConfig.j_RF + + + + + +cfg.FixedComponentsConfig.j_RF->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.p_fast + + + + +FixedComponentsConfig.p_fast + + + + + +cfg.FixedComponentsConfig.p_fast->fn.baseline._resolve_fixed + + + + + + + + +cfg.FixedComponentsConfig.psi_N + + + + +FixedComponentsConfig.psi_N + + + + + +cfg.FixedComponentsConfig.psi_N->fn.baseline._resolve_fixed + + + + + + + + +cfg.GenerationConfig.recalculate_j_BS + + + + +GenerationConfig.recalculate_j_BS + + + + + +cfg.GenerationConfig.recalculate_j_BS->qty.j_BS + + + + + + + + +cfg.ReconstructionSource.impurity_Z + + + + +ReconstructionSource.impurity_Z + + + + + +fn.baseline._load_kinetic_profiles + + +_load_kinetic_profiles(source) + + + + + +cfg.ReconstructionSource.impurity_Z->fn.baseline._load_kinetic_profiles + + + + + + + + +cfg.UncertaintyConfig.aux_baselines + + + + +UncertaintyConfig.aux_baselines + + + + + +fn.baseline._sigma_zeff_baseline + + +resolve zeff baseline (aux or baseline.Zeff) + + + + + +cfg.UncertaintyConfig.aux_baselines->fn.baseline._sigma_zeff_baseline + + + + + + + + +cfg.UncertaintyConfig.aux_length_scales + + + + +UncertaintyConfig.aux_length_scales + + + + + +cfg.UncertaintyConfig.aux_sigmas + + + + +UncertaintyConfig.aux_sigmas + + + + + +gate.sigma_priority_zeff + + +zeff sigma priority: explicit | default auto-inject + + + + + +cfg.UncertaintyConfig.aux_sigmas->gate.sigma_priority_zeff + + + + + + + + +cfg.UncertaintyConfig.ida_path + + + + +UncertaintyConfig.ida_path + + + + + +gate.sigma_priority_ne + + +ne sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ne + + + + + + + + +gate.sigma_priority_ni + + +ni sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ni + + + + + + + + +gate.sigma_priority_te + + +te sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_te + + + + + + + + +gate.sigma_priority_ti + + +ti sigma priority: explicit | IDA | scalar + + + + + +cfg.UncertaintyConfig.ida_path->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.jphi_scalar_sigma + + + + +UncertaintyConfig.jphi_scalar_sigma + + + + + +qty.sigma_jphi + + +sigma_jphi [A/m^2] + + + + + +cfg.UncertaintyConfig.jphi_scalar_sigma->qty.sigma_jphi + + + + + + + +cfg.UncertaintyConfig.ne_scalar_sigma + + + + +UncertaintyConfig.ne_scalar_sigma + + + + + +cfg.UncertaintyConfig.ne_scalar_sigma->gate.sigma_priority_ne + + + + + + + + +cfg.UncertaintyConfig.ni_scalar_sigma + + + + +UncertaintyConfig.ni_scalar_sigma + + + + + +cfg.UncertaintyConfig.ni_scalar_sigma->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_ni_from_ne + + + + +UncertaintyConfig.sigma_ni_from_ne + + + + + +cfg.UncertaintyConfig.sigma_ni_from_ne->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles + + + + +UncertaintyConfig.sigma_profiles + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ne + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ni + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_te + + + + + + + + +cfg.UncertaintyConfig.sigma_profiles->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.te_scalar_sigma + + + + +UncertaintyConfig.te_scalar_sigma + + + + + +cfg.UncertaintyConfig.te_scalar_sigma->gate.sigma_priority_te + + + + + + + + +cfg.UncertaintyConfig.ti_scalar_sigma + + + + +UncertaintyConfig.ti_scalar_sigma + + + + + +cfg.UncertaintyConfig.ti_scalar_sigma->gate.sigma_priority_ti + + + + + + + + +cfg.UncertaintyConfig.zeff_scalar_sigma + + + + +UncertaintyConfig.zeff_scalar_sigma + + + + + +gate.zeff_channel_enable + + +zeff channel enabled (when zeff_scalar_sigma>0) + + + + + +cfg.UncertaintyConfig.zeff_scalar_sigma->gate.zeff_channel_enable + + + + + + + + +fn.baseline._load_kinetic_profiles->gate.profile_file_type + + + + + + + + +qty.j_NBI + + +j_NBI [A/m^2] (beam-driven) + + + + + +fn.baseline._resolve_fixed->qty.j_NBI + + + + + + + + +fn.baseline._resolve_fixed->qty.j_RF + + + + + + + + +fn.baseline._resolve_fixed->qty.p_fast + + + + + + + + +fn.baseline._resolve_reconstruction + + +_resolve_reconstruction(source, config, mygs) + + + + + +fn.baseline._resolve_reconstruction->fn.baseline._load_kinetic_profiles + + + + + + + + +fn.baseline._resolve_reconstruction->fn.baseline._resolve_fixed + + + + + + + + +fn.baseline._resolve_reconstruction->qty.Ip_target + + + + + + + + +fn.baseline._resolve_reconstruction->qty.j_BS + + + + + + + + +qty.j_inductive + + +j_inductive (ohmic current) + + + + + +fn.baseline._resolve_reconstruction->qty.j_inductive + + + + + + + + +fn.baseline._resolve_reconstruction->qty.j_phi + + + + + + + + +fn.baseline._resolve_reconstruction->qty.li_target + + + + + + + + +fn.baseline._resolve_reconstruction->qty.psi_N + + + + + + + + +qty.aux_baselines + + +aux_baselines dict + + + + + +fn.baseline._sigma_zeff_baseline->qty.aux_baselines + + + + + + + + +fn.baseline.resolve_baseline + + +resolve_baseline(config, mygs) + + + + + +gate.source_type + + +source type: ImasSource | ReconstructionSource + + + + + +fn.baseline.resolve_baseline->gate.source_type + + + + + + + + +fn.baseline.resolve_uncertainty + + +resolve_uncertainty(config, baseline) + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ne + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ni + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_te + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_ti + + + + + + + + +fn.baseline.resolve_uncertainty->gate.sigma_priority_zeff + + + + + + + + +fn.baseline.resolve_uncertainty->qty.aux_baselines + + + + + + + + +qty.aux_sigmas + + +aux_sigmas dict + + + + + +fn.baseline.resolve_uncertainty->qty.aux_sigmas + + + + + + + + + +fn.baseline.resolve_uncertainty->qty.sigma_jphi + + + + + + + + + +fn.io.imas.read_imas_baseline + + +read_imas_baseline(source, fixed, ...) + + + + + +fn.io.pfile.read_pfile->qty.ne + + + + + + + + + +fn.io.pfile.read_pfile->qty.ni + + + + + + + + + +fn.io.pfile.read_pfile->qty.psi_N_kinetic + + + + + + + + + +fn.io.pfile.read_pfile->qty.te + + + + + + + + +fn.io.pfile.read_pfile->qty.ti + + + + + + + + +fn.io.pfile.read_pfile->qty.zeff + + + + + + + + +gate.sigma_priority_ne->qty.sigma_ne + + + + + + + + +gate.sigma_priority_ni->qty.sigma_ni + + + + + + + + +gate.sigma_priority_te->qty.sigma_te + + + + + + + + +gate.sigma_priority_ti->qty.sigma_ti + + + + + + + + +gate.sigma_priority_zeff->qty.aux_sigmas + + + + + + + + +gate.source_type->fn.baseline._resolve_reconstruction + + + + + + + + +gate.source_type->fn.io.imas.read_imas_baseline + + + + + + + + +gate.zeff_channel_enable->fn.baseline._sigma_zeff_baseline + + + + + + + + +cfg.isolate_edge_jBS + + + + +isolate_edge_jBS + + + + + +ext.solve_with_bootstrap + + +solve_with_bootstrap() + + + + + +cfg.isolate_edge_jBS->ext.solve_with_bootstrap + + + + + + + + +cfg.isolate_edge_jBS->ext.solve_with_bootstrap + + + + + + + + +gate.j_inductive_decomposition + + +j_inductive storage logic (isolate_edge_jBS) + + + + + +cfg.isolate_edge_jBS->gate.j_inductive_decomposition + + + + + + + + +cfg.n_k + + + + +n_k (spline order) + + + + + +fn.tmi.fit_inductive_profile + + +fit_inductive_profile + + + + + +cfg.n_k->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.psi_bridge + + + + +psi_bridge + + + + + +cfg.psi_bridge->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.psi_pad + + + + +psi_pad + + + + + +fn.sampling.calc_cylindrical_li_proxy + + +calc_cylindrical_li_proxy + + + + + +cfg.psi_pad->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +fn.tmi._swb_jbs_to_toroidal + + +_swb_jbs_to_toroidal + + + + + +cfg.psi_pad->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +cfg.rescale_j_BS + + + + +rescale_j_BS + + + + + +cfg.rescale_j_BS->fn.tmi.fit_inductive_profile + + + + + + + + +cfg.shelf_psi_N + + + + +shelf_psi_N + + + + + +cfg.shelf_psi_N->fn.tmi.fit_inductive_profile + + + + + + + + +qty.j_BS_shelved + + +j_BS after optional shelf + + + + + +cfg.shelf_psi_N->qty.j_BS_shelved + + + + + + + + +ext.corrective_jphi_iteration + + +_corrective_jphi_iteration + + + + + +qty.j_phi_output_corr + + +j_phi_output (corrective) + + + + + +ext.corrective_jphi_iteration->qty.j_phi_output_corr + + + + + + + + +qty.li_proxy_baseline + + +baseline li proxy + + + + + +fn.sampling.calc_cylindrical_li_proxy->qty.li_proxy_baseline + + + + + + + + +fn.tmi._shelf_blend_decompose + + +_shelf_blend_decompose + + + + + +qty.shelf_psi_value + + +shelf_psi (location) + + + + + +fn.tmi._shelf_blend_decompose->qty.shelf_psi_value + + + + + + + + +qty.full_j_BS + + +full_j_BS (full bootstrap, physical) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.full_j_BS + + + + + + + + +qty.j_dot_B + + +<j.B> (undo SWB projection) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.j_dot_B + + + + + + + + +qty.spike_profile + + +spike_profile (bootstrap spike) + + + + + +fn.tmi._swb_jbs_to_toroidal->qty.spike_profile + + + + + + + + +fn.tmi.classify_jphi_profile + + +classify_jphi_profile + + + + + +qty.jphi_mode + + +jphi_mode + + + + + +fn.tmi.classify_jphi_profile->qty.jphi_mode + + + + + + + + +qty.spike_metrics + + +spike_metrics + + + + + +fn.tmi.classify_jphi_profile->qty.spike_metrics + + + + + + + + +qty.bs_scale + + +bootstrap scaling factor + + + + + +fn.tmi.fit_inductive_profile->qty.bs_scale + + + + + + + + +qty.ind_scale + + +inductive scaling factor + + + + + +fn.tmi.fit_inductive_profile->qty.ind_scale + + + + + + + + +qty.j_inductive_basis + + +j_inductive_basis (spline fit) + + + + + +fn.tmi.fit_inductive_profile->qty.j_inductive_basis + + + + + + + + +fn.tmi.reconstruct_equilibrium + + +reconstruct_equilibrium + + + + + +gate.jphi_classified + + +gate.jphi_classified + + + + + +qty.j_BS_final + + +j_BS_final + + + + + +gate.jphi_classified->qty.j_BS_final + + + + + + + + +qty.j_phi_corrective_target + + +j_phi_corrective_target + + + + + +gate.jphi_classified->qty.j_phi_corrective_target + + + + + + + + +gate.li_converged + + +gate.li_converged + + + + + +gate.li_converged->fn.tmi.reconstruct_equilibrium + + + + + + + + +qty.ind_factor_opt + + +ind_factor (li-converged) + + + + + +gate.li_converged->qty.ind_factor_opt + + + + + + + + +input.eqdsk + + +EQDSK geqdsk equilibrium + + + + + +input.eqdsk->ext.solve_with_bootstrap + + + + + + + + +input.eqdsk->qty.Ip_target + + + + + + + + +qty.eqdsk_j_tor + + +eqdsk j_tor (baseline) + + + + + +input.eqdsk->qty.eqdsk_j_tor + + + + + + + + +input.eqdsk->qty.li_target + + + + + + + + +input.eqdsk->qty.psi_N + + + + + + + + +input.isoflux + + +Isoflux constraint points & weights + + + + + +qty.quality_metrics + + +quality metrics dict + + + + + +input.isoflux->qty.quality_metrics + + + + + + + +input.kinetics + + +Kinetic profiles (ne, te, ni, ti, Zeff) + + + + + +input.kinetics->ext.solve_with_bootstrap + + + + + + + + +qty.pressure + + +pressure profile + + + + + +input.kinetics->qty.pressure + + + + + + + + +input.mygs + + +TokaMaker GS solver + + + + + +input.mygs->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +input.mygs->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +art.h5_archive + + + +HDF5 archive {header}.h5 + + + + + +fn.run.export + + +export() + + + + + +art.h5_archive->fn.run.export + + + + + + + + +fn.archive.BouquetArchive + + + +BouquetArchive(ref) + + + + + +art.h5_archive->fn.archive.BouquetArchive + + + + + + + + +fn.utils.discover_scan_keys + + +discover_scan_keys(h5path_or_header) + + + + + +art.h5_archive->fn.utils.discover_scan_keys + + + + + + + + +fn.utils.list_equilibrium_indices + + +list_equilibrium_indices(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.list_equilibrium_indices + + + + + + + + +fn.utils.load_baseline_profiles + + +load_baseline_profiles(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.load_baseline_profiles + + + + + + + + +fn.utils.load_config + + +load_config(h5path, scan_key) + + + + + +art.h5_archive->fn.utils.load_config + + + + + + + + +fn.utils.load_equilibrium + + +load_equilibrium(header, count, scan_key, eqdsk_out_dir) + + + + + +art.h5_archive->fn.utils.load_equilibrium + + + + + + + + +cfg.generation.floor_j_BS + + + + +config.generation.floor_j_BS + + + + + +fn.run._forward_solve_imas_baseline + + +_forward_solve_imas_baseline() + + + + + +cfg.generation.floor_j_BS->fn.run._forward_solve_imas_baseline + + + + + + + + +cfg.generation.isolate_edge_jBS + + + + +config.generation.isolate_edge_jBS + + + + + +cfg.generation.jBS_baseline_mode + + + + +config.generation.jBS_baseline_mode + + + + + +gate.jBS_baseline_mode + + +jBS_baseline_mode (diff vs rescale) + + + + + +cfg.generation.jBS_baseline_mode->gate.jBS_baseline_mode + + + + + + + + +gate.workflow_guard + + +workflow validation gate + + + + + +cfg.generation.jBS_baseline_mode->gate.workflow_guard + + + + + + + + +cfg.generation.recalculate_j_BS + + + + +config.generation.recalculate_j_BS + + + + + +cfg.generation.recalculate_j_BS->fn.run._forward_solve_imas_baseline + + + + + + + + +cfg.source.type + + + + +source type + + + + + +fn.run._validate_workflow + + +_validate_workflow() + + + + + +cfg.source.type->fn.run._validate_workflow + + + + + + + + +ext.generate_bouquet + + +generate_bouquet() + + + + + +ext.solve_with_bootstrap->qty.full_j_BS + + + + + + + + +qty.j_BS_swb + + +j_BS from solve_with_bootstrap (parallel) + + + + + +ext.solve_with_bootstrap->qty.j_BS_swb + + + + + + + + +ext.solve_with_bootstrap->qty.spike_profile + + + + + + + + +gate.ip_sanity + + +Ip convergence check + + + + + +fn.run._forward_solve_imas_baseline->gate.ip_sanity + + + + + + + + +fn.run._forward_solve_imas_baseline->qty.li_target + + + + + + + + +fn.run._repoint_imas_geometry + + +_repoint_imas_geometry() + + + + + +fn.run._repoint_imas_geometry->qty.boundary_lcfs + + + + + + + + +fn.run._resolve_workflow_preset + + +resolve workflow preset + + + + + +fn.run._resolve_workflow_preset->gate.workflow_guard + + + + + + + + +fn.run.generate + + +generate() + + + + + +fn.run._validate_workflow->fn.run.generate + + + + + + + + +fn.run.run + + +run() [convenience] + + + + + +fn.run.export->fn.run.run + + + + + + + + +fn.run.filter + + +filter() + + + + + +fn.run.filter->fn.run.export + + + + + + + + +fn.run.filter->fn.run.run + + + + + + + + + +fn.run.run_slices + + +run_slices() + + + + + +fn.run.filter->fn.run.run_slices + + + + + + + + +fn.run.generate->art.h5_archive + + + + + + + + +fn.run.generate->fn.run.filter + + + + + + + + +fn.run.generate->fn.run.run + + + + + + + + +fn.run.generate->fn.run.run_slices + + + + + + + + +fn.run.prepare_baseline + + +prepare_baseline() + + + + + +fn.run.prepare_baseline->fn.run.run + + + + + + + + +fn.run.prepare_baseline->fn.run.run_slices + + + + + + + + +fn.run.prepare_baseline->qty.Ip_target + + + + + + + + + +qty.j_BS_src + + +j_BS_src + + + + + +fn.run.prepare_baseline->qty.j_BS_src + + + + + + + +fn.run.prepare_baseline->qty.j_inductive + + + + + + + +fn.run.prepare_baseline->qty.j_phi + + + + + + + + + +fn.run.prepare_baseline->qty.ne + + + + + + + + +fn.run.prepare_baseline->qty.ni + + + + + + + +fn.run.prepare_baseline->qty.psi_N + + + + + + + + +fn.run.prepare_baseline->qty.psi_N_kinetic + + + + + + + + +fn.run.prepare_baseline->qty.te + + + + + + + + +fn.run.prepare_baseline->qty.ti + + + + + + + +fn.run.prepare_baseline->qty.zeff + + + + + + + +fn.run.set_slice + + +set_slice() + + + + + +fn.run.set_slice->fn.run._repoint_imas_geometry + + + + + + + + +fn.run.set_slice->fn.run.run_slices + + + + + + + + +fn.run.setup_solver + + +setup_solver() + + + + + +fn.run.setup_solver->fn.run.prepare_baseline + + + + + + + + +fn.run.setup_solver->fn.run.run + + + + + + + + +fn.run.setup_solver->fn.run.run_slices + + + + + + + + +fn.run.setup_solver->qty.F0 + + + + + + + + +fn.run.setup_solver->qty.boundary_lcfs + + + + + + + + +gate.ip_sanity->fn.run.generate + + + + + + + + +gate.jBS_baseline_mode->qty.bs_scale + + + + + + + + +qty.jBS_diff + + +jBS_diff [A/m^2] (bootstrap correction) + + + + + +gate.jBS_baseline_mode->qty.jBS_diff + + + + + + + + +qty.j_phi_diff_mode + + +j_phi (diff) + + + + + +gate.jBS_baseline_mode->qty.j_phi_diff_mode + + + + + + + + +qty.j_phi_rescale_mode + + +j_phi (rescale) + + + + + +gate.jBS_baseline_mode->qty.j_phi_rescale_mode + + + + + + + + +cfg.coil_drift + + + + +coil_drift + + + + + +cfg.constrain_sawteeth + + + + +constrain_sawteeth + + + + + +gate.sawteeth_q0 + + +gate.sawteeth_q0 (q0 constraint) + + + + + +cfg.constrain_sawteeth->gate.sawteeth_q0 + + + + + + + + +gate.constrain_sawteeth_post + + +Post-check q_0 < 1 (final reject) + + + + + +cfg.constrain_sawteeth->gate.constrain_sawteeth_post + + + + + + + + +gate.constrain_sawteeth_pre + + +Pre-check q_0 < 1 (early reject) + + + + + +cfg.constrain_sawteeth->gate.constrain_sawteeth_pre + + + + + + + + +cfg.jBS_scale_range + + + + +jBS_scale_range + + + + + +qty.jBS_scales + + +jBS_scales (per-draw samples) + + + + + +cfg.jBS_scale_range->qty.jBS_scales + + + + + + + + +cfg.l_i_tolerance + + + + +l_i_tolerance + + + + + +gate.li_band + + +gate.li_band (l_i acceptance) + + + + + +cfg.l_i_tolerance->gate.li_band + + + + + + + + +gate.li_acceptance + + +l_i band acceptance gate + + + + + +cfg.l_i_tolerance->gate.li_acceptance + + + + + + + + +cfg.l_i_uncertainty + + + + +l_i_uncertainty + + + + + +qty.l_i_target_draw + + +l_i_target_draw (per-draw sample) + + + + + +cfg.l_i_uncertainty->qty.l_i_target_draw + + + + + + + + +cfg.n_equils + + + + +n_equils + + + + + +fn.tmi.generate_bouquet + + +generate_bouquet (batch driver) + + + + + +cfg.n_equils->fn.tmi.generate_bouquet + + + + + + + + +cfg.recalculate_j_BS + + + + +recalculate_j_BS + + + + + +gate.recalculate_jBS + + +Bootstrap recalculation gate + + + + + +cfg.recalculate_j_BS->gate.recalculate_jBS + + + + + + + + +cfg.seed + + + + +seed (RNG) + + + + + +cfg.seed->fn.tmi.generate_bouquet + + + + + + + + +fn.sampling.generate_perturbed_GPR + + +generate_perturbed_GPR (GPR sampling) + + + + + +qty.aux_out + + +aux_out (per-draw auxiliary) + + + + + +fn.sampling.generate_perturbed_GPR->qty.aux_out + + + + + + + + +qty.ne_draw + + +ne_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ne_draw + + + + + + + + +qty.ni_draw + + +ni_draw (per-draw perturb or derived) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ni_draw + + + + + + + + +qty.te_draw + + +te_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.te_draw + + + + + + + + +qty.ti_draw + + +ti_draw (per-draw perturb) + + + + + +fn.sampling.generate_perturbed_GPR->qty.ti_draw + + + + + + + + +qty.zeff_draw + + +zeff_draw (per-draw sample) + + + + + +fn.sampling.generate_perturbed_GPR->qty.zeff_draw + + + + + + + + +fn.tmi.perturb_kinetic_equilibrium + + +perturb_kinetic_equilibrium (core loop) + + + + + +gate.li_target_sample + + +sample per-draw l_i target? + + + + + +fn.tmi.perturb_kinetic_equilibrium->gate.li_target_sample + + + + + + + + +qty.diagnostics + + +diagnostics (per-draw metrics) + + + + + +fn.tmi.perturb_kinetic_equilibrium->qty.diagnostics + + + + + + + + +qty.output_jphi + + +output_jphi (per-draw j_phi) + + + + + +fn.tmi.perturb_kinetic_equilibrium->qty.output_jphi + + + + + + + + +fn.utils.store_baseline_profiles + + +store_baseline_profiles (baseline save) + + + + + +art.h5.baseline + + + +baseline group (_baseline) + + + + + +fn.utils.store_baseline_profiles->art.h5.baseline + + + + + + + + +art.h5.coil_currents + + + +coil_currents + coil_names + + + + + +fn.utils.store_baseline_profiles->art.h5.coil_currents + + + + + + + + + +art.h5.eqdsk + + + +eqdsk dataset + + + + + +fn.utils.store_baseline_profiles->art.h5.eqdsk + + + + + + + + + + +art.h5.x_points + + + +x_points + + + + + +fn.utils.store_baseline_profiles->art.h5.x_points + + + + + + + + + +fn.utils.store_equilibrium + + +store_equilibrium (per-draw save) + + + + + +fn.utils.store_equilibrium->art.h5_archive + + + + + + + + +art.h5.aux + + + +aux_* profiles + + + + + +fn.utils.store_equilibrium->art.h5.aux + + + + + + + + +fn.utils.store_equilibrium->art.h5.coil_currents + + + + + + + +fn.utils.store_equilibrium->art.h5.eqdsk + + + + + + + +art.h5.filter_flags + + + +filter flags (group attrs) + + + + + +fn.utils.store_equilibrium->art.h5.filter_flags + + + + + + + +art.h5.perturbed_lcfs_ref + + + +perturbed_lcfs_ref + + + + + +fn.utils.store_equilibrium->art.h5.perturbed_lcfs_ref + + + + + + + + +art.h5.profiles + + + +profiles (psi_N, j_phi, j_BS, ...) + + + + + +fn.utils.store_equilibrium->art.h5.profiles + + + + + + + + + +fn.utils.store_equilibrium->art.h5.x_points + + + + + + + + +gate.draw_accepted + + +gate.draw_accepted (final acceptance) + + + + + +gate.li_band->gate.draw_accepted + + + + + + + + +fn.tmi._corrective_jphi_iteration + + +_corrective_jphi_iteration (residual refinement) + + + + + +gate.li_target_sample->fn.tmi._corrective_jphi_iteration + + + + + + + + +gate.sawteeth_q0->gate.draw_accepted + + + + + + + + +gate.solve_failed + + +gate.solve_failed (solver convergence) + + + + + +gate.solve_failed->gate.draw_accepted + + + + + + + + +progress_callback + + +progress_callback (per-draw tick) + + + + + +progress_callback->fn.tmi.generate_bouquet + + + + + + + + +art.eqdsk_bytes + + + +EQDSK file (per-draw) + + + + + +art.perturbed_lcfs_ref + + + +LCFS trace (perturbed) + + + + + +art.x_points + + + +X-point locations + + + + + +cfg.accept_anchor_inband + + + + +accept_anchor_inband (Fix-B path) + + + + + +gate.li_loop_variant + + +l_i match strategy gate + + + + + +cfg.accept_anchor_inband->gate.li_loop_variant + + + + + + + + +gate.perturb_jind_in_anchor_loop + + +Fix-C resample loop (perturb_jind_in_anchor) + + + + + +cfg.accept_anchor_inband->gate.perturb_jind_in_anchor_loop + + + + + + + + +cfg.floor_j_BS + + + + +floor_j_BS (negative bootstrap clipping) + + + + + +cfg.floor_j_BS->qty.spike_profile + + + + + + + + +cfg.max_li_iter + + + + +max_li_iter (l_i loop cap) + + + + + +cfg.max_pressure_iter + + + + +max_pressure_iter (pressure loop cap) + + + + + +cfg.max_proxy_draws + + + + +max_proxy_draws (proxy-draw cap) + + + + + +cfg.mygs + + +mygs (TokaMaker solver) + + + + + +cfg.npsi + + +npsi (grid size) + + + + + +cfg.p_thresh + + + + +p_thresh (pressure match tolerance) + + + + + +cfg.perturb_jind_in_anchor + + + + +perturb_jind_in_anchor (Fix-C path) + + + + + +cfg.perturb_jind_in_anchor->gate.li_loop_variant + + + + + + + + +cfg.perturb_jind_in_anchor->gate.perturb_jind_in_anchor_loop + + + + + + + + +cfg.pin_jphi + + + + +pin_jphi (PIN_JPHI diagnostic) + + + + + +gate.pin_jphi_branch + + +PIN_JPHI diagnostic branch + + + + + +cfg.pin_jphi->gate.pin_jphi_branch + + + + + + + + +cfg.proxy_bias_warmstart + + + + +proxy_bias_warmstart (cross-draw cache) + + + + + +cfg.recon_eq_snapshot + + + + +recon_eq_snapshot (DIFF_BS cache) + + + + + +gate.diff_bs_branch + + +DIFF_BS differential-bootstrap branch + + + + + +cfg.recon_eq_snapshot->gate.diff_bs_branch + + + + + + + + +cfg.scale_jBS + + + + +scale_jBS (bootstrap scale factor) + + + + + +cfg.scale_jBS->ext.solve_with_bootstrap + + + + + + + + +cfg.spike_profile_recon_cached + + + + +spike_profile_recon_cached (DIFF_BS cache) + + + + + +cfg.spike_profile_recon_cached->gate.diff_bs_branch + + + + + + + + +cfg.swb_iterations + + + + +swb_iterations (SWB self-consistency) + + + + + +cfg.swb_iterations->ext.solve_with_bootstrap + + + + + + + + +ext.scipy_interp1d + + +interp1d (kinetic↔equilibrium grid) + + + + + +ext.tokamaker_get_stats + + +mygs.get_stats (extract equilibrium state) + + + + + +ext.tokamaker_replace_eq + + +mygs.replace_eq (state restore for DIFF_BS) + + + + + +ext.tokamaker_set_profiles + + +mygs.set_profiles (pressure/current assignment) + + + + + +ext.tokamaker_solve + + +mygs.solve() (GS forward solve) + + + + + +qty.F_prof + + +F (flux function) + + + + + +ext.tokamaker_solve->qty.F_prof + + + + + + + + +qty.Ip_tokamaker + + +Ip (TokaMaker output) + + + + + +ext.tokamaker_solve->qty.Ip_tokamaker + + + + + + + + +qty.li_current + + +li (TokaMaker output) + + + + + +ext.tokamaker_solve->qty.li_current + + + + + + + + +qty.li_final + + +li_final + + + + + +ext.tokamaker_solve->qty.li_final + + + + + + + + +fn.tmi.Ip_flux_integral_vs_target + + +Ip_flux_integral_vs_target (root-find target) + + + + + +gate.skip_hard_bounds_env + + +SKIP_HARD env? + + + + + +fn.tmi._corrective_jphi_iteration->gate.skip_hard_bounds_env + + + + + + + + +fn.tmi._corrective_jphi_iteration->qty.output_jphi + + + + + + + + +fn.tmi._kin_to_eq + + +_kin_to_eq (kinetic grid → equilibrium grid) + + + + + +fn.tmi._vsc_channel_drift_pct + + +VSC drift (common-mode + differential, quadrature sigma) + + + + + +gate.in_spec_verdict + + +in-spec verdict + + + + + +fn.tmi._vsc_channel_drift_pct->gate.in_spec_verdict + + + + + + + + +fn.tmi.calc_cylindrical_li_proxy + + +calc_cylindrical_li_proxy (fast proxy) + + + + + +fn.tmi.calc_realgeom_li_proxy_fast + + +calc_realgeom_li_proxy_fast (real-geom pre-screen) + + + + + +fn.tmi.find_optimal_scale + + +find_optimal_scale (SWB OFT import) + + + + + +qty.final_jphi + + +final_jphi (find_optimal_scale output) + + + + + +fn.tmi.find_optimal_scale->qty.final_jphi + + + + + + + + +qty.final_scale_j0 + + +final_scale_j0 (core j0 scale factor) + + + + + +fn.tmi.find_optimal_scale->qty.final_scale_j0 + + + + + + + + +fn.tmi.generate_perturbed_GPR + + +generate_perturbed_GPR (external import) + + + + + +fn.tmi.get_li_proxy_geometry + + +get_li_proxy_geometry (real-geom prescreen) + + + + + +fn.tmi.recon_anchor_solve + + +recon-anchor forward solve + + + + + +qty.eq_stats + + +eq_stats (TokaMaker equilibrium stats) + + + + + +fn.tmi.recon_anchor_solve->qty.eq_stats + + + + + + + + +gate.diff_bs_branch->ext.solve_with_bootstrap + + + + + + + + +gate.homotopy_early_stop + + +next pass already infeasible? + + + + + +gate.homotopy_early_stop->gate.in_spec_verdict + + + + + + + + +gate.homotopy_feasible + + +homotopy pass converged? + + + + + +gate.qp_saturation + + +QP saturated at coil bound? + + + + + +gate.homotopy_feasible->gate.qp_saturation + + + + + + + + +gate.post_align_failed + + +post-alignment failure? + + + + + +gate.in_spec_verdict->gate.post_align_failed + + + + + + + + +gate.iso_update + + +re-point isoflux to perturbed LCFS? + + + + + +gate.skip_homotopy_env + + +SKIP_HOMOTOPY env? + + + + + +gate.iso_update->gate.skip_homotopy_env + + + + + + + + +qty.j_inductive_consistent + + +j_inductive_consistent (stored inductive) + + + + + +gate.j_inductive_decomposition->qty.j_inductive_consistent + + + + + + + + +gate.li_band_loop + + +l_i band-conditioning loop (rejection sampling) + + + + + +gate.li_acceptance->gate.li_band_loop + + + + + + + + +qty.jphi_perturb + + +jphi_perturb (GPR j_phi candidate) + + + + + +gate.li_band_loop->qty.jphi_perturb + + + + + + + + +gate.li_loop_variant->gate.li_band_loop + + + + + + + + +qty.matched_j_inductive + + +matched_j_inductive (Ip-scaled inductive) + + + + + +gate.perturb_jind_in_anchor_loop->qty.matched_j_inductive + + + + + + + + +gate.pin_jphi_branch->qty.spike_profile + + + + + + + + +gate.post_align_failed->gate.draw_accepted + + + + + + + + +gate.pressure_match + + +pressure-match loop + + + + + +qty.ne_perturb + + +ne_perturb (perturbed density) + + + + + +gate.pressure_match->qty.ne_perturb + + + + + + + + +qty.ni_perturb + + +ni_perturb (perturbed ion density) + + + + + +gate.pressure_match->qty.ni_perturb + + + + + + + + +qty.te_perturb + + +te_perturb (perturbed temperature) + + + + + +gate.pressure_match->qty.te_perturb + + + + + + + + +qty.ti_perturb + + +ti_perturb (perturbed ion temperature) + + + + + +gate.pressure_match->qty.ti_perturb + + + + + + + + +gate.qp_saturation->gate.homotopy_early_stop + + + + + + + + +gate.skip_hard_bounds_env->gate.iso_update + + + + + + + + +gate.skip_homotopy_env->gate.homotopy_feasible + + + + + + + + +gate.skip_iso_env + + +SKIP_ISO env? + + + + + +gate.standard_swb_branch + + +Standard SWB branch + + + + + +gate.zeff_active + + +Zeff-primary channel active + + + + + +qty.Z_imp + + +effective impurity charge + + + + + +gate.zeff_active->qty.Z_imp + + + + + + + + +gate.zeff_active->qty.zeff_draw + + + + + + + + +qty.Zeff + + +Zeff (effective charge profile) + + + + + +qty.Zeff->ext.solve_with_bootstrap + + + + + + + + +qty.Zeff->gate.zeff_active + + + + + + + + +qty.coil_currents + + + +Coil currents (per-draw) + + + + + +qty.coil_currents->art.eqdsk_bytes + + + + + + + + +qty.coil_currents->art.perturbed_lcfs_ref + + + + + + + + +qty.in_spec_metrics + + + +In-spec boundary metrics + + + + + +qty.input_j_phi + + +input_j_phi (total j_phi baseline) + + + + + +qty.input_j_phi->qty.spike_profile + + + + + + + + +qty.input_jinductive + + +input_jinductive (inductive j_phi component) + + + + + +qty.input_jinductive->qty.jphi_perturb + + + + + + + + +qty.new_jphi + + +new_jphi (total j_phi for anchor) + + + + + +qty.input_jinductive->qty.new_jphi + + + + + + + + +qty.input_jinductive->qty.spike_profile + + + + + + + + +qty.l_i_target + + +l_i_target (internal inductance target) + + + + + +qty.l_i_target->gate.li_acceptance + + + + + + + + +fn.plotting.plot_bouquet + + +plot_bouquet(h5path, scan_key, mode, ...) + + + + + +art.h5.baseline->fn.plotting.plot_bouquet + + + + + + + + +fn.plotting.plot_coil_currents + + +plot_coil_currents(h5path, scan_key, vsc_coils, ...) + + + + + +art.h5.baseline->fn.plotting.plot_coil_currents + + + + + + + + +fn.plotting.plot_traces + + +plot_traces(h5path, scan_key, li_band, rms_max_mm) + + + + + +art.h5.baseline->fn.plotting.plot_traces + + + + + + + + +fn.filtering._baseline_boundary + + +filtering._baseline_boundary + + + + + +art.h5.baseline->fn.filtering._baseline_boundary + + + + + + + + +fn.filtering.filter_coil_currents + + +filter_coil_currents(h5path, scan_key, F_max_pct, VSC_max_pct, apply, plot) + + + + + +art.h5.coil_currents->fn.filtering.filter_coil_currents + + + + + + + + +art.h5.coil_currents->fn.plotting.plot_coil_currents + + + + + + + + +art.h5.config_json + + + +config_json dataset + + + + + +fn.archive.DrawView + + + +DrawView(archive, scan_key, count) + + + + + +art.h5.eqdsk->fn.archive.DrawView + + + + + + + + +fn.plotting.plot_geqdsk_bouquet + + +plot_geqdsk_bouquet(geqdsk_path_or_eq, ...) + + + + + +art.h5.eqdsk->fn.plotting.plot_geqdsk_bouquet + + + + + + + + +fn.filtering._boundary_devs + + +_boundary_devs(bl_boundary, grp) + + + + + +art.h5.perturbed_lcfs_ref->fn.filtering._boundary_devs + + + + + + + + +art.h5.perturbed_lcfs_ref->fn.plotting.plot_traces + + + + + + + + +art.h5.pfile + + + +pfile dataset + + + + + +art.h5.pfile->fn.archive.DrawView + + + + + + + + +fn.plotting.plot_pfile_bouquet + + +plot_pfile_bouquet(pfile_path_or_pf, ...) + + + + + +art.h5.pfile->fn.plotting.plot_pfile_bouquet + + + + + + + + +art.h5.profiles->fn.archive.DrawView + + + + + + + + +fn.gui.EquilibriumBrowser + + + +EquilibriumBrowser(h5path) + + + + + +art.h5.profiles->fn.gui.EquilibriumBrowser + + + + + + + + +art.h5.profiles->fn.plotting.plot_bouquet + + + + + + + + +art.h5.x_points->fn.plotting.plot_traces + + + + + + + + +cfg.filtering.F_max_pct + + + + +F_max_pct + + + + + +cfg.filtering.F_max_pct->fn.filtering.filter_coil_currents + + + + + + + + +cfg.filtering.VSC_max_pct + + + + +VSC_max_pct + + + + + +cfg.filtering.VSC_max_pct->fn.filtering.filter_coil_currents + + + + + + + + +cfg.filtering.max_max_mm + + + + +max_max_mm + + + + + +fn.filtering.filter_boundaries + + +filter_boundaries(h5path, scan_key, rms_max_mm, max_max_mm, apply, plot) + + + + + +cfg.filtering.max_max_mm->fn.filtering.filter_boundaries + + + + + + + + +cfg.filtering.rms_max_mm + + + + +rms_max_mm + + + + + +cfg.filtering.rms_max_mm->fn.filtering.filter_boundaries + + + + + + + + +fn.archive.ScanView + + + +ScanView(archive, scan_key) + + + + + +fn.archive.BouquetArchive->fn.archive.ScanView + + + + + + + + +fn.archive.ScanView->fn.archive.DrawView + + + + + + + + +fn.filtering._boundary_devs->fn.filtering.filter_boundaries + + + + + + + + +fn.filtering.export_filtered + + +export_filtered(h5path, out_path, scan_key, selection, overwrite) + + + + + +fn.filtering.export_filtered->art.h5_archive + + + + + + + + +fn.filtering.filter_boundaries->art.h5.filter_flags + + + + + + + + + +gate.selected + + +selected (AND of filters) + + + + + +fn.filtering.filter_boundaries->gate.selected + + + + + + + + +fn.filtering.filter_coil_currents->art.h5.filter_flags + + + + + + + + + +fn.filtering.filter_coil_currents->gate.selected + + + + + + + + +fn.filtering.read_filter_flags + + +read_filter_flags(h5path, scan_key) + + + + + +fn.filtering.select_indices + + +select_indices(h5path, scan_key, selection) + + + + + +fn.filtering.read_filter_flags->fn.filtering.select_indices + + + + + + + + +fn.filtering.select_indices->fn.archive.ScanView + + + + + + + + +fn.filtering.select_indices->fn.filtering.export_filtered + + + + + + + + +fn.filtering.select_indices->fn.plotting.plot_bouquet + + + + + + + + +fn.schema.find_bytes_dataset + + +find_bytes_dataset(grp, kind) + + + + + +fn.schema.find_bytes_dataset->fn.archive.DrawView + + + + + + + + +fn.schema.write_profile + + +write_profile(grp, name, data) + + + + + +fn.schema.write_profile->fn.utils.store_baseline_profiles + + + + + + + + + +fn.schema.write_profile->fn.utils.store_equilibrium + + + + + + + +fn.utils.discover_scan_keys->fn.archive.BouquetArchive + + + + + + + + +fn.utils.initialize_equilibrium_database + + +initialize_equilibrium_database(header) + + + + + +fn.utils.initialize_equilibrium_database->fn.utils.store_equilibrium + + + + + + + + +fn.utils.list_equilibrium_indices->fn.archive.ScanView + + + + + + + + +fn.utils.load_baseline_profiles->fn.archive.ScanView + + + + + + + + +fn.utils.load_baseline_profiles->fn.gui.EquilibriumBrowser + + + + + + + + +fn.utils.load_baseline_profiles->fn.plotting.plot_bouquet + + + + + + + + +fn.utils.write_provenance + + +write_provenance(h5path, config, scan_key) + + + + + +fn.utils.write_provenance->art.h5_archive + + + + + + + + +gate.boundary_rms + + +Boundary RMS/max pass/fail + + + + + +gate.boundary_rms->fn.filtering.filter_boundaries + + + + + + + + +gate.coil_spec + + +Coil-spec pass/fail + + + + + +gate.coil_spec->fn.filtering.filter_coil_currents + + + + + + + + +gate.selected->art.h5.filter_flags + + + + + + + + +art.sbatch_scripts + + + +{job_name}_array.sbatch, {job_name}_merge.sbatch, {job_name}_submit.sh + + + + + +art.shard_h5 + + + +{out_header}_w{worker_id}.h5 + + + + + +fn.parallel.merge_archives + + +merge_archives(shard_paths, out_header, ...) + + + + + +art.shard_h5->fn.parallel.merge_archives + + + + + + + + +art.slurm_bundle + + + +{job_name}_bundle.json + + + + + +fn.parallel._cli + + +_cli(argv) + + + + + +art.slurm_bundle->fn.parallel._cli + + + + + + + + +env.blas_pinning + + +BLAS/OpenMP env pinning + + + + + +fn.run.Bouquet_pipeline + + +Bouquet.setup_solver -> prepare_baseline -> generate + + + + + +env.blas_pinning->fn.run.Bouquet_pipeline + + + + + + + + +env.fd_suppression + + +fd-level stdout/stderr suppression + + + + + +fn.parallel.run_shard + + +run_shard(config, worker_id, n_workers, ...) + + + + + +env.fd_suppression->fn.parallel.run_shard + + + + + + + + +fn.parallel._cli->fn.parallel.merge_archives + + + + + + + + +fn.parallel._cli->fn.parallel.run_shard + + + + + + + + +fn.parallel._derive_seed + + +_derive_seed(seed_base, worker_id, scan_key) + + + + + +fn.parallel._physical_cores + + +_physical_cores() + + + + + +knob.n_workers + + + + +n_workers + + + + + +fn.parallel._shard_size + + +_shard_size(total, n_workers, worker_id) + + + + + +fn.parallel._warn_multithreaded + + +_warn_multithreaded(threads_per_worker) + + + + + +gate.threads_warn + + +threads_per_worker > 1 warning + + + + + +fn.parallel._warn_multithreaded->gate.threads_warn + + + + + + + + +fn.parallel.emit_slurm_script + + +emit_slurm_script(config, ...) + + + + + +fn.parallel.emit_slurm_script->art.sbatch_scripts + + + + + + + + +fn.parallel.emit_slurm_script->art.slurm_bundle + + + + + + + + +fn.parallel.merge_archives->art.h5_archive + + + + + + + + +fn.parallel.merge_archives->art.h5.config_json + + + + + + + + +fn.parallel.parallel_generate + + +parallel_generate(config, ...) + + + + + +fn.parallel.merge_archives->fn.parallel.parallel_generate + + + + + + + + +gate.baseline_match_merge + + +baseline consistency check (merge) + + + + + +fn.parallel.merge_archives->gate.baseline_match_merge + + + + + + + + + +gate.baseline_match_laptop + + +baseline consistency check (laptop) + + + + + +fn.parallel.parallel_generate->gate.baseline_match_laptop + + + + + + + + +fn.parallel.run_shard->art.shard_h5 + + + + + + + + +fn.parallel.run_shard->fn.parallel.parallel_generate + + + + + + + + +fn.parallel.run_shard->fn.run.Bouquet_pipeline + + + + + + + + + +fn.run.Bouquet_pipeline->art.shard_h5 + + + + + + + + +fn.utils.capture_native_output + + +capture_native_output (fd redirect) + + + + + +fn.utils.capture_native_output->fn.parallel.run_shard + + + + + + + + +gate.backend + + +backend decision + + + + + +gate.backend->fn.parallel.emit_slurm_script + + + + + + + + +gate.backend->fn.parallel.parallel_generate + + + + + + + + + + +gate.baseline_match_laptop->fn.parallel.merge_archives + + + + + + + + +gate.missing_shards + + +missing shards handling (CLI) + + + + + +gate.missing_shards->fn.parallel._cli + + + + + + + + +input.config + + +BouquetConfig + + + + + +input.config->art.h5.config_json + + + + + + + + +input.config->fn.parallel.emit_slurm_script + + + + + + + + +input.config->fn.parallel.parallel_generate + + + + + + + +input.config->fn.parallel.run_shard + + + + + + + + +knob.scan_key + + + + +scan_key + + + + + +input.config->knob.scan_key + + + + + + + + +quantity.n_equils_total + + +n_equils_total + + + + + +input.config->quantity.n_equils_total + + + + + + + + +input.user_args + + +CLI/user args + + + + + +knob.backend + + + + +backend + + + + + +input.user_args->knob.backend + + + + + + + + +input.user_args->knob.n_workers + + + + + + + + +knob.seed + + + + +seed + + + + + +input.user_args->knob.seed + + + + + + + + + +knob.threads_per_worker + + + + +threads_per_worker + + + + + +input.user_args->knob.threads_per_worker + + + + + + + + +knob.backend->gate.backend + + + + + + + + +knob.n_workers->fn.parallel._physical_cores + + + + + + + + + +knob.n_workers->fn.parallel.emit_slurm_script + + + + + + + + +quantity.n_equils_per_worker + + +n_equils_per_worker + + + + + +knob.n_workers->quantity.n_equils_per_worker + + + + + + + + +quantity.per_worker_seed + + +per_worker_seed + + + + + +knob.scan_key->quantity.per_worker_seed + + + + + + + + +knob.seed->fn.parallel.emit_slurm_script + + + + + + + + +knob.seed->quantity.per_worker_seed + + + + + + + + +knob.threads_per_worker->env.blas_pinning + + + + + + + + +knob.threads_per_worker->fn.parallel._warn_multithreaded + + + + + + + + +knob.threads_per_worker->fn.parallel.emit_slurm_script + + + + + + + + +quantity.n_equils_per_worker->fn.parallel.run_shard + + + + + + + +quantity.n_equils_total->quantity.n_equils_per_worker + + + + + + + + +quantity.per_worker_seed->fn.parallel.run_shard + + + + + + + + + +qty.F0->fn.reconstruct_equilibrium + + + + + + + + + +qty.FUSE_tot + + +FUSE_tot + + + + + +qty.FUSE_tot->gate.jBS_baseline_mode + + + + + + + + +qty.Ip + + +Ip (plasma current) + + + + + +qty.Ip->art.eqdsk_bytes + + + + + + + + +qty.Ip_scales + + +Ip_scales + + + + + +qty.Ip_scales->qty.diagnostics + + + + + + + + +qty.Ip_target->fn.reconstruct_equilibrium + + + + + + + + + + +qty.Ip_target->artifact.baseline + + + + + + + + +qty.Ip_target->ext.corrective_jphi_iteration + + + + + + + + +qty.Ip_target->ext.solve_with_bootstrap + + + + + + + + +qty.Ip_target->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.Ip_target->fn.run.generate + + + + + + + + +qty.Ip_target->fn.tmi._corrective_jphi_iteration + + + + + + + + +qty.Ip_target->fn.tmi.find_optimal_scale + + + + + + + + +qty.Ip_target->fn.tmi.recon_anchor_solve + + + + + + + + +qty.a_optimal + + +a_optimal (Ip scale factor) + + + + + +qty.Ip_target->qty.a_optimal + + + + + + + + + +qty.Ip_target->qty.quality_metrics + + + + + + + + +qty.Ip_tokamaker->qty.quality_metrics + + + + + + + + +qty.Z_imp->artifact.baseline + + + + + + + + +qty.pres_tmp + + +pres_tmp (per-draw pressure) + + + + + +qty.Z_imp->qty.pres_tmp + + + + + + + + +qty.Zeff_eq + + +Zeff_eq + + + + + +qty.Zeff_eq->fn.run.generate + + + + + + + + +qty.matched_jphi_perturb + + +matched_jphi_perturb (Ip-matched j_phi candidate) + + + + + +qty.a_optimal->qty.matched_jphi_perturb + + + + + + + + +qty.aux_baselines->gate.zeff_active + + + + + + + +qty.aux_baselines->qty.aux_out + + + + + + + + +qty.aux_baselines->qty.zeff_draw + + + + + + + + +qty.aux_length_scales + + +aux_length_scales (auxiliary GPR scales) + + + + + +qty.aux_length_scales->qty.aux_out + + + + + + + + +qty.aux_length_scales->qty.zeff_draw + + + + + + + + +qty.aux_out->fn.utils.store_equilibrium + + + + + + + + +qty.aux_out->qty.diagnostics + + + + + + + + +qty.aux_sigmas->gate.zeff_active + + + + + + + + + +qty.aux_sigmas->qty.aux_out + + + + + + + + +qty.aux_sigmas->qty.zeff_draw + + + + + + + + +qty.avg_B2 + + +<B²> (FSA) + + + + + +qty.avg_inv_R + + +<1/R> (FSA) + + + + + +qty.baseline_j_BS_with_diff + + +baseline_j_BS (+ jBS_diff) + + + + + +qty.baseline_j_BS_with_diff->fn.run.generate + + + + + + + + +qty.baseline_li_proxy + + +baseline_li_proxy (cylindrical proxy l_i) + + + + + +qty.proxy_target + + +proxy_target (adaptive proxy target) + + + + + +qty.baseline_li_proxy->qty.proxy_target + + + + + + + + +qty.boundary_lcfs->fn.reconstruct_equilibrium + + + + + + + + +qty.bs_scale->fn.run.generate + + + + + + + + +qty.j_phi_fit_prelim + + +j_phi_fit (pre-li-match) + + + + + +qty.bs_scale->qty.j_phi_fit_prelim + + + + + + + + +qty.chi_e + + +chi_e [m^2/s] (electron transport) + + + + + +qty.chi_i + + +chi_i [m^2/s] (ion transport) + + + + + +qty.diagnostics->fn.utils.store_equilibrium + + + + + + + + +qty.e_r + + +e_r [V/m] (radial electric field) + + + + + +qty.eq_stats->qty.baseline_li_proxy + + + + + + + + +qty.eqdsk_j_tor->fn.sampling.calc_cylindrical_li_proxy + + + + + + + + +qty.eqdsk_j_tor->fn.tmi._shelf_blend_decompose + + + + + + + + +qty.eqdsk_j_tor->fn.tmi.classify_jphi_profile + + + + + + + + +qty.eqdsk_j_tor->qty.j_phi_corrective_target + + + + + + + + + +qty.eqdsk_j_tor->qty.quality_metrics + + + + + + + + +qty.ffp_prof_corr + + +FFp for GS (corrective) + + + + + +qty.ffp_prof_li + + +FFp for GS (li-match) + + + + + +qty.ffp_prof_li->ext.tokamaker_solve + + + + + + + + +qty.final_jphi->gate.constrain_sawteeth_pre + + + + + + + + +qty.target_jphi_perturb + + +target_jphi_perturb (corrective target) + + + + + +qty.final_jphi->qty.target_jphi_perturb + + + + + + + + +qty.final_li_proxy + + +final_li_proxy (diagnostic cylindrical proxy) + + + + + +qty.proxy_vs_real + + +proxy_vs_real (proxy-equilibrium offset %) + + + + + +qty.final_li_proxy->qty.proxy_vs_real + + + + + + + + +qty.final_scale_j0->qty.target_jphi_perturb + + + + + + + + +qty.full_j_BS->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.full_j_BS->qty.diagnostics + + + + + + + + +qty.guess_j_inductive + + +guess_j_inductive + + + + + +qty.j_ind_li_matched + + +j_ind (li-matched) + + + + + +qty.ind_factor_opt->qty.j_ind_li_matched + + + + + + + + +qty.j_inductive_fit + + +j_inductive_fit (scaled) + + + + + +qty.ind_scale->qty.j_inductive_fit + + + + + + + + +qty.iteration_Ips + + +iteration_Ips + + + + + +qty.iteration_Ips->qty.diagnostics + + + + + + + + +qty.iteration_l_is + + +iteration_l_is + + + + + +qty.iteration_l_is->qty.diagnostics + + + + + + + + +qty.j0_scales + + +j0_scales + + + + + +qty.j0_scales->qty.diagnostics + + + + + + + + +qty.jBS_diff->fn.run.generate + + + + + + + + +qty.jBS_diff->qty.baseline_j_BS_with_diff + + + + + + + + +qty.jBS_diff->qty.spike_profile + + + + + + + + +qty.jBS_scale_range_centered + + +jBS_scale_range (centered) + + + + + +qty.jBS_scale_range_centered->ext.generate_bouquet + + + + + + + + +qty.jBS_scales->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.j_BS->artifact.baseline + + + + + + + + +qty.j_BS->qty.j_inductive + + + + + + + + +qty.j_ind_final + + +j_ind_final + + + + + +qty.j_BS_final->qty.j_ind_final + + + + + + + + +qty.j_BS_isolated->fn.tmi._shelf_blend_decompose + + + + + + + + +qty.j_BS_isolated->fn.tmi.classify_jphi_profile + + + + + + + + +qty.j_BS_isolated->fn.tmi.fit_inductive_profile + + + + + + + + +qty.j_BS_isolated->qty.ffp_prof_li + + + + + + + + +qty.j_BS_isolated->qty.j_BS_shelved + + + + + + + + +qty.j_BS_isolated->qty.j_phi_corrective_target + + + + + + + +qty.j_BS_isolated->qty.j_phi_fit_prelim + + + + + + + + + +qty.j_BS_smoothed + + +j_BS smoothed transition + + + + + +qty.j_BS_shelved->qty.j_BS_smoothed + + + + + + + + +qty.j_BS_smoothed->qty.j_BS_isolated + + + + + + + + +qty.j_BS_src->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_BS_src->gate.jBS_baseline_mode + + + + + + + + +qty.j_BS_swb->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.j_BS_swb->gate.jBS_baseline_mode + + + + + + + + +qty.j_BS_swb->qty.baseline_j_BS_with_diff + + + + + + + + +qty.j_fixed_eff + + +j_fixed_eff (fixed additive currents) + + + + + +qty.j_NBI->qty.j_fixed_eff + + + + + + + + +qty.j_NBI_toroidal->artifact.baseline + + + + + + + + +qty.j_NBI_toroidal->qty.j_inductive + + + + + + + + +qty.j_RF->artifact.baseline + + + + + + + + +qty.j_RF->qty.j_fixed_eff + + + + + + + + +qty.j_RF->qty.j_inductive + + + + + + + + +qty.j_bootstrap_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_fixed_eff->qty.a_optimal + + + + + + + + +qty.j_fixed_eff->qty.j_inductive_consistent + + + + + + + + +qty.j_fixed_eff->qty.matched_jphi_perturb + + + + + + + + +qty.j_fixed_eff->qty.new_jphi + + + + + + + + +qty.j_fixed_eff->qty.target_jphi_perturb + + + + + + + + +qty.j_ind_li_matched->qty.j_phi_corrective_target + + + + + + + + +qty.j_inductive->artifact.baseline + + + + + + + + + +qty.j_inductive->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_inductive->fn.run.generate + + + + + + + + +qty.j_inductive_basis->qty.j_inductive_fit + + + + + + + + +qty.j_inductive_consistent->qty.diagnostics + + + + + + + + +qty.j_inductive_fit->qty.ffp_prof_li + + + + + + + + +qty.j_inductive_fit->qty.j_ind_li_matched + + + + + + + + +qty.j_inductive_fit->qty.j_phi_fit_prelim + + + + + + + + +qty.j_ls + + +j_ls (current length scale) + + + + + +qty.j_ls->qty.jphi_perturb + + + + + + + + +qty.j_nbi_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_phi->artifact.baseline + + + + + + + + +qty.j_phi->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.j_phi->fn.run.generate + + + + + + + + +qty.j_phi->qty.j_inductive + + + + + + + + +qty.j_phi->qty.jphi_diff + + + + + + + + +qty.j_phi->qty.sigma_jphi + + + + + + + + +qty.j_phi_corrective_target->ext.corrective_jphi_iteration + + + + + + + + +qty.j_phi_final + + +j_phi_final + + + + + +qty.j_phi_final->qty.j_ind_final + + + + + + + + +qty.j_phi_final->qty.quality_metrics + + + + + + + + +qty.j_phi_output_corr->qty.j_phi_final + + + + + + + + +qty.j_tor_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.j_tor_parallel->qty.j_phi + + + + + + + + +qty.j_total_parallel->fn.physics.parallel_to_toroidal + + + + + + + + +qty.jphi_diff->artifact.baseline + + + + + + + + +qty.jphi_diff->fn.run.generate + + + + + + + + +qty.jphi_diff->qty.j_fixed_eff + + + + + + + + +qty.jphi_mode->gate.jphi_classified + + + + + + + + +qty.jphi_mode->qty.quality_metrics + + + + + + + + + +qty.jphi_perturb->qty.a_optimal + + + + + + + + +qty.jphi_perturb->qty.matched_jphi_perturb + + + + + + + + +qty.l_i + + +l_i (equilibrium internal inductance) + + + + + +qty.l_i->art.eqdsk_bytes + + + + + + + + +qty.l_i->gate.li_acceptance + + + + + + + + +qty.l_i->qty.proxy_vs_real + + + + + + + + +qty.l_i_target_draw->gate.li_band + + + + + + + + +qty.li_current->gate.li_converged + + + + + + + + +qty.li_final->qty.quality_metrics + + + + + + + + +qty.li_proxy_baseline->fn.tmi.fit_inductive_profile + + + + + + + + +qty.li_target->artifact.baseline + + + + + + + + +qty.li_target->gate.li_converged + + + + + + + + +qty.li_target->fn.run.generate + + + + + + + +qty.matched_j_inductive->gate.li_loop_variant + + + + + + + + +qty.matched_jphi_perturb->fn.tmi.find_optimal_scale + + + + + + + + +qty.n_ls + + +n_ls (density length scale) + + + + + +qty.n_ls->gate.pressure_match + + + + + + + + +qty.n_ls->qty.ne_draw + + + + + + + + +qty.ne->fn.reconstruct_equilibrium + + + + + + + + +qty.ne->artifact.baseline + + + + + + + + +qty.ne->fn.imas._merge_ida_kinetics + + + + + + + + +qty.ne->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ne->gate.sigma_priority_ne + + + + + + + + +qty.ne->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ne->fn.run.generate + + + + + + + + +qty.ne->gate.pressure_match + + + + + + + + +qty.ne->qty.Z_imp + + + + + + + + +qty.ne->qty.ne_draw + + + + + + + + +qty.ne->qty.zeff + + + + + + + + +qty.ne_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ne_draw->qty.ni_draw + + + + + + + + +qty.ne_draw->qty.pres_tmp + + + + + + + +qty.ne_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ne_perturb->art.eqdsk_bytes + + + + + + + + +qty.ne_perturb->qty.p_thermal + + + + + + + + +qty.new_jphi->fn.tmi.recon_anchor_solve + + + + + + + + +qty.ni->fn.reconstruct_equilibrium + + + + + + + + + + +qty.ni->artifact.baseline + + + + + + + + +qty.ni->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ni->gate.sigma_priority_ni + + + + + + + + +qty.ni->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ni->fn.run.generate + + + + + + + + + +qty.ni->gate.pressure_match + + + + + + + + +qty.ni->qty.Z_imp + + + + + + + + + +qty.ni->qty.ni_draw + + + + + + + + +qty.p_imp + + +impurity pressure + + + + + +qty.ni->qty.p_imp + + + + + + + + +qty.ni_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ni_draw->qty.pres_tmp + + + + + + + + +qty.ni_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ni_perturb->art.eqdsk_bytes + + + + + + + + +qty.ni_perturb->qty.p_thermal + + + + + + + + +qty.output_jphi->fn.utils.store_equilibrium + + + + + + + + +qty.output_jphi->art.eqdsk_bytes + + + + + + + + +qty.output_jphi->gate.constrain_sawteeth_post + + + + + + + + +qty.output_jphi->qty.Ip + + + + + + + + +qty.output_jphi->qty.final_li_proxy + + + + + + + + +qty.output_jphi->qty.j_inductive_consistent + + + + + + + + +qty.output_jphi->qty.l_i + + + + + + + + +qty.p_diff->artifact.baseline + + + + + + + + +qty.p_diff->fn.run.generate + + + + + + + + +qty.p_diff->qty.pres_tmp + + + + + + + + +qty.p_equilibrium->artifact.baseline + + + + + + + + +qty.p_equilibrium->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_equilibrium->qty.p_diff + + + + + + + + +qty.p_fast->artifact.baseline + + + + + + + + +qty.p_fast->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_recon + + +reconstructed pressure + + + + + +qty.p_fast->qty.p_recon + + + + + + + + +qty.p_fast->qty.pres_tmp + + + + + + + + +qty.p_imp->fn.imas._validate_pressure_completeness + + + + + + + + +qty.p_imp->qty.p_recon + + + + + + + + +qty.p_recon->qty.p_diff + + + + + + + + +qty.p_thermal->fn.reconstruct_equilibrium + + + + + + + + +qty.p_thermal->qty.pres_tmp + + + + + + + + +qty.p_total + + +p_total + + + + + +qty.p_total->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.pprime + + +p' (pressure gradient) + + + + + +qty.pprime_gs + + +p' for GS + + + + + +qty.pprime->qty.pprime_gs + + + + + + + + +qty.pprime_gs->ext.corrective_jphi_iteration + + + + + + + + +qty.pprime_gs->ext.tokamaker_solve + + + + + + + + +qty.pres_tmp->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.pres_tmp->fn.tmi._corrective_jphi_iteration + + + + + + + +qty.pres_tmp->fn.tmi.find_optimal_scale + + + + + + + + + +qty.pres_tmp->fn.tmi.recon_anchor_solve + + + + + + + + +qty.pres_tmp->gate.recalculate_jBS + + + + + + + +qty.pressure->fn.tmi.perturb_kinetic_equilibrium + + + + + + + + +qty.pressure->qty.pprime + + + + + + + + +qty.proxy_target->gate.li_band_loop + + + + + + + + +qty.proxy_vs_real->qty.proxy_target + + + + + + + + +qty.psi_N->fn.reconstruct_equilibrium + + + + + + + + +qty.psi_N->artifact.baseline + + + + + + + + +qty.psi_N->fn.imas._merge_ida_kinetics + + + + + + + + +qty.psi_N->fn.imas._override + + + + + + + + +qty.psi_N->fn.tmi.classify_jphi_profile + + + + + + + + +qty.psi_N->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.psi_N->qty.Zeff_eq + + + + + + + + +qty.psi_N_kinetic->artifact.baseline + + + + + + + + +qty.psi_N_kinetic->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.sigma_jphi->qty.jphi_perturb + + + + + + + + +qty.sigma_ne->gate.pressure_match + + + + + + + + +qty.sigma_ne->qty.ne_draw + + + + + + + + +qty.sigma_te->gate.pressure_match + + + + + + + + +qty.sigma_te->qty.te_draw + + + + + + + + +qty.sigma_ti->qty.ti_draw + + + + + + + + +qty.spike_metrics->qty.quality_metrics + + + + + + + +qty.spike_profile->fn.tmi._swb_jbs_to_toroidal + + + + + + + + +qty.spike_profile->qty.a_optimal + + + + + + + + +qty.spike_profile->qty.diagnostics + + + + + + + + + +qty.spike_profile->qty.j_inductive_consistent + + + + + + + + +qty.spike_profile->qty.matched_jphi_perturb + + + + + + + + +qty.spike_profile->qty.new_jphi + + + + + + + + +qty.spike_profile->qty.target_jphi_perturb + + + + + + + + +qty.t_ls + + +t_ls (temperature length scale) + + + + + +qty.t_ls->gate.pressure_match + + + + + + + + +qty.t_ls->qty.te_draw + + + + + + + + +qty.target_jphi_perturb->fn.tmi._corrective_jphi_iteration + + + + + + + + +qty.te->fn.reconstruct_equilibrium + + + + + + + + +qty.te->artifact.baseline + + + + + + + + +qty.te->fn.imas._validate_pressure_completeness + + + + + + + + +qty.te->gate.sigma_priority_te + + + + + + + + +qty.te->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.te->fn.run.generate + + + + + + + + +qty.te->gate.pressure_match + + + + + + + + +qty.te->qty.p_recon + + + + + + + + +qty.te->qty.te_draw + + + + + + + + +qty.te_draw->fn.utils.store_equilibrium + + + + + + + + +qty.te_draw->qty.pres_tmp + + + + + + + + + +qty.te_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.te_perturb->art.eqdsk_bytes + + + + + + + + +qty.te_perturb->qty.p_thermal + + + + + + + + +qty.ti->fn.reconstruct_equilibrium + + + + + + + + +qty.ti->artifact.baseline + + + + + + + + +qty.ti->fn.imas._validate_pressure_completeness + + + + + + + + +qty.ti->gate.sigma_priority_ti + + + + + + + + +qty.ti->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.ti->fn.run.generate + + + + + + + + +qty.ti->gate.pressure_match + + + + + + + + +qty.ti->qty.p_imp + + + + + + + + +qty.ti->qty.p_recon + + + + + + + + +qty.ti->qty.ti_draw + + + + + + + + +qty.ti_draw->fn.utils.store_equilibrium + + + + + + + + +qty.ti_draw->qty.pres_tmp + + + + + + + + +qty.ti_perturb->ext.solve_with_bootstrap + + + + + + + + +qty.ti_perturb->art.eqdsk_bytes + + + + + + + + +qty.ti_perturb->qty.p_thermal + + + + + + + + +qty.zeff->artifact.baseline + + + + + + + + +qty.zeff->gate.sigma_priority_zeff + + + + + + + + +qty.zeff->fn.run._forward_solve_imas_baseline + + + + + + + + +qty.zeff->qty.Z_imp + + + + + + + + +qty.zeff->qty.Zeff_eq + + + + + + + + +qty.zeff_draw->qty.ni_draw + + + + + + + + +qty.zeff_draw->qty.ni_perturb + + + + + + + + +quantity.eqdsk_j_tor + + +eqdsk_j_tor + + + + + +quantity.eqdsk_j_tor->fn.tmi.fit_inductive_profile + + + + + + + + diff --git a/docs/flowchart/physics_workflow.pdf b/docs/flowchart/physics_workflow.pdf new file mode 100644 index 0000000..146c8e7 Binary files /dev/null and b/docs/flowchart/physics_workflow.pdf differ diff --git a/docs/flowchart/physics_workflow.svg b/docs/flowchart/physics_workflow.svg new file mode 100644 index 0000000..4df0307 --- /dev/null +++ b/docs/flowchart/physics_workflow.svg @@ -0,0 +1,613 @@ + + + + + + +bouquet_physics + + + + + +cluster_p0 + + +Inputs        (solid blue = required for its path, dashed = optional) + + + + +cluster_p1 + + +Baseline (once per slice) + + + + +cluster_p2 + + +repeat × +N +ens +   (each draw independent) + + + + + +gfile + +geqdsk +ψ +(R,Z), +p +, +q +, +j +φ +, separatrix + + + +recon + +GS reconstruction (geqdsk path) +fit inductive spline, full-Sauter +j +BS +j +φ + = +j +ind + + +j +BS + ;  match + +i +(1) by secant +targets: +I +p +, + +i + + + +gfile->recon + + + + + +kin + +kinetic profiles + σ( +ψ +N +) envelopes +n +e +, +T +e +, +T +i + (, +n +i +, +ω +tor +) +p-file or kinetic-fit netCDF + + + +kin->recon + + + + + +envel + +uncertainty envelope +σ +n +, +σ +T +, +σ +Zeff +, +σ + +  +  GP length scales + +n +, + +T +, + +j + + + +kin->envel + + + + + +ids + +IMAS/OMAS IDS +n +e +, +T +e +, +T +i +, +Z +eff +;   +j +ohmic +, +j +BS +, +j +NBI +; +p +fast +;  equilibrium anchors + + + +fsolve + +forward solve (IMAS/OMAS path) +keep IDS +j +ohmic +;  Sauter +j +BS + reconciliation +(diff: +j +BS,diff + = +j +BS +IDS + +j +BS +Sauter +  |  rescale) +anchors: +p +diff +, +j +φ,diff + ;   + +i + target = solved + +i +(1) + + + +ids->fsolve + + + + + +lcfs + +magnetics-only LCFS +(separatrix target override) + + + +lcfs->fsolve + + + + + +fixed + +fixed arrays +j +NBI +, +j +RF +, +p +fast +( +ψ +N +) + + + +rebuild + +rebuild total current +j +φ + = +j +ind + + +s +· +j +BS + (+ +j +BS,diff +) + +j +NBI + + +j +RF + (+ +j +φ,diff +) + + + +fixed->rebuild + + + + + +sigmas + +explicit σ profiles +or diagnostic σ source + + + +sigmas->envel + + + + + +quasi + +quasineutral densities +n +i + = +n +e + ( +Z +imp + +Z +eff +) / ( +Z +imp + − 1) + + + +recon->quasi + + + + + +fsolve->quasi + + + + + +quasi->envel + + + + + +gp + +GP profile sampling (Gibbs kernel) +draw +n +e +, +T +e +, +T +i +, +Z +eff +, +j +ind + ~ GP(baseline, σ, ℓ) +within envelopes; SOL included via +ψ +N,kin + grid + + + +envel->gp + + + + + +derive + +recompute derived +n +i + from drawn +Z +eff + (quasineutrality) +p +tot + = Σ +a + +e + +n +a + +T +a + + +p +imp + + +p +fast + (+ +p +diff +) + + + +gp->derive + + + + + +pgate + + +P +⟩ within 5% +of baseline? + + + +derive->pgate + + + + + +pgate->gp + + +resample + + + +boot + +bootstrap recompute (Sauter) +j +BS + = f( +n +, +T +, +Z +eff +)   (3 self-consistent iterations) +parallel→toroidal: +c + = 1 / (⟨ +R +⟩⟨1/ +R +⟩) +scale +s + ~ U(0.99, 1.01) · +s +0 + + + +pgate->boot + + +yes + + + +boot->rebuild + + + + + +limatch + + +i + matching +(optionally sample target ~ N( + +i +, +σ +ℓi +)) +scale +j +ind + + corrective iteration +until | + +i + − target| ≤ 5% + + + +rebuild->limatch + + + + + +limatch->limatch + + + iterate + + + +gssolve + +TokaMaker free-boundary GS solve +isoflux separatrix + +I +p + target +coil homotopy: bounds ±5% → ±2% → ±1% (warm-started) +VSC pair handles vertical control + + + +limatch->gssolve + + + + + +gssolve->gssolve + + + homotopy + passes + + + +agate + +accepted? +converged, + +i + in band, +q +0 + ≥ 1 (optional) + + + +gssolve->agate + + + + + +agate->gp + + +reject draw + + + +inspec + +in-spec tag +coil drift ≤ 2%;  VSC via quadrature-propagated σ + + + +agate->inspec + + +yes + + + +archive + +HDF5 ensemble archive (schema v2) +profiles, +j + components, g-/p-file bytes, +coil currents, targets, provenance (config) + + + +inspec->archive + + + + + +filter + +post-filtering (non-destructive) +boundary RMS ≤ 5 mm;  coil spec +⇒ selected (machine-realizable) sub-ensemble + + + +archive->filter + + + + + diff --git a/docs/flowchart/svg-pan-zoom.min.js b/docs/flowchart/svg-pan-zoom.min.js new file mode 100644 index 0000000..cadc36e --- /dev/null +++ b/docs/flowchart/svg-pan-zoom.min.js @@ -0,0 +1,3 @@ +// svg-pan-zoom v3.6.2 +// https://github.com/bumbu/svg-pan-zoom +!function s(r,a,l){function u(e,t){if(!a[e]){if(!r[e]){var o="function"==typeof require&&require;if(!t&&o)return o(e,!0);if(h)return h(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var i=a[e]={exports:{}};r[e][0].call(i.exports,function(t){return u(r[e][1][t]||t)},i,i.exports,s,r,a,l)}return a[e].exports}for(var h="function"==typeof require&&require,t=0;tthis.options.maxZoom*n.zoom&&(t=this.options.maxZoom*n.zoom/this.getZoom());var i=this.viewport.getCTM(),s=e.matrixTransform(i.inverse()),r=this.svg.createSVGMatrix().translate(s.x,s.y).scale(t).translate(-s.x,-s.y),a=i.multiply(r);a.a!==i.a&&this.viewport.setCTM(a)},i.prototype.zoom=function(t,e){this.zoomAtPoint(t,a.getSvgCenterPoint(this.svg,this.width,this.height),e)},i.prototype.publicZoom=function(t,e){e&&(t=this.computeFromRelativeZoom(t)),this.zoom(t,e)},i.prototype.publicZoomAtPoint=function(t,e,o){if(o&&(t=this.computeFromRelativeZoom(t)),"SVGPoint"!==r.getType(e)){if(!("x"in e&&"y"in e))throw new Error("Given point is invalid");e=a.createSVGPoint(this.svg,e.x,e.y)}this.zoomAtPoint(t,e,o)},i.prototype.getZoom=function(){return this.viewport.getZoom()},i.prototype.getRelativeZoom=function(){return this.viewport.getRelativeZoom()},i.prototype.computeFromRelativeZoom=function(t){return t*this.viewport.getOriginalState().zoom},i.prototype.resetZoom=function(){var t=this.viewport.getOriginalState();this.zoom(t.zoom,!0)},i.prototype.resetPan=function(){this.pan(this.viewport.getOriginalState())},i.prototype.reset=function(){this.resetZoom(),this.resetPan()},i.prototype.handleDblClick=function(t){var e;if((this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),this.options.controlIconsEnabled)&&-1<(t.target.getAttribute("class")||"").indexOf("svg-pan-zoom-control"))return!1;e=t.shiftKey?1/(2*(1+this.options.zoomScaleSensitivity)):2*(1+this.options.zoomScaleSensitivity);var o=a.getEventPoint(t,this.svg).matrixTransform(this.svg.getScreenCTM().inverse());this.zoomAtPoint(e,o)},i.prototype.handleMouseDown=function(t,e){this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),r.mouseAndTouchNormalize(t,this.svg),this.options.dblClickZoomEnabled&&r.isDblClick(t,e)?this.handleDblClick(t):(this.state="pan",this.firstEventCTM=this.viewport.getCTM(),this.stateOrigin=a.getEventPoint(t,this.svg).matrixTransform(this.firstEventCTM.inverse()))},i.prototype.handleMouseMove=function(t){if(this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),"pan"===this.state&&this.options.panEnabled){var e=a.getEventPoint(t,this.svg).matrixTransform(this.firstEventCTM.inverse()),o=this.firstEventCTM.translate(e.x-this.stateOrigin.x,e.y-this.stateOrigin.y);this.viewport.setCTM(o)}},i.prototype.handleMouseUp=function(t){this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),"pan"===this.state&&(this.state="none")},i.prototype.fit=function(){var t=this.viewport.getViewBox(),e=Math.min(this.width/t.width,this.height/t.height);this.zoom(e,!0)},i.prototype.contain=function(){var t=this.viewport.getViewBox(),e=Math.max(this.width/t.width,this.height/t.height);this.zoom(e,!0)},i.prototype.center=function(){var t=this.viewport.getViewBox(),e=.5*(this.width-(t.width+2*t.x)*this.getZoom()),o=.5*(this.height-(t.height+2*t.y)*this.getZoom());this.getPublicInstance().pan({x:e,y:o})},i.prototype.updateBBox=function(){this.viewport.simpleViewBoxCache()},i.prototype.pan=function(t){var e=this.viewport.getCTM();e.e=t.x,e.f=t.y,this.viewport.setCTM(e)},i.prototype.panBy=function(t){var e=this.viewport.getCTM();e.e+=t.x,e.f+=t.y,this.viewport.setCTM(e)},i.prototype.getPan=function(){var t=this.viewport.getState();return{x:t.x,y:t.y}},i.prototype.resize=function(){var t=a.getBoundingClientRectNormalized(this.svg);this.width=t.width,this.height=t.height;var e=this.viewport;e.options.width=this.width,e.options.height=this.height,e.processCTM(),this.options.controlIconsEnabled&&(this.getPublicInstance().disableControlIcons(),this.getPublicInstance().enableControlIcons())},i.prototype.destroy=function(){var e=this;for(var t in this.beforeZoom=null,this.onZoom=null,this.beforePan=null,this.onPan=null,(this.onUpdatedCTM=null)!=this.options.customEventsHandler&&this.options.customEventsHandler.destroy({svgElement:this.svg,eventsListenerElement:this.options.eventsListenerElement,instance:this.getPublicInstance()}),this.eventListeners)(this.options.eventsListenerElement||this.svg).removeEventListener(t,this.eventListeners[t],!this.options.preventMouseEventsDefault&&h);this.disableMouseWheelZoom(),this.getPublicInstance().disableControlIcons(),this.reset(),c=c.filter(function(t){return t.svg!==e.svg}),delete this.options,delete this.viewport,delete this.publicInstance,delete this.pi,this.getPublicInstance=function(){return null}},i.prototype.getPublicInstance=function(){var o=this;return this.publicInstance||(this.publicInstance=this.pi={enablePan:function(){return o.options.panEnabled=!0,o.pi},disablePan:function(){return o.options.panEnabled=!1,o.pi},isPanEnabled:function(){return!!o.options.panEnabled},pan:function(t){return o.pan(t),o.pi},panBy:function(t){return o.panBy(t),o.pi},getPan:function(){return o.getPan()},setBeforePan:function(t){return o.options.beforePan=null===t?null:r.proxy(t,o.publicInstance),o.pi},setOnPan:function(t){return o.options.onPan=null===t?null:r.proxy(t,o.publicInstance),o.pi},enableZoom:function(){return o.options.zoomEnabled=!0,o.pi},disableZoom:function(){return o.options.zoomEnabled=!1,o.pi},isZoomEnabled:function(){return!!o.options.zoomEnabled},enableControlIcons:function(){return o.options.controlIconsEnabled||(o.options.controlIconsEnabled=!0,s.enable(o)),o.pi},disableControlIcons:function(){return o.options.controlIconsEnabled&&(o.options.controlIconsEnabled=!1,s.disable(o)),o.pi},isControlIconsEnabled:function(){return!!o.options.controlIconsEnabled},enableDblClickZoom:function(){return o.options.dblClickZoomEnabled=!0,o.pi},disableDblClickZoom:function(){return o.options.dblClickZoomEnabled=!1,o.pi},isDblClickZoomEnabled:function(){return!!o.options.dblClickZoomEnabled},enableMouseWheelZoom:function(){return o.enableMouseWheelZoom(),o.pi},disableMouseWheelZoom:function(){return o.disableMouseWheelZoom(),o.pi},isMouseWheelZoomEnabled:function(){return!!o.options.mouseWheelZoomEnabled},setZoomScaleSensitivity:function(t){return o.options.zoomScaleSensitivity=t,o.pi},setMinZoom:function(t){return o.options.minZoom=t,o.pi},setMaxZoom:function(t){return o.options.maxZoom=t,o.pi},setBeforeZoom:function(t){return o.options.beforeZoom=null===t?null:r.proxy(t,o.publicInstance),o.pi},setOnZoom:function(t){return o.options.onZoom=null===t?null:r.proxy(t,o.publicInstance),o.pi},zoom:function(t){return o.publicZoom(t,!0),o.pi},zoomBy:function(t){return o.publicZoom(t,!1),o.pi},zoomAtPoint:function(t,e){return o.publicZoomAtPoint(t,e,!0),o.pi},zoomAtPointBy:function(t,e){return o.publicZoomAtPoint(t,e,!1),o.pi},zoomIn:function(){return this.zoomBy(1+o.options.zoomScaleSensitivity),o.pi},zoomOut:function(){return this.zoomBy(1/(1+o.options.zoomScaleSensitivity)),o.pi},getZoom:function(){return o.getRelativeZoom()},setOnUpdatedCTM:function(t){return o.options.onUpdatedCTM=null===t?null:r.proxy(t,o.publicInstance),o.pi},resetZoom:function(){return o.resetZoom(),o.pi},resetPan:function(){return o.resetPan(),o.pi},reset:function(){return o.reset(),o.pi},fit:function(){return o.fit(),o.pi},contain:function(){return o.contain(),o.pi},center:function(){return o.center(),o.pi},updateBBox:function(){return o.updateBBox(),o.pi},resize:function(){return o.resize(),o.pi},getSizes:function(){return{width:o.width,height:o.height,realZoom:o.getZoom(),viewBox:o.viewport.getViewBox()}},destroy:function(){return o.destroy(),o.pi}}),this.publicInstance};var c=[];e.exports=function(t,e){var o=r.getSvg(t);if(null===o)return null;for(var n=c.length-1;0<=n;n--)if(c[n].svg===o)return c[n].instance.getPublicInstance();return c.push({svg:o,instance:new i(o,e)}),c[c.length-1].instance.getPublicInstance()}},{"./control-icons":1,"./shadow-viewport":2,"./svg-utilities":5,"./uniwheel":6,"./utilities":7}],5:[function(t,e,o){var l=t("./utilities"),s="unknown";document.documentMode&&(s="ie"),e.exports={svgNS:"http://www.w3.org/2000/svg",xmlNS:"http://www.w3.org/XML/1998/namespace",xmlnsNS:"http://www.w3.org/2000/xmlns/",xlinkNS:"http://www.w3.org/1999/xlink",evNS:"http://www.w3.org/2001/xml-events",getBoundingClientRectNormalized:function(t){if(t.clientWidth&&t.clientHeight)return{width:t.clientWidth,height:t.clientHeight};if(t.getBoundingClientRect())return t.getBoundingClientRect();throw new Error("Cannot get BoundingClientRect for SVG.")},getOrCreateViewport:function(t,e){var o=null;if(!(o=l.isElement(e)?e:t.querySelector(e))){var n=Array.prototype.slice.call(t.childNodes||t.children).filter(function(t){return"defs"!==t.nodeName&&"#text"!==t.nodeName});1===n.length&&"g"===n[0].nodeName&&null===n[0].getAttribute("transform")&&(o=n[0])}if(!o){var i="viewport-"+(new Date).toISOString().replace(/\D/g,"");(o=document.createElementNS(this.svgNS,"g")).setAttribute("id",i);var s=t.childNodes||t.children;if(s&&0 **Temporary working document** (2026-07-01). Review of the class-API branch's user -> experience and the HDF5 output architecture, with a concrete change plan. -> Delete (or fold into `docs/CHANGES_SUMMARY.md`) before merging to `main`. -> -> Evidence base: direct read of `bouquet/{config,run,filtering,utils,paths}.py`; -> walkthrough of the three `examples/D3D-like/bouquet_D3Dlike_*_example.ipynb` -> notebooks; the downstream shot notebooks + debug scripts in the IDA_run repo -> (9 structurally identical workflow notebooks, `shot_debug/*.py`); and a full -> map of every h5 write/read path. - ---- - -## STATUS — all phases implemented 2026-07-02 (187 tests green) - -| Phase | Status | -|---|---| -| 1 config serialization + provenance (F8/F9/F10) + F25 | ✅ | -| 2 `BouquetArchive` reader (F13, F12-read) | ✅ | -| 3 de-thread (header, scan_key) (F1, F7) | ✅ (example-notebook rewrite deferred) | -| 4 schema v2 — **clean break, no legacy** (F11/F12/F15/F16a) | ✅ (adversarial review caught 1 silent coil bug, fixed) | -| 5 config/API simplifications (F3/F4) | ✅ (5.1 jphi-default **won't do**; imas-summary formatting deferred) | -| 6 sweeps + plotting (F5/F6) | ✅ (6.3 IDA-run templating **won't do**) | -| 7 parallel hardening (F17–F26) | ✅ (was already done; F25 finished with Phase 1) | - -**Won't-do (user decisions):** 5.1 (keep `jphi_scalar_sigma=0.10`), 6.3/F8 -(keep Nelson's split IDA_run notebooks). **Deferred (cosmetic):** rewriting the -3 example notebooks to run-object forms (Phase 3.5); reconstruction-style IMAS -baseline summary (5.4). New modules: `bouquet/schema.py`, `bouquet/archive.py`. -This document can be deleted / folded into `docs/CHANGES_SUMMARY.md` at merge. - ---- - -## Verdict - -The core design is solid and should not be reworked: - -- Typed dataclass config with early `__post_init__` validation. -- Staged orchestrator (`setup_solver → prepare_baseline → generate → filter → - export`) with an inspection gate at every stage and a `run()` convenience. -- Non-destructive filter flags (`passes_*`, `selected = AND(flags)`) + pruned - `export_filtered` copy. -- The per-path workflow guard (`run._validate_workflow`) that raises on - known-bad knob combos. -- `paths.py` resolution (env var → hint → candidates → walk-up, actionable - errors). -- Byte-opaque eqdsk/pfile storage (bit-perfect round-trip). -- Solver-chatter capture to `reconstruction_log` / `generation_log`. - -The UX debt concentrates in four places: - -1. The `(header, scan_key)` string pair is manually re-threaded into every - post-run call — fragile, and mismatches fail **silently**. -2. Notebooks restate ~10 config values that are (or should be) defaults, copied - verbatim across 12+ notebooks in two repos. -3. No high-level archive reader — downstream scripts hand-roll h5 tree walking - and byte extraction (schema knowledge duplicated outside the package). -4. No provenance in the h5 file (no schema version, package version, or config - snapshot). - ---- - -## Part 1 — findings - -### 1.1 UX / API surface - -**F1. `(header, scan_key)` re-threading (biggest friction + silent-failure source).** -The `Bouquet` object knows both, yet every notebook does: - -```python -bq.plot_traces(HEADER + '.h5', scan_key=2100, ...) # wants the .h5 path -bq.filter_coil_currents(HEADER, scan_key=2100) # wants the bare header -sel = bq.select_indices(HEADER, scan_key=2100, selection='selected') -``` - -- A wrong `scan_key` returns empty results with no error. -- Renaming `HEADER` mid-notebook silently reads a stale file (observed in the - omas notebook: `HEADER_FULL = HEADER + '_full'` mid-run; and in IDA_run). -- Inconsistent path conventions: filtering accepts header-or-path - (`filtering._resolve`), plotting wants the `.h5` path. -- `Bouquet.plot_bouquet()` and `Bouquet.filter()` already exist and auto-wire - header/scan_key, but the notebooks call the module-level functions with - strings instead (they appear to predate the methods). - -**F2. The "validated production settings" block restates defaults.** -The same ~10-line block appears verbatim in all 3 example notebooks and all 9 -IDA_run shot notebooks: - -```python -run.uncertainty.ne_scalar_sigma = 0.05 # == default -run.uncertainty.te_scalar_sigma = 0.05 # == default -run.uncertainty.ti_scalar_sigma = 0.10 # == default -run.uncertainty.jphi_scalar_sigma = 0.05 # DEFAULT IS 0.10 — real delta -run.uncertainty.zeff_scalar_sigma = 0.05 # == default -run.uncertainty.n_ls, ..., = 0.5, 0.4, 0.25 # == defaults -run.generation.seed = 42 # real delta (default None) -run.generation.l_i_tolerance = 0.05 # == default -run.generation.recalculate_j_BS = True # == default -run.generation.jBS_scale_range = (0.99, 1.01) # == default -run.filtering.inspec_F_max = 0.02 # == default -run.filtering.inspec_VSC_max = 0.02 # == default -run.filtering.rms_max_mm = 5.0 # == default -``` - -Only `jphi_scalar_sigma` and `seed` differ from the dataclass defaults. If -0.05 is the validated production value, the default in `config.py` is wrong; -align it and the whole block collapses to one line. - -**F3. Path asymmetry at the baseline gate.** -geqdsk: `run.reconstruct()` — one call, curated PASS/CHECK fidelity summary. -IMAS: `run.setup_solver(); run.prepare_baseline()` — two calls, one-line -`[imas forward-solve]` print. A reader of both notebooks concludes the IMAS -path has no validation step. - -**F4. Workflow knobs encode an enum as booleans.** -`_validate_workflow` enforces that only two combinations of -`perturb_jind_in_anchor` / `jBS_baseline_mode` / (`isolate_edge_jBS`) are -valid — `imas → diff+C`, `geqdsk → standard l_i loop`. That's a missing named -preset; the guard + four flags + `allow_unsafe_workflow` is the hard way to -say `workflow = "imas-diff-c" | "geqdsk-standard" | "custom"`. - -**F5. Multi-slice sweeps are boilerplate, and there are two overlapping -organizing mechanisms.** The omas timeseries loop (`set_slice → prepare → -generate → filter → export` + hand-collected `li/Ip/counts` dict) is ~15 lines -repeated per notebook; `parallel.py` re-implements its own per-slice loop. -Separately: `scan//` inside one file AND one-file-per-slice both exist, -and the notebooks use **both at once** (per-slice headers and per-slice -scan_keys). Every downstream call then needs both coordinates. - -**F6. Plotting surface proliferation.** `__all__` exports ~20 plot functions -including near-duplicates (`plot_bouquet` / `plot_imas_bouquet` / -`plot_geqdsk_bouquet` / `plot_pfile_bouquet`). `source_kind` is already stored -in the baseline attrs precisely so plotting can dispatch on path. - -**F7. Filter summary duplication.** `run.filter()` already prints the curated -generation summary, but the notebooks then re-call `filter_coil_currents` / -`filter_boundaries` / `select_indices` manually to print counts and get the -distribution figures (`run.filter()` hardcodes `plot=False`). - -**F8. Per-shot notebooks in IDA_run are full copies differing in 5 strings** -(`GFILE`, `IDA`, `TIME`, `HEADER`, `SCAN_KEY`). That's a config file, not a -notebook copy — blocked on config serialization (see F9/P1). - -**F9. `BouquetConfig` has no serialization.** Needed independently by: h5 -provenance, per-shot templating, and `parallel.py` shipping configs to -SLURM workers. - -### 1.2 HDF5 architecture - -Current schema (as written by this branch — `GenerationConfig.scan_key` -defaults to `0`, so the class API always writes the `scan/` layout): - -``` -{header}.h5 -└── scan/{scan_key}/ - ├── _baseline/ - │ ├── psi_N, n_e, T_e, n_i, T_i, pressure[, pressure_thermal] - │ ├── j_phi, [j_BS, j_inductive] (all "[unit]"-suffixed names) - │ ├── sigma_ne/te/ni/ti/jphi, [sigma_aux_*], [aux_*] - │ ├── baseline.eqdsk, [baseline.pfile], [recon_lcfs_ref], [x_points] - │ ├── [coil_currents [A] + coil_names dataset] - │ └── attrs: Ip_target, l_i_target, source_kind, [diverted] - └── {count}/ (integer; gaps allowed) - ├── {header}_{key}_{count}.eqdsk (np.void bytes) - ├── [{...}.pfile] - ├── psi_N, j_phi, j_BS, j_inductive, n_e, T_e, n_i, T_i, w_ExB - ├── [pressure, pressure_thermal, psi_N_kinetic, Zeff, j_BS,edge] - ├── [coil_currents [A]] (+ coil_names JSON attr) - ├── [perturbed_lcfs_ref, x_points, aux_*] - └── attrs: l_i(1), l_i(3), count, homotopy_*, max_*_drift_pct, - in_spec, inspec_*, l_i_target_used, [diverted], - [passes_coil_filter, passes_boundary_filter, selected] -``` - -**F10. No provenance.** No schema version, no `bouquet.__version__`, no -timestamp, no record of the config that produced the file. - -**F11. Eqdsk dataset names embed `{header}_{scan}_{count}`.** -Consequences: `load_equilibrium` must *reconstruct* the exact string; -`merge_archives` must rename every eqdsk/pfile dataset; renaming the file -breaks lookups. Meanwhile `filtering.py` ignores the name and scans for the -`.eqdsk` suffix — two lookup strategies for the same dataset in one codebase. - -**F12. Dual layout (flat vs `scan/`).** Flat only exists for pre-class files, -yet every reader branches on it and downstream users have learned to probe for -it (`if 'scan' in hf: ... else:` in IDA_run `shot_debug/169510_debug.py`). - -**F13. No archive reader class.** `169510_debug.py` contains ~100 lines of -hand-rolled tree-walking, `.eqdsk`-suffix scanning, byte extraction, and -`PFile.from_bytes` — package schema knowledge duplicated downstream. The -in-package idiom is also awkward: -`bq.read_eqdsk_from_bytes(d['eqdsk_bytes'], bq.read_geqdsk)`. - -**F14. `merge_archives` trusts shard baselines.** Copies the baseline from the -first non-empty shard with no check that other shards' baselines match -(a worker config drift would merge silently). - -**F15. Coil-current representation is split.** Values dataset + JSON-names -attr per draw; values dataset + names *dataset* in the baseline. Two -zip-at-read conventions. - -**F16. Units live in dataset names** (`"j_phi [A m^-2]"`). Forces exact-string -knowledge into every reader and makes ad-hoc h5py access awkward. (Schema-v2 -material only — breaking.) - ---- - -## Part 2 — the plan - -Ordered so each phase is independently landable; phases 1–3 are the payoff -core. No physics code changes anywhere in this plan. - -### Phase 1 — config serialization + h5 provenance *(unlocks F9, F10, F8)* ✅ IMPLEMENTED 2026-07-02 - -1. ✅ `bouquet/config.py`: `BouquetConfig.to_dict()` / `from_dict()` + - `to_json` / `from_json`. ndarray fields (isoflux, `sigma_profiles`, `aux_*`, - fixed components, `profile_overrides`) encode as `{"__ndarray__": [...]}` and - restore to ndarray; source recorded via a `"source_type"` discriminator - (inferred from keys if absent). Round-trip test exercises every optional - field on both source types (`tests/test_config.py::TestSerialization`). -2. ✅ `bouquet/utils.py` `write_provenance(h5, config, scan_key)` called from - `Bouquet.generate`: file-level attrs `schema_version` (`utils.SCHEMA_VERSION`, - **currently `1`** — the class-API `scan/` layout; Phase 4 bumps it to `2`), - `bouquet_version`, `created` (set once, ISO), `updated`, and a `config_json` - dataset at the file root **and** mirrored per `scan//` group. - *(Deviation from the plan: version starts at 1 to honestly reflect the - current on-disk layout; the v2 stamp lands with the Phase-4 writer changes.)* -3. ✅ `bouquet/parallel.py`: SLURM bundle is now `{job}_bundle.json` - (`config.to_dict()` + scalar params) loaded via `BouquetConfig.from_dict`; - `pickle` dropped (F25 — was blocked on this phase). -4. ✅ `bq.load_config(h5path_or_header, scan_key=None)` → `BouquetConfig` - (per-scan `config_json` first, else file root; raises a clear `KeyError` - on pre-provenance files). Tests in `tests/test_config.py::TestProvenance`. - -### Phase 2 — `BouquetArchive` reader class *(fixes F13, F1-read-side, F12-read-side)* ✅ IMPLEMENTED 2026-07-02 - -Done as specified: new `bouquet/archive.py` with `BouquetArchive` / `ScanView` / -`DrawView` (lazy, open-per-access). `ar.scan_keys` (flat → `[None]`), -`ar[key]` / `ar.scan()`, `sc.indices/baseline/all/selected/excluded`, `sc[i]`, -`d.li1/li3/attrs/flags/selected/profiles`, `d.equilibrium()`, `d.pfile()`, -`d.extract(...)`, `ar.provenance` (Phase-1 attrs + `load_config`). -`Bouquet.archive` property added. Eqdsk/pfile by **suffix scan** (v2 fixed name -first, else `.eqdsk`/`.pfile`) — verified it reads the golden fixture where -`load_equilibrium`'s exact-name lookup fails (a live demonstration of F11). -The functional readers stay the public API and are reused internally -(`select_indices`, `list_equilibrium_indices`, `load_baseline_profiles`, -`read_filter_flags`, `read_eqdsk_from_bytes`). Tests: `tests/test_archive.py` -(golden round-trip + legacy/v2 suffix-scan). - -**Not done (deferred, non-breaking):** demoting `read_eqdsk_from_bytes` from -`__all__` — kept exported for now; revisit at merge. - -Original spec follows. - -New module `bouquet/archive.py`; single authoritative home for schema -knowledge. The existing functional readers -(`load_equilibrium`, `select_indices`, …) become thin wrappers (keep them — -they're public API — but implement them on the archive internally). - -```python -ar = bq.BouquetArchive("run.h5") # or bq.BouquetArchive(run) / run.archive -ar.scan_keys # ['4400'] (always list; flat legacy → [None]) -sc = ar["4400"] # ScanView (default scan if only one) -sc.indices, sc.baseline # gap-tolerant indices; baseline dict/handle -sc.selected, sc.excluded, sc.all # lists of DrawView, per filter flags -d = sc[3] # DrawView (lazy) -d.li1, d.li3, d.flags, d.attrs # scalars + filter/spec metadata -d.profiles # dict of named arrays (psi_N, j_phi, ...) -d.equilibrium() # parsed GEQDSKEquilibrium from stored bytes -d.pfile() # parsed PFile (None if absent) -d.extract("out/", formats=("geqdsk", "pfile")) # write files, return paths -for d in sc.selected: ... -``` - -Implementation notes: -- Eqdsk/pfile lookup by **suffix scan** (the `filtering.py` strategy), so it - works on legacy names and the phase-4 fixed names alike. -- `ar.provenance` property surfaces the phase-1 attrs/config. -- `Bouquet.archive` property returns `BouquetArchive(self.config.output_header)`. -- Port the readable parts of `filtering.read_filter_flags` / - `utils.load_equilibrium` here; deprecate `read_eqdsk_from_bytes` from - `__all__` (keep importable). -- Tests: build a small archive via the existing golden-fixture path; assert - round-trip against `load_equilibrium` outputs. - -### Phase 3 — kill the `(header, scan_key)` re-threading *(fixes F1, F7)* ✅ IMPLEMENTED 2026-07-02 (item 5 deferred) - -1. ✅ `utils._resolve_h5` now duck-types a `Bouquet` (→ `config.output_header`) - / `BouquetArchive` (→ `.path`) / header / path, so **every** reader accepts a - run or archive as the first arg; `filtering._resolve` delegates to it. - `utils._default_scan_key(ref, scan_key)` fills a missing key from a passed - `Bouquet`. -2. ✅ `select_indices` raises a listing `KeyError` on an unknown explicit - `scan_key` (`filtering._require_scan_key`) — the silent-empty failure is gone. - *(Applied at `select_indices`, the primary offender; the same guard can be - dropped into the other accessors trivially — left as a fast follow.)* -3. ✅ `Bouquet.plot_traces()` / `plot_coil_currents()` / `plot_spec_summary()` / - `selected_indices()` added (auto-wire header + `scan_key`), mirroring - `plot_bouquet()`. -4. ✅ `run.filter(plot=True)` returns the coil + boundary distribution figures - under `summary["figures"]` (F7). -5. ⬜ **Deferred**: rewriting the 3 example notebooks to the run-object forms - end-to-end. The API now supports it (`run.plot_traces()`, - `run.selected_indices()`, pass `run` to any reader); the notebook edits are a - separate, low-risk sweep left for the notebook-proofing pass. - -Tests: `tests/test_archive.py::TestDethread`. Original spec follows. - -1. Module-level readers (`plot_*`, `filter_*`, `select_indices`, - `read_filter_flags`, `export_filtered`, `load_*`): accept a `Bouquet` or - `BouquetArchive` as the first argument in addition to header/path. - One shared `_coerce_archive(obj)` helper; when given a `Bouquet`, default - `scan_key` to `config.generation.scan_key`. -2. `select_indices` / plotting: **raise `KeyError`** (or warn loudly) when an - explicit `scan_key` is absent from the file, listing available keys. - Silent-empty is the current failure mode. -3. Add the missing thin methods on `Bouquet`, mirroring `plot_bouquet`: - `plot_traces()`, `plot_coil_currents()`, `selected_indices()`. -4. `run.filter(plot=False)` → add `plot=True` support (return the two - distribution figures alongside the summary dict). -5. Update the 3 example notebooks to use the run-object forms end-to-end - (no bare `HEADER` strings after construction). - -### Phase 4 — schema v2 (CLEAN BREAK, no legacy) *(fixes F11, F12, F15, F16)* ✅ IMPLEMENTED 2026-07-02 - -**Decision (user 2026-07-02): no active users yet, so this is a clean break — -no legacy readers / flat fallback / schema-version gating.** New `bouquet/schema.py` -is the single source of truth (`PROFILE_UNITS`, `write_profile`, fixed names). - -- ✅ **F16(a) full**: profile datasets renamed to **bare** names (`j_phi`, `n_e`, - `pressure`, …) with the unit in `ds.attrs["units"]`. Exhaustive global rename - of the 17 bracketed literals (171 sites) + writer routed through - `schema.write_profile` (30 creates). Confirmed the literals were only - dataset-names/keys (plot labels use mathtext), so the rename was mechanical. -- ✅ **F11**: draws + baseline store fixed `eqdsk` / `pfile` names (no - `{header}_{scan}_{count}` embedding, no `baseline.` prefix); `_eqdsk_dataset_name` - returns `"eqdsk"`; `merge_archives` rename step deleted. -- ✅ **F12**: writer is scan-only (already true); the `.eqdsk`/`.pfile` suffix-scan - readers replaced with fixed-name lookups. -- ✅ **F15**: coil currents = `coil_currents` values dataset + `coil_names` string - **dataset** in BOTH draw and baseline groups (per-draw was a JSON attr); - readers use `utils._read_coil_names`. -- ✅ `schema_version` now **2** (`utils.SCHEMA_VERSION` imports from `schema`). -- ✅ Golden fixture migrated in place to v2 (bare names + units, fixed byte - names, coil_names dataset); tests updated. - -**Verification (the user-requested second pass):** -- Full suite **187 pass** on v2 (incl. 2 new coil-drift regression tests). -- End-to-end: a real `reconstruct → generate → filter` through the NEW writer - produces a v2 file that load_equilibrium / BouquetArchive / load_config / - plot_bouquet / plot_traces / plot_coil_currents all read. -- **Adversarial diff review caught one real (silent) bug**: `plot_coil_currents` - still read per-draw `coil_names` from the old JSON attr → every per-draw - coil-drift cell was NaN on a v2 file (no error, just an empty heatmap). Fixed - to read the dataset (matching the baseline path) + added a - `test_plot_coil_currents_finite_drift` regression. Also aligned the stale - `SCHEMA_VERSION=1`, removed dead `_eqdsk_dataset_name` imports, fixed the - `merge_archives` docstring. No other reader/writer mismatches found. - -**Deviation from the original plan:** F14 (merge baseline verification) already -landed in Phase 7; F16 units-as-attrs was done as the full bare-name rename -(a), not skipped. Original v2-with-legacy spec follows. - -Gate all of these behind the `schema_version = 2` stamp from phase 1. - -1. **Fixed in-group dataset names**: draws store `eqdsk` / `pfile`; baseline - stores `eqdsk` / `pfile` (drop the `baseline.`-prefix duplication too). - Readers already suffix-scan after phase 2, so legacy files keep working. - `merge_archives` deletes its rename step entirely. -2. **Scan layout only**: writers drop the flat branch (`_group_path` always - emits `scan//`); readers keep flat fallback for legacy files. -3. **Unify coil-current storage**: one representation both places — - `coil_currents` values dataset + `coil_names` string dataset (baseline - convention wins). Reader zips; legacy JSON-attr fallback retained. -4. **`merge_archives` baseline verification**: compare `Ip_target`, - `l_i_target`, and `psi_N`/`j_phi` array hashes across shards; raise on - mismatch (message: which shard, which field). -5. *(Optional, decide before stamping v2)* **Units to attrs**: dataset names - `j_phi`, `n_e`, … with `ds.attrs["units"]`. Touches every reader/writer — - only worth it bundled with 1–3 since v2 is the one-time break. If skipped, - keep the bracketed names forever; do not do this later as a v3. - -### Phase 5 — config/API simplifications *(fixes F2, F4, F3)* ✅ IMPLEMENTED 2026-07-02 (5.1 won't-do; imas-summary formatting deferred) - -- ✅ **5.2 `run.describe()`** (below). -- ✅ **5.3 workflow preset** — `GenerationConfig.workflow = "auto" | "geqdsk-standard" - | "imas-diff-c" | "custom"`. `_validate_workflow` now folds `allow_unsafe_workflow` - into `"custom"` (deprecated alias, still honoured), asserts named presets match - the source, and validates the value in `__post_init__`. `"auto"` keeps the - existing per-source flag resolution. -- ✅ **5.4 symmetric `run.prepare()`** = `setup_solver()+prepare_baseline()` on - either path (`reconstruct()` stays the g-file alias). ⬜ The IMAS baseline still - prints its one-line `[imas forward-solve] converged (…Ip%…TokaMaker vs IDS li…)` - summary (which already carries the key validation metrics) rather than a - reconstruction-style block — richer formatting deferred as cosmetic. - -1. ❌ **WON'T DO (user decision 2026-07-02): keep `jphi_scalar_sigma = 0.10`.** - The default stays; notebooks continue to set 0.05 explicitly. -2. ✅ **`run.describe()`** implemented — prints/returns the config grouped by - section, showing source paths (required) + only the knobs that differ from - their dataclass default (safe ndarray/dict handling). Replaces the ~60-line - commented knob-reference cell. *(Original spec:)* print the config grouped by - section, showing only - non-default values (plus source paths + output header). Replaces the - ~60-line commented knob-reference cell that is already diverging between - the geqdsk and omas notebooks. -3. **Workflow preset enum**: `GenerationConfig.workflow: str = "auto"` with - values `"auto" | "imas-diff-c" | "geqdsk-standard" | "custom"`. - - `"auto"`: resolved per source type at `generate()` (what - `from_geqdsk`/`from_imas` hardcode today). - - Presets set `perturb_jind_in_anchor` / `jBS_baseline_mode` / - `isolate_edge_jBS`; `"custom"` leaves flags as-is and downgrades the - guard to a warning (subsumes `allow_unsafe_workflow`, which stays as a - deprecated alias). - - `_validate_workflow` reduces to: preset says X, flags say Y. -4. **Symmetric baseline gate**: `run.prepare()` = `setup_solver()` + - `prepare_baseline()` on either path (`reconstruct()` stays as the - recon-path alias); add `_print_imas_summary()` in the same visual format - as the reconstruction block (Ip err, TokaMaker vs IDS li_1/li_3, SWB/FUSE - peak ratio, nl its, boundary source). - -### Phase 6 — sweeps + notebooks *(fixes F5, F6, F8)* ✅ IMPLEMENTED 2026-07-02 (6.3 won't-do) - -- ✅ **6.1 `run.run_slices(times, scan_keys=None, header=None, export=False)`** — - wraps the `set_slice → prepare_baseline → generate → filter` loop into one - archive (one `scan_key`/slice, defaulting to `round(t*1000)` ms), returns - `{scan_key: {time, n_all, n_sel, l_i, Ip}}`. (A full IMAS multi-slice run isn't - in the unit suite — exercised via the notebooks.) -- ✅ **6.2 plotting surface** — `plot_bouquet` is already source-agnostic; the - wrapper `plot_imas_bouquet` demoted from `__all__` (still importable). The - source-specific *input* viewers (`plot_geqdsk_bouquet`/`plot_pfile_bouquet`) - stay advertised — they're the §1 input plotters, not `plot_bouquet` duplicates. -- ❌ **6.3 IDA_run JSON templating (F8): WON'T DO** (user 2026-07-02) — the - per-shot notebooks are Nelson's originals; kept split (plus our E_r/rotation - adds). The Phase-1 serialization is in place if that ever changes. - -Original spec follows. - -1. **`run.run_slices(times, scan_keys=None, header=None)`**: wraps the - `set_slice` loop; one output file, one `scan_key` per slice by default - (per-slice headers remain possible but stop being the documented pattern); - returns `{scan_key: {n_all, n_sel, li, Ip, ...}}`. Refactor the - `parallel.py` per-slice loop onto the same iteration helper. -2. **Plotting consolidation**: `plot_bouquet` dispatches on stored - `source_kind`; demote `plot_imas_bouquet` / `plot_geqdsk_bouquet` / - `plot_pfile_bouquet` from `__all__` (keep importable). Trim `__all__` - plotting exports to the ~8 actually used in notebooks. -3. **IDA_run templating** (downstream repo, after phases 1+5): one template - notebook that loads a per-shot JSON (5 paths/values) via - `BouquetConfig.from_json`, replacing the 9 copied notebooks. Optional - `python -m bouquet run shot.json` CLI entry point in `__main__.py`. - -### Suggested sequencing / sizing - -| Phase | Depends on | Size | Risk | Status | -|---|---|---|---|---| -| 1 config serialization + provenance | — | S–M | low | ✅ done 2026-07-02 | -| 2 `BouquetArchive` | — (better after 1) | M | low (read-only) | ✅ done 2026-07-02 | -| 3 de-thread header/scan_key | 2 | S | low | ✅ done 2026-07-02 (notebook rewrite deferred) | -| 4 schema v2 | 1, 2 | M | medium (writer change) | ✅ done 2026-07-02 (clean break, F16a full; review caught 1 silent bug, fixed) | -| 5 config simplifications | — | S | low | ✅ done 2026-07-02 (5.1 **won't do**; imas-summary formatting deferred) | -| 6 sweeps + notebooks | 1, 3, 5 | M | low | ✅ done 2026-07-02 (6.3 IDA templating **won't do** — keep Nelson's split notebooks) | - -Regression guardrails for every phase: `tests/test_golden_bouquet.py` must -pass unchanged on a **pre-branch legacy h5** (add one as a fixture if not -already covered), and the geqdsk + omas example notebooks must run end-to-end. -For phase 5.1 (default `jphi_scalar_sigma` change), verify draw yield on both -the D3D-like geqdsk and OMAS testbeds before landing. - ---- - -## Part 3 — parallel mode (`bouquet/parallel.py`, laptop + SLURM) - -Doctrine this section is checked against: **every TokaMaker instance needs its -own process and its own core** (`OFT_env` per-process singleton; `nthreads=1` -for determinism and to avoid DLSODE hangs on stiff slices). - -Already correct: spawn context (fork would break OFT's cached state); -BLAS/OpenMP env pinned before workers spawn (with restore); laptop cross-worker -baseline guard (`li`/`Ip` @ rtol 1e-6); contiguous renumber + eqdsk rename in -merge; `OMP_PROC_BIND=close OMP_PLACES=cores` on SLURM; honest -"parallel ≠ bit-identical to serial" docstring. - -### Contamination risks - -**F17. Stale-shard contamination (bug — laptop AND slurm).** -`run_shard` writes `{header}_w{i}.h5` but `initialize_equilibrium_database` -opens **append** and `store_equilibrium` only deletes the group it rewrites. -Leftover shards (crashed laptop run never reaches cleanup; cancelled SLURM -array; re-run with fewer draws/worker) keep their old higher-index draws, and -`merge_archives` copies every integer group it finds → merged bouquet silently -contains previous-config draws. *Fix: `run_shard` removes its shard file -before generating (one line).* - -**F18. No baseline cross-check on SLURM.** Laptop checks worker `li`/`Ip` -before merging; the `python -m bouquet.parallel merge` path checks nothing. -Heterogeneous nodes (AVX2 vs AVX512 BLAS/libm paths) can break bit-identical -baselines even at `nthreads=1`. Each shard's `_baseline` attrs already store -`Ip_target`/`l_i_target` → *fix: do the check inside `merge_archives` itself -(covers both backends, zero extra plumbing).* - -**F19. `threads_per_worker>1` violates the one-core doctrine — and the -committed example does it.** `run_shard` maps `threads_per_worker` → -`cfg.solver.nthreads`; `examples/D3D-like/slurm_jobs/*_array.sbatch` ships -`--cpus-per-task=4` / `OMP_NUM_THREADS=4`. Consequences: ±1.3% li_1 jitter → -workers accept draws against **different** `l_i_target`s (contamination; -silent on SLURM per F18), plus occasional DLSODE hard-hangs → array task burns -its time limit and loses its whole shard (yield). Laptop's baseline guard -would at least raise. *Fix: regenerate the example at 1 cpu/task; warn or -require an explicit override for `threads_per_worker > 1`.* - -**F20. Seeding soft spots.** Workers use global `np.random.seed(seed_base + -worker_id)` (MT19937). (a) Adjacent integer seeds aren't provably independent -— rigorous fix is `SeedSequence(seed_base).spawn(n_workers)` + a `Generator` -threaded through `generate_bouquet` (opportunistic). (b) **Real**: the -timeseries pattern reuses the same `SEED` every slice → draw *i* is correlated -across time slices (same perturbation stream). *Fix: fold slice index / -scan_key into `seed_base` per slice; document.* - -### Yield / robustness - -**F21. Stuck or silently-shrunk merges.** `afterok` + one timed-out array task -= merge pending forever, no message. And the merge CLI existence-filters shard -paths (`if os.path.exists`) — a missing worker quietly shrinks the bouquet. -*Fix: merge validates expected-vs-found shards loudly (then `afterany` is -safe); laptop worker crash currently also skips merge/cleanup and leaves -shards → feeds F17.* - -### Operational - -**F22. SLURM emitted-script path inconsistency.** Array script references the -bundle as `{out_dir}/bundle.pkl` (relative to parent) while `submit.sh` does -`sbatch {job_name}_array.sbatch` (relative to `out_dir`) — no CWD satisfies -both. *Fix: absolutize bundle + `out_header` in the scripts; -`cd "$(dirname "$0")"` in submit.sh.* - -**F23. No environment setup hook in sbatch** (no venv/conda, `module load`, -`OFT_PYTHONPATH`) → shard dies at `import OpenFUSIONToolkit` on most clusters. -*Fix: `setup=[...]` lines param on `emit_slurm_script`.* - -**F24. Blind cluster debugging.** `run_shard` fd-suppresses stdout/stderr -unless `verbose=True`; the CLI never passes it → per-task `slurm-*.out` files -are empty. SLURM already isolates per-task logs, so the notebook flooding -rationale doesn't apply. *Fix: CLI runs `verbose=True`.* - -**F25. Pickle bundle fragility.** `.pkl` config ties the cluster run to the -emitting package/Python version → replaced by phase-1 config JSON. - -**F26. Laptop core budgeting.** `os.cpu_count()` is logical cores; with one -solver per core, default the worker ceiling to physical cores. - -### Phase 7 — parallel hardening *(fixes F17–F26; items 1–6 IMPLEMENTED 2026-07-02 except the JSON-bundle part of 6, which waits on phase 1)* - -1. ✅ `run_shard`: delete pre-existing shard file before generating (F17). -2. ✅ `merge_archives`: cross-shard baseline check from `_baseline` attrs - (`Ip_target`, `l_i_target`; `baseline_match_rtol` arg, default 1e-6, - loosenable for heterogeneous clusters), raises **before** anything is - copied; missing shard paths raise. CLI `merge` counts expected-vs-found - shards (zero-draw workers excluded), aborts on missing with the exact - `--array=` re-run hint, `--allow-missing` merges a partial set loudly - (F18, F21). Laptop orchestrator keeps its pre-merge check. -3. ✅ `threads_per_worker>1` now warns (li_1 jitter / DLSODE-hang rationale) - in both `parallel_generate` and `emit_slurm_script`; the committed - `examples/D3D-like/slurm_jobs/` set (bundle + sbatch + submit) was - re-emitted at `threads_per_worker=1` / `--cpus-per-task=1` — it previously - shipped `threads_per_worker=4` in the bundle, i.e. `nthreads=4` TokaMakers - (F19). Verified: 8-case synthetic-shard test (renumber/rename, drift - detection, rtol, missing-shard accounting, partial merge, zero-draw - workers, warning) + full test suite 161 passed. -4. ✅ Seeding: worker seeds now derive from - `SeedSequence([seed, worker_id, sha256(scan_key)])` (`_derive_seed`) - instead of `seed + worker_id` — provably separated worker streams AND - slice decorrelation for timeseries sweeps run with one seed (F20). - **Note: this changes the draw set produced by a given `seed` relative to - runs made before 2026-07-02** (statistically equivalent; baseline - unchanged). The full `SeedSequence.spawn` + `Generator` threading through - `generate_bouquet` (replacing global `np.random.seed`) remains future - work. -5. ✅ `emit_slurm_script`: `setup=[...]` env lines in both sbatch scripts - (module load / conda / `OFT_PYTHONPATH`); bundle referenced by basename + - `submit.sh` cd's to its own dir (works from any CWD, no machine-specific - absolute paths baked into committed examples); CLI shard runs - `verbose=True` so per-task `slurm-*.out` captures solver output; - `afterok`→`afterany` (safe now that the merge validates shards and aborts - loudly) (F22–F24). -6. ✅ Physical-core default: `parallel_generate(n_workers=None)` resolves to - physical (not logical/SMT) cores via psutil → `sysctl` → fallback (F26). - ✅ Bundle → config JSON (F25) — done with Phase 1 (2026-07-02): - `emit_slurm_script` writes `{job}_bundle.json` via `config.to_dict()`, the - CLI rebuilds it with `BouquetConfig.from_dict`, `pickle` removed. - -Verified: 12-case synthetic-shard test + full suite (161 passed); committed -`examples/D3D-like/slurm_jobs/` re-emitted with the new emitter. - ---- - -## Explicitly out of scope / leave alone - -- Homotopy & coil-drift knob set and their documented values. -- `_finalize_scan_result` shape-follows-the-call convention in `filtering.py`. -- Byte-opaque eqdsk/pfile storage. -- Solver-chatter capture design (`verbose=False` + logs). -- `paths.py` resolution logic. -- Any physics: SWB split modes, li targeting, Zeff-primary density scheme. - ---- - -## Post-implementation review fixes (2026-07-02) - -An 8-angle adversarial review of the implementation diff surfaced 8 verified -findings; all fixed on this branch: - -1. **Solver-marked tests were broken** (hidden by default deselection): - `test_systematics.py` read per-draw `coil_names` as a v1 JSON attr → - KeyError on the v2 golden. Now uses `utils._read_coil_names` everywhere. -2. **Merged archives had no provenance**: `merge_archives(config=...)` now - stamps run-level `config_json` (wired from `parallel_generate` + the CLI); - without it the deliverable cluster file carried no config record. -3. **Root `config_json` was last-writer-wins in multi-slice files**: - `load_config` is now scan-aware — per-scan copies authoritative, a - multi-scan file with `scan_key=None` raises listing the keys. -4. **`DrawView` efficiency**: attrs cached per view (snapshot semantics + - `refresh()`), `flags` built from the draw's own attrs (was a whole-scan - sweep per access → O(N²) loops), `extract()` reads both blobs in one open. -5. **Schema lookup consolidated**: new `schema.find_bytes_dataset()` (fixed - name first, legacy suffix-scan fallback) replaces the 8 copy-pasted - lookups in plotting/filtering and `archive._find_suffixed`. -6. **`_eqdsk_dataset_name` removed** (returned a constant, ignored its args); - `eqdsk_out_dir` extraction now writes coordinate-carrying FILENAMES again - (the fixed dataset name made every extracted draw clobber `eqdsk`). -7. **Legacy signal**: `initialize_equilibrium_database` stamps - `schema_version`/`bouquet_version`/`created` at creation (single - chokepoint), `BouquetArchive` warns on unstamped files, and - `load_equilibrium` raises a clear "pre-v2 archive" error naming any - legacy-suffixed dataset it finds. -8. Refuted at verify (no code change): config tuple→list JSON drift (all - consumers sequence-generic), provenance write race (workers write - distinct files), v1 silent-read claim (failures were already loud). - -Scope note: the diff also carries an unrelated new physics feature -(`read_ida_cer` + `radial_field_from_cer`, impurity radial force balance -E_r) — committed separately from the refactor. diff --git a/examples/README.md b/examples/README.md index 5e37719..aae1637 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,10 +7,12 @@ on fully synthetic, non-proprietary DIII-D-like data. ## Prerequisites -The package needs the **OpenFUSION Toolkit** (TokaMaker) on `PYTHONPATH`: +The package needs the **OpenFUSION Toolkit** (TokaMaker) importable — either +call `bq.add_oft_to_path()` (resolves `OFT_PYTHONPATH`, known install +locations, or a sibling checkout) or set the path yourself: ```bash -export PYTHONPATH=/path/to/OpenFUSIONToolkit/build_release/python:$PYTHONPATH +export OFT_PYTHONPATH=/path/to/OpenFUSIONToolkit/build_release/python ``` `import bouquet` itself works without OFT (all TokaMaker imports are lazy); a @@ -30,6 +32,8 @@ what you need. The two share a skeleton — the only real difference is the |---|---|---|---| | [`D3D-like/bouquet_D3Dlike_geqdsk_example.ipynb`](D3D-like/bouquet_D3Dlike_geqdsk_example.ipynb) | EFIT **g-file** + Osborne **p-file** (reconstructed) | reconstruction fidelity report, perturbed LCFS/profile overlays, manual switchboard extras | ~7–10 min | | [`D3D-like/bouquet_D3Dlike_omas_example.ipynb`](D3D-like/bouquet_D3Dlike_omas_example.ipynb) | FUSE **IMAS/OMAS** IDS (pre-separated) | pre-separated currents, switchboard extras from the IDS, 3-slice L→H time evolution | ~10 min/slice | +| [`D3D-like/bouquet_D3Dlike_parallel_IMAS_example.ipynb`](D3D-like/bouquet_D3Dlike_parallel_IMAS_example.ipynb) | same OMAS IDS, **process-parallel** | `parallel_generate` (laptop pool) + SLURM job-array emission, shard merge + baseline guard | scales with cores | +| [`D3D-like/bouquet_D3Dlike_systematics.ipynb`](D3D-like/bouquet_D3Dlike_systematics.ipynb) | committed golden fixture | bias/systematics decomposition: j_phi pinned σ=0 / pinned IDA-σ / full production | solver-marked | **New to bouquet?** Start with the **geqdsk** notebook — it's fully self-contained (reconstructs from the committed fixtures) and the reconstruction @@ -59,17 +63,12 @@ so a fresh checkout regenerates them: the committed g-file/p-file. - **IMAS** single slices regenerate from the committed OMAS json; the 3-slice **time series** is produced by `D3D-like/_run_omas_timeseries.py` (one - subprocess per slice, because `OFT_env` is a per-process singleton). + subprocess per slice, because `OFT_env` is a per-process singleton) — or, + within one process, via `run.run_slices(times=[...], scan_keys=[...])`. Rendered outputs are saved in the committed notebooks, so you can preview results on GitHub without running anything. -## Advanced - -- [`D3D-like/bouquet_D3Dlike_systematics.ipynb`](D3D-like/bouquet_D3Dlike_systematics.ipynb) - — a bias/systematics check that runs the bouquet three ways (j_phi pinned with - σ=0, pinned IDA-σ, full production) to expose any inherent offset. - ## Fixtures (all synthetic, non-proprietary) - `D3Dlike_Hmode_baseline.geqdsk` / `.peqdsk` — H-mode equilibrium + kinetic profiles