Getting started¶
This guide runs the FRC merge-trigger pipeline from Python and from the command line, and walks the pulsed-shot lifecycle. It covers the software surfaces that ship today; the sub-50 ns trigger fabric, its formal proofs, and the FPGA timing-closure report are roadmap items (see Architecture).
One-command demo¶
The fastest way to see the whole thing run end to end — the pulsed-shot lifecycle,
the locked-fire vs preempted merge-trigger decisions, and both seeded campaigns with
their JSON + figure artifacts — is the demo target. It needs no input files and
finishes in well under five minutes on the pure-Python floor:
git clone https://github.com/anulum/scpn-mif-core.git
cd scpn-mif-core
pip install -e ".[demo]" # core + matplotlib for the campaign figures
make demo
Artifacts land in campaigns/results/ (merge_preemption.{json,png},
faraday_compression_recovery.{json,png}). Or run it container-only, with no local
Python at all:
A GitHub Codespace (.devcontainer/) installs the same environment on open; then
just run make demo.
Install¶
The bare install runs the pure-Python reference everywhere. To pull the prebuilt
native extension so the dispatcher selects the Rust backend — the fastest measured
chain — add the accelerated extra:
The Rust path is selected automatically when the extension is importable; the package falls back to the Python reference when it is not, so behaviour is identical either way and only the speed differs.
For a working checkout with the Rust acceleration extension built from source and the developer tooling:
git clone https://github.com/anulum/scpn-mif-core.git
cd scpn-mif-core
pip install -e ".[dev]"
make bridge # build the Rust extension (optional; a Python reference runs without it)
The merge-trigger decision¶
evaluate_merge_trigger composes the kinematic, safety, capacitor-bank, and
Faraday-recovery surfaces into one fire/abort/hold decision for two
counter-propagating plasmoids.
import numpy as np
from scpn_mif_core import (
CapacitorBankSpec,
KinematicSafetySpec,
MergeWindowSpec,
MovingFrameUPDESpec,
PulseSpec,
evaluate_merge_trigger,
)
from scpn_mif_core.merge_trigger import MergeTriggerScenario
scenario = MergeTriggerScenario(
moving_frame=MovingFrameUPDESpec(
omega_rad_s=np.asarray([1.0, 1.0]),
coupling_rad_s=np.asarray([[0.0, 50.0], [50.0, 0.0]]),
),
initial_phases_rad=np.asarray([0.0, 0.004]),
initial_positions_m=np.asarray([-5.0e-4, 5.0e-4]),
velocities_m_s=np.asarray([0.0, 0.0]),
dt_s=1.0e-3,
steps=20,
merge_window=MergeWindowSpec(phase_tolerance_rad=0.01, spatial_tolerance_m=0.002, consecutive_samples=3),
safety=KinematicSafetySpec(),
bank=CapacitorBankSpec(
capacitance_F=1.0e-3,
inductance_H=1.0e-6,
series_resistance_ohm=1.0e-3,
voltage_max_V=2.0e4,
recharge_power_kW=10.0,
),
bank_initial_voltage_V=2.0e4,
compression_pulse=PulseSpec(peak_current_A=1.0e5, duration_s=1.0e-5, waveform="half_sine"),
)
report = evaluate_merge_trigger(scenario)
print(report.outcome.value) # fire
Interpreting the outcome¶
| Outcome | Meaning |
|---|---|
fire |
The approach locked at the chamber centre within the safety envelope and the bank can deliver the compression pulse. |
abort_unsafe |
The axial-separation envelope was violated; the merge is preempted before it can drive an n = 1 tilt. |
hold_no_lock |
No sustained phase-and-spatial lock within the merge window. |
abort_bank_infeasible |
Locked and safe, but the bank cannot deliver the requested compression pulse. |
Safety is checked first: an unsafe approach aborts regardless of lock, because firing into an unsafe merge is the failure the pipeline exists to preempt.
The command line¶
A fresh pip install runs a useful decision immediately, with no input file:
scpn-mif demo # built-in two-plasmoid scenario, human-readable
scpn-mif demo --json # the decision as JSON
scpn-mif demo --emit-scenario > scenario.json # save the scenario to adapt
The same decision then runs from your own JSON scenario file:
scpn-mif run scenario.json # human-readable
scpn-mif run scenario.json --json # full decision as JSON
scpn-mif ecosystem # sibling-repository compatibility report
The scenario file mirrors MergeTriggerScenario: each nested object maps to the
matching spec, with optional recovery and expansion blocks (supplied
together) for a Faraday energy-recovery estimate.
The pulsed-shot lifecycle¶
The MIF-004 finite-state machine advances a shot through
idle → ramp_up → flat_top → burn → expansion → dump → recharge → cool_down → idle
under telemetry guards. See
examples/pulsed_shot_lifecycle.py
for a complete traversal.
Runnable examples¶
Both scripts run from the repository root and are smoke-tested in CI: