Reference
Utilities¶
Output grid¶
The single shared builder of the uniform, endpoint-inclusive output time grid
([t0, t0+dt, …, tf]) that every integrator samples its results onto.
make_output_grid
¶
Build a uniform output grid from t0 to tf (inclusive).
The grid is arange(t0, tf, dt) with tf appended when the last
sample would otherwise fall short of it — so the final time is always
sampled exactly, regardless of whether dt divides tf - t0.
The endpoint tolerance
tf is appended when t_arr is empty or its last sample sits below
tf - 1e-12. The small absolute slack matters: when dt divides the
window cleanly, the last arange sample lands on tf only up to
floating-point error — typically a fraction of a ULP below it. Comparing
against the bare tf would then see t_arr[-1] < tf and append a second,
sub-ULP-spaced "endpoint", giving a spurious final segment of width ~1e-16.
The 1e-12 slack treats any sample already within that band of tf as
being the endpoint, so a cleanly-dividing window yields no duplicate tail.
It is an absolute tolerance (not relative) by deliberate design: the
integration windows here are O(1)–O(1e3) in time units and dt is rarely
below ~1e-6, so 1e-12 is far smaller than any meaningful step yet comfortably
larger than arange round-off — a relative tolerance would buy nothing and
complicate the contract. (A pathological window with dt itself near
1e-12 is already rejected upstream as physically meaningless.)
This is the one chokepoint every flow family (ODE / DDE / SDE) and the
engine run layer build their grid through, so it is also where the
silent-footgun horizons are caught early with a domain message: a
non-positive dt (which used to surface as a bare ZeroDivisionError
from this helper) and a window that does not run forward in time (which used
to yield a one-sample garbage trajectory).
Every bound must additionally be finite. dt and final_time were
guarded only by > 0 / > t0, which +inf satisfies: an infinite
dt slipped through to a two-sample [t0, tf] grid (a "trajectory" of
one giant step, silently nothing like the requested sampling), and an
infinite final_time reached :func:numpy.arange, which raised the
unhelpful ValueError: Maximum allowed size exceeded. Both are rejected
here instead, naming the offending value.
| PARAMETER | DESCRIPTION |
|---|---|
t0
|
Start and end of the window.
TYPE:
|
tf
|
Start and end of the window.
TYPE:
|
dt
|
Output sampling interval. Must be strictly positive.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ndarray
|
The output times, with |
| RAISES | DESCRIPTION |
|---|---|
InvalidParameterError
|
If |
Examples:
Source code in src/tsdynamics/_utils/grids.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |