Errors and warnings reference

The exception and warning classes Deepwave raises. Usage covers the conventions of the interface that raises them.

Exceptions and warnings

Deepwave raises its own exception types. Each one also inherits the builtin exception type that the same failure raised historically, so an existing except ValueError (or TypeError, RuntimeError, NotImplementedError, OSError, FloatingPointError) keeps catching exactly what it caught before – while except deepwave.DeepwaveError catches everything Deepwave raises deliberately, and nothing else. See Stability policy for what may change about them.

What “deliberately” covers

Every rejection Deepwave decides on – an argument it validates, a combination it cannot serve, a build or backend that is unavailable, a diverged wavefield, a scratch directory the filesystem refused – raises one of the classes below, so:

try:
    out = deepwave.scalar(v, dx, dt, source_amplitudes=a,
                          source_locations=x_s)
except deepwave.DeepwaveError as error:
    ...

catches all of them. Two kinds of failure are deliberately outside it, and neither can be brought inside:

  • A TypeError raised by Python’s own argument binding, before any Deepwave code runs: a missing required argument, a keyword spelled wrongly enough that no propagator accepts it, or an argument given twice. Python raises it while matching the call to the signature, so Deepwave has no opportunity to classify it. (A keyword a propagator recognises but cannot act on is a different thing: Deepwave checks that itself and raises deepwave.DeepwaveValueError.)

  • Any exception from PyTorch or from the standard library – a shape mismatch inside an operation, an out-of-memory error, a CUDA failure. It stays exactly the exception those libraries raised; Deepwave does not wrap it, so a traceback still points at the operation that failed.

Deepwave also raises a few builtin exceptions where Python’s own protocols require them, rather than as a message to the caller: AttributeError from a __getattr__ for an unknown name, KeyError from a mapping lookup for an absent key, and AssertionError for an internal invariant that no call can violate (reaching one is a bug in Deepwave; please report it). These are protocol obligations and bug reports, not rejected requests, so they are not deepwave.DeepwaveError subclasses either. Everything else Deepwave raises on purpose is: tests/test_error_classes.py walks the source of every Deepwave module and fails if a raise of any other builtin exception type appears.

The classes

exception deepwave.DeepwaveError(*args)

Base class for every exception Deepwave raises deliberately.

Catching this catches Deepwave’s own validation and capability errors without also catching unrelated exceptions from PyTorch or the standard library. Deepwave never raises DeepwaveError itself: every raise site uses one of the subclasses below, each of which also inherits the builtin exception type that site raised historically, so except ValueError (or TypeError, RuntimeError, NotImplementedError, FloatingPointError) keeps working unchanged.

exception deepwave.DeepwaveValueError(*args)

A Deepwave error that is also a ValueError.

Raised for an argument whose type is right but whose value is not (an out-of-range number, an unrecognised option string, a mismatched shape).

exception deepwave.DeepwaveTypeError(*args)

A Deepwave error that is also a TypeError.

Raised for an argument of the wrong type (a float where an int is required, a non-Tensor model).

exception deepwave.DeepwaveRuntimeError(*args)

A Deepwave error that is also a RuntimeError.

Raised for a request that is well-formed but that this build, backend, or combination of options cannot serve.

exception deepwave.DeepwaveNotImplementedError(*args)

A Deepwave error that is also a NotImplementedError.

Raised for a combination of options that is intended to work but has not been implemented yet.

exception deepwave.DeepwaveOSError(*args)

A Deepwave error that is also an OSError.

Raised when the operating system refuses a filesystem operation Deepwave performs on the caller’s behalf, such as creating the scratch directory that storage_mode="disk" writes its wavefield history into. The message names the argument that chose the location (storage_path) so that the fix is visible from the traceback alone. except OSError around a Deepwave call keeps catching it.

exception deepwave.DeepwaveFloatingPointError(*args)

A Deepwave error that is also a FloatingPointError.

Raised when a tensor contains non-finite values, which usually means the simulation diverged; see deepwave.check_finite().

exception deepwave.DeepwaveFutureWarning(*args)

Warning category for a deprecated Deepwave spelling.

Emitted once per call per deprecated name, by the name that is going away, naming both the replacement and the release that removes it (see DEPRECATION_REMOVAL_VERSION). Nothing that emits one changes what a call computes: the deprecated spelling keeps doing what it always did until it is removed.

Silence it with one line:

warnings.filterwarnings(
    "ignore", category=deepwave.DeepwaveFutureWarning
)

It subclasses FutureWarning, so any filter that already targets FutureWarning also covers it. FutureWarning rather than DeprecationWarning because the call that has to change is the user’s own: Python’s default filters show FutureWarning from any module, while DeprecationWarning is hidden outside __main__, which is where a library’s deprecation is least likely to be read.

exception deepwave.DeepwaveWarning(*args)

Base class for every warning Deepwave raises about a call’s behaviour.

One subclass per cause, never one per propagator or per message: the category is what a user filters on, so it has to name the thing they would decide about. Every warning raised under one of these categories names its class in its own text, so the one-line recipe for silencing it is in the message itself. Deepwave also still emits some plain UserWarning messages that predate this hierarchy and are not classified under it (the grid-cells-per-wavelength advice, the pml_freq-above-Nyquist warning, and the storage/auxiliary-state notices); those name no category, and are filtered as UserWarning.

Filtering the base covers this class and its subclasses:

warnings.filterwarnings("ignore", category=deepwave.DeepwaveWarning)

It subclasses UserWarning, so a filter that already targets UserWarning also covers it. DeepwaveFutureWarning is deliberately outside this hierarchy: a deprecated spelling is a message about the code that was written, not about the physics it asks for.

exception deepwave.ZeroWidthFaceWarning(*args)

A "pml" face of zero width, which reflects instead of absorbing.

A "pml" face whose pml_width is zero absorbs nothing. It is a reflecting boundary whose exact condition depends on the propagator (see Boundary conditions), and it is reached identically whether boundary was omitted, given as the single string "pml", or given per face – those three spellings are the same call, so they warn the same way.

Silence it with one line:

warnings.filterwarnings(
    "ignore", category=deepwave.ZeroWidthFaceWarning
)

The warning is about a silent choice, not an error: the call runs, and naming the condition you meant with boundary= is the fix.

exception deepwave.MigrationWarning(*args)

A call whose numbers changed from what an older Deepwave computed.

Nothing about the call is wrong: the same arguments now mean something better than they used to. The warning exists so that a difference against an older run is explained rather than discovered. Where one line restores the previous behaviour exactly, the message names it; where no argument can, the message says so and names what the difference is confined to instead.

Silence it with one line:

warnings.filterwarnings(
    "ignore", category=deepwave.MigrationWarning
)
exception deepwave.PmlFreqInferenceWarning(*args)

pml_freq was inferred, and differs from the old fixed default.

Deepwave 0.0.27 used a fixed pml_freq of 25.0 whenever the argument was omitted; it is now inferred from the source amplitudes. An inference of exactly 25.0 computes what that release computed and says nothing; this is the narrower category for every other inferred value, each of which gives a different absorbing boundary from that release. It is a migration aid, and is removed in Deepwave 0.4.0.

Silence it with one line:

warnings.filterwarnings(
    "ignore", category=deepwave.PmlFreqInferenceWarning
)

Passing pml_freq explicitly silences it too, and is the better fix: it makes the call say what it means.