API reference#
The public API is importable from the top-level battwin package; the modules below are where the objects live. Anything not documented here (names starting with _) is internal.
battwin.envelope: the document model#
Battery Twin Envelope (BTE) document model.
A twin envelope is an immutable, serializable JSON document that composes existing open artifacts into one exchangeable representation of a battery digital twin:
identity -> who/what the twin mirrors (serials, passport IDs, BattINFO IRIs)
specification -> the cell/pack spec, by reference to a BattINFO record
models -> parameter sets (BPX/BattMo/…) with validity windows
state -> estimated states (SoC/SoH/…) with provenance
data -> links to time-series (BDF datasets, live feeds)
extensions -> namespaced vendor/tool-specific facts (non-canonical)
version -> immutable version chain (content-hash linked)
The envelope deliberately references other resources by IRI/path instead of importing their toolchains: BattINFO records, BPX files, and BDF datasets are linked, never embedded code dependencies. Executing models, hosting twins, and synchronizing live state are out of scope (see SPEC.md, “Non-goals”).
- battwin.envelope.BTE_VERSION = '0.1.1'#
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
- pydantic model battwin.envelope.TwinEnvelope[source]#
The top-level Battery Twin Envelope document.
extensionscarries namespaced, non-canonical facts (SPEC.md §3.8); it participates incanonical_json()andcontent_hash()like every other field.- Fields:
- field specification: Specification | None = None#
- field models: list[ModelBinding] [Optional]#
- field state: StateSnapshot | None = None#
- field state_history: list[StateSnapshot] [Optional]#
- field provenance: Provenance [Required]#
- field extensions: dict[str, Any] | None = None#
Vendor/tool-specific facts that are not (yet) canonical. Keys MUST be namespaced as ‘<prefix>:<name>’ (SPEC.md §3.8); values are arbitrary non-null JSON.
- field version: VersionInfo [Required]#
- pydantic model battwin.envelope.Identity[source]#
What physical (or virtual) battery this twin mirrors.
- Fields:
- field label: str [Required]#
Human-readable name of the twinned battery.
- Constraints:
min_length = 1
- field battinfo_iri: str | None = None#
IRI of the cell/cell-instance record in a BattINFO registry, e.g. https://w3id.org/battinfo/cell/<id>.
- pydantic model battwin.envelope.Specification[source]#
The design-level description of the battery, by reference where possible.
- Fields:
- pydantic model battwin.envelope.ModelBinding[source]#
A parameter set / model attached to the twin.
Exactly one of source (path or IRI) or inline (embedded document, e.g. a BPX JSON object) must be provided.
- Fields:
- field kind: Literal['bpx', 'battmo', 'pybamm', 'custom'] [Required]#
- field solver_hint: str | None = None#
Non-binding hint for implementations, e.g. ‘pybamm’ or ‘battmo’.
- field validity: ValidityWindow | None = None#
- pydantic model battwin.envelope.ValidityWindow[source]#
Operating window within which a model binding is considered valid.
- Fields:
- pydantic model battwin.envelope.StateSnapshot[source]#
An estimated state of the battery at a point in time.
- Fields:
- field as_of: UTCDateTime [Required]#
- Constraints:
func = <function _rfc3339_utc at 0x7f47046640e0>
return_type = <class ‘str’>
when_used = json
- field energy_throughput_kwh: float | None = None#
Lifetime cumulative energy throughput, in kWh.
- Constraints:
ge = 0
- pydantic model battwin.envelope.DataLink[source]#
A link to time-series or other data belonging to the twin.
- field kind: Literal['bdf', 'feed', 'other'] [Required]#
- pydantic model battwin.envelope.Provenance[source]#
-
- field created: UTCDateTime [Required]#
- Constraints:
func = <function _rfc3339_utc at 0x7f47046640e0>
return_type = <class ‘str’>
when_used = json
- pydantic model battwin.envelope.VersionInfo[source]#
Immutable version chain: previous is the content hash of the prior document.
- field timestamp: UTCDateTime [Required]#
- Constraints:
func = <function _rfc3339_utc at 0x7f47046640e0>
return_type = <class ‘str’>
when_used = json
battwin.io: reading and writing#
Load and save Battery Twin Envelope documents.
- battwin.io.from_dict(doc)[source]#
Build an envelope from a parsed JSON document.
Accepts both plain-JSON and JSON-LD renderings:
@contextand@typeare dropped, and@idis used asidwhen the plain key is absent.- Parameters:
- Return type:
- battwin.io.load(path)[source]#
Load an envelope from a
.twin.json/.json/.jsonldfile.- Parameters:
- Return type:
battwin.validate: validation#
Validation of Battery Twin Envelope documents.
Three layers, matching the spec:
JSON Schema (
battwin/schemas/twin-envelope.schema.json) — the public, language-neutral contract. Anyone can validate an envelope without Python.Model rules (pydantic,
battwin.envelope) — the reference implementation’s stricter semantic checks (e.g. a model binding must have exactly one ofsource/inline).SHACL shapes (
battwin/shapes/twin-envelope.shapes.ttl, optional) — graph-level constraints on the JSON-LD rendering, so envelopes exchanged as RDF are checkable too. Requires thebattwin[shacl]extra.
validate_dict/validate_file run the first two — plus the
version-declaration rule of SPEC.md §3.1 (a document must declare a
bte_version that defines every field it uses) — and the SHACL layer when
called with shacl=True. They return a flat list of human-readable problem
strings (empty list = valid).
- battwin.validate.load_context()[source]#
Return the packaged BTE JSON-LD context (the value of
@context).
- battwin.validate.load_shapes()[source]#
Return the packaged BTE SHACL shapes as Turtle text.
- Return type:
- battwin.validate.shacl_problems(doc)[source]#
Validate the JSON-LD rendering of
docagainst the packaged shapes.Plain-JSON documents are wrapped with the packaged
@context(and@id/@type) first; documents that already carry@contextare parsed as-is. Returns problems formatted like the other layers, prefixedshacl:. Requires the optional dependency pyshacl.
battwin.battinfo: BattINFO helpers#
Seed a Battery Twin Envelope from a BattINFO registry record.
envelope_from_battinfo dereferences a cell-spec IRI (e.g.
https://w3id.org/battinfo/spec/<id>), reads the identity facts out of the
returned record, and scaffolds a valid envelope whose specification
references the record by IRI – the envelope points at the registry, it does
not copy the record in.
Standard library only, by design: fetching a record is one HTTPS GET
returning JSON, so twinning a cell from its IRI works on a bare
pip install battwin. (The heavier [data] extra is for tabular data,
not for this.)
The record shapes handled here follow the battery-genome registry exports:
identity facts are looked up in metadata first, then in the
battinfo_records.*.product block; the literal string "unknown" is
treated as absent, so a sparse record seeds a sparse (but valid) envelope
rather than one full of placeholder values.
- battwin.battinfo.envelope_from_battinfo(iri, *, label=None, twin_id=None, chemistry=None, created_by=None, timestamp=None, fetch=None)[source]#
Scaffold an envelope for the cell described by a BattINFO record.
The record is dereferenced and its identity facts (name, manufacturer, model, chemistry, capacity/voltage when present) seed
identityandspecification;specification.battinfo_recordcarries the given IRI so consumers can re-resolve the source.labelandchemistryoverride what the record says (useful while a record is sparse).fetchinjects a record loader for tests (defaults tofetch_battinfo_record()).
- battwin.battinfo.fetch_battinfo_record(iri, *, timeout_s=30.0)[source]#
Dereference
iri(following redirects) and return the JSON record.Sends
Accept: application/json; w3id.org IRIs 303-redirect to the registry, which urllib follows. RaisesValueErrorfor a non-HTTP IRI or a non-object payload, and lets network errors (urllib.error.URLError, anOSErrorsubclass) propagate for the caller to surface.
battwin.ecm: ECM parameter sets#
ECM Parameter Set (ECM-PS) validation.
An ECM-PS document expresses equivalent-circuit-model parameters in a form
deliberately styled after BPX (Header/Parameterisation/State/Validation
sections, natural-language parameter names with bracketed SI units, values as
constants or interpolated tables), so that ECM-PS reads as the ECM
counterpart of a BPX file even though BPX itself defines no ECM model type.
Semantic grounding lives at spec level: each defined parameter name maps to a
class in the EMMO domain-equivalent-circuit-model ontology, and the Header
may carry a BattINFO record IRI. A twin attaches an ECM-PS through a model
binding whose payload (inline or the document behind source) is the
document itself.
battwin packages the ECM-PS JSON Schema validation-only: this module can
check that a payload is a well-formed ECM-PS document, and never evaluates
the model – execution belongs to PyBaMM/PyBOP and friends (SPEC.md §7).
The schema $id under the EMMO domain namespace is provisional until the
corresponding w3id redirects are registered.
- battwin.ecm.ecm_ps_problems(doc)[source]#
Validate a parsed ECM-PS document; returns problems (empty = valid).
Problem strings follow the envelope validators’ format, prefixed
ecm:. Only schema conformance is checked – cross-value consistency (e.g. that everyR{i}/C{i}up toNumber of RC elementsis present, or that table rows are equally long) is enforced by consumers such asbattwin.sim.build_thevenin().
battwin.sim: simulation (battwin[sim])#
Run a twin’s ECM model binding in PyBaMM (the battwin[sim] extra).
This is the execution half of the ECM story: battwin.ecm checks that a
binding’s payload is a well-formed ECM Parameter Set; this module turns that
payload into a pybamm.equivalent_circuit.Thevenin model and runs an
experiment against it. ECM-PS 0.2 is styled after BPX (Header/Parameterisation
sections, bracketed-unit parameter names, scalar-or-table values, Kelvin), and
the mapping here follows the parameter names’ own -> PyBaMM annotations in
the packaged schema.
The spec fence is unchanged: the format never specifies execution. This
module is an optional convenience of the reference SDK – pip install
"battwin[sim]" – and everything it computes flows back into the envelope
as ordinary spec objects (data links, state snapshots) via
TwinEnvelope.next_version().
Deliberate simplifications, surfaced in TheveninBuild.warnings or as
errors:
Open-circuit voltage [V]is the mean of the charge/discharge branches when both are present – PyBaMM’s basic Thevenin has a single OCV, so the hysteresis branches and decay rate are dropped (kept in the ECM-PS for round-trip).Expression-string values are not part of ECM-PS and are rejected with a clear error; only constants and 1-D/2-D interpolated tables are evaluated.
- class battwin.sim.TheveninBuild(model, parameter_values, options, warnings=<factory>)[source]#
A ready-to-run PyBaMM Thevenin model built from an ECM-PS document.
- battwin.sim.build_thevenin(ecm_ps, *, initial_soc=1.0, ambient_celsius=25.0)[source]#
Build a PyBaMM Thevenin model + parameter values from an ECM-PS 0.2 document.
Constants pass through; 1-D tables become SoC interpolants; 2-D tables become (temperature, SoC) interpolants (the document’s Kelvin axis is converted to the Celsius axis PyBaMM’s ECM callbacks use).
- battwin.sim.run_experiment(build, instructions, *, period_s=10.0)[source]#
Run a PyBaMM experiment against a built Thevenin model.
instructionsare PyBaMM experiment strings (e.g."Discharge at 1C until 2.5 V"). Returns plain column lists in BDF naming (positive current = charging, per the BDF sign convention – PyBaMM’s load-positive sign is flipped here) so callers can write a.bdf.csvand attach it to the envelope as a data link.
battwin.fit: parameter identification (battwin[fit])#
Fit a twin’s ECM parameters against measured data (the battwin[fit] extra).
This closes the loop the tutorials walk one way: a twin links measured data
(DataLink), and this module uses PyBOP to identify circuit parameters from
that data, returning a new ECM-PS document with the fitted constants and
the fit’s provenance recorded in the document’s User-defined section. The
caller attaches the result to the twin as a new model binding via
TwinEnvelope.next_version() – outputs land back in the envelope as
ordinary spec objects, like everything else in the reference SDK.
Scope, stated plainly: parameters are fitted as constants (a fitted value
replaces whatever the base document carried for that name, including a 2-D
table – surfaced in FitResult.warnings). Identifying full
SoC/temperature lookup surfaces from one dataset is ill-posed and out of
scope. OCV curves are not fittable here either; they come from
characterization, not regression against a drive trace.
- class battwin.fit.FitResult(ecm_ps, fitted, rmse_volt, initial_rmse_volt, n_iterations, warnings=<factory>)[source]#
The outcome of
fit_thevenin().- Parameters:
- battwin.fit.fit_thevenin(ecm_ps, data, *, fit=('R0 [Ohm]',), initial=None, bounds=None, initial_soc=1.0, ambient_celsius=25.0, max_iterations=1000, source_data=None)[source]#
Fit Circuit parameters of an ECM-PS document to measured data.
datais a mapping of BDF-named columns (test_time_second,current_amperewith the BDF positive-=-charging sign, andvoltage_volt), e.g. the columns of a dataset the twin links –read_bdf()reads one from disk.fitnames the Circuit parameters to identify ("R0 [Ohm]","R1 [Ohm]","C1 [F]", …); each is fitted as a constant, starting frominitial(default: the base document’s value at ambient temperature and mid-SoC) withinbounds(default: a factor of 10 either side of the start).Returns a
FitResultwhoseecm_psis a new, schema-valid document;source_data, when given, is recorded in the fit provenance so the fitted model names the dataset it was calibrated against.