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

Improve handling of NEST synaptic delay parameter #887

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/nestml_language/synapses_in_nestml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,13 @@ The synapse is allowed to contain an ``update`` block. Statements in the ``updat
Dendritic delay
~~~~~~~~~~~~~~~

In NEST, all synapses are expected to specify a nonzero dendritic delay, that is, the delay between arrival of a spike at the dendritic spine and the time at which its effects are felt at the soma (or conversely, the delay between a somatic action potential and the arrival at the dendritic spine due to dendritic backpropagation). To indicate that a given parameter is specifying this NEST-specific delay value, use an annotation:
In NEST, all synapses are expected to specify a nonzero dendritic delay, that is, the delay between arrival of a spike at the dendritic spine and the time at which its effects are felt at the soma (or conversely, the delay between a somatic action potential and the arrival at the dendritic spine due to dendritic backpropagation). As delays and weights are hard-wired into the NEST C++ base classes for the NESTML synapse classes, special annotations must be made in the NESTML model to indicate which state variables or parameters correspond to weight and delay. To indicate the correspondence, use an annotation:

.. code:: nestml

state:
w ms = 1 ms @nest::weight

parameters:
dend_delay ms = 1 ms @nest::delay

Expand Down
6,073 changes: 5,949 additions & 124 deletions doc/tutorials/stdp_dopa_synapse/stdp_dopa_synapse.ipynb

Large diffs are not rendered by default.

1,031 changes: 957 additions & 74 deletions doc/tutorials/stdp_windows/stdp_windows.ipynb

Large diffs are not rendered by default.

1,720 changes: 1,639 additions & 81 deletions doc/tutorials/triplet_stdp_synapse/triplet_stdp_synapse.ipynb

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion models/neurons/wb_cond_multisyn.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ wb_cond_multisyn
neuron wb_cond_multisyn:
state:
r integer = 0 # number of steps in the current refractory phase

V_m mV = -65. mV # Membrane potential
Inact_h real = alpha_h_init / ( alpha_h_init + beta_h_init ) # Inactivation variable h for Na
Act_n real = alpha_n_init / (alpha_n_init + beta_n_init) # Activation variable n for K
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/neuromodulated_stdp.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ References
"""
synapse neuromodulated_stdp:
state:
w real = 1.
w real = 1. @nest::weight # Synaptic weight
n real = 0. # Neuromodulator concentration
c real = 0. # Eligibility trace
pre_tr real = 0.
post_tr real = 0.

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay
tau_tr_pre ms = 20 ms # STDP time constant for weight changes caused by pre-before-post spike pairings.
tau_tr_post ms = 20 ms # STDP time constant for weight changes caused by post-before-pre spike pairings.
tau_c ms = 1000 ms # Time constant of eligibility trace
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/noisy_synapse.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Each presynaptic spike is passed to the postsynaptic partner with a weight sampl
"""
synapse noisy_synapse:
parameters:
w real = 1 # Synaptic weight
d ms = 1 ms @nest::delay # Synaptic transmission delay
w real = 1. @nest::weight # Synaptic weight
d ms = 1 ms @nest::delay # Synaptic transmission delay
A_noise real = .4

input:
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/stdp_nn_pre_centered.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ References
"""
synapse stdp_nn_pre_centered:
state:
w real = 1 # Synaptic weight
w real = 1. @nest::weight # Synaptic weight
pre_trace real = 0.
post_trace real = 0.

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay
lambda real = .01
tau_tr_pre ms = 20 ms
tau_tr_post ms = 20 ms
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/stdp_nn_restr_symm.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ References
"""
synapse stdp_nn_restr_symm:
state:
w real = 1. # Synaptic weight
w real = 1. @nest::weight # Synaptic weight
pre_trace real = 0.
post_trace real = 0.
pre_handled boolean = True

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay
lambda real = .01
tau_tr_pre ms = 20 ms
tau_tr_post ms = 20 ms
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/stdp_nn_symm.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ References
"""
synapse stdp_nn_symm:
state:
w real = 1. # Synaptic weight
w real = 1. @nest::weight # Synaptic weight
pre_trace real = 0.
post_trace real = 0.

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay
lambda real = .01
tau_tr_pre ms = 20 ms
tau_tr_post ms = 20 ms
Expand Down
12 changes: 6 additions & 6 deletions models/synapses/stdp_triplet_naive.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ References
"""
synapse stdp_triplet:
state:
w nS = 1 nS # Synaptic weight
w real = 1. @nest::weight # Synaptic weight

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay

tau_plus ms = 16.8 ms # time constant for tr_r1
tau_x ms = 101 ms # time constant for tr_r2
Expand Down Expand Up @@ -61,14 +61,14 @@ synapse stdp_triplet:

