Costs

Cost-function schemas. This is a convenience alias for a subset of ionworks_schema.objective_functions that mirrors ionworkspipeline.costs.

Schemas for costs (match ionworkspipeline: iwp.costs).

class ionworks_schema.costs.ChiSquare(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None, variable_standard_deviations: dict[str, float])

Bases: ErrorFunction

Chi-square cost function that measures the weighted sum of squared differences between observed and expected values, normalized by their standard deviations.

The chi-square statistic is calculated as: chi2 = sum((observed - expected) / sigma)**2 where sigma is the standard deviation for each variable.

Parameters

variable_standard_deviationsdict

Dictionary mapping variable names to their standard deviations. For example: {“a”: 0.5, “b”: 0.3} means variable “a” has sigma=0.5 and variable “b” has sigma=0.3.

Notes

For a dataset with N points, if the model fits the data well and the errors are normally distributed, the chi-square value should be approximately N (the number of degrees of freedom).

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

variable_standard_deviations: dict[str, float]
model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.DesignFunction(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None)

Bases: ObjectiveFunction

A generalized design cost function for optimization problems.

This class serves as a base for design optimization objectives where the goal is to maximize (or minimize) certain design metrics like energy density, power density, etc.

Parameters

objective_weightsdict, optional

Dictionary of {name: weight} pairs for each objective in the cost function. If None, all objectives are weighted equally. If a name is not in the dictionary, it is given a weight of 1.

Extends: ionworks_schema.objective_functions.objective_functions.ObjectiveFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.ErrorFunction(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ObjectiveFunction

Base for residual-based error measures (also known as distance functions).

Adds normalization (and the deprecated scale alias) on top of ObjectiveFunction. RMSE, MAE, MSE, Max, SSE, ChiSquare, and MultiCost all inherit from here.

Parameters

normalizationstr or float, optional

How to normalize the model and data for each variable in the cost.

  • "mean" (default): use the mean of the data.

  • "identity": use 1 (no normalization).

  • "range": use the range of the data.

  • "sum_squares": use the sum of squares of the data.

  • "mean_squares": use the mean of the sum of squares of

    the data.

  • "root_mean_squares": use the root mean square of the

    data.

  • float: use that fixed value.

nan_valuesstr or float, optional

How to replace NaN values in the model output — see ObjectiveFunction.

objective_weightsdict[str, float], optional

Per-objective weights — see ObjectiveFunction.

variable_weightsdict[str, float], optional

Per-variable weights — see ObjectiveFunction.

scalestr or float, optional

Deprecated alias for normalization. Use normalization instead.

Extends: ionworks_schema.objective_functions.objective_functions.ObjectiveFunction

normalization: str | int | float | None
scale: str | int | float | None
model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.GaussianLogLikelihood(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, sigma: dict[str, int | float | str])

Bases: ObjectiveFunction

Gaussian negative log-likelihood cost function.

Computes the Gaussian NLL:

NLL = 0.5 * Σ_vars [ N_i * log(2π * σ_i²) + Σ_j (y_ij - ŷ_ij)² / σ_i² ]

This enables MLE with noise estimation, MAP estimation, and Bayesian posterior sampling (MCMC).

Parameters

sigmadict[str, float | str]

Mapping of variable names to noise standard deviations (σ). Values can be:

  • A float: fixed known noise standard deviation.

  • A string: name of a fitting parameter to be optimised (looked up from the current inputs at evaluation time via set_current_inputs).

nan_valuesstr or float, optional

How to handle NaN values in model output. Options: a float constant (default: 1e10), “mean”, or “min”. The default fills NaN with a large penalty value to ensure solver failures produce high costs.

Examples

>>> cost = iws.costs.GaussianLogLikelihood(sigma={"Voltage [V]": 0.005})
>>> fit = iws.DataFit(
...     objectives={"cycle": iws.objectives.CurrentDriven(data_input="path/to/cycle.csv")},
...     parameters={"x": iws.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0))},
...     cost=cost,
... )

Extends: ionworks_schema.objective_functions.objective_functions.ObjectiveFunction

sigma: dict[str, int | float | str]
model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.MAE(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ErrorFunction

Mean-absolute-error cost function.

Instead of squaring residuals, this cost function uses the absolute values, which makes it less sensitive to outliers compared to squared-error metrics.

For scalar output, it returns the sum of absolute residuals divided by the number of points. For array output, it returns the signed square root of the absolute residuals, normalized by the square root of the number of points.

Examples

>>> cost = iws.costs.MAE()
>>> val = iws.Validation(
...     objectives={"cycle": iws.objectives.CurrentDriven(data_input="path/to/cycle.csv")},
...     summary_stats=[cost],
... )

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.Max(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ErrorFunction

Cost function that reports the maximum error between the model and the data.

For scalar output, it returns the maximum absolute value of any residual. For array output, it returns a single-element array containing the square root of the maximum error.

Useful when you want to minimize the worst-case error rather than an average.

Examples

>>> cost = iws.costs.Max()
>>> val = iws.Validation(
...     objectives={"cycle": iws.objectives.CurrentDriven(data_input="path/to/cycle.csv")},
...     summary_stats=[cost],
... )

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.MSE(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ErrorFunction

Mean-square-error cost function.

Similar to SSE, but normalizes by the number of data points. This makes the cost independent of the number of data points.

For scalar output, it returns the sum of squared residuals divided by the number of points. For array output, it returns the SSE residuals divided by the square root of the number of points.

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.MultiCost(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None, costs: list[dict[str, Any]] | dict[Any, float], accumulator: Any | None = None)

Bases: ErrorFunction

Cost function that is a combination of multiple costs

Parameters

costsdict of {cost: weight}

Dict of costs and their weights.

accumulatorfunction, optional

The function to use to combine the costs. Default is sum.

Notes

All constituent costs must support the output mode (scalar or residuals) selected by the optimizer. The default accumulator (sum) combines the weighted costs by addition.

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

costs: list[dict[str, Any]] | dict[Any, float]
accumulator: Any | None
model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.ObjectiveFunction(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None)

Bases: BaseSchema

Base class for all cost / objective functions.

Concrete cost classes (RMSE, MAE, Max, ChiSquare, GaussianLogLikelihood, DesignFunction, …) all inherit from this base, so anywhere the schema needs to type “a list of costs” (e.g. Validation.summary_stats) the type is list[ObjectiveFunction].

Parameters

objective_weightsdict[str, float], optional

Mapping of objective name to weight in the combined cost. If None, all objectives are weighted equally. Objectives not listed in the dict get a weight of 1.

variable_weightsdict[str, float], optional

Mapping of variable name to weight. If None, all variables are weighted equally. Variables not listed in the dict get a weight of 1.

nan_valuesstr or float, optional

How to replace NaN values in the model output.

  • "mean": use the mean of the non-NaN model values.

  • "min": use the minimum of the non-NaN model values.

  • float: use that fixed value.

Defaults to "mean".

Extends: ionworks_schema.base.BaseSchema

objective_weights: dict[str, float] | None
variable_weights: dict[str, float] | None
nan_values: str | int | float | None
model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.RMSE(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ErrorFunction

Root-mean-square-error cost function.

Takes the square root of the MSE to provide a value in the same units as the original data. This is often used in scientific and engineering applications when the magnitude of error in the original units is important.

This cost function only supports scalar output.

Examples

>>> cost = iws.costs.RMSE()
>>> # slot into a DataFit's `cost` or a Validation's `summary_stats`
>>> val = iws.Validation(
...     objectives={"cycle": iws.objectives.CurrentDriven(data_input="path/to/cycle.csv")},
...     summary_stats=[cost],
... )

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.

class ionworks_schema.costs.SSE(*, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, nan_values: str | int | float | None = None, normalization: str | int | float | None = None, scale: str | int | float | None = None)

Bases: ErrorFunction

Sum-of-squared-errors cost function.

Calculates the sum of squared differences between model and data: SSE = Σ(model - data)²

Extends: ionworks_schema.objective_functions.objective_functions.ErrorFunction

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Args:

self: The BaseModel instance. context: The context.