Changelog — ionworks-schema¶
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.34.0] - 2026-11-02¶
Breaking changes¶
calculations.ElectrodeBalanceFromFirstCycleEfficiencyno longer reads"Nominal cell capacity [A.h]"; cyclable lithium is first cycle efficiency times positive electrode capacity, so existing configs give different stoichiometry limits (#2613)
Added¶
models.SimulationSettings(discretisation_kwargs=...)carriespybamm.Discretisationoptions for a model, parameterized model or simulation run (#2598)calculations.ElectrodeBalanceFromFirstCycleEfficiency(options=...): composite electrodes viaparticle phases; the formation loss is now taken against positive electrode capacity, not nominal capacity (#2613)
[0.33.0] - 2026-10-23¶
Added¶
calculations.ElectrodeBalanceFromFirstCycleEfficiency: stoichiometry limits and initial concentrations at 100% SOC in one step, from both electrodes’ geometry, the nominal capacity and the first cycle efficiency (#2111)calculations.ElectrodeGeometryFromLoading(electrode): an electrode’s thickness, active material volume fraction and porosity from its coating mass loading and press density (#2111)
Changed¶
CyclableLithium.methodandElectrodeVolumeFractionFromLoading.methodare typed as their allowed values rather than free strings, so an unknown method is rejected when the config is built (#2111)
[0.32.1] - 2026-10-20¶
Changed¶
Requires
pandas>=2.2.2. Earlier pandas releases do not import alongside numpy 2.
[0.32.0] - 2026-10-09¶
Added¶
iws.direct_entries.DirectEntry(pipeline_id=..., keep=[...])takes only the named parameters from a completed pipeline. A name the pipeline did not produce, or an emptykeep, is an error. Withoutkeep, every parameter is taken, as before.iws.direct_entries.DirectEntry(cell_spec_id=..., mapping={...})reads parameter values from a cell specification.mappinggives each parameter’s JSON path in the specification (e.g."anode.properties.thickness"), and each value is converted to the unit in the parameter’s name. Values are read once, when the pipeline is submitted.DirectEntry.provenancerecords where each parameter came from: the path it was read from, and the value and unit written there.
Deprecated¶
Constructing
iws.SimplePipelineemits aDeprecationWarning. Useiws.Pipeline, which takes the same elements. SimplePipeline will be removed no earlier than November 2026.
[0.31.0] - 2026-09-30¶
Added¶
CycleAgeingOptions.split_cc_cv: emit a step the cycler logged as one CC-CV charge as a constant-current step followed by a constant-voltage step. DefaultTrue. Applies only to an experiment generated from data, liketermination.
Changed¶
Docstrings for
PenaltyandConstraintnow say that each term contributesregularizer_weight * fun**2to the cost. Pass the unsquared quantity asfun.Optimizer docstrings now say that
Constraintobjects are applied as a penalty on the cost by every scipy optimizer and method.
[0.30.0] - 2026-09-29¶
Breaking changes¶
DataLoaderOptionsandDataLoaderTransformsdrop thegitt_to_ocpfield, so passing it now fails validation. Userest_to_ocpinstead.
Changed¶
Raised the
pybammlower bound to>=26.9.0.0, and thematplotliblower bound in theplotextra to>=3.11.2.
[0.29.0] - 2026-09-25¶
Added¶
TimeRangeSpecacceptsdurationas an alternative toend, measured fromstart:TimeRangeSpec(start=0.0, duration=86_400.0)is the first day of a test. It resolves toendat construction, so the emitted config still carries onlystartandend. Passing bothendandduration, or a negativeduration, is rejected.TimeRangeSpecis exported from the top-levelionworks_schemapackage.
[0.28.0] - 2026-09-24¶
Added¶
AnalysisSpec, a selector (analysis_id,analysis_type,name) for one of a measurement’s stored analyses. A data input of{"data": "db:<measurement_id>", "analysis": {...}}, or anionworksdata.AnalysisLoader, reads that analysis as an objective’s data instead of the measurement’s time series, so aCycleAgeingfit can take its targets from the measurement it is fitted against.analysiscannot be combined withoptionsortime_range.CycleAgeingdata may be sparse: a NaN in a target column means the variable was not measured at that cycle, and that row is left out for that variable only, rather than every variable having to be measured at every cycle.
Changed¶
analysisandtime_rangeare now reserved keys of a dict data input, so a column literally named either is read as a payload key.
Fixed¶
A
time_rangecombined withfirst_step/last_stepnarrows within the chosen steps, rather than shifting which steps are chosen.
[0.27.0] - 2026-09-22¶
Added¶
CycleAgeingOptionstakesterminationanduse_cv, matching the newDataLoader.generate_experimentarguments. Both apply only to a generated experiment; passing either alongside an explicit one raises.
Fixed¶
A
pybamm.Symbolfunon aConstraintorPenaltynow survives submission through the API.to_configemits the symbol as a pybamm JSON tree, and the schema rebuilds it on validation, where previously the serialized dict was rejected againstis-instance[Symbol]— so a symbolic constraint or penalty was local-only.A
DataLoaderpassed as aCycleAgeingOptionsexperiment is wrapped in the"from data"form its consumers dispatch on. An unwrapped reference was resolved by nobody and then rejected by the parser. This also lets the protocol come from a different measurement than the fitted data.An entry or
DirectEntryconfig that names more than one source of parameters —path,values,pipeline_id— is rejected with an error naming the keys that clash, instead of silently picking one.
[0.26.0] - 2026-09-15¶
Breaking changes¶
A field value with no wire form now raises when the schema is built, naming the field, instead of reaching the server as a
reprstring such as"<pybamm...SPM object at 0x...>". Nested failures report the full path (options: model:). Convert such values to a number, string, list, dict, or pybamm object before putting them in a schema.callbacksandcost_loggerhold live objects and now raise onto_config(). They were never wire-capable — previously they were embedded raw and failed later, more confusingly, in the API client’s JSON encoding.custom_parametersis rejected by name; useparametersinstead. The positional slot is retained so a positional caller gets an error rather than silently shiftingconstraintsinto the vacated position.
Changed¶
Parameter serialisation moved onto the type:
ParameterValuesLikecarries the serialiser, so it applies on both construction and assignment for every field that uses it, rather than being re-declared per owner. This also fixescustom_parametersmappings never having theircitationsdropped or scalars flattened.Re-serialising an already-serialised parameter mapping now short-circuits instead of deep-walking the expanded symbol tree, so a read-modify-write on
.parametersno longer pays the full cost.
Removed¶
The internal pybamm-model serialiser, superseded by pybamm’s own
BaseModel.to_config(). The old helper reported any non-lithium-ion model as"custom"; pybamm’s emits the real module.
[0.25.0] - 2026-09-09¶
Added¶
penalize Xj complement boundsoniws.objectives.MSMRHalfCellOptions(defaultFalse) penalizes a reformulated Xj complement that falls outside the final Xj bounds. Only used with thereformulatemethod.
Changed¶
MSMRHalfCelldocuments that the capacity origin is carried by the electrode’s lower excess capacity, and how to seed it.ConstraintandPenaltydocument that apybamm.Symbolfunis local only — it does not survive submission through the API, where the serialized symbol is rejected in validation.
[0.24.1] - 2026-09-08¶
Added¶
iws.example_data(name)returns the path to a small dataset bundled with the package, andiws.list_example_data()names the ones available. They back the worked examples in the documentation, so an example can be copied out and run as-is with no download and no network. The datasets are synthetic sample data for illustration — substitute your own export, or read a measurement from the platform.Worked examples in the documentation for current-driven fitting, cycle ageing, EIS, and MSMR OCP, each rendered with its figure and runnable from a copy.
[0.24.0] - 2026-09-07¶
Added¶
Post-fit analysis is expressible as a pipeline element:
iws.LinearConfidenceIntervalfor linear confidence intervals andiws.SobolSensitivityfor Sobol sensitivity. Both take the sameobjectivesandparametersas aDataFit, and accept only aPointEstimateoptimizer, since they analyse a fit rather than performing one.iws.ConfidenceIntervalResultandiws.SensitivityResulttype their results, so intervals and sensitivity indices are reachable off the result object rather than by reading raw job metadata.An analysis element placed after a
DataFitwith the same objectives and parameters picks up the fitted point automatically, so the parameters do not have to be restated.
[0.23.0] - 2026-09-04¶
Added¶
33 schema classes that their packages defined but never re-exported are now reachable as attributes: 15 in
calculations, 11 inobjectives, 5 inmodels, plusdirect_entries.BaseInterpolationandobjective_functions.Regularizer. Every*Optionscompanion was affected —iws.objectives.CurrentDrivenOptions,iws.models.ECMOptions,iws.calculations.ElectrodeSOHOptionsand their siblings did not exist as attributes at all, so building a fit against a typed options object was not possible without reaching into a submodule.LumpedSPMRis also newly exported alongside its options.
[0.22.0] - 2026-08-31¶
Added¶
A typed result hierarchy in the new
ionworks_schema.resultsmodule, exported at the top level:BaseResultsplusParameterEstimatorResult,OptimizationResult,EnsembleResult,PosteriorResult,RegressionResult,ValidationResult, andPassthroughResult, withfrom_configto rebuild one from a config. Results round-trip throughto_config()/from_config()and exposeplot_fit_results()andplot_trace(). Plotting needs matplotlib, available as an optional extra:pip install 'ionworks-schema[plot]'.Lazy
overlay,trace,posterior, andseriesfields onBaseResults, fetched on first read and cached.overlaygives decimated data suited to figures;seriesgives the full-resolution per-objective model-vs-data channels as{objective: {channel: [values]}}for saving or further analysis.A new
ionworks_schema.plotsmodule describing what a panel contains — its traces and axis labels — independently of how it is drawn, so the same description backs both the schema’s own plotting and the pipeline’s.
Changed¶
StoichiometryLimitsFromCapacitynow rejects a missingusable capacityat validation time whenparticle phasescontains"2", instead of accepting the config and failing once the calculation runs.usable capacityis per direction: a joint-hysteresis fit uses a different value for charge than for discharge, so run one calculation per direction with that direction’s value.Requires pybamm 26.8.0.0 or newer.
[0.21.0] - 2026-08-25¶
Added¶
TimeRangeSpec, and atime_rangefield onDataPayloadSpec, describing an elapsed-seconds window that pins adb:source to the samples it held when the run was first pinned.startandendareTime [s]values from the first sample rather than wall-clock datetimes, and a window whoseendprecedes itsstartis rejected at validation.
Changed¶
Declares support for Python 3.13.
[0.20.0] - 2026-08-18¶
Breaking changes¶
The
optionsfield on every model, objective, and calculation class is now a typed options model instead of a free-formdict[str, Any]. Unknown or misspelt keys are rejected when the class is constructed, instead of being silently accepted (and previously ignored) at runtime. Pass a plaindictas before — it’s still validated against the typed schema — or import the new*Optionsclass (e.g.ECMOptions,CalendarAgeingOptions,StoichiometryLimitsFromCapacityOptions) directly for autocomplete and static checking.
Added¶
StoichiometryLimitsFromCapacityOptionsgainsnegative voltage limits,positive voltage limits, andusable capacityoptions, used to solve the shared stoichiometry window for a composite electrode from its lower-excess capacity.
[0.19.0] - 2026-08-11¶
Breaking changes¶
Simulation objectives (
CalendarAgeing,CurrentDriven,CycleAgeing,EIS,Pulse, and any otherSimulationObjectivesubclass) now require a model, and construction fails without one. Pass it asoptions={"model": <pybamm model>}, or name a stored model withoptions={"parameterized_model_id": <id>}. Previously an objective with no model was accepted and only failed later, once the fit ran.# before obj = iws.objectives.Pulse(data_input="file:gitt.csv") # after obj = iws.objectives.Pulse(data_input="file:gitt.csv", options={"model": "SPM"})
A parameter whose value is
Noneis now rejected instead of being serialised as a null the rest of the stack cannot use. The error names every offending key. Give the parameter a value, or omit the key entirely.A measurement given as a string must now start with a locator prefix saying where to read it from —
file:,folder:, ordb:. The loader already required this and rejected anything else; the rejection now happens when the config is built. Rewrite a bare path asfile:path/to/data.csv.A measurement given as a dict is now routed by its keys to a named, strictly-validated shape, so a misspelt key or option is rejected at construction rather than silently ignored.
time_series,steps,data,options, andmetadataare consequently reserved: a dict using one of them is read as a payload key, not as a column of that name. A dict matching none of the named shapes is still accepted as a plain column mapping.
Added¶
DataLoaderOptionsandDataLoaderTransformsschemas, giving the measurement-loading option surface a validated, documented type. Both are accepted anywhere loader options are taken, alongside a plain mapping.
Changed¶
The design-optimization optimizer field is now typed rather than free-form, so an unsupported optimizer is caught at construction.
[0.18.1] - 2026-08-10¶
Changed¶
Documented that
MultiCost.calculation_structureaccepts onlyNonefor every value. AMultiCostweights and sums what its component costs return, so per-variable scoping belongs on those components. Construction does not reject a variable list: converting such a config directly to a runtime cost raises, while sending it as a stored configuration drops the list and logs a warning. Behaviour is unchanged — the constraint was already real but undocumented.
[0.18.0] - 2026-08-06¶
Breaking changes¶
MultiCost.costsnow takes a list of costs instead of a{cost: weight}mapping. A bare cost gets weight 1.0; wrap one in the newWeightedCostto give it another. At least one component is required.# before cost = iws.costs.MultiCost(costs={rmse: 1.0, max_err: 0.25}) # after cost = iws.costs.MultiCost( costs=[iws.costs.RMSE(), iws.costs.WeightedCost(iws.costs.Max(), 0.25)] )
Passing a mapping now raises a
ValueErrornaming the accepted form. The same change landed inionworkspipeline, so the two packages now describe a combined cost the same way.MultiCost.accumulatoris gone. Only summation was ever supported for serialization, which is what the field now does unconditionally.MultiCostrejectsnormalization,nan_values,objective_weights, andvariable_weights. It only weights and sums what its components return, so these never affected the result — set them on the component costs instead. Previously they were accepted and silently ignored.
Added¶
WeightedCost(cost, weight)pairs a component cost with its weight inside aMultiCost. It serializes to a bare{"cost": ..., "weight": ...}record, so a stored config round-trips throughMultiCost.to_config().
Changed¶
ChiSquare,GaussianLogLikelihood, andDesignFunctionnow raise when given a field they cannot apply, rather than accepting and ignoring it:ChiSquare—normalization(fixed at 1),objective_weights, andvariable_weights(derived fromvariable_standard_deviations).GaussianLogLikelihood—objective_weightsandvariable_weights; every variable already carries its noise scale viasigma.DesignFunction—nan_valuesandvariable_weights; design metrics are scalar per objective, so there is no per-variable axis.
MultiCost.to_config()normalizes every component to a{"cost": ..., "weight": ...}record regardless of how it was constructed, so the emitted config always matches what the pipeline parser reads.Documented that
RMSEsupports scalar output only, so aMultiCostcontaining it needs a scalar optimizer rather than a least-squares one.
[0.17.2] - 2026-08-03¶
Added¶
Documented the
ECMmodel option"butler-volmer"("false"by default). When"true", the series overpotential gains a symmetric charge-transfer term driven by the new"Exchange current [A]"parameter, exposed as the"Charge-transfer overpotential [V]"variable. Theparameter_dependencieskey"i0"controls its dependencies and defaults to("soc",)even when a mapping is supplied, so existing configs keep a state-of-charge-dependent exchange current; pass"i0": ()for a constant.
Changed¶
EISnow inherits fromSimulationObjectiverather thanFittingObjective, matching the other objectives that run a simulation and compare against measured data. The accepted arguments are unchanged.
[0.17.1] - 2026-07-29¶
Fixed¶
canonicalize_element_typenow raises the documentedValueErrorwhen given a non-string value, instead of leaking aTypeErrorfrom the internal alias lookup.
[0.17.0] - 2026-07-28¶
Added¶
canonicalize_element_typeand the legacy display-label → wire alias map are now owned and exported byionworks_schema, making it the single source of truth for element-type wire aliasing. The package does not start accepting display labels —schema_class_forstill rejects them — so the contract itself is unchanged.LEGACY_ELEMENT_TYPE_ALIASESis exported so consumers can derive their own alias tables from the schema vocabulary instead of hand-listing it.ionworks_schema.serializewithserialize_parameter_value,serialize_parameters,deserialize_parameter_value, anddeserialize_parameters— the single definition of the parameter wire format, so aParameterValues, interpolant, or other pybamm symbol round-trips identically wherever it appears in a config.
Changed¶
A
ParameterValuesnested anywhere in a config now serialises through the shared helper (dropping citations, flatteningScalars), and objectives route theirparametersfield through it, matching how a direct entry has always been written.
[0.16.0] - 2026-07-24¶
Added¶
Persistent model
simulation_settings(mesh and solver configuration).
Changed¶
Migrated to numpy 2 and pandas 3; bumped pybamm to 26.7.1.0.
[0.15.5] - 2026-07-22¶
Changed¶
MSMRHalfCell: theconstrain Xj methodoption gained a new"project"mode and its default changed from"explicit"to"project". With"project"the complete Xj groups are projected onto the bounded simplex so the fitted fractions sum to exactly 1, whereas the previous"explicit"default applied a soft equality constraint that could drift. Configs omitting this option now use"project"(#1304).
[0.15.4] - 2026-07-20¶
Changed¶
Raised the
pydanticdependency floor from>=2.12.5to>=2.13.4(#1284).
[0.15.3] - 2026-07-16¶
Changed¶
Documentation only: expanded the
ECMdocstring to document the newoptionskeys for throughput-based degradation —"capacity"and"resistance scale"("constant"or"function"), and the degradation inputs ("Capacity throughput [A.h]","Time [s]") supplied to a degradation function (#1235).
[0.15.2] - 2026-07-14¶
Changed¶
Documentation only: clarified which
simulation_kwargskeys theEISobjective honors — only the mesh/discretisation kwargs (var_pts,submesh_types,geometry,spatial_methods) are applied, so anEISobjective can share asimulation_kwargsdict with aCurrentDriven/Pulseobjective in the same fit without error (#1126).
[0.15.1] - 2026-07-14¶
Changed¶
Documentation only: clarified the
to_config()serializer and the runtime-object guard in the README and package docs (#1078).
[0.15.0] - 2026-07-13¶
Breaking changes¶
Dropped support for Python 3.10; the minimum supported version is now Python 3.11 (#1174).
[0.14.0] - 2026-07-08¶
Added¶
interpolant_losslessoption on theCurrentDrivenandPulseobjectives: when True, the measured current samples are used directly for the interpolant (reproducing the input exactly) instead of being compressed withininterpolant_atol/interpolant_rtol(#1104).
Removed¶
solver_max_save_pointsoption onCurrentDrivenandPulse, which is no longer supported (#1104).
[0.13.1] - 2026-07-07¶
Added¶
Parameter-estimator and optimizer schemas (
Nested,BayesianOptimization,CMAES,PSO,SOBER,TuRBO,XNES,DifferentialEvolution,GridSearch, and more), so least-squares fitting configurations that select an optimizer are validated at construction time (#1023).
[0.13.0] - 2026-06-30¶
Added¶
data_fit.ArrayDataFitschema for fits that run independently at each value of an independent variable and return the fitted parameter as a 2xN array (e.g. diffusivity vs. stoichiometry, parameter vs. temperature).
[0.12.0] - 2026-06-26¶
Added¶
Materialis now strictly validated, rejecting unknown fields and enforcing per-field types (#980).Priors, distributions, and samplers are now modelled as discriminated unions, so invalid combinations are caught at construction time (#978).
Changed¶
All 1-D interpolant calculations now accept
"pchip"as an interpolator option (#1044).Pipeline.elementsis now deeply validated against the contract, surfacing nested configuration errors earlier (#981, #982).
[0.11.0] - 2026-06-25¶
Breaking changes¶
Removed
num_workers,parallel, andmax_batch_sizefromDataFit, andasync_modefromAskTellOptimizer. Parallelism is now determined by the execution engine rather than these schema fields. Because the schema forbids unknown fields, constructing a model with a removed field (e.g.DataFit(num_workers=...)) now raises a validation error. Stored configs carrying the removed fields are migrated automatically when parsed, so no action is needed for existing saved configurations (#949).The
costfield onDataFitand objectives no longer accepts a bare cost-name string (e.g.cost="RMSE"). Pass a cost schema instance (iws.costs.SSE()) or a config dict ({"type": "SSE"}) instead (#1015).Objectives are now validated against a discriminated union at the schema gate: each objective carries a
typetag (e.g."CurrentDriven","CycleAgeing") and unknown objective types or fields are rejected rather than silently accepted. Objects built directly (iws.objectives.X(...)) are unaffected (#962).
Added¶
objective_parallelism("auto"|"on"|"off") onDataFitcontrols objective-level parallelism. Defaults to"auto"(#949).
[0.10.0] - 2026-06-16¶
Added¶
GITTModel: a diffusion-only schema for fitting solid diffusivities (and the lumped ohmic resistance) to GITT or pulse-relaxation data (#904).dQ/dU outputs on
ElectrodeBalancing: newdQdU cutoff/dU/dQ cutoffoptions and the"Differential capacity [Ah/V]"output (with masked-axis siblings"Voltage [V] (dQdU)"/"Capacity [A.h] (dQdU)") so weighted costs (e.g. Wasserstein) can compare incremental-capacity curves (#859).calculation_structurefield on cost / objective-function schemas (e.g.SSE): an explicit objective→variable scoping map (objective name to the list of variable names to compute, ornullfor all). Use it to keep a per-variable cost from consuming variables that only a weighted Wasserstein should, such as model-axis dQ/dV arrays whose model and data lengths differ by construction (#953).dQdU model axisoption onElectrodeBalancing: additionally emit dQ/dV on the model’s own full-window voltage axis ("Differential capacity [Ah/V] (model axis)"/"Voltage [V] (model axis)") so a weighted cost can position-shift, aligning dQ/dV peaks in voltage rather than on the data grid (#953).
Deprecated¶
objective_nameson cost / objective-function schemas — a flat list of objective names the cost applies to. Usecalculation_structureinstead; specifying both raises a validation error (#953).
Fixed¶
A bare
pandas/polarsDataFrame passed to adatafield (objectivedata_input,OCPDataInterpolant.data, Arrhenius calculations) now serializes wrapped as{"data": <columns>}, matching what the server parser expects. Previously it serialized to a bare column dict and the server rejected it with “Required field ‘data’ missing”, forcing callers to hand-wrap as{"data": df}. String paths and already-wrapped dicts are unaffected (#1005).
[0.9.0] - 2026-06-10¶
Added¶
Bayesian Optimization, TuRBO, and SOBER optimization algorithms (#727).
SimplePipelineschema for single-datafit / single-validation runs, with accompanying documentation (#658).solve_kwargson objectives — a generic mapping forwarded tosim.solve(#821).
Changed¶
store_first_lastis now auto-enabled forCycleAgeingmetrics that only need the first/last cycle (#828).CycleAgeingobjective now supportsexperiment='from data'(#834).CycleAgeing.simulation_kwargsdocumentsexperiment_model_mode, which defaults to"unified"whenever an experiment is supplied (#862).
[0.8.2] - 2026-06-05¶
Changed¶
Documented the
skip_objective_callbacksdata-fit option, which skips capturing initial/final per-objective fit results for performance (#765).Documented that
simulation_kwargson simulation objectives may includesolver_kwargsto tune the auto-built solver (#776).
[0.8.1] - 2026-05-29¶
Removed¶
Dropped the unused
numpyruntime dependency (#752).
[0.8.0] - 2026-05-28¶
Added¶
costs.Wassersteinnow supports a weighted point-cloud mode for comparing sparse experimental data against dense simulation outputs (#733).MSMRFullCelldata-fit objective now exposes dQ/dU (incremental capacity analysis) output alongside the existing voltage curves (#733).DirectEntrynow accepts apybamm.ParameterValuesobject directly, serializing callable entries to symbolic JSON automatically (#742).
[0.7.0] - 2026-05-19¶
Breaking changes¶
Renamed
maxiterstomax_iterationsinDataFit.optionsto unify optimiser kwargs across the stack. Update any configs or call sites that setoptions={"maxiters": ...}to useoptions={"max_iterations": ...}(#655).
Added¶
costs.Wassersteinerror metric for data-fit objective functions (#679).
[0.6.0] - 2026-05-12¶
Breaking changes¶
Renamed
direct_entries.AverageOcptodirect_entries.AverageOCPto match the project-wideOCPcapitalisation (OCPHalfCell,OCPDataInterpolant,OCPMSMRInterpolant). Update any imports ofAverageOcp.Removed the opaque
distributionplaceholder field from thestats.Distributionbase class. Concrete subclasses (Normal,LogNormal,Uniform, …) never used it, andto_config()continues to emit"distribution": "<ClassName>"unchanged, so configs round-trip identically.
Improved¶
Docstrings on the public schema surface re-written for non-technical users.
to_config()is now consistently described as the method that builds the dict you submit throughionworks-api._typesplaceholder classes for optional dependencies (polars,ionworksdata) simplified to plain sentinel classes instead of a nested module-impersonation wrapper.Added numpy-style
Parametersblocks toPipeline,library.Material, anddirect_entries.DirectEntryso every public schema class surfaces its fields inhelp()/ IDE hovers / Sphinx (#634).Fixed LaTeX math rendering in
calculationsdocstrings — four classes (Arrhenius / standardDiffusivityFromMSMR{Data,Function}) switched to raw strings so\fracno longer renders asrac(#634).Renamed footnote references on
DiffusivityFromPulseandElectrodeSOHfrom the anonymous[1]_to named[Wang2022]_and[Mohtat2019]_so they don’t collide under docutils (#634).Schema docs site live at https://packages.docs.ionworks.com/ionworks-schema/ (vanity URL: https://schema.docs.ionworks.com/) (#634).
[0.5.0] - 2026-05-11¶
Added¶
Schema gap fixes: new
Constraint,Penalty,*Options(CMAES/PSO/DE/XNES),LatinHypercube, andUniformclasses to match what pipeline already supports (#509).Sphinx documentation skeleton with autodoc + per-submodule reference pages and intersphinx cross-links to ionworkspipeline (#509).
Field(description=...)enrichment across ~40 classes inobjectives,data_fit,direct_entries,costs,parameter_estimators,stats,parameter,library,regularizers,distribution_samplers, plus top-levelPipelineandValidation(#509).
Changed¶
Uniformnow lives only indistribution_samplers(resolves the previous ambiguity withiws.Uniform) (#509).
[0.4.0] - 2026-04-30¶
Breaking changes¶
Cost schema restructure with correctness fixes. Existing pipeline configs that reference the old cost shape will need to be updated to match the new structure.