Battery Pack 24-Cell Module

PARITYS3 · dim 254

No clear winner. The survival gap is under 10 percentage points and the balanced-score gap is under 0.05, so neither SolvSRK nor the best baseline clears the win threshold. Either works — choose on cost, licensing, or integration effort. All verdicts →

24-cell 6x4 module with 4-stage TR and 2D thermal coupling (dim=254, S3)

Batteries & energy storage

Problem definition

Hatchard & Dahn (2001); SAE J2464

Canonical RHS excerpt from the registered callable used for this benchmark cell. Expand it to verify the state equations; it is not a standalone runnable fixture.

Show canonical RHS excerpt
def _bp24_cell_idx(r, c):
    return r * _BP24_NC + c

def _four_stage_decomposition(alpha_sei, alpha_ae, alpha_ca, alpha_el, T):
    k_sei = _arrhenius_rate(_A_SEI, _E_SEI, T)
    k_ae = _arrhenius_rate(_A_AE, _E_AE, T)
    k_ca = _arrhenius_rate(_A_CA, _E_CA, T)
    k_el = _arrhenius_rate(_A_EL, _E_EL, T)

    d_sei = -k_sei * alpha_sei
    d_ae = k_ae * alpha_ae * (1.0 - alpha_ae)
    if alpha_ae < 1e-12 and alpha_sei < 0.15 - 1e-6:
        d_ae = k_ae * 1e-6
    d_ca = k_ca * (1.0 - alpha_ca)
    d_el = k_el * (1.0 - alpha_el)

    q_dot = (_Q_SEI * _W_SEI * abs(d_sei)
             + _Q_AE * _W_AE * d_ae
             + _Q_CA * _W_CA * d_ca
             + _Q_EL * _W_EL * d_el)

    return d_sei, d_ae, d_ca, d_el, q_dot

def _single_cell_4stage(state, T_amb_eff):
    """4-stage dynamics for one cell. Returns (dy[8], q_gen)."""
    alpha_sei = np.clip(state[0], 0.0, 1.0)
    alpha_ae = np.clip(state[1], 0.0, 1.0)
    alpha_ca = np.clip(state[2], 0.0, 1.0)
    alpha_el = np.clip(state[3], 0.0, 1.0)
    T = np.clip(state[4], 250.0, 2000.0)

    d_sei, d_ae, d_ca, d_el, q_dot = _four_stage_decomposition(
        alpha_sei, alpha_ae, alpha_ca, alpha_el, T)

    q_gen = q_dot * _M_CELL
    q_cool = _H_CONV * _A_SURF * (T - T_amb_eff)
    dT = (q_gen - q_cool) / (_M_CELL * _CP)
    dQ = q_gen

    n_gas_max = 0.01
    n_gas = alpha_el * n_gas_max
    dn_gas = n_gas_max * d_el
    dP = (dn_gas * _R_GAS * T + n_gas * _R_GAS * dT) / _V_HEAD

    dR = _R0 * (0.5 * abs(d_sei) + 2.0 * d_ae)

    dy = np.empty(8)
    dy[0] = d_sei
    dy[1] = d_ae
    dy[2] = d_ca
    dy[3] = d_el
    dy[4] = dT
    dy[5] = dQ
    dy[6] = dP
    dy[7] = dR
    return dy, q_gen

def _bp24_rhs(t, y):
    cells = [y[i * _CELL_DIM_4STAGE:(i + 1) * _CELL_DIM_4STAGE]
             for i in range(_BP24_N_CELLS)]
    T = np.array([np.clip(cells[i][4], 250.0, 2000.0)
                  for i in range(_BP24_N_CELLS)])

    flux_offset = _BP24_CELL_BLOCK
    loss_offset = flux_offset + _BP24_N_EDGES
    q_edge = y[flux_offset:loss_offset]
    q_loss = y[loss_offset:]

    dy = np.zeros(_BP24_DIM)

    cell_dy = []
    for i in range(_BP24_N_CELLS):
        cdy, _ = _single_cell_4stage(cells[i], _T_AMB)
        cell_dy.append(cdy)

    # Horizontal edges
    edge_idx = 0
    for r in range(_BP24_NR):
        for c in range(_BP24_NC - 1):
            ci = _bp24_cell_idx(r, c)
            cj = _bp24_cell_idx(r, c + 1)
            q_cond = _K_CONTACT * _A_CONTACT * (T[ci] - T[cj]) / _D_GAP
            q_rad = _SIGMA * _EMISSIVITY * _A_CONTACT * (T[ci]**4 - T[cj]**4)
            q_total = q_cond + q_rad

            cell_dy[ci][4] -= q_total / (_M_CELL * _CP)
            cell_dy[cj][4] += q_total / (_M_CELL * _CP)

            dy[flux_offset + edge_idx] = (q_total - q_edge[edge_idx]) / 0.1
            edge_idx += 1

    # Vertical edges
    for r in range(_BP24_NR - 1):
        for c in range(_BP24_NC):
            ci = _bp24_cell_idx(r, c)
            cj = _bp24_cell_idx(r + 1, c)
            q_cond = _K_CONTACT * _A_CONTACT * (T[ci] - T[cj]) / _D_GAP
            q_rad = _SIGMA * _EMISSIVITY * _A_CONTACT * (T[ci]**4 - T[cj]**4)
            q_total = q_cond + q_rad

            cell_dy[ci][4] -= q_total / (_M_CELL * _CP)
            cell_dy[cj][4] += q_total / (_M_CELL * _CP)

            dy[flux_offset + edge_idx] = (q_total - q_edge[edge_idx]) / 0.1
            edge_idx += 1

    # Pack cell derivatives and loss trackers
    for i in range(_BP24_N_CELLS):
        dy[i * _CELL_DIM_4STAGE:(i + 1) * _CELL_DIM_4STAGE] = cell_dy[i]
        q_loss_actual = _H_CONV * _A_SURF * (T[i] - _T_AMB)
        dy[loss_offset + i] = (q_loss_actual - q_loss[i]) / 1.0

    return dy
