/*
* test_spike_generator.sli
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* NEST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* BeginDocumentation
Name: testsuite::test_spike_generator - sli script to test spike_generator device
Synopsis: (test_spike_generator) run
Description:
test_spike_generator checks the spike_generator device and its
consistency with the nest simulation kernel.
/start specifies the earliest possible time stamp of a spike event to
be emitted. /stop specifies the earliest time stamp of a potential
spike event that is not emitted.
spike_generator is a device emitting spike events restricted to the
time grid spanned by the computation step size h. Nevertheless, the
time stamps of the spike events to be emitted are specified by device
property /spike_times as double floats in milliseconds (ms). The
spike_generator automatically assigns the appropriate time stamps on
the simulation grid. For an arbitrary spike time s this is t=i*h with
s in the interval (t-h, t], the corresponding event with time stamp t
is emitted in the simulation step t-h -> t. See test_iaf_i0_refractory
for consistency with spike generation in integrate-and-fire type neuron
models and test_iaf_dc_aligned_stop.sli for consistency with the
generation of grid based dc currents.
A a consequence of the restriction of spike events to the simulation
grid, multiple spike events with identical time stamps may be emitted.
The results at different computation step sizes (resolutions) require
some further discussion. Let us assume that /start and /stop are at
joined grid positions of all resolutions tested. If all spike events
are specified on joined grid positions, the simulation results are
inependent of the computation step size. However, if spikes occur on
non-joined grid positions, spike times are shifted to the appropriate
position on the current grid and simulation results will differ. Also,
the spike count cannot be preserved because spikes at the end of the
interval may be shifted to grid position /stop which is not a valid
time stamp of a spike event anymore.
Note that the number of emitted spike events can always be made
independent of the computation step size by setting /stop to an
appropriately late joined grid position.
The usage of values for /start and /stop that are not simultaneous
grid positions of the computation step sizes to be used should be
avoided because the set of spike events delivered in the simulation
will vary in complex ways.
The expected output is documented at the end of the script.
FirstVersion: July 2004
Author: Diesmann
SeeAlso: spike_generator, testsuite::test_iaf_i0_refractory, testsuite::test_iaf_dc_aligned_stop
*/
/unittest (8331) require
/unittest using
% check, if truncating spike times to grid causes an assertion
% if precise_times is set to false
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/precise_times false
/spike_times [4.33] % in ms
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms,
>> SetStatus
10.0 Simulate
}
fail_or_die
% check, if spike times are rounded up or down,
% if doube value is closer than tic/2 to next grid point
% tic = 1 mu s
%
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/precise_times false
/spike_times [2.9999 4.3001] % in ms
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sd [ /events /times ] get cva
[30 43]
eq
}
assert_or_die
% test first example from documentation
% /spike_generator << /spike_times [1.0 1.9999 3.0001] >> Create
% ---> spikes at steps 10 (==1.0ms), 20 (==2.0ms) and 30 (==3.0ms)
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/spike_times [1.0 1.9999 3.0001] % in ms
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sd [ /events /times ] get cva
[10 20 30]
eq
}
assert_or_die
% test second example from documentation
% /spike_generator << /spike_times [1.0 1.05 3.0001] >> Create
% ---> error, spike time 1.05 not within tic/2 of step
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/spike_times [1.0 1.05 3.0001] % in ms
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms
>> SetStatus
} fail_or_die
% test third example from documentation
% /spike_generator << /spike_times [1.0 1.05 3.0001]
% /allow_offgrid_times true >> Create
% ---> spikes at steps 10, 11 (mid-step time rounded up),
% 30 (time within tic/2 of step moved to step)
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/spike_times [1.0 1.05 3.0001] % in ms
/allow_offgrid_spikes true
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sd [ /events /times ] get cva
[10 11 30]
eq
}
assert_or_die
% fourth example from documentation
% /spike_generator << /spike_times [1.0 1.05 3.0001]
% /precise_times true >> Create
% ---> spikes at step 10, offset 0.0; step 11, offset 0.05;
% step 31, offset 0.0999
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
/off_grid_spiking true
>> SetStatus
/spike_generator Create /sg Set
sg <<
/spike_times [1.0 1.05 3.0001] % in ms
/precise_times true
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 6.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sd [ /events /times ] get cva [10 11 31] eq
sd [ /events /offsets ] get cva 5 ToUnitTestPrecision [0 0.05 0.0999] eq
and
}
assert_or_die
% fifth example from documentation
% Assume we have simulated 10.0ms and simulation times is thus 10.0 (step 100).
% Then, any spike times set, at this time, must be later than step 100.
%
% /spike_generator << /spike_times [10.0001] >> Create
% ---> spike time is within tic/2 of step 100, rounded down to 100 thus
% not in the future and should not be emitted
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
/spike_detector Create /sd Set
sg sd Connect
10 Simulate
sg <<
/spike_times [10.0001] % in ms
/origin 0.0 % in ms
/start 0.0 % in ms
/stop 16.0 % in ms
>> SetStatus
10 Simulate
sd /n_events get 0 eq
} assert_or_die
% sixth example from documentation
% /spike_generator << /spike_times [10.0001] /precise_times true >> Create
% ---> spike at step 101, offset 0.0999 is in the future, requires recipients
% that respect the offset (precise-timing model neurons)
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
/off_grid_spiking true
>> SetStatus
/spike_generator Create /sg Set
sg <<
/precise_times true
/origin 0.0 % in ms
/start 0.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd Connect
10.0 Simulate
sg << /spike_times [10.0001] >> SetStatus % in ms
10.0 Simulate
sd [ /events /times ] get cva [101] eq
sd [ /events /offsets ] get cva 5 ToUnitTestPrecision [0.0999] eq
and
}
assert_or_die
% seventh example from documentation
% /spike_generator << /spike_times [10.0001 11.0001] /shift_now_spikes true >> Create
% ---> spike at step 101, spike shifted into the future; spike at 110 not shifted
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/shift_now_spikes true
/origin 0.0 % in ms
/start 0.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sg << /spike_times [10.0001 11.0001] >> SetStatus % in ms
10.0 Simulate
sd [ /events /times ] get cva
[101 110] eq
sd [ /events /offsets ] get cva
5 ToUnitTestPrecision [0 0] eq
and
}
assert_or_die
% seventh example from documentation, but with origin
% /spike_generator << /spike_times [0.0001 1.0001] /origin 10.0 /shift_now_spikes true >> Create
% ---> spike at step 101, spike shifted into the future; spike at 110 not shifted
{
ResetKernel
0 <<
/local_num_threads 1
/resolution 0.1
>> SetStatus
/spike_generator Create /sg Set
sg <<
/shift_now_spikes true
/origin 0.0 % in ms
/start 0.0 % in ms
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps true >> SetStatus
sg sd 1.0 1.0 Connect
10.0 Simulate
sg << /origin 10.0 /spike_times [0.0001 1.0001] >> SetStatus % in ms
10.0 Simulate
sd [ /events /times ] get cva
[101 110] eq
sd [ /events /offsets ] get cva
5 ToUnitTestPrecision [0 0] eq
and
}
assert_or_die
% ensure exclusivity between /precise_times and /allow_offgrid_spikes and /shift_now_spikes
{ /spike_generator << /precise_times true /allow_offgrid_spikes true >> Create } fail_or_die
{ /spike_generator << /precise_times true /shift_now_spikes true >> Create } fail_or_die
% test set-get
{
ResetKernel
0 << /local_num_threads 1 /resolution 0.1 >> SetStatus
/spike_generator << /spike_times [ 0.1 10.0 10.5 10.50001 ] >> Create
/spike_times get cva 5 ToUnitTestPrecision
[0.1 10.0 10.5 10.5] 5 ToUnitTestPrecision
eq
}
assert_or_die
{
ResetKernel
0 << /local_num_threads 1 /resolution 0.1 >> SetStatus
/spike_generator << /spike_times [ 0.1 10.0 10.5 10.50001 10.55 ]
/allow_offgrid_spikes true >> Create
/spike_times get cva 5 ToUnitTestPrecision
[0.1 10.0 10.5 10.5 10.6 ] 5 ToUnitTestPrecision pstack
eq
}
assert_or_die
{
ResetKernel
0 << /local_num_threads 1 /resolution 0.1 >> SetStatus
/spike_generator << /spike_times [ 0.1 10.0 10.5 10.50001 10.55 ]
/precise_times true >> Create
/spike_times get cva 5 ToUnitTestPrecision
[0.1 10.0 10.5 10.5 10.55 ] 5 ToUnitTestPrecision
eq
}
assert_or_die
{
ResetKernel
0 << /local_num_threads 1 /resolution 0.1 >> SetStatus
/spike_generator << /spike_times [ 0.0 10.0 10.5 10.50001 ]
/shift_now_spikes true >> Create
/spike_times get cva 5 ToUnitTestPrecision
[0.1 10.0 10.5 10.5 ] 5 ToUnitTestPrecision
eq
}
assert_or_die
%
% check, if precise times are conveyed up to desired precision
% check, if events outside [start, stop] are skipped
/AlignedEmission
{
/expected Set
/h Set
ResetKernel
0 <<
/local_num_threads 1
/resolution h
/off_grid_spiking true
>> SetStatus
/spike_generator Create /sg Set
sg <<
/precise_times true
/spike_times [0.1 5.0 5.3 5.300001 5.399999 5.9 6.0 9.3] % in ms
/origin 0.0 % in ms
/start 5.0 % in ms
/stop 6.0 % in ms, set to 6.0 to keep number of emitted spikes constant
>> SetStatus
/spike_detector Create /sd Set
sd << /withtime true /to_memory true /withgid true /time_in_steps false >> SetStatus
sg sd 1.0 1.0 Connect
7.0 Simulate
sd [ /events /times ] get cva
expected
eq
} def
{
Transpose
{
dup First exch Rest
AlignedEmission
} Map
true exch {and} Fold % all equal ?
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Expected output of this program:
%
[
% h =
[ 0.1 0.2 0.5 1.0 ]
% time stamp
% [5.0 5.0 5.0 5.0]% <-- would be here with /start 4.0
[5.3 5.3 5.3 5.3]
[5.300001 5.300001 5.300001 5.300001]
[5.399999 5.399999 5.399999 5.399999]
[5.9 5.9 5.9 5.9]
[6.0 6.0 6.0 6.0]% <-- with /stop 6.0 this spike is still emitted
]%
exch exec assert_or_die