diff --git a/doc/models_library/ignore_and_fire.rst b/doc/models_library/ignore_and_fire.rst new file mode 100644 index 000000000..cf5c8d82b --- /dev/null +++ b/doc/models_library/ignore_and_fire.rst @@ -0,0 +1,68 @@ +ignore_and_fire +############### + + +ignore_and_fire - Neuron generating spikes at fixed intervals irrespective of inputs + +Description ++++++++++++ + +The ``ignore_and_fire`` neuron is a neuron model generating spikes at a predefined ``firing_rate`` with a constant inter-spike interval ("fire"), irrespective of its inputs ("ignore"). In this simplest version of the ``ignore_and_fire`` neuron, the inputs from other neurons or devices are not processed at all (*). The ``ignore_and_fire`` neuron is primarily used for neuronal-network model verification and validation purposes, in particular, to evaluate the correctness and performance of connectivity generation and inter-neuron communication. It permits an easy scaling of the network size and/or connectivity without affecting the output spike statistics. The amount of network traffic is predefined by the user, and therefore fully controllable and predictable, irrespective of the network size and structure. + +To create asynchronous activity for a population of ``ignore_and_fire`` neurons, the firing ``phase``s can be randomly initialised. Note that the firing ``phase`` is a real number, defined as the time to the next spike relative to the firing period. + +(*) The model can easily be extended and equipped with any arbitrary input processing (such as calculating input currents with alpha-function shaped PSC kernels or updating the gating variables in the Hodgkin-Huxley model) or (after-) spike generation dynamics to make it more similar and comparable to other non-ignorant neuron models. In such extended ignore_and_fire models, the spike emission process would still be decoupled from the intrinsic neuron dynamics. + +Authors ++++++++ + +Tetzlaff (February 2021; January 2022) + + + + +Parameters +++++++++++ +.. csv-table:: + :header: "Name", "Physical unit", "Default value", "Description" + :widths: auto + + + "firing_rate", "Bq", "10.0Bq", "# firing rate" + + + +State variables ++++++++++++++++ + +.. csv-table:: + :header: "Name", "Physical unit", "Default value", "Description" + :widths: auto + + + "phase", "real", "1.0", "# relative time to next spike (in (0,1])" + + + + +Equations ++++++++++ + + + + + +Source code ++++++++++++ + +The model source code can be found in the NESTML models repository here: `ignore_and_fire `_. + +Characterisation +++++++++++++++++ + +.. include:: ignore_and_fire_characterisation.rst + + +.. footer:: + + Generated at 2023-08-08 15:01:40.284515 \ No newline at end of file diff --git a/doc/models_library/index.rst b/doc/models_library/index.rst index c95819a56..1345204a1 100644 --- a/doc/models_library/index.rst +++ b/doc/models_library/index.rst @@ -292,6 +292,15 @@ Wang-Buzsaki model with multiple synapses Source file: `wb_cond_multisyn.nestml `_ + +:doc:`ignore_and_fire ` +------------------------------------ + +Neuron generating spikes at fixed intervals irrespective of inputs + +Source file: `ignore_and_fire.nestml `_ + + Synapse models ~~~~~~~~~~~~~~ diff --git a/models/neurons/ignore_and_fire.nestml b/models/neurons/ignore_and_fire.nestml new file mode 100644 index 000000000..20cc8e2ba --- /dev/null +++ b/models/neurons/ignore_and_fire.nestml @@ -0,0 +1,48 @@ +""" +ignore_and_fire - Neuron generating spikes at fixed intervals irrespective of inputs +###################################################################################### + +Description ++++++++++++ + +The ``ignore_and_fire`` neuron is a neuron model generating spikes at a predefined ``firing_rate`` with a constant inter-spike interval ("fire"), irrespective of its inputs ("ignore"). In this simplest version of the ``ignore_and_fire`` neuron, the inputs from other neurons or devices are not processed at all (*). The ``ignore_and_fire`` neuron is primarily used for neuronal-network model verification and validation purposes, in particular, to evaluate the correctness and performance of connectivity generation and inter-neuron communication. It permits an easy scaling of the network size and/or connectivity without affecting the output spike statistics. The amount of network traffic is predefined by the user, and therefore fully controllable and predictable, irrespective of the network size and structure. + +To create asynchronous activity for a population of ``ignore_and_fire`` neurons, the firing ``phase``s can be randomly initialised. Note that the firing ``phase`` is a real number, defined as the time to the next spike relative to the firing period. + +(*) The model can easily be extended and equipped with any arbitrary input processing (such as calculating input currents with alpha-function shaped PSC kernels or updating the gating variables in the Hodgkin-Huxley model) or (after-) spike generation dynamics to make it more similar and comparable to other non-ignorant neuron models. In such extended ignore_and_fire models, the spike emission process would still be decoupled from the intrinsic neuron dynamics. + +Authors ++++++++ + +Tetzlaff (February 2021; January 2022) + +""" + +neuron ignore_and_fire: + + state: + phase real = 1. ## relative time to next spike (in (0,1]) + + parameters: + firing_rate Bq = 10. Bq ## firing rate + + internals: + firing_period_steps integer = steps( 1. / firing_rate ) ## firing period in steps + phase_steps integer = steps( max(0.,phase) / firing_rate ) ## firing phase in steps + + input: + spikes Bq <- spike ## the neuron receives spikes, but is not processing them + + output: + spike + + update: + integrate_odes() + if phase_steps == 0: + emit_spike() + phase_steps = firing_period_steps - 1 + #println("spike") + else: + phase_steps -= 1 + + phase = 1. * phase_steps / firing_period_steps diff --git a/pynestml/codegeneration/nest_code_generator.py b/pynestml/codegeneration/nest_code_generator.py index 0aa0a48a1..644f2667a 100644 --- a/pynestml/codegeneration/nest_code_generator.py +++ b/pynestml/codegeneration/nest_code_generator.py @@ -281,7 +281,7 @@ def analyse_neuron(self, neuron: ASTNeuron) -> Tuple[Dict[str, ASTAssignment], D self.non_equations_state_variables[neuron.get_name()].extend( ASTUtils.all_variables_defined_in_block(neuron.get_state_blocks())) - return [], [], [], [] + return {}, {}, [], [] if len(neuron.get_equations_blocks()) > 1: raise Exception("Only one equations block per model supported for now") diff --git a/pynestml/transformers/synapse_post_neuron_transformer.py b/pynestml/transformers/synapse_post_neuron_transformer.py index 8b4804c87..606201390 100644 --- a/pynestml/transformers/synapse_post_neuron_transformer.py +++ b/pynestml/transformers/synapse_post_neuron_transformer.py @@ -224,6 +224,9 @@ def transform_neuron_synapse_pair_(self, neuron, synapse): new_neuron = neuron.clone() new_synapse = synapse.clone() + new_neuron.accept(ASTSymbolTableVisitor()) + new_synapse.accept(ASTSymbolTableVisitor()) + assert len(new_neuron.get_equations_blocks()) <= 1, "Only one equations block per neuron supported for now." assert len(new_synapse.get_equations_blocks()) <= 1, "Only one equations block per synapse supported for now." assert len(new_neuron.get_state_blocks()) <= 1, "Only one state block supported per neuron for now." diff --git a/tests/nest_tests/test_ignore_and_fire.py b/tests/nest_tests/test_ignore_and_fire.py new file mode 100644 index 000000000..2bc7c8b13 --- /dev/null +++ b/tests/nest_tests/test_ignore_and_fire.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# +# test_ignore_and_fire.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 . + +import numpy as np +import os +import pytest + +import nest + +from pynestml.codegeneration.nest_tools import NESTTools +from pynestml.frontend.pynestml_frontend import generate_nest_target + +try: + import matplotlib + matplotlib.use("Agg") + import matplotlib.ticker + import matplotlib.pyplot as plt + TEST_PLOTS = True +except Exception: + TEST_PLOTS = False + + +class TestIgnoreAndFire: + + neuron_model_name = "ignore_and_fire_nestml__with_stdp_nestml" + synapse_model_name = "stdp_nestml__with_ignore_and_fire_nestml" + + @pytest.fixture(scope="module", autouse=True) + def setUp(self): + """Generate the model code""" + + codegen_opts = {"neuron_synapse_pairs": [{"neuron": "ignore_and_fire", + "synapse": "stdp", + "post_ports": ["post_spikes"]}]} + + files = [os.path.join("models", "neurons", "ignore_and_fire.nestml"), + os.path.join("models", "synapses", "stdp_synapse.nestml")] + input_path = [os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.join( + os.pardir, os.pardir, s))) for s in files] + generate_nest_target(input_path=input_path, + logging_level="DEBUG", + suffix="_nestml", + codegen_opts=codegen_opts) + + @pytest.mark.skipif(NESTTools.detect_nest_version().startswith("v2"), + reason="This test does not support NEST 2") + def test_ignore_and_fire_with_stdp(self): + resolution = 1. # [ms] + sim_time = 1001. # [ms] + + nest.set_verbosity("M_ALL") + nest.Install("nestmlmodule") + nest.ResetKernel() + nest.SetKernelStatus({"resolution": resolution}) + + pre_neuron = nest.Create(self.neuron_model_name) + post_neuron = nest.Create(self.neuron_model_name) + pre_neuron.firing_rate = 10. + post_neuron.firing_rate = 100. + pre_sr = nest.Create("spike_recorder") + post_sr = nest.Create("spike_recorder") + nest.Connect(pre_neuron, pre_sr) + nest.Connect(post_neuron, post_sr) + + nest.Connect(pre_neuron, post_neuron, syn_spec={"synapse_model": self.synapse_model_name}) + + nest.Simulate(sim_time) + + n_ev_pre = len(pre_sr.get("events")["times"]) + n_ev_post = len(post_sr.get("events")["times"]) + + assert n_ev_pre == pre_neuron.firing_rate + assert n_ev_post == post_neuron.firing_rate