Deterministic checks for pymrm models.
Small tools for the verification steps every model needs, so that they do not have to be rewritten (and debugged) for each model:
check_jacobiancompares a Jacobian with finite differences;observed_ordersruns a refinement study and reports observed orders;find_rootslocates every sign change of a scalar function in a range;residual_checkjudges a converged solution by a scale-free backward error instead of an absolute residual threshold.
The module depends on numpy and scipy only.
Public API¶
| Symbol | Type | Summary |
|---|---|---|
check_jacobian | function | Compare the Jacobian returned by fun with central differences. |
find_roots | function | Locate every sign change of f on [lo, hi] and refine each root. |
observed_orders | function | Run a refinement study and report observed orders of convergence. |
residual_check | function | Judge a solution by its componentwise backward error. |
check_jacobian(fun, x, n_probe = 4, rtol = 0.0001, seed = 0, eps = None)¶
Compare the Jacobian returned by fun with central differences.
Parameters¶
fun(callable)fun(x) -> (g, jac), the residual and its Jacobian, as passed topymrm.newton.jacmust be a matrix (not a factorisation).x(numpy.ndarray) State at which to compare. Use a state away from the solution, where all terms are active.n_probe(int, optional) Number of random directionsvfor whichjac @ vis compared with a central difference ofg.rtol(float, optional) Tolerance on the relative mismatch.seed(int, optional) Seed of the random directions (the check is deterministic).eps(float, optional) Relative finite-difference step; defaultcbrt(machine epsilon). Each component is perturbed in proportion to its own size.
Returns¶
dictok(bool),max_rel_errorover the probes, and, for at most 500 unknowns,worst_entry(row, col, jac_value, fd_value)from a full column-by-column comparison.
find_roots(f, lo, hi, n_scan = 64, log = False, xtol = 1e-12)¶
Locate every sign change of f on [lo, hi] and refine each root.
Parameters¶
f(callable) Scalar function. It may raise, or returnnan, where the underlying model cannot be evaluated; such points are reported, never taken as a sign.lo, hi(float) Physically possible range.n_scan(int, optional) Number of scan points.log(bool, optional) Scan on a logarithmic grid (loandhimust be positive).xtol(float, optional) Absolute tolerance of each refined root (brentqxtol).
Returns¶
dictroots(sorted list),failed(scan points wherefcould not be evaluated) andmessage. No sign change gives an empty list and says so; it does NOT widen the range.
observed_orders(solve, ns, ratio = None)¶
Run a refinement study and report observed orders of convergence.
Parameters¶
solve(callable)solve(n) -> float or array, the quantity of interest computed with resolutionn(cells, or number of time steps). An array must have the same shape at every resolution (for example values at fixed positions).ns(sequence[int]) At least three resolutions with a constant refinement ratio, for example(50, 100, 200, 400).ratio(float, optional) Refinement ratio; defaultns[1] / ns[0].
Returns¶
dictvaluesper resolution,ordersfrom each consecutive triple,extrapolated(Richardson estimate from the finest triple) anderror_estimateof the finest value against it;nanwhen the finest order is not positive (the study is not converging).
Notes¶
The order from values q1, q2, q3 on successively finer grids is
log(|q1 - q2| / |q2 - q3|) / log(ratio); it needs no exact solution. An
order far from the expected one means the study is not in the asymptotic
range, the refinement does not control the error that dominates, or there is
a bug. For a non-uniform grid, refine it in a nested way (see the pymrm
agent plugin’s profiles.md).
residual_check(fun, x, tol = 1e-08)¶
Judge a solution by its componentwise backward error.
An absolute threshold on the residual depends on the units and scaling of
the equations. The backward error max_i |g_i| / (|J| |x| + |J x - g|)_i
is scale-free: it measures the relative change in the (linearised) equation
coefficients that would make x exact.
Parameters¶
fun(callable)fun(x) -> (g, jac).x(numpy.ndarray) Candidate solution, for exampleresult.xfrompymrm.newton.tol(float, optional) Acceptance threshold on the backward error.
Returns¶
dictok(bool),backward_errorandmax_abs_residual.