solprop.backends.node_chunk#

How many nodes a response pass holds at once: the backend’s node-chunk plan.

A response pass synthesises the field at a chunk of the transform’s nodes, evaluates the responses there and projects back; the chunk bounds the space-domain buffers. It is an execution choice, not part of the scientific problem (SEP 47 sections 4.3 and 6.5): two runs that differ only in their chunks compute the same fields to rounding, which the chunked rows of tests/data/convergence/spatial_accuracy.json assert. So the translation records none, and each backend plans its chunk when it is prepared, from the problem and its ExecutionOptions (plan_node_chunk()).

The rule is the one the translation applied before SEP 47 moved it here, so that every default and every explicit budget chooses the chunk it chose then:

  • The budget. An explicit node_budget is authoritative; without one a free-space, line or planar problem takes DEFAULT_SPATIAL_NODE_BUDGET and every other DEFAULT_NODE_BUDGET.

  • The base chunk. A modal or radial node holds BUFFERS_PER_NODE complex temporal columns per component; a Cartesian or planar column holds FREE_COLUMN_BUFFERS. A mode-averaged run has one node, and a general modal guide’s static matrices are a placeholder of one (its route sizes its own chunk from solprop.backends.numpy_ref.general_modal.general_node_chunk() at the same budget).

  • The response admissions then shrink the chunk until each node’s envelope plasma, Raman, dispersive and held-current buffers fit the same budget, refusing a budget that cannot hold one node (or one planar row), and the last step spreads the nodes evenly over the passes the admitted chunk needs.

The counts are conservative inventories, not the live buffers of each route: SEP 28’s phase 0 found the twenty Cartesian column-equivalents about three times the live group buffers (solprop issue #349). They stay, so that a user’s budget keeps buying the chunk it bought before; counting a route’s live buffers changes the chunk of every explicit budget, which is the maintainer’s decision under #349 and #89, not this move’s.

A device backend may choose differently when no budget is given (solprop issue #361); the native backend’s rule is solprop_native.backend.device_node_chunk, and an explicit budget or chunk is never overridden by it.

Module Attributes

DEFAULT_NODE_BUDGET

Bytes of node-chunk buffers a problem may hold, before the chunk size is reduced.

DEFAULT_SPATIAL_NODE_BUDGET

Node-chunk bytes a free-space, line or planar problem may hold by default (SEP 28).

BUFFERS_PER_NODE

Node-chunk buffers the fused pass holds: E, P and the Raman drive.

FREE_COLUMN_BUFFERS

Complex-equivalent buffers per component a Cartesian or planar column holds.

ChunkSource

Where a plan's chunk came from: the default budget, an explicit one, or a chunk.

Functions

default_node_budget(transform)

Return the node budget a problem takes when none is given.

dispersive_node_buffers(responses, *, spatial)

Return the buffers per node and component SEP 6's dispersive response adds.

plan_node_chunk(problem[, options])

Plan a problem's node chunk on the host rule, before anything is allocated.

Classes

NodeChunkPlan(chunk, budget, source[, requested])

A backend's node chunk and what chose it, recorded as execution metadata.

solprop.backends.node_chunk.BUFFERS_PER_NODE = 3#

Node-chunk buffers the fused pass holds: E, P and the Raman drive.

solprop.backends.node_chunk.ChunkSource#

Where a plan’s chunk came from: the default budget, an explicit one, or a chunk.

alias of Literal[‘default’, ‘explicit’, ‘forced’]

solprop.backends.node_chunk.DEFAULT_NODE_BUDGET = 67108864#

Bytes of node-chunk buffers a problem may hold, before the chunk size is reduced.

Architecture section 13 chooses the whole node set when it fits a per-problem budget and the largest chunk that fits otherwise. Sixty-four mebibytes reproduces the chunk of about sixteen nodes that section 8 tabulates for the comb-to-continuum target (32768 time samples, six modes, Raman) while leaving a small problem un-chunked. It is an estimate until the benchmark suite measures the crossover.

The free-space, line and planar grids default to DEFAULT_SPATIAL_NODE_BUDGET.

solprop.backends.node_chunk.DEFAULT_SPATIAL_NODE_BUDGET = 1073741824#

Node-chunk bytes a free-space, line or planar problem may hold by default (SEP 28).

A spatial evaluation pays a fixed cost per node chunk: its launches, its temporal transforms’ thread wake-ups, and its gather and scatter. A field volume is gigabytes, so a larger group is cheap in memory. With the per-chunk copies and clears removed, one gibibyte was the fastest of 64, 256 and 1024 MiB for the 384- and 768-square Kerr beams on Zen 5 and on Apple silicon, 2.3 to 2.4 times faster than 64 MiB on the native backend’s march; on an H200, IP-DOPRI5 was 1.3 times faster at one gibibyte than at 64 MiB.

solprop.backends.node_chunk.FREE_COLUMN_BUFFERS = 20#

Complex-equivalent buffers per component a Cartesian or planar column holds.

Eight response and FFT buffers, three doubled Raman buffers, 3.5 device plasma buffers, two split-step buffers and 2.5 statistic buffers: 19, and one more column for the real FFT’s endpoint bins. The transverse scratch and the opaque FFT plans are named separately in the memory ledgers. A conservative inventory, about three times the live group buffers (solprop issue #349); the dispersive admission adds its own to it.

class solprop.backends.node_chunk.NodeChunkPlan(chunk, budget, source, requested=None)[source]#

Bases: object

A backend’s node chunk and what chose it, recorded as execution metadata.

Attributes:
chunkint

Nodes a response pass holds at once, between 1 and the transform’s node count; one on a general modal guide, whose static matrices are a placeholder.

budgetint

The budget the chunk was planned within, bytes: the explicit one, or the problem’s default (default_node_budget()).

source{‘default’, ‘explicit’, ‘forced’}

"default" without an explicit budget (the route’s default budget), "explicit" with one, and "forced" for an exact chunk (solprop.backends.session.ExecutionOptions.node_chunk).

requestedint or None

The exact chunk asked for, before it was bounded by the node count; None unless source is "forced". A general modal guide’s route takes it in place of its own budgeted chunk.

Examples

>>> from solprop.backends.node_chunk import NodeChunkPlan
>>> NodeChunkPlan(16, 2**26, "default").record()
{'node_chunk': 16, 'node_budget': 67108864, 'node_chunk_source': 'default'}
property automatic: bool[source]#

Return whether no budget or chunk was given, so a machine rule may apply.

Returns:
bool

True when source is "default".

budget: int#
chunk: int#
record()[source]#

Return the plan as execution metadata, outside every identity.

Returns:
dict

node_chunk, node_budget and node_chunk_source.

requested: int | None = None#
source: Literal['default', 'explicit', 'forced']#
solprop.backends.node_chunk.default_node_budget(transform)[source]#

Return the node budget a problem takes when none is given.

Parameters:
transformsolprop.translate.modal.Transform

The problem’s transform.

Returns:
int

DEFAULT_SPATIAL_NODE_BUDGET on a Cartesian (free-space or line) or planar transform, DEFAULT_NODE_BUDGET otherwise.

solprop.backends.node_chunk.dispersive_node_buffers(responses, *, spatial)[source]#

Return the buffers per node and component SEP 6’s dispersive response adds.

On the fused node path a backend forms the response’s products at the nodes: one node buffer beside other responses for the symmetric evaluator, which a lone one shares with the bare field, and two for the polynomial, whose cube and derivative products take them in turn. A Cartesian or planar column also holds its filtered fields and products in time and their spectra: two buffers per product, the symmetric evaluator’s one (a mixture’s under its mixture filter) and the polynomial’s 1 + 2 G for G groups of equal leg bound (groups()), and the planar nodes’ one or two besides.

Parameters:
responsessolprop.translate.responses.CompiledResponses

The compiled responses, with or without the dispersive leaf.

spatialbool

Whether the route’s nodes are Cartesian or planar columns.

Returns:
int

Complex-equivalent buffers per node and component; zero without the leaf.

solprop.backends.node_chunk.plan_node_chunk(problem, options=None)[source]#

Plan a problem’s node chunk on the host rule, before anything is allocated.

Parameters:
problemsolprop.translate.problem.PropagationProblem

The validated problem.

optionssolprop.backends.session.ExecutionOptions or None, optional

The run’s execution options; None for the defaults.

Returns:
NodeChunkPlan

The chunk, its budget and its source.

Raises:
solprop.exceptions.BackendError

If the budget cannot hold one node’s buffers (one complete temporal column, or one planar transverse row, with every response’s own).

Examples

>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> from solprop.backends.node_chunk import plan_node_chunk
>>> grid = EnvelopeGrid.from_limits(0.01, 835e-9, (500e-9, 2e-6), 1e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0, gamma=0.11)
>>> start = SechPulse(wavelength=835e-9, width=1e-13, peak_power=1.0).build(grid)
>>> problem, request = assemble(grid, gnlse.mode, [gnlse.kerr], start,
...                    controller=PIController(rtol=1e-8, atol=1e-14),
...                    save_planes=[0.01], dz_max=0.01, dz_init=1e-3,
...                    density=1.0, shock=False, prefactor_index=1.0)
>>> plan_node_chunk(problem).chunk
1