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

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

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.2.tar.gz (23.4 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.2-py3-none-any.whl (30.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ionworks_api-0.1.2.tar.gz
  • Upload date:
  • Size: 23.4 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.2.tar.gz
Algorithm Hash digest
SHA256 3ff4607d2040a6362fa6494cf208b678a112bca9ee6913b5f9c2f12b0f7ceec1
MD5 bebbf12f17a3b2bfbface499f46e05fc
BLAKE2b-256 a7fa4d3c4267db6cc1b9a44a210e28323a22c9596a4d18d5f1b724b8b1dfc7f1

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: ionworks_api-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 30.3 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9851e099719f02916fb940cba0d1872f6347d9cd114221d94101d69830b6da0a
MD5 1e2181e2f1899ba627d4675a9d028f21
BLAKE2b-256 e8416c71ac1a25e299f44c83539f24ccc818c330e5c14a8e3ef94e96d321d384

See more details on using hashes here.

Provenance

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