aquakin.dgsm#
- aquakin.dgsm(fn, ranges, *, input_names=None, output_names=None, n_samples=64, seed=0, diff=DifferentiationConfig(mode='reverse', method='stable', check_finite=True, adjoint_max_steps=100000, adjoint_low_memory=False), batched=True)[source]#
Derivative-based global sensitivity measure via autodiff + Sobol QMC.
Estimates, for each uncertain input
z_j,nu_j = E_z[ (d fn / d z_j)^2 ]by averaging the squared partial derivative over scrambled-Sobol quasi-random points in the input ranges.
nu_jbounds the Sobol total-order index (seeDGSMResult.sobol_total_bound), so it is the AD analogue of a variance-based Sobol total index, obtained from derivatives rather than a variance decomposition.The derivatives are exact (no finite-difference truncation) and reuse the differentiable model, so the same machinery serves the calibration and identifiability analyses. The cost depends on
ad_modeand on the number of outputsmand inputsd:ad_mode="reverse"(default) forms the per-sample sensitivities withmreverse-mode passes (one per output), each independent ofd. Best when there are few outputs relative to inputs and the adjoint is cheap. Works with any reactor adjoint.ad_mode="forward"forms them withdforward-mode tangents pushed through a single solve, independent ofm. Best when there are many outputs, or when the reverse adjoint is expensive – e.g. a stiff solve whose differentiated step must be capped (dtmax), which inflates the reverse pass. The reactor inside ``fn`` must then be built withadjoint=aquakin.forward_adjoint()(dgsmcannot set the adjoint for you, becausefnconstructs the reactor): the defaultRecursiveCheckpointAdjointregisters acustom_vjpthat rejects forward-mode autodiff.
Both modes return identical sensitivities (to machine precision);
ad_modeis purely a performance choice. For a single scalar outputreverseis almost always cheaper; theforwardadvantage appears for multi-output screening of a stiff model.- Parameters:
fn (callable) – Maps an input vector (shape
(d,)) to either a scalar JAX value or a vector ofmoutputs (shape(m,)). Must bejax-differentiable in the requestedmode. For a reactor study,fntypically maps the uncertain inputs into a parameter vector / initial state, callsreactor.solveand reduces the solution to the output(s). If the model is stiff, build the reactor with a suitabledtmaxso the differentiated solve stays finite.dgsmdoes not own the solve (yourfnbuilds the reactor and chooses thet_eval), so it cannot apply atime_unitconversion for you: anyt_eval/t_spaninsidefnmust be in the model’s native time unit, orfnmust passtime_unit=to its ownreactor.solvecall.ranges (array-like, shape (d, 2)) –
[lower, upper]bound for each input; sampling is uniform within.input_names (list[str], optional) – Names for reporting; defaults to
["z0", "z1", ...].output_names (list[str], optional) – Names for the
moutputs whenfnis vector-valued; defaults to["output0", ...]. Ignored for a scalarfn.n_samples (int, optional) – Target number of quasi-random points; rounded to the nearest power of two (Sobol sequences are balanced at powers of two). Increase until
std_erroris small relative to the ranking gaps.seed (int, optional) – Seed for the scrambled-Sobol sampler. Fixing it (the default
0) makes the analysis exactly reproducible.diff (DifferentiationConfig, optional) – Autodiff configuration.
mode({“reverse”, “forward”}) selects the direction used to form the per-sample sensitivities (see above).batched (bool, optional) – When
True(default) the whole sample is pushed through onejax.vmapdispatch and finiteness is filtered once on the stacked result – one device->host transfer instead of one per point. SetFalseto evaluate point-by-point (lower peak memory for a large screen). Both give identical results.
- Returns:
A single
DGSMResultwhenfnis scalar-valued, or a list of results (one per output, in order, each carrying itsoutput_name) whenfnis vector-valued.- Return type:
DGSMResult or list[DGSMResult]
Examples
>>> def fn(z): # output sensitive to z0, not z1 ... return 3.0 * z[0] + 0.0 * z[1] >>> res = aquakin.dgsm(fn, [(0.0, 1.0), (0.0, 1.0)], input_names=["a", "b"]) >>> res.ranked()[0][0] 'a'