API Reference
This section provides detailed documentation for the StellCoilBench Python API. The API is organized into several modules, each handling a specific aspect of the benchmarking framework.
Module Overview
``stellcoilbench.cli``: Command-line interface implementation
``stellcoilbench.coil_optimization``: Core coil optimization logic
``stellcoilbench.config_scheme``: Configuration data structures
``stellcoilbench.evaluate``: Data structure for aggregated results (
SubmissionResults)``stellcoilbench.submission_packaging``: Builds submission dirs, zips, and
results.jsonfrom optimization output``stellcoilbench.update_db``: Scans submissions, aggregates metrics, generates leaderboards (RST/MD/JSON)
``stellcoilbench.validate_config``: Configuration validation
``stellcoilbench.post_processing``: VMEC, Poincaré, QFM, Boozer plots, SIMPLE, finite-build VTK
``stellcoilbench.sensitivity``: Coil sensitivity analysis via stochastic perturbation
``stellcoilbench.path_utils``: Path resolution, surface/case lookup, YAML load/dump
``stellcoilbench.finite_build``: Finite-build coil geometry (rectangular cross-section swept along centerline)
``stellcoilbench.structural_analysis``: FEM structural analysis (DOLFINx / scikit-fem)
Configuration Module
Configuration dataclasses for StellCoilBench case definitions.
This module defines the schema for case YAML files and submission metadata, providing typed structures for validation and runtime use.
- class stellcoilbench.config_scheme.CaseConfig(description: str, surface_params: SurfaceParams, coils_params: CoilsParams, optimizer_params: OptimizerParams, scoring: dict[str, Any] | None = None, coil_objective_terms: dict[str, Any] | None = None, fourier_continuation: dict[str, Any] | None = None, post_processing_params: dict[str, Any] | None = None)
Bases:
objectConfiguration for a single benchmark case, usually parsed from case.yaml.
- description
Human-readable description of the benchmark case.
- Type:
str
- surface_params
Plasma surface parameters (e.g., surface filename, range, virtual_casing).
- Type:
SurfaceParams
- coils_params
Coil configuration (ncoils, order, coil_type, etc.).
- Type:
CoilsParams
- optimizer_params
Optimizer settings (max_iterations, algorithm, tolerances).
- Type:
OptimizerParams
- coil_objective_terms
Optional coil regularization terms (length, curvature, distances).
- Type:
dict[str, Any] | None
- fourier_continuation
Optional Fourier continuation orders for progressive refinement.
- Type:
dict[str, Any] | None
- post_processing_params
Optional post-processing options (VMEC, Poincaré, etc.).
- Type:
dict[str, Any] | None
- coil_objective_terms: dict[str, Any] | None = None
- coils_params: CoilsParams
- description: str
- fourier_continuation: dict[str, Any] | None = None
- classmethod from_dict(data: dict[str, Any]) CaseConfig
Construct a CaseConfig from a parsed YAML/JSON dictionary.
- Parameters:
data (dict[str, Any]) – Raw configuration dict (e.g., from yaml.safe_load).
- Returns:
Validated configuration instance.
- Return type:
CaseConfig
- optimizer_params: OptimizerParams
- post_processing_params: dict[str, Any] | None = None
- scoring: dict[str, Any] | None = None
- surface_params: SurfaceParams
- class stellcoilbench.config_scheme.CoilsParams
Bases:
TypedDictTyped dictionary for coil parameter configuration.
- coil_type: str
- coil_width: float
- inboard_radius: float
- ncoils: int
- order: int
- target_B: float
- vv_extension: float
- class stellcoilbench.config_scheme.OptimizerParams
Bases:
TypedDictTyped dictionary for optimizer parameter configuration.
- algorithm: str
- algorithm_options: dict
- max_iter_subopt: int
- max_iterations: int
- verbose: bool
- class stellcoilbench.config_scheme.PostProcessingConfig(run_vmec: bool = False, helicity_m: int = 1, helicity_n: int = 0, ns: int = 50, plot_boozer: bool = True, plot_poincare: bool = True, nfieldlines: int = 20, run_simple: bool = False, simple_executable_path: Path | None = None, run_vmec_original: bool = False, plot_finite_build: bool = False, finite_build_width: float | None = None, finite_build_height: float | None = None, run_structural: bool = False, export_structural_full_coil_set: bool = False, structural_E: float | None = None, structural_nu: float | None = None, compute_shape_gradient: bool = False)
Bases:
objectConfiguration for the post-processing pipeline.
Groups the parameters accepted by
run_post_processinginto a structured object for cleaner function signatures and easier forwarding from higher-level orchestration code.- run_vmec
Whether to run VMEC equilibrium reconstruction.
- Type:
bool
- helicity_m
Poloidal helicity index for quasisymmetry evaluation.
- Type:
int
- helicity_n
Toroidal helicity index for quasisymmetry evaluation.
- Type:
int
- ns
Number of VMEC radial surfaces.
- Type:
int
- plot_boozer
Whether to generate Boozer-surface plots.
- Type:
bool
- plot_poincare
Whether to generate Poincaré section plots.
- Type:
bool
- nfieldlines
Number of field lines for Poincaré tracing.
- Type:
int
- run_simple
Whether to run SIMPLE particle tracing.
- Type:
bool
- simple_executable_path
Path to the SIMPLE executable (
Noneuses system default).- Type:
Optional[Path]
- run_vmec_original
Whether to run VMEC on the original (pre-optimization) coils.
- Type:
bool
- plot_finite_build
Whether to generate finite-build cross-section plots.
- Type:
bool
- finite_build_width
Winding-pack width for finite-build visualization (metres).
- Type:
Optional[float]
- finite_build_height
Winding-pack height for finite-build visualization (metres).
- Type:
Optional[float]
- run_structural
Whether to run FEM structural (linear-elasticity) analysis on finite-build coil geometry. Requires DOLFINx and a tetrahedral mesh (Gmsh).
- Type:
bool
- export_structural_full_coil_set
When True and run_structural is True, also export structural_results_full.vtk with the full coil set (unique coils plus toroidal/stellarator symmetry copies).
- Type:
bool
- structural_E
Young’s modulus [Pa] for the winding-pack material.
Noneuses the default fromconstants.WP_YOUNGS_MODULUS_PA.- Type:
Optional[float]
- structural_nu
Poisson ratio for the winding-pack material.
Noneuses the default fromconstants.WP_POISSON_RATIO.- Type:
Optional[float]
- compute_shape_gradient
Whether to compute per-coil shape gradients and save to VTK.
- Type:
bool
- compute_shape_gradient: bool = False
- export_structural_full_coil_set: bool = False
- finite_build_height: float | None = None
- finite_build_width: float | None = None
- classmethod from_case_config(case_cfg: CaseConfig, **overrides: Any) PostProcessingConfig
Create from a CaseConfig’s
post_processing_params, with optional overrides.- Parameters:
case_cfg (CaseConfig) – The case configuration whose
post_processing_paramsdict supplies default values.**overrides – Any keyword argument accepted by
PostProcessingConfig; these take precedence over values inpost_processing_params.
- Returns:
A fully-resolved configuration instance.
- Return type:
PostProcessingConfig
- classmethod from_cli_options(**kwargs: Any) PostProcessingConfig
Create from raw Typer CLI option values.
Accepts keyword arguments matching PostProcessingConfig field names; unknown keys are ignored. Use after apply_all_post_processing_flags when building config from submit-case or post-process CLI.
- Parameters:
**kwargs – CLI option values (e.g. run_vmec, run_simple, plot_poincare, finite_build_width, structural_E). Only keys that match PostProcessingConfig fields are used.
- Returns:
A configuration instance with provided values; defaults for omitted keys.
- Return type:
PostProcessingConfig
- helicity_m: int = 1
- helicity_n: int = 0
- nfieldlines: int = 20
- ns: int = 50
- plot_boozer: bool = True
- plot_finite_build: bool = False
- plot_poincare: bool = True
- run_simple: bool = False
- run_structural: bool = False
- run_vmec: bool = False
- run_vmec_original: bool = False
- simple_executable_path: Path | None = None
- structural_E: float | None = None
- structural_nu: float | None = None
- to_run_post_processing_kwargs(*, helicity_n: int | None = None, ns: int | None = None, **extra: Any) dict[str, Any]
Build kwargs dict for run_post_processing.
- Parameters:
helicity_n (int | None) – Override helicity_n (e.g. from case surface detection). Uses self.helicity_n if None.
ns (int | None) – Override VMEC radial surfaces. Uses self.ns if None.
**extra (Any) – Additional kwargs (coils_json_path, output_dir, case_yaml_path, plasma_surfaces_dir, mpi) to merge into the result.
- Returns:
Kwargs suitable for run_post_processing.
- Return type:
dict[str, Any]
- class stellcoilbench.config_scheme.SubmissionMetadata(method_version: str, contact: str, hardware: str)
Bases:
objectDescriptive information about a submission or method implementation.
- method_version
Version string for reproducibility.
- Type:
str
- contact
Contact identifier (e.g., GitHub username, email).
- Type:
str
- hardware
Hardware description (e.g., CPU model, GPU type).
- Type:
str
- contact: str
- hardware: str
- method_version: str
- class stellcoilbench.config_scheme.SurfaceParams
Bases:
TypedDictTyped dictionary for surface parameter configuration.
- range: str
- surface: str
- virtual_casing: bool
The config_scheme module defines data structures for case configurations and
submission metadata.
- CaseConfig
Represents a complete case configuration loaded from a YAML file. Contains:
description: Case descriptionsurface_params: Plasma surface configurationcoils_params: Coil geometry parametersoptimizer_params: Optimization algorithm settingscoil_objective_terms: Objective function terms
Methods:
from_dict(data: Dict[str, Any]) -> CaseConfig: Create from dictionary
- SubmissionMetadata
Metadata for submissions, including method information, contact details, hardware information, and timestamps.
Case Loader Module
Case loading and path resolution for StellCoilBench.
Provides a single entry point for loading, validating, and resolving case.yaml configurations across the codebase.
- stellcoilbench.case_loader.load_case(path: Path | str, *, validate: bool = True) CaseConfig
Load a case configuration from a file path or directory.
Accepts either a path to case.yaml or a directory containing case.yaml. Uses path_utils.load_yaml, validate_config.validate_case_config, and CaseConfig.from_dict as a single entry point for load+validate+CaseConfig.
- Parameters:
path (Path | str) – Path to case.yaml file, or directory containing case.yaml.
validate (bool, default=True) – If True, run validate_case_config before constructing CaseConfig. If False, skip validation (not recommended for untrusted input).
- Returns:
Parsed and validated case configuration.
- Return type:
CaseConfig
- Raises:
FileNotFoundError – If case.yaml is not found at the expected location.
ValueError – If validation fails (when validate=True).
Use stellcoilbench.case_loader.load_case() to load validated case
configurations from a YAML file or directory containing case.yaml.
- load_case(path: Path | str, *, validate: bool = True) -> CaseConfig
Load and validate a case configuration.
Parameters:
path: Path to case.yaml file or directory containing case.yamlvalidate: If True (default), run validation before constructing CaseConfig
Returns:
CaseConfig: Validated configuration
Raises:
FileNotFoundError: If case.yaml not found (includes searched paths and suggested next steps)ValueError: If configuration validation fails
Evaluation Module
Evaluation utilities for StellCoilBench.
This module provides dataclasses for evaluation results. Case loading is
handled by stellcoilbench.case_loader.
- class stellcoilbench.evaluate.SubmissionResults(metadata: SubmissionMetadata, metrics: Dict[str, Any])
Bases:
objectAggregated results for a single submission.
- metadata
Method name, version, contact, hardware.
- Type:
SubmissionMetadata
- metrics
Evaluation metrics (scores, coil metrics, reactor-scale quantities).
- Type:
dict[str, Any]
- metadata: SubmissionMetadata
- metrics: Dict[str, Any]
The evaluate module provides SubmissionResults for aggregated evaluation
metrics. Use stellcoilbench.case_loader.load_case() for case loading.
Coil Optimization Module
The coil_optimization module contains the core optimization logic. Key
functions: optimize_coils (main entry point), initialize_coils_loop,
optimize_coils_loop, optimize_coils_with_fourier_continuation.
LinearPenalty provides threshold-based penalty terms. See the automodule
output above for full signatures and docstrings.
- save_coils_config(coils: List, config_path: Path) -> None
Save coil configuration to JSON file.
Parameters:
coils: List of coil objectsconfig_path: Path to save coils.json
- coils_to_vtk(coils: List, filename: Path) -> None
Export coils to VTK format for visualization.
Parameters:
coils: List of coil objectsfilename: Output VTK file path
- plot_bn_error_3d(surface, bs, coils, out_dir: Path, filename: str = “bn_error_3d_plot.pdf”, title: str = “B_N/|B| Error on Plasma Surface with Optimized Coils”, plot_upsample: int = 3) -> None
Create 3D visualization of B_N error on plasma surface.
Generates a high-resolution PDF plot showing:
Plasma surface colored by \(B_N/|B|\) error magnitude
Coils colored by current magnitude
Colorbars for both
Parameters:
surface: Plasma surface objectbs: BiotSavart field calculatorcoils: List of coil objectsout_dir: Output directoryfilename: Output PDF filenametitle: Plot titleplot_upsample: Surface upsampling factor for higher resolution
Update Database Module
Leaderboard generation and database update for StellCoilBench.
Scans submissions/ for zip files containing results.json, aggregates metrics,
and generates per-surface leaderboards in RST, Markdown, and JSON under
docs/leaderboards/. Handles reactor-scale constraints, composite scoring,
and submission formatting.
- stellcoilbench.update_db.build_leaderboard_json(methods: Dict[str, Any]) Dict[str, Any]
Build a leaderboard summary from methods.json-style data.
Ranking uses the composite score (higher is better). Entries that fail hard reactor-scale constraints receive composite_score=0 and are moved to excluded_entries. Entries without any usable score are filtered out.
- Parameters:
methods (dict[str, Any]) – Per-method data from
build_methods_json().- Returns:
Keys:
entries(ranked list),excluded_entries(failed constraints). Each entry has rank, composite_score, metrics, etc.- Return type:
dict[str, Any]
- stellcoilbench.update_db.build_methods_json(submissions_root: Path, repo_root: Path) Dict[str, Any]
Build the per-method summary dictionary from submissions.
Scans submissions, normalizes metrics, recomputes coils_linked_to_surface, checks reactor-scale constraints, and computes composite scores.
- Parameters:
submissions_root (Path) – Root directory containing submission results.json files.
repo_root (Path) – Repository root for resolving plasma surfaces and relative paths.
- Returns:
Keys are
"contact:surface:user:version"; values hold metadata, metrics, reactor_scale_metrics, composite_score, passes_constraints.- Return type:
dict[str, Any]
- stellcoilbench.update_db.build_surface_leaderboards(leaderboard: Dict[str, Any], submissions_root: Path, plasma_surfaces_dir: Path) Dict[str, Dict[str, Any]]
Group entries by plasma surface extracted from case.yaml or path structure.
Expects path structure: submissions/surface/user/timestamp/results.json or all_files.zip. Entries within each surface are ranked by composite_score.
- Parameters:
leaderboard (dict) – Leaderboard with
entrieslist.submissions_root (Path) – Root of submissions directory (for path parsing).
plasma_surfaces_dir (Path) – Unused; kept for API compatibility.
- Returns:
Mapping surface_name ->
{"entries": [...]}with ranked entries.- Return type:
dict[str, dict]
- stellcoilbench.update_db.check_reactor_constraints(metrics: Dict[str, Any], reactor_scale_metrics: Dict[str, Any]) Tuple[bool, List[Dict[str, Any]]]
Check whether a submission meets all reactor-scale engineering constraints.
Evaluates each constraint in
REACTOR_SCALE_CONSTRAINTSagainst the provided metrics. Hard violations indicate infeasibility; soft violations are recorded but do not affect the pass/fail flag.- Parameters:
metrics (dict) – Device-scale metrics (e.g.
coils_linked_to_surface,final_linking_number).reactor_scale_metrics (dict) – Reactor-scale metrics (e.g. separations, length, curvature, turns).
- Returns:
passes_hard (bool) – True if no hard constraints are violated.
violations (list of dict) – All violated constraints, each with
label,metric,value,bound,direction,units, andhard.
- stellcoilbench.update_db.compute_composite_score(metrics: Dict[str, Any], reactor_scale_metrics: Dict[str, Any]) Tuple[Any, Dict[str, Any]]
Compute a composite feasibility/quality score.
Combines soft constraints via a geometric mean of exponential margin factors. Hard constraint violations return 0.0 immediately.
Score interpretation: - 0.0: Hard infeasibility (e.g. coils delinked, interlinked). - < 1: One or more soft constraints violated on average. - 1.0: All constraints met exactly. - > 1: Constraints met with engineering margin.
- Parameters:
metrics (dict) – Device-scale metrics.
reactor_scale_metrics (dict) – Reactor-scale metrics.
- Returns:
score (float | None) – Composite score; 0.0 for infeasible, > 0 for feasible, None when no soft-constraint metrics are available.
details (dict) – Diagnostic info:
factors(per-constraint margins),infeasible,reason,n_factors,mean_margin.
- stellcoilbench.update_db.normalize_submission_metrics(data: Dict[str, Any]) Dict[str, Any]
Normalize submission data to canonical structure.
Ensures consistent layout for leaderboard processing: - Maps
final_normalized_squared_flux→final_squared_flux. - Promotes top-level metric keys into ametricsdict when missing. - Preservesmetadataand ensures it exists.- Parameters:
data (dict) – Raw submission data (from results.json or zip contents).
- Returns:
Copy of data with normalized
metricsandmetadatakeys.- Return type:
dict
- stellcoilbench.update_db.parse_submission_path(path: Path, submissions_root: Path) Dict[str, Any]
Parse a submission path into surface, user, timestamp, and version.
Extracts structured metadata from paths under the submissions directory. Supports both directory-based layouts (results.json in timestamp dir) and zip files (all_files.zip or timestamp-named zips).
- Parameters:
path (Path) – Path to a submission file, e.g.
submissions/surface/user/timestamp/results.jsonorsubmissions/surface/user/12-01-2025_01-51.zip.submissions_root (Path) – Root directory containing submissions (e.g.
repo_root / "submissions").
- Returns:
Keys:
surface,user,timestamp,version,parts. Uses"unknown"for surface/user when path structure is incomplete.partsis the list of path components after strippingsubmissions/.- Return type:
dict
Examples
>>> parse_submission_path(Path("submissions/QA/user1/run1/results.json"), Path("submissions")) {'surface': 'QA', 'user': 'user1', 'timestamp': 'run1', 'version': 'run1', ...}
- stellcoilbench.update_db.update_database(repo_root: Path, submissions_root: Path | None = None, docs_dir: Path | None = None, cases_root: Path | None = None, plasma_surfaces_dir: Path | None = None, *, use_local_viz_links: bool = False) dict
High-level entry point to rebuild the leaderboard.
- It does several things:
Scans submissions_root for results.json files
Aggregates data from submissions (in-memory)
Writes docs/leaderboards/ (per-surface leaderboards)
Writes docs/leaderboard.json for reference
- Parameters:
repo_root – Root of the git repo (e.g. Path.cwd() when called from repo root).
submissions_root – Directory containing per-method submissions. Defaults to repo_root / “submissions”.
docs_dir – Directory where docs/leaderboards/ leaderboards and leaderboard.json are written. Defaults to repo_root / “docs”.
cases_root – Directory containing case.yaml files. Defaults to repo_root / “cases”.
plasma_surfaces_dir – Directory containing plasma surface files. Defaults to repo_root / “plasma_surfaces”.
use_local_viz_links (bool, optional) – If True, leaderboard PDF links use relative paths (e.g. ../../../../submissions/…/file.pdf) instead of jsDelivr CDN URLs. Use for local docs so PDFs open from disk and avoid the CDN 50 MB limit.
- Returns:
Summary with
submissions_count,surfaces_updated, anderrors.- Return type:
dict
- Raises:
RuntimeError – If leaderboard.json could not be written.
- stellcoilbench.update_db.write_markdown_leaderboard(leaderboard: Dict[str, Any], out_md: Path) None
Write a markdown leaderboard table to out_md.
- Parameters:
leaderboard (dict) – Leaderboard with
entrieslist (each entry has rank, metrics, etc.).out_md (Path) – Output path for the Markdown file.
- stellcoilbench.update_db.write_reactor_scale_leaderboard(leaderboard: Dict[str, Any], surface_leaderboards: Dict[str, Dict[str, Any]], out_rst: Path, repo_root: Path | None = None, *, use_local_links: bool = False) None
Write a reactor-scale leaderboard RST file with per-surface tables.
Shows reactor-scale engineering metrics (MN/m forces, curvatures in 1/m) alongside composite score and constraint status. Violated constraints are highlighted (red=hard, orange=soft).
- Parameters:
leaderboard (dict) – Leaderboard (unused; surface_leaderboards carries entries).
surface_leaderboards (dict[str, dict]) – Per-surface data; includes excluded entries for diagnostics.
out_rst (Path) – Output path for reactor_scale.rst.
repo_root (Path, optional) – Repository root for visualization links; inferred from out_rst if None.
- stellcoilbench.update_db.write_rst_leaderboard(leaderboard: Dict[str, Any], out_rst: Path, surface_leaderboards: Dict[str, Dict[str, Any]]) None
Write a ReadTheDocs-friendly RST leaderboard with metric definitions and per-surface tables.
Writes leaderboard.rst, leaderboard/metric_definitions.rst, and leaderboard/surface_specific.rst.
- Parameters:
leaderboard (dict) – Leaderboard with
entrieslist.out_rst (Path) – Path for main leaderboard.rst file.
surface_leaderboards (dict[str, dict]) – Per-surface data from
build_surface_leaderboards().
- stellcoilbench.update_db.write_surface_leaderboards(surface_leaderboards: Dict[str, Dict[str, Any]], docs_dir: Path, repo_root: Path) list[str]
Write per-surface leaderboard Markdown files.
Each surface gets a file in docs_dir/leaderboards/ with sortable HTML tables and metric legend.
- Parameters:
surface_leaderboards (dict[str, dict]) – Per-surface data from
build_surface_leaderboards().docs_dir (Path) – Docs root (e.g. repo_root / “docs”).
repo_root (Path) – Repository root (unused; kept for API compatibility).
- Returns:
Sorted list of surface names written.
- Return type:
list[str]
The update_db module handles leaderboard generation and management.
- update_database(repo_root: Path, submissions_root: Path | None = None, docs_dir: Path | None = None, cases_root: Path | None = None, plasma_surfaces_dir: Path | None = None, *, use_local_viz_links: bool = False) -> dict
Main function to update leaderboards from submissions.
Scans submissions directory, loads results, computes rankings, and generates leaderboard files.
Parameters:
repo_root: Repository root directorysubmissions_root: Submissions directory (default: repo_root / “submissions”)docs_dir: Documentation directory (default: repo_root / “docs”)cases_root: Cases directory (default: repo_root / “cases”)plasma_surfaces_dir: Plasma surfaces directory (default: repo_root / “plasma_surfaces”)use_local_viz_links: If True, use relative paths for PDF links instead of CDN
Returns:
dict: Summary withsubmissions_count,surfaces_updated,errors
- build_surface_leaderboards(leaderboard: Dict[str, Any], submissions_root: Path, plasma_surfaces_dir: Path) -> Dict[str, Dict[str, Any]]
Group leaderboard entries by plasma surface.
Parameters:
leaderboard: Overall leaderboard dictionarysubmissions_root: Submissions directoryplasma_surfaces_dir: Plasma surfaces directory
Returns:
Dict[str, Dict[str, Any]]: Dictionary mapping surface names to leaderboard entries
- write_rst_leaderboard(leaderboard: Dict[str, Any], out_rst: Path, surface_leaderboards: Dict[str, Dict[str, Any]]) -> None
Write ReadTheDocs-formatted leaderboard.
Generates a comprehensive RST file with embedded tables for all surfaces.
Parameters:
leaderboard: Overall leaderboard dictionaryout_rst: Output RST file pathsurface_leaderboards: Per-surface leaderboards
- write_markdown_leaderboard(leaderboard: Dict[str, Any], out_md: Path) -> None
Write markdown-formatted leaderboard.
Parameters:
leaderboard: Leaderboard dictionaryout_md: Output markdown file path
- write_surface_leaderboards(surface_leaderboards: Dict[str, Dict[str, Any]], docs_dir: Path, repo_root: Path) -> list[str]
Write per-surface markdown leaderboards.
Parameters:
surface_leaderboards: Per-surface leaderboardsdocs_dir: Documentation directoryrepo_root: Repository root
Returns:
list[str]: List of generated surface names
- load_submissions(submissions_root: Path) -> Iterable[Tuple[str, Path, Dict[str, Any]]]
Load all submissions from directory.
Handles both regular directories and zip files. Extracts results.json from zips as needed.
Parameters:
submissions_root: Submissions directory
Yields:
(method_key, path, data): Method key, submission path, and results data
- metric_shorthand(metric_name: str) -> str
Convert metric names to compact shorthand for display.
Parameters:
metric_name: Full metric name
Returns:
Shorthand/acronym (e.g., “f_B” for “final_normalized_squared_flux”)
- metric_definition(metric_name: str) -> str
Get detailed mathematical definition for a metric.
Parameters:
metric_name: Metric name
Returns:
LaTeX-formatted mathematical definition
Post-Processing Module
The post_processing module handles post-optimization analysis including VMEC
equilibrium calculations, Poincaré plots, quasisymmetry analysis, and Boozer surface plots.
- run_post_processing(coils_json_path: Path, output_dir: Path, case_yaml_path: Optional[Path] = None, plasma_surfaces_dir: Optional[Path] = None, run_vmec: bool = True, helicity_m: int = 1, helicity_n: int = 0, ns: int = 50, plot_boozer: bool = True, plot_poincare: bool = True, nfieldlines: int = 20, mpi: Optional[Any] = None) -> Dict[str, Any]
Run complete post-processing pipeline.
This function:
Loads coils and plasma surface
Generates Poincaré plot (if requested)
Computes QFM surface
Optionally runs VMEC equilibrium
Computes quasisymmetry metrics
Generates VMEC-dependent plots (Boozer, iota, quasisymmetry)
Parameters:
coils_json_path: Path to coils JSON fileoutput_dir: Directory where output files will be savedcase_yaml_path: Path to case.yaml file (optional)plasma_surfaces_dir: Directory containing plasma surface files (optional)run_vmec: Whether to run VMEC equilibrium calculation (default: True)helicity_m: Poloidal mode number for quasisymmetry (default: 1)helicity_n: Toroidal mode number for quasisymmetry (default: 0)ns: Number of radial surfaces for quasisymmetry evaluation (default: 50)plot_boozer: Whether to generate Boozer surface plot (default: True)plot_poincare: Whether to generate Poincaré plot (default: True)nfieldlines: Number of fieldlines to trace for Poincaré plot (default: 20)mpi: MPI partition for parallel execution (optional)
Returns:
Dict[str, Any]: Dictionary containing post-processing results: -qfm_surface: QFM surface object -quasisymmetry_average: Average quasisymmetry error -quasisymmetry_profile: Radial quasisymmetry profile -vmec: VMEC equilibrium object (if run_vmec=True)
Sensitivity Module
Coil sensitivity analysis via stochastic perturbation.
Uses simsopt’s CurvePerturbed / GaussianSampler to quantify how robust optimized coil solutions are to geometric perturbations (e.g. manufacturing tolerances, positioning errors). The principal output is sigma* – the perturbation amplitude (standard deviation in metres) at which the squared-flux metric f_B degrades by no more than a user-chosen factor (default 2x) at the chosen percentile (default 95th).
Typical usage
>>> from stellcoilbench.sensitivity import run_sensitivity_analysis
>>> results = run_sensitivity_analysis(
... coils_json_path=Path("coils.json"),
... case_yaml_path=Path("case.yaml"),
... )
>>> print(f"Critical sigma*: {results['critical_sigma_m'] * 1e3:.2f} mm")
- class stellcoilbench.sensitivity.BisectionStep(sigma: float, percentile_ratio: float, n_samples: int)
Bases:
objectRecord of a single bisection iteration.
- sigma
Perturbation amplitude [m] at this step.
- Type:
float
- percentile_ratio
Ratio \(f_B^{\mathrm{pert}}/f_B^{\mathrm{nom}}\) at the target percentile.
- Type:
float
- n_samples
Monte-Carlo sample count used.
- Type:
int
- n_samples: int
- percentile_ratio: float
- sigma: float
- class stellcoilbench.sensitivity.SensitivityResult(critical_sigma_m: float, nominal_fb: float, factor: float, percentile: float, correlation_length_m: float, n_samples: int, seed: int, bisection_history: list[BisectionStep] = <factory>, sweep_sigmas: list[float] = <factory>, sweep_p50_ratios: list[float] = <factory>, sweep_p95_ratios: list[float] = <factory>, sweep_mean_ratios: list[float] = <factory>)
Bases:
objectFull output of a sensitivity analysis run.
- critical_sigma_m
Critical perturbation amplitude \(\sigma^*\) [m].
- Type:
float
- nominal_fb
Squared-flux \(f_B\) of the unperturbed coils.
- Type:
float
- factor
Maximum tolerated degradation factor (e.g. 2.0).
- Type:
float
- percentile
Percentile used for bisection (e.g. 95).
- Type:
float
- correlation_length_m
GP correlation length [m].
- Type:
float
- n_samples
Monte-Carlo samples per evaluation.
- Type:
int
- seed
Random seed.
- Type:
int
- bisection_history
Log of bisection iterations.
- Type:
list
- sweep_sigmas, sweep_p50_ratios, sweep_p95_ratios, sweep_mean_ratios
Sweep data for plotting.
- Type:
list
- bisection_history: list[BisectionStep]
- correlation_length_m: float
- critical_sigma_m: float
- factor: float
- n_samples: int
- nominal_fb: float
- percentile: float
- seed: int
- sweep_mean_ratios: list[float]
- sweep_p50_ratios: list[float]
- sweep_p95_ratios: list[float]
- sweep_sigmas: list[float]
- to_dict() dict[str, Any]
Serialize to a JSON-friendly dictionary.
- stellcoilbench.sensitivity.compute_fb_perturbed(bs: BiotSavart, surface: SurfaceRZFourier, sigma: float, correlation_length_m: float, n_samples: int, seed: int = 42, flux_threshold: float = 0.0, samplers: list | None = None) np.ndarray
Evaluate \(f_B\) over n_samples stochastic coil perturbations.
Uses a Gaussian-process perturbation model with covariance \(k(s,s')\) (squared-exponential in arclength) to draw coil deformations, then evaluates SquaredFlux \(f_B\) on each perturbed coil set.
- Parameters:
bs (simsopt.field.BiotSavart) – Nominal (unperturbed) BiotSavart field.
surface (simsopt.geo.SurfaceRZFourier) – Plasma surface for the SquaredFlux evaluation.
sigma (float) – Standard deviation of the Gaussian-process perturbation (metres).
correlation_length_m (float) – Correlation length of the perturbation along the coil (metres). Internally converted to the normalised [0, 1] domain used by
GaussianSamplerby dividing by each coil’s arc length. Ignored when samplers is provided.n_samples (int) – Number of Monte-Carlo realisations to draw.
seed (int) – Base random seed for reproducibility.
flux_threshold (float) – Threshold passed to
SquaredFlux(same semantics as optimisation).samplers (list[GaussianSampler] | None) – Pre-built unit-sigma samplers (one per coil). When provided the drawn samples are scaled by sigma, avoiding the expensive sampler construction on every call. Build with
_build_unit_samplers.
- Returns:
Array of shape
(n_samples,)with the f_B value for each perturbed coil set.- Return type:
np.ndarray
- stellcoilbench.sensitivity.export_perturbed_coils_vtk(bs: BiotSavart, surface: SurfaceRZFourier, sigma: float, correlation_length_m: float, output_dir: Path, n_vtk_samples: int = 3, seed: int = 42) list[Path]
Export perturbed coil sets and surface B·n to VTK.
Uses perturbation amplitude \(\sigma\) (typically \(\sigma^*\)) to generate \(n\) perturbed coil sets via the GP sampler. For each sample writes
coils_perturbed_XX.vtuandsurface_perturbed_XX.vts(full-torus plasma surface coloured by B.n from the perturbed field, matchingsurface_optimized.vts).- Parameters:
bs (simsopt.field.BiotSavart) – Nominal BiotSavart field.
surface (simsopt.geo.SurfaceRZFourier) – Plasma surface (may be half-period; a full-torus copy is built internally for VTK output).
sigma (float) – Perturbation amplitude (metres) – typically sigma*.
correlation_length_m (float) – Correlation length (metres).
output_dir (Path) – Directory to write VTK files into.
n_vtk_samples (int) – Number of perturbed coil sets to export (default 3).
seed (int) – Random seed for reproducibility.
- Returns:
Paths to the written VTK files (coils + surfaces interleaved).
- Return type:
list[Path]
- stellcoilbench.sensitivity.find_critical_sigma(bs: BiotSavart, surface: SurfaceRZFourier, nominal_fb: float, correlation_length_m: float = 1.0, n_samples: int = 100, factor: float = 2.0, percentile: float = 95.0, sigma_min: float = 1e-05, sigma_max: float = 0.05, seed: int = 42, flux_threshold: float = 0.0, bisection_tol: float = 0.05, max_bisection_iter: int = 20, samplers: list | None = None) tuple[float, list[BisectionStep]]
Find the critical perturbation amplitude \(\sigma^*\) via bisection.
\(\sigma^*\) is the largest \(\sigma\) for which the
percentile-th percentile of \(f_B^{\mathrm{pert}}/f_B^{\mathrm{nom}}\) is at mostfactor. Bisection criterion: accept \(\sigma\) if \(P_{\mathrm{percentile}}(f_B^{\mathrm{pert}}/f_B^{\mathrm{nom}}) \leq \mathtt{factor}\).- Parameters:
bs (simsopt.field.BiotSavart) – Nominal BiotSavart field.
surface (simsopt.geo.SurfaceRZFourier) – Plasma surface.
nominal_fb (float) – f_B of the unperturbed coil set.
correlation_length_m (float) – Physical correlation length (metres).
n_samples (int) – Monte-Carlo samples per sigma evaluation.
factor (float) – Maximum tolerated f_B degradation factor (e.g. 2.0).
percentile (float) – Percentile at which to enforce the factor (e.g. 95).
sigma_min (float) – Bisection bounds in metres.
sigma_max (float) – Bisection bounds in metres.
seed (int) – Random seed.
flux_threshold (float) – Passed to
SquaredFlux.bisection_tol (float) – Relative tolerance on sigma for convergence (fraction of interval).
max_bisection_iter (int) – Maximum bisection iterations.
samplers (list[GaussianSampler] | None) – Pre-built unit-sigma samplers (one per coil). When provided, avoids recreating samplers on every bisection iteration.
- Returns:
sigma_star (float) – Critical perturbation amplitude (metres).
history (list[BisectionStep]) – Bisection iteration log.
- stellcoilbench.sensitivity.plot_sensitivity(result: SensitivityResult, output_path: Path) Path
Generate a sensitivity plot (\(f_B\) ratio vs \(\sigma\)) and save.
Plots median, percentile (e.g. 95th), and mean of \(f_B^{\mathrm{pert}}/f_B^{\mathrm{nom}}\) vs perturbation amplitude \(\sigma\), with \(\sigma^*\) and the factor threshold marked.
- Parameters:
result (SensitivityResult) – Completed sensitivity analysis result containing sweep data.
output_path (Path) – Destination file (e.g.
sensitivity_plot.pdf).
- Returns:
The written file path.
- Return type:
Path
- stellcoilbench.sensitivity.run_sensitivity_analysis(coils_json_path: Path, case_yaml_path: Path | None = None, plasma_surfaces_dir: Path | None = None, correlation_length_m: float = 1.0, n_samples: int = 20, factor: float = 2.0, percentile: float = 95.0, sigma_min: float = 1e-05, sigma_max: float = 0.05, seed: int = 42, output_dir: Path | None = None, make_plot: bool = True, n_sweep: int = 8, n_vtk_samples: int = 0) SensitivityResult
Run a full coil sensitivity analysis.
Loads coils and surface, computes nominal \(f_B\), bisects to find \(\sigma^*\), optionally runs a sweep for visualisation, exports perturbed coil VTK files, and writes
sensitivity_results.json(and an optional plot) to output_dir.- Parameters:
coils_json_path (Path) – Optimised coils JSON file.
case_yaml_path (Path | None) – Case YAML (auto-detected if None).
plasma_surfaces_dir (Path | None) – Plasma-surface directory (default
plasma_surfaces/).correlation_length_m (float) – Correlation length of perturbation along the coil (metres). Default 1.0 m – appropriate for reactor-scale coils (20-40 m).
n_samples (int) – Monte-Carlo samples per sigma evaluation.
factor (float) – Maximum tolerated f_B degradation factor.
percentile (float) – Percentile at which the factor is enforced.
sigma_min (float) – Bisection bounds (metres).
sigma_max (float) – Bisection bounds (metres).
seed (int) – Random seed.
output_dir (Path | None) – Where to write results. Defaults to the parent of coils_json_path.
make_plot (bool) – Whether to produce a PDF plot.
n_sweep (int) – Number of sigma values in the optional sweep.
n_vtk_samples (int) – Number of perturbed coil sets to export as VTK files (at sigma*) for visual comparison. 0 disables VTK export (default).
- Returns:
Dataclass with all outputs.
- Return type:
Coil sensitivity analysis via stochastic perturbation (CurvePerturbed / GaussianSampler).
Quantifies robustness to geometric perturbations. Key entry point:
run_sensitivity_analysis(coils_json_path, case_yaml_path, ...).
Path Utils Module
Shared path resolution utilities for StellCoilBench.
Provides helpers for locating plasma_surfaces directories, surface files, and case YAML files across the repository layout.
- class stellcoilbench.path_utils.CaseResolutionResult(case_yaml_path: Path | None, surface_path: Path | None, case_data: dict[str, Any])
Bases:
objectResult of case and surface path resolution.
Use
resolve_case_and_surface()as the canonical resolver. Supports tuple unpacking:case_path, surface_path, case_data = result.- case_data: dict[str, Any]
- case_yaml_path: Path | None
- surface_path: Path | None
- class stellcoilbench.path_utils.ResolvedPaths(case_yaml: Path | None, surface_file: Path | None, coils_json: Path | None, plasma_surfaces_dir: Path | None)
Bases:
objectCanonical result of path resolution for post-processing and coil loading.
Single entry point for case YAML, surface file, coils JSON, and plasma surfaces directory. Use
resolve_all()to populate.- case_yaml: Path | None
- coils_json: Path | None
- plasma_surfaces_dir: Path | None
- surface_file: Path | None
- stellcoilbench.path_utils.coils_json_path_from_dir(out_dir: Path) Path | None
Return path to coils JSON in directory, preferring biot_savart_optimized.json.
Checks for
biot_savart_optimized.jsonfirst (simsopt optimization output), thencoils.json(generic fallback). Returns the first that exists.- Parameters:
out_dir (Path) – Directory containing coil output files.
- Returns:
Path to coils JSON file if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.dump_yaml(data: dict[str, Any], path: Path | None = None, **kwargs: Any) str | None
Write a dict to YAML. If path is given, write to file and return None. Otherwise return the YAML string.
- Parameters:
data (dict) – Data to serialize.
path (Path, optional) – If provided, write to this file.
**kwargs – Passed to yaml.dump (e.g. default_flow_style, sort_keys).
- Returns:
YAML string if path is None; None if written to file.
- Return type:
str | None
- stellcoilbench.path_utils.find_case_and_surface_path(coils_json_path: Path, case_yaml_path: Path | None, plasma_surfaces_dir: Path | None) tuple[Path, Path]
Locate case YAML and plasma surface path; raise if not found.
Wrapper around
resolve_case_and_surface()that raises FileNotFoundError or ValueError when case/surface cannot be resolved.- Parameters:
coils_json_path (Path) – Path to coils JSON file.
case_yaml_path (Path | None) – Explicit case YAML path, or None to search from coils_json_path.
plasma_surfaces_dir (Path | None) – Optional plasma surfaces directory.
- Returns:
(resolved_case_yaml_path, surface_path).
- Return type:
tuple of (Path, Path)
- Raises:
FileNotFoundError – If case YAML or surface file cannot be found.
ValueError – If case YAML does not specify a surface.
- stellcoilbench.path_utils.find_dir_up(start_path: Path, dir_name: str, max_levels: int = 5) Path | None
Walk up from start_path to find a directory with the given name.
- Parameters:
start_path (Path) – Directory to start searching from.
dir_name (str) – Name of the directory to find (e.g., “plasma_surfaces”, “cases”).
max_levels (int, default=5) – Maximum number of parent levels to traverse.
- Returns:
Path to the directory if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.find_file_up(start_path: Path, file_name: str, max_levels: int = 5) Path | None
Walk up from start_path to find a file with the given name.
- Parameters:
start_path (Path) – Directory to start searching from.
file_name (str) – Name of the file to find (e.g., “case.yaml”).
max_levels (int, default=5) – Maximum number of parent levels to traverse.
- Returns:
Path to the file if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.find_plasma_surfaces_dir(start_path: Path, max_levels: int = 5) Path | None
Walk up from start_path to find a plasma_surfaces directory.
- Parameters:
start_path (Path) – Directory to start searching from (e.g., output dir, case dir).
max_levels (int, default=5) – Maximum number of parent levels to traverse.
- Returns:
Path to plasma_surfaces directory if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.find_repo_root(start_path: Path | None = None, max_levels: int = 15) Path | None
Walk up from start_path to find repository root (.git or pyproject.toml).
- Parameters:
start_path (Path | None) – Directory to start searching from. Defaults to Path.cwd().
max_levels (int, default=15) – Maximum number of parent levels to traverse.
- Returns:
Repository root directory if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.get_reference_radii(surface: SurfaceRZFourier) tuple[float, float]
Return (major_radius, minor_radius) from raw file when available, else from surface.
Surfaces loaded via load_surface_with_range have _major_radius_raw and _minor_radius_raw from the raw simsopt load (before quadpoint rebuild). These are stable across resolution and ensure consistent a0 and threshold scaling.
- Parameters:
surface (SurfaceRZFourier) – Plasma boundary surface.
- Returns:
(major_radius [m], minor_radius [m]).
- Return type:
tuple[float, float]
- stellcoilbench.path_utils.get_surface_filename(case_data: dict | Any) str
Extract surface filename from case config (dict or CaseConfig).
- Parameters:
case_data (dict | CaseConfig) – Case configuration (parsed YAML dict or CaseConfig instance).
- Returns:
Surface filename (e.g.
input.LandremanPaul2021_QA), or empty string.- Return type:
str
- stellcoilbench.path_utils.get_surface_search_base_dirs(case_path: Path | None = None, plasma_surfaces_dir: Path | None = None, coils_json_path: Path | None = None) list[Path]
Build list of directories to search for surface files.
Collects plasma_surfaces directories and case/output directories that may contain surface files. Used with resolve_surface_path for consistent surface resolution across the codebase.
- Parameters:
case_path (Path | None) – Case directory or case.yaml path.
plasma_surfaces_dir (Path | None) – Explicit plasma_surfaces directory (e.g., from config).
coils_json_path (Path | None) – Path to coils JSON (used to find plasma_surfaces via find_plasma_surfaces_dir).
- Returns:
Directories to search, in priority order.
- Return type:
list[Path]
- stellcoilbench.path_utils.get_target_B_from_surface(surface_file: str) float
Get target on-axis B-field [T] from surface filename.
Maps known surface names to their design target B-field for coil optimization and reactor-scale scaling.
- Parameters:
surface_file (str) – Surface filename (e.g., “input.LandremanPaul2021_QA”, “muse.focus”).
- Returns:
Target B-field in Tesla.
- Return type:
float
- stellcoilbench.path_utils.load_surface_with_range(surface_path: Path | str, surface_range: str = 'full torus', nphi: int = 256, ntheta: int = 256, *, endpoints: bool = True) SurfaceRZFourier
Load a surface from file with a specified range and resolution.
Detects file type from path (input/wout/focus) and uses the appropriate SurfaceRZFourier loader.
- Parameters:
surface_path (Path | str) – Path to surface file.
surface_range (str, default="full torus") – Range for surface loading (“full torus” or “half period”).
nphi (int, default=256) – Number of phi quadrature points.
ntheta (int, default=256) – Number of theta quadrature points.
endpoints (bool, default=True) – If True, quadpoints include 0 and 1 so the surface closes at the boundaries. Use for VTK visualization to avoid holes in ParaView.
- Returns:
Loaded surface with specified range.
- Return type:
SurfaceRZFourier
- stellcoilbench.path_utils.load_yaml(path: Path | None = None, content: str | bytes | None = None) dict[str, Any]
Load YAML into a dict from a file path or string/bytes content.
- Parameters:
path (Path, optional) – Path to the YAML file. Mutually exclusive with content.
content (str | bytes, optional) – YAML content as string or bytes. Mutually exclusive with path.
- Returns:
Parsed YAML content.
- Return type:
dict
- stellcoilbench.path_utils.load_yaml_safe(path: Path | None = None, content: str | bytes | None = None) dict[str, Any] | None
Load YAML into a dict, returning None on failure.
Catches OSError and yaml.YAMLError. Use when callers prefer None over raising.
- Parameters:
path (Path, optional) – Path to the YAML file. Mutually exclusive with content.
content (str | bytes, optional) – YAML content as string or bytes. Mutually exclusive with path.
- Returns:
Parsed YAML content, or None if loading fails.
- Return type:
dict | None
- stellcoilbench.path_utils.normalize_surface_id(name: str, for_filename: bool = False) str
Canonical surface identifier for leaderboards and filenames.
Strips input./wout. prefixes and .focus suffix, then optionally replaces dots and spaces for filesystem-safe identifiers.
- Parameters:
name (str) – Surface name or filename (e.g., “input.LandremanPaul2021_QA”).
for_filename (bool, default=False) – If True, replace “.” and “ “ with “_” for safe filenames.
- Returns:
Normalized identifier (e.g., “LandremanPaul2021_QA” or “LandremanPaul2021_QA” with underscores when for_filename=True).
- Return type:
str
- stellcoilbench.path_utils.resolve_all(out_dir: Path, case_hint: Path | str | None = None, surface_filename: str | None = None, coils_hint: Path | None = None) ResolvedPaths
Resolve case YAML, surface file, coils JSON, and plasma_surfaces dir.
Canonical path resolution entry point. Combines resolve_case_yaml_path, resolve_surface_file_path, coils_json_path_from_dir, and find_plasma_surfaces_dir into a single call.
- Parameters:
out_dir (Path) – Output directory (e.g., optimization output dir) used as search base.
case_hint (Path | str | None, optional) – Explicit case path (file or directory containing case.yaml).
surface_filename (str | None, optional) – Surface filename for case.yaml search (e.g., from s.filename).
coils_hint (Path | None, optional) – Explicit coils JSON path. When None, probes out_dir for coils.
- Returns:
case_yaml, surface_file, coils_json, plasma_surfaces_dir (any may be None).
- Return type:
- stellcoilbench.path_utils.resolve_case_and_surface(case_hint: Path | str | None, coils_path: Path | None = None, plasma_dir: Path | None = None) CaseResolutionResult
Resolve case YAML and plasma surface paths from hints.
Single source of truth for case/surface resolution. When case_hint is None, searches from coils_path: walk up for case.yaml, guess cases/<stem>/, or scan cases/ for matching surface.
- Parameters:
case_hint (Path or str or None) – Explicit path to case.yaml or case directory. If None, resolved from coils_path when provided.
coils_path (Path, optional) – Path to coils JSON; used as search base when case_hint is None.
plasma_dir (Path, optional) – Directory containing plasma surface files.
- Returns:
(case_yaml_path, surface_path, raw_case_data). Any may be None/empty if not found. Supports tuple unpacking for backward compatibility.
- Return type:
- stellcoilbench.path_utils.resolve_case_yaml_path(out_dir: Path, case_path_hint: Path | str | None = None, surface_filename: str | None = None) Path | None
Resolve case.yaml path from output directory, hints, and surface filename.
Search order: (1) case_path_hint if valid file/dir, (2)
out_dir/case.yaml, (3)out_dir.parent/case.yaml, (4) surface-based paths (surface_dir,cases/stem), (5) scan cases/*.yaml for surface match.- Parameters:
out_dir (Path) – Output directory (e.g., from optimization).
case_path_hint (Path | str | None) – Known case path (file or directory containing case.yaml).
surface_filename (str | None) – Surface filename (e.g., from s.filename) for cases/stem/case.yaml search.
- Returns:
Path to case.yaml if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.resolve_surface_file_path(case_yaml_path: Path | None = None, surface_filename: str | None = None, plasma_surfaces_dir: Path | None = None, coils_json_path: Path | None = None) Path | None
Resolve a plasma surface file path from case YAML or explicit filename.
Centralises the surface-path resolution logic shared by coil loading, Poincaré plotting, and VMEC input resolution. When case_yaml_path or coils_json_path is provided, delegates to resolve_case_and_surface for unified resolution; otherwise uses get_surface_search_base_dirs + resolve_surface_path for explicit surface_filename lookup.
- Parameters:
case_yaml_path (Path, optional) – Path to a
case.yamlfile containingsurface_params.surface.surface_filename (str, optional) – Explicit surface filename to resolve (overrides case YAML lookup).
plasma_surfaces_dir (Path, optional) – Directory containing plasma surface files.
coils_json_path (Path, optional) – Coils JSON path used as an additional base directory for search.
- Returns:
Resolved absolute path to the surface file, or
Noneif not found.- Return type:
Path or None
- stellcoilbench.path_utils.resolve_surface_path(surface_name: str, base_dirs: list[Path], case_insensitive: bool = True) Path | None
Resolve a surface filename to an existing file path.
Searches in base_dirs (e.g., plasma_surfaces, case dirs). Optionally falls back to case-insensitive match within those directories.
- Parameters:
surface_name (str) – Surface filename (e.g., “input.LandremanPaul2021_QA”).
base_dirs (list[Path]) – Directories to search (e.g., [Path(“plasma_surfaces”), Path.cwd() / “plasma_surfaces”]).
case_insensitive (bool, default=True) – If exact match fails, try case-insensitive directory search.
- Returns:
Path to surface file if found; None otherwise.
- Return type:
Path | None
- stellcoilbench.path_utils.surface_stem_from_filename(filename: str) str
Extract a normalized surface stem from a surface filename.
Strips common prefixes (input., wout.) and suffixes (.focus) so that “input.LandremanPaul2021_QA”, “wout.LandremanPaul2021_QA”, and “LandremanPaul2021_QA.focus” all yield “LandremanPaul2021_QA”.
- Parameters:
filename (str) – Surface filename (e.g., “input.LandremanPaul2021_QA”, “foo.focus”).
- Returns:
Normalized stem for use as a surface identifier.
- Return type:
str
Path resolution for plasma surfaces, case YAML, and coils. Key functions:
resolve_case_and_surface, resolve_all, find_plasma_surfaces_dir,
load_yaml, dump_yaml, get_surface_filename.
Finite Build Module
Finite-build coil geometry generation and VTK export.
Generates 3D coil geometry by sweeping a rectangular cross-section along the coil centerline (filament) using a rotation-minimizing frame. Output is a surface mesh VTK file suitable for visualization. Uses ParaStell when available for tetrahedral mesh; falls back to built-in sweep otherwise.
- stellcoilbench.finite_build.finite_build_coils_to_msh(coils: List, msh_path: str | Path, width: float, height: float, mesh_size: float, min_mesh_size: float | None = None, max_mesh_size: float | None = None) Tuple[Path, List[int]] | None
Generate tetrahedral .msh for finite-build coils.
Tries ParaStell first. If ParaStell is unavailable or fails, falls back to sweep-based mesh generation (stub: returns None for now).
- Parameters:
coils (List) – List of simsopt Coil objects.
msh_path (Path or str) – Output .msh file path.
width (float) – Cross-section width [m].
height (float) – Cross-section height [m].
mesh_size (float) – Characteristic element size [m].
min_mesh_size (float, optional) – Gmsh minimum element size [m]. If None, uses mesh_size.
max_mesh_size (float, optional) – Gmsh maximum element size [m]. If None, uses mesh_size.
- Returns:
(msh_path, list of coil indices) if successful; None on failure.
- Return type:
tuple[Path, list[int]] or None
- stellcoilbench.finite_build.finite_build_coils_to_vtk(coils: List, output_path: str | Path, width: float | None = None, height: float | None = None, width_per_coil: List[float] | None = None, height_per_coil: List[float] | None = None, n_along: int | None = None, use_stellaris_default: bool = True, min_mesh_size: float | None = None, max_mesh_size: float | None = None) Path
Generate finite-build coil geometry and export to VTK.
Sweeps a rectangular cross-section along each coil centerline and writes a combined VTK file. Cross-section dimensions can be: - Uniform (width, height) for all coils - Per-coil (width_per_coil, height_per_coil) - Stellaris-derived: sqrt(N_turns) * 20 mm square when N_turns available - Default: 35 cm × 35 cm (reactor scale).
- Parameters:
coils (List) – List of simsopt Coil objects (with .curve attribute).
output_path (Path or str) – Output file path (e.g. “finite_build_coils” -> finite_build_coils.vtk).
width (float, optional) – Uniform cross-section width [m] for all coils.
height (float, optional) – Uniform cross-section height [m] for all coils.
width_per_coil (List[float], optional) – Per-coil width [m]. Length must match number of coils.
height_per_coil (List[float], optional) – Per-coil height [m]. Length must match number of coils.
n_along (int, optional) – Number of points along each coil for sampling. If None, uses the curve’s existing quadrature points.
use_stellaris_default (bool, default=True) – If no dimensions given, use DEFAULT_CROSS_SECTION_M (35 cm).
min_mesh_size (float, optional) – Gmsh minimum element size [m] for ParaStell tetrahedral mesh. Used only when ParaStell succeeds (no per-coil dimensions).
max_mesh_size (float, optional) – Gmsh maximum element size [m] for ParaStell tetrahedral mesh. Used only when ParaStell succeeds (no per-coil dimensions).
- Returns:
Path to the written VTK file.
- Return type:
Path
- Raises:
ValueError – If coil list is empty or dimension arrays have wrong length.
- stellcoilbench.finite_build.sweep_rectangular_cross_section(gamma: ndarray, gammadash: ndarray, width: float, height: float, n_cross: int = 4) Tuple[ndarray, ndarray]
Sweep a rectangular cross-section along a curve to create a surface mesh.
- Parameters:
gamma (np.ndarray) – Curve points, shape (n_points, 3).
gammadash (np.ndarray) – Curve derivatives (tangents), shape (n_points, 3).
width (float) – Cross-section width [m] along the first in-plane direction.
height (float) – Cross-section height [m] along the second in-plane direction.
n_cross (int) – Number of vertices per cross-section (4 for rectangle corners).
- Returns:
vertices (np.ndarray) – Mesh vertices, shape (n_vertices, 3).
faces (np.ndarray) – Triangle faces as vertex indices, shape (n_faces, 3).
Notes
The first point is appended to gamma/gammadash to close the curve, so the last segment connects back to the start for a fully connected loop.
Finite-build coil geometry: rectangular cross-section swept along centerline.
Key function: finite_build_coils_to_vtk. Requires pip install .[structural] for Gmsh.
Structural Analysis Module
FEM-based structural analysis for finite-build stellarator coils.
Solves 3-D linear elasticity on a tetrahedral mesh of the winding pack, using electromagnetic Lorentz-force body loads (J × B) and outputs the displacement field, Cauchy stress tensor, and Von Mises stress as XDMF / VTK files suitable for ParaView.
The primary solver backend is DOLFINx (FEniCSx). A lightweight scikit-fem fallback is provided for environments where DOLFINx is not installed (no MPI parallelism, but pip-installable).
Both backends are optional imports; a clear error is raised when neither is available and the user requests a structural solve.
- stellcoilbench.structural_analysis.compute_lorentz_body_force(coils: list[Coil], bs: BiotSavart, mesh: dolfinx.mesh.Mesh | skfem.MeshTet1, cross_section_area: float, *, width: float = 0.05, height: float = 0.05, use_regularized: bool = True, mesh_coils: list[Coil] | None = None, all_coils: list[Coil] | None = None, backend: str | None = None, quadrature_degree: int | None = None) dolfinx.fem.Function | np.ndarray
Compute Lorentz body-force density J × B on the coil mesh.
The current density is assumed uniform across the winding-pack cross-section, directed along the coil tangent at the nearest centerline point:
\[\mathbf{J} = \frac{I}{A}\,\mathbf{t}\]The body-force density (force per unit volume) is:
\[\mathbf{f} = \mathbf{J} \times \mathbf{B} \quad [\mathrm{N/m^3}]\]When
use_regularized=True(default), the Landreman et al. (2025) regularized internal field model is used for self-field; BiotSavart provides the mutual field from other coils.- Parameters:
coils (list[Coil]) – simsopt
Coilobjects.bs (BiotSavart) – Magnetic field evaluator.
mesh (dolfinx.mesh.Mesh | skfem.MeshTet1) – Tetrahedral coil mesh.
cross_section_area (float) – Winding-pack cross-section area [m²].
width (float, optional) – Cross-section full width [m]. Default 0.05.
height (float, optional) – Cross-section full height [m]. Default 0.05.
use_regularized (bool, optional) – If True, use regularized internal field for self-field. Default True.
mesh_coils (list[Coil] | None, optional) – Coils on which mesh points lie (for multi-coil meshes).
all_coils (list[Coil] | None, optional) – Full coil set including symmetry copies for mutual-field B.
- Returns:
Body-force density [N/m³] at quadrature points (DOLFINx) or mesh nodes (scikit-fem).
- Return type:
dolfinx.fem.Function | np.ndarray
- stellcoilbench.structural_analysis.compute_stress_field(mesh: dolfinx.mesh.Mesh | skfem.MeshTet1, displacement: dolfinx.fem.Function | np.ndarray, E: float = 100000000000.0, nu: float = 0.3, *, backend: str | None = None) tuple['dolfinx.fem.Function | None', 'dolfinx.fem.Function | np.ndarray']
Compute the Cauchy stress tensor and Von Mises stress from displacement.
The Cauchy stress follows isotropic Hooke’s law:
\[\sigma = \lambda\mathrm{tr}(\varepsilon)I + 2\mu\varepsilon\]with strain \(\varepsilon = \tfrac{1}{2}(\nabla\mathbf{u} + \nabla\mathbf{u}^T)\). The Von Mises equivalent stress is:
\[\sigma_{\mathrm{vm}} = \sqrt{\tfrac{3}{2}\,\mathbf{s}:\mathbf{s}} \quad\text{where}\quad \mathbf{s} = \sigma - \tfrac{1}{3}\mathrm{tr} (\sigma)I\](deviatoric stress \(\mathbf{s}\)).
- Parameters:
mesh (dolfinx.mesh.Mesh | skfem.MeshTet1) – Tetrahedral mesh.
displacement (dolfinx.fem.Function | np.ndarray) – Displacement field from
solve_linear_elasticity().E (float, optional) – Young’s modulus [Pa].
nu (float, optional) – Poisson ratio.
- Returns:
(sigma_field, von_mises). DOLFINx returns full stress tensor; scikit-fem returns(None, von_mises).- Return type:
tuple
- stellcoilbench.structural_analysis.export_results(mesh: dolfinx.mesh.Mesh | skfem.MeshTet1, displacement: dolfinx.fem.Function | np.ndarray, von_mises: dolfinx.fem.Function | np.ndarray, output_dir: Path, *, backend: str | None = None) dict[str, str]
Write displacement and Von Mises stress to backend-specific output files.
DOLFINx writes XDMF (
displacement.xdmf,von_mises_stress.xdmf). scikit-fem writes a single VTK via meshio.- Parameters:
mesh (dolfinx.mesh.Mesh | skfem.MeshTet1) – Tetrahedral mesh.
displacement (dolfinx.fem.Function | np.ndarray) – Displacement field.
von_mises (dolfinx.fem.Function | np.ndarray) – Von Mises stress.
output_dir (Path) – Directory for output files.
backend (str | None) – Override:
"dolfinx"or"skfem"when that backend is available.
- Returns:
Mapping of result name to file path (e.g.
"displacement_xdmf","von_mises_xdmf","structural_vtk").- Return type:
dict[str, str]
- stellcoilbench.structural_analysis.load_coil_mesh(msh_path: Path, *, backend: str | None = None) dolfinx.mesh.Mesh | skfem.MeshTet1
Load a Gmsh
.mshcoil mesh using the available backend.- Parameters:
msh_path (Path) – Path to the
.mshfile.backend (str | None) – Override:
"dolfinx"or"skfem"when that backend is available.
- Returns:
Backend-specific mesh object (
dolfinx.mesh.Meshorskfem.MeshTet1).- Return type:
object
- stellcoilbench.structural_analysis.run_structural_analysis(coils: list[Coil], bs: BiotSavart, output_dir: Path, msh_path: Path | None = None, vtk_path: Path | None = None, width: float = 0.05, height: float = 0.05, E: float | None = None, nu: float | None = None, structural_mesh_resolution_coarse: float | None = None, backend: str | None = None, quadrature_degree: int | None = None, polynomial_degree: int | None = None, use_spring_bc: bool = True, export_full_coil_set: bool = False, nfp: int = 1, stellsym: bool = False) dict[str, Any]
FEM structural analysis of coil geometry (J×B body force, linear elasticity, VTK/XDMF export).
Loads mesh, computes Lorentz body force, solves elasticity, exports displacement and Von Mises stress. Uses Landreman et al. regularized internal field for self-field. BC: fixed_supports pins bottom 15% z-range. See _dolfinx/_skfem for implementation details.
- Parameters:
coils (list[Coil]) – simsopt Coil objects.
bs (BiotSavart) – Magnetic field evaluator.
output_dir (Path) – Output directory.
msh_path (Path, optional) – Path to .msh file. If None, uses finite_build_coils_parastell.msh if present, else generates via sweep fallback (structural_coils.msh).
vtk_path (Path, optional) – Unused (API compatibility).
width (float) – Winding-pack cross-section [m] (default 0.05 each).
height (float) – Winding-pack cross-section [m] (default 0.05 each).
E (float, optional) – Young’s modulus [Pa], Poisson ratio. Default WP_YOUNGS_MODULUS_PA, WP_POISSON_RATIO.
nu (float, optional) – Young’s modulus [Pa], Poisson ratio. Default WP_YOUNGS_MODULUS_PA, WP_POISSON_RATIO.
structural_mesh_resolution_coarse (float, optional) – Element size [m] for tetrahedral mesh. If None, uses default (0.08 m).
backend (str, optional) – Override backend:
"dolfinx"or"skfem".quadrature_degree (int, optional) – Quadrature degree q for body-force RHS integration. Default 4.
polynomial_degree (int, optional) – FEM Lagrange order p (DOLFINx only). Default 1. Ignored by scikit-fem.
use_spring_bc (bool, optional) – Use Winkler spring-foundation BC when True (default).
export_full_coil_set (bool, optional) – When True and symmetry_factor > 1, write structural_results_full.vtk with the full coil set (unique coils + symmetry copies).
nfp (int, optional) – Number of field periods for toroidal symmetry (default 1).
stellsym (bool, optional) – Whether stellarator symmetry is used (default False).
- Returns:
max_von_mises_stress_Pa, mean_von_mises_stress_Pa, max_displacement_m, backend, structural_vtk, displacement_xdmf, von_mises_xdmf.
- Return type:
dict[str, Any]
- stellcoilbench.structural_analysis.solve_linear_elasticity(mesh: dolfinx.mesh.Mesh | skfem.MeshTet1, body_force: dolfinx.fem.Function | np.ndarray, E: float = 100000000000.0, nu: float = 0.3, *, coils: list[Coil] | None = None, bs: BiotSavart | None = None, cross_section_area: float | None = None, width: float | None = None, height: float | None = None, mesh_coils: list[Coil] | None = None, all_coils: list[Coil] | None = None, backend: str | None = None, polynomial_degree: int | None = None, use_spring_bc: bool = True) dolfinx.fem.Function | np.ndarray
Solve the 3-D linear-elasticity boundary-value problem.
Solves the weak form for displacement \(\mathbf{u}\):
\[\int_\Omega \sigma(\mathbf{u}) : \varepsilon(\mathbf{v})\,dx = \int_\Omega \mathbf{f} \cdot \mathbf{v}\,dx\]where \(\sigma = \lambda\mathrm{tr}(\varepsilon)I + 2\mu\varepsilon\) (isotropic Hooke’s law), \(\varepsilon = \tfrac{1}{2}(\nabla\mathbf{u} + \nabla\mathbf{u}^T)\), and \(\mathbf{f}\) is the Lorentz body-force density. With
use_spring_bc=True(default), a Winkler spring-foundation Robin BC is applied over the bottom 15% of the z-range, eliminating the clamped-free stress singularity. Setuse_spring_bc=Falsefor the legacy hard-Dirichlet path (\(\mathbf{u}=0\)).- Parameters:
mesh (dolfinx.mesh.Mesh | skfem.MeshTet1) – Tetrahedral mesh.
body_force (dolfinx.fem.Function | np.ndarray) – Body-force density [N/m³] from
compute_lorentz_body_force().E (float, optional) – Young’s modulus [Pa]. Default from
WP_YOUNGS_MODULUS_PA.nu (float, optional) – Poisson ratio. Default from
WP_POISSON_RATIO.coils (optional) – Passed to scikit-fem backend when body_force was precomputed elsewhere.
bs (optional) – Passed to scikit-fem backend when body_force was precomputed elsewhere.
cross_section_area (optional) – Passed to scikit-fem backend when body_force was precomputed elsewhere.
width (optional) – Passed to scikit-fem backend when body_force was precomputed elsewhere.
height (optional) – Passed to scikit-fem backend when body_force was precomputed elsewhere.
mesh_coils (list[Coil] | None, optional) – Coils for mesh (multi-coil case).
all_coils (list[Coil] | None, optional) – Full coil set for mutual B in scikit-fem.
use_spring_bc (bool, optional) – When
True(default), uses a Winkler spring-foundation Robin BC to avoid the clamped-free stress singularity.Falseselects the legacy hard-Dirichlet BC for comparison. Dolfinx backend only.
- Returns:
Displacement field [m] at mesh nodes.
- Return type:
dolfinx.fem.Function | np.ndarray
- stellcoilbench.structural_analysis.write_structural_vtk(mesh: dolfinx.mesh.Mesh | skfem.MeshTet1, displacement: dolfinx.fem.Function | np.ndarray, von_mises: dolfinx.fem.Function | np.ndarray, output_path: Path) Path
Write a standalone tetrahedral VTK with displacement and Von Mises stress.
Produces a single VTK file with: - Point data:
Displacement(3-vector),DisplacementMagnitude- Cell data:VonMisesStress(scalar per tetrahedron)- Parameters:
mesh (dolfinx.mesh.Mesh | skfem.MeshTet1) – Tetrahedral mesh.
displacement (dolfinx.fem.Function | np.ndarray) – Displacement field, shape
(n_nodes, 3).von_mises (dolfinx.fem.Function | np.ndarray) – Von Mises stress per cell or per node.
output_path (Path) – Output file path (e.g.
structural_results.vtk).
- Returns:
The path written.
- Return type:
Path
FEM structural analysis (Von Mises stress, Lorentz force). Backends: DOLFINx or scikit-fem.
Key function: run_structural_analysis. Optional: pip install .[structural].
Evaluate and Submission Pipeline (Module Responsibilities)
``evaluate``: Defines
SubmissionResultsdataclass (metadata + metrics). Lightweight container; used when structuring evaluation output.``submission_packaging``: Assembles the physical submission: builds dirs, writes
results.json, copies case YAML, zips. Used bysubmit-case.``update_db``: Consumes submissions (zips/dirs), aggregates metrics, generates leaderboards. Does not create submissions.
Validate Config Module
Validation functions for case.yaml configuration files and CI autopilot case JSON.
Validates case YAML (surface_params, coils_params, optimizer_params, coil_objective_terms, fourier_continuation, and related fields) and CI case JSON (case_id, resource caps, case_config embedding, policy limits).
- stellcoilbench.validate_config.validate_case_config(data: dict[str, Any], file_path: Path | None = None, surfaces_dir: Path | None = None) list[str]
Validate a case.yaml configuration dictionary.
Checks required fields (description, surface_params, coils_params, optimizer_params), valid keys for each section, type/value constraints, and that the referenced surface file exists in plasma_surfaces/.
- Parameters:
data (dict[str, Any]) – Parsed YAML/JSON configuration to validate.
file_path (Path, optional) – Path to source file; used for error message prefixes.
surfaces_dir (Path, optional) – Directory containing surface files. If None, uses repo-relative
plasma_surfaces/.
- Returns:
Error messages. Empty list means validation passed.
- Return type:
list[str]
- stellcoilbench.validate_config.validate_case_yaml_file(file_path: Path, surfaces_dir: Path | None = None) list[str]
Validate a case.yaml file on disk.
Loads the file with load_yaml, then delegates to validate_case_config.
- Parameters:
file_path (Path) – Path to the case YAML file.
surfaces_dir (Path, optional) – Directory containing plasma surface files. If None, uses repo-relative plasma_surfaces/.
- Returns:
Error messages. Empty list means validation passed.
- Return type:
list[str]
- stellcoilbench.validate_config.validate_ci_case(data: dict[str, Any], policy: dict[str, Any] | None = None, file_path: Path | None = None) list[str]
Validate a CI autopilot case JSON dictionary.
The CI case wraps a standard case config inside a
case_configkey and addscase_id,resource, and optionalparent_ids/tags/random_seedfields.- Parameters:
data (dict) – Parsed JSON for the CI case.
policy (dict, optional) – Proposer policy (from
policy/proposer_policy.yaml). If provided, resource caps are taken frompolicy["resource_caps"].file_path (Path, optional) – Used for error-message prefixes.
- Returns:
Error messages. Empty list means validation passed.
- Return type:
list[str]
- stellcoilbench.validate_config.validate_ci_case_file(file_path: Path, policy: dict[str, Any] | None = None) list[str]
Validate a CI autopilot case JSON file on disk.
Loads the file with json.load, then delegates to validate_ci_case.
- Parameters:
file_path (Path) – Path to the CI case JSON file.
policy (dict[str, Any], optional) – Proposer policy for resource caps.
- Returns:
Error messages. Empty list means validation passed.
- Return type:
list[str]
The validate_config module provides configuration validation.
- validate_case_config(data: Dict[str, Any], file_path: Path | None = None, surfaces_dir: Path | None = None) -> List[str]
Validate a case configuration dictionary.
Checks for:
Required fields
Valid surface names
Valid algorithm names
Valid objective term options
Type correctness
Parameters:
data: Configuration dictionaryfile_path: Optional file path for error messagessurfaces_dir: Optional directory for surface file existence checks
Returns:
List[str]: List of error messages (empty if valid)
- validate_case_yaml_file(file_path: Path, surfaces_dir: Path | None = None) -> List[str]
Validate a case YAML file on disk. Loads with load_yaml, then delegates to validate_case_config.
CLI Module
Typer CLI package for StellCoilBench.
Provides commands: submit-case, run-case, run-ci-case, update-db, generate-submission, post-process. Subcommand implementations live in sibling modules; this module wires the app and exports the public API.
- stellcoilbench.cli.main() None
The cli module implements the command-line interface.
Public vs internal: Commands (submit_case, run_case, etc.) and app are
public. Helpers such as _detect_github_username, _zip_submission_directory,
NumpyJSONEncoder are re-exported for tests and advanced use but may change.
- app
Typer application instance. Commands: validate-config, list-cases, submit-case, run-case, run-ci-case, update-db, generate-submission, post-process, sensitivity.
- NumpyJSONEncoder
Custom JSON encoder that handles numpy types and arrays. Used for serializing results to JSON.
validate_config_cmd — CLI command: Validate a case YAML configuration.
list_cases — CLI command: List available benchmark cases from cases/*.yaml.
submit_case — CLI command: Run a case and create a submission.
run_case — CLI command: Run a case without creating a submission.
run_ci_case — CLI command: Run a case in CI mode (optimization only).
- generate_submission — CLI command: Create a submission from existing results.
Packages coils.json and metadata.yaml into a results.json submission. Uses a placeholder
chi2_Bn: 0.001for metrics (external results are not recomputed). For full metric computation, runsubmit-caseorpost-processfirst. Expected metadata.yaml keys:method_version,contact,hardware.
post_process — CLI command: Run post-processing on coils (Poincaré, VMEC, etc.).
update_db_cmd — CLI command: Regenerate leaderboards.
sensitivity_cmd — CLI command: Run coil sensitivity analysis.
See Overview for usage details.
Usage Examples
Running Optimization Programmatically
from pathlib import Path from stellcoilbench.case_loader import load_case from stellcoilbench.coil_optimization import optimize_coils # Load case case_path = Path("cases/basic_LandremanPaulQA.yaml") case_cfg = load_case(case_path) # Run optimization (returns metrics directly) results = optimize_coils( case_path=case_path, coils_out_path=Path("output/coils.json"), case_cfg=case_cfg, output_dir=Path("output/") ) # Results contain metrics from the optimization pipeline print(f"Results: {results}")
Creating Custom Objective Terms
from stellcoilbench.coil_optimization import LinearPenalty from simsopt.objectives import Weight # Create a custom penalty term penalty = LinearPenalty( func=lambda x: compute_something(x), threshold=1.0, penalty_type="l2_threshold" ) # Scale with weight weighted_penalty = Weight(1e-3) * penalty # Add to objective objective = flux_term + weighted_penalty
Updating Leaderboards Programmatically
from pathlib import Path from stellcoilbench.update_db import update_database # Update leaderboards update_database( repo_root=Path("."), submissions_root=Path("submissions/"), docs_dir=Path("docs/") )
Next Steps
Overview: See Overview for setup and quick start
Cases: Learn about case files in Cases
Usage: See Overview for commands and workflow
Leaderboard: View results in StellCoilBench Leaderboard