Skip to content

Latest commit

 

History

History
531 lines (384 loc) · 17.3 KB

File metadata and controls

531 lines (384 loc) · 17.3 KB

Contributing to SCPN Fusion Core

Thank you for your interest in contributing to SCPN Fusion Core -- a neuro-symbolic tokamak simulation and control framework. Contributions from the fusion plasma physics, scientific computing, and open-source communities are welcome and valued.

Please read this guide carefully before submitting your first pull request.


Table of Contents


Code of Conduct

This project follows the Contributor Covenant v2.1. By participating, you agree to uphold a welcoming, inclusive, and harassment-free environment for everyone. Violations can be reported to protoscience@anulum.li.


Getting Started

  1. Fork the repository on GitHub.
  2. Clone your fork:
    git clone https://github.com/<your-username>/scpn-fusion-core.git
    cd scpn-fusion-core
  3. Create a feature branch from main:
    git checkout -b feature/your-feature-name
  4. Install in development mode:
    pip install -e ".[dev]"
  5. Verify your setup by running the test suite:
    pytest tests/ -v

Development Environment

Python

Required: Python 3.9 or later.

# Create a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate    # Linux/macOS
.venv\Scripts\activate       # Windows

# Install with development dependencies
pip install -e ".[dev]"

# Verify installation
python -c "import scpn_fusion; print(scpn_fusion.__version__)"
pytest tests/ -v

Git LFS (Required for Weights/Reference Binaries)

Model weights and reference .npz/.npy artifacts are tracked with Git LFS. Set this up once per machine:

git lfs install
git lfs pull

Before pushing, run:

python tools/check_lfs_hygiene.py

This is also enforced by local pre-commit/pre-push guards.

Rust (Optional)

The Rust workspace provides high-performance kernels. All functionality works without Rust via NumPy/SciPy fallbacks. If you want to contribute to the Rust codebase:

Required: Rust stable toolchain (1.75+), installed via rustup.

cd scpn-fusion-rs

# Build
cargo build --release

# Test
cargo test --all-features

# Format check
cargo fmt --all -- --check

# Lint (zero warnings policy)
cargo clippy --all-targets --all-features -- -D warnings

# Build Python bindings (requires maturin)
pip install maturin
cd crates/fusion-python
maturin develop --release

Docker

For a reproducible environment without local toolchain setup:

docker build --build-arg INSTALL_DEV=1 -t scpn-fusion-core:dev .
docker run scpn-fusion-core:dev pytest tests/ -v

Code Style

Python

Tool Purpose Configuration
black Formatter Default settings (line length 88)
ruff Linter Default rule set
# Format
black src/ tests/

# Lint
ruff check src/ tests/
# Optional: install pre-commit hooks for local parity with CI style gates
pip install pre-commit
pre-commit install
pre-commit run --all-files

# Required: enable repository-native git hooks (commit + push guards)
git config core.hooksPath .githooks

# Ensure hook scripts are executable (Linux/macOS/Git Bash)
chmod +x .githooks/pre-commit .githooks/pre-push

Additional conventions:

  • Type hints: Use on all public API functions and class methods.
  • Docstrings: NumPy or Google style. All public functions, classes, and modules must have docstrings.
  • Imports: Standard library, then third-party, then local -- separated by blank lines. Use absolute imports within the package.

Rust

Tool Purpose Policy
rustfmt Formatter Default settings; run cargo fmt before every commit
clippy Linter Zero warnings (-D warnings); no #[allow] without justification
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings

Additional conventions:

  • All pub items must have /// doc comments.
  • Avoid unwrap() and expect() in library code. Use FusionResult<T> for fallible operations.
  • Use thiserror for error type definitions.

Copyright Headers

Every new source file must include a copyright header at the top. Use the following template:

Python:

# SCPN Fusion Core
# Copyright concepts (c) 1996-2026 Miroslav Sotek. All rights reserved.
# Copyright code (c) 2023-2026 Miroslav Sotek. All rights reserved.
# ORCID: https://orcid.org/0009-0009-3560-0851
# Contact: www.anulum.li | protoscience@anulum.li
# License: GNU AGPL v3 | Commercial licensing available

Rust:

// SCPN Fusion Core
// Copyright concepts (c) 1996-2026 Miroslav Sotek. All rights reserved.
// Copyright code (c) 2023-2026 Miroslav Sotek. All rights reserved.
// ORCID: https://orcid.org/0009-0009-3560-0851
// Contact: www.anulum.li | protoscience@anulum.li
// License: GNU AGPL v3 | Commercial licensing available

Testing Requirements

All tests must pass before a pull request will be reviewed.

Python Tests

# Run the full test suite
pytest tests/ -v

# Run strict typing with CI-parity settings
python tools/run_mypy_strict.py

# Run a specific test file
pytest tests/test_physics.py -v

