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

# 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
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 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.1.5.tar.gz (25.9 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.5-py3-none-any.whl (32.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ionworks_api-0.1.5.tar.gz
  • Upload date:
  • Size: 25.9 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.5.tar.gz
Algorithm Hash digest
SHA256 24596f502ff087ce83bba546163f14ff333a51751dc53f0079dbda22efbe246e
MD5 c78e402b2848d32d13f323427fce8756
BLAKE2b-256 d60f035c3d255d4ada68c4715f5d19bfff1de4ff074e5838f57e129d67a588d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for ionworks_api-0.1.5.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.5-py3-none-any.whl.

File metadata

  • Download URL: ionworks_api-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 32.7 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 bdd20aa479a0d1979146c2c58c37c684b64c2a3dd5d459e2df6c6c139aca5bd4
MD5 14df0a3b519e16102b528ca1f8268053
BLAKE2b-256 846729256e2b47201e1fcd89a11a8fbf97581e78388ceb315d7db1ec51ae65e5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ionworks_api-0.1.5-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