GNLSE validation & convergence harness¶
Grid/step convergence studies and cited analytical validation checks for the GNLSE. Docstrings are the source of truth, rendered with mkdocstrings (numpydoc style). See GNLSE physics for the physics background and references.
photonics_helper.gnlse_validation ¶
GNLSE validation and convergence harness.
Two related tools for demonstrating numerical credibility on the user's own configuration (the "research-first" validation stance of this library):
-
:func:
convergence_study— run a caller-supplied GNLSE factory at a sequence of refined temporal grids / step sizes and report, per caller-selected observable, the value at each resolution, the relative change between successive refinements, and a converged verdict at a caller tolerance (Sinkin, Holzlöhner, Zweck & Menyuk, J. Lightwave Technol. 21, 61 (2003); Agrawal, Nonlinear Fiber Optics, 5th ed., §2.4). -
Cited analytical checks — :func:
check_spm, :func:check_mi, :func:check_soliton, :func:check_gordon_ssfs— compare a propagation result against a closed-form reference for the canonical limits: -
SPM: Stolen & Lin, Phys. Rev. A 17, 1448 (1978); Agrawal §4.1 (
N_peaks = floor(φ_max/π) + 1). - MI: Agrawal §5.1 (
g(Ω) = |β₂Ω|√(Ω_c²−Ω²),Ω_c² = 4γP/|β₂|). - Soliton: Agrawal §5.2 (fundamental soliton,
z_sol = (π/2) L_D). - SSFS: Gordon, Opt. Lett. 11, 662 (1986);
dΩ/dz = −8|β₂|T_R/(15T₀⁴),T_R = f_R ∫t·h_R(t) dt.
The checks raise :class:ValidationFailure when the documented tolerance is
exceeded, so they can be wired directly into application-level test suites.
Worked example: examples/35_gnlse_validation_harness.py runs all four
checks, prints each measured metric beside the closed form it is compared
against, runs :func:convergence_study over a z-step ladder (including
the mapping form of observables), and demonstrates both failure paths — an
under-resolved ladder with converged=False rows and a caught
:class:ValidationFailure.
Importing this module pulls the solver stack only — no plotting backends.
DEFAULT_OBSERVABLES
module-attribute
¶
DEFAULT_OBSERVABLES: dict[str, ObservableFn] = {'peak_intensity': _obs_peak_intensity, 'pulse_energy': _obs_pulse_energy, 'rms_bandwidth': _obs_rms_bandwidth, 'rms_width': _obs_rms_width}
ValidationFailure ¶
ValidationFailure(case: str, message: str, metrics: dict[str, Any] | None = None)
ObservableReport
dataclass
¶
ObservableReport(name: str, values: list[float], changes: list[float | None], change_last: float | None, converged: bool)
Per-observable convergence data (Sinkin et al. 2003).
ConvergenceReport
dataclass
¶
ConvergenceReport(refinements: list[dict[str, Any]] = list(), observables: list[ObservableReport] = list())
Result of :func:convergence_study.
refinements
class-attribute
instance-attribute
¶
refinements: list[dict[str, Any]] = field(default_factory=list)
observables
class-attribute
instance-attribute
¶
observables: list[ObservableReport] = field(default_factory=list)
converged
property
¶
converged: bool
True when every selected observable converged at the finest pair.
convergence_study ¶
convergence_study(build_solver: Callable[..., Any], refinements: Sequence[Mapping[str, Any]] | None = None, *, observables: Sequence[str] | Mapping[str, ObservableFn] | None = None, tolerance: float = 0.001, shared: Mapping[str, Any] | None = None) -> ConvergenceReport
Run a GNLSE factory at successive refinements and report convergence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
build_solver
|
callable
|
|
required |
refinements
|
sequence of mappings
|
One kwargs dict per resolution, ordered coarse → fine. |
None
|
observables
|
sequence[str] | mapping[str, callable]
|
Caller-selected observables: names into :data: |
None
|
tolerance
|
float
|
Relative-change threshold applied between the two finest resolutions. |
0.001
|
shared
|
mapping
|
Factory kwargs forwarded to every refinement. |
None
|
Returns:
| Type | Description |
|---|---|
ConvergenceReport
|
|
check_spm ¶
check_spm(gamma: float, peak_power: float, t0: float, wavelength_m: float, phi_max: float, grid: Any, tolerance: float = 0.005) -> dict[str, Any]
Kerr-only SPM: compare the propagated spectrum with the closed form.
For a Gaussian input with zero dispersion the exact output field is
A(L,t) = √P₀ e^{−t²/2T₀²} e^{i φ_max e^{−t²/T₀²}} with
φ_max = γP₀L (Stolen & Lin 1978; Agrawal §4.1). Checks (i) the
simulated spectrum against the closed-form Fourier integral and (ii) the
fringe rule N_peaks = floor(φ_max/π) + 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid
|
TemporalGrid
|
|
required |
tolerance
|
float
|
Max absolute deviation between normalized spectra. |
0.005
|
Returns:
| Type | Description |
|---|---|
dict — the validation metrics (also returned on success).
|
|
Raises:
| Type | Description |
|---|---|
ValidationFailure — when either check fails.
|
|
mi_gain_of ¶
mi_gain_of(beta2: float, gamma: float, P: float, omega: float) -> float
Exact linear-stability MI gain g(Ω) at a single offset (Agrawal 5.1.9).
g(Ω) = |β₂Ω|√(Ω_c²−Ω²), Ω_c² = 4γP/|β₂|, in the power-gain
convention (sideband intensity grows as e^{g z}) used throughout this
library — validated by :func:check_mi and the Dudley Fig. 23
reproduction (g_max = 2γP).
gordon_ssfs_rate ¶
gordon_ssfs_rate(beta2: float, gamma: float, peak_power: float, t0: float, t_raman: float) -> float
Gordon's linear SSFS rate dΩ/dz (rad/s/m, negative = red shift).
Gordon, Opt. Lett. 11, 662 (1986), for a fundamental soliton:
dΩ/dz = −(8/15)·|β₂|·T_R/T₀⁴, T_R = f_R ∫t·h_R(t)dt.
The peak_power/gamma inputs are used to assert the soliton-order
condition γP₀T₀²/|β₂| = 1 (within 1 %); pass the soliton's peak power.
Dimensions: β₂ (s²/m) × T_R (s) / T₀⁴ (s⁴) → 1/(m·s³).
check_mi ¶
check_mi(beta2: float, gamma: float, pump_power: float, wavelength_m: float, probe_omega: float, grid: Any, length: float | None = None, rel_tolerance: float = 0.15) -> dict[str, Any]
Modulation-instability gain vs the exact linear-stability result.
Seeds a CW pump with a weak real probe perturbation
ε·cos(probe_omega·t) (one sideband pair on the periodic grid) and
measures the exponential power-gain coefficient of the sideband pair
from the late-time slope of ln(P_side(z)); compares against the closed
form g(Ω) = |β₂Ω|√(Ω_c²−Ω²), Ω_c² = 4γP/|β₂| (Agrawal Eq. 5.1.9,
in the power-gain convention validated against Dudley Fig. 23 by the
fix-mi-gain-convention change: sideband intensity grows as
e^{g z}, so the field amplitude grows as e^{g z/2}). Requires
anomalous dispersion (β₂ < 0) and Ω_probe < Ω_c.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid
|
TemporalGrid
|
|
required |
length
|
float | None — propagation length (m). When ``None``, chosen so
|
the analytic sideband power gain reaches a factor ≈ e⁴. |
None
|
rel_tolerance
|
float — allowed relative deviation of the measured gain.
|
|
0.15
|
Raises:
| Type | Description |
|---|---|
ValidationFailure — when the measured gain deviates beyond tolerance.
|
|
check_soliton ¶
check_soliton(beta2: float, gamma: float, t0: float, wavelength_m: float, grid: Any, periods: float = 1.0, tolerance: float = 0.02) -> dict[str, float]
Fundamental soliton: after z_sol = (π/2)·L_D the shape returns.
Propagates an N = 1 soliton over periods × z_sol and checks the
field-weighted shape overlap with the input (Agrawal §5.2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid
|
TemporalGrid
|
|
required |
periods
|
float — number of soliton periods to propagate (default 1).
|
|
1.0
|
tolerance
|
float — maximum allowed overlap deficit (1 − overlap).
|
|
0.02
|
Raises:
| Type | Description |
|---|---|
ValidationFailure — when the overlap drops below ``1 − tolerance``.
|
|
check_gordon_ssfs ¶
check_gordon_ssfs(beta2: float, gamma: float, peak_power: float, t0: float, wavelength_m: float, raman_response: Any, grid: Any, length: float, ratio_tolerance: float = 0.25, num_steps: int = 4000) -> dict[str, float]
Raman soliton self-frequency shift vs Gordon's analytic law.
Propagates a soliton with the fiber's Raman response and compares the
measured red shift of the spectral peak against Gordon's analytic rate
dΩ/dz = −8|β₂|T_R/(15 T₀⁴) with T_R = f_R·∫t·h_R(t)dt (Gordon
1986). The measured/analytic ratio must be within ratio_tolerance
of unity; see reproductions/gordon_1986_ssfs (ratio 1.19 on the
published benchmark configuration).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid
|
TemporalGrid
|
|
required |
length
|
float — fibre length (m).
|
|
required |
raman_response
|
RamanResponse (or any object with ``fR`` and a public
|
|
required |
Raises:
| Type | Description |
|---|---|
ValidationFailure — when the shift direction or rate is wrong.
|
|