Skip to content

Commit

Permalink
Merge pull request #2815 from nicolossus/port_test_pulsepacket_generator
Browse files Browse the repository at this point in the history
Port `test_pulsepacket_generator` from SLI-2-Py
  • Loading branch information
heplesser authored Jun 28, 2023
2 parents 6c2a396 + ff63411 commit 379d507
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 157 deletions.
17 changes: 8 additions & 9 deletions models/pulsepacket_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ Generate sequence of Gaussian pulse packets
Description
+++++++++++
The pulsepacket_generator produces a spike train contains Gaussian pulse
packets centered about given times. A Gaussian pulse packet is
a given number of spikes with normal distributed random displacements
from the center time of the pulse.
It resembles the output of synfire groups of neurons.
The ``pulsepacket_generator`` produces a spike train contains Gaussian pulse
packets centered about given times. A Gaussian pulse packet is a given
number of spikes with normal distributed random displacements from the center
time of the pulse. It resembles the output of synfire groups of neurons.
- All targets receive identical spike trains.
- New pulse packets are generated when activity or sdev are changed.
- New pulse packets are generated when activity or ``sdev`` are changed.
- Gaussian pulse are independently generated for each given
pulse-center time.
- Both standard deviation and number of spikes may be set at any time.
Expand All @@ -64,13 +63,13 @@ It resembles the output of synfire groups of neurons.
.. include:: ../models/stimulation_device.rst
pulse_times
Times of the centers of pulses (ms)
List of times of the centers of pulses in ms.
activity
Number of spikes per pulse
Number of spikes per pulse. Default: ``0``.
sdev
Standard deviation of spike times in each pulse (ms)
Standard deviation of spike times in each pulse in ms. Default: ``0.0``.
Setting parameters from a stimulation backend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
39 changes: 20 additions & 19 deletions nestkernel/stimulation_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ global offset that shifts the stimulation period. All three values are
set as times in ms.
- For spike-emitting devices, only spikes with times `t` that fulfill
`start` < `t` <= `stop` are emitted. Spikes that have timestamp of
`t` = `start` are not emitted.
:math:`\mathrm{start} < t \leq \mathrm{stop}` are emitted. Spikes
that have timestamp of :math:`t = \mathrm{start}` are not emitted.
- For current-emitting devices, the current is activated and
deactivated such that the current first affects the target dynamics
during the update step (start, start+h], i.e., an effect can be
recorded at the earliest at time start+h. The last interval during
which the current affects the target's dynamics is (stop-h, stop].
during the update step :math:`(\mathrm{start}, \mathrm{start}+h]`,
that is, an effect can be recorded at the earliest at time
:math:`\mathrm{start}+h`. The last interval during which the current
affects the target's dynamics is :math:`(\textrm{stop}-h, \textrm{stop}]`.
The property ``stimulus_source`` defaults to an empty string. It can
be set to the name of a stimulation backend, in which case it will
Expand All @@ -68,28 +69,28 @@ Parameters
++++++++++
label
A string (default: `""`) specifying an arbitrary textual label for
the device. Stimulation backends might use the label to generate
device specific identifiers like filenames and such.
A string specifying an arbitrary textual label for the device.
Stimulation backends might use the label to generate device specific
identifiers like filenames and such. Default: ``""``.
origin
A positive floating point number (default : `0.0`) used as the
reference time in ms for `start` and `stop`.
A positive floating point number used as the reference time in ms
for ``start`` and ``stop``. Default: ``0.0``.
start
A positive floating point number (default: `0.0`) specifying the
activation time in ms, relative to `origin`.
A positive floating point number specifying the activation time in ms,
relative to ``origin``. Default: ``0.0``.
stimulus_source
A string (default: `""`) specifying the name of the stimulation
backend from which to get the data for updating the stimulus
parameters of the device. By default the device uses its
internally stored parameters for updating the stimulus.
A string specifying the name of the stimulation backend from which to
get the data for updating the stimulus parameters of the device.
By default, the device uses its internally stored parameters for updating
the stimulus. Default: ``""``.
stop
A floating point number (default: `infinity`) specifying the
deactivation time in ms, relative to `origin`. The value of `stop`
must be greater than or equal to `start`.
A floating point number specifying the deactivation time in ms, relative
to ``origin``. The value of ``stop`` must be greater than or equal to
``start``. Default: ``infinity``.
EndUserDocs */

