Changelog — ionworksdata¶
All notable changes to this package are documented here. The format is based on Keep a Changelog, and this package follows Semantic Versioning.
For platform-wide release notes (Studio, pipeline, SDK, and more), see docs.ionworks.com/changelog.
[0.21.0] - 2026-11-02¶
Added¶
read.maccor_procedureextracts the test procedure embedded in a Maccor raw data file, as aMaccorProcedurethat reports which parts are missing (#2568)Reading a file adds cycle-cumulative charge/discharge capacity and energy columns, which reset each cycle;
transform.set_cycle_cumulative_capacityandset_cycle_cumulative_energycompute them (#2231)
Changed¶
Requires
polars>=2.1.0, up frompolars>=1.44.2(#2657)
Fixed¶
With
termination="events", a CC or CP step whose last sample belongs to the next step now ends at its own cut-off, not early (#2466)
[0.20.2] - 2026-10-20¶
Added¶
ionworksdata.cycle_metrics.INPUT_COLUMNS: the steps-table columnsget_cycle_metricsreads, for reading a steps table selectively.
Changed¶
Requires
pandas>=2.2.2. Earlier pandas releases do not import alongside numpy 2.
Fixed¶
Step classification leaves out a step’s last sample when measuring its spread, as it already did the first. A constant-current step whose last logged sample belongs to the next step now classifies as constant current instead of
Unknown.
[0.20.1] - 2026-10-09¶
Changed¶
DataLoader.from_dbwithfirst_step/last_stepdownloads only the rows those steps cover, instead of the whole time series.
Fixed¶
Excel readers no longer print fastexcel’s “Could not determine dtype for column” warning when the caller has configured
logging.Text in a numeric column that cannot be parsed as a number (e.g.
"N/A", or a repeated header row) now emits aUserWarningnaming the column, the count and example values, instead of silently becoming null.
[0.20.0] - 2026-09-30¶
Added¶
DataLoader.generate_experiment(split_cc_cv=...). A step the cycler logged as one CC-CV charge (constant current, then a voltage hold) is emitted as a constant-current step followed by a constant-voltage step instead of a current interpolant. On by default; passsplit_cc_cv=Falsefor the previous output.DataLoader.experiment_step_sources: for each cycle of the last generated experiment, the steps-table row ("Start index") behind each experiment step. A split row appears twice.
Changed¶
Because
split_cc_cvdefaults toTrue, an experiment generated from data with CC-CV charges now has more steps than the steps table has rows. Code that reads the experiment’s steps by steps-table position should map throughexperiment_step_sources.
Fixed¶
The Neware reader maps the BTSDA flat-CSV columns
"Cycle Index","Step Index"and"Date", and reads capacity, energy and power columns as floats even when a long opening rest writes them as0.
[0.19.0] - 2026-09-29¶
Breaking changes¶
The step-labeling API is removed:
steps.label_cycling,steps.label_pulse,steps.label_eisandsteps.validateno longer exist, andsteps.summarize/steps.identifyno longer emitLabelorGroup numbercolumns. Use theStep typecolumn to tell steps apart.read.measurement_detailsdrops itslabelsargument and no longer setsstep_labels_validated.keep_only_required_columnsanddata_typeeach move up one position, so pass them by keyword.The
DataLoadergitt_to_ocptransform is removed. It selected rests by theGITTstep label, which raw uploads never carry. Userest_to_ocp, which reduces every rest step to an OCP curve.
Changed¶
Raised the
pybammlower bound to>=26.9.0.0and thematplotliblower bound to>=3.11.2.
[0.18.0] - 2026-09-24¶
Added¶
AnalysisLoader(measurement_id, analysis_id=..., analysis_type=..., name=...)reads one of a measurement’s stored analyses (for example degradation modes per RPT) as a fit’s data, the feature-table counterpart toDataLoader.from_db. At least one selector is required, and a selector matching more than one analysis raises rather than picking one.window_rows(frame, time_range)keeps the rows of a table whoseTime [s]falls inside a{"start", "end"}window in seconds.
Fixed¶
A
time_rangegiven alongsidefirst_step/last_stepis applied after the steps are chosen, by narrowing the selected slice. Previously the window was applied first, so step positions shifted: a fit could fail with an index error, or silently run on data offset from the steps it named.Maccor data records which procedure call ran each step in a new
Framecolumn, read from the file’s call codes, so steps in sibling sub-procedures are no longer merged or nested under each other. Step numbering starts a new step wherever the frame changes.
Changed¶
Requires
ionworks-api>=0.34.0, which provides theclient.analysis.find_onelookup thatAnalysisLoaderreads through.
[0.17.0] - 2026-09-22¶
Added¶
DataLoader.generate_experimenttakesterminationandperiod. Under the defaulttermination="duration"each step replays its measured length, as before;termination="events"instead replays the endpoint each step reached in the variable it was controlling, so a capacity disagreement reads as capacity to that endpoint rather than as a residual voltage.periodsets the sample interval, defaulting to each step’s own mean interval.
Changed¶
generate_experimentkeeps the cycle structure of the loaded data rather than flattening every step into one cycle, so a generated experiment cycles the way the measurement did.use_cv=Trueemits constant-voltage steps as real voltage holds, simulated rather than driven with the measured current. Pair it withtermination="events": under"duration"the preceding step stops on the clock, and a hold entered below its setpoint draws whatever current closes the gap.
Fixed¶
A step whose indices no longer select its own samples is now rejected with a clear error instead of silently generating a step built from another step’s data.
[0.16.0] - 2026-09-07¶
Added¶
Header metadata is extracted for every cycler format, not just Maccor. Novonix, Basytec, Biologic, Arbin, Neware, Gamry, Digatron and Repower each read their own header block, where previously they fell back to reporting only the reader name and start time.
Readers translate their native labels into one shared vocabulary, so
test_setupkeeps the same shape across cyclers. Maccor’sProcedure, Novonix’sProtocol, Basytec’sTestplan, Arbin’sSchedule File Nameand Neware’sStep fileall arrive asprotocol["name"]; Arbin’sCreatorand Biologic’sUserboth arrive asoperator.A header field that maps to no known key is dropped rather than passed through under its native name, so the metadata surface stays the same across formats and widening it is a deliberate change in one place.
[0.15.0] - 2026-09-04¶
Added¶
Maccor header metadata is read and surfaced, rather than parsed for the test date and discarded.
Maccor.read_metadata()returns the parsed header, the new module-levelread.metadata(filename, reader, options)reaches it with reader auto-detection, andmeasurement_details()merges the keys into the measurement dict callers already build before upload. Most useful isprotocol["name"], from the file’sProcedure:line, which identifies the schedule that produced a file and so can link a measurement to its protocol on upload; the export date, source path, source file id, and barcode comment land undertest_setup. Merging usessetdefault, so a value the caller set is never overwritten by the header.BaseReader.read_metadata()reports the reader name and start time, so any reader can be asked without branching on reader type.Maccor columns recording the cycler’s own execution are carried through instead of dropped, each named with the existing
... from cyclersuffix:Mode from cycler(MD),End status from cycler(ES),Loop N from cycler(Loop1..Loop4), andVARn/FLAGn from cycler(theSetVarregisters). All are optional — a file without them reads as before.MDwas previously mapped only to an internal working column that is dropped after the unsigned-current correction, so the mode never reached a caller; it is the only thing distinguishing Maccor’s step-transition markers from genuine zero-current rest samples, andVAR1commonly holds the per-cell capacity the procedure used as its C-rate basis, which nothing else in the export records.
[0.14.0] - 2026-08-31¶
Added¶
A Digatron CSV reader.
Time [s]is derived from the file’sTimestampat microsecond resolution rather than from the vendor duration columns, whose#sheader suffix can disagree with the values actually written. A cumulative duration column whose span disagrees with the wall clock is reported; passstrict_duration_units=Trueto refuse the file instead.Arbin electrochemical impedance sweeps are no longer dropped.
read.time_series()on an Arbin workbook now splices the sweeps from theACIM_*sheet into the cycling data in test-time order, as their own step with a nullTime [s],Voltage [V], andCurrent [A]— a sweep is measured against frequency, so it carries no timestamp to record. Passoptions={"include_eis": False}for the cycling data alone.Maccor exports that report current in mA and capacity/energy in mAHr/mWHr are read, with the values converted to A and A.h/W.h. Previously these files failed on a missing
Current [A]column, and renaming the column by hand produced values 1000x too large.Maccor files carry the cycler’s own DC internal-resistance column through to the output instead of dropping it.
The CSV reader tolerates two structural quirks that are common across cyclers rather than specific to one vendor: a metadata preamble above the real header (each line a label padded out to the table width), and data rows carrying more fields than the header names — a trailing delimiter on every row, say. The header is located rather than assumed to be the first line, and the surplus fields are dropped before columns are matched.
Changed¶
Maccor header matching is canonical rather than literal: bracket style (
[]vs()),-/_/space separators, padding around the unit, and unit spellings (AHr/ah,WHr/wh,Sec/s) are folded before lookup. Every header spelling that was recognised before still resolves, and punctuation variants of a known column now resolve without needing a new mapping.Worksheet selection is consistent across the Arbin, Neware, and Maccor Excel readers: each confirms a candidate sheet by its headers rather than trusting a fixed name or the first sheet.
When several source columns map to the same output column, the winner is chosen by one shared rule across the readers instead of four private ones. No reader’s output changes.
Requires pybamm 26.8.0.0 or newer.
Fixed¶
Arbin
.xlsxworkbooks read theChannel_*data sheet instead of the leadingGlobal_Infometadata sheet, which had made most multi-sheet Arbin workbooks unreadable.Arbin headers in the
Test_Time(s)dialect no longer lose their units to a unit-stripper that did not fold underscores — this had dropped the time axis itself, leaving only voltage and current.Maccor bracketed-unit headers (
Test Time [s],Current [A]) are mapped instead of discarded, and a comma-separated header that carries its own units no longer has its first measurement row eaten as a units row.BioLogic exports written in a decimal-comma locale (
3,6955268E+000) parse instead of failing before the first row.BaSyTec
.txtresult exports are supported, including latin1-encoded headers such asT1[°C]that previously failed as invalid UTF-8.Novonix
-9999no-sensor sentinels are read as missing rather than as a real temperature.Neware exports whose vendor time column resets mid-file keep a monotonic
Time [s].
[0.13.0] - 2026-08-25¶
Added¶
DataLoader.from_db()accepts atime_rangewindow,{"start": seconds, "end": seconds}, carried through intoto_config(). Bounds are elapsedTime [s]values from the first sample, not wall-clock datetimes, so the window stays meaningful for a measurement with no recorded start time and does not drift when that metadata is edited.It pins how much of a measurement a pipeline run uses. A measurement that is still being extended grows over time, so re-running an unpinned config silently reads more data than the first run did; a pinned config keeps re-runs comparable. The window is applied when the config is resolved for a run — a local
from_db()still loads the full current series.
[0.12.0] - 2026-08-11¶
Breaking changes¶
DataLoadernow rejects an unrecognised option instead of ignoring it. The accepted set is closed, so a misspelt option can no longer silently skip the preprocessing you asked for — it raises at construction. Code that passed a stray or misspelt key and relied on it being dropped must remove it or correct the spelling.
Added¶
DataLoaderaccepts aDataLoaderOptionsschema object wherever it accepts an options mapping, so a caller holding one no longer has to unwrap it by hand before merging it with keyword options.
Changed¶
interpolateis documented as taking a float or a list of floats; a numpy array is still accepted and normalised to a list.first_step/last_stepare documented as taking a step index, a query selecting one row of the steps table, or the deprecated cycle/step dict.Added a dependency on
ionworks-schema>=0.18.0, which now owns the validated definition of the loader’s option surface.
[0.11.6] - 2026-08-03¶
Changed¶
Raised the
fastexcellower bound to>=0.20.2.
[0.11.5] - 2026-07-29¶
Changed¶
Raised the
polarslower bound to>=1.43.0.
[0.11.4] - 2026-07-28¶
Changed¶
Power [W]is now computed during raw→parquet processing rather than derived on every read. A newset_power()transform mirrors the existingset_capacity/set_energypattern, computingPower [W] = Voltage [V] * Current [A]and inheriting the current’s sign. It is a no-op whenPower [W]is already present or the source columns are missing, so previously processed measurements are unaffected.
Fixed¶
The current-sign auto-flip retry path now drops and recomputes
Power [W]alongside the capacity and energy columns; previously power silently kept the pre-flip sign.
[0.11.3] - 2026-07-24¶
Changed¶
Migrated to numpy 2 and pandas 3.
Bumped pybamm to 26.7.1.0 and adapted UCP power-mode simulations and
FunctionForExportserialization accordingly.
Fixed¶
Incremented the numpy lower pin.
[0.11.2] - 2026-07-20¶
Changed¶
Raised the
polarsdependency floor from>=1.33.1to>=1.42.1(#1284).
[0.11.1] - 2026-07-10¶
Fixed¶
BioLogic EIS reader: flip the reported
-Im(Z)into the canonicalZ_Im [Ohm]via an intermediate column instead of negating in place, avoiding a column-name collision during the rename step (#1133).
[0.11.0] - 2026-07-08¶
Breaking changes¶
PiecewiseLinearTimeseriesis now an abstract base class. Build a piecewise-linear timeseries via the newpiecewise_linear_timeseries()factory (or the concretePiecewiseLinearTimeseriesCompressed/PiecewiseLinearTimeseriesLosslesssubclasses); constructing the base class directly now raisesNotImplementedError(#1104).
Added¶
piecewise_linear_timeseriesfactory for constructing a piecewise-linear timeseries, with a lossless variant that reproduces the input current samples exactly instead of compressing them within the tolerances (#1104).
Fixed¶
Neware BTSDA workbooks now auto-select the
recordsheet when the active sheet is not the data sheet (#1113).Maccor exports now read the cycle number from
"Cycle C"rather than"Cycle P"(#1112).
[0.10.1] - 2026-06-26¶
Fixed¶
Corrected the documented Neware column mappings:
"Current(A)"maps to"Current [A]"(not"Current [mA]") (#969).
[0.10.0] - 2026-06-10¶
Added¶
CycleAgeingobjective now supportsexperiment='from data', deriving the cycling experiment directly from the measured data instead of requiring it to be specified separately (#834).
Changed¶
The Arbin
.resreader now bounds eachmdb-exportcall with a 300-second timeout, raising a clearRuntimeErrorinstead of hanging on a corrupt or locked MDB file (#806).
Fixed¶
Corrected CC-discharge step mislabeling (#807) and an unsigned mixed-mode current sign error (#810) in step identification (#848).
[0.9.3] - 2026-06-05¶
Changed¶
Canonical CSV column detection now warns when two columns collapse to the same whitespace-stripped key, making it clear that the later column shadows the earlier one (#718).
[0.9.2] - 2026-06-01¶
Changed¶
Switched the
polarsdependency frompolars-lts-cputo the standardpolarsdistribution (#768).
[0.9.1] - 2026-05-29¶
Changed¶
Relaxed the
numpydependency bound to allownumpy>=2(#754).
[0.9.0] - 2026-05-22¶
Added¶
Generic parquet reader (
ionworksdata.read.parquet) that mirrors the existing CSV ingestion path: format auto-detection picks it up viafrom_path/from_filefor.parquetinputs (#697).
Changed¶
Capacity and energy are now integrated with a per-step reset that matches the columns reported by the platform, instead of a single cumulative integral. Values inside a step are unchanged; the cumulative totals across resets will differ from previous releases (#687).
Fixed¶
Coin-cell ingestion now applies the correct current sign and capacity convention; previously some coin-cell sources were imported with flipped charge/discharge labels (#697).
[0.8.0] - 2026-05-11¶
Breaking changes¶
MeasurementValidationError.errorsis nowlist[ValidationIssue](a frozen dataclass with stableCheckName,severity,message, and structuredpayload) instead oflist[str]. Downstream callers that string-matched error messages should switch toe.has_check(CheckName.X)(#544).
Changed¶
ionworksdata.readauto-fix now keys offe.has_check(CheckName.CURRENT_SIGN_CONVENTION)rather than substring-matching the human-readable message (#544).
[0.7.0] - 2026-04-30¶
Added¶
Arbin CSV/XLSX/RES reader.
Maccor reader supports compact short-form column headers.
Fixed¶
cycle-metricskeeps the “Cycle count” column name in its output.