Objectives¶
Experiment-specific objective schemas.
Schemas for objectives.
- class ionworks.pipeline.objectives.BaseObjective(options=None, callbacks=None, custom_parameters=None, cost=None, constraints=None, penalties=None, parameters=None)[source]¶
Bases:
BaseSchemaShared base for every objective. Not used directly.
Concrete subclasses (
Pulse,EIS,CycleAgeing,MSMRHalfCell,DesignObjective, …) inherit from here. An objective tells the pipeline what to fit (or optimize) and which data to compare against — pick a concrete subclass that matches your experiment.- Parameters:
options (dict, optional) – Objective-specific settings. The supported keys depend on the subclass — see each subclass’s docstring for the list.
callbacks (Callback or list of Callback, optional) – Callback(s) that run at various points during the fit (logging, plotting, early stopping).
cost (Cost or dict, optional) – The cost function used to score the fit (e.g.
RMSE,MAE,GaussianLogLikelihood). IfNone, the optimizer’s default cost is used.constraints (list of Constraint, optional) – Equality or inequality constraints that must hold during the fit.
penalties (list of Penalty, optional) – Soft penalties added to the cost.
parameters (dict or pybamm.ParameterValues, optional) – Parameter overrides applied only to this objective.
- cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CalendarAgeing(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['CalendarAgeing'] = 'CalendarAgeing')[source]¶
Bases:
SimulationObjectiveFit degradation parameters (loss of lithium inventory, loss of active material) to calendar-ageing data for a full cell.
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The calendar-ageing data — see
FittingObjective.options (CalendarAgeingOptions or dict, optional) – See
CalendarAgeingOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.CalendarAgeing( ... data_input="path/to/calendar.csv", ... options={"model": "SPM", "modes": ["LLI [%]", "LAM_pe [%]"]}, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: CalendarAgeingOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CalendarAgeingOptions(*, model: Any | None = None, parameterized_model_id: str | None = None, modes: list[Literal['LLI [%]', 'LAM_ne [%]', 'LAM_pe [%]']] | None = None, simulation_kwargs: dict[str, Any] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for a
CalendarAgeingobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CurrentDriven(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['CurrentDriven'] = 'CurrentDriven')[source]¶
Bases:
SimulationObjectiveFit a model against any current-driven experiment — pulse trains, drive cycles, custom load profiles.
Pass in the recorded current/voltage data along with the model and the objective will simulate the same current profile and compare voltages (or any other variable you ask for).
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The current/voltage data — see
FittingObjective.options (CurrentDrivenOptions or dict, optional) – See
CurrentDrivenOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.CurrentDriven( ... data_input="path/to/drive_cycle.csv", ... options={"model": "SPM", "objective variables": ["Voltage [V]"]}, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: CurrentDrivenOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CurrentDrivenOptions(*, model: Any | None = None, parameterized_model_id: str | None = None, independent_variable: Literal['time', 'voltage'] = 'time', simulation_kwargs: dict[str, Any] | None = None, objective_variables: list[str] | None = None, interpolant_atol: float | None = None, interpolant_rtol: float | None = None, interpolant_lossless: bool = False)[source]¶
Bases:
_ObjectiveOptionsOptions for a
CurrentDrivenobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CycleAgeing(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['CycleAgeing'] = 'CycleAgeing')[source]¶
Bases:
SimulationObjectiveFit summary variables (capacity, resistance, LLI, LAM) against cell-cycling data.
Each row in the data is one summary measurement across a cycle (or a small group of cycles). The objective runs the requested cycling experiment, extracts the same summary variables from the simulation, and compares the two.
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The cycling summary data — see
FittingObjective. One row per summary measurement, so a per-cycle table — a measurement’s stored analysis is the usual platform source, and is a different object from the measurement whose steps define the protocol. A row names the cycle its quantity was measured in, so a quantity measured later in the same test occupies its own row. A target column may be sparse: a NaN says there is no measured value at that cycle, and that row is left out of the fit for that variable alone, so only the measured points are scored.options (CycleAgeingOptions or dict, optional) – See
CycleAgeingOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.CycleAgeing( ... data_input="path/to/cycling_summary.csv", ... options={ ... "model": "SPM", ... "objective variables": ["Discharge capacity [A.h]"], ... }, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: CycleAgeingOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.CycleAgeingOptions(*, model: Any | None = None, parameterized_model_id: str | None = None, experiment: Any | None = None, termination: Literal['duration', 'events'] | None = None, use_cv: bool | None = None, split_cc_cv: bool | None = None, objective_variables: list[str] | None = None, metrics: dict[str, Any] | None = None, simulation_kwargs: dict[str, Any] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for a
CycleAgeingobjective.- classmethod wrap_dataloader_experiment(value)[source]¶
Put a DataLoader experiment in the
from dataform consumers read.A DataLoader serializes to a bare data config, but every consumer dispatches on a
"from data"key: an unwrapped reference is resolved by nobody and then rejected by the parser.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.DesignObjective(actions, constraints=None, options=None, callbacks=None, custom_parameters=None, cost=None, validate_against_experiment_steps=True, output_variables_full=None, save_at_cycles=None, penalties=None, parameters=None)[source]¶
Bases:
BaseObjectiveObjective for design optimisation — maximise (or minimise) one or more cell metrics by adjusting design parameters.
You describe each design target as an
Actionwrapping aMetric(e.g. maximise energy density, hit a target fast-charge time) and pass them in viaactions. The optimiser then searches the parameter space to find the design that best satisfies all of them, subject to any constraints you specify.The objective handles simulation failures and edge-case parameter combinations automatically — failed simulations receive large penalties so the optimiser steers away from those regions.
- Parameters:
actions (dict[str, Any]) – Mapping of action name to an
Action-wrappedMetricdefining each design target.constraints (dict[str, BaseAction] or list of Constraint, optional) – Hard limits on the design. For design optimization this may be either a dict of
Action-wrapped metrics (e.g. minimum capacity) or a list ofConstraintterms on pybamm symbols.options (dict, optional) – Settings for the design simulation (model, experiment, simulation kwargs).
callbacks (Callback or list of Callback, optional) – Callback(s) invoked at various points during optimisation.
cost (Cost or dict, optional) – Cost function used to combine the actions into a single design score. If
None, the optimizer’s default design cost is used.penalties (list of Penalty, optional) – Soft penalties added to the cost.
parameters (dict or pybamm.ParameterValues, optional) – Parameter overrides applied only to this objective.
- cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- to_config() dict[source]¶
Build the dict you submit through
ionworks.api.Same as the base
to_config, withactionsfolded under the"options"key so the payload matches the structure the Ionworks API expects for cycling objectives.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.EIS(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['EIS'] = 'EIS')[source]¶
Bases:
SimulationObjectiveFit a model against electrochemical impedance spectroscopy (EIS) data.
Simulates the model response at the supplied frequencies and compares the predicted impedance to the measured spectrum. Uses pybamm’s frequency-domain EIS simulator under the hood.
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The EIS data — see
FittingObjective.options (EISOptions or dict, optional) – See
EISOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.EIS(data_input="path/to/eis.csv", options={"model": "SPM"}) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: EISOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.EISOptions(*, model: Any | None = None, parameterized_model_id: str | None = None, simulation_kwargs: dict[str, Any] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for an
EISobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.ElectrodeBalancing(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['ElectrodeBalancing'] = 'ElectrodeBalancing')[source]¶
Bases:
FittingObjectiveFind the electrode capacities and stoichiometry windows that best reconstruct a full-cell OCV curve from the underlying half-cell OCPs.
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The full-cell OCV data — see
FittingObjective.options (ElectrodeBalancingOptions or dict, optional) – See
ElectrodeBalancingOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.ElectrodeBalancing( ... data_input="path/to/full_cell_ocv.csv", ... options={"direction": "discharge"}, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: ElectrodeBalancingOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.ElectrodeBalancingHalfCell(electrode=None, data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['ElectrodeBalancingHalfCell'] = 'ElectrodeBalancingHalfCell')[source]¶
Bases:
FittingObjectiveFind the starting capacity and total capacity of one electrode, given a known OCV function for that electrode.
Useful for aligning a fresh experiment (for example a GITT scan) to a previously measured OCV curve — the fit slides and scales the data so it lines up with the OCV in stoichiometry.
- Parameters:
electrode (str) – The electrode to fit —
"positive"or"negative".data_input (DataLoader, DataFrame, str, or dict) – The half-cell data — see
FittingObjective.options (ElectrodeBalancingHalfCellOptions or dict, optional) – See
ElectrodeBalancingHalfCellOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.ElectrodeBalancingHalfCell( ... electrode="positive", ... data_input="path/to/half_cell.csv", ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: ElectrodeBalancingHalfCellOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.ElectrodeBalancingHalfCellOptions(*, direction: Literal['lithiation', 'delithiation'] | None = None, GITT: bool = False, dudq_cutoff: float | None = None, objective_variables: list[str] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for an
ElectrodeBalancingHalfCellobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.ElectrodeBalancingOptions(*, dudq_cutoff: float | None = None, dqdu_cutoff: float | None = None, direction: Literal['charge', 'discharge'] | None = None, GITT: bool = False, dqdu_model_axis: bool = False, objective_variables: list[str] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for an
ElectrodeBalancingobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.FittingObjective(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None)[source]¶
Bases:
BaseObjectiveShared base for objectives that fit a model to measured data.
On top of
BaseObjectivethis addsdata_input— the experimental data the model is compared against. Pick a concrete subclass that matches your experiment (Pulse,EIS,OCPHalfCell,CycleAgeing, …).- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The measured data. Accepts an
ionworks.data.DataLoader(constructed directly from DataFrames, or viaDataLoader.from_local(path)/DataLoader.from_db(measurement_id)), a path to a data file, apandasorpolarsDataFrame, or a dict with keysdata(DataFrame of raw values) andmetadata(dict describing the experiment).options (dict, optional) – Objective-specific settings — see each subclass for supported keys.
callbacks (Callback or list of Callback, optional) – Callback(s) invoked at various points during the fit.
cost (Cost or dict, optional) – Cost function used to score the fit. If
None, the optimizer’s default cost is used.constraints (list of Constraint, optional) – Equality or inequality constraints that must hold during the fit.
penalties (list of Penalty, optional) – Soft penalties added to the cost.
parameters (dict or pybamm.ParameterValues, optional) – Parameter overrides applied only to this objective.
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.MSMRFullCell(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['MSMRFullCell'] = 'MSMRFullCell')[source]¶
Bases:
FittingObjectiveFit an MSMR model to full-cell open-circuit voltage data.
Compares both the capacity-vs-voltage curve and the differential voltage
dU/dQof the full cell — fitting both together gives much tighter constraints on the underlying half-cell MSMR parameters than fitting the OCV alone [1].- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The full-cell OCV data — see
FittingObjective.options (MSMRFullCellOptions or dict, optional) – See
MSMRFullCellOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
References
Examples
>>> obj = iw.pipeline.objectives.MSMRFullCell( ... data_input="path/to/full_cell_ocv.csv", ... options={ ... "negative voltage limits": (0.005, 1.5), ... "positive voltage limits": (3.0, 4.3), ... }, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: MSMRFullCellOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.MSMRFullCellOptions(*, model: Any | None = None, dudq_cutoff: Literal['none'] | float | None = None, dqdu_cutoff: Literal['none'] | float | None = None, negative_voltage_limits: tuple[float, float] | None = None, positive_voltage_limits: tuple[float, float] | None = None, objective_variables: list[str] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for an
MSMRFullCellobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.MSMRHalfCell(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['MSMRHalfCell'] = 'MSMRHalfCell')[source]¶
Bases:
FittingObjectiveFit an MSMR model to half-cell open-circuit potential data.
Compares the capacity-vs-voltage curve and (optionally) the differential voltage
dU/dQof one electrode to a measured half-cell OCP.Capacity [A.h]is used as given: its origin is carried by{Electrode} electrode lower excess capacity [A.h], not re-zeroed away. Seed that parameter from the data (-min(q)) and bound it of order the capacity span; a library value is in another frame.- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The half-cell OCP data — see
FittingObjective.options (MSMRHalfCellOptions or dict, optional) – See
MSMRHalfCellOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.MSMRHalfCell( ... data_input="path/to/half_cell.csv", ... options={"model": iw.pipeline.models.MSMRHalfCellModel(electrode="positive")}, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: MSMRHalfCellOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.MSMRHalfCellOptions(*, model: Any | None = None, dudq_cutoff: Literal['none'] | float | None = None, dqdu_cutoff: Literal['none'] | float | None = None, voltage_limits: tuple[float, float] | None = None, GITT: bool = False, objective_variables: list[str] | None = None, constrain_xj_method: Literal['project', 'explicit', 'reformulate'] = 'project', penalize_xj_complement_bounds: bool = False, preserve_u0j_order: bool = False)[source]¶
Bases:
_ObjectiveOptionsOptions for an
MSMRHalfCellobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.OCPHalfCell(electrode=None, data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['OCPHalfCell'] = 'OCPHalfCell')[source]¶
Bases:
FittingObjectiveFit a smooth open-circuit-potential function to half-cell OCP data.
- Parameters:
electrode (str) – The electrode to fit —
"positive"or"negative".data_input (DataLoader, DataFrame, str, or dict) – The half-cell OCP data — see
FittingObjective.options (OCPHalfCellOptions or dict, optional) – See
OCPHalfCellOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", ... data_input="path/to/ocp.csv", ... options={"stoichiometry limits": (0.05, 0.95)}, ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: OCPHalfCellOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.Objective(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['Objective'] = 'Objective')[source]¶
Bases:
FittingObjectiveDeprecated alias for FittingObjective.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.OCPHalfCellOptions(*, theta_ref: float | None = None, stoichiometry_limits: tuple[float, float] | None = None, voltage_limits: tuple[float, float] | None = None, dudq_cutoff: float | None = None, dqdu_cutoff: float | None = None, direction: Literal['lithiation', 'delithiation'] | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for an
OCPHalfCellobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.Pulse(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['Pulse'] = 'Pulse')[source]¶
Bases:
SimulationObjectiveFit a model against pulse experiments — GITT, HPPC, ICI, and similar.
By default the fit compares simulated voltage against measured voltage, but you can swap in a different
objective variablesfunction to compare overpotentials, resistances, or ICI/GITT features instead.- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – The pulse data — see
FittingObjective.options (PulseOptions or dict, optional) – See
PulseOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.Pulse( ... data_input="path/to/gitt.csv", options={"model": "SPM"} ... ) >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: PulseOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.PulseOptions(*, model: Any | None = None, parameterized_model_id: str | None = None, simulation_kwargs: dict[str, Any] | None = None, objective_variables: Callable | None = None, interpolant_atol: float | None = None, interpolant_rtol: float | None = None, interpolant_lossless: bool = False)[source]¶
Bases:
_ObjectiveOptionsOptions for a
Pulseobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.Resistance(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None, type: Literal['Resistance'] = 'Resistance')[source]¶
Bases:
FittingObjectiveFit a cell-resistance curve against measured resistance vs SOC.
- Parameters:
data_input (DataLoader, DataFrame, str, or dict) – Resistance data — see
FittingObjective. Must contain columns"SOC"and"Resistance [Ohm]", plus any extra columns the resistance model needs.options (ResistanceOptions or dict, optional) – See
ResistanceOptionsfor the available keys.callbacks – Shared with
BaseObjective.constraints – Shared with
BaseObjective.penalties – Shared with
BaseObjective.parameters – Shared with
BaseObjective.
Examples
>>> obj = iw.pipeline.objectives.Resistance(data_input="path/to/resistance.csv") >>> # slot into a DataFit (parameters omitted for brevity)
- data_input: Annotated[str | DataFrame | DataFrame | Annotated[object, PlainValidator(func=_as_loader, json_schema_input_type=Any)] | TimeSeriesSpec | DataPayloadSpec | MetadataSpec | dict[str, Any], BeforeValidator(func=_route_measurement_input, json_schema_input_type=PydanticUndefined)]¶
- options: ResistanceOptions | None¶
- constraints: list[Constraint] | None¶
- parameters: Annotated[dict[str, Any] | ParameterValues, BeforeValidator(func=serialize_parameters, json_schema_input_type=PydanticUndefined)] | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.ResistanceOptions(*, model: Any | None = None)[source]¶
Bases:
_ObjectiveOptionsOptions for a
Resistanceobjective.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.objectives.SimulationObjective(data=None, options=None, callbacks=None, custom_parameters=None, constraints=None, penalties=None, parameters=None, *, cost: Annotated[RMSE | MAE | MSE | Max | SSE | Wasserstein | ChiSquare | MultiCost | GaussianLogLikelihood | DesignFunction, FieldInfo(annotation=NoneType, required=True, discriminator='type')] | None = None)[source]¶
Bases:
FittingObjectiveShared base for objectives that run a pybamm simulation and compare the output to measured data.
Subclasses such as
Pulse,CurrentDriven,CalendarAgeing,CycleAgeing, andEISinherit from here. The arguments are the same asFittingObjective— pick a concrete subclass that matches your experiment.Every subclass needs a model to fit against, given either as
options={"model": ...}or, for a model stored on the platform, asoptions={"parameterized_model_id": ...}. Construction fails without one.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].