Skip to content

stanford-developers/steer-core

Repository files navigation

steer-core

Tests License: AGPL v3 Python 3.10+ Documentation

Base utilities for the STEER / OpenCell platform: the mixin framework (validation, serialization, plotting, geometry, change propagation), shared constants, recalculation decorators, and the DataManager REST API client. Every domain class in the STEER ecosystem — materials, electrodes, cells — is built by composing the mixins in this package.


Table of Contents


Install

pip install steer-core

Or from source:

git clone https://github.com/stanford-developers/steer-core.git
cd steer-core
pip install -e .

Requires Python >= 3.10.


Quick Start

Domain classes are built by composing mixins:

from steer_core import ValidationMixin, SerializerMixin, DunderMixin

class MyComponent(ValidationMixin, SerializerMixin, DunderMixin):
    def __init__(self, name: str, mass: float):
        self.validate_string(name, "name")
        self.validate_positive_float(mass, "mass")
        self._name = name
        self._mass = mass

    @property
    def name(self) -> str:
        return self._name

    @property
    def mass(self) -> float:
        return self._mass

comp = MyComponent("cathode", 0.5)
data = comp.serialize()                      # bytes (MessagePack + LZ4)
restored = MyComponent.deserialize(data)
assert comp == restored                      # property-aware equality from DunderMixin

Mixins

Seven mixins are exported at the top level:

from steer_core import (
    ColorMixin,
    CoordinateMixin,
    DataMixin,
    DunderMixin,
    PlotterMixin,
    SerializerMixin,
    ValidationMixin,
)

The rest are imported from their submodules (e.g. from steer_core.Mixins.Propagation import PropagationMixin).

ValidationMixin

Static type and value validators that raise TypeError/ValueError with consistent messages. Used in every setter across the ecosystem.

from steer_core import ValidationMixin

ValidationMixin.validate_type(value, (int, float), "thickness")
ValidationMixin.validate_positive_float(thickness, "thickness")
ValidationMixin.validate_fraction(porosity, "porosity")          # [0, 1]
ValidationMixin.validate_percentage(efficiency, "efficiency")    # [0, 100]
ValidationMixin.validate_string(name, "name")
ValidationMixin.validate_datum(datum)                            # 3-element numeric tuple
ValidationMixin.validate_pandas_dataframe(df, "data", column_names=["x", "y"])
ValidationMixin.validate_enum_string(mode, ControlMode, "mode")

SerializerMixin

Binary serialization with MessagePack + LZ4 compression, and database loading. Handles nested objects, numpy arrays, pandas DataFrames, datetime, Enum, and object-keyed dicts.

Method What it does
serialize(compress=True) Instance → bytes
deserialize(data) (classmethod) bytes → instance (class path stored in payload)
from_database(name, table_name=None) (classmethod) Load a named object from the database backend (see Development vs Production Mode)
_to_dict() / _from_dict(data) Override hooks for custom serialization
blob = cell.serialize()
restored = Cell.deserialize(blob)

# Requires a _table_name on the subclass:
material = CathodeMaterial.from_database("LFP")

DunderMixin

Property-aware comparison and string representation.

  • __eq__ — deep equality over all public @property values (numpy arrays, DataFrames, and nested objects compared correctly; Plotly traces skipped)
  • __str__ / __repr__ClassName (name) when the object has a .name
  • __hash__ — identity-based, safe for mutable objects

PropagationMixin

Parent-child change propagation for hierarchical models (cell → assembly → electrode → formulation → material). Lives in steer_core.Mixins.Propagation.

Member What it does
propagating_setter(attr_name=None, deepcopy=False) Setter decorator: manages parent links when a child is assigned
update() Re-run the parent's setter for this object (triggers recalculation)
propagate_changes() Bubble updates all the way to the root object
batch_updates() Context manager: defer recalculation until exit
from steer_core.Mixins.Propagation import PropagationMixin, propagating_setter

class Electrode(PropagationMixin, ...):
    @property
    def formulation(self):
        return self._formulation

    @formulation.setter
    @propagating_setter()
    def formulation(self, value):
        self._formulation = value

# Change a leaf, recompute the whole tree:
formulation.active_material_fraction = 0.97
formulation.propagate_changes()

# Batch multiple changes with a single recalculation:
with cell.batch_updates():
    cell.diameter = 21
    cell.height = 70

PlotterMixin

Plotly figure builders and shared layout presets used by all STEER visualizations.

  • Layout presetsDEFAULT_PALETTE, SCATTER_X_AXIS / SCATTER_Y_AXIS, SCHEMATIC_X/Y/Z_AXIS, BOTTOM_LEGEND
  • Domain helperscreate_component_trace() (filled cross-section traces), plot_breakdown_sunburst() (mass/cost roll-ups)
  • Generic plotsplot_scatter, plot_bar, plot_histogram, plot_pdf, plot_box, plot_violin, plot_radar, plot_correlation_heatmap, and grouped variants — all return plotly.graph_objects.Figure
fig = PlotterMixin.plot_breakdown_sunburst(cell.mass_breakdown, title="Mass", unit="g")
fig.show()

CoordinateMixin

Static 2D/3D geometry utilities built on numpy and shapely.

Method What it does
rotate_coordinates(coords, axis, angle, center=None) Rotate (N,2) or (N,3) points about x/y/z
get_area_from_points(x, y) Shoelace area (handles NaN-separated segments)
get_radius_of_points(coords) Minimum bounding circle
build_square_array / build_circle_array Boundary point generators
extrude_footprint(x, y, datum, thickness) 2D footprint → 3D solid coordinates
get_coordinate_intersection(coords1, coords2) Polygon intersection area
order_coordinates_clockwise(df, plane="xy") Sort boundary points clockwise

ColorMixin

Color conversion and manipulation for Plotly figures: rgb_tuple_to_hex(), get_colorway(color1, color2, n) (n-step gradients), adjust_fill_opacity(), adjust_trace_opacity(), get_color_format().

DataMixin

Numeric data helpers: enforce_monotonicity(array) (PCHIP-smoothed monotonic curves, used for voltage-capacity data) and sum_breakdowns(components, breakdown_type) (recursive roll-up of mass / cost breakdown dicts across component trees).

DatumMixin

Positional datum handling for components placed in 3D space. Stores the datum in meters internally, exposes millimeters through datum, datum_x, datum_y, datum_z properties. Lives in steer_core.Mixins.Datum.

DateTimeMixin

Datetime parsing and arithmetic with the STEER standard formats (YYYY-MM-DD-HH / YYYY-MM-DD): str_to_datetime(), datetime_to_str(), shift_years(), shift_months() (calendar-aware), validate_end_after_start(). Lives in steer_core.Mixins.DateTime.

ThermodynamicsMixin

Basic thermodynamic relations: calculate_antoine_pressure(T, A, B, C), calculate_antoine_temperature(P, A, B, C), and calculate_ideal_gas_density(P, T, MW). Lives in steer_core.Mixins.Thermodynamics.


Constants

Module-level constants shared across the ecosystem:

from steer_core.Constants.Units import MM_TO_M, M_TO_MM, KG_TO_G, J_TO_WH
from steer_core.Constants.Universal import PI, R_GAS, GRAVITY, STANDARD_PRESSURE
from steer_core.Constants.Format import DEFAULT_HOUR_FMT, DEFAULT_DAY_FMT

thickness_m = thickness_mm * MM_TO_M
Module Contents
Constants.Units Unit conversion factors — mass (KG_TO_G), length (M_TO_MM, UM_TO_M), time (H_TO_S), energy (J_TO_WH, KW_TO_W), pressure (BAR_TO_PA), temperature (C_TO_K), currency, and angles. Multiply a source-unit value by the factor to get the target unit.
Constants.Universal Physical constants: PI, TWO_PI, R_GAS (8.3145 J/mol/K), GRAVITY, STANDARD_PRESSURE, STANDARD_TEMPERATURE
Constants.Format Standard datetime format strings: DEFAULT_HOUR_FMT (%Y-%m-%d-%H), DEFAULT_DAY_FMT (%Y-%m-%d)

Decorators

Setter decorators that trigger recalculation of derived properties after an attribute changes.

from steer_core.Decorators.General import recalculate, calculate_all_properties
from steer_core.Decorators.Coordinates import calculate_coordinates

class Electrode(...):
    @thickness.setter
    @calculate_all_properties        # calls self._calculate_all_properties() after the set
    def thickness(self, value):
        self._thickness = value

    @datum.setter
    @calculate_coordinates           # calls self._calculate_coordinates() after the set
    def datum(self, value):
        self._datum = value
