# Run an ECM simulation Turn a model binding's ECM Parameter Set into a PyBaMM Thevenin model, run experiments, and get BDF-named results ready to attach to the envelope. Requires the `sim` extra: ```bash pip install "battwin[sim]" ``` ## Build and run ```python import json from battwin.sim import build_thevenin, run_experiment ecm_ps = json.load(open("cell.ecm-ps.json")) build = build_thevenin(ecm_ps, initial_soc=1.0, ambient_celsius=25.0) for w in build.warnings: print("warning:", w) columns = run_experiment(build, ["Discharge at 1C until 2.5 V"], period_s=10.0) # columns: test_time_second, voltage_volt, current_ampere, # state_of_charge, surface_temperature_celsius ``` `instructions` are ordinary PyBaMM experiment strings, so multi-step protocols (`"Charge at C/2 until 4.2 V"`, `"Hold at 4.2 V until C/50"`, ...) work as-is. ## Behavior that matters Sign convention : Returned currents follow BDF (positive = charging); PyBaMM's load-positive sign is flipped for you. Values become interpolants : Constants pass straight through; 1-D tables become SoC interpolants; 2-D tables become (temperature, SoC) interpolants, with the document's Kelvin axis converted to the Celsius axis PyBaMM's ECM callbacks use. Expression strings are not part of [ECM-PS](../reference/ecm-ps.md) and are rejected with a clear error. Hysteresis is projected : PyBaMM's basic Thevenin has a single OCV, so when an ECM-PS carries charge and discharge branches, their mean is used (2-D branches are read at the temperature nearest ambient); the branches stay untouched in the document. This and any similar simplification is surfaced in `TheveninBuild.warnings`. Consistency is enforced at build time : `build_thevenin` raises a clear `ValueError` when the Circuit is missing an `R{i}`/`C{i}` pair implied by `Number of RC elements`, or when the OCV branches disagree about their SoC grid. ## Write the results back Simulation output goes back into the envelope as ordinary spec objects, keeping all runtime activity inside the hash-chained document: ```python from datetime import datetime, timezone from battwin import DataLink, StateSnapshot, load, save v1 = load("cell.twin.json") v2 = v1.next_version( data=list(v1.data) + [DataLink(kind="bdf", uri="sim/discharge_1c.bdf.csv", role="simulation")], state=StateSnapshot( as_of=datetime.now(timezone.utc), state_of_charge=columns["state_of_charge"][-1], method="ecm_simulation", source_data="sim/discharge_1c.bdf.csv", ), ) save(v2, "cell.v2.twin.json") ``` ```{admonition} PyBaMM telemetry :class: note PyBaMM includes opt-out usage telemetry (via `posthog`). To keep a local run from reporting usage, set `PYBAMM_DISABLE_TELEMETRY=true` before importing PyBaMM; see the [PyBaMM documentation](https://docs.pybamm.org/) for the current mechanism. ``` ## Related - The tutorial [Simulate a twin's ECM](../tutorials/simulate-ecm.md) walks the full workflow end to end with a real parameter set. - [Why simulation lives in an extra](../explanation/design.md) covers the spec fence this feature sits behind.