Skip to content

Architecture

Module Map

graph TD
    CLI[cli.py] --> SCPN[scpn/]
    CLI --> CORE[core/]
    CLI --> CTRL[control/]
    CLI --> PHASE[phase/]

    subgraph "scpn/ — Petri Net Compiler"
        SPN[structure.py] --> COMP[compiler.py]
        COMP --> CNET[CompiledNet]
        CNET --> NSC[controller.py]
        CON[contracts.py] --> NSC
    end

    subgraph "core/ — Physics Solvers (67 modules)"
        FK[fusion_kernel.py] --> TC[tokamak_config.py]
        ITS[integrated_transport_solver.py]
        NEQ[neural_equilibrium.py]
        GT2[gyrokinetic_transport.py]
        BS2[ballooning_solver.py]
        ST2[sawtooth.py]
        NTM2[ntm_dynamics.py]
        CD2[current_diffusion.py]
        SOL2[sol_model.py]
        ISS2[integrated_scenario.py]
    end

    subgraph "control/ — Controllers (42 modules)"
        HINF2[h_infinity_controller.py]
        MU2[mu_synthesis.py]
        NMPC2[nmpc_controller.py]
        GS_C[gain_scheduled_controller.py]
        SM2[sliding_mode_vertical.py]
        FT2[fault_tolerant_control.py]
        SC2[shape_controller.py]
        DP[disruption_predictor.py]
        GYM[gym_tokamak_env.py]
    end

    subgraph "phase/ — Paper 27 Dynamics"
        KUR[kuramoto.py] --> UPDE[upde.py]
        KNM[knm.py] --> UPDE
        UPDE --> LG[lyapunov_guard.py]
        UPDE --> RM[realtime_monitor.py]
        RM --> WS[ws_phase_stream.py]
    end

Logical Data Flow

The following diagram illustrates the signal path from equilibrium input to real-time actuation through the optional Rust acceleration layer.

GEQDSK/IMAS Input
FusionKernel (GS solver, 65×65)
    ↓                    ↓
NeuralEquilibrium   IntegratedTransportSolver
(0.39ms surrogate)    (1.5D Crank-Nicolson)
    ↓                    ↓
    └──────┬─────────────┘
    Controller Selection
    ├── PID / Gain-Scheduled (GainScheduledController)
    ├── H-infinity (HInfinityController)
    ├── Mu-Synthesis (MuSynthesisController)
    ├── NMPC (NMPCController, SQP 20-step)
    ├── MPC (ModelPredictiveController)
    ├── Sliding-Mode (SlidingModeVerticalController)
    ├── Fault-Tolerant (FaultTolerantController)
    ├── Shape (ShapeController)
    ├── RL/PPO (SafeRLController + SB3)
    └── SNN (LIF+NEF SNN Controller)
    DisruptionPredictor
    (LSTM + Greenwald + VDE)
    SPIMitigation → CoilSet actuation
    Rust Kernel (11.9 µs, PyO3)

Module Dependencies

Simplified internal dependency graph (arrows indicate "imports"):

graph LR
    subgraph "High Level"
        FS[tokamak_flight_sim]
        GYM[gym_tokamak_env]
    end

    subgraph "Controllers"
        MPC[fusion_sota_mpc]
        HINF[h_infinity_controller]
        MU[mu_synthesis]
        NMPC[nmpc_controller]
        GS_CTRL[gain_scheduled]
        SM[sliding_mode_vertical]
        FT[fault_tolerant]
        SC[shape_controller]
        SNN[snn_controller]
        SRL[safe_rl_controller]
    end

    subgraph "Core Physics"
        ITS[integrated_transport_solver]
        FK[fusion_kernel]
        NEQ[neural_equilibrium]
        NT[neural_transport]
        GT[gyrokinetic_transport]
        BS[ballooning_solver]
        ST[sawtooth]
        NTM[ntm_dynamics]
        CD[current_diffusion]
        SOL[sol_model]
        ISS[integrated_scenario]
    end

    subgraph "Foundation"
        RC[_rust_compat]
        VAL[_validators]
    end

    FS --> MPC
    FS --> HINF
    GYM --> FK
    MPC --> NEQ
    ITS --> FK
    ITS --> NT
    FK --> RC
    NEQ --> RC
    RC --> VAL

Rust / Python Boundary

flowchart LR
    subgraph Python
        P1[FusionKernel]
        P2[RealtimeMonitor]
        P3[SnnPool]
        P4[MpcController]
    end

    subgraph "PyO3 Bindings (control-python)"
        B1[PyFusionKernel]
        B2[PyRealtimeMonitor]
        B3[PySnnPool]
        B4[PyMpcController]
    end

    subgraph "Rust Workspace"
        R1[control-core]
        R2[control-math]
        R3[control-control]
        R4[control-types]
    end

    P1 -. "_rust_compat" .-> B1 --> R1
    P2 -. "_rust_compat" .-> B2 --> R2
    P3 -. "_rust_compat" .-> B3 --> R3
    P4 -. "_rust_compat" .-> B4 --> R3
    R1 --> R4
    R2 --> R4
    R3 --> R4

The _rust_compat.py module probes for the compiled scpn_control_rs extension at import time. If present, hot paths (GS solve, Kuramoto step, SNN tick, MPC solve) dispatch to Rust. Otherwise, pure-NumPy fallbacks execute identically.

Data Flow: Closed-Loop Control

sequenceDiagram
    participant Plant as TokamakDigitalTwin
    participant Obs as ControlObservation
    participant Ctrl as NeuroSymbolicController
    participant Act as ControlAction
    participant Guard as LyapunovGuard

    loop every dt
        Plant->>Obs: measure(Ip, q95, βN, li, Wmhd, ...)
        Obs->>Ctrl: step(observation)
        Ctrl->>Act: (Ip_cmd, shape_cmd, heating_cmd)
        Act->>Plant: actuate(action)
        Plant->>Guard: check(θ, Ψ)
        Guard-->>Ctrl: approved / halt
    end

Directory Layout

scpn-control/
├── src/scpn_control/     # 130 Python modules (125 non-init)
│   ├── scpn/             # SPN → SNN compiler (6 modules)
│   ├── core/             # Equilibrium, transport, scaling (67 modules)
│   ├── control/          # Controllers (42 modules, optional deps guarded)
│   └── phase/            # Kuramoto/UPDE engine (9 modules)
├── scpn-control-rs/      # Rust workspace (5 crates)
├── tests/                # 3,300+ tests (235 files, 100% coverage)


├── examples/             # 6 notebooks + 3 scripts
├── validation/           # DIII-D, JET, SPARC, ITER configs + reference data
├── docs/                 # MkDocs site
└── tools/                # CI gates, calibration, publishing