Skip to content

Make the quadrature scheme the configuration choice#728

Draft
haakon-e wants to merge 4 commits into
mainfrom
he/quadrature-choice
Draft

Make the quadrature scheme the configuration choice#728
haakon-e wants to merge 4 commits into
mainfrom
he/quadrature-choice

Conversation

@haakon-e

@haakon-e haakon-e commented Jun 14, 2026

Copy link
Copy Markdown
Member

Make the quadrature scheme the configuration choice

Motivation

The P3 size-distribution integrals (deposition and sublimation, melting, riming, ice-rain collection, sedimentation) were configured through a single integer quadrature_order knob. build_quadrature then mapped a magic set of orders, {16, 32, 40, 64}, to Gauss-Legendre and silently fell back to Chebyshev-Gauss for every other order. That coupling makes the knob misleading: the order selects the scheme as a side effect, so a caller who lowers the order from 40 to 36 to trade a little accuracy for speed silently switches integration rules and changes the error characteristics in a way the knob name does not suggest. The two attributes being conflated, the scheme and its order, are independent choices.

What changed

The quadrature scheme is now the explicit configuration value, passed as a scheme instance that carries its own parameters, the order among them:

Microphysics2MParams(FT; with_ice = true,
    quadrature = Quadrature.GaussLegendre(40))

build_quadrature is reduced to materializing the chosen scheme in the working float type. Chebyshev-Gauss has closed-form nodes and passes through unchanged; Gauss-Legendre is rebuilt so its stored nodes and weights adopt FT, since a Float64 rule would leak Float64 into Float32 collision integrals. This is host-side and one-shot, and the result is isbits and reused in the GPU hot loop with no per-call construction, as before.

The default is Chebyshev-Gauss at order 100, which reproduces the previous default behavior exactly (the old default order of 100 was not in the Gauss-Legendre magic set, so it already resolved to Chebyshev-Gauss). The documentation now states the scheme tradeoff directly: at matched order Gauss-Legendre is substantially more accurate on the smooth P3 integrands, roughly a factor of 20 lower error on the dominant ice-rain collision integral, while Chebyshev-Gauss remains the conservative default; the cusp-limited ice self-collection diagonal is quadrature-limited under either scheme.

Breaking change

The quadrature_order keyword argument to Microphysics2MParams and P3IceParams is removed and replaced by the quadrature keyword, which takes a scheme instance. Callers passing quadrature_order must switch to quadrature = Quadrature.ChebyshevGauss(n) or Quadrature.GaussLegendre(n). Callers relying on the implicit order-to-scheme mapping (e.g. expecting order 40 to mean Gauss-Legendre) must now name the scheme explicitly. The default behavior is unchanged.

Testing

The bulk-tendencies quadrature tests are updated to construct schemes explicitly and to cover both the pass-through (Chebyshev-Gauss) and the FT-rebuild (Gauss-Legendre) paths of build_quadrature.

@haakon-e

haakon-e commented Jun 14, 2026

Copy link
Copy Markdown
Member Author

@haakon-e
haakon-e force-pushed the he/rosenbrock-2m-p3 branch from 730166f to 34dc9a0 Compare June 14, 2026 02:45
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch 2 times, most recently from fac357f to aaf6093 Compare June 14, 2026 03:42
@haakon-e
haakon-e changed the base branch from he/rosenbrock-2m-p3 to he/implicit-T June 14, 2026 04:08
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from aaf6093 to 603d7a2 Compare June 14, 2026 04:08
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch 2 times, most recently from 8024b90 to 8d49258 Compare June 17, 2026 00:20
@haakon-e
haakon-e changed the base branch from he/implicit-T to he/postsolve-diagnostics June 17, 2026 00:20
@haakon-e
haakon-e force-pushed the he/postsolve-diagnostics branch from 0122e0e to 224c902 Compare June 17, 2026 21:20
@haakon-e
haakon-e changed the base branch from he/postsolve-diagnostics to he/rosenbrock-modes June 17, 2026 21:20
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from 8d49258 to 74d309e Compare June 17, 2026 21:20
@haakon-e
haakon-e force-pushed the he/rosenbrock-modes branch from a4aa680 to 440ddbf Compare June 18, 2026 21:42
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch 2 times, most recently from 42ceb49 to 3713bbb Compare June 18, 2026 22:41
@haakon-e
haakon-e force-pushed the he/rosenbrock-modes branch from 440ddbf to 309724f Compare June 18, 2026 22:41
@haakon-e haakon-e mentioned this pull request Jun 18, 2026
@haakon-e
haakon-e force-pushed the he/rosenbrock-modes branch from 309724f to 871b731 Compare June 22, 2026 21:01
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch 2 times, most recently from c26927a to c7e9087 Compare June 22, 2026 23:42
@haakon-e
haakon-e force-pushed the he/rosenbrock-modes branch from 871b731 to 205acdc Compare June 22, 2026 23:43
@haakon-e
haakon-e changed the base branch from he/rosenbrock-modes to he/ad-compat-2m-p3 June 22, 2026 23:55
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from c7e9087 to a74dba4 Compare June 22, 2026 23:55
@haakon-e
haakon-e force-pushed the he/ad-compat-2m-p3 branch from db7adcf to 04792a8 Compare June 23, 2026 00:31
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from a74dba4 to 9507c4b Compare June 23, 2026 00:31
@haakon-e
haakon-e force-pushed the he/ad-compat-2m-p3 branch from 04792a8 to 26145ad Compare June 23, 2026 21:31
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from 9507c4b to 5bbf1e7 Compare June 23, 2026 21:31
haakon-e added 4 commits June 23, 2026 15:25
`get_state_from_prognostic` is not defined anywhere; the path was
unexercised by tests.
Implicit substepping needs Jacobians of the pointwise tendencies
w.r.t. the 8 prognostic species (`logλ` held fixed).

