scpn_fusion.phase – Phase Bridges

The phase package provides Kuramoto, UPDE, plasma K_nm, and phase-stream bridges used by cross-repository orchestration and quantum-control adapters.

Kuramoto Runtime

Mean-field Kuramoto-Sakaguchi with exogenous global driver.

Equation:

dθ_i/dt = ω_i + K·R·sin(ψ_r − θ_i − α) + ζ·sin(Ψ − θ_i)

The ζ sin(Ψ−θ) term implements the reviewer’s requested “intention as carrier” injection. Ψ is a Lagrangian pull parameter with no own dynamics (no dotΨ equation) — it is resolved either from an external value or from the mean-field phase.

Reference: arXiv:2004.06344 (generalized Kuramoto-Sakaguchi finite-size)

scpn_fusion.phase.kuramoto.wrap_phase(x)[source]

Map phases to (-π, π].

Return type:

ndarray[Any, dtype[float64]]

Parameters:

x (ndarray[Any, dtype[float64]])

scpn_fusion.phase.kuramoto.order_parameter(theta, weights=None)[source]

Kuramoto order parameter R·exp(i·ψ_r) = <w·exp(i·θ)> / W.

Returns (R, ψ_r).

Return type:

tuple[float, float]

Parameters:
class scpn_fusion.phase.kuramoto.GlobalPsiDriver(mode='external')[source]

Bases: object

Resolve the global field phase Ψ.

mode=”external” : Ψ supplied by caller (intention/carrier, no dotΨ). mode=”mean_field” : Ψ = arg(<exp(iθ)>) from the oscillator population.

Parameters:

mode (str)

mode: str = 'external'
resolve(theta, psi_external)[source]

Resolve the global driver phase Ψ for the current tick.

Parameters:
  • theta (ndarray[Any, dtype[float64]]) – Current oscillator phase vector.

  • psi_external (float | None) – Required when mode is "external" and interpreted as carrier phase injected from supervisory policy.

Returns:

The resolved Psi to be used by kuramoto_sakaguchi_step().

Return type:

float

scpn_fusion.phase.kuramoto.lyapunov_v(theta, psi)[source]

Lyapunov candidate V(t) = (1/N) Σ (1 − cos(θ_i − Ψ)).

V=0 at perfect sync (all θ_i = Ψ), V=2 at maximal desync. Range: [0, 2]. Mirror of control-math/kuramoto.rs::lyapunov_v.

Return type:

float

Parameters:
scpn_fusion.phase.kuramoto.lyapunov_exponent(v_hist, dt)[source]

λ = (1/T) · ln(V_final / V_initial). λ < 0 ⟹ stable.

Return type:

float

Parameters:
scpn_fusion.phase.kuramoto.kuramoto_sakaguchi_step(theta, omega, *, dt, K, alpha=0.0, zeta=0.0, psi_driver=None, psi_mode='external', wrap=True)[source]

Single Euler step of mean-field Kuramoto-Sakaguchi + global driver.

dθ_i/dt = ω_i + K·R·sin(ψ_r − θ_i − α) + ζ·sin(Ψ − θ_i)

The driver phase Ψ is resolved here (external/mean-field policy), then the arithmetic executes on the fastest available kuramoto_step dispatcher tier (Rust fusion-phase when built, NumPy floor always). Tiers agree to floating-point summation order (~1e-14 relative).

Return type:

dict[str, Any]

Parameters:

Plasma K_nm Bridge

Paper 27 Knm specification.

K[n, m] encodes coupling from source layer n to target layer m. Diagonal: intra-layer synchronisation strength. Off-diagonal: inter-layer bidirectional causality (bottom-up / top-down).

class scpn_fusion.phase.knm.KnmSpec(K, alpha=None, zeta=None, layer_names=None)[source]

Bases: object

Paper 27 coupling specification.

K : (L, L) coupling matrix. K[n, m] = source n -> target m. alpha : (L, L) Sakaguchi phase-lag (optional). zeta : (L,) per-layer global-driver gain ζ_m (optional).

Parameters:
K: ndarray[Any, dtype[float64]]
alpha: ndarray[Any, dtype[float64]] | None = None
zeta: ndarray[Any, dtype[float64]] | None = None
layer_names: Optional[Sequence[str]] = None
property L: int

Number of Kuramoto layers in this specification.

Returns:

Number of sources/targets (matrix width and height) for K.

Return type:

int

scpn_fusion.phase.knm.build_knm_paper27(L=16, K_base=0.45, K_alpha=0.3, zeta_uniform=0.0)[source]

Build the canonical Paper 27 Knm with exponential distance decay.

K[i, j] = K_base * exp(-K_alpha * abs(i - j)); diag(K) is kept for intra-layer sync, unlike the inter-oscillator Knm which zeros the diagonal.

K_base=0.45 and K_alpha=0.3 from Paper 27 §3.2, Eq. 12. Calibration anchors from Paper 27, Table 2. Cross-hierarchy boosts from Paper 27 §4.3.

Return type:

KnmSpec

Parameters:

UPDE Runtime

Unified Phase Dynamics Equation — multi-layer evolution parameterised by the Knm coupling matrix from Paper 27.

Per-layer equation:
dθ_{m,i}/dt = ω_{m,i}
  • K_{mm} · R_m · sin(ψ_m − θ_{m,i} − α_{mm})

  • Σ_{n≠m} K_{nm} · R_n · sin(ψ_n − θ_{m,i} − α_{nm})

  • ζ_m · sin(Ψ − θ_{m,i})

