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

pip install ionworks-api

Then copy the example environment file and fill in your credentials:

cp .env.example .env

Get your API key from the Ionworks account settings and your project ID from your project settings page. See Environment Setup for details.

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")

# Customize timeout and retry behavior
# By default, the client uses a 10 second request timeout and will retry failed requests up to 5 times.
# You can override these defaults as shown below:
client = Ionworks(timeout=30, max_retries=3)  # 30s timeout, max 3 retries

# 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']}")

# List instances for a spec and pick the first
instances = client.cell_instance.list(spec_id)
instance_id = instances[0].id

# 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
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
            "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"},
}

# 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 and wait for completion
pipeline = client.pipeline.create(pipeline_config)
print(f"Pipeline submitted: {pipeline.id}")

pipeline = client.pipeline.wait_for_completion(pipeline.id, timeout=600)

if pipeline.status == "completed":
    result = client.pipeline.result(pipeline.id)
    print("Fitted parameters:", result.element_results["fit data"])

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", {})

Environment Setup

The client uses environment variables for configuration. Copy the example file and fill in your values:

cp .env.example .env
Variable Required Default Description
IONWORKS_API_KEY Yes API key from account settings
IONWORKS_API_URL No https://api.ionworks.com API base URL
PROJECT_ID For pipelines Project ID from your project settings page

The client loads .env automatically via python-dotenv.

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)

When HTTP errors occur, the client automatically prints the x-correlation-id header from the response (if present). This correlation ID helps trace requests in backend logs for debugging purposes.

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.3.3.tar.gz (40.8 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.3.3-py3-none-any.whl (48.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ionworks_api-0.3.3.tar.gz
  • Upload date:
  • Size: 40.8 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.3.3.tar.gz
Algorithm Hash digest
SHA256 1b312086743ef352b8b25019399115a7634e7c4160f247137d31e036d4906dcd
MD5 41e1db8675f6e90e375ba25ea3167e22
BLAKE2b-256 69c12ea093805b06111379b16b5cd4c913e8b0ff5e5f04473f1e78289c371f67

See more details on using hashes here.

Provenance

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

Publisher: release-package.yml on ionworks/ionworks-app

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.3.3-py3-none-any.whl.

File metadata

  • Download URL: ionworks_api-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 48.6 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.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 faa5047578402d26d9d4f8bf20a9e5c62fa0db611b0fdccc36022d79a5fe370e
MD5 1623661404c949d974de23961d451c86
BLAKE2b-256 8b75d6e171416e853cdf88e0d9669125b94c37a8a659d8f0bf62eff1978daff9

See more details on using hashes here.

Provenance

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

Publisher: release-package.yml on ionworks/ionworks-app

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