Run_regularly doesn't run if the variable its manipulating is refractory

Description of problem

Howdy Y’all,
I have a very specific use case. I have been dynamic clamping with brian2 with somewhat decent results.
However, I was testing a configuration where I would brute force build a hybrid network by overwriting the membrane potential of an in slico neuron with the membrane potential of my clamped in vitro neuron. I accomplished this by running a run_regularly call every timestep to write to the membrane potential variable.
However, I’ve encountered an issue: when the neuron spikes, the run_regularly function stops executing for a few time steps. This behavior only occurs when the variable being overwritten (the membrane potential) has the unless refractory flag set.

Minimal code to reproduce problem

from brian2 import *

#run standalone

device = get_device()

set_device('cpp_standalone', build_on_run=True)

#ramp volt

voltage = np.arange(-70, 0, 0.01)

input_volt = TimedArray(voltage*mV, dt=0.01*second)

Eqs = Equations('''

dv/dt = 0*mV/ms: volt (unless refractory)

Vcut : volt

''')

P = NeuronGroup(1, model=Eqs, threshold='v>Vcut', refractory='v>Vcut', method='euler')

P.run_regularly("v = input_volt(t)", dt=0.1*ms)

M = SpikeMonitor(P)

M2 = StateMonitor(P, ['v'], record=True)

P.Vcut = -30*mV

run(60*second, report='text')

What you have aready tried

-Removing the unless refractory flag does fix it.

Expected output (if relevant)

Neuron membrane potential climbs from -70 to 0

Actual output (if relevant)

Neuron membrane potential climbs from -70 to -30, where it gets stuck

Hi @smestern. I agree that this is not necessarily intuitive, but this is actually working as intended. The (unless refractory) flag marks a variable as read-only during the refractoriness period:

In addition, a variable of a neuron that is in its refractory period is read-only: incoming synapses or other code will have no effect on the value of v until it leaves its refractory period.
Refractoriness — Brian 2 2.8.0.4 documentation

The way to implement this is to use the underlying mechanism directly as described in Refractoriness — Brian 2 2.8.0.4 documentation. In your example, you’d remove the unless refracory and instead write:

'''
dv/dt = int(not_refractory)*0*mV/ms: volt
Vcut : volt
'''

Of course, in the example with dv/dt = 0*mV/ms the refractoriness does not really matter, but I think you get the idea :smirking_face:

Let us know whether this works for you!

PS: Your title somewhat implies that there is a difference between standalone and runtime mode here, but this should work the same in both, otherwise this would be bug…

I see! That makes sense! the * int(not_refractory) works great thanks - it reproduces the exact behaviour as the (unless refractory) flag! I will edit the title accordingly for anyone that that may need to reference this thread in future.

1 Like