Parameters
  • _A_AE = 2.5e+13
  • _A_CA = 6.667e+13
  • _A_CONTACT = 0.0004
  • _A_EL = 5.14e+25
  • _A_SEI = 1.667e+15
  • _A_SURF = 0.000818
  • _BP24_CELL_BLOCK = 192
  • _BP24_DIM = 254
  • _BP24_NC = 4
  • _BP24_NR = 6
  • _BP24_N_CELLS = 24
  • _BP24_N_EDGES = 38
  • _CELL_DIM_4STAGE = 8
  • _CP = 830
  • _D_GAP = 0.001
  • _EMISSIVITY = 0.8
  • _E_AE = 135080
  • _E_CA = 139600
  • _E_EL = 274000
  • _E_SEI = 135080
  • _H_CONV = 10
  • _K_CONTACT = 0.5
  • _M_CELL = 0.044
  • _Q_AE = 1.714e+06
  • _Q_CA = 314000
  • _Q_EL = 155000
  • _Q_SEI = 257000
  • _R0 = 0.02
  • _R_GAS = 8.314
  • _SIGMA = 5.67e-08
  • _T_AMB = 298
  • _V_HEAD = 1e-06
  • _W_AE = 0.5
  • _W_CA = 0.25
  • _W_EL = 0.217
  • _W_SEI = 0.033
Initial condition
y(0) = [0.15, 0, 0, 0, 450, 0, …] [shape=(254,), min=0, max=101325]
Horizon
t ∈ [0, 3600]

Canonical RHS excerpt captured from the same registered callable used for the published benchmark. Frozen closure values are summarized below; helper imports and solver settings are intentionally omitted.

Fingerprint

Spread: extreme

Default noise: high

Recommendation snapshot

Clean best: SolvSRK

Noisy best: SciPy BDF

Coverage

14 solver arms · clean + 5 noise levels

Ranked on survival, precision, and speed

Versions & freeze

Methodology →
Freeze
2026-08-13
libsolvsrk
2.3.0
SciPy
1.14
SUNDIALS
CVODE (bundled backend)

20 seeds/cell default · 14 arms · TRL 4–5 · simulation-lab validated · this page: Battery Pack 24-Cell Module (battery-pack-24-cell-module)

Governed SolvTune benchmark freeze; per-arm medians only. RHS definitions and raw trial rows are not published.

Self-reported by Resonix Labs · not independently verified

Results matrix

Pick an objective and a noise level to rank all arms on survival, median SCD, median nfev, and median wall time. Medians across seeds.

Objective

Best overall trade-off of survival, precision, and speed.

Noise level

#SolverSurvivalSCDnfevWallScore
1SolvSRK
100%
10.728,44212.58 s0.873
2Tsit5external
100%
9.961,83653.72 s0.855
3SciPy LSODASciPy
100%
9.513,84610.49 s0.846
4SciPy RadauSciPy
100%
9.45,0234.04 s0.843
5CVODE Adamsexternal
100%
9.110,5798.10 s0.835
6CVODE BDFexternal
100%
8.42,4901.91 s0.819
7SciPy BDFSciPy
100%
8.22,1071.69 s0.814
SciPy RK45SciPy
0%
SciPy DOP853SciPy
0%
SciPy RK23SciPy
0%

At Clean, best balanced arm is SolvSRK.

Values are medians across seeds, measured by Resonix Labs on Resonix hardware and not independently verified; nfev and wall are on reference lab hardware (indicative). Under injected noise only SolvSRK and the SciPy arms are run. How we measure accuracy → · Verification status →

SolvScout · free

Profile your problem for free

This page shows one published benchmark cell. SolvScout fingerprints your ODE, compares it to the full corpus, and recommends a solver with the same survival / precision / speed ranking you see here — including when a SciPy arm wins.

SolvSRK · 30-day trial

Run the winner on your machine

SolvSRK is the stiffness-adaptive integrator behind the SolvSRK column in these tables. Create an account, activate a machine, and take a 30-day trial — same binary you'd ship after purchase.

Cite this page

Replace the access date. Pin the freeze ID and library versions when comparing against a later export. Cite it as what it is — a self-reported vendor benchmark, not an independently verified result. The note field says so; please keep it.

@misc{resonix_evidence_battery_pack_24_cell_module_2026,
  title        = {Resonix Evidence Portal: Battery Pack 24-Cell Module},
  author       = {{Resonix Labs (Canada) Inc.}},
  year         = {2026},
  howpublished = {\url{https://resonix.tech/evidence/problems/battery-pack-24-cell-module}},
  note         = {Self-reported vendor benchmark; internally generated by Resonix Labs and not independently verified. Accessed YYYY-MM-DD. Freeze 2026-08-13; libsolvsrk 2.3.0; SciPy 1.14.}
}

Related

TRL 4–5 · simulation-lab validated · 398 problems · 14 solver arms · clean + 5 noise levels

Freeze: 2026-08-13 · scipy 1.14 · libsolvsrk 2.3.0 · Methodology

Self-reported by Resonix Labs · not independently verified · Verification status