Skip to content

Releases: tum-ees/PyDMA

v2.1.0

Choose a tag to compare

@mathiasrehm mathiasrehm released this 02 Sep 11:40

Changed

  • Python 3.10 and 3.11 are supported again; requires-python drops from 3.12
    to 3.10. The entire 3.12 requirement came down to the two PEP 695 type
    aliases in pydma.utils.roi, which now use typing.TypeAlias and parse on
    every supported interpreter. Runtime behavior is unchanged.
  • The pinned-minimum CI leg runs on Python 3.10 and black targets 3.10. mypy
    keeps the 3.12 grammar, because current numpy stubs use PEP 695 syntax that
    mypy refuses to parse under an older target; the floor itself is enforced by
    the 3.10 CI leg. On 3.10 the resolver serves at most numpy 2.2 /
    scipy 1.15, since newer releases of both dropped 3.10 wheels.

v2.0.0

Choose a tag to compare

@mathiasrehm mathiasrehm released this 01 Sep 19:11

Major release with breaking changes: removed exports, keyword-only
fit_* signatures, and hard errors where earlier versions silently
degraded. popsize now means what it says, and the full-cell
reconstruction gained an optional fitted series resistance (default
off).

Added

  • Fitted series-resistance correction for the full-cell reconstruction (default
    off): DMAConfig.allow_resistance_offset with pocv_current_a,
    resistance_offset_limit_ohm_ah, and allow_negative_resistance_offset.
    Parameter slot 9 (r_offset_ohm, in Ohm) lifts the model OCV by
    sign(direction) * R * |I|. DVA and ICA never read the slot; a constant would
    drop out of their derivatives anyway. With the flag off the slot is pinned to
    zero, and every stored 8-parameter vector expands to the same reconstruction as
    before.

  • apply_aging in pydma.utils.balancing: derives an aged electrode balancing at
    fixed c_max by scaling eps_s with 1 - LAM. The former docstring recipe
    cancelled LAM out of Q_n and is documented as such.

  • FittedParams.from_dict, DMAResult.config_snapshot for fit provenance, and
    the accepted-run parameter scatter (param_std) on DMAResult.

  • csv_kwargs passthrough in the loaders (for example {"sep": ";", "decimal": ","}), cathode_convention in the OCP-model window functions, x_is_soc in
    the comparison plots, include_geometry in pybamm_overrides.

  • Loud validation: blend electrodes must match use_anode_blend/use_cathode_blend,
    OCP curves must be finite, ROI bounds must be SOC fractions, DMAConfig rejects
    unknown attributes and re-validates on assignment, CellGeometry rejects
    non-positive fields.

  • An expanded regression suite: hand-derived LAM/LLI expectations, direct PAV
    pooling checks, plot smoke tests with an rcParams invariance check, aging-study
    gap discovery, and a resistance-offset acceptance suite.

Changed

  • popsize now sets the actual differential-evolution population size regardless
    of pinned parameter slots; the effective population no longer shrinks as
    features are disabled.

  • lfp_preset selects the intended split OCV ROI (0-15 % and 85-100 % SOC)
    instead of the full range.

  • load_aging_study discovers every present check-up by listing the directory and
    warns about missing indices instead of stopping at the first gap.

  • Objective failures raise or warn once instead of silently returning the penalty
    value for every exception; an empty ROI is a configuration error and raises.

  • Plot functions no longer mutate global plt.rcParams; styles are scoped per
    call.

  • Electrode and blend interpolation clamps at the support edges instead of
    returning 0.0 outside the support.

  • derive_balancing_from_result defaults to on_out_of_range="raise" and reports
    clipping explicitly.

  • fit_ocv/fit_dva/fit_ica/combined_objective take ROI and flag arguments
    keyword-only; the inert inhom_points parameter is gone. The three fit terms
    share precomputed electrode potentials with bit-identical results.

Fixed

  • Type checking passes across matplotlib releases. matplotlib 3.11 types the
    rc_context mapping by the literal set of rcParams names it ships with, which
    a plain string-keyed dict does not satisfy, so the plotting module applies its
    style through a single wrapper. Plot output is unchanged.

  • voltage_anchored_windows inverts only the strictly monotonic part of the
    reconstruction, keeping interpolation fill artefacts out of the anchored
    windows.

  • DVA/ICA edge guards (zero denominators, fewer than two points, NaN inputs),
    .mat NaN filtering, direction-symmetric pOCV file matching, and
    calculate_mse returning inf for an empty mask.

Removed

  • Dead API: calculate_full_cell_ocv, create_optimizer_from_config,
    run_single_fast, SiliconCurveParams, calculate_inhomogeneity_for_electrode,
    DMAConfig.get_bounds, DMAConfig.calculate_roi_bounds, and the
    never-populated is_cyclic/fit_reverse fields, get_potential_at_scaled_soc.

v1.1.2: fix silent voltage-support loss in the plateau collapse

Choose a tag to compare

@mathiasrehm mathiasrehm released this 04 Aug 14:07

Patch release.

Fixed

  • _collapse_plateaus no longer loses voltage support silently. Shifts are
    bounded by the neighbouring level gap, boundary plateaus shift inward only,
    the range clamp is gone, and a fully pooled curve keeps both exact range
    edges.
  • The function states its contract explicitly. ValueError for non-finite
    input, constant curves and overflowing ranges. RuntimeError if the output is
    non-finite, not strictly monotone or does not preserve both range endpoints
    exactly.

Changed

  • Default outputs, the raw-PAV PCHIP path and the committed M35A tables are
    unchanged and verified bit-identical. Only opt-in collapse_plateaus=True
    calls change, intentionally.
  • Ruff pinned to the 0.15 release line for the lint gate.

Details in the CHANGELOG.

v1.1.1 — citation metadata, reproducible release gates, loader fix

Choose a tag to compare

@mathiasrehm mathiasrehm released this 13 Jul 21:35

Maintenance release focused on software citation, reproducible release tooling,
and cross-platform reliability. No scientific algorithms or public APIs changed.

Highlights

  • Software citation metadata. Added CITATION.cff with the three PyDMA
    creators and the Journal of Power Sources framework paper as the preferred
    citation, ready for Zenodo ingestion.
  • Reproducible release gates. Added GitLab CI and public GitHub Actions
    checks covering Python 3.12 minimum dependencies and Python 3.14 current
    dependencies, formatting, linting, typing, tests, scientific regressions,
    and package builds.
  • Repository cleanup. Applied the pinned Black and isort formatting,
    aligned development dependencies and pre-commit hooks, and removed
    workstation-specific notebook output.
  • Current typing compatibility. Updated NumPy and Matplotlib typing without
    changing runtime behavior.
  • Cross-platform loader fix. Fixed charge/discharge CSV selection in
    aging-study directories so it no longer depends on filesystem iteration
    order.

Verification

  • 37 normal tests passed
  • 2 scientific regression tests passed
  • Python 3.12 and 3.14 CI passed
  • Wheel and source distribution passed twine check
  • Clean PyPI installation and loader smoke test passed

Install

pip install --upgrade pydma==1.1.1

v1.1.0 — Python 3.12 floor, PyBaMM-safe Si OCP, seeded golden tests

Choose a tag to compare

@mathiasrehm mathiasrehm released this 26 May 08:28

v1.1.0 — Python 3.12 floor, PyBaMM-safe Si OCP, seeded golden tests

Major release. Drops Python 3.9-3.11, modernizes typing, adds a PyBaMM-stable silicon OCP filter, and locks scientific behavior with a seeded regression suite.

