Skip to content

Full cell v2: flow, tanks, Shah's 2D cell, and a layered sumfem.electrochemistry - #28

Open
jorgensd wants to merge 7 commits into
mainfrom
dokken/full-cell-v2
Open

jorgensd wants to merge 7 commits into
mainfrom
dokken/full-cell-v2

Conversation

@jorgensd

@jorgensd jorgensd commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Builds on the first full cell. The cell now runs with flow through the electrodes and tanks, through a pluggable flow component. A new demo runs the full 2D cell of Shah et al. (2008), corrected. sumfem.electrochemistry is reorganised into three layers, and every material property can be coupled to another model.

Flow and tanks

  • FlowSpec adds the flow of the electrolytes to a FullCell: the inlet velocity, the outlet pressure, and a tank ratio, the tank volume over the electrode's pore volume.
    • At the inlet, each ion's flux is $v_\mathrm{in} c_k^\mathrm{in}$ rather than a fixed concentration. Shah et al. hold the concentration instead; with the flux, the cell and its tanks together conserve every ion exactly.
    • The equations are labelled full-cell-flow.
  • FullCell.update_tanks(disc, dt) takes a step of Shah's eq. 33 after each time step, using the fluxes of that step (full-cell-tank).
  • New FullCell methods: amount (an ion's amount in an electrode and its tank) and state_of_charge (tank included).

Pluggable flow through the electrodes (models/electrode_flow.py)

  • ElectrodeFlow is an abstract component, created by the cell from a FlowSetup. It provides:
    • velocity(side);
    • models, which may include time derivatives;
    • a pressure on the electrodes and the membrane, which the membrane's SchloeglFlow shares;
    • conditions() and initialize().
  • DarcyFlow is the default, with the Kozeny–Carman permeability of each electrode.
  • FlowSpec.model takes any ElectrodeFlow, so Brinkman–Forchheimer, transient Stokes or transient Darcy flow can plug in. The docstring shows a transient Darcy flow as a subclass of a few lines.

Shah et al.'s cell in 2D (examples/electrochemistry/vanadium_full_cell_2d.py)

  • The model:
    • built on a symbolic domain, from Shah's Tables 2–5: two half-cells, the membrane, collectors, Darcy flow, and tanks;
    • then discretized on a layered mesh with the cell's markers.
  • The run: charge for 2017 s at 10 A, rest, then discharge until the voltage falls to 1 V.
  • Checks:
    • the cell and its tanks conserve vanadium on each side;
    • V²⁺ made equals the charge passed over F;
    • the state of charge holds still at rest;
    • sulfate stays positive.
  • Corrections to Shah et al., listed in a subsection and checked against the paper's text and figures:
    • The model: at the membrane faces, sulfate is blocked rather than the protons being held at $c_f$.
    • The paper's errors:
      • Table 1's proton source is in the wrong column;
      • eq. 22 uses $\log_{10}$ and $c_\mathrm{IV}/c_\mathrm{IV}$, and sends readers to the wrong table;
      • eq. 23 pairs each rate constant with the other couple's potential;
      • Table 2's water is ten times too low;
      • Table 3 gives the half-cell volume in metres;
      • Table 5 lacks the electrolyte diffusivities of H⁺, HSO₄⁻ and SO₄²⁻, so these come from Knehr et al. (2012).
    • Choices the paper leaves open: continuity at the faces, and a superficial inlet velocity.

sumfem.electrochemistry in three layers

  • materials/: Electrolyte, Ion, RedoxCouple, PorousElectrode, Region.
  • models/: transport, conduction, kinetics, membranes, and the electrode flow.
  • cells/: RedoxHalfCell, FullCell, and the specs (HalfCellSpec, MembraneSpec, FlowSpec).

Each layer imports only from those before it. Every name is still imported from sumfem.electrochemistry, and the API page follows the layers.

Inputs can come from other models

  • What can be an expression: every property of PorousElectrode, every field of HalfCellSpec from the porosity on, the couple's rate constant, formal potential and transfer coefficients, and the electrolyte's temperature, density and viscosity. Each is either a UFL expression, such as a field of another PDE, used as given, or the default of a parameter.
  • How: this goes through sumfem.symbolic.expression_or_parameter.
  • Initialization: RedoxHalfCell.equilibrium_potential and initialize average expressions over the electrode.

Core additions and moves

  • sumfem.symbolic: expression_or_parameter, with the type aliases ExpressionOrValue and ExpressionOrDefault.
  • sumfem.symbolic.si: the units CONCENTRATION, DENSITY, DIFFUSIVITY, PERMEABILITY and VISCOSITY. They replace copies in models/flow.py and the electrochemistry modules.
  • Domain.interfaces_of(measure): used by RateReaction and MembraneProtonFlux, which checks that the membrane is on the "−" side of its face.
  • RedoxHalfCell: gains reservoir_concentration and equilibrium_potential.

Tests

  • 2D cell with flow at rest: it stays at rest, and the pressure drop is exactly $\mu v H/K$.
  • 2D discharge with tanks: cell plus tanks conserve vanadium and bisulfate, and turn over $Q/F$ of each couple, to round-off.
    • Protons balance to within 2%. In 2D, the membrane's current at a face differs from the electrode's reaction current by a first-order discretization error: 1.05%, 0.48% and 0.21% with P1, or 0.074%, 0.030% and 0.017% with P2, under refinement.
  • A transient flow plugged in: a Darcy flow with storage of the pressure, whose velocity isn't divergence-free while the pressure develops, still conserves exactly.
  • Inputs from other models: a temperature field and a compression field set the electrodes' properties and the couples' kinetics, the units are consistent, and a cell at rest stays at the Nernst voltage of that temperature.
  • Core helpers: expression_or_parameter and Domain.interfaces_of.

Not in this PR

  • The membrane's face current is only first-order accurate in 2D. The next step makes it exact: separate electrode and membrane potentials joined by an InterfaceLagrangeMultiplier, which is also where the Donnan jump enters.
  • The proton term in the positive Nernst potential.
  • Knehr et al.'s crossing membrane.
  • Brinkman–Forchheimer and Stokes flows: the interface supports them, but they aren't implemented.

🤖 Generated with Claude Code

@jorgensd
jorgensd added this pull request to stack #25 November 12, 2026 12:39
@jorgensd jorgensd changed the title Full cell model Full cell v2: flow, tanks, Shah's 2D cell, and a layered sumfem.electrochemistry Nov 12, 2026
@jorgensd
jorgensd force-pushed the dokken/full-cell-v2 branch from ee16501 to 5e1a5be Compare November 12, 2026 12:45
Base automatically changed from dokken/full-cell-version1 to main November 12, 2026 13:18
@jorgensd
jorgensd force-pushed the dokken/full-cell-v2 branch from 5e1a5be to 96c06df Compare November 12, 2026 13:18

This branch has not been deployed

No deployments
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