v2.5.0
The charge-diffusion correction in vmr_signal is integrated by 64-node Gauss-Legendre quadrature in place of a 1001-node midpoint rule: three orders of magnitude more accurate with fifteen times fewer evaluations. There is no closed form to reach for, the integrand reducing to a family sympy returns as non-elementary (#217).
The axes along the edges of the two stop surfaces are named in public, as axis_field_stop, axis_pupil_stop, and axis_stops. field_boundary tells a caller to reduce its outline in whichever way their instrument takes to be its field of view, and until now gave them no supported way to say which axes to reduce over (#216).
Replaceable is a new mixin, giving every object which carries it a replace method, as named_arrays.AbstractArray already had. A nested change now reads the same at every level rather than needing dataclasses.replace wrapped around the outer one. It is carried wherever Printable already was. The copy is shallow, as dataclasses.replace is (#218).
A multilayer coating interpolated over the angle of incidence is now tested with rays whose angle carries a distribution, for every concrete material. num_interpolation shipped in 2.4.0 with nothing in the suite enabling it (#214).