K_{mm} (diagonal): intra-layer synchronisation K_{nm} (off-diagonal): inter-layer bidirectional causality ζ_m sin(Ψ − θ): global field driver (reviewer request)

class scpn_fusion.phase.upde.UPDESystem(spec, dt=0.001, psi_mode='external', wrap=True)[source]

Bases: object

Multi-layer UPDE driven by a KnmSpec.

Parameters:
spec: KnmSpec
dt: float = 0.001
psi_mode: str = 'external'
wrap: bool = True
step(theta_layers, omega_layers, *, psi_driver=None, actuation_gain=1.0, pac_gamma=0.0, K_override=None)[source]

Advance all L layers by one Euler step.

Parameters:
  • theta_layers (sequence of 1D arrays) – Phase vectors per layer.

  • omega_layers (sequence of 1D arrays) – Natural frequencies per layer.

  • psi_driver (float or None) – External global field phase Ψ (required if psi_mode=”external”).

  • actuation_gain (float) – Multiplicative gain on all coupling terms.

  • pac_gamma (float) – PAC-like gating: boost inter-layer coupling by (1 + pac_gamma·(1 − R_source)).

  • K_override (array or None) – Per-tick replacement for spec.K (adaptive coupling).

Return type:

dict[str, Any]

run(n_steps, theta_layers, omega_layers, *, psi_driver=None, actuation_gain=1.0, pac_gamma=0.0, K_override=None)[source]

Run n_steps and return trajectory of per-layer R and global R.

With psi_mode="external" (constant driver) the whole loop runs on the batched upde_run dispatcher kernel — one boundary crossing instead of one per tick. The mean-field mode keeps the per-step path because Ψ then depends on the evolving state.

Return type:

dict[str, Any]

Parameters:
run_lyapunov(n_steps, theta_layers, omega_layers, *, psi_driver=None, actuation_gain=1.0, pac_gamma=0.0, K_override=None)[source]

Run n_steps with Lyapunov tracking.

Returns R histories, V histories, and per-layer + global λ. λ < 0 ⟹ stable convergence toward Ψ.

Return type:

dict[str, Any]

Parameters:

Gyrokinetic UPDE Bridge

Bridge gyrokinetic transport fluxes into the 8-layer UPDE Kuramoto phase dynamics system.

Maps GK-computed growth rates and diffusivities into adaptive K_nm coupling modulation for layers P0 (microturbulence), P1 (zonal flows), P4 (transport barrier), and P5 (current profile).

Reference layer mappings:

P0 ← max(gamma_ITG, gamma_TEM): turbulence drive P1 ← chi_e suppression ratio: zonal flow damping of transport P4 ← chi_i pedestal / chi_i core: transport barrier strength P5 ← bootstrap current contribution (via pressure gradient)

scpn_fusion.phase.gk_upde_bridge.adaptive_knm(K_base, gk_output, chi_i_profile=None, gamma_ref=0.2, chi_ref=1.0)[source]

Modulate K_nm based on GK fluxes.

Parameters:
  • K_base (array, shape (L, L)) – Baseline coupling matrix from build_knm_plasma().

  • gk_output (GKOutput) – GK solver output (growth rates, fluxes).

  • chi_i_profile (array or None) – Full chi_i(rho) profile for pedestal ratio calculation.

  • gamma_ref (float) – Reference growth rate for tanh scaling [c_s/a].

  • chi_ref (float) – Reference chi_e for transport modulation [m^2/s].

Return type:

ndarray[Any, dtype[float64]]

scpn_fusion.phase.gk_upde_bridge.gk_natural_frequencies(omega_base, gk_output, gamma_scale=0.1)[source]

Adjust layer-0 natural frequency based on GK growth rate.

The turbulence layer’s effective frequency increases with the dominant instability growth rate.

Return type:

ndarray[Any, dtype[float64]]

Parameters:

Phase Stream

Async WebSocket server streaming RealtimeMonitor tick snapshots.

Start standalone:

python -m scpn_fusion.phase.ws_phase_stream --port 8765

Or embed in an existing asyncio loop. Non-loopback bindings require a SCPN_PHASE_STREAM_TOKEN value and may be served with --tls-cert and --tls-key for WSS:

server = PhaseStreamServer(monitor)
await server.serve(host="127.0.0.1", port=8765)

Clients receive JSON frames every tick:

{"tick": 1, "R_global": 0.42, "V_global": 0.83, "lambda_exp": -0.12, ...}
class scpn_fusion.phase.ws_phase_stream.PhaseStreamServer(monitor, tick_interval_s=0.001, auth_token=None, max_command_messages_per_second=20, command_value_bound=1000.0)[source]

Bases: object

Async WebSocket server wrapping a RealtimeMonitor.

Parameters:
  • monitor (RealtimeMonitor)

  • tick_interval_s (float)

  • auth_token (str | None)

  • max_command_messages_per_second (int)

  • command_value_bound (float)

monitor: RealtimeMonitor
tick_interval_s: float = 0.001
auth_token: str | None = None
max_command_messages_per_second: int = 20
command_value_bound: float = 1000.0
async serve(host='127.0.0.1', port=8765, *, ssl_context=None)[source]

Start WebSocket server and tick loop.

Return type:

None

Parameters:
serve_sync(host='127.0.0.1', port=8765, *, ssl_context=None)[source]

Blocking entry point.

Return type:

None

Parameters:
scpn_fusion.phase.ws_phase_stream.main()[source]

Run the async WebSocket phase-stream server from CLI.

The server publishes one JSON snapshot per active WebSocket client per tick. Use argparse options to control topology, discretisation, and coupling intensity for reproducible replay.

Return type:

None