Inputs (Brian 1 –> 2 conversion)

Poisson Input

Brian 2 provides the same two groups that Brian 1 provided: PoissonGroup and PoissonInput. The mechanism for inhomogoneous Poisson processes has changed: instead of providing a Python function of time, you’ll now have to provide a string expression that is evaluated at every time step. For most use cases, this should allow a direct translation:

Brian 1

Brian 2

rates = lambda t:(1+cos(2*pi*t*1*Hz))*10*Hz
group = PoissonGroup(100, rates=rates)
rates = '(1 + cos(2*pi*t*1*Hz)*10*Hz)'
group = PoissonGroup(100, rates=rates)

For more complex rate modulations, the expression can refer to User-provided functions and/or you can replace the PoissonGroup by a general NeuronGroup with a threshold condition rand()<rates*dt (which allows you to store per-neuron attributes).

There is currently no direct replacement for the more advanced features of PoissonInput (record, freeze, copies, jitter, and reliability keywords), but various workarounds are possible, e.g. by directly using a BinomialFunction in the equations. For example, you can get the functionality of the freeze keyword (identical Poisson events for all neurons) by storing the input in a shared variable and then distribute the input to all neurons:

Brian 1

Brian 2

group = NeuronGroup(10,
                    'dv/dt = -v/(10*ms) : 1')
input = PoissonInput(group, N=1000, rate=1*Hz,
                     weight=0.1, state='v',
                     freeze=True)
group = NeuronGroup(10, '''dv/dt = -v / (10*ms) : 1
                           shared_input : 1 (shared)''')
poisson_input = BinomialFunction(n=1000, p=1*Hz*group.dt)
group.run_regularly('''shared_input = poisson_input()*0.1
                       v += shared_input''')

Spike generation

SpikeGeneratorGroup provides mostly the same functionality as in Brian 1. In contrast to Brian 1, there is only one way to specify which neurons spike and when – you have to provide the index array and the times array as separate arguments:

Brian 1

Brian 2

gen1 = SpikeGeneratorGroup(2, [(0, 0*ms), (1, 1*ms)])
gen2 = SpikeGeneratorGroup(2, [(array([0, 1]), 0*ms),
                               (array([0, 1]), 1*ms)]
gen3 = SpikeGeneratorGroup(2, (array([0, 1]),
                               array([0, 1])*ms))
gen4 = SpikeGeneratorGroup(2, array([[0, 0.0],
                                    [1, 0.001]])
gen1 = SpikeGeneratorGroup(2, [0, 1], [0, 1]*ms)
gen2 = SpikeGeneratorGroup(2, [0, 1, 0, 1],
                           [0, 0, 1, 1]*ms)
gen3 = SpikeGeneratorGroup(2, [0, 1], [0, 1]*ms)

gen4 = SpikeGeneratorGroup(2, [0, 1], [0, 1]*ms)

Note

For large arrays, make sure to provide a Quantity array (e.g. [0, 1, 2]*ms) and not a list of Quantity values (e.g. [0*ms, 1*ms, 2*ms]). A list has first to be translated into an array which can take a considerable amount of time for a list with many elements.

There is no direct equivalent of the Brian 1 option to use a generator that updates spike times online. The easiest alternative in Brian 2 is to pre-calculate the spikes and then use a standard SpikeGeneratorGroup. If this is not possible (e.g. there are two many spikes to fit in memory), then you can workaround the restriction by using custom code (see User-provided functions and Arbitrary Python code (network operations)).

Arbitrary time-dependent input (TimedArray)

For a detailed description of the TimedArray mechanism in Brian 2, see Timed arrays.

In Brian 1, timed arrays where special objects that could be assigned to a state variable and would then be used to update this state variable at every time step. In Brian 2, a timed array is implemented using the standard Functions mechanism which has the advantage that more complex access patterns can be implemented (e.g. by not using t as an argument, but something like t - delay). This syntax was possible in Brian 1 as well, but was disadvantageous for performance and had other limits (e.g. no unit support, no linear integration). In Brian 2, these disadvantages no longer apply and the function syntax is therefore the only available syntax. You can convert the old-style Brian 1 syntax to Brian 2 as follows:

Warning

The example below does not correctly translate the changed semantics of TimedArray related to the time. In Brian 1, TimedArray([0, 1, 2], dt=10*ms) will return 0 for t<5*ms, 1 for 5*ms<=t<15*ms, and 2 for t>=15*ms. Brian 2 will return 0 for t<10*ms, 1 for 10*ms<=t<20*ms, and 2 for t>=20*ms.

Brian 1

Brian 2

# same input for all neurons
eqs = '''
      dv/dt = (I - v)/tau : volt
      I : volt
      '''
group = NeuronGroup(1, model=eqs,
                    reset=0*mV, threshold=15*mV)
group.I = TimedArray(linspace(0*mV, 20*mV, 100),
                     dt=10*ms)
# same input for all neurons
I = TimedArray(linspace(0*mV, 20*mV, 100),
               dt=10*ms)
eqs = '''
      dv/dt = (I(t) - v)/tau : volt
      '''
group = NeuronGroup(1, model=eqs,
                    reset='v = 0*mV',
                    threshold='v > 15*mV')
# neuron-specific input
eqs = '''
      dv/dt = (I - v)/tau : volt
      I : volt
      '''
group = NeuronGroup(5, model=eqs,
                    reset=0*mV, threshold=15*mV)
values = (linspace(0*mV, 20*mV, 100)[:, None] *
          linspace(0, 1, 5))
group.I = TimedArray(values, dt=10*ms)
# neuron-specific input
values = (linspace(0*mV, 20*mV, 100)[:, None] *
          linspace(0, 1, 5))
I = TimedArray(values, dt=10*ms)
eqs = '''
      dv/dt = (I(t, i) - v)/tau : volt
      '''
group = NeuronGroup(5, model=eqs,
                    reset='v = 0*mV',
                    threshold='v > 15*mV')