# Run with coverage reporting
pytest tests/ -v --cov=scpn_fusion --cov-report=term-missing

# Run local CI-parity gate before every push (recommended default)
python tools/run_python_preflight.py --gate release

# Optional stricter local gate (release + research lane)
python tools/run_python_preflight.py --gate all

Local CI-First Rules (Mandatory)

  1. Never push without a green local preflight gate (release at minimum).
  2. Never use --no-verify to bypass hooks except for incident recovery; if used, document reason in docs/CI_FAILURE_LEDGER.md.
  3. Treat drift detected and manifest is stale as local process failures; regenerate artifacts and re-run preflight before push.
  4. Treat infrastructure-only errors (e.g., upstream HTTP 500 from GitHub services) as transient and re-run CI before changing code.
  5. Keep core.hooksPath=.githooks configured in every local clone.

Rust Tests

cd scpn-fusion-rs
cargo test --all-features

# Run benchmarks (optional, for performance-related changes)
cargo bench

What to Test

  • New features: Add unit tests that cover the happy path, edge cases, and expected error conditions.
  • Bug fixes: Add a regression test that fails without the fix and passes with it.
  • Physics modules: Include at least one numerical invariant test (e.g., conservation law, symmetry property, known analytical solution).
  • Property-based tests: Use Hypothesis (Python) or proptest (Rust) for numerical routines where applicable.

Continuous Integration

The CI pipeline runs on every push and pull request. It checks:

  • black --check and ruff check (Python formatting/linting)
  • python tools/run_mypy_strict.py (strict Python typing)
  • cargo fmt --check and cargo clippy (Rust formatting/linting)
  • pytest tests/ (Python test suite)
  • cargo test (Rust test suite)
  • cargo audit (Rust dependency vulnerability scan)

Your PR will not be merged until all CI checks pass.


Local Operational Artifacts

Operational handover notes under .handovers/ are strictly local-only working artifacts and must not be committed or pushed to public remotes.

If you generate local handover notes, keep them under .handovers/ and verify they are excluded from git status before committing.


Branch Naming Conventions

Use descriptive branch names with the following prefixes:

Prefix Use Case Example
feature/ New functionality feature/multigrid-v-cycle
fix/ Bug fixes fix/sor-convergence-check
docs/ Documentation only docs/solver-tuning-examples
refactor/ Code restructuring (no behavior change) refactor/transport-module-split
test/ Test additions or improvements test/property-based-inverse
bench/ Benchmarking additions bench/criterion-fft-kernel
ci/ CI/CD pipeline changes ci/add-coverage-reporting

Always branch from main. Keep branches focused on a single concern.


Commit Message Format

Use clear, descriptive commit messages following this pattern:

<type>(<scope>): <short summary>

<optional body explaining WHY, not WHAT>

<optional footer with references>

Types: feat, fix, docs, test, refactor, bench, ci, chore

Scope: The module or area affected (e.g., kernel, transport, scpn, fusion-core, ci).

Examples:

feat(transport): add neoclassical bootstrap current model

Implements the Sauter et al. (1999) bootstrap current formula
for use in the integrated transport solver. Validated against
Table 2 of the original paper.

Refs: Sauter et al., Phys. Plasmas 6, 2834 (1999)
fix(inverse): prevent singular Jacobian in Levenberg-Marquardt

The LM solver could encounter a singular Jacobian when coil
currents were near zero. Added a Tikhonov regularization floor
of 1e-8 to prevent division by zero.

Fixes #42
test(stability): add proptest for Mercier criterion symmetry

Pull Request Process

Before Submitting

  1. Rebase on latest main to avoid merge conflicts.
  2. Run the full test suite locally (pytest tests/ -v and cargo test).
  3. Format and lint your code (black, ruff, cargo fmt, cargo clippy).
  4. Update documentation if you changed any public API.
  5. Review your own diff -- remove debugging artifacts, unrelated changes, and commented-out code.

PR Requirements

  • Focused scope: One feature, one fix, or one refactor per PR. Do not mix unrelated changes.
  • Tests: Include tests that fail without your change and pass with it.
  • Documentation: Update docstrings, Sphinx docs, or rustdoc for any public API changes.
  • No regressions: All existing tests must continue to pass.
  • Descriptive title and body: Summarize the change, explain why it is needed, and link any related issues.

Review Process

  1. At least one maintainer approval is required before merge.
  2. Reviewers may request changes. Please address all comments or explain why you disagree.
  3. Once approved, a maintainer will merge using squash-merge to keep the commit history clean.
  4. The CI pipeline must be fully green before merge.

What Makes a Good PR

  • Focused scope (one logical change).
  • Tests that demonstrate the change works.
  • No unrelated formatting or whitespace changes.
  • Clear commit messages that explain why, not just what.
  • Links to relevant issues, papers, or external references.

Reporting Issues

Use our issue templates:

  • Bug Report: Include reproduction steps, environment details, and full error output.
  • Feature Request: Describe the problem being solved and the proposed approach, including any relevant physics or engineering context.
  • Security Vulnerability: Do not open a public issue. See SECURITY.md for responsible disclosure instructions.

Architecture Overview

Understanding the project structure will help you contribute effectively:

  • src/scpn_fusion/ -- Python package (src layout), the primary interface.
  • scpn-fusion-rs/ -- Rust workspace mirroring the Python structure for performance-critical paths.
  • scpn-fusion-rs/crates/fusion-python/ -- PyO3 bindings connecting Rust to Python.
  • scpn/ -- Neuro-symbolic compiler (Petri nets to stochastic neurons).
  • validation/ -- Reference data from real tokamaks (SPARC, ITPA, ITER).
  • tests/ -- Python test suite.
  • docs/ -- Technical documentation, solver guides, benchmark reports.
  • examples/ -- Jupyter notebooks and standalone scripts.

For a detailed architecture diagram, see the README.


Priority Areas for Contribution

We especially welcome contributions in these areas:

Area Examples Skill Level
Benchmarks Criterion.rs benchmarks, Python timing comparisons Intermediate
Validation Cross-checking against published tokamak data (JET, DIII-D, ITER) Advanced
Solver improvements SOR/multigrid upgrades, adaptive mesh refinement Advanced
Documentation Tutorials, Jupyter notebooks, docstring improvements Beginner
Testing Increasing coverage, property-based testing (Hypothesis/proptest) Beginner-Intermediate
GPU acceleration CUDA/OpenCL offload for SOR, FFT, transport solvers Advanced
Data integration IMAS IDS import/export, MDSplus readers, CHEASE format Intermediate

Good First Issues

Look for issues tagged good first issue on our issue tracker. Some ideas:

  • Add GEQDSK test cases from publicly available tokamak data (MAST-U, W7-X).
  • Add Hypothesis property tests for numerical routines in core/.
  • Write a new tutorial notebook demonstrating a specific physics module.
  • Reduce P0/P1 entries in UNDERDEVELOPED_REGISTER.md (see Executive Summary for current counts).
  • Contribute real experimental validation data (equilibria, confinement profiles).

License Implications

SCPN Fusion Core is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later). By submitting a pull request, you agree to the following:

  1. Your contributions will be licensed under the AGPL-3.0-or-later, the same license as the rest of the project. You retain copyright on your contributions.
  2. You certify that you have the right to submit the contribution under this license (i.e., it is your original work, or you have permission from the copyright holder).
  3. Derivative works that incorporate your contribution must also be released under the AGPL-3.0-or-later when distributed or made available over a network.
  4. Commercial licensing is available separately from the project maintainer for organizations that cannot comply with AGPL requirements. Contact protoscience@anulum.li for details.

If you have questions about licensing, please ask before submitting your contribution.


Questions?

Thank you for helping improve fusion plasma simulation and control.


Module Ownership

The Python source tree (src/scpn_fusion/) is organised into subsystems. When contributing, target the appropriate subsystem and follow existing patterns within that directory.

Subsystem Files Scope
core/ 118 GS equilibrium, transport, GK three-path, MHD stability, disruptions, edge physics, neural surrogates, JAX solvers, scenario simulation, 3D geometry, UQ
control/ 54 PID, H-infinity, mu-synthesis, NMPC, SNN, RL, free-boundary tracking, disruption mitigation, burn control, flight sim, HiL
phase/ 10 Kuramoto UPDE solver, adaptive K_nm, GK-to-UPDE bridge, plasma coupling, Lyapunov guard
scpn/ 12 Petri net compiler, formal contracts, safety interlocks, artifact management
io/ 15 IMAS connector/adapter, GEQDSK I/O, tokamak archive, logging
diagnostics/ 5 Synthetic diagnostic forward models, sensors, tomography
engineering/ 4 Balance of plant, CAD raytrace, thermal hydraulics
nuclear/ 5 Blanket neutronics, PWI erosion, tritium breeding
hpc/ 2 C++ solver bridge, HPC types
ui/ 4 Streamlit dashboard, generator, launcher

Rust crates (scpn-fusion-rs/crates/): 11 crates mirroring the Python structure. See ARCHITECTURE.md for the full crate map.

Total: 234 Python source files, 62,570 lines, 11 Rust crates, 2859 tests.


Session Logs & Handovers

All session logs and handover documents for this project are stored permanently in the monorepo's canonical location:

  • Session logs: .coordination/sessions/SCPN-Fusion-Core/
  • Handovers: .coordination/handovers/SCPN-Fusion-Core/

Do not place session logs or handovers inside this project directory. They will be moved during consolidation.

These files are permanent records and must never be deleted, even if outdated.

See .coordination/SESSION_AND_HANDOVER_POLICY.md for naming conventions, templates, and the full policy.