Battery Pack Thermal Digital Twin · Phase 0 of 4

The Differentiable Pack

By Majid Mazouchi · Drafted with Claude

Before a neural operator can learn a battery pack's thermal life, something has to tell it the truth. Phase 0 builds that truth-teller: a 3D transient solver for a liquid-cooled prismatic pack, written entirely in NVIDIA Warp kernels, so the whole simulation is one differentiable program. This page shows the concepts, lets you run the physics live, and replays the real results.

Where this sits

1Four phases, three model families, one pack

Each downstream phase answers a different question about the same pack, and every one of them eats Phase 0's output. Gradients from the differentiable solver flow forward too: they benchmark the PINN inverse problem and enable solver-in-the-loop fine-tuning of the operators.

PHASE 0 Differentiable Warp ground truth + adjoint PHASE 1 · PINN inverse R_int estimation PHASE 2 · KNO / FNO fast field surrogate PHASE 3 · GNN pack-topology transfer PHASE 4 · VHM residual detectors + Koopman eigen-tracking fleet health adjoint gradients labeled data
The physical model

2Anatomy of one time step

Prismatic cells sit on a voxel grid: in-plane conductivity 25 W/mK, only 2 W/mK through the stack, so heat prefers to run along a cell rather than across its neighbors. Interface material (TIM) bridges cells; foam fills the margins. Coolant channels run under the floor, and each channel warms as it flows, so downstream cells always run hotter. Heat enters through the Bernardi equation:

q̇ = ( I² R_int  +  I · T · dU/dT ) / V_cell
CROSS-SECTION (y-z) · cells stacked along y, cooled floor at z = 0 foam coolant channels · flow along x (into the page here), inlet-to-outlet warming h ∝ ff⁰⋅⁸ sink

Every step launches three Warp kernels in order, and because each is pure Warp, the composition is a single differentiable program:

heat_source Bernardi q̇ per cell voxel coolant_march 1D energy balance / channel diffuse explicit FTCS, harmonic k stability: Δt ≤ Δx² / 6α_max  →  0.40 s at 5 mm voxels (0.20 s used)
Run the physics yourself

3Live pack simulation

This is the same numerical method as the Warp solver, running a 2D cross-section in your browser: explicit FTCS, harmonic-mean face conductivities, Bernardi heating from a looping synthetic drive cycle, convective floor cooling. Inject a fault and watch the field respond. Hot spots take tens of simulated seconds to develop, exactly why early detection needs a model, not a threshold.

speed
t = 0 s I = 0 A max T = 25.0 °C ΔT pack = 0.0 °C
rust trace: hottest cell · teal trace: pack mean · the colormap rescales as the pack heats
From the actual Warp runs

4Results: the solver at work

Everything below is real output embedded from the Phase 0 runs, not an illustration. The scenario shown is the degraded-TIM fault: 300 seconds of drive cycle on the 50,400-voxel demo pack, about 4 seconds of wall time per scenario on CPU.

DRIVE CYCLE CURRENT AND PER-CELL MEAN TEMPERATURES
FINAL TEMPERATURE FIELD · mid-height x-y slice · the bright band is heat trapped behind the delaminated TIM interface
The differentiability payoff

5Backpropagating through 240 time steps

Warp records every kernel launch on a tape, then replays exact adjoints in reverse. A sensor-mismatch loss at the end of a rollout therefore has a gradient with respect to each cell's internal resistance, through every diffusion step, every coolant march, every heat-source evaluation in between.

FORWARD: rollout recorded on wp.Tape() R_int step 1 step 2 ··· step 240 sensor MSE BACKWARD: tape.backward() → ∂loss / ∂R_int, exact, in one pass

The experiment: one cell carries a 3× resistance fault. Six surface thermocouples, sampled every 10 seconds with noise, feed 40 Adam iterations. Press play to replay the actual optimization trace:

iteration 0 / 39
left: sensor MSE (log scale) · right: per-cell R_int estimates, rust = faulted cell, dashed = truth · final error on the faulted cell: 0.4%
Trust, then automate

6Verification gate

run_all.bat and run_all.sh execute the pipeline end to end and stop at scripts/verify.py, which exits nonzero on any failure, so it doubles as a CI gate. Current status of every check:

PASS 5 scenario files present (nominal + 3 fault families)
PASS all temperature fields finite, within 5 to 90 °C
PASS cells measurably heat under the drive cycle
PASS inverse loss decreased 1.363 → 0.123
PASS faulted cell R_int recovered to 0.4% (tolerance 5%)
PASS healthy cells within tolerance of nominal
PASS pipeline: venv → data → inverse → figures → verify