May 18, 2026
Material properties in Studio, native UCP simulation for design optimization, SimplePipeline workflow, global /search endpoint
Material properties in Studio
A new Materials section in the project sidebar lets you create materials within a project and attach measured property datasets (CSV / parquet) to each one. Upload, plot, edit, re-process, replace, and delete are all wired up, backed by a newmaterial_property_datasets table with composite
(project_id, organization_id) foreign keys and a dedicated Supabase
bucket. The Python SDK gains read-only client.material and
client.material_property_dataset sub-clients with list, get,
get_units, and get_data (returns a polars.DataFrame); the REST
surface supports signed-URL downloads, on-the-fly downsampling, and
x-range filtering. A new docs page covers the UI workflow and REST
endpoints.Native UCP simulation for design optimization
DesignObjective gained a backend="ucp" option (also selectable via
the IONWORKS_SIMULATION_BACKEND env var) that runs UCP protocols
natively inside the optimization loop instead of converting them to a
pybamm.Experiment. This preserves UCP features that the conversion
dropped — dynamic loops, conditionals, gotos, set_variable,
subroutines — and avoids the per-iteration parser overhead. EIS steps
are now rejected up front in design optimization (with a clear error
both in the frontend form and at the backend), because the UCP backend
does not yet support frequency-domain steps; standalone simulations
remain the path for EIS.SimplePipeline workflow
A new lightweight pipeline variant for configs with at most one expensive element (one data fit or one validation). The whole config runs end-to-end as a single Ray job on the batch queue instead of fanning out to child jobs. CRUD endpoints under/simple_pipelines (POST returns 202; LIST supports filters and
Supabase operator syntax; PATCH for name/description; cancel and
delete), plus a client.simple_pipeline SDK sub-client with
create, get, list, update, cancel, delete, and
wait_for_completion. Large validation outputs are written to
metadata storage instead of the DB record, and distributed evaluation
inside the single job is wired through a new _on_setup_complete
hook on DataFit.setup().Global search API
NewGET /search endpoint performs prefix full-text + substring
search across projects, studies, simulations, models, parameterized
models, optimizations, optimization templates, experiment templates,
pipelines, cell specifications, and materials within the authenticated
organization. Backed by Postgres tsvector columns + GIN indexes per
table, with all entity queries fanned out in parallel via
asyncio.gather. There is no frontend search bar in Studio yet — the
new docs page makes this explicit so you don’t go looking for one.Studio
Studio
Improvements
- Optimizations table: bulk Delete restored next to the existing
bulk Cancel action, gated by
optimization:delete, with a confirmation dialog that pluralizes correctly and per-row error toasts. - Protocol simulator: Download CSV button next to “Configure Plot” exports the full time-series plus step-level columns (cycle count, step number, protocol variables) expanded to match each time point, regardless of zoom.
- Time-series measurement plot: overlay multiple variables sharing the
same unit on either Y-axis via a
+button — unit-filtered dropdown, distinct color cycle per series, individual×to remove, and selecting a primary variable with a different unit clears incompatible extras. - ECM models now expose
Anode potential [V],Cathode potential [V], and their open-circuit counterparts so BioLogic three-electrode EWE / ECE control limits can be reproduced from a simulation. NewLFP/Li metalhalf-cell chemistry added to the parameter library and the cell configuration UI. - Hover tooltips standardized to 3 decimal places across Plotly and
Highcharts via
createBasePlotLayout; documented as a new frontend convention. - EIS Nyquist plot renders as markers-only scatter (no connecting lines), with a slightly larger marker.
- Cell-spec cascade delete batches up to 1000 storage paths per
bucket.remove()call and parallelises per-measurement folder deletes withSemaphore(16), withasyncio.gatherfor measurement-list fetches so one transient DB failure doesn’t abort cleanup for the others. - Supabase storage downloads now retry transient 5xx errors with exponential backoff (3 attempts, 0.5 s → 4 s, jittered) — fixes job failures where storage3 crashed on non-JSON 502 response bodies.
GET /jobs/{job_id}/metadataroute returns the parsed contents of a job’smetadata.json.gzblob, giving the Python SDK a path to large validation payloads (validation_results,validation_plot_config) that the legacy/pipelines/validations/{job_id}/resultendpoint could not reach.- Simulation submission unified to a two-step pattern
(
/protocols/parse-to-template→/simulations/with-template/batch). Removed the redundant/simulations/protocol,/simulations/protocol/batch, single/simulations/with-template, and/standalone-cycler/simulateendpoints, and dropped the transientcycler_protocol_resultstable.
- Simulation dedup: removed
cycler_protocol_record_id(which changes every parse session) from the simulation_options uniqueness key, so the “simulation already exists” path actually triggers and duplicate rows stop accumulating. - Measurement details: Cycles tab is visible again and the cycle
filter slider’s range is correct after the
Cycle number→Cycle countcolumn rename. - Measurements of type
propertiesorfilenow show an informational alert pointing to the details panel or the SDK instead of rendering empty time-series tabs.
Pipeline
Pipeline
Improvements
-
ionworks-schemais now the single validation boundary for parser inputs across the pipeline. Every pipeline class with a schema counterpart (~40 classes) gained afrom_schema(schema)classmethod; parsers calliws.X.model_validate(config)and construct runtime objects viafrom_schema. The auto-generatedConfigMixin.config_schema()is retired, and the SDK now depends onionworks-schemadirectly soPipelineClient.create()acceptsiws.Pipeline | dict. -
Standardized user-facing optimiser kwargs across all scipy wrappers:
max_iterationsreplacesmaxiter/max_nfev/iters/niter, andpopulation_sizereplacespopsizeonScipyDifferentialEvolution. Old names continue to work with aDeprecationWarning.DataFit.max_iterationsandFunctionTimeout.max_iterationsalign with the same name. -
ionworks_ucp.SolverErroris now registered inBaseObjective._acceptable_errors, so a transient UCP solver failure during differential evolution lands on the finite-penalty path instead of killing the optimization. Protocol and configuration errors remainValueError/RuntimeErrorso static bugs still surface. Fixes -
pybamm.Experimentperiodandtemperaturenow round-trip throughSerialise.serialise_experiment(fix shipped inpybamm 26.4.3).ExperimentStepConfigSchemaandExperimentConfigSchemaaccept the new field set (per-stepperiod,temperature,tags,description,direction,start_time,skip_ok; experiment-levelperiod,temperature,termination);durationalso accepts human-readable strings like"287 seconds". The previous_apply_dropped_fieldsworkaround is removed. -
SimplePipeline jobs run
DataFitin-process and now establish their own Ray connection (sharing_connect_to_ray_with_retrywith the child-job runner) so distributed evaluation actually fires; when the Ray connection fails the evaluator hook is skipped and DataFit falls back to its in-process path. Legacy element-type labels ("Data Fit","Direct Entry","datafit") are now canonicalized to wire discriminators at ingress.
Python API
Python API
Improvements
client.simple_pipelinesub-client for the new SimplePipeline workflow.client.protocol.convert(protocol, target)returns aConvertResultwithprimary_bytes,text(), andsave(dir)helpers — exports a UCP YAML protocol to a native vendor file (Maccor, Arbin, Neware, BioLogic BT-Test, or Novonix). Maccor returns any drive-cycle MWF assets alongside the primary file.client.job.get_metadata(job_id)returns the parsed contents of a job’smetadata.json.gz, giving the SDK access to large validation payloads the legacy result endpoint could not reach.
Protocol Simulator
Protocol Simulator
Improvements
- BioLogic
.mpsparser: User Profile (drive cycle) steps are now extracted from embedded Urban Profile Tables, or from sibling.txtfiles supplied viaadditional_contentwhen the.mpslacks embedded tables. Current sign is flipped on the way in so positive represents discharge for UCP/PyBaMM. - Arbin parser rewritten to keep the step list flat with raw gotos
instead of inferring loops from backward-goto patterns —
dynamic_experimentalready resolves gotos in a flat namespace and guards backward jumps viamax_backward_jumps. Fixes sibling backward gotos to the same target, cross-loop goto resolution, and digit-bearing formula labels likeF_EIS_10%_capacity_change. Pause steps emit UCP’s first-class auxiliaryPausestep. - More Arbin / Maccor step types recognized:
Arbin
Internal Resistance→Restwith aUserWarning,av_t/pv_chan_test_time/pv_chan_cv_stage_currentmapped to their UCP types, bracketedMV_UD[n]normalised, leading-negative current expressions classified asDischarge. MaccorUser Def CYCLE <op> Ntranslated to a UCPVariableEndagainst the runtimeCYCLEalias. - Per-step overhead trimmed substantially on long protocols. When the
model lacks
Temperature [degC]the per-step lookup skips pybamm’s O(N²) “did you mean…?”difflibsearch entirely (~41 ms per step); when the protocol contains no derivative ends,set_variable, or variable-driven goto targets, the per-step full-trace evaluation is skipped and_create_minimal_step_dfemits a single-row frame with onlyTime [s]. - New
ionworks_ucp.SolverErrorexception is raised for genuine pybamm solver failures; protocol and configuration errors keep their originalValueError/RuntimeErrortypes and just gain step context.
- Real Maccor
.MWFexports that include the ~28-line preamble plus aType\tMode\tValue\t…header row now parse —read_waveformscans for the header sentinel and skips up to and including it before handing the rest topd.read_csv. Files containing only data rows still parse unchanged.
Skills
Skills
Improvements
- New
run-simple-pipelinesskill walks through the SimplePipeline client end-to-end. process-data: clarified thatprotocolholds test conditions that affect the electrochemical outcome (temperature, C-rate, SoC, DoD, pressure) whiletest_setupholds physical logistics (cycler model, operator, lab, channel) that do not.test_setuplives only on measurements, not on cell instances.process-data:set_step_countwith a step column is now the unambiguous default — it keys offnp.sign(np.diff(...)), so decreasing / repeating step ids from GITT or RPT-with-substeps work the same as monotonic ones;set_cumulative_step_number(method="current sign")is reframed as a fallback for when no step column exists at all. Added a caveat for cyclers that emit duplicateTime [s]rows at step transitions.process-data: mandatory header-audit step codifies eight rules (walk every file, group by cohort × column-set, classify Standard / Auxiliary / Drop, diff reader output, preserve aux columns, keep multi-thermocouple channels separate, confirm units / sign per cohort, surface missing-temperature as a finding) and a required confirmation-report shape, so silent column drops between cycler families are caught before any standardized parquet is written.