Pipelines#
Pipelines let you chain together data fitting, calculations, and validation
steps into a single server-side workflow. A pipeline is defined as an ordered
dictionary of named elements, each with an element_type and
type-specific configuration.
Element types#
Type |
Purpose |
|---|---|
|
Provide initial parameter values to downstream elements |
|
Fit model parameters to experimental data |
|
Fit the same model separately at each value of an independent variable (e.g. temperature, SOC) |
|
Run a calculation (e.g. OCP fitting) |
|
Validate a model against experimental data |
Elements run in the order they appear. Later elements can reference results
from earlier ones through the existing_parameters field.
Submitting a pipeline#
Entry element#
An entry element seeds the pipeline with known parameter values:
entry_config = {
"element_type": "entry",
"values": {
"Negative particle diffusivity [m2.s-1]": 3.3e-14,
"Positive particle diffusivity [m2.s-1]": 4e-15,
},
}
Data-fit element#
A data_fit element optimizes model parameters against uploaded measurement
data. Reference measurement data stored in Ionworks with the db:<id> prefix:
measurement_id = "..." # from client.cell_measurement.create()
datafit_config = {
"element_type": "data_fit",
"objectives": {
"test_1C": {
"objective": "CurrentDriven",
"model": {"type": "SPMe"},
"data": f"db:{measurement_id}",
"parameters": {
"Ambient temperature [K]": 298.15,
},
},
},
"parameters": {
"Negative particle diffusivity [m2.s-1]": {
"bounds": [1e-14, 1e-13],
"initial_value": 2e-14,
},
"Positive particle diffusivity [m2.s-1]": {
"bounds": [1e-15, 1e-14],
"initial_value": 2e-15,
},
},
"cost": {"type": "RMSE"},
"optimizer": {"type": "ScipyDifferentialEvolution"},
}
Array-data-fit element#
An array_data_fit element fits the same model separately at each key of the
objectives dictionary, where the key is the value of some independent variable
(e.g. temperature, midpoint stoichiometry, pulse SOC). It accepts the same
top-level fields as data_fit; the only difference is the shape of objectives:
array_datafit_config = {
"element_type": "array_data_fit",
"objectives": {
# key = value of the independent variable
0.25: {"objective": "Pulse", "data": f"db:{m1_id}", ...},
0.50: {"objective": "Pulse", "data": f"db:{m2_id}", ...},
0.75: {"objective": "Pulse", "data": f"db:{m3_id}", ...},
},
"parameters": {
"Positive particle diffusivity [m2.s-1]": {
"bounds": [1e-15, 1e-13],
"initial_value": 1e-14,
},
},
}
The result contains one fitted parameter value per independent-variable key, so the fitted parameter is returned as a 2×N array (independent-variable values along one row, fitted values along the other).
Combining elements#
Pass all elements as a dictionary to client.pipeline.create():
pipeline = client.pipeline.create({
"elements": {
"entry": entry_config,
"fit data": datafit_config,
},
})
print(f"Pipeline ID: {pipeline.id}")
Polling for results#
Pipelines run asynchronously. Poll client.pipeline.get() until the status
is completed or failed:
import time
while True:
pipeline = client.pipeline.get(pipeline.id)
print(f"Status: {pipeline.status}")
if pipeline.status == "completed":
result = client.pipeline.result(pipeline.id)
print("Fitted parameters:", result.element_results["fit data"])
break
elif pipeline.status == "failed":
print("Pipeline failed:", pipeline.error)
break
time.sleep(2)
Listing pipelines#
# All pipelines
pipelines = client.pipeline.list()
# Filter by project
pipelines = client.pipeline.list(project_id="...", limit=10)
Data sources#
Pipeline elements can load data from several sources:
Prefix |
Description |
|---|---|
|
Measurement stored in Ionworks |
|
Local CSV file |
|
Folder of CSV files |
Next steps#
To run forward simulations instead of fitting to data, see Simulations.