Skip to main content

aec-modelling: four-parameter thermo-electrochemical model of alkaline electrolysers

tests PyPI Python DOI

A lightweight Python package for alkaline water electrolysis (AWE / AEC). It provides:

  • an electrochemical model that describes the polarisation curve with only four fitted parameters;
  • fitting tools to calibrate those parameters on your own measurements, from as few as ~20 points;
  • thermal models of the stack: a 0D transient energy balance and a 1D along-the-channel model;
  • literature datasets ready to fit (Ulleberg, Sakas, Sánchez, de Groot) and field data from UNIVPM.

It is intended for system-level studies such as power-to-hydrogen plants, temperature control, lye-cooling sizing and techno-economic analysis. In these studies you need a model that is fast, robust and extrapolates sensibly in temperature.

The package was developed during a visiting PhD period (2022) at DTU Energy under the supervision of Henrik Lund Frandsen.

UNIVPM DTU


Contents


Installation

pip install aec-modelling            # core: numpy, scipy, pandas
pip install "aec-modelling[plot]"    # + matplotlib plotting helpers

From source, for development:

git clone https://github.com/Lingkangjin/AEC-Modelling.git
cd AEC-Modelling
uv sync --extra dev          # or: python -m pip install -e ".[dev]"

Python ≥ 3.9 is required.

Quick start

import numpy as np
from aec_modelling import AECModel, datasets, fit_polarization

# 1. Fit the four parameters on a literature dataset (or your own DataFrame)
df = datasets.load("sakas")          # columns: j [mA/cm2], T [K], V [V], P [bar], w [-]
fit = fit_polarization(df)
print(fit.summary())

# 2. Use the calibrated model
cell = fit.model
cell.voltage(300, 353.15)                    # V at 300 mA/cm2, 80 °C
cell.overpotentials(np.linspace(10, 500, 50), 353.15)   # DataFrame: V_rev, V_act, V_ohm, V_cell, V_tn
cell.current_density(1.9, 353.15)            # inverse: j at 1.9 V
cell.voltage_efficiency(300, 353.15)         # V_tn / V_cell
Four-parameter AEC model fit
--------------------------------------------
 delta_l =      0.59344 +/- 0.0364     [cm]
   alpha =      0.13121 +/- 0.00803    [-]
      C1 =      -6646.3 +/- 397        [K]
      C2 =       20.816 +/- 1          [-]
--------------------------------------------
points = 40   R2 = 0.9982   RMSE = 3.6 mV
activation energy Ea = 55.3 kJ/mol

The model in one minute

V_cell = V_rev + V_act + V_ohm

V_rev = U0(T) + RT/(2F) · ln[ (P − p_v)^1.5 / a_w ]     reversible
V_act = RT/(2·alpha·F) · ( ln j − C1/T − C2 )            activation (Tafel)
V_ohm = delta_l · j / sigma(T, w)                        ohmic
Parameter Unit Physical meaning
delta_l cm effective ionic path length (gap + separator + bubbles)
alpha – lumped charge-transfer coefficient, which sets the Tafel slope
C1 K Arrhenius slope of the exchange current density (activation energy Ea = −C1·R)
C2 – Arrhenius intercept of ln i0

The reversible voltage, electrolyte conductivity, vapour pressure and water activity come from literature correlations that depend on temperature, pressure and KOH concentration. Only the four parameters above are fitted. The full equations are in docs/model.md.

Polarisation curves and voltage breakdown

Fitting your own data

Put your measurements in a DataFrame with one row per point:

column unit
j mA/cm² current density (> 0)
T K cell / stack temperature
V V per-cell voltage
P bar abs. optional column, or pass P=...
w – KOH mass fraction, optional column, or pass w=...
import pandas as pd
from aec_modelling import fit_polarization, sample_points

df = pd.read_csv("my_test_bench.csv")          # j, T, V
fit = fit_polarization(df, P=10.0, w=0.30)

