Source code for scpn_fusion.phase.gk_upde_bridge

# SPDX-License-Identifier: AGPL-3.0-or-later
# Commercial license available
# © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
# © Code 2020–2026 Miroslav Šotek. All rights reserved.
# ORCID: 0009-0009-3560-0851
# Contact: www.anulum.li | protoscience@anulum.li
# SCPN Fusion Core — GK → UPDE Phase Dynamics 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)
"""

from __future__ import annotations

import numpy as np
from numpy.typing import NDArray

from scpn_fusion.core.gk_interface import GKOutput


[docs] def adaptive_knm( K_base: NDArray[np.float64], gk_output: GKOutput, chi_i_profile: NDArray[np.float64] | None = None, gamma_ref: float = 0.2, chi_ref: float = 1.0, ) -> NDArray[np.float64]: """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]. """ K = K_base.copy() L = K.shape[0] if L < 6: return K # P0↔P1: microturbulence ↔ zonal flows max_gamma = float(np.max(gk_output.gamma)) if len(gk_output.gamma) > 0 else 0.0 K[0, 1] = K_base[0, 1] * (1.0 + 0.5 * np.tanh(max_gamma / max(gamma_ref, 1e-10))) K[1, 0] = K[0, 1] # P1↔P4: zonal flow ↔ transport barrier mean_chi_e = max(gk_output.chi_e, 1e-10) K[1, 4] = K_base[1, 4] * (1.0 + 0.3 * np.clip(mean_chi_e / chi_ref, 0, 2)) K[4, 1] = K[1, 4] # P3↔P4: sawtooth/ELM ↔ transport barrier (pedestal ratio) if chi_i_profile is not None and len(chi_i_profile) > 5: chi_core = max(float(np.mean(chi_i_profile[: len(chi_i_profile) // 3])), 1e-10) chi_ped = max(float(np.mean(chi_i_profile[-len(chi_i_profile) // 5 :])), 1e-10) K[3, 4] = K_base[3, 4] * (1.0 + 0.4 * (chi_ped / chi_core - 1.0)) K[4, 3] = K[3, 4] return K
[docs] def gk_natural_frequencies( omega_base: NDArray[np.float64], gk_output: GKOutput, gamma_scale: float = 0.1, ) -> NDArray[np.float64]: """Adjust layer-0 natural frequency based on GK growth rate. The turbulence layer's effective frequency increases with the dominant instability growth rate. """ omega = omega_base.copy() max_gamma = float(np.max(gk_output.gamma)) if len(gk_output.gamma) > 0 else 0.0 omega[0] += gamma_scale * max_gamma return omega