Пример #1
0
    def before_run(self, run_namespace):
        # Do some checks on the period vs. dt
        dt = self.dt_[:]  # make a copy
        period = self.period_
        if period < np.inf:
            if period < dt:
                raise ValueError('The period of %s is %s, which is smaller '
                                 'than its dt of %s.' %
                                 (self.name, self.period, dt))
            if (abs(int(period / dt) * dt - period) >
                    period * np.finfo(dt.dtype).eps):
                raise NotImplementedError('The period of %s is %s, which is '
                                          'not an integer multiple of its dt '
                                          'of %s.' %
                                          (self.name, self.period, dt))

        if self._spikes_changed:
            current_t = self.variables['t'].get_value().item()
            timesteps = timestep(self._spike_time, dt)
            current_step = timestep(current_t, dt)
            in_the_past = np.nonzero(timesteps < current_step)[0]
            if len(in_the_past):
                logger.warn('The SpikeGeneratorGroup contains spike times '
                            'earlier than the start time of the current run '
                            '(t = {}), these spikes will be '
                            'ignored.'.format(str(current_t * second)),
                            name_suffix='ignored_spikes')
                self.variables['_lastindex'].set_value(in_the_past[-1] + 1)
            else:
                self.variables['_lastindex'].set_value(0)

        # Check that we don't have more than one spike per neuron in a time bin
        if self._previous_dt is None or dt != self._previous_dt or self._spikes_changed:
            # We shift all the spikes by a tiny amount to make sure that spikes
            # at exact multiples of dt do not end up in the previous time bin
            # This shift has to be quite significant relative to machine
            # epsilon, we use 1e-3 of the dt here
            shift = 1e-3 * dt
            timebins = np.asarray(np.asarray(self._spike_time + shift) / dt,
                                  dtype=np.int32)
            # time is already in sorted order, so it's enough to check if the condition
            # that timebins[i]==timebins[i+1] and self._neuron_index[i]==self._neuron_index[i+1]
            # is ever both true
            if (np.logical_and(
                    np.diff(timebins) == 0,
                    np.diff(self._neuron_index) == 0)).any():
                raise ValueError('Using a dt of %s, some neurons of '
                                 'SpikeGeneratorGroup "%s" spike more than '
                                 'once during a time step.' %
                                 (str(self.dt), self.name))
            self._previous_dt = dt
            self._spikes_changed = False

        super(SpikeGeneratorGroup,
              self).before_run(run_namespace=run_namespace)
Пример #2
0
def test_timestep_function():
    dt = defaultclock.dt_
    # Check that multiples of dt end up in the correct time step
    t = np.arange(100000) * dt
    assert_equal(timestep(t, dt), np.arange(100000))

    # Scalar values should stay scalar
    ts = timestep(0.0005, 0.0001)
    assert np.isscalar(ts) and ts == 5

    # Length-1 arrays should stay arrays
    ts = timestep(np.array([0.0005]), 0.0001)
    assert ts.shape == (1, ) and ts == 5
Пример #3
0
def test_timestep_function():
    dt = defaultclock.dt_
    # Check that multiples of dt end up in the correct time step
    t = np.arange(100000)*dt
    assert_equal(timestep(t, dt), np.arange(100000))

    # Scalar values should stay scalar
    ts = timestep(0.0005, 0.0001)
    assert np.isscalar(ts) and ts == 5

    # Length-1 arrays should stay arrays
    ts = timestep(np.array([0.0005]), 0.0001)
    assert ts.shape == (1,) and ts == 5
Пример #4
0
def test_timestep_function():
    dt = defaultclock.dt_
    # Check that multiples of dt end up in the correct time step
    t = np.arange(100000) * dt
    assert_equal(timestep(t, dt), np.arange(100000))
    # Check that inf is handled correctly
    t = np.array([-np.inf, np.inf])
    ts = timestep(t, dt)
    assert ts[0] < -1e9
    assert ts[1] > 1e9

    # Scalar values should stay scalar
    ts = timestep(0.0005, 0.0001)
    assert np.isscalar(ts) and ts == 5
