Source code for solprop.exceptions

# SPDX-FileCopyrightText: 2026 John C. Travers and contributors
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""The exception and warning hierarchies.

Every error raised by solprop is a :class:`SolpropError` and every warning it emits is a
:class:`SolpropWarning`, so callers can catch or filter the whole family with one clause
and still tell the cases apart. Raise the most specific subclass; never raise a bare
:class:`Exception`, and never return a sentinel where raising is correct.
"""

__all__ = [
    "AdiabaticTaperWarning",
    "ApertureEdgeWarning",
    "BackendError",
    "ConvergenceError",
    "CouplingError",
    "DiluteScalingWarning",
    "DriverError",
    "ExponentBudgetWarning",
    "GasFlowWarning",
    "GeneralModalBasisWarning",
    "GrazingIncidenceWarning",
    "GridError",
    "MaterialError",
    "MaterialRangeWarning",
    "MaterialStatusWarning",
    "MemoryBudgetError",
    "MemoryBudgetWarning",
    "ModeError",
    "NoiseError",
    "OpticsGeometryError",
    "OutputError",
    "PolarisationError",
    "ProcessingError",
    "PulseError",
    "RamanTemperatureWarning",
    "ResponseBudgetError",
    "RunTerminated",
    "SampledPeakWarning",
    "SolpropError",
    "SolpropWarning",
    "StepperError",
    "SurrogateAreaWarning",
    "TDSEArchiveError",
    "TDSEConsistencyError",
    "TDSEConsistencyWarning",
    "TDSECostWarning",
    "TDSEDomainWarning",
    "TDSEUnqualifiedModelWarning",
    "ToolsError",
    "TranslationError",
]


[docs] class SolpropError(Exception): """Base class for every error raised by solprop."""
[docs] class RunTerminated(SystemExit): """A run stopped by SIGTERM, after writing where it stood. A scheduler's time limit (Slurm's, for one) sends SIGTERM before it kills the process. During a run it raises this at once, or as soon as the step or the save being written is complete, so the run's terminal checkpoint and march snapshot are written as for any failure and ``resume=True`` continues the run. It is a :class:`SystemExit` carrying the conventional exit status ``128 + SIGTERM`` (143), so a script that does not catch it ends as a terminated process does. Parameters ---------- signal_number : int The signal that stopped the run. Examples -------- >>> import signal >>> from solprop.exceptions import RunTerminated >>> error = RunTerminated(signal.SIGTERM) >>> error.code, str(error) (143, 'terminated by SIGTERM') """ def __init__(self, signal_number: int) -> None: """Hold the signal and the exit status it implies.""" import signal # noqa: PLC0415 - only for the signal's name super().__init__(128 + int(signal_number)) self.signal_number = int(signal_number) self.signal_name = signal.Signals(self.signal_number).name def __str__(self) -> str: """Return what stopped the run. Returns ------- str ``"terminated by <signal>"``. """ return f"terminated by {self.signal_name}"
[docs] class DriverError(SolpropError, RuntimeError): """A run was asked for something the driver cannot execute."""
[docs] class MemoryBudgetError(DriverError): """A run's estimated persistent memory exceeds its declared memory budget."""
[docs] class GridError(SolpropError, ValueError): """A time or frequency grid is inconsistent or unsupported."""
[docs] class MaterialError(SolpropError, ValueError): """A material, gas or model is unknown or used outside its validity range."""
[docs] class OpticsGeometryError(MaterialError): """An optical setting has no forward, non-grazing ray or diffraction order."""
[docs] class ModeError(SolpropError, ValueError): """A waveguide mode or mode set is invalid."""
[docs] class PulseError(SolpropError, ValueError): """An input pulse specification is invalid or does not fit the grid."""
[docs] class PolarisationError(SolpropError, ValueError): """A Jones or Stokes vector, optical element or polarisation angle is invalid."""
[docs] class NoiseError(SolpropError, ValueError): """A shot-noise request is invalid."""
[docs] class TranslationError(SolpropError, ValueError): """The translation layer could not build a valid kernel problem."""
[docs] class BackendError(SolpropError, RuntimeError): """A backend is unavailable, misused or failed during propagation."""
[docs] class OutputError(SolpropError, RuntimeError): """An output handler could not save, load or resume a run."""
[docs] class TDSEArchiveError(OutputError): """A TDSE response archive could not be opened, serialized or written (SEP 20). Raised before any provider call when the archive path is refused, and in place of the next provider call after a failed write, so a run stops at its last optical checkpoint. A provider failure stays the primary error when recording it also fails. """
[docs] class TDSEConsistencyError(MaterialError): """A haCC response failed, or could not complete, its weak-field linear check. Raised before any propagation call when the per-atom linear susceptibility of the atomic model departs from optmat's helium by more than the declared ``refuse`` bound, or when the check's own extraction is invalid (SEP 20, section 5.4). The structured result is attached as ``result`` when one exists. """ result: object | None = None
[docs] class ProcessingError(SolpropError, ValueError): """A post-processing or plotting request is invalid."""
[docs] class ConvergenceError(SolpropError, RuntimeError): """A numerical procedure did not converge within its budget."""
[docs] class CouplingError(SolpropError, ValueError): """A field plane, a remap or a launch between simulations is refused (SEP 31)."""
[docs] class ResponseBudgetError(ConvergenceError): """A run stopped before its end because its source-call budget was spent. Raised before a trial that the budget could not pay for, so no step is accepted to fit the budget and the run is never marked complete (SEP 13 section 5). The state at the last accepted step travels with the error; a file output holds every plane reached, from which the run resumes afresh. Parameters ---------- message : str What stopped and where. z : float Position of the last accepted step, m. field : numpy.ndarray or None The state there. calls : int Source calls charged before the stop. Attributes ---------- z : float Position of the last accepted step, m. field : numpy.ndarray or None The state there, in the kernel's canonical layout and FFT convention. calls : int Source calls charged before the stop. """ def __init__(self, message: str, *, z: float, field: object, calls: int) -> None: """Carry the stop's position, state and spent calls with the message.""" super().__init__(message) self.z = z self.field = field self.calls = calls
[docs] class StepperError(SolpropError, ValueError): """A tableau, controller, schedule or landing setting is invalid."""
[docs] class ToolsError(SolpropError, ValueError): """A design calculation was asked for something it cannot answer."""
[docs] class SolpropWarning(UserWarning): """Base class for every warning raised by solprop."""
[docs] class MaterialRangeWarning(SolpropWarning): """A material model is evaluated outside the validity range of its source."""
[docs] class MaterialStatusWarning(SolpropWarning): """A resolved material model is flagged provisional or untested by its source."""
[docs] class DiluteScalingWarning(SolpropWarning): """A gas's dilute-limit index departs from its finite-density law beyond a bound."""
[docs] class ExponentBudgetWarning(SolpropWarning): """A step the run cannot shrink forms a propagator factor near the overflow limit. A replayed schedule's step, or the step floor ``dz_min``, between nine tenths of ``log(DBL_MAX)`` and the limit itself (SEP 22 section 4.5): the run completes only while its field stays small enough that the factor times it does not overflow. """
[docs] class GrazingIncidenceWarning(SolpropWarning): """A grazing-incidence model is evaluated outside the range it is valid in. A spatial spectral bin with an unresolved clamp branch, a coherent wall block near its validity limit, or a wall-pair guide (rectangular or slab) past its first-order ratios. """
[docs] class AdiabaticTaperWarning(SolpropWarning): """A multimode run on a guide whose modes move along z omits their coupling."""
[docs] class ApertureEdgeWarning(SolpropWarning): """A wide ``tanh`` aperture edge converges slowly for light at the aperture centre. Amplitude-weighted ``tanh`` with ``2 <= r/w < 4`` (SEP 23, open question 10): the profile slopes at its centre, so a bright beam there is collected with a lattice error near ``1e-5``, where ``rcos`` is flat inside ``r - w``. """
[docs] class MemoryBudgetWarning(SolpropWarning): """A run's estimated persistent memory exceeds a budget declared to warn."""
[docs] class GeneralModalBasisWarning(SolpropWarning): """A general modal basis leaves its budget somewhere the run's light can reach."""
[docs] class GasFlowWarning(SolpropWarning): """A steady-flow gas fill leaves the regime its laminar continuum law describes."""
[docs] class RamanTemperatureWarning(SolpropWarning): """Rotational Raman populations are held at one temperature; the gas's varies."""
[docs] class SampledPeakWarning(SolpropWarning): """A node-maximum plasma statistic is read where no quadrature node is on the axis. A field-scale radial rule of few nodes (SEP 19) integrates the source but samples the axial peak at its innermost node; the ``on_axis_*`` statistics read the axis. """
[docs] class SurrogateAreaWarning(SolpropWarning): """A scalar model takes a provider channel's area at a frequency nobody chose."""
[docs] class TDSECostWarning(SolpropWarning): """A TDSE response runs on a many-node radial rule: each node is one atom a call."""
[docs] class TDSEDomainWarning(SolpropWarning): """A haCC preset is used beyond its qualifying duration, intensity or carrier."""
[docs] class TDSEConsistencyWarning(SolpropWarning): """A haCC weak-field linear check warned, or was skipped at the caller's request."""
[docs] class TDSEUnqualifiedModelWarning(SolpropWarning): """A custom haCC basis has no qualified accuracy, or lacks the current closure."""