pub fn central_difference(
base: &ResolvedSolveRequestV1,
axis: InputAxis,
ranges_m: &[f64],
step: Option<f64>,
) -> Result<Vec<Derivative>, KernelError>Expand description
Central difference: (f(x+h) - f(x-h)) / 2h, covering every range in ranges_m with
exactly two solves total (one per side) in the common case – see the module doc’s “Cost”
section. The step follows the crate convention
h = (|x| * default_rel_step).max(min_abs_step) (axis_meta, taxonomy.rs) unless the
caller supplies an explicit step. When one perturbed side leaves the axis’s physical
domain, falls back to a one-sided difference – see the module doc’s “One-sided fallback”
section and Derivative::scheme.
§Errors
KernelError::CategoricalAxisifaxis_meta(axis).kindisAxisKind::Categorical(spec D7: categorical axes are never differentiated).KernelError::AxisAbsentifaxishas no value onbase–read_axisreturnsNonehere directly, without ever reachingwith_axis– most notably the three wind axes under segmented wind.KernelError::TypeMismatchifread_axisever returns a non-Scalarvalue for a continuous axis. Not reachable with the current taxonomy (everyContinuousaxis reads back asScalarorNone;Flag/DragModel/TwistDirectiononly ever come fromCategoricalaxes, already rejected above), kept as a defensive catch-all so a future axis added under the wrongAxisKindfails loudly here instead of miscomputing silently.KernelError::NonFiniteif the computed or caller-supplied step is not a finite positive number, or if either resulting derivative is not finite.KernelError::AxisUnsupportedForRequestorKernelError::AxisAbsent, propagated unchanged fromwith_axis– these depend only onaxis/base, never on the perturbed value, so they surface immediately with no fallback attempted (see the module doc).KernelError::StepOutOfDomainif BOTH perturbed sides fail with a domain rejection (KernelError::is_domain_rejection) – there is no data left to build even a one-sided difference from.KernelError::SolveorKernelError::Observation, propagated unchanged fromevaluate, for any failure that is NOT a domain rejection on either perturbed side (see the module doc’s “One-sided fallback” – this is the case the fallback must NOT swallow), or if the UNPERTURBED value atxitself also fails to evaluate during a one-sided fallback – a degenerate case distinct fromStepOutOfDomainin that even the base value is unusable, not just the step.