Expand Down
128 changes: 128 additions & 0 deletions testsuite/pytests/sli2py_stimulating/test_pulsepacket_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
#
# test_pulsepacket_generator.py
#
# 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/>.

"""
Test parameter setting and correct number of spikes emitted by `pulsepacket_generator`.
"""

import numpy as np
import pandas as pd
import pandas.testing as pdtest
import pytest

import nest


@pytest.fixture(autouse=True)
def reset():
nest.ResetKernel()


def test_set_params_on_instance_and_model():
"""
Test setting `pulsepacket_generator` parameters on instance and model.
"""

params = {"pulse_times": [1.0, 2.5, 4.6], "activity": 150, "sdev": 0.1234}

# Set params on instance
ppg1 = nest.Create("pulsepacket_generator")
ppg1.set(params)

# Set params on model
nest.SetDefaults("pulsepacket_generator", params)
ppg2 = nest.Create("pulsepacket_generator")

# Verify that both ways to set params give same result
df_pgg1 = pd.DataFrame.from_dict(ppg1.get(params.keys()))
df_pgg2 = pd.DataFrame.from_dict(ppg2.get(params.keys()))
pdtest.assert_frame_equal(df_pgg1, df_pgg2)


@pytest.mark.parametrize("params", [{"sdev": -5.0}, {"activity": -5}])
def test_set_illegal_values(params):
"""
Test that an error is raised if `sdev` or `activity` is set to negative value.
"""

with pytest.raises(nest.kernel.NESTErrors.BadProperty):
nest.SetDefaults("pulsepacket_generator", params)


def test_valid_to_pass_empty_pulse_times():
"""
Assure that a `pulsepacket_generator` with empty `pulse_times` can be simulated.
"""

params = {"pulse_times": [], "activity": 0, "sdev": 0.0}
ppg = nest.Create("pulsepacket_generator")
ppg.set(params)
nest.Simulate(1.0)


def test_number_of_spikes():
"""
Test that `pulsepacket_generator` emits expected number of spikes.
The test builds and simulates a system with `pulsepacket_generator`
connected to a `spike_recorder`. The test checks the number of
recorded spikes against our expectation.
"""

nest.resolution = 0.1

tstart = 75.0
tstop = 225.0
nspk = 10
pulset = np.array([10.0, 125.0, 175.0, 275.0])
stddev = 5.0

# Find number of pulse centers in [tstart, tstop]
npulseff = np.count_nonzero(np.logical_and(pulset >= tstart, pulset <= tstop))

# Since tstart, tstop are far from pulse times, it is highly likely that
# only spikes belonging to the pulses with centers in [tstart, tstop] are
# fired and then we get for the total spike number
npsktot = nspk * npulseff

# Build and simulate system
params = {
"start": tstart,
"stop": tstop,
"pulse_times": pulset,
"activity": nspk,
"sdev": stddev,
}
ppg = nest.Create("pulsepacket_generator", params)
sr = nest.Create("spike_recorder")

nest.Connect(ppg, sr)

nest.Simulate(300.0)

actual_spikes = sr.events["times"]

# Check that min and max are inside [tstart, tstop]
assert np.min(actual_spikes) >= tstart
assert np.max(actual_spikes) <= tstop

# Check number of spikes
assert actual_spikes.size == npsktot
129 changes: 0 additions & 129 deletions testsuite/unittests/test_pulsepacket_generator.sli

This file was deleted.

0 comments on commit 379d507

Please sign in to comment.