solprop.monitor#
The boundary monitor: guard and collar occupancy, and the energy the collar removes.
SEP 21 decisions D5 and D7. At the launch and at every committed step the monitor
reads the field’s time-domain energy density, P(t), summed over modes,
polarisations and transverse columns (with their quadrature weights), and forms:
the guard occupancy of each edge, the share of
Pwithin the outerBoundaryCheck.guard_fractionof the realised window: what has reached the window’s edge and is about to wrap or be absorbed;the collar occupancy, the share of
Pweighted by1 - Wof the temporal collar;the removal rate
int alpha(t) P(t) dtof the temporal collar, integrated along z by the trapezoid over committed steps into the removed fraction of the launch energy. Under the"split_step"scheme the backend adds up what each accepted step’s split takes instead,sum_t P(t) (1 - exp(-alpha(t) h))of the powerPit finds, which is exact on unchecked steps too (BoundaryEnergies.removed).
Under the "split_step" scheme the occupancies are judged on the power the last
accepted step’s split found, taken halfway through its factor
(BoundaryEnergies.found). The state the split leaves has its deep collar
multiplied by exp(-alpha h), about exp(-10) at an adaptive step, so it shows no
light at the window’s edge however much arrived there; the state before it holds what
walked into the guard during the step unabsorbed. Each verdict would depend on the
step. Half the factor, exp(-alpha h / 2) on the power, is the symmetric (Strang)
splitting’s state at the step’s end, second order in the step where the one-sided
split is first: the guards then read as the in-stage scheme’s do. Every share of one
verdict, the guards’, the collar’s and the no-light test, is of that one state.
P is the energy-density proxy of SEP 21 section 4.6: exact for modal true-power
amplitudes, and on spatial routes the quadrature-weighted field norm rather than the
admittance-weighted flux. The quantities are relative, so the proxy’s scale cancels.
Where the reduction runs. A check needs five numbers of the state, its energy and
its four weighted energies (BoundaryEnergies), and the backend forms them
where its state lives (StepDriver._boundary_energies): only the five cross to the
host. BoundaryMonitor.energies() and BoundaryMonitor.split_sums() are
the host reductions, the reference every backend is held to.
The shot-noise floor (Q24). An input-noise launch carries one photon per mode
across the whole window, guards and collar included. Light below that floor cannot be
told from the vacuum, so the monitor judges what lies above it: from each region’s
energy it subtracts FLOOR_MARGIN times the floor’s expected share before
taking that energy’s share of the whole field (the floor is stationary, so its expected
density is uniform in time; the removal rate subtracts the expectation alone). Without
noise nothing is subtracted; with a weak launch the field is mostly floor and what lies
above it is a small share. The raw values, of the whole field, are recorded beside the
judged ones.
Policy (D7, one rule from the launch on): the square root of a guard occupancy above
BoundaryCheck.budget warns, and above stop_factor times it stops the run, or
refuses it at the launch before a step is spent. At the end of a run the removed
fraction is reported, and warns when its square root exceeds the budget (D5).
The quiet collar is opt-in (BoundaryCheck.quiet_collar, SEP 21 D15 as
amended by ADR-057). When asked for, a collar that held less than QUIET of the
field’s energy, the shot-noise floor included, at QUIET_CHECKS consecutive
checks may be left out of the in-stage stages until light returns. It is judged on the
whole field because light below the floor is still light the collar would have
absorbed: judged above the floor, the threshold became a few times the floor itself
and dropped a term that moved the field by up to a percent. By default the collar
stays in every stage.
Module Attributes
How many times its expected energy the floor is allowed in a region before light is counted there. |
|
Committed steps between checks while the edges are quiet: every one of them while a guard or the collar holds more than |
|
The fewest checks over the guide's length: a quiet window is checked at least every |
|
The fraction of the budget, as a field amplitude, above which a guard or the collar counts as active and every step is checked. |
|
The share of the field's energy, floor included, below which the collar counts as quiet: when the run opts in ( |
|
Consecutive quiet checks before the collar's term is left out. |
|
The check a run takes unless its settings or an interface keyword say otherwise. |
Classes
|
How a run watches its time window's edges (SEP 21, D5 and D7). |
|
What a backend reads of its state at a check: the monitor's five numbers. |
|
The monitor of one run: its weights, its running totals and its record. |
- solprop.monitor.ACTIVE = 0.1#
The fraction of the budget, as a field amplitude, above which a guard or the collar counts as active and every step is checked.
- class solprop.monitor.BoundaryCheck(guard_fraction=0.05, budget=0.001, stop_factor=10.0, quiet_collar=False, transverse_budget=None)[source]#
Bases:
objectHow a run watches its time window’s edges (SEP 21, D5 and D7).
- Attributes:
- guard_fractionfloat
Width of each edge’s guard, as a fraction of the realised window, in (0, 0.5). Default 0.05.
- budgetfloat
The run’s field-error budget: the square root of a guard occupancy, or of the removed fraction, above it warns. Default 1e-3.
- stop_factorfloat
The run stops when the square root of a guard occupancy exceeds this many budgets, and a launch above it is refused. Default 10.
- quiet_collarbool
Leave the in-stage temporal collar out of the stages while it is quiet (
QUIET,QUIET_CHECKS), a speed-up for runs whose light stays clear of the edges. Off by default: the collar then stays in every stage. It applies on binary64 modal routes with the"nonlinear"absorber scheme and a temporal collar alone; elsewhere the collar always stays.- transverse_budgetfloat or None
The budget of a free-space run’s transverse edge (SEP 40 section 5.3), a field amplitude like budget;
None, the default, takes budget, so relaxing the transverse edge does not relax time.
Examples
>>> from solprop.monitor import BoundaryCheck >>> check = BoundaryCheck() >>> check.guard_fraction, check.budget, check.stop_factor, check.quiet_collar (0.05, 0.001, 10.0, False)
- class solprop.monitor.BoundaryEnergies(total, regions, removed=0.0, found=None, occupancy=None)[source]#
Bases:
objectWhat a backend reads of its state at a check: the monitor’s five numbers.
Each is a sum over the coarse time axis of the energy-density proxy
P(t), summed over everything but time with the columns’ quadrature weights (BoundaryMonitor.power()), in the proxy’s units of energy.- Attributes:
- totalfloat
The state’s energy,
sum_t P(t).- regionsnumpy.ndarray
Shape
(4,):sum_t w_k(t) P(t)for the four rows ofBoundaryMonitor.weights, the energies in the low guard, the high guard and the collar (weighted by1 - W), and the collar’s removal rate, energy per metre.- removedfloat
What the
"split_step"collar took since the previous reading, summed over every accepted step:sum_t P(t) (1 - exp(-alpha(t) h))of the powerPeach step’s split found. Zero under the in-stage scheme or without a collar.- foundnumpy.ndarray or None
Shape
(4,):sum_t P'(t)and the first three weighted energies, the low and high guards’ and the collar’s, ofP'(t) = P(t) exp(-alpha(t) h / 2), the powerPthe last accepted step’s split found taken halfway through its factor, in the same units; the occupancies are judged on them under the"split_step"scheme.Noneunder the in-stage scheme, without a collar, and before the first accepted step.- occupancynumpy.ndarray or None
The state’s energy per walk-off bucket of the split collar’s crossing limit (
solprop.boundaries.SplitCrossing.occupancy()), which the steps after the check are capped by;Nonewithout one.
Examples
>>> import numpy as np >>> from solprop.monitor import BoundaryEnergies >>> reading = BoundaryEnergies(1.0, np.zeros(4)) >>> reading.removed, reading.found (0.0, None)
- regions: Float[ndarray, '4']#
- class solprop.monitor.BoundaryMonitor(check, weights, kind, columns=None, split=False, interval=inf, transverse=None, crossing=None)[source]#
Bases:
objectThe monitor of one run: its weights, its running totals and its record.
- Attributes:
- checkBoundaryCheck
The thresholds.
- weightsnumpy.ndarray
Time weights on the coarse axis, shape
(4, n_t): the low guard, the high guard, the collar’s1 - Wand the temporal collar rate in 1/m.- kind{‘field’, ‘envelope’}
The grid’s spectral layout.
- columnsnumpy.ndarray or None
Quadrature weights of the transverse columns, or
Nonefor modal routes.- intervalfloat
The longest distance, m, a quiet window goes unchecked (
CHECKS).- transversesolprop.transverse_monitor.TransverseEdge or None
A free-space run’s transverse edge (SEP 40 section 5.3), read on its own spacing; its record joins this monitor’s under
transverse.- crossingsolprop.boundaries.SplitCrossing or None
The split collar’s crossing limit, set by the step driver when the monitor is attached to a split run: every reading then carries the state’s occupancy, and the limit it gives caps the steps until the next check (
step_cap).- splitbool
Whether the temporal collar is applied once per accepted step (the
"split_step"scheme), whose removal the backend then adds up exactly at every accepted step (BoundaryEnergies.removed) rather than the monitor integrating the rate by the trapezoid (D5), and whose guards are judged on the power the split found (BoundaryEnergies.found), which every reading after a step must then carry.
- classmethod build(grid, temporal_rate, check, *, columns=None, split=False)[source]#
Return a monitor for a grid and its temporal collar.
- Parameters:
- gridTimeGrid
The run’s grid.
- temporal_ratenumpy.ndarray or None
The collar’s power rate on the coarse axis, 1/m, or
Nonewithout one.- checkBoundaryCheck
The thresholds.
- columnsnumpy.ndarray or None, optional
Quadrature weights of a spatial run’s transverse columns.
- splitbool, optional
Whether the collar is applied by the
"split_step"scheme.
- Returns:
- BoundaryMonitor
A monitor with nothing recorded.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.monitor import BoundaryCheck, BoundaryMonitor >>> grid = EnvelopeGrid.from_limits(1.0, 800e-9, (600e-9, 1.2e-6), 1e-12) >>> BoundaryMonitor.build(grid, None, BoundaryCheck()).weights.shape[0] 4
- check: BoundaryCheck#
- property checked_at: float | None[source]#
Return the position of the last check, m, or
Nonebefore the first.- Returns:
- float or None
Where
due()’s distance rule measures from.
- property collar_quiet: bool[source]#
Whether the collar’s in-stage term may be left out of the next stages.
True only when the run opted in (
BoundaryCheck.quiet_collar) and the collar held less thanQUIETof the field’s energy, floor included, at the lastQUIET_CHECKSchecks.- Returns:
- bool
The flag.
- crossing: SplitCrossing | None = None#
- due(z)[source]#
Return whether the step just committed at z is to be checked.
Every step is while a guard or the collar is active (
ACTIVE), and otherwise everyCADENCE-th or afterinterval, whichever comes first; the caller passes the others toskip()without reading the state.- Parameters:
- zfloat
The committed position, m.
- Returns:
- bool
True to call
step()with the committed state.
- energies(field_spectrum)[source]#
Return a state’s energy and its four weighted energies, on the host.
The reference reduction every backend’s own is held to; a split’s removal is not a property of one state, and is zero here.
- Parameters:
- field_spectrumnumpy.ndarray
A state, canonical layout, FFT convention.
- Returns:
- BoundaryEnergies
sum_t P(t)andweights @ P.
Examples
>>> import numpy as np >>> from solprop.grid import EnvelopeGrid >>> from solprop.monitor import BoundaryCheck, BoundaryMonitor >>> grid = EnvelopeGrid.from_limits(1.0, 800e-9, (600e-9, 1.2e-6), 1e-12) >>> monitor = BoundaryMonitor.build(grid, None, BoundaryCheck()) >>> pulse = np.exp(-((grid.t / 50e-15) ** 2)).astype(complex) >>> energies = monitor.energies(np.fft.fft(pulse)[None, None, None, :]) >>> bool(np.isclose(energies.total, np.sum(np.abs(pulse) ** 2))) True
- finish()[source]#
Report the removed fraction at the end of a run (D5).
Logged always; warns when its square root exceeds the budget.
- launch(energies, z, *, floor=None)[source]#
Record the launch, and warn or refuse if it already fills a guard.
The rule of every later check (
step()): the square root of a guard occupancy above the budget warns, and abovestop_factorbudgets refuses the run before its first step. Afterresume()the state is the one the run resumes from, recorded and not judged.- Parameters:
- energiesBoundaryEnergies
The backend’s reading of the launched state; its removal is not read.
- zfloat
Its position, m.
- floornumpy.ndarray or None, optional
The input-noise draw the launch carries, canonical layout, FFT convention;
Nonewithout one. Its energy is the vacuum floor the monitor judges above (Q24), read here on the host once.
- Raises:
- BoundaryError
When the square root of a guard occupancy exceeds
stop_factorbudgets.
- note_collar(left_out)[source]#
Record whether the stages leave the collar’s term out from here on.
The run’s driver decides, from this monitor’s
collar_quietand from whether its route can leave the term out at all; while it is out the collar absorbs nothing, andstep()adds no removal for those steps.- Parameters:
- left_outbool
True while the in-stage term is left out.
- plane(z)[source]#
Record the row of the saved plane the run has just reached.
The row holds the collar occupancy at the plane, each guard’s largest occupancy over the committed steps since the previous plane, and the removed fraction so far, all above the shot-noise floor (SEP 21 section 6, D5).
- Parameters:
- zfloat
The plane’s position, m.
- power(field_spectrum)[source]#
Return the time-domain energy density summed over everything but time.
The host reduction, in binary64 whatever the state’s precision.
- Parameters:
- field_spectrumnumpy.ndarray
A state, canonical layout, FFT convention.
- Returns:
- numpy.ndarray
P(t)on the coarse time axis, weighted by the columns’ quadrature.
- property removed: float[source]#
Return the collar’s removal of the launched signal, above the floor’s share.
The whole field’s removal (
raw_removed_fraction) less what the input noise’s floor is expected to lose, which is at most the floor itself: the input model puts one floor in at the launch and never adds to it. Signed; the record and the warning read it clipped at zero.- Returns:
- float
A fraction of the launch energy.
- resume(record, *, plane, unwatched=())[source]#
Continue the record of the executions a resumed run follows (SEP 21).
Called before
launch(), which then records the resumed state without judging it: the first execution judged the launch, and a run stopped at an edge may be resumed under a relaxed check. When record carries the monitor’s totals,launch_energyamong them, they are restored, so the removed fraction, the guard maxima and the rows continue against the original launch; otherwise the record starts again from the resumed state, its launch fields unmeasured.- Parameters:
- recordcollections.abc.Mapping or None
The
boundary_monitorrecord of the latest earlier execution, orNonewithout one. Rows are restored from a closing record; a running one, written at a plane, carries none (solprop.driver.run.run_problem()).- planebool
Whether the run resumes at a saved plane, whose row is then recorded unless the restored rows hold it.
- unwatchedcollections.abc.Sequence of tuple of float, optional
Stretches,
(start, end)in m, that executions after record’s ran without a monitor. Their removal is unknown rather than zero: the totals continue from record, and the stretches are listed in the record (unwatched).
- split_sums(field_spectrum, step)[source]#
Return what one accepted step’s split collar takes, and what it finds.
The split multiplies the field by
exp(-alpha(t) h / 2), so it takesP(t) (1 - exp(-alpha(t) h))of the powerPit finds, read exactly from the state before the split; the band mask after it is not counted. Read back from the committed state instead, the same removal would beP (exp(alpha h) - 1)of the power the split left, which multiplies whatever the mask leaves deep in the collar byexp(alpha h): a removal made from nothing. The energy and the guards’ energies ofP exp(-alpha h / 2), the same power halfway through the factor, are what the guards are judged on (BoundaryEnergies.found), with the collar’s. The host reduction a backend’s accepted-step finish is held to.- Parameters:
- field_spectrumnumpy.ndarray
The accepted state before the split, canonical layout, FFT convention.
- stepfloat
The step’s length, m.
- Returns:
- numpy.ndarray
Shape
(5,), in the proxy’s units: the energy taken, then the energy and the low guard’s, the high guard’s and the collar’s energies of the power found, halfway through the factor.
Examples
>>> import numpy as np >>> from solprop.boundaries import absorber >>> from solprop.grid import EnvelopeGrid >>> from solprop.monitor import BoundaryCheck, BoundaryMonitor >>> grid = EnvelopeGrid.from_limits(1.0, 800e-9, (600e-9, 1.2e-6), 1e-12) >>> rate = absorber(grid).temporal_rate >>> monitor = BoundaryMonitor.build(grid, rate, BoundaryCheck(), split=True) >>> edge = 0.5 * grid.n_t * grid.dt >>> pulse = np.exp(-(((grid.t - 0.98 * edge) / 10e-15) ** 2)).astype(complex) >>> taken, found, low, high, collar = monitor.split_sums( ... np.fft.fft(pulse)[None, None, None, :], 0.01 ... ) >>> bool(taken > 0.0), bool(low < 1e-20 * found), bool(high > 0.5 * found) (True, True, True)
- property stale: bool[source]#
Whether the last committed step went unchecked.
- Returns:
- bool
True when
skip()was the last call.
- step(energies, z)[source]#
Account one committed step, and warn or stop on a guard occupancy.
- Parameters:
- energiesBoundaryEnergies
The backend’s reading of the committed state, with what a split collar took since the previous reading.
- zfloat
Its position, m.
- Raises:
- BoundaryError
When the square root of a guard occupancy exceeds
stop_factorbudgets.
- property step_cap: float[source]#
Return the split collar’s crossing limit the last reading gave, m.
The steps until the next check are held to it;
infwithout one.- Returns:
- float
The cap, m.
- steps_to_check()[source]#
Return after how many more committed steps the cadence makes a check due.
One while a guard or the collar is busy, and before the first check; otherwise the steps left to
CADENCE. The distance rule can make a check due sooner:intervalpastchecked_at. A native Adams march returns to its host at the step either makes due (SEP 39 section 4.8).- Returns:
- int
At least one.
- summary()[source]#
Return the record of the run so far, for its execution record.
- Returns:
- dict
The thresholds of this execution (
guard_fraction,budget,stop_factor,quiet_collar); the launch’s energy in the monitor’s own units, the denominator of every fraction (launch_energy), and where the run was resumed (resumed_at, empty for an uninterrupted one). Launch occupancies, the largest guard and collar occupancies and where the guards peaked, the removed fraction of the launched signal and the number of committed steps accounted, all judged above the shot-noise floor;Nonefor what was never measured (a launch a resume could not recover, a guard nothing reached). Beside them, the floor’s share of the launch energy (noise_floor, zero without input noise), and the largest guard share and the removed fraction of the whole field, floor included (raw_guard_max,raw_removed_fraction), and how many checks found the collar’s term left out since the previous one (collar_left_out_checks, zero unless the run opted in toBoundaryCheck.quiet_collar). Underplanes, one row per saved plane from the launch on:z, thecollar_occupancythere, each guard’s largest occupancy since the previous plane (guard_low,guard_high) and theremoved_fractionso far. For a resume to continue from:removed_signed, the removal unclipped (removed);floor_removed_fraction, the floor’s expected removal, uncapped;quiet_checksandcollar_quiet, the quiet collar’s count and flag.unwatchedlists the stretches,[start, end]in m, that an execution ran without a monitor, whose removal is unknown. A resumed run continues all of these (resume()).
- transverse: TransverseEdge | None = None#
- weights: Float[ndarray, '4 n_t']#
- solprop.monitor.CADENCE = 8#
Committed steps between checks while the edges are quiet: every one of them while a guard or the collar holds more than
ACTIVEbudgets squared, and the state of every saved plane, are checked regardless.
- solprop.monitor.CHECKS = 256#
The fewest checks over the guide’s length: a quiet window is checked at least every
length / CHECKS(or at every committed step, when the steps are longer), so light must walk about twenty windows over the run to cross the collar and guards between two checks. While an opted-in quiet collar is left out of the stages no step is longer than that interval, so the premise holds where an unabsorbed crossing would matter.
- solprop.monitor.DEFAULT_BOUNDARY_CHECK = BoundaryCheck(guard_fraction=0.05, budget=0.001, stop_factor=10.0, quiet_collar=False, transverse_budget=None)#
The check a run takes unless its settings or an interface keyword say otherwise.
- solprop.monitor.FLOOR_MARGIN = 3.0#
How many times its expected energy the floor is allowed in a region before light is counted there. A region of
ntime samples holds the floor to a relative spread of about1/sqrt(n); three times the expectation keeps the narrowest guards in use (a few samples) from reading the floor’s fluctuation as light.
- solprop.monitor.QUIET = 1e-12#
The share of the field’s energy, floor included, below which the collar counts as quiet: when the run opts in (
BoundaryCheck.quiet_collar), its in-stage term may then be left out of the stages (SEP 21). As a field amplitude, a thousandth of the default budget’s thousandth.
- solprop.monitor.QUIET_CHECKS = 2#
Consecutive quiet checks before the collar’s term is left out. Light returning puts it back at the first check that sees it; asking for two quiet ones before leaving it out again keeps a collar hovering at the threshold from switching at every check, each switch costing the march a reused stage or an Adams rejection.