Skip to main content

Python client for interacting with the Ionworks API

Project description

Ionworks API Client

⚠️ Warning: This client is under active development and the API may change without notice.

A Python client for interacting with the Ionworks API.

Installation

  1. Clone this repository
  2. Install the package in editable mode:
pip install -e .
  1. Get your API key from the Ionworks account settings and set it as the IONWORKS_API_KEY environment variable (or in a .env file).

Usage

Basic usage example:

from ionworks import Ionworks

# Initialize client (uses IONWORKS_API_KEY from environment/.env file)
client = Ionworks()

# or provide credentials directly
client = Ionworks(api_key="your_key")

# Check API health
health = client.health_check()
print(health)

Uploading data to the Ionworks app

Uploading data to the Ionworks app follows a three-step process:

  1. Create a cell spec (or get an existing one)
  2. Create a cell instance with the spec id
  3. Upload measurement(s) with time series data using the instance id

Given time series data, the data can be uploaded as follows:

from ionworks import Ionworks
import pandas as pd

client = Ionworks()

# Step 1: Create or get a cell specification
cell_spec = client.cell_spec.create_or_get(
    {
        "name": "NCM622/Graphite Coin Cell",
        "form_factor": "R2032",
        "manufacturer": "Custom Cells",
        "ratings": {
            "capacity": {"value": 0.002, "unit": "A*h"},
            "voltage_min": {"value": 2.5, "unit": "V"},
            "voltage_max": {"value": 4.2, "unit": "V"},
        },
        "cathode": {
            "properties": {"loading": {"value": 12.3, "unit": "mg/cm**2"}},
            "material": {"name": "NCM622", "manufacturer": "BASF"},
        },
        "anode": {
            "properties": {"loading": {"value": 6.5, "unit": "mg/cm**2"}},
            "material": {"name": "Graphite", "manufacturer": "Customcells"},
        },
    }
)

# Step 2: Create or get a cell instance
cell_instance = client.cell_instance.create_or_get(
    cell_spec.id,
    {
        "name": "NCM622-GR-001",
        "batch": "BATCH-2024-001",
        "date_manufactured": "2024-01-20",
        "measured_properties": {
            "cathode": {"loading": {"value": 12.1, "unit": "mg/cm**2"}},
            "anode": {"loading": {"value": 6.4, "unit": "mg/cm**2"}},
        },
    },
)

# Step 3: Upload measurement with time series data
time_series = pd.DataFrame(
    {
        "Time [s]": [0, 1, 2, 3, 4, 5],
        "Voltage [V]": [3.0, 3.2, 3.5, 3.8, 4.0, 4.2],
        "Current [A]": [0.002, 0.002, 0.002, 0.002, 0.002, 0.002],
        "Step count": [0, 0, 0, 1, 1, 1],
        "Cycle count": [0, 0, 0, 0, 0, 0],
        "Step from cycler": [1, 1, 1, 2, 2, 2],
        "Cycle from cycler": [0, 0, 0, 0, 0, 0],
    }
)

measurement_data = {
    "measurement": {
        "name": "Formation Cycle 1",
        "protocol": {
            "name": "CC-CV charge at C/10 to 4.2V",
            "ambient_temperature_degc": 25,
        },
        "test_setup": {
            "cycler": "Biologic VMP3",
            "operator": "Jane Smith",
        },
        "notes": "Formation cycle - first charge",
    },
    "time_series": time_series,
}

measurement_bundle = client.cell_measurement.create(
    cell_instance.id, measurement_data
)

print(f"Created measurement: {measurement_bundle.measurement.name}")
print(f"Steps created: {measurement_bundle.steps_created}")

Reading cell data

from ionworks import Ionworks

client = Ionworks()

# List all cell specifications
specs = client.cell_spec.list()
for spec in specs[:5]:
    print(f"  - {spec.name} (form_factor: {spec.form_factor})")

# Get a specific cell spec with full nested data
full_spec = client.cell_spec.get(spec_id)
print(f"Capacity: {full_spec.ratings['capacity']['value']} "
      f"{full_spec.ratings['capacity']['unit']}")

# Get cell instance by slug
instance = client.cell_instance.get_by_slug("ncm622-gr-001")

# List measurements for an instance
measurements = client.cell_measurement.list(instance.id)

# Get measurement detail with time series
measurement_detail = client.cell_measurement.detail(measurement_id)
print(f"Time series shape: {measurement_detail.time_series.shape}")

Running pipelines