Пример #5
0
 def __call__(self, t):
     if not hasattr(self, 'target_variable'):
         self.target_variable = weakref.ref(self.group().variables[self.targetvar])
     i = timestep(t, self.dt)
     if not (self.buffer_start<=i<self.buffer_end):
         if i==0:
             self.filterbank.buffer_init()
         self.buffer_start = i
         self.buffer_end = self.buffer_start+self.buffersize
         self.buffer = self.filterbank.buffer_fetch(self.buffer_start, self.buffer_end)
     self.target_variable().set_value(self.buffer[i-self.buffer_start, :])
Пример #6
0
    def _check_args(self, indices, times, period, N, sorted, dt):
        times = Quantity(times)
        if len(indices) != len(times):
            raise ValueError(('Length of the indices and times array must '
                              'match, but %d != %d') % (len(indices),
                                                        len(times)))
        if period < 0*second:
            raise ValueError('The period cannot be negative.')
        elif len(times) and period != 0*second:
            period_bins = np.round(period / dt)
            # Note: we have to use the timestep function here, to use the same
            # binning as in the actual simulation
            max_bin = timestep(np.max(times), dt)
            if max_bin >= period_bins:
                raise ValueError('The period has to be greater than the '
                                 'maximum of the spike times')
        if len(times) and np.min(times) < 0*second:
            raise ValueError('Spike times cannot be negative')
        if len(indices) and (np.min(indices) < 0 or np.max(indices) >= N):
            raise ValueError('Indices have to lie in the interval [0, %d[' % N)

        times = np.asarray(times)
        indices = np.asarray(indices)
        if not sorted:
            # sort times and indices first by time, then by indices
            I = np.lexsort((indices, times))
            indices = indices[I]
            times = times[I]

        # We store the indices and times also directly in the Python object,
        # this way we can use them for checks in `before_run` even in standalone
        # TODO: Remove this when the checks in `before_run` have been moved to the template
        self._neuron_index = indices
        self._spike_time = times
        self._spikes_changed = True

        return indices, times
Пример #7
0
    def _check_args(self, indices, times, period, N, sorted, dt):
        times = Quantity(times)
        if len(indices) != len(times):
            raise ValueError(
                ('Length of the indices and times array must '
                 'match, but %d != %d') % (len(indices), len(times)))
        if period < 0 * second:
            raise ValueError('The period cannot be negative.')
        elif len(times) and period != 0 * second:
            period_bins = np.round(period / dt)
            # Note: we have to use the timestep function here, to use the same
            # binning as in the actual simulation
            max_bin = timestep(np.max(times), dt)
            if max_bin >= period_bins:
                raise ValueError('The period has to be greater than the '
                                 'maximum of the spike times')
        if len(times) and np.min(times) < 0 * second:
            raise ValueError('Spike times cannot be negative')
        if len(indices) and (np.min(indices) < 0 or np.max(indices) >= N):
            raise ValueError('Indices have to lie in the interval [0, %d[' % N)

        times = np.asarray(times)
        indices = np.asarray(indices)
        if not sorted:
            # sort times and indices first by time, then by indices
            I = np.lexsort((indices, times))
            indices = indices[I]
            times = times[I]

        # We store the indices and times also directly in the Python object,
        # this way we can use them for checks in `before_run` even in standalone
        # TODO: Remove this when the checks in `before_run` have been moved to the template
        self._neuron_index = indices
        self._spike_time = times
        self._spikes_changed = True

        return indices, times
Пример #8
0
    def before_run(self, run_namespace):
        # Do some checks on the period vs. dt
        dt = self.dt_[:]  # make a copy
        period = self.period_
        if period < np.inf and period != 0:
            if period < dt:
                raise ValueError('The period of %s is %s, which is smaller '
                                 'than its dt of %s.' % (self.name,
                                                         self.period[:],
                                                         dt*second))

        if self._spikes_changed:
            current_t = self.variables['t'].get_value().item()
            timesteps = timestep(self._spike_time, dt)
            current_step = timestep(current_t, dt)
            in_the_past = np.nonzero(timesteps < current_step)[0]
            if len(in_the_past):
                logger.warn('The SpikeGeneratorGroup contains spike times '
                            'earlier than the start time of the current run '
                            '(t = {}), these spikes will be '
                            'ignored.'.format(str(current_t*second)),
                            name_suffix='ignored_spikes')
                self.variables['_lastindex'].set_value(in_the_past[-1] + 1)
            else:
                self.variables['_lastindex'].set_value(0)

        # Check that we don't have more than one spike per neuron in a time bin
        if self._previous_dt is None or dt != self._previous_dt or self._spikes_changed:
            # We shift all the spikes by a tiny amount to make sure that spikes
            # at exact multiples of dt do not end up in the previous time bin
            # This shift has to be quite significant relative to machine
            # epsilon, we use 1e-3 of the dt here
            shift = 1e-3*dt
            timebins = np.asarray(np.asarray(self._spike_time + shift)/dt,
                                  dtype=np.int32)
            # time is already in sorted order, so it's enough to check if the condition
            # that timebins[i]==timebins[i+1] and self._neuron_index[i]==self._neuron_index[i+1]
            # is ever both true
            if (np.logical_and(np.diff(timebins)==0, np.diff(self._neuron_index)==0)).any():
                raise ValueError('Using a dt of %s, some neurons of '
                                 'SpikeGeneratorGroup "%s" spike more than '
                                 'once during a time step.' % (str(self.dt),
                                                               self.name))
            self.variables['_timebins'].set_value(timebins)
            period_bins = np.round(period / dt)
            max_int = np.iinfo(np.int32).max
            if period_bins > max_int:
                logger.warn('Periods longer than {} timesteps (={}) are not '
                            'supported, the period will therefore be '
                            'considered infinite. Set the period to 0*second '
                            'to avoid this '
                            'warning.'.format(max_int, str(max_int*dt*second)),
                            'spikegenerator_long_period')
                period = period_bins = 0
            if np.abs(period_bins * dt - period) > period * np.finfo(dt.dtype).eps:
                raise NotImplementedError('The period of %s is %s, which is '
                                          'not an integer multiple of its dt '
                                          'of %s.' % (self.name,
                                                      self.period[:],
                                                      dt * second))

            self.variables['_period_bins'].set_value(period_bins)

            self._previous_dt = dt
            self._spikes_changed = False

        super(SpikeGeneratorGroup, self).before_run(run_namespace=run_namespace)
Пример #9
0
def test_refractoriness_variables(ref_time):
    # Try a string evaluating to a quantity, and an explicit boolean
    # condition -- all should do the same thing
    G = NeuronGroup(1,
                    """
                    dv/dt = 99.999*Hz : 1 (unless refractory)
                    dw/dt = 99.999*Hz : 1
                    ref : second
                    ref_no_unit : 1
                    time_since_spike = (t - lastspike) +1e-3*dt : second
                    ref_subexpression = (t - lastspike + 1e-3*dt) < ref : boolean
                    """,
                    threshold='v>1',
                    reset='v=0;w=0',
                    refractory=ref_time,
                    dtype={
                        'ref': defaultclock.variables['t'].dtype,
                        'ref_no_unit': defaultclock.variables['t'].dtype,
                        'lastspike': defaultclock.variables['t'].dtype,
                        'time_since_spike': defaultclock.variables['t'].dtype
                    })
    G.ref = 5 * ms
    G.ref_no_unit = 5
    # It should take 10ms to reach the threshold, then v should stay at 0
    # for 5ms, while w continues to increase
    mon = StateMonitor(G, ['v', 'w'], record=True, when='end')
    run(20 * ms)
    try:
        # No difference before the spike
        assert_allclose(mon[0].v[:timestep(10 * ms, defaultclock.dt)],
                        mon[0].w[:timestep(10 * ms, defaultclock.dt)])
        # v is not updated during refractoriness
        in_refractoriness = mon[0].v[
            timestep(10 *
                     ms, defaultclock.dt):timestep(15 * ms, defaultclock.dt)]
        assert_allclose(in_refractoriness, np.zeros_like(in_refractoriness))
        # w should evolve as before
        assert_allclose(
            mon[0].w[:timestep(5 * ms, defaultclock.dt)],
            mon[0].w[timestep(10 * ms, defaultclock.dt) +
                     1:timestep(15 * ms, defaultclock.dt) + 1])
        assert np.all(mon[0].w[timestep(10 * ms, defaultclock.dt) +
                               1:timestep(15 * ms, defaultclock.dt) + 1] > 0)
        # After refractoriness, v should increase again
        assert np.all(
            mon[0].v[timestep(15 * ms, defaultclock.dt
                              ):timestep(20 * ms, defaultclock.dt)] > 0)
    except AssertionError as ex:
        raise
        raise AssertionError(
            f'Assertion failed when using {ref_time!r} as refractory argument:\n{ex}'
        )
Пример #10
0
def test_refractoriness_basic():
    G = NeuronGroup(1,
                    """
                       dv/dt = 99.999*Hz : 1 (unless refractory)
                       dw/dt = 99.999*Hz : 1
                       """,
                    threshold='v>1',
                    reset='v=0;w=0',
                    refractory=5 * ms)
    # It should take 10ms to reach the threshold, then v should stay at 0
    # for 5ms, while w continues to increase
    mon = StateMonitor(G, ['v', 'w'], record=True, when='end')
    run(20 * ms)
    # No difference before the spike
    assert_allclose(mon[0].v[:timestep(10 * ms, defaultclock.dt)],
                    mon[0].w[:timestep(10 * ms, defaultclock.dt)])
    # v is not updated during refractoriness
    in_refractoriness = mon[0].v[timestep(10 * ms, defaultclock.dt
                                          ):timestep(15 * ms, defaultclock.dt)]
    assert_equal(in_refractoriness, np.zeros_like(in_refractoriness))
    # w should evolve as before
    assert_allclose(
        mon[0].w[:timestep(5 * ms, defaultclock.dt)],
        mon[0].w[timestep(10 * ms, defaultclock.dt) +
                 1:timestep(15 * ms, defaultclock.dt) + 1])
    assert np.all(mon[0].w[timestep(10 * ms, defaultclock.dt) +
                           1:timestep(15 * ms, defaultclock.dt) + 1] > 0)
    # After refractoriness, v should increase again
    assert np.all(mon[0].v[timestep(15 * ms, defaultclock.dt
                                    ):timestep(20 * ms, defaultclock.dt)] > 0)
Пример #11
0
    def before_run(self, run_namespace):
        # Do some checks on the period vs. dt
        dt = self.dt_[:]  # make a copy
        period = self.period_
        if period < np.inf and period != 0:
            if period < dt:
                raise ValueError(
                    f"The period of '{self.name}' is {self.period[:]!s}, "
                    f"which is smaller than its dt of {dt*second!s}.")

        if self._spikes_changed:
            current_t = self.variables['t'].get_value().item()
            timesteps = timestep(self._spike_time, dt)
            current_step = timestep(current_t, dt)
            in_the_past = np.nonzero(timesteps < current_step)[0]
            if len(in_the_past):
                logger.warn(
                    f"The SpikeGeneratorGroup contains spike times "
                    f"earlier than the start time of the current run "
                    f"(t = {current_t*second!s}), these spikes will be "
                    f"ignored.",
                    name_suffix='ignored_spikes')
                self.variables['_lastindex'].set_value(in_the_past[-1] + 1)
            else:
                self.variables['_lastindex'].set_value(0)

        # Check that we don't have more than one spike per neuron in a time bin
        if self._previous_dt is None or dt != self._previous_dt or self._spikes_changed:
            # We shift all the spikes by a tiny amount to make sure that spikes
            # at exact multiples of dt do not end up in the previous time bin
            # This shift has to be quite significant relative to machine
            # epsilon, we use 1e-3 of the dt here
            shift = 1e-3 * dt
            timebins = np.asarray(np.asarray(self._spike_time + shift) / dt,
                                  dtype=np.int32)
            # time is already in sorted order, so it's enough to check if the condition
            # that timebins[i]==timebins[i+1] and self._neuron_index[i]==self._neuron_index[i+1]
            # is ever both true
            if (np.logical_and(
                    np.diff(timebins) == 0,
                    np.diff(self._neuron_index) == 0)).any():
                raise ValueError(
                    f"Using a dt of {self.dt!s}, some neurons of "
                    f"SpikeGeneratorGroup '{self.name}' spike more than "
                    f"once during a time step.")
            self.variables['_timebins'].set_value(timebins)
            period_bins = np.round(period / dt)
            max_int = np.iinfo(np.int32).max
            if period_bins > max_int:
                logger.warn(
                    f"Periods longer than {max_int} timesteps "
                    f"(={max_int*dt*second!s}) are not "
                    "supported, the period will therefore be "
                    "considered infinite. Set the period to 0*second "
                    "to avoid this "
                    "warning.", 'spikegenerator_long_period')
                period = period_bins = 0
            if np.abs(period_bins * dt -
                      period) > period * np.finfo(dt.dtype).eps:
                raise NotImplementedError(f"The period of '{self.name}' is "
                                          f"{self.period[:]!s}, which is "
                                          f"not an integer multiple of its dt "
                                          f"of {dt*second!s}.")

            self.variables['_period_bins'].set_value(period_bins)

            self._previous_dt = dt
            self._spikes_changed = False

        super(SpikeGeneratorGroup,
              self).before_run(run_namespace=run_namespace)
Пример #12
0
def test_refractoriness_variables():
    # Try a string evaluating to a quantity an an explicit boolean
    # condition -- all should do the same thing
    for ref_time in [
            '5*ms', '(t-lastspike) < 5*ms', 'time_since_spike < 5*ms',
            'ref_subexpression', '(t-lastspike) <= ref', 'ref',
            'ref_no_unit*ms'
    ]:
        reinit_devices()
        G = NeuronGroup(1,
                        '''
                        dv/dt = 99.999*Hz : 1 (unless refractory)
                        dw/dt = 99.999*Hz : 1
                        ref : second
                        ref_no_unit : 1
                        time_since_spike = t - lastspike : second
                        ref_subexpression = (t - lastspike) < ref : boolean
                        ''',
                        threshold='v>1',
                        reset='v=0;w=0',
                        refractory=ref_time)
        G.ref = 5 * ms
        G.ref_no_unit = 5
        # It should take 10ms to reach the threshold, then v should stay at 0
        # for 5ms, while w continues to increase
        mon = StateMonitor(G, ['v', 'w'], record=True, when='end')
        run(20 * ms)
        try:
            # No difference before the spike
            assert_equal(mon[0].v[:timestep(10 * ms, defaultclock.dt)],
                         mon[0].w[:timestep(10 * ms, defaultclock.dt)])
            # v is not updated during refractoriness
            in_refractoriness = mon[0].v[timestep(10 * ms, defaultclock.dt):
                                         timestep(15 * ms, defaultclock.dt)]
            assert_equal(in_refractoriness, np.zeros_like(in_refractoriness))
            # w should evolve as before
            assert_equal(
                mon[0].w[:timestep(5 * ms, defaultclock.dt)],
                mon[0].w[timestep(10 * ms, defaultclock.dt) +
                         1:timestep(15 * ms, defaultclock.dt) + 1])
            assert np.all(
                mon[0].w[timestep(10 * ms, defaultclock.dt) +
                         1:timestep(15 * ms, defaultclock.dt) + 1] > 0)
            # After refractoriness, v should increase again
            assert np.all(mon[0].v[timestep(15 * ms, defaultclock.dt
                                            ):timestep(20 *
                                                       ms, defaultclock.dt)])
        except AssertionError as ex:
            raise