# Calibrate on 20 random points spanning 2+ temperatures and validate on the rest
calib = sample_points(df, n=20, min_temperatures=2, random_state=0)
fit = fit_polarization(calib, P=10.0, w=0.30)
print(fit.evaluate(df, by="T"))                # R2 / RMSE / MAPE per temperature

# Custom initial guess and bounds: (delta_l, alpha, C1, C2)
fit = fit_polarization(df, P=10, w=0.3, p0=(0.4, 0.13, -6330, 14),
                       bounds=((0, 0.05, -1e4, -5), (2, 1, 0, 30)))

Tips

  • Use data at two or more temperatures. With a single temperature, C1 and C2 cannot be separated.
  • For stack data, divide the stack voltage by the number of cells.
  • activation="asinh" avoids negative activation overpotential when the data include very low current densities.

Calibration on 20 points, validation on all

Thermal modelling

A cell releases heat when its voltage is above the thermoneutral voltage V_tn ≈ 1.48 V: Q_gen = N_cells · (V_cell − V_tn) · I. The package couples this heat source to two stack energy-balance models.

from aec_modelling import Stack, LumpedThermalModel, AxialThermalModel

stack = Stack(fit.model, n_cells=100, cell_area=2.6e4)     # area in cm2
I = stack.current(300)                                      # A at 300 mA/cm2

# 0D: well-mixed stack with lye cooling and heat losses
th = LumpedThermalModel(stack, heat_capacity=2e7, thermal_resistance=0.01)
m_lye = th.required_lye_flow(I, T_out=353.15, T_in=343.15)   # kg/s
T_ss  = th.steady_state(I, T_in=343.15, m_lye=m_lye)
t     = np.linspace(0, 4 * 3600, 400)                       # s
sim   = th.simulate(t, I=lambda t: I if t < 7200 else I/2, T_in=343.15, m_lye=m_lye, T0=313.15)

# 1D: temperature rise along the cell and the resulting current maldistribution
res = AxialThermalModel(stack, n_segments=50).solve(I, T_in=343.15, m_lye=8.0)
res.V_cell, res.T_out, res.current_maldistribution, res.profile    # profile: z, T, j, q
0D: warm-up and load step 1D: profiles vs. lye flow

Bundled datasets

from aec_modelling import datasets
datasets.list_datasets()        # overview table
df = datasets.load("ulleberg")  # tidy DataFrame; metadata in df.attrs (reference, doi, notes)
name source T range P KOH points R² (all points)
ulleberg Ulleberg 2003, PHOEBUS 26 kW 30–80 °C 7 bar 30 wt% 86 0.997
sakas Sakas et al. 2022, industrial 3 MW 59–70 °C 16 bar 25 wt% 40 0.998
sanchez Sánchez et al. 2018, 15 kW stack 55–75 °C 7 bar 35 wt% 24 0.998
degroot_pressure de Groot et al. 2022 50 °C 10/30 bar 30 wt% 13 0.999
degroot_temperature de Groot et al. 2022 50–70 °C 30 bar 30 wt% 24 0.998
univpm UNIVPM field data (2023), 1-min log 32–56 °C 1–5.5 bar not logged 184 n/a (raw)

Note: pressure and KOH fraction that are not part of the raw files are the values used in the original analysis scripts. Check them against the source paper before using the fitted parameters quantitatively. The univpm set is raw field data that includes transients. It is provided for exploration, and fitting it requires w=....

Fits on all literature datasets

Examples

Script What it shows
examples/01_quickstart.py polarisation curves at several temperatures, voltage breakdown, inverse model
examples/02_fit_sakas.py calibration on 20 random points and validation on the full dataset (the original Main.py workflow)
examples/03_fit_all_datasets.py fits every literature dataset and compares parameters and activation energies
examples/04_lumped_thermal.py 0D stack: lye-flow sizing, cold start, load step, heat balance
examples/05_axial_thermal.py 1D cell: temperature and current profiles for different lye flows, 1D vs 0D
python examples/02_fit_sakas.py     # figures are saved to examples/figures/

Repository structure

AEC-Modelling/
├── src/aec_modelling/        # the installable package
│   ├── electrochemistry.py   # AECModel, reversible voltage, cell_voltage()
│   ├── fitting.py            # fit_polarization, FitResult, sample_points, metrics
│   ├── thermal.py            # Stack, LumpedThermalModel (0D), AxialThermalModel (1D)
│   ├── electrolyte.py        # KOH density, molarity, conductivity, vapour pressure, ...
│   ├── thermo.py             # Shomate data, ΔH/ΔS/ΔG, thermoneutral voltage
│   ├── datasets.py           # dataset registry and loaders
│   ├── plotting.py           # optional matplotlib helpers
│   └── data/*.csv            # tidy datasets shipped with the package
├── examples/                 # runnable scripts
├── tests/                    # pytest suite
├── data/raw/                 # original raw data files
├── data/legacy_fitting_parameters/  # Kibria/Miles fits of the earlier detailed model
├── scripts/prepare_datasets.py      # raw -> tidy dataset conversion
└── docs/                     # model description and figures

Development

uv sync --extra dev
uv run pytest                 # tests
uv run ruff check .           # lint
uv run ruff format .          # format
uv build                      # sdist + wheel in dist/

Adding a dataset: put the raw file in data/raw/, add a DatasetInfo entry in src/aec_modelling/datasets.py and a builder function in scripts/prepare_datasets.py, then run python scripts/prepare_datasets.py.

Releasing to PyPI: bump __version__ in src/aec_modelling/__init__.py, update CHANGELOG.md, and create a GitHub release. The publish workflow then uploads the release through PyPI trusted publishing. Configure the trusted publisher on pypi.org once before the first release.

Contributions are welcome through issues and pull requests.

Citation

If you use this package, please cite:

[1] Lingkang Jin, Rafael Nogueira Nakashima, Gabriele Comodi, Henrik Lund Frandsen. Alkaline electrolysis for green hydrogen production: A novel, simple model for thermo-electrochemical coupled system analysis. Applied Thermal Engineering 262 (2025) 125154. https://doi.org/10.1016/j.applthermaleng.2024.125154

[2] Lingkang Jin, Rafael Nogueira Nakashima, Henrik Lund Frandsen, Gabriele Comodi. Alkaline Electrolysis for Green Hydrogen Production: Techno-Economic Analysis of Temperature Influence and Control. ECOS 2023, 908–919. https://doi.org/10.52202/069564-0082

@article{JIN2025125154,
  title   = {Alkaline electrolysis for green hydrogen production: A novel, simple model for thermo-electrochemical coupled system analysis},
  journal = {Applied Thermal Engineering},
  volume  = {262},
  pages   = {125154},
  year    = {2025},
  issn    = {1359-4311},
  doi     = {10.1016/j.applthermaleng.2024.125154},
  author  = {Lingkang Jin and Rafael {Nogueira Nakashima} and Gabriele Comodi and Henrik Lund Frandsen}
}

@inproceedings{Jin2023AlkalineControl,
  title     = {{Alkaline Electrolysis for Green Hydrogen Production: Techno-Economic Analysis of Temperature Influence and Control}},
  booktitle = {36th International Conference on Efficiency, Cost, Optimization, Simulation and Environmental Impact of Energy Systems (ECOS 2023)},
  author    = {Jin, Lingkang and Nogueira Nakashima, Rafael and Lund Frandsen, Henrik and Comodi, Gabriele},
  year      = {2023},
  pages     = {908--919},
  address   = {Las Palmas de Gran Canaria, Spain},
  isbn      = {978-1-7138-7492-8},
  doi       = {10.52202/069564-0082}
}

GitHub also reads CITATION.cff and shows a "Cite this repository" button.

License

Released under the MIT License.

Code contributors

References

Datasets

  1. Ulleberg Ø. Modeling of advanced alkaline electrolyzers: a system simulation approach. Int J Hydrogen Energy 2003;28:21–33. https://doi.org/10.1016/S0360-3199(02)00033-2
  2. Sakas G, Ibáñez-Rioja A, Ruuskanen V, Kosonen A, Ahola J, Bergmann O. Dynamic energy and mass balance model for an industrial alkaline water electrolyzer plant process. Int J Hydrogen Energy 2022;47:4328–45. https://doi.org/10.1016/J.IJHYDENE.2021.11.126
  3. Sánchez M, Amores E, Rodríguez L, Clemente-Jul C. Semi-empirical model and experimental validation for the performance evaluation of a 15 kW alkaline water electrolyzer. Int J Hydrogen Energy 2018;43:20332–45. https://doi.org/10.1016/j.ijhydene.2018.09.029
  4. de Groot MT, Kraakman J, Garcia Barros RL. Optimal operating parameters for advanced alkaline water electrolysis. Int J Hydrogen Energy 2022. https://doi.org/10.1016/j.ijhydene.2022.08.075

Reversible voltage

  • Domain E, Conductivity SE. A Comprehensive Survey of Alkaline Electrolyzer Modeling: Electrical Domain and Specific Electrolyte Conductivity 2022.
  • Kibria MF, Mridha MS. Electrochemical studies of the nickel electrode for the oxygen evolution reaction. 1996;21.

Electrode kinetics

  • Miles MH, Kissel G, Lu PWT, Srinivasan S. Effect of temperature on electrode kinetic parameters for hydrogen and oxygen evolution reactions on nickel electrodes in alkaline solutions. J Electrochem Soc 1976;123:332–6. https://doi.org/10.1149/1.2132820
  • Kibria MF, Mridha MS, Khan AH. Electrochemical studies of a nickel electrode for the hydrogen evolution reaction. Int J Hydrogen Energy 1995;20:435–40. https://doi.org/10.1016/0360-3199(94)00073-9
  • Huot J-Y. Hydrogen evolution and interface phenomena on a nickel cathode in 30 w/o KOH. J Electrochem Soc 1989;136:1933–9. https://doi.org/10.1149/1.2097088

Electrolyte conductivity, density and concentration

  • Gilliam RJ, Graydon JW, Kirk DW, Thorpe SJ. A review of specific conductivities of potassium hydroxide solutions for various concentrations and temperatures. Int J Hydrogen Energy 2007;32:359–64. https://doi.org/10.1016/j.ijhydene.2006.10.062

Separator, gas solubility and diffusion

Bubbles

Metadata

Release files for aec-modelling 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aec-modelling 0.1.0
File Size Uploaded Provenance
aec_modelling-0.1.0.tar.gz 33.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for aec-modelling 0.1.0
File Interpreter ABI Platform
aec_modelling-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 64.5 kB

Release files / aec_modelling-0.1.0.tar.gz

Download URL aec_modelling-0.1.0.tar.gz
Size 33.2 kB
Tags Source
SHA-256 checksum
How to use checksums
65a7ca864c2f90cc23d4401399b08207d62dd324f841b91e5245fc204dfc8e7e
BLAKE2b-256 checksum
How to use checksums
b9d5b72188a2ef3e8e274be43c0962a9d66979c2db1cebb4f6931ae5648f913a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / aec_modelling-0.1.0-py3-none-any.whl

Download URL aec_modelling-0.1.0-py3-none-any.whl
Size 31.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
119c0be15c5da6ec0c7272783c16516ebc49448076e45219589679d119440c6e
BLAKE2b-256 checksum
How to use checksums
04ce956464fbc802816df2e2078e06aafcbd5a01fa95812acc24a12d9ed95601
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Security for aec-modelling 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for aec_modelling-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page