Pipelines allow you to run complex workflows combining data fitting, calculations, and validations. A pipeline consists of named elements, where each element has an element_type and configuration specific to that type.

Recommended workflow: First upload your experimental data using the cell measurement API (see "Uploading data to the Ionworks app" above), then reference it in your pipeline using the db:<measurement_id> format. This ensures your data is stored and versioned in the database.

Available element types:

  • entry: Provide initial parameter values
  • data_fit: Fit model parameters to experimental data
  • calculation: Run calculations (e.g., OCP fitting)
  • validation: Validate model against data
import time
from ionworks import Ionworks

client = Ionworks()

# First, upload your data (see "Uploading data to the Ionworks app" section)
# Then get the measurement ID to reference in the pipeline
measurements = client.cell_measurement.list(cell_instance_id)
measurement_id = measurements[0].id  # or find the specific measurement you need

# Define entry configuration with initial parameter values
entry_config = {
    "values": {
        "Negative particle diffusivity [m2.s-1]": 3.3e-14,
        "Positive particle diffusivity [m2.s-1]": 4e-15,
        # ... other parameters
    }
}

# Define datafit configuration - reference uploaded data with db:<measurement_id>
datafit_config = {
    "objectives": {
        "test_1C": {
            "objective": "CurrentDriven",
            "model": {"type": "SPMe"},
            "data": f"db:{measurement_id}",  # Reference data from database
            "custom_parameters": {"Ambient temperature [K]": "initial_temperature"},
        },
    },
    "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"},
}

# Create pipeline config with named elements
pipeline_config = {
    "elements": {
        "entry": {**entry_config, "element_type": "entry"},
        "fit data": {**datafit_config, "element_type": "data_fit"},
    },
}

# Submit pipeline
pipeline = client.pipeline.create(pipeline_config)
print(f"Pipeline submitted: {pipeline.id}")

# Poll for completion
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)

Running simulations

The client supports running battery simulations using the Universal Cycler Protocol (UCP) format:

from ionworks import Ionworks

client = Ionworks()

# Define a charge/discharge protocol in YAML format
protocol_yaml = """global:
  initial_state_type: soc_percentage
  initial_state_value: 50
  initial_temperature: 25.0
steps:
  - Charge:
      mode: C-rate
      value: "0.6"
      ends:
        - Voltage > 4.2
  - Rest:
      duration: 3600
  - Discharge:
      mode: C-rate
      value: "0.5"
      ends:
        - Voltage < 2.5
"""

# Create simulation with quick model
config = {
    "parameterized_model": {
        "quick_model": {"capacity": 1.0, "chemistry": "NMC/Graphite"}
    },
    "protocol_experiment": {
        "protocol": protocol_yaml,
        "name": "NMC Charge Discharge Protocol",
    },
}

result = client.simulation.protocol(config)
print(f"Simulation ID: {result.simulation_id}")

# Wait for completion
simulation = client.simulation.wait_for_completion(
    result.simulation_id, timeout=60, poll_interval=2
)

# Get results
simulation_data = client.simulation.get_result(result.simulation_id)
time_series = simulation_data.get("time_series", {})

Error Handling

The client will raise exceptions in the following cases:

  • Missing API credentials
  • Invalid API credentials
  • API request errors (will raise IonworksError with details)

Make sure to handle these exceptions appropriately in your code.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ionworks_api-0.1.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ionworks_api-0.1.0-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file ionworks_api-0.1.0.tar.gz.

File metadata

  • Download URL: ionworks_api-0.1.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ionworks_api-0.1.0.tar.gz
Algorithm Hash digest
SHA256 482bde5ba40aba7c459b86541658b655cb16041d01a73a5c7c45b17db1e18c64
MD5 512e24a8724d73ae9686a116dd4d11bf
BLAKE2b-256 08a6cd606f074acb168647adea2fcda09fe59dc769d4077eb1e60e765b157cd5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ionworks_api-0.1.0.tar.gz:

Publisher: publish.yml on ionworks/ionworks-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ionworks_api-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ionworks_api-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ionworks_api-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d550884837e51ae43d8fdf3c56d0593f33c8d2a026dcf52cbed2fe8d326612a3
MD5 cb3922e99d8a7722f11e050ad4568735
BLAKE2b-256 2b31d3f18727ac8165a540376bd8c1b43c57389d6365dcbb1574ba9e2f826a58

See more details on using hashes here.

Provenance

The following attestation bundles were made for ionworks_api-0.1.0-py3-none-any.whl:

Publisher: publish.yml on ionworks/ionworks-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page