Highlights

  • PyBaMM-safe silicon OCP filter. New pydma.silicon.strict_sto.pchip_resample_for_pybamm produces a smooth strictly-monotone Si OCP on a uniform sto grid with an optional endpoint-V snap. More stable for PyBaMM's CasADi/IDAS interpolant. Replaces the previous strict_sto_eps_spread helper.
  • LOWESS-on-PCHIP gotcha documented. When re-fitting a PCHIP-output curve through PyDMA itself, set DMAConfig(smoothing_points=1) — the default 30 over-smooths the already-smoothed input and the optimizer basin-escapes (measured on Molicel M35A in discharge direction: RMSE 3.3 → 21 mV, γ_Si 0.293 → 0.18; M35A dataset not included).
  • Python ≥ 3.12 required. Drops 3.9–3.11 and the from __future__ import annotations shims. Runtime floors bumped to the lowest 3.12-wheel releases: numpy>=1.26, scipy>=1.11.4, pandas>=2.1.1, matplotlib>=3.8, statsmodels>=0.14.
  • Deterministic optimizer + scientific regression suite. DMAConfig.random_seed is now a real settable field (default None preserves prior nondeterministic behavior). New opt-in pytest -m scientific suite locks down a seeded P45B/NCA fit against golden RMSE / parameter / degradation-mode numbers, and skips cleanly from an unpacked sdist when its data files aren't present.
  • Maintainer ops. Added RELEASING.md checklist; both tutorial notebooks (getting_started.ipynb, pybamm_integration.ipynb) are now release artifacts. Internal: typing modernized to PEP 585/604/695 and mypy src/pydma is clean.

Install

pip install --upgrade pydma==1.1.0

PyPI: https://pypi.org/project/pydma/1.1.0/ · Full notes: CHANGELOG.md

v1.0.2 — PyDMA → PyBaMM balancing bridge

Choose a tag to compare

@mathiasrehm mathiasrehm released this 12 May 14:27

A PyDMA fit now plugs directly into a PyBaMM ParameterValues.

Highlights

  • PyDMA → PyBaMM bridge. The new pydma.utils.balancing module derives c_max and c_init(SoC) directly from a voltage-anchored PyDMA fit plus the user-supplied cell geometry. ElectrodeBalancing.pybamm_overrides(soc) returns a dict keyed by PyBaMM's exact parameter names, ready for pybamm.ParameterValues.update(...).
  • New notebook notebooks/pybamm_integration.ipynb: end-to-end bridge for the Molicel INR21700-P45B, verified by a C/500 DFN charge round-trip. All material/geometry values come from Frank et al. (2025), Table III (DOI 10.1149/1945-7111/adc03c). Chen2020 is used only as a public Li-ion fallback base for parameters Frank et al. do not document.
  • New data file notebooks/parameter_data/frank2025_p45b_table_iii.json: 24 Frank et al. Table III constants as {value, unit, source}.
  • notebooks/getting_started.ipynb is now purely a DMA-analysis tutorial.

Install

pip install --upgrade pydma==1.0.2

PyPI: https://pypi.org/project/pydma/1.0.2/ · Full notes: CHANGELOG.md

v1.0.1 — corrected voltage-anchored stoichiometry export

Choose a tag to compare

@mathiasrehm mathiasrehm released this 29 Apr 11:11

Highlights

  • Stoichiometry windows now match the requested voltage cutoffs. Anode and cathode stoichiometry windows are anchored to the fitted reconstructed cell voltage at the requested voltage limits, via DMAResult.voltage_anchored_windows(...). The previous output used raw internal fit-window endpoints, which in most cases did not correspond to the measured pseudo-OCV voltage cutoffs — exported values were systematically off for downstream consumers. For inhomogeneous fits, the anchored values are the central/nominal stoichiometries of the fitted trajectory.
  • Composite anode phase mapping. BlendElectrode.get_component_stoichiometries(...) and BlendElectrode.get_component_stoichiometry_window(...) map a fitted blend coordinate to per-phase graphite/silicon stoichiometries, so anchored blend coordinates are also exported as Gr/Si stoichiometry windows.
  • Per-phase inspection helper. FittedParams.sto_window_an_per_phase(...) exposes raw per-phase windows when needed.
  • Strictly monotone silicon OCP. generate_si_curve(monotone_filter=True) now returns strictly monotone output, making the filtered curve safe for downstream spline interpolation (e.g. PyBaMM preprocessing) without changing fitting results.
  • Updated getting_started.ipynb to demonstrate fitted-reconstruction voltage anchoring and anchored Gr/Si phase windows.

See the full CHANGELOG.md for details.

v1.0.0

Choose a tag to compare

@mathiasrehm mathiasrehm released this 13 Apr 10:42

Highlights

  • New: inhomogeneity offset (inhom_anode_offset, inhom_cathode_offset) — MATLAB inhomOffsetFraction parity.
  • Numerical: q0 restored to MATLAB parity (span of the normalized SOC axis). Fits with weight_dva > 0 and/or weight_ica > 0 may differ slightly from PyDMA ≤ 0.1.0. OCV-only fits are unaffected.

Install: pip install pydma==1.0.0


Added

  • Inhomogeneity offset for anode and cathode (DMAConfig.inhom_anode_offset,
    DMAConfig.inhom_cathode_offset, default 0.0, validated [0, 1]). A
    positive offset allows a fraction of the maximum inhomogeneity spread to
    be present already at SOC = 0 instead of starting from zero. Setting the
    offset to 1.0 reproduces SOC-independent inhomogeneity, which is
    analogous to earlier degradation mode analysis frameworks in literature.
    Matches MATLAB's new inhomOffsetFraction argument
    (calculate_inhomogeneity.m).
  • DMAAnalyzer.analyze_aging_study(path, ...) convenience API that accepts
    a directory or single .mat file, loads it using the configured
    direction, and runs every CU.
  • Top-level load_aging_study export and support for single-file multi-CU
    .mat payloads in the loader.
  • Isotonic-regression-based silicon OCP filtering in generate_si_curve,
    producing strictly monotonic curves while keeping the maximum amount of
    information.
  • Regression tests pinning MATLAB-parity invariants (q0, fitted-bounds,
    degradation-mode delegation, inhomogeneity offset formula, loader CU
    handling, reset-state completeness, FittedParams None handling).

Changed

  • Numerical: q0 now matches MATLAB (span of the normalized SOC axis,
    ≈ 1.0) instead of the raw Ah span. Because the DVA and ICA cost
    contributions scale as q0², this may produce small numerical
    differences compared with older PyDMA versions when weight_dva and/or
    weight_ica are non-zero
    . In return, fits are now cell-size independent
    and consistent with the MATLAB-tuned weight_dva / weight_ica defaults.
    OCV-only fits (weight_dva = 0, weight_ica = 0) are unaffected.
  • Breaking: compare_with_reference now delegates to
    calculate_degradation_modes, so blend LAMs
    (lam_anode_blend1/2, lam_cathode_blend1/2) are populated rather
    than silently zero. Constructor keyword arguments for DegradationModes
    renamed lam_an / lam_calam_anode / lam_cathode (the short
    names remain available as read-only property aliases).
  • DMAConfig.algorithm is now actually consumed by the optimizer, and
    DMAConfig.get_initial_guess() now includes blend-weight initial values.
  • Aging-study runs now populate real fit_ocv_mse / fit_dva_mse /
    fit_ica_mse and the is_accepted / status / algorithm metadata
    on every DMAResult instead of placeholder values.
  • Aging-study loader honors the configured direction when choosing
    per-CU folders.

Fixed

  • Inhomogeneity out-of-range clamping now uses
    np.interp(..., left=voltage[0], right=voltage[-1]), matching MATLAB
    griddedInterpolant(..., 'linear', 'nearest'). The previous code
    clamped both OOB sides to voltage[-1], a latent mismatch that affected
    fits even when inhom_offset = 0.
  • compare_with_reference now falls back to
    self.reference_data.reference_capacity, and its capacity-loss guard
    protects against division by zero (reference_capacity == 0).
  • FittedParams type annotations and to_array() correctly handle None
    for disabled blend/inhomogeneity parameters and always return a
    float64 numpy array.
  • DMAAnalyzer.reset_state now also clears _capacity_history and the
    normalized-SOC warning flag, so repeated aging studies start clean.
  • Loader now handles nested .mat structs (mat_struct) and single-file
    multi-CU .mat payloads, and falls back to direction-based folder
    matching when no explicit CU markers are present.
  • Reoriented-OCV warning is now one-shot and only fires when
    auto-correction implies a direction opposite to config.direction.
  • DMAConfig now validates blend initial guesses against their upper
    bounds and rejects out-of-range inhomogeneity offsets at construction
    time.

Removed

  • Dead DMAConfig fields and the unused internal direction threading
    in the loader's CU matcher.