Decorator Module Triggers
recalculate(*names, requires=None) Decorators.General Factory — calls self._calculate_<name>() for each name, optionally gated on attribute predicates
calculate_all_properties Decorators.General _calculate_all_properties()
calculate_bulk_properties Decorators.General _calculate_bulk_properties()
calculate_coordinates Decorators.Coordinates _calculate_coordinates()
calculate_areas Decorators.Coordinates _calculate_coordinates() + _calculate_areas()
calculate_volumes Decorators.Coordinates _calculate_bulk_properties() + _calculate_coordinates()

Environment Variables

Variable Required Default Description
OPENCELL_ENV No development development = local SQLite, no auth. production = REST API + Cognito auth.
API_URL In production Base URL of the deployed REST API (e.g. https://api.opencell.example.com/production)
API_TIMEOUT No 30 HTTP request timeout in seconds

Development vs Production Mode

Controlled by the OPENCELL_ENV environment variable. The helper is_development() from steer_core.Data is the single source of truth — use it anywhere you need to branch on mode.

from steer_core.Data import is_development

if is_development():
    # local SQLite path
else:
    # REST API path

Development mode (OPENCELL_ENV=development or unset)

  • SerializerMixin.from_database() uses the local SQLite database via steer_opencell_data.DataManager
  • No network calls, works fully offline
  • Requires steer-opencell-data installed with database.db
  • Use this when developing new cells locally before publishing via the CLI migration tool (steer-opencell-data CLI)

Production mode (OPENCELL_ENV=production)

  • SerializerMixin.from_database() uses the REST API via steer_core.Data.DataManager
  • Requires API_URL pointing to the deployed Lambda endpoint
  • JWT token passed automatically for authenticated operations (DataManager.set_token())
  • Logs API calls and S3 downloads to the steer_core.DataManager logger

DataManager REST Client

steer_core.Data.DataManager — drop-in replacement for the SQLite-based DataManager. Same interface, talks to the REST API + S3 instead.

Key methods

Method What it does
get_data(table, condition="name='X'") Fetch item + download blob from S3 presigned URL
get_data(table) (no condition) List items — metadata only, no blob
get_unique_values(table, column) List unique values from API
get_table_names() List available tables
insert_data(table, df) Upload blob to S3 via presigned URL
remove_data(table, condition) Soft-delete via API
set_token(token) Set JWT for authenticated requests

Domain-specific convenience methods (e.g. get_cathode_materials(), fork_cell(), publish_cell(), check_name_available()) live in OpenCellDataManager in the steer-opencell-design package, which subclasses this client.

Exceptions

Exception HTTP Status When
DataManagerError Base class / missing API_URL
APIError 5xx Server error
AuthenticationError 401 Missing or invalid token
ForbiddenError 403 Insufficient permissions
NotFoundError 404 Resource not found
ConflictError 409 Name already taken (fork/publish)

Logging

API calls and S3 downloads are logged to the steer_core.DataManager logger:

[steer_core.DataManager] [API] GET /materials/tape_materials/Kapton -> 200 (164 ms)
[steer_core.DataManager] [S3] Downloaded 0.2 KB in 499 ms

STEER Ecosystem

steer-core is the foundation of the STEER platform:

Package Role
steer-core This package. The mixin framework shared by all STEER packages — validation, serialization, coordinate systems, change propagation, Plotly-based plotting, and database access.
steer-materials Base material classes with from_database() support, volumetric tracking, and metal subclasses.
steer-opencell-design The cell design API that composes materials and components into complete virtual battery cells with cost, mass, and electrochemical calculations.
steer-opencell-data The open dataset: local SQLite database of materials, reference cell designs, and commercial cell teardowns, plus the scripts that build it.

Documentation

Full documentation is available at stanford-developers.github.io/steer-core.

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Citation

If you use this software, please cite it using the metadata in CITATION.cff.

License

steer-core is dual-licensed:

See LICENSE for full terms.

Contributions require signing a Contributor License Agreement.

About

Foundational Python utilities for the OpenCell platform: shared mixins (serialization, validation, plotting), decorators, and a REST client for the OpenCell data API, with seamless switching between local SQLite and the production backend.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages