Skip to content

KernelBackend: the aero_panel kernel's analytical Jacobian is NaN under ContinuousAero - #299

Open
1-Bort-1 wants to merge 4 commits into
mainfrom
agent/289-kernelbackend-the-aero-panel-kernel-s-an
Open

KernelBackend: the aero_panel kernel's analytical Jacobian is NaN under ContinuousAero#299
1-Bort-1 wants to merge 4 commits into
mainfrom
agent/289-kernelbackend-the-aero-panel-kernel-s-an

Conversation

@1-Bort-1

@1-Bort-1 1-Bort-1 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixed

The guard warned where you asked it to error, and once it errored it fired on
models whose Jacobian is fine: it was evaluated before the parameters were
synchronised, so it read the buffer assemble leaves rather than the masses and
inertias the system structure writes.

Changes

  • src/kernel_backend/jacobian.jl:258check_jacobian_finite evaluates the
    plan once and throws, naming the kernels whose own dual pass came back
    non-finite and pointing at analytic_jacobian=false. build_jacobian is
    untouched planning again, so this file's diff to main is purely the added
    function. The self-feeding path keeps its warn-and-decline: a model shape, not
    a broken derivative.
  • src/kernel_backend/backend.jl:44 — the check runs after
    sync_params!, on problem.u0/problem.p. Before this it ran ten lines
    earlier and reported rigid_body/ride_wrench as non-finite on a healthy
    model.
  • test/test_analytic_jacobian.jl:232 — asserts the throw; the ContinuousAero
    • KernelBackend case above it is the MWE this issue asked for.
  • Merged origin/main (fc9b9494); only CHANGELOG.md conflicted, both sides'
    entries kept.

Verification

  • test/test_flap_aero.jl on the KernelBackend: 6 passed, 2 errored
    before the ordering fix, 18 passed after · test_analytic_jacobian.jl
    14 passed, and its throw testset is red when the guard only warns
    (13 passed, 1 failed, "No exception thrown").
  • Full kernel-backend suite on the box: 3378 pass, 0 fail, 0 error,
    10 broken
    (17m44s) — the 10 broken are the pre-existing Flow curvature
    ones · agent ci-local (monolith) PASS in 31m · GitHub CI all 7
    checks green
    on this head, the 1.12 ubuntu kernel cell included — that
    is the cell whose failure found the ordering bug above.
  • Risk: init! now throws where it silently handed the solver a broken
    Jacobian, so a genuinely non-finite plan fails at build time instead of at the
    first implicit step. analytic_jacobian=false is the way past it.

Closes #289 · task SymbolicAWEModels.jl-289

The KernelBackend plans a Jacobian and gives it to FBDF unseen. #289 reports it
coming back NaN for the aero_panel kernel under ContinuousAero on some hardware,
and the only thing the user sees is dt driven below floating-point epsilon on the
first implicit step, which names neither the Jacobian nor the kernel.

build_jacobian now evaluates its plan once at the model's initial state. A
non-finite result warns, names the kernels whose own dual pass came back
non-finite, and returns nothing, so the solver differentiates the right-hand side
itself. That is the policy the self-feeding case already had, and the same
outcome as the analytic_jacobian=false workaround, reached without the user
having to find it.

test_analytic_jacobian.jl gains the ContinuousAero wing the report is about, so
the aero_panel kernel's dual pass is covered and the guard is shown not to fire
on a healthy model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y87tAaun3BWKHndQYmPoxx
@codecov-commenter

codecov-commenter commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@1-Bart-1

1-Bart-1 commented Sep 8, 2026

Copy link
Copy Markdown
Member

It should error instead of warn

1-Bort-1 and others added 3 commits September 8, 2026 17:37
…nd-the-aero-panel-kernel-s-an

# Conflicts:
#	CHANGELOG.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxezjtdNiiUyeFn5TQgXPR
@1-Bort-1

1-Bort-1 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Local full suite: PASS (37 min, Julia 1.12.7, one cell of the matrix)

@1-Bart-1

1-Bart-1 commented Sep 9, 2026

Copy link
Copy Markdown
Member

But this doesn't close the issue. You haven't found the cause of the issue. Can it be reproduced on a docker image?

@1-Bort-1

1-Bort-1 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Agreed, and I have changed #299's trailer from Closes to Refs so merging it does not close this. It turns a silent NaN Jacobian into an error at init! and nothing more.

Not on this box: there is no container runtime here — no docker, podman, apptainer, bwrap or chroot — and sudo wants a password.

It would not add anything here in any case. A container swaps userspace, not the CPU, and the version axis it would pin is already pinned: this branch runs Julia 1.12.7, VortexStepMethod 4.3.1 and SymbolicIndexingInterface 0.3.55, the exact versions in the report, and an earlier round ran the whole of v0.15.1's src/ against ModelingToolkit 11.38.2, SciMLBase 3.34.0 and OrdinaryDiffEqCore 4.6.0. Both are clean on the V3 system_cabauw model — 0 non-finite of 7756 entries, and max|J - ForwardDiff.jacobian(rhs)| = 1.86e-9 against max|J| = 5.69e7, which is the same 5.69e7 the report measured.

On the machine that does reproduce it a container is exactly the right experiment, because there it holds the silicon fixed and swaps everything else. Still NaN inside → the CPU or the RAM. Clean inside → that install, and ~/.julia/compiled is the first thing I would delete; the scratchspace that was cleared is our model cache, not Julia's precompile cache.

Worth running, because the contradiction in the report holds up against the generated body and against everything it calls. AeroPanel's twenty inputs are le_a 1-3, te_a 4-6, le_b 7-9, te_b 10-12, va_a 13-15, va_b 16-18, rho_a 19, rho_b 20, so the slot labels in the report are right and the lane accounting is not the error. The body's whole vocabulary is +, *, /, abs2, atan, NaNMath.sqrt/pow/sin/cos and three scalar polar callables; those three go PanelPolar → ContinuousPolar → VortexStepMethod.calculate_cl/cd/cm → a clamp to alpha_window → a gridded linear Interpolations lookup, which is comparisons, clamps and lane-uniform arithmetic and nothing else. ForwardDiff maps a Partials through every one of those the same way in all twenty lanes — a·p_i + b·q_i with one a and one b — so nothing on this path can leave lane 14 NaN while lane 17 is finite out of arg2[14] + arg2[17]. What is wrong is the partials tuple as it sits in memory or in a vector register, which is a property of the machine rather than of the model, and that is why it does not travel with the model to another box.

@1-Bort-1 1-Bort-1 added agent:ci Agent task state agent:review Agent task state and removed agent:running Agent task state agent:ci Agent task state labels Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:review Agent task state

Projects

None yet

Development

Successfully merging this pull request may close these issues.

KernelBackend: the aero_panel kernel's analytical Jacobian is NaN under ContinuousAero

3 participants