Skip to content

Visualise multi-experiment protocols #507

Description

@FinbarArgus

Apologies in advance, this issue is huge, I'm just putting this here to communicate where things are going with calibration and what I think would be good to have in the future.

Feature request: multi-experiment protocols with time-varying stimulus traces and experimental data overlay
Summary

I am working on electrophysiology parameter identification for a CellML neuron model (sympathetic stellate ganglion neuron) and would love to be able to open the calibrated model in WebOpenCOR alongside the experimental data that was used to calibrate it. The goal is an interactive OMEX archive where collaborators can open the model, see calibrated vs experimental traces side-by-side, and adjust key parameters with sliders — all in the browser, without needing a local installation.

I have a working pipeline that produces a structured JSON (obs_data.json) describing several experimental protocols (current-clamp and voltage-clamp sweeps) and the time-varying stimulus waveforms used to drive each one. I simulate these protocols using Myokit currently because of the time varying inputs, but switching to libopencor when available would be a possibility.

After exploring the webapp, I can see that the current SED-ML subset (one model, one uniform time course, static changeAttribute) and the simulation.json externalData overlay mechanism already cover the simpler use cases well. The cardiomyocyte OMEX demo is a great example. However, the following capabilities would be needed to represent the kind of protocols I am working with.

Use case: calibrated electrophysiology model with multi-protocol comparison
After calibration, I want to be able to open an OMEX in WebOpenCOR that:

Runs each experimental protocol in sequence — each experiment has a pre-simulation phase (model runs to steady state, ~1 s) followed by a stimulus phase of variable duration (0.5–1.5 s).
Changes scalar parameters between experiments — for example, soma_SN/alpha_4AP = 1.0 for drug-blocked experiments vs a different value for another condition.
Injects a time-varying stimulus waveform during the stimulus phase — the waveform is a sampled current (current clamp) or voltage (voltage clamp) command recorded directly from the experiment, stored as (t, values) arrays at ~1 kHz.
Overlays the simulated output against the experimental recording for each sweep.
Has sliders for a subset of calibrated model parameters so the user can explore sensitivity interactively.
Example obs_data.json structure (annotated)
Below is a simplified, commented version of the data format that drives my pipeline. I am including it to make the feature request concrete — this is what I am starting from, not a proposed standard.

{
  // --- Protocol information ---
  "protocol_info": {
    // One entry per experiment.
    // The model is run for pre_times[i] seconds to reach steady state
    // before the stimulus is applied.
    "pre_times": [1.0, 1.0, 1.0],
    // Each experiment has two subexperiment phases:
    //   subexperiment 0: pre-phase duration (same as pre_times[i])
    //   subexperiment 1: stimulus phase duration
    "sim_times": [
      [1.0, 1.201],   // experiment 0: 1 s pre + 1.201 s stim
      [1.0, 1.201],   // experiment 1
      [1.0, 0.547]    // experiment 2: shorter action-potential protocol
    ],
    // Scalar parameter values per experiment and per subexperiment.
    // Shape: params_to_change[param_name][exp_idx][sub_idx]
    // A string value is a key into protocol_traces (time-varying trace).
    // A numeric value is applied as a constant for that phase.
    "params_to_change": {
      // Switch between current- and voltage-clamp mode (binary flag in the model)
      "soma_SN/set_V": [
        [0.0, 0.0],   // exp 0: current clamp both phases
        [0.0, 0.0],   // exp 1
        [1.0, 1.0]    // exp 2: voltage clamp both phases
      ],
      // Holding potential (voltage clamp only).
      // The string references a sampled trace in protocol_traces below.
      "soma_SN/V_set": [
        [0.0, 0.0],
        [0.0, 0.0],
        [-96.4, "Vc_exp2_UniqueAp_sw0"]  // pre = scalar, stim = trace key
      ],
      // Injected current (current clamp).
      // The string references a sampled trace in protocol_traces below.
      "soma_SN/I_in": [
        [0.0, "Ic_exp0_Kv90_sw0"],  // pre = 0, stim = recorded current command
        [0.0, "Ic_exp1_Kv90_sw1"],
        [0.0, 0.0]                   // no current in voltage clamp mode
      ],
      // Pharmacological parameter: uniform across all phases.
      // Multiplies potassium channel conductance (4-AP drug effect).
      "soma_SN/alpha_4AP": [
        [1.0, 1.0],
        [1.0, 1.0],
        [1.0, 1.0]
      ]
    },
    // Time-varying waveforms referenced by string keys in params_to_change.
    // Each trace was recorded from the patch-clamp amplifier, smoothed,
    // and downsampled to 1 kHz. Times are relative to stimulus onset (t=0).
    // The solver interpolates linearly between samples during integration.
    "protocol_traces": {
      "Ic_exp0_Kv90_sw0": {
        "t":      [0.0, 0.001, 0.002, /* ... */ 1.200],  // seconds
        "values": [0.0, 0.0,  -0.12,  /* ... */ 0.0]     // nA
      },
      "Ic_exp1_Kv90_sw1": {
        "t":      [0.0, 0.001, /* ... */ 1.200],
        "values": [0.0, 0.0,   /* ... */ 0.0]
      },
      "Vc_exp2_UniqueAp_sw0": {
        "t":      [0.0, 0.001, /* ... */ 0.546],
        "values": [-96.4, -96.4, /* ... */ -95.0]  // mV
      }
    },
    // Human-readable labels for each experiment (used in plot titles)
    "experiment_labels": ["I_Kv90_sw0", "I_Kv90_sw1", "V_UniqueAp_sw0"],
    // Optional: identifiers linking experiments back to source data files
    "experiment_ids": [
      "4AP_200926_005.1.Kv-90.wcp",
      "4AP_200926_005.1.Kv-90.wcp",
      "4AP_200926_006.UniqueAp.wcp"
    ]
  },
  // --- Observation targets for calibration cost (not needed for viewer,
  //     but useful context for what the model was fitted to) ---
  "data_items": [
    {
      // A scalar feature extracted from the experimental trace
      "data_type": "constant",
      "variable": "soma_SN/V_sensed",       // CellML variable being compared
      "operand": "peak_inward_current_in_range",
      "value": -45.2,                        // measured value (mV)
      "std": 2.1,                            // measurement uncertainty
      "unit": "milliV",
      "experiment_idx": 0,                   // links to protocol_info above
      "subexperiment_idx": 1                 // which phase the measurement is from
    },
    {
      // A full time-series comparison (Vm trace vs simulated Vm)
      "data_type": "series",
      "variable": "soma_SN/V_sensed",
      "obs_dt": 0.0001,                      // seconds between samples
      "t_path": "series_data/Kv90_sw0_t.npy",       // optional external files
      "value_path": "series_data/Kv90_sw0_vm.npy",
      "experiment_idx": 0,
      "subexperiment_idx": 1
    }
  ]
}

The specific features I am hoping to request

  1. Multiple experiments with per-experiment timing

Currently the webapp enforces a single uniformTimeCourse. It would be very useful to be able to specify an ordered list of experiments, each with an independent outputEndTime (and optionally a pre-simulation duration), so that the model is run independently for each and the results plotted side by side.

  1. Scalar parameter changes between experiment phases

changeAttribute in SED-ML covers static changes before the whole simulation. Being able to specify a list of scalar values applied per-experiment and per-phase (i.e. changing I_in from 0 → 0 between pre- and stim-phase) would allow modelling standard two-phase patch-clamp protocols.

  1. Time-varying parameter injection (stimulus traces)

This is the most significant gap. For patch-clamp experiments the stimulus is a sampled waveform, not a constant. I use Myokit's trace-following mechanism (set_constant + pacing_log) to inject this during integration. In SED-ML terms, something like a dataSource referenced from a setValue inside a repeatedTask/oneStep sequence would achieve this — but the ability to interpolate a sampled array during a single continuous integration step seems to be the missing piece.

  1. Per-experiment experimental data overlay

The externalData mechanism in simulation.json already covers this beautifully for single-experiment cases. The main extension needed would be: one externalData block per experiment, with each block displayed only on the corresponding experiment's plot.

  1. Parameter sliders mapping to calibrated parameters

The existing input / parameters mechanism in simulation.json already supports this perfectly. No changes needed here.

Why this would be valuable
After fitting a model to data it is very useful to be able to share a single self-contained archive that lets collaborators:

See how the fitted model compares to each individual experimental sweep
Adjust key parameters (conductances, time constants) interactively and see the effect across all protocols simultaneously
Do this in the browser, with no local installation
The existing cardiomyocyte demo shows this is achievable for single-experiment cases. The multi-protocol extension would open this workflow to the broader patch-clamp modelling community where protocols routinely involve multiple sweeps with different stimulus waveforms.

My students have started claude coding a temporary solution to visualise the protocol outputs with sliders so I'm leaving this here to see whether we should try to push for these features in the webapp or if we should continue with our temporary solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions