Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ionworks.com/llms.txt

Use this file to discover all available pages before exploring further.

Data fitting is the process of estimating unknown model parameters by minimizing the difference between model predictions and experimental measurements. The Ionworks Pipeline provides a flexible framework for this task.

The Data Fitting Problem

Given experimental data and a model with unknown parameters, we seek parameters θ\theta that minimize a cost function: θ^=argminθ  C(θ)=argminθi(yimodel(θ)yidata)2\hat{\theta} = \arg\min_\theta \; C(\theta) = \arg\min_\theta \sum_i \left( y_i^{\text{model}}(\theta) - y_i^{\text{data}} \right)^2 In battery modeling, this typically means:
  • Model: Physics-based simulation (SPMe, DFN, etc.)
  • Data: Voltage, current, temperature measurements
  • Parameters: Diffusivities, reaction rates, capacities, etc.

Core Components

The data fitting framework consists of three main components:
import ionworkspipeline as iwp

datafit = iwp.DataFit(
    objectives=objectives,      # What to minimize
    parameters=parameters,      # What to vary
    optimizer=optimizer,        # How to search
)

result = datafit.run(fixed_parameters)

Objectives

Define what to minimize: the difference between model and data

Parameters

Specify which parameters to fit and their bounds

Optimizer

Choose how to search the parameter space

Why Separate Components?

Separating the Objective, Cost, and Optimizer provides several benefits:
  • Reusable objectives: The same objective can be used with different cost functions (e.g., RMSE vs. feature extraction)
  • Sequential refinement: Objectives can be reused within a pipeline—first for approximate values, then for fine-tuning
  • Combined objectives: Multiple objectives can be combined to simultaneously optimize over different datasets (e.g., constant-current discharge at different C-rates or temperatures)

Objectives

An objective computes the cost for a given set of parameters:
objective = iwp.objectives.CurrentDriven(
    model=model,
    data=data,
    variables=["Voltage [V]"],
)
Each objective:
  1. Runs the model with the proposed parameters
  2. Compares model output to experimental data
  3. Returns a scalar cost value
Multiple objectives can be combined for fitting to different experiments simultaneously.

Parameters

Parameters define what the optimizer can adjust:
parameters = iwp.Parameters(
    {
        "Positive particle diffusivity [m2.s-1]": iwp.Parameter(
            initial_value=1e-14,
            bounds=(1e-16, 1e-12),
        ),
        "Negative particle diffusivity [m2.s-1]": iwp.Parameter(
            initial_value=1e-14,
            bounds=(1e-16, 1e-12),
        ),
    }
)
Key attributes:
  • Initial value: Starting point for optimization
  • Bounds: Physical limits on the parameter
  • Transform: Optional scaling (e.g., log-transform for diffusivities)

Optimizers

The optimizer searches for parameters that minimize the cost:
optimizer = iwp.optimizers.ScipyMinimize(method="L-BFGS-B")
# or
optimizer = iwp.optimizers.AskTellOptimizer(method="CMAES")
OptimizerBest for
L-BFGS-BSmooth problems, fast local optimization
Nelder-MeadNon-smooth problems, no gradients needed
CMAESGlobal optimization, many local minima
PSOGlobal optimization, parallelizable
The examples and options in this section are not exhaustive. See the API reference for full details.

Workflow

1

Prepare Data

Load experimental data and preprocess as needed
2

Define Model

Set up the physics-based model with fixed parameters
3

Create Objectives

Specify what data to fit and how to compare
4

Set Parameters

Choose which parameters to fit and their bounds
5

Run Optimization

Execute the fitting and analyze results

Results

The optimization returns a Result object:
result = datafit.run(fixed_parameters)

# Best-fit parameters
best_params = result.inputs

# Final cost value
cost = result.cost

# For multi-start optimization, access all results
all_results = result.children  # Sorted by cost

Multi-Start Optimization

For problems with multiple local minima, run optimization from different starting points:
datafit = iwp.DataFit(
    objectives=objectives,
    parameters=parameters,
    multistarts=20,  # Run 20 optimizations with different initial guesses
)
The framework automatically:
  • Generates initial guesses using Latin Hypercube sampling
  • Runs optimizations in parallel
  • Returns all results sorted by cost

Objective Functions

Detailed guide to cost functions and objectives

Regularization

Ridge regression and MAP estimation for stability

Sensitivity Analysis

Understanding parameter identifiability

Voltage & Stoichiometry

Fitting electrode stoichiometry windows

Python Examples

Code examples in the Python documentation