solprop.backends.registry#

Selecting a backend by name, and saying why one is not usable.

docs/dev/backends.md section 1: selection is by name, availability is detected with importlib.util.find_spec() and never cached. The errors are two-tier, because the two failures need different answers from the reader: a name this package has never heard of is a ValueError listing what is usable, and a known name whose dependencies are missing is an ImportError saying what to install.

Each backend is one row of BACKENDS, a BackendEntry naming by import path everything selection reads of it – its constructor, its lockstep runner and its policy hooks – so nothing here branches on a backend’s name to construct one, and an optional backend in another distribution registers with one row (docs/dev/backends.md section 1).

The native backend is a second distribution, solprop-native, built from native/ in this repository and a required dependency; probing availability does not import it. Automatic selection is that backend, with no fallback (SEP 43). It refuses when the package is absent or this processor is below the installed build’s CPU baseline, using the package’s own check (solprop_native._cpu), loaded by path and read from the same code that refuses the import. Import, compatibility and construction errors remain visible, and they never trigger different arithmetic.

Module Attributes

BACKENDS

The backends this package knows, by name: one row each.

AUTO

What "auto" selects, with no fallback (SEP 43).

REMOVED_BACKENDS

What to say about a backend that no longer exists, by the name it had.

FAR_FIELD_BACKENDS

The backends that form the far-field statistics of SEP 23.

REQUIRE_DEVICE_SETTING

Where a run must execute: cuda, hip or any; unset for no requirement.

Functions

available([precision])

Return the names of the backends that can run a precision here and now.

resolve_name([name])

Resolve automatic selection to an installed backend's registry name.

select(name, problem, request, *[, grid, ...])

Construct the named backend for a validated problem and its run's request.

select_batch(owners)

Select batch arithmetic without substituting a different backend.

statistics_refusal(name, names)

Return why a backend cannot form some of the statistics named, or None.

Classes

BackendEntry(requires, extras, factory[, ...])

What selection needs of a backend, each object named by its import path.

solprop.backends.registry.AUTO: Final = 'native'#

What "auto" selects, with no fallback (SEP 43).

solprop.backends.registry.BACKENDS: Mapping[str, BackendEntry] = {'native': BackendEntry(requires=('solprop_native',), extras=(), factory='solprop_native:NativeBackend', batch=None, install='solprop, or build solprop-native from native/ in the solprop repository', distribution='solprop-native', first_use='solprop.calibration.first_use:ensure', device='solprop_native:build_info', far_field='solprop_native:NativeBackend.far_field_statistics'), 'numpy_ref': BackendEntry(requires=(), extras=(), factory='solprop.backends.numpy_ref:construct', batch='solprop.backends.numpy_ref.batch:lockstep_runner', install=None, distribution=None, first_use=None, device=None, far_field=None)}#

The backends this package knows, by name: one row each.

class solprop.backends.registry.BackendEntry(requires, extras, factory, batch=None, install=None, distribution=None, first_use=None, device=None, far_field=None)[source]#

Bases: object

What selection needs of a backend, each object named by its import path.

A path is "module:attribute", the attribute dotted for one inside a class. It is imported only when selection needs it, after requires was found, so listing a backend imports nothing.

Attributes:
requirestuple of str

Importable module names that must be present. Empty for a backend that needs nothing beyond the package’s own dependencies.

extrastuple of str

The optional-dependency groups that supply requires, for the error message.

factorystr

The backend’s constructor, called as factory(problem, request, *, grid, modes, profiles, options), and with tdse_binding too for a TDSE run, which only the reference is given (select()).

batchstr or None, optional

The reference group’s lockstep runner over loaded members, batch(owners) (select_batch()); None for a backend whose prepared group runs its members itself, as the native group session does (SEP 47 section 6.7).

installstr or None, optional

What to install when requires is missing; None names extras.

distributionstr or None, optional

The distribution that ships the backend, named by the messages of the policies below; None names the package or the backend instead.

first_usestr or None, optional

Called with no arguments before each construction: the native backend’s first-use calibration (SEP 46); None for nothing.

devicestr or None, optional

The build’s description, device(), whose device_backend ("none" on a CPU build) and device_count say where it runs (REQUIRE_DEVICE_SETTING); the module holding it carries the version. None for a backend that never runs on a device.

far_fieldstr or None, optional

The far-field statistics (SEP 23) the installed backend declares it forms; another is refused by name before construction (statistics_refusal()). None for a backend that forms every one, or declares nothing to check.

batch: str | None = None#
device: str | None = None#
distribution: str | None = None#
extras: tuple[str, ...]#
factory: str#
far_field: str | None = None#
first_use: str | None = None#
install: str | None = None#
requires: tuple[str, ...]#
solprop.backends.registry.FAR_FIELD_BACKENDS: tuple[str, ...] = ('numpy_ref', 'native')#

The backends that form the far-field statistics of SEP 23.

numpy_ref always does; the native backend declares what it forms by its class’s far_field_statistics attribute (its row’s far_field). A statistic it does not declare is refused by name on this side of the seam (statistics_refusal()), before it is built.

solprop.backends.registry.REMOVED_BACKENDS: Mapping[str, str] = {'mlx': "the experimental mlx backend was retired in SEP 47: use backend='native', the solprop-native package, or, for precision='single', backend='numpy_ref', the reference. Output that records mlx still opens", 'numba_cpu': "the numba_cpu backend was removed in SEP 43: use backend='native', the solprop-native package, or backend='numpy_ref', the reference, which is unthreaded and far slower. Output and snapshots that record numba_cpu still load"}#

What to say about a backend that no longer exists, by the name it had.

solprop.backends.registry.REQUIRE_DEVICE_SETTING: Final = 'SOLPROP_REQUIRE_DEVICE'#

Where a run must execute: cuda, hip or any; unset for no requirement.

solprop.backends.registry.available(precision='double')[source]#

Return the names of the backends that can run a precision here and now.

Detection is by importlib.util.find_spec(), so nothing is imported and nothing is cached: a backend whose optional dependency is installed while the process runs becomes available without a restart, and initializing a native runtime is never a side effect of asking.

Parameters:
precision{‘double’, ‘single’}, optional

The arithmetic asked for (SEP 33). "double", the default, lists every backend; "single" lists those that admit single precision (solprop.translate.precision.SINGLE_PRECISION_BACKENDS).

Returns:
tuple of str

The usable names, in the table’s order.

Examples

>>> from solprop.backends.registry import available
>>> "numpy_ref" in available()
True
solprop.backends.registry.resolve_name(name='auto')[source]#

Resolve automatic selection to an installed backend’s registry name.

Parameters:
namestr, optional

"auto" is "native", and has no fallback: it refuses if solprop_native can’t be found or this processor doesn’t meet the installed build’s CPU baseline. Other names pass through unchanged, but for a removed backend (REMOVED_BACKENDS).

Returns:
str

Concrete selection to store in simulation settings. This uncached probe does not import a backend or initialize a native runtime. select() validates the name and constructs the backend; failures there never cause a fallback.

Raises:
BackendError

If name is a removed backend, or "auto" has nothing to select; the message says what to do.

Examples

>>> resolve_name("numpy_ref")
'numpy_ref'
solprop.backends.registry.select(name, problem, request, *, grid=None, modes=None, profiles=None, tdse_binding=None, options=None)[source]#

Construct the named backend for a validated problem and its run’s request.

The backend receives the request where it is built (SEP 47 section 5.2): it checks the pair (solprop.translate.problem.validate_run()) and refuses an unsupported combination by name before it allocates, and it lowers the method, the error control, the itinerary, the planes and the statistics once. A session is then started on it with that request, adapted to one run (for_run()).

Parameters:
namestr

The backend’s registry name, for example "numpy_ref", or "auto" for the native backend, with no fallback (resolve_name()).

problemsolprop.translate.problem.PropagationProblem

The problem to step.

requestsolprop.translate.run_request.RunRequest

The run’s policies. The backend validates it with the problem again.

gridsolprop.grid.TimeGrid, optional

The grid the state lives on. Statistics need it and the kernel contract does not carry it, so it is passed alongside rather than inside the problem.

modescollections.abc.Sequence, optional

The propagated modes, in state order, for the statistics that need them.

profilescollections.abc.Mapping, optional

The z-profiles keyed by statistic name, for the profile statistics.

tdse_bindingsolprop.translate.tdse.TDSEBinding or None, optional

Driver-owned host response binding for a TDSE problem on NumPy.

optionssolprop.backends.session.ExecutionOptions or None, optional

The run’s execution options, among them an explicit node budget, from which the backend plans its node chunk (SEP 47 section 6.5); None for the automatic choice.

Returns:
Backend

The constructed backend.

Raises:
ValueError

If name is not a backend this package knows; the message lists what is usable.

BackendError

If name is a backend that has been removed, or one that does not form a statistic the problem asks for; the message says what to use instead.

ImportError

If name is known but its dependencies are missing; the message says what to install.

Examples

>>> from solprop.backends.registry import BACKENDS
>>> sorted(BACKENDS)
['native', 'numpy_ref']
solprop.backends.registry.select_batch(owners)[source]#

Select batch arithmetic without substituting a different backend.

This is the reference group’s lockstep runner, read from the registry row’s batch. A backend whose row names none, as native’s, runs its groups through its own prepared group instead (solprop.backends.sessions.start_group(); SEP 47 section 6.7), and is refused here by name.

Parameters:
ownerssequence of solprop.backends.protocol.Backend

Compatible, loaded member owners.

Returns:
BatchBackend

Common fixed march using the selected backend’s arithmetic.

Raises:
BackendError

If the members are not of one backend, or their backend has no lockstep runner (its groups start through start_group).

solprop.backends.registry.statistics_refusal(name, names)[source]#

Return why a backend cannot form some of the statistics named, or None.

Asking about a backend whose row declares its far-field statistics (the native backend’s) imports the installed plugin, as selecting it would, to read them.

Parameters:
namestr

The resolved backend name.

namescollections.abc.Sequence of str

The statistics asked for.

Returns:
str or None

The refusal, naming the backends that do form them, or None when the backend forms every one (or is not installed, which selecting it reports).

Examples

>>> from solprop.backends.registry import statistics_refusal
>>> statistics_refusal("numpy_ref", ["energy", "beam_spectrum"]) is None
True