Skip to main content
May 11, 2026
Custom PyBaMM model + Li-S support, ECM capacity co-optimization, default project for the Python SDK, structured validation issues

Custom PyBaMM models with Lithium-Sulfur chemistry

The /models/upload-custom endpoint now accepts a chemistry field (defaulting to lithium_ion), and Li-S models get a chemistry-aware initial-state shim plus tighter IDAKLU tolerances when they run. The manage-projects SDK skill documents the full upload workflow — pybamm.Serialise().save_custom_model(filename=...) → multipart upload → client.model.get(id) returns is_custom_model: true — including the EventType-not-JSON-serializable gotcha that hits anyone trying to json.dumps the dict from serialise_custom_model() directly.

ECM fit: capacity co-optimization and per-segment initial SoC

Several interlocking improvements to the project-scoped ECM fit. Supplying an ocv_soc_curve (and optional bounds_capacity) lets you co-optimize cell capacity Q jointly with the RC beta knots in the outer least-squares loop instead of pinning Q to a single seed; on a 25 °C rate-test trace the fitted capacity now lands within 0.9 % of the coulomb-counting truth across all knot schedules. initial_soc accepts a list (one entry per measurement) so multi-measurement fits reset SoC at each segment boundary instead of integrating coulombs across the gaps; if you omit it, the new auto-seed routine refines each segment’s soc0 by root-finding V[s] = OCV(soc0) − I[s]·R0(soc0). num_knots, num_knots_r0, knot_schedule, and clamp_max_ratio are now first-class parameters on /fit-from-measurements and /fit-from-file. The boundary clamp default also loosened from max_ratio=1.0 to 10.0, which was collapsing R0 and triggering pybamm IDAKLU CONV_FAIL on rate-test forward sims.

Default project for the Python SDK

The Ionworks client now resolves a default project_id at construction time from a project_id= argument or the new IONWORKS_PROJECT_ID environment variable, so callers no longer have to thread project_id through every call. The previous PROJECT_ID env var still works but emits a DeprecationWarning. All client.study.* methods take project_id as an optional keyword (after the resource ID) defaulting to the client value, and pipelines and optimizations auto-inject it into payloads.

Structured measurement-validation issues

MeasurementValidationError.errors is now list[ValidationIssue] — a frozen dataclass carrying a stable IssueCode (StrEnum), severity, human-readable message, and JSON-native payload. Downstream code can branch on check identity via e.has_code(IssueCode.CURRENT_SIGN_REVERSED) instead of grepping the message string. ionworksdata’s auto-fix path now keys off the new codes; IssueCode and ValidationIssue are re-exported from the top-level ionworks package.
Improvements
  • organization_id is now NOT NULL on ~15 tables, all RLS policies have been rewritten to read it directly (replacing the has_permission_via_* function chain), and composite (project_id, organization_id) foreign keys prevent org drift on project-scoped tables.
  • Simulation boards CRUD moved to a proper backend API at /projects/{project_id}/studies/{study_id}/simulation_boards with organization_id resolved server-side, fixing a blank Visualization tab on stage where direct Supabase inserts were silently rejected by the stricter RLS.
  • Optimization Performance Detail and Performance Summary tabs now surface buried validation_warning / validation_not_supported issues as top-level alerts above the tabs, with info “no data” alerts inside the tabs for the rare empty-but-valid case.
  • Defensive UX in the Visualization tab: the Data/Visualization toggle stays visible even when no board is available, with a warning alert prompting the switch back to Data instead of trapping the user on a blank page.
Fixes
  • The single simulation result page no longer flashes “Simulation not found” before the data loads on a fresh navigation.
Improvements
  • ionworks-schema gained Constraint, Penalty, CMAESOptions, PSOOptions, DEOptions, LatinHypercube, and Uniform schema classes that pipeline already had, plus Field(description=...) enrichment on ~40 pilot-touched classes across objectives, data fits, parameter estimators, regularizers, and distribution samplers. A new Sphinx docs skeleton auto-generates a reference page per submodule and cross-links each schema class to the matching ionworkspipeline page via intersphinx.
Fixes
  • EmptySolution AttributeError (raised when SUNDIALS gives up at IC for a bad parameter combination) now routes to the existing fit-failure penalty path instead of crashing the whole datafit. Cloud fits stay alive and the offending sample just gets a huge cost.
Improvements
  • New client.urls.measurement(measurement_id, project_id) helper returns the web app deep link for a measurement, so callers don’t have to hand-build URLs against frontend/src/routes/paths.ts.
Improvements
  • manage-projects documents the /models/upload-custom multipart workflow and the Model / ParameterizedModel disambiguation.
  • upload-data and other validation-aware skills updated to reference the new IssueCode / ValidationIssue API and the e.has_code(...) pattern instead of substring-matching error strings.