- Type flexibility for mixed Dual/plain inputs: P3State, Γ_incl, the
  gamma_inc_inv wrapper, ice_mass_coeffs, logistic_function_integral,
  Chen2022_exponential_pdf, LclRaiRates, the size-distribution closures.
- gamma_inc_inv: add an implicit-function-theorem Dual rule (none upstream),
  exact in the quantile slots; the shape slot differences
  the smaller of (P, Q), the larger saturating in the tails.
- SB2006 autoconversion: ϕ_au ∝ τ^0.7 has a vertical tangent at
  τ = 0, so ∂/∂q_rai is NaN at zero rain with cloud present. Condition
  the enhancement below ϵ_numerics_2M_M; value at q_rai = 0 unchanged.
- sgs_weight_function: Check the lower tail where atanh → -Inf
  makes rime-ratio partials bad in Float32.
- Early returns: typing from one argument (e.g. `FT = eltype(q_tot)`)
  makes the return union-typed and heap-boxed for mixed-type callers.
  Add Utilities.promote_typeof and apply it wher relevant.

Tests: per-row Jacobian-vs-FD consistency tests; AD coverage for the
regularised-ratio band, the tail shape slots, and mixed arguments;
sentinel_type_tests assert concrete returns per signature.

Deferred: the logλ shape solve (needs ∂/∂a of forward gamma_inc) and
the 1M early return cases.
The analytical solution for ρ_d has a denominator that is 0/0 as
F_rim → 0. In Float32 the cancellation drives ρ_d, and therefore ρ_g,
negative, which later raises a DomainError in get_D_gr. Rewrite get_ρ_d
with the relative exponential functions exprel1 and exprel2 so the
cancellation is removed; ρ_g then stays positive for every physical
input, with no clipping. Add the derivation and an error-cancellation
figure to the P3 documentation, and a Float32 stability test.
The P3 size-distribution quadrature was configured through a single
quadrature_order knob, with build_quadrature silently mapping a magic
set of orders {16, 32, 40, 64} to GaussLegendre and everything else to
ChebyshevGauss. The scheme — with its parameters, notably the order —
is now the explicit choice: pass a scheme instance,

    Microphysics2MParams(FT; with_ice = true,
        quadrature = Quadrature.GaussLegendre(40))

and build_quadrature only materializes it in the working float type
(GaussLegendre nodes are rebuilt in FT; ChebyshevGauss is closed-form
and passes through). The default ChebyshevGauss(100) preserves the
previous default behavior.
@haakon-e
haakon-e force-pushed the he/ad-compat-2m-p3 branch from 26145ad to 2c7d843 Compare June 23, 2026 22:26
@haakon-e
haakon-e force-pushed the he/quadrature-choice branch from 5bbf1e7 to aaf1fff Compare June 23, 2026 22:26
@haakon-e
haakon-e force-pushed the he/ad-compat-2m-p3 branch 7 times, most recently from 11eb605 to ddd64f0 Compare July 1, 2026 06:24
Base automatically changed from he/ad-compat-2m-p3 to main July 1, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant