Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compilation error when synapse model uses random_normal function #805

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -399,6 +399,9 @@ private:
update_internal_state_(double t_start, double timestep, const {{synapseName}}CommonSynapseProperties& cp);

void recompute_internal_variables();
{%- if norm_rng %}
int get_thread();
{%- endif %}

{#
/**
Expand Down Expand Up @@ -1091,6 +1094,15 @@ void {{synapseName}}< targetidentifierT >::recompute_internal_variables()
{%- endfilter %}
}

{%- if norm_rng %}
template < typename targetidentifierT >
int {{synapseName}}< targetidentifierT >::get_thread()
{
const thread tid = kernel().vp_manager.get_thread_id();
return tid;
}
{%- endif %}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use kernel().vp_manager.get_thread_id() directly wherever this is needed? I'm not sure I like this additional indirection... Optimally, I think get_thread_id() should just be available as an API function in the nest namespace defined in nestkernel/nest.h in NEST Simulator proper.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated code for the random_normal() function from NESTML is the same for both neurons and synapses. See here. The neuron already has an implementation of the get_thread() function in its base class whereas the synapse doesn't. Hence this PR adds a private implementation for the function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should synapses instead use the thread t that is passed as a parameter to the send() method, rather than calling kernel().vp_manager.get_thread_id()? (cc @jougs)

/**
* constructor
**/
Expand Down
79 changes: 79 additions & 0 deletions tests/nest_tests/resources/stdp_stp_synapse.nestml
@@ -0,0 +1,79 @@
"""
stdp_stp - Synapse model for spike-timing dependent plasticity
##############################################################

Copyright statement
+++++++++++++++++++

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/>.
"""
synapse stdp_stp:

state:
w real = 1. @nest::weight
u real = U # facilitation
x real = 1. # depression
a_pre real = 0.
a_post real = 0.
end

parameters:
#STP
U real = random_normal(0.5, 0.25)
tau_d ms = random_normal(110 ms, 55 ms) # depression timescale
tau_f ms = random_normal(5 ms, 2.5 ms) # facilitation timescale
foo real = random_uniform(0, 1) # test parameter for random uniform

#STDP
d ms = 3. ms @nest::delay # !!! cannot have a variable called "delay"
tau_tr_pre ms = 15 ms # presynaptic time constant
tau_tr_post ms = 30 ms # postsynaptic time constant
A_plus real = 0.48 # presynaptic amplitude
A_minus real = -0.24 # postsynaptic amplitude

end

equations:
u' = (U - u) / tau_f # STP
x' = (1 - x) / tau_d # STP

a_pre' = -a_pre/tau_tr_pre # STDP
a_post' = -a_post/tau_tr_post # STDP
end

input:
pre_spikes nS <- spike
post_spikes nS <- spike
end

output: spike

# potentiation
onReceive(post_spikes):
w_ real = w + a_pre
end

onReceive(pre_spikes):
w_eff real = u * x * w # compute effective weight changing the conductance

x -= x * u # STD
u += U * (1 - u) # STF

deliver_spike(w_eff, d)
end
end
55 changes: 55 additions & 0 deletions tests/nest_tests/stdp_stp_synapse_test.py
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
#
# stdp_stp_synapse_test.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/>.
import os

import nest
import pytest

from pynestml.codegeneration.nest_tools import NESTTools
from pynestml.frontend.pynestml_frontend import generate_nest_target

nest_version = NESTTools.detect_nest_version()


@pytest.mark.skipif(nest_version.startswith("v2"),
reason="This test does not support NEST 2")
def test_stdp_stp_synapse():
"""
This test currently verifies the code generation and compilation when a synapse model has the function ``random_normal()`` defined.

TODO: The test needs to be improved by adding more functionality and assertions.
:return:
"""
input_path = [os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.join(os.pardir, os.pardir, "models", "neurons", "iaf_psc_delta.nestml"))),
os.path.realpath(os.path.join(os.path.dirname(__file__), "resources", "stdp_stp_synapse.nestml"))]
target_path = "/tmp/nestml-stdp-stp"
module_name = "nestml_module"
generate_nest_target(input_path=input_path,
target_path=target_path,
logging_level="INFO",
module_name=module_name,
suffix="_nestml",
codegen_opts={"neuron_parent_class": "StructuralPlasticityNode",
"neuron_parent_class_include": "structural_plasticity_node.h",
"neuron_synapse_pairs": [{"neuron": "iaf_psc_delta",
"synapse": "stdp_stp",
"post_ports": ["post_spikes"]}]})
nest.Install(module_name)