onReceive(post_spikes):
# potentiate synapse
#w_ nS = Wmax * ( w / Wmax + tr_r1 * ( A2_plus + A3_plus * tr_o2 ) )
w_ nS = w + tr_r1 * ( A2_plus + A3_plus * tr_o2 )
#w_ real = Wmax * ( w / Wmax + tr_r1 * ( A2_plus + A3_plus * tr_o2 ) )
w_ real = w + tr_r1 * ( A2_plus + A3_plus * tr_o2 )
w = min(Wmax, w_)

onReceive(pre_spikes):
# depress synapse
#w_ nS = Wmax * ( w / Wmax - tr_o1 * ( A2_minus + A3_minus * tr_r2 ) )
w_ nS = w - tr_o1 * ( A2_minus + A3_minus * tr_r2 )
#w_ real = Wmax * ( w / Wmax - tr_o1 * ( A2_minus + A3_minus * tr_r2 ) )
w_ real = w - tr_o1 * ( A2_minus + A3_minus * tr_r2 )
w = max(Wmin, w_)

# deliver spike to postsynaptic partner
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/third_factor_stdp_synapse.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ References
"""
synapse third_factor_stdp:
state:
w real = 1. # Synaptic weight
w real = 1. @nest::weight # Synaptic weight

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay
lambda real = .01
tau_tr_pre ms = 20 ms
tau_tr_post ms = 20 ms
Expand Down
4 changes: 2 additions & 2 deletions models/synapses/triplet_stdp_synapse.nestml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ References
"""
synapse stdp_triplet_nn:
state:
w nS = 1 nS # Synaptic weight
w real = 1. @nest::weight # Synaptic weight

tr_r1 real = 0.
tr_r2 real = 0.
tr_o1 real = 0.
tr_o2 real = 0.

parameters:
d ms = 1 ms @nest::delay # Synaptic transmission delay
d ms = 1 ms @nest::delay # Synaptic transmission delay

tau_plus ms = 16.8 ms # time constant for tr_r1
tau_x ms = 101 ms # time constant for tr_r2
Expand Down
4 changes: 4 additions & 0 deletions pynestml/cocos/co_co_all_variables_defined.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def check_co_co(cls, node: ASTNeuron, after_ast_rewrite: bool = False):
for var in vars:
symbol = var.get_scope().resolve_to_symbol(var.get_complete_name(), SymbolKind.VARIABLE)

if var.alternate_scope:
# external reference resolved in a different scope
continue

# test if the symbol has been defined at least
if symbol is None:
if after_ast_rewrite: # after ODE-toolbox transformations, convolutions are replaced by state variables, so cannot perform this check properly
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# co_co_nest_delay_decorator_specified.py
# co_co_nest_decorators_specified.py
#
# This file is part of NEST.
#
Expand All @@ -25,9 +25,9 @@
from pynestml.utils.messages import Messages


class CoCoNESTDelayDecoratorSpecified(CoCo):
class CoCoNESTDecoratorsSpecified(CoCo):
"""
This CoCo ensures that there is precisely one parameter decorated as "@nest::delay".
This CoCo ensures that there is precisely one variable decorated as "@nest::delay" and one as "@nest::weight".
"""

@classmethod
Expand All @@ -36,14 +36,23 @@ def check_co_co(cls, node: ASTNeuronOrSynapse):
Checks if the coco applies for the node.
:param node:
"""
decorator_found = False
for variable in node.get_parameter_symbols() + node.get_internal_symbols():
delay_decorator_found = False
weight_decorator_found = False
for variable in node.get_state_symbols() + node.get_parameter_symbols() + node.get_internal_symbols():
if variable.get_namespace_decorator("nest") == "delay":
decorator_found = True
break
delay_decorator_found = True

if not decorator_found:
if variable.get_namespace_decorator("nest") == "weight":
weight_decorator_found = True

if not delay_decorator_found:
code, message = Messages.get_nest_delay_decorator_not_found()
Logger.log_message(node=node, error_position=None,
code=code, message=message,
log_level=LoggingLevel.ERROR)

if not weight_decorator_found:
code, message = Messages.get_nest_weight_decorator_not_found()
Logger.log_message(node=node, error_position=None,
code=code, message=message,
log_level=LoggingLevel.ERROR)
4 changes: 2 additions & 2 deletions pynestml/cocos/co_co_no_kernels_except_in_convolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
from pynestml.cocos.co_co import CoCo
from pynestml.meta_model.ast_function_call import ASTFunctionCall
from pynestml.meta_model.ast_node import ASTNode
from pynestml.meta_model.ast_external_variable import ASTExternalVariable
from pynestml.meta_model.ast_kernel import ASTKernel
from pynestml.meta_model.ast_variable import ASTVariable
from pynestml.symbols.symbol import SymbolKind
from pynestml.utils.logger import Logger, LoggingLevel
from pynestml.utils.messages import Messages
Expand Down Expand Up @@ -84,7 +84,7 @@ def visit_variable(self, node: ASTNode):
symbol = node.get_scope().resolve_to_symbol(kernelName, SymbolKind.VARIABLE)
# if it is not a kernel just continue
if symbol is None:
if not isinstance(node, ASTExternalVariable):
if not (isinstance(node, ASTVariable) and node.get_alternate_name()):
code, message = Messages.get_no_variable_found(kernelName)
Logger.log_message(node=self.__neuron_node, code=code, message=message, log_level=LoggingLevel.ERROR)
continue
Expand Down
1 change: 1 addition & 0 deletions pynestml/codegeneration/nest_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def build(self) -> None:
n_cpu = len(os.sched_getaffinity(0)) # only available on Linux
except AttributeError:
n_cpu = os.cpu_count()
n_cpu = 8

nest_config_path = f"-Dwith-nest={os.path.join(nest_path, 'bin', 'nest-config')}"
cmake_cmd = ['cmake', nest_config_path, install_prefix, '.']
Expand Down
6 changes: 4 additions & 2 deletions pynestml/codegeneration/nest_code_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import odetoolbox
import pynestml

from pynestml.cocos.co_co_nest_delay_decorator_specified import CoCoNESTDelayDecoratorSpecified
from pynestml.cocos.co_co_nest_decorators_specified import CoCoNESTDecoratorsSpecified
from pynestml.codegeneration.code_generator import CodeGenerator
from pynestml.codegeneration.nest_assignments_helper import NestAssignmentsHelper
from pynestml.codegeneration.nest_code_generator_utils import NESTCodeGeneratorUtils
Expand Down Expand Up @@ -212,7 +212,7 @@ def set_options(self, options: Mapping[str, Any]) -> Mapping[str, Any]:

def run_nest_target_specific_cocos(self, neurons: Sequence[ASTNeuron], synapses: Sequence[ASTSynapse]):
for synapse in synapses:
CoCoNESTDelayDecoratorSpecified.check_co_co(synapse)
CoCoNESTDecoratorsSpecified.check_co_co(synapse)
if Logger.has_errors(synapse):
raise Exception("Error(s) occurred during code generation")

Expand Down Expand Up @@ -400,6 +400,8 @@ def analyse_synapse(self, synapse: ASTSynapse) -> Dict[str, ASTAssignment]:
ASTUtils.add_timestep_symbol(synapse)

ASTUtils.update_blocktype_for_common_parameters(synapse)
ASTUtils.set_nest_namespace_decorator_alternate_name(synapse, {"delay": "get_delay()",
"weight": "get_weight()"})

return spike_updates

Expand Down
10 changes: 2 additions & 8 deletions pynestml/codegeneration/printers/nest_variable_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from pynestml.codegeneration.printers.cpp_variable_printer import CppVariablePrinter
from pynestml.codegeneration.printers.expression_printer import ExpressionPrinter
from pynestml.codegeneration.nest_unit_converter import NESTUnitConverter
from pynestml.meta_model.ast_external_variable import ASTExternalVariable
from pynestml.meta_model.ast_variable import ASTVariable
from pynestml.symbols.predefined_units import PredefinedUnits
from pynestml.symbols.predefined_variables import PredefinedVariables
Expand Down Expand Up @@ -56,13 +55,8 @@ def print_variable(self, variable: ASTVariable) -> str:
"""
assert isinstance(variable, ASTVariable)

if isinstance(variable, ASTExternalVariable):
_name = str(variable)
if variable.get_alternate_name():
# the disadvantage of this approach is that the time the value is to be obtained is not explicitly specified, so we will actually get the value at the end of the min_delay timestep
return "((post_neuron_t*)(__target))->get_" + variable.get_alternate_name() + "()"

return "((post_neuron_t*)(__target))->get_" + _name + "(_tr_t)"
if variable.get_alternate_name():
return variable.get_alternate_name()

if variable.get_name() == PredefinedVariables.E_CONSTANT:
return "numerics::e"
Expand Down
5 changes: 2 additions & 3 deletions pynestml/codegeneration/printers/python_variable_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from pynestml.codegeneration.printers.expression_printer import ExpressionPrinter
from pynestml.codegeneration.printers.variable_printer import VariablePrinter
from pynestml.codegeneration.python_code_generator_utils import PythonCodeGeneratorUtils
from pynestml.meta_model.ast_external_variable import ASTExternalVariable
from pynestml.meta_model.ast_variable import ASTVariable
from pynestml.symbols.predefined_units import PredefinedUnits
from pynestml.symbols.predefined_variables import PredefinedVariables
Expand Down Expand Up @@ -68,8 +67,8 @@ def print_variable(self, variable: ASTVariable) -> str:
"""
assert isinstance(variable, ASTVariable)

if isinstance(variable, ASTExternalVariable):
raise Exception("Python-standalone target does not support synapses")
if variable.get_alternate_name():
raise Exception("Python-standalone target does not support alternate names for variables")

if variable.get_name() == PredefinedVariables.E_CONSTANT:
return "math.e"
Expand Down
Loading
Loading