Skip to content

Steady-state inactivation (h∞) curve from a two-pulse VC protocol#366

Merged
JCorson merged 8 commits into
mainfrom
issue-184-steady-state-inactivation
May 13, 2026
Merged

Steady-state inactivation (h∞) curve from a two-pulse VC protocol#366
JCorson merged 8 commits into
mainfrom
issue-184-steady-state-inactivation

Conversation

@JCorson
Copy link
Copy Markdown
Owner

@JCorson JCorson commented May 12, 2026

Summary

  • Adds an Inactivation voltage-clamp protocol type (INACTIVATION_PROTOCOL): a two-pulse protocol where each sweep holds at a different conditioning prepulse voltage (swept via the existing min/max/step range) and then steps to a fixed test_pulse_voltage. Built from ordinary step_voltage arrays so analyze_iv extracts the test-pulse peak inward current per sweep over the [pre, pre+stim] window.
  • New patch_sim/analysis/inactivation.pycompute_inactivation(iv_result) derives normalized availability h∞(V) = I_peak(V) / I_peak_max per prepulse and fits a decreasing Boltzmann h∞(V) = 1 / (1 + exp((V − V_half) / k)), reporting V_half and k. Reuses gv_curve.boltzmann (via a _decreasing_boltzmann wrapper) and gv_curve.BoltzmannFit, sharing the Boltzmann implementation with the activation g-V curve (Compute and plot normalised conductance vs. voltage (g-V curve) #177).
  • New Steady-State Inactivation protocol preset: 150 ms conditioning prepulse from −120 to −20 mV in 10 mV steps, 15 ms fixed test pulse to 0 mV.
  • UI: the I-V Analysis panel now shows an h∞ vs. prepulse-voltage scatter with a dashed Boltzmann fit and a V₁/₂ = … mV, k = … mV annotation below the I-V curve when the Inactivation protocol is run. For that protocol the g-V / τ-V plots are skipped (their x-axis would be the prepulse voltage, not the test voltage); the I-V plot remains as the un-normalized inactivation curve. protocol_panel renders Prepulse min/max/step + Test pulse fields, and continuous mode is disabled for this inherently-multi-sweep protocol.
  • Tests: unit (compute_inactivation, the build_voltage_protocol Inactivation branch), integration (squid HH end-to-end: h∞ in [0, 1], monotone-decreasing, Boltzmann V½ ≈ −60 mV), UI plotting + clear_results, and e2e (preset populates inactivation_data, skips g-V / τ-V).

Test plan

  • Mode = Voltage Clamp, Protocol = Inactivation: the param form shows Prepulse min/max/step + Test pulse; "Run continuously" is disabled.
  • Run it (or load the "Steady-State Inactivation" preset): the I-V Analysis panel shows the I-V curve and, below it, an h∞ vs. prepulse-voltage scatter with a dashed Boltzmann fit and a V₁/₂ = … mV, k = … mV annotation; the g-V and τ-V plots are absent.
  • Loading the "Steady-State Inactivation" preset on the Squid Giant Axon yields a decreasing h∞ curve with V½ around −60 mV.
  • Switching back to a Step VC protocol restores the g-V / τ-V plots and the holding-voltage field.

Closes #184

JCorson added 8 commits May 12, 2026 13:44
…type

Adds an INACTIVATION_PROTOCOL ("Inactivation") voltage-clamp protocol whose
per-sweep holding voltage is the conditioning prepulse (swept via the existing
min/max/step range) and whose step amplitude is a fixed test_pulse_voltage.
Built from ordinary step_voltage arrays so the standard I-V analysis can later
extract the test-pulse peak current per sweep.

- patch_sim/constants.py: INACTIVATION_PROTOCOL, STEADY_STATE_INACTIVATION
  preset-name constant, "Inactivation" added to VOLTAGE_PROTOCOLS.
- build_voltage_protocol: new test_pulse_voltage param + "Inactivation" branch
  (rejects a missing prepulse range — inherently multi-sweep).
- ProtocolState: vc_test_pulse_voltage field + setter, passed through
  _build_protocols; can_run_continuous now excludes the Inactivation protocol.
- protocol_panel: param-form schema entry so the new type renders in the UI.

Refs #184
New patch_sim/analysis/inactivation.py: InactivationPoint,
InactivationAnalysisResult, and compute_inactivation, which takes an
IVAnalysisResult whose stimulus window is the fixed test pulse of a two-pulse
protocol and returns normalized availability h∞(V) = I_peak(V) / I_peak_max per
conditioning prepulse, plus a decreasing-Boltzmann fit
h∞(V) = 1 / (1 + exp((V - v_half) / k)).  Reuses gv_curve.boltzmann (via a
_decreasing_boltzmann wrapper) and gv_curve.BoltzmannFit so the activation and
inactivation analyses share one Boltzmann implementation, per #184.

Re-exports compute_inactivation, InactivationAnalysisResult, InactivationPoint
and the INACTIVATION_PROTOCOL constant from patch_sim / patch_sim.analysis.

Refs #184
A two-pulse VC preset: 150 ms conditioning prepulse from -120 to -20 mV in
10 mV steps, then a 15 ms fixed test pulse to 0 mV.  Auto-surfaces in the UI
preset dropdown via PROTOCOL_PRESET_NAMES.

Refs #184
…V panel

Wires compute_inactivation through the simulation pipeline and renders it:

- _analysis_format._compute_inactivation_data: serialise an
  InactivationAnalysisResult (h∞ points + decreasing-Boltzmann fit, with a
  pre-computed dense fit curve) for AnalysisState.
- _sweep_executor: when the protocol is "Inactivation", run the h∞ analysis
  off the same IVAnalysisResult and skip g-V / τ-V (the swept command voltage
  is the conditioning prepulse, not the test voltage); new
  _SimResult.inactivation_data field.
- simulation._do_apply_simulation: copy inactivation_data to AnalysisState.
- AnalysisState: inactivation_data field, clear_results entry,
  has_inactivation_data / inactivation_figure rx.vars.
- plotting/inactivation.build_inactivation_figure: h∞ scatter + dashed
  decreasing-Boltzmann line + V₁/₂ / k annotation.
- metrics/fi_gv_panel: _inactivation_plot() shown below the I-V curve in the
  I-V Analysis tab when h∞ data is available.

Refs #184
…refix)

ProtocolState._apply_protocol_preset setattr's preset-dict keys onto the
state, and build_protocol_from_preset forwards the same dict to
build_voltage_protocol — so the field name must match the builder parameter
test_pulse_voltage.  Like holding_voltage it has no current-clamp twin, so the
vc_ disambiguation prefix isn't needed.  Without this, loading the
Steady-State Inactivation preset raised SetUndefinedStateVarError.

Refs #184
- tests/unit/test_inactivation.py: compute_inactivation normalization,
  sorting, unit-range clamping, Boltzmann parameter recovery, monotonicity,
  and edge cases (empty / single point / all-non-negative peaks).
- tests/unit/test_protocol_builders.py: build_voltage_protocol "Inactivation"
  shape, per-sweep prepulse/test-pulse levels, the range/step/min>max
  validation errors, and the Steady-State Inactivation preset.
- tests/integration/test_inactivation_simulation.py: end-to-end squid HH run
  → analyze_iv → compute_inactivation; h∞ in [0, 1], monotone-decreasing,
  Boltzmann V½ ≈ -60 mV, k > 0.
- tests/ui/test_plotting.py: build_inactivation_figure traces, fit/annotation,
  and axis titles.
- tests/ui/test_state.py: clear_results also clears inactivation_data.
- tests/e2e/test_voltage_clamp_flow.py: the Steady-State Inactivation preset
  produces multi-sweep, populates inactivation_data, and skips g-V / τ-V.

Refs #184
…ous gate

Addresses code-review feedback on #366:
- _BOLTZMANN_FIT_POINTS now reads correctly as a constant shared by the g-V
  and h∞ dense fit curves.
- Add a test that can_run_continuous is False for the Inactivation protocol.

Refs #184
…30 ms

The 5 ms post-test window crammed the test-pulse current transient against
the right edge of the trace. Widen it to 30 ms so the transient (and its
decay) sit clear of the edge.
@JCorson JCorson merged commit 2a9d875 into main May 13, 2026
4 checks passed
@JCorson JCorson deleted the issue-184-steady-state-inactivation branch May 13, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Construct steady-state inactivation (h∞) curve from two-pulse voltage clamp protocol

1 participant