gap_junction#

class brainpy.state.gap_junction(weight=1.0, name=None)#

NEST-compatible gap_junction connection model for electrical synaptic coupling.

This class implements electrical gap junction connections that transmit GapJunctionEvent data and contribute currents proportional to membrane voltage differences between coupled neurons. It follows the connection-level semantics of NEST’s models/gap_junction.{h,cpp} implementation, including waveform-relaxation (WFR) support for multi-timestep integration.

Parameters:
  • weight (float or array-like, optional) – Gap junction conductance weight (unitless coupling strength). Must be a scalar value. Default: 1.0.

  • name (str or None, optional) – Optional model instance name for identification. Default: None.

name#

Model instance name.

Type:

str or None

weight#

Gap junction conductance weight.

Type:

float

sumj_g_ij#

Sum of incoming gap junction weights (runtime state).

Type:

float

interpolation_coefficients#

Buffer of summed interpolation coefficients from incoming events, shape (min_delay_steps * (interpolation_order + 1),).

Type:

ndarray

REQUIRES_SYMMETRIC#

Class constant, always True for gap junctions.

Type:

bool

SUPPORTS_WFR#

Class constant, always True for WFR compatibility.

Type:

bool

SUPPORTED_WFR_INTERPOLATION_ORDERS#

Supported interpolation orders: (0, 1, 3).

Type:

tuple

Parameter Mapping

NEST Name

brainpy.state Name

Description

weight

weight

Gap junction conductance (nS)

delay

unsupported

Delay not allowed for gap junctions

Mathematical Formulation

1. Gap Junction Current

The gap junction current for a post-synaptic neuron \(i\) coupled to pre-synaptic neurons \(j\) is given by:

\[I_{\text{gap},i} = -\sum_j g_{ij} V_i + P_{\text{interp}}(t)\]

where:

  • \(g_{ij}\) is the gap junction conductance (weight) from neuron \(j\) to \(i\)

  • \(V_i\) is the membrane potential of the post-synaptic neuron

  • \(P_{\text{interp}}(t)\) is the interpolation polynomial constructed from pre-synaptic voltage contributions

2. Waveform Relaxation (WFR) Event Accumulation

During WFR cycles, incoming GapJunctionEvent objects update two quantities:

\[\begin{split}\Sigma g_{ij} &\leftarrow \Sigma g_{ij} + w_{ij} \\ c_k &\leftarrow c_k + w_{ij} \cdot a_k\end{split}\]

where:

  • \(w_{ij}\) is the connection weight

  • \(a_k\) are source neuron interpolation coefficients

  • \(c_k\) are target-side summed coefficients for polynomial reconstruction

3. Interpolation Polynomials

The interpolation term \(P_{\text{interp}}(t)\) depends on the WFR order:

  • Order 0 (constant interpolation):

    \[P_{\text{interp}}(t) = c_0\]
  • Order 1 (linear interpolation):

    \[P_{\text{interp}}(t) = c_0 + c_1 \cdot t\]
  • Order 3 (cubic Hermite interpolation):

    \[P_{\text{interp}}(t) = c_0 + c_1 \cdot t + c_2 \cdot t^2 + c_3 \cdot t^3\]

where \(t \in [0, 1]\) is the normalized time within the current WFR substep.

Implementation Details

1. Update Ordering (matching NEST)

The WFR cycle follows this sequence:

  1. Begin WFR window: Clear sumj_g_ij and interpolation coefficient buffer.

  2. Event accumulation: For each arriving secondary event, add weight and weighted coefficients.

  3. ODE substeps: Evaluate \(I_{\text{gap}}\) from current voltage, lag, interpolation order, and normalized substep time.

  4. End WFR window: Reset runtime buffers for the next window.

2. Symmetric Connectivity Requirement

Gap junctions require symmetric connections: if neuron \(i\) is coupled to neuron \(j\) with weight \(w_{ij}\), then neuron \(j\) must also be coupled to neuron \(i\) with weight \(w_{ji}\). Asymmetric configurations will produce incorrect dynamics.

3. Delay Constraint

Unlike chemical synapses, gap junctions are instantaneous (or near-instantaneous) electrical connections. Setting a delay raises a ValueError.

4. Coefficient Buffer Sizing

For WFR with min_delay_steps lags and interpolation order \(n\), the coefficient buffer size is:

\[\text{buffer\_size} = \text{min\_delay\_steps} \times (n + 1)\]

Examples

Basic gap junction setup:

>>> import brainpy_state as bp
>>> import saiunit as u
>>>
>>> # Create gap junction with 10 nS conductance
>>> gap = bp.nest.gap_junction(weight=10.0)
>>>
>>> # Query connection properties
>>> gap.get_status()
{'weight': 10.0, 'delay': None, 'requires_symmetric': True,
 'supports_wfr': True, 'supported_wfr_interpolation_orders': (0, 1, 3)}

WFR cycle simulation:

>>> import numpy as np
>>>
>>> # Initialize WFR with 5 delay steps and linear interpolation
>>> gap.begin_wfr_cycle(min_delay_steps=5, interpolation_order=1)
>>>
>>> # Simulate incoming event with pre-synaptic coefficients
>>> pre_coeffs = np.array([1.0, 0.5, 1.2, 0.8, 1.5, 0.3, 1.1, 0.9, 1.3, 0.7])
>>> gap.handle_gap_event(coeffarray=pre_coeffs)
>>>
>>> # Evaluate gap current at lag 2, normalized time t=0.5
>>> V_post = -65.0  # mV
>>> I_gap = gap.evaluate_gap_current(V_m=V_post, lag=2, t=0.5)
>>> print(f"Gap junction current: {I_gap:.2f}")
Gap junction current: ...

Error: attempting to set delay:

>>> gap.set_delay(1.5)
ValueError: gap_junction connection has no delay

See also

hh_psc_alpha_gap

Hodgkin-Huxley neuron with gap junction support

hh_cond_beta_gap_traub

Traub HH neuron with gap junction support

Notes

  • Delay is intentionally unsupported: Matches NEST’s constraint that gap junctions have no synaptic delay.

  • Connection-level semantics only: This class represents gap junction connection properties. Neuron-specific ODE dynamics (voltage interpolation, coefficient broadcasting) remain in the neuron model.

  • Interpolation coefficient ownership: The neuron model owns and updates interpolation coefficients based on its voltage history. This class only accumulates weighted coefficients from incoming events.

  • Thread safety: Not thread-safe. Runtime state (sumj_g_ij, interpolation_coefficients) assumes single-threaded access within each WFR cycle.

References

begin_wfr_cycle(min_delay_steps, interpolation_order=0)[source]#

Initialize a new waveform-relaxation (WFR) cycle.

Resets runtime state (sumj_g_ij and interpolation_coefficients) and allocates the coefficient buffer based on the number of delay steps and the interpolation order.

Parameters:
  • min_delay_steps (int or array-like) – Minimum delay in discrete timesteps (must be > 0). Determines the number of lag slots in the interpolation coefficient buffer.

  • interpolation_order (int, optional) –

    Interpolation polynomial order. Must be in {0, 1, 3}:

    • 0 – Constant interpolation (piecewise constant).

    • 1 – Linear interpolation.

    • 3 – Cubic Hermite interpolation.

    Default: 0.

Raises:

ValueError

  • If min_delay_steps <= 0. - If interpolation_order is not in {0, 1, 3}.

Notes

The coefficient buffer size is min_delay_steps * (interpolation_order + 1). For example, with min_delay_steps=5 and interpolation_order=1, the buffer will have 10 elements (2 coefficients per lag).

Examples

>>> gap = bp.nest.gap_junction(weight=2.0)
>>> gap.begin_wfr_cycle(min_delay_steps=3, interpolation_order=1)
>>> gap.interpolation_coefficients.shape
(6,)  # 3 lags * 2 coefficients per lag
>>> gap.sumj_g_ij
0.0

See also

reset_runtime_state

Clear runtime state without reallocating buffer

handle_gap_event

Accumulate incoming gap junction events

evaluate_gap_current(V_m, lag, t=0.0, interpolation_order=None)[source]#

Evaluate the gap junction current at a specific WFR lag and substep time.

Computes the gap junction current contribution using the accumulated weight sum and interpolation coefficients from incoming events. The current is computed as:

\[I_{\text{gap}} = -\Sigma g_{ij} \cdot V_m + P_{\text{interp}}(t)\]

where \(P_{\text{interp}}(t)\) is the interpolation polynomial evaluated at normalized time \(t \in [0, 1]\) within the current substep.

Parameters:
  • V_m (float or array-like) – Post-synaptic membrane potential (scalar or array). Units should match the voltage scale used in the neuron model (typically mV).

  • lag (int) – WFR lag index (delay step offset). Must be in range [0, n_lags), where n_lags = buffer_size / (interpolation_order + 1).

  • t (float or array-like, optional) – Normalized substep time in \([0, 1]\). Represents the position within the current integration step. Default: 0.0.

  • interpolation_order (int or None, optional) – Interpolation order override. If None, uses the order set in begin_wfr_cycle(). Must be in {0, 1, 3}.

Returns:

Gap junction current \(I_{\text{gap}}\). Shape matches V_m. Units depend on weight scaling (typically nA for conductance-based models).

Return type:

float or ndarray

Raises:

ValueError

  • If interpolation_coefficients buffer is empty (call begin_wfr_cycle() first). - If buffer size is incompatible with interpolation_order. - If lag is out of bounds. - If interpolation_order is not in {0, 1, 3}.

Notes

Interpolation formulas:

  • Order 0 (constant):

    \[P_{\text{interp}}(t) = c_0\]
  • Order 1 (linear):

    \[P_{\text{interp}}(t) = c_0 + c_1 \cdot t\]
  • Order 3 (cubic Hermite):

    \[P_{\text{interp}}(t) = c_0 + c_1 \cdot t + c_2 \cdot t^2 + c_3 \cdot t^3\]

Coefficient indexing: Coefficients are stored in a flat array with layout [lag0_c0, lag0_c1, ..., lag1_c0, lag1_c1, ...]. For lag \(L\) and order \(n\), coefficients start at index \(L \times (n + 1)\).

Examples

Constant interpolation (order 0):

>>> import numpy as np
>>> gap = bp.nest.gap_junction(weight=2.0)
>>> gap.begin_wfr_cycle(min_delay_steps=3, interpolation_order=0)
>>> gap.handle_gap_event(coeffarray=np.array([10.0, 20.0, 30.0]))
>>> V_post = -65.0  # mV
>>> I_gap = gap.evaluate_gap_current(V_m=V_post, lag=1)
>>> I_gap
170.0  # -2.0 * (-65.0) + 40.0

Linear interpolation (order 1):

>>> gap2 = bp.nest.gap_junction(weight=1.5)
>>> gap2.begin_wfr_cycle(min_delay_steps=2, interpolation_order=1)
>>> gap2.handle_gap_event(coeffarray=np.array([5.0, 10.0, 15.0, 20.0]))
>>> I_gap = gap2.evaluate_gap_current(V_m=-70.0, lag=0, t=0.5)
>>> # I_gap = -1.5 * (-70.0) + (7.5 + 15.0 * 0.5)
>>> I_gap
120.0

Cubic interpolation (order 3):

>>> gap3 = bp.nest.gap_junction(weight=1.0)
>>> gap3.begin_wfr_cycle(min_delay_steps=1, interpolation_order=3)
>>> gap3.handle_gap_event(coeffarray=np.array([1.0, 2.0, 3.0, 4.0]))
>>> I_gap = gap3.evaluate_gap_current(V_m=-60.0, lag=0, t=0.3)
>>> # I_gap = -1.0 * (-60.0) + (1.0 + 2.0*0.3 + 3.0*0.09 + 4.0*0.027)
>>> I_gap
62.438

See also

begin_wfr_cycle

Initialize WFR cycle with interpolation order

handle_gap_event

Accumulate gap junction events

reset_runtime_state

Clear accumulated state

get(key='status')[source]#

Retrieve a specific status parameter or the full status dictionary.

Parameters:

key (str, optional) – Parameter name to retrieve. Use 'status' for the full dictionary. Default: 'status'.

Returns:

If key == 'status', returns the full status dictionary. Otherwise, returns the value associated with key.

Return type:

Any

Raises:

KeyError – If key is not a valid status parameter name.

Examples

>>> gap = bp.nest.gap_junction(weight=3.5)
>>> gap.get('weight')
3.5
>>> gap.get('requires_symmetric')
True
>>> gap.get()  # defaults to 'status'
{'weight': 3.5, 'delay': None, ...}

See also

get_status

Full status dictionary retrieval

get_status()[source]#

Retrieve the current connection status and parameters.

Returns:

Status dictionary containing:
  • 'weight' (float): Current gap junction weight.

  • 'delay' (None): Always None (delays not supported).

  • 'requires_symmetric' (bool): Symmetric connectivity requirement.

  • 'supports_wfr' (bool): WFR support flag.

  • 'supported_wfr_interpolation_orders' (tuple): Tuple of supported interpolation orders (0, 1, 3).

Return type:

dict[str, Any]

Examples

>>> gap = bp.nest.gap_junction(weight=2.5)
>>> status = gap.get_status()
>>> status['weight']
2.5
>>> status['delay'] is None
True

See also

set_status

Update connection parameters

get

Retrieve specific status keys

handle_gap_event(coeffarray, weight=None)[source]#

Process an incoming gap junction event and accumulate contributions.

Updates runtime state by adding the event weight to sumj_g_ij and accumulating weighted interpolation coefficients. This method matches NEST’s handle(GapJunctionEvent&) semantics.

Parameters:
  • coeffarray (array-like) – Pre-synaptic neuron’s interpolation coefficients. Must be a 1D array with size matching the current coefficient buffer size.

  • weight (float, array-like, or None, optional) – Event-specific weight override. If None (default), uses the connection’s stored self.weight.

Raises:

ValueError

  • If coeffarray is empty. - If coeffarray size does not match the current buffer size. - If weight is provided but not a scalar.

Notes

Accumulation rule:

\[\begin{split}\Sigma g_{ij} &\leftarrow \Sigma g_{ij} + w \\ c_k &\leftarrow c_k + w \cdot a_k\end{split}\]

where \(w\) is the event weight and \(a_k\) are the incoming coefficients.

Buffer initialization: If the coefficient buffer is empty when the first event arrives, it is initialized to match the incoming array size.

Examples

>>> import numpy as np
>>> gap = bp.nest.gap_junction(weight=2.0)
>>> gap.begin_wfr_cycle(min_delay_steps=3, interpolation_order=0)
>>> pre_coeffs = np.array([1.0, 1.5, 2.0])
>>> gap.handle_gap_event(coeffarray=pre_coeffs)
>>> gap.sumj_g_ij
2.0
>>> gap.interpolation_coefficients
array([2. , 3. , 4. ])  # weight * coeffarray

Multiple events accumulate:

>>> gap.handle_gap_event(coeffarray=np.array([0.5, 0.5, 0.5]))
>>> gap.sumj_g_ij
4.0  # 2.0 + 2.0
>>> gap.interpolation_coefficients
array([3. , 4. , 5. ])  # previous + 2.0 * [0.5, 0.5, 0.5]

See also

prepare_secondary_event

Create event payload

evaluate_gap_current

Compute gap junction current from accumulated events

prepare_secondary_event(coeffarray)[source]#

Prepare a secondary gap junction event payload for transmission.

Packages the connection weight and pre-synaptic interpolation coefficients into a dictionary suitable for transmission as a GapJunctionEvent in a WFR simulation.

Parameters:

coeffarray (array-like) – Pre-synaptic neuron’s interpolation coefficients. Must be a non-empty 1D array. For interpolation order \(n\) and min_delay_steps lags, the expected size is min_delay_steps * (n + 1).

Returns:

Event payload containing:
  • 'weight' (float): Connection weight.

  • 'coeffarray' (ndarray): 1D float64 array of interpolation coefficients.

Return type:

dict[str, Any]

Raises:

ValueError – If coeffarray is empty or cannot be converted to a 1D array.

Examples

>>> import numpy as np
>>> gap = bp.nest.gap_junction(weight=3.0)
>>> pre_coeffs = np.array([0.5, 1.0, 1.5])
>>> event = gap.prepare_secondary_event(pre_coeffs)
>>> event['weight']
3.0
>>> event['coeffarray']
array([0.5, 1. , 1.5])

See also

handle_gap_event

Process incoming gap junction events

property properties: dict[str, Any]#

Get static connection model properties.

Returns:

Dictionary containing:
  • 'requires_symmetric' (bool): Always True.

  • 'supports_wfr' (bool): Always True.

Return type:

dict[str, Any]

Examples

>>> gap = bp.nest.gap_junction(weight=5.0)
>>> gap.properties
{'requires_symmetric': True, 'supports_wfr': True}
reset_runtime_state()[source]#

Clear runtime state accumulated from gap junction events.

Resets sumj_g_ij to 0.0 and zeros out the interpolation coefficient buffer without reallocating it. This method is typically called at the end of a WFR cycle to prepare for the next cycle.

Examples

>>> gap = bp.nest.gap_junction(weight=2.0)
>>> gap.begin_wfr_cycle(min_delay_steps=3, interpolation_order=0)
>>> gap.handle_gap_event(coeffarray=np.array([1.0, 2.0, 3.0]))
>>> gap.sumj_g_ij
2.0
>>> gap.reset_runtime_state()
>>> gap.sumj_g_ij
0.0
>>> np.all(gap.interpolation_coefficients == 0.0)
True

See also

begin_wfr_cycle

Initialize WFR cycle (resets and reallocates buffer)

handle_gap_event

Accumulate gap junction events

set_delay(_)[source]#

Attempt to set delay (always raises an error).

Gap junctions are instantaneous electrical connections and do not support synaptic delays. This method exists for API compatibility with NEST but always raises a ValueError.

Parameters:

_ (Any) – Ignored (delay value).

Raises:

ValueError – Always raised with message 'gap_junction connection has no delay'.

Examples

>>> gap = bp.nest.gap_junction()
>>> gap.set_delay(1.5)
ValueError: gap_junction connection has no delay

See also

set_status

General parameter update method (also rejects delay)

set_status(status=None, **kwargs)[source]#

Update connection parameters from a status dictionary or keyword arguments.

Parameters:
  • status (dict[str, Any] or None, optional) – Dictionary of parameter updates. Keys must be valid parameter names.

  • **kwargs – Additional parameter updates passed as keyword arguments. These override values in status if both are provided.

Raises:

ValueError – If attempting to set 'delay' (gap junctions have no delay).

Examples

>>> gap = bp.nest.gap_junction(weight=1.0)
>>> gap.set_status({'weight': 5.0})
>>> gap.get_status()['weight']
5.0
>>> gap.set_status(weight=10.0)
>>> gap.weight
10.0

Error case:

>>> gap.set_status({'delay': 1.0})
ValueError: gap_junction connection has no delay

See also

get_status

Retrieve current status

set_weight

Update weight parameter directly

set_weight(weight)[source]#

Update the gap junction conductance weight.

Parameters:

weight (float or array-like) – New gap junction weight (must be scalar).

Raises:

ValueError – If weight is not a scalar value.

Examples

>>> gap = bp.nest.gap_junction(weight=1.0)
>>> gap.set_weight(5.5)
>>> gap.weight
5.5

See also

set_status

Update multiple parameters at once