Skip to content

Commit

Permalink
Fix special handling of NEST delay and weight variables in synapse (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
clinssen authored Jun 12, 2024
1 parent 4fb3c96 commit fef2d71
Show file tree
Hide file tree
Showing 79 changed files with 5,829 additions and 6,215 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nestml-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ jobs:
done;
exit $rc
# Run only the nest_integration_test for the NEST versions other than master and 2.20.2
# Run only the nest integration tests for NEST versions other than master and 2.20.2
- name: Run integration tests
if: ${{ !(matrix.nest_branch == 'master' || matrix.nest_branch == 'v2.20.2') }}
env:
Expand Down
76 changes: 0 additions & 76 deletions doc/nestml_language/synapses_in_nestml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -488,82 +488,6 @@ Further integration with NEST Simulator is planned, to achieve a just-in-time co
Code generator options instruct the target platform code generator (in this case, NEST) how to process the models.



The NEST target
---------------

Event-based updating
~~~~~~~~~~~~~~~~~~~~

NEST target synapses are not allowed to have any time-based internal dynamics (ODEs). This is due to the fact that synapses are, unlike nodes, not updated on a regular time grid.

The synapse is allowed to contain an ``update`` block. Statements in the ``update`` block are executed whenever the internal state of the synapse is updated from one timepoint to the next; these updates are typically triggered by incoming spikes. The NESTML ``resolution()`` function will return the time that has elapsed since the last event was handled.


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:

.. code:: nestml
parameters:
dend_delay ms = 1 ms @nest::delay
Generating code
---------------

When NESTML is invoked to generate code for plastic synapses, the code generator needs to know which neuron model the synapses will be connected to, so that it can generate fast C++ code for the neuron and the synapse that is mutually dependent at runtime. These pairs can be specified as a list of two-element dictionaries of the form :python:`{"neuron": "neuron_model_name", "synapse": "synapse_model_name"}`, for example:

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp"}]})
Additionally, if the synapse requires it, specify the ``"post_ports"`` entry to connect the input port on the synapse with the right variable of the postsynaptic neuron:

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp",
"post_ports": ["post_spikes",
["I_post_dend", "I_dend"]]}]})
This specifies that the neuron ``iaf_psc_exp_dend`` has to be generated paired with the synapse ``third_factor_stdp``, and that the input ports ``post_spikes`` and ``I_post_dend`` in the synapse are to be connected to the postsynaptic partner. For the ``I_post_dend`` input port, the corresponding variable in the (postsynaptic) neuron is called ``I_dend``.

Simulation of volume-transmitted neuromodulation in NEST can be done using "volume transmitter" devices [5]_. These are event-based and should correspond to a "spike" type input port in NESTML. The code generator options keyword "vt_ports" can be used here.

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp",
"vt_ports": ["dopa_spikes"]}]})
Implementation notes
~~~~~~~~~~~~~~~~~~~~

Note that ``access_counter`` now has an extra multiplicative factor equal to the number of trace values that exist, so that spikes are removed from the history only after they have been read out for the sake of computing each trace.

.. figure:: https://www.frontiersin.org/files/Articles/1382/fncom-04-00141-r1/image_m/fncom-04-00141-g003.jpg

Potjans et al. 2010

Random numbers
~~~~~~~~~~~~~~

In case random numbers are needed inside the synapse, the random number generator belonging to the postsynaptic target is used.



References
----------

Expand Down
117 changes: 99 additions & 18 deletions doc/running/running_nest.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
NEST Simulator target
---------------------
=====================

*NESTML features supported:* :doc:`neurons </nestml_language/neurons_in_nestml>`, :doc:`synapses </nestml_language/synapses_in_nestml>`, :ref:`vectors <Vectors>`, :ref:`delay differential equations <Delay Differential Equations>`, :ref:`guards <Guards>`

After NESTML completes, the NEST extension module (by default called ``"nestmlmodule"``) can either be statically linked into NEST (see `Writing an extension module <https://nest-extension-module.readthedocs.io/>`_), or loaded dynamically using the ``Install`` API call in Python.


Simulation loop
~~~~~~~~~~~~~~~
---------------

Note that NEST Simulator uses a hybrid integration strategy [Hanuschkin2010]_; see :numref:`fig_integration_order`, panel A for a graphical depiction.

Expand All @@ -18,36 +18,40 @@ Then, the code is run corresponding to the NESTML ``update`` block.
At the end of the timestep, variables corresponding to convolutions are updated according to their ODE dynamics.


Code generation options
~~~~~~~~~~~~~~~~~~~~~~~
Event-based updating of synapses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Several code generator options are available; for an overview see :class:`pynestml.codegeneration.nest_code_generator.NESTCodeGenerator`.
The synapse is allowed to contain an ``update`` block. Statements in the ``update`` block are executed whenever the internal state of the synapse is updated from one timepoint to the next; these updates are typically triggered by incoming spikes. The NESTML ``resolution()`` function will return the time that has elapsed since the last event was handled.

Synapses in NEST are not allowed to have any nonlinear time-based internal dynamics (ODEs). This is due to the fact that synapses are, unlike nodes, not updated on a regular time grid. Linear ODEs are allowed, because they admit an analytical solution, which can be updated in a single step from the previous event time to the current event time. However, nonlinear dynamics are not allowed because they would require a numeric solver evaluating the dynamics on a regular time grid.

If ODE-toolbox is not successful in finding the propagator solver to a system of ODEs that is, however, solvable, the propagators may be entered "by hand" in the ``update`` block of the model. This block may contain any series of statements to update the state of the system from the current timestep to the next, for example, multiplications of state variables by the propagators.


Setting and retrieving model properties
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---------------------------------------

- All variables in the ``state`` and ``parameters`` blocks are added to the status dictionary of the neuron.
- Values can be set using the PyNEST API call ``node_collection.<variable> = <value>`` where ``<variable>`` is the name of the corresponding NESTML variable.
- Values can be read using the PyNEST API call ``node_collection.<variable>``. This will return the value of the corresponding NESTML variable.


Recording values with devices
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------

All values in the ``state`` block are recordable by a ``multimeter`` in NEST.


Solver selection
~~~~~~~~~~~~~~~~
----------------

Currently, there is support for GSL, forward Euler, and exact integration. ODEs that can be solved analytically are integrated to machine precision from one timestep to the next. To allow more precise values for analytically solvable ODEs *within* a timestep, the same ODEs are evaluated numerically by the GSL solver. In this way, the long-term dynamics obeys the "exact" equations, while the short-term (within one timestep) dynamics is evaluated to the precision of the numerical integrator.

In the case that the model is solved with the GSL integrator, desired absolute error of an integration step can be adjusted with the ``gsl_error_tol`` parameter in a ``SetStatus`` call. The default value of ``gsl_error_tol`` is ``1e-3``.


Manually building the extension module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--------------------------------------

Sometimes it can be convenient to directly edit the generated code. To manually build and install the NEST extension module, go into the target directory and run:

Expand All @@ -60,14 +64,8 @@ Sometimes it can be convenient to directly edit the generated code. To manually
where ``<nest_install_dir>`` is the installation directory of NEST (e.g. ``/home/nest/work/nest-install``).


Custom templates
~~~~~~~~~~~~~~~~

See :ref:`Running NESTML with custom templates`.


Gap junctions (electrical synapses)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------

Each neuron model can be endowed with gap junctions. The model does not need to be (necessarily) modified itself, but additional flags are passed during code generation that identify which model variables correspond to the membrane potential and the gap junction current. For instance, the code generator options can look as follows:

Expand All @@ -83,7 +81,7 @@ For a full example, please see `test_gap_junction.py <https://github.com/nest/ne


Multiple input ports in NEST
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
----------------------------

See :ref:`Multiple input ports` to specify multiple input ports in a neuron.

Expand Down Expand Up @@ -174,6 +172,80 @@ The above code querying for ``receptor_types`` gives a list of port names and NE

For a full example, please see `iaf_psc_exp_multisynapse_vectors.nestml <https://github.com/nest/nestml/blob/master/tests/nest_tests/resources/iaf_psc_exp_multisynapse_vectors.nestml>`_ for the neuron model and ``test_multisynapse_with_vector_input_ports`` in `tests/nest_tests/nest_multisynapse_test.py <https://github.com/nest/nestml/blob/master/tests/nest_tests/nest_multisynapse_test.py>`_ for the corresponding test.


Generating code
---------------

.. note::

Several code generator options are available; for an overview see :class:`pynestml.codegeneration.nest_code_generator.NESTCodeGenerator`.

Generating code for plastic synapses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When NESTML is invoked to generate code for plastic synapses, the code generator needs to know which neuron model the synapses will be connected to, so that it can generate fast C++ code for the neuron and the synapse that is mutually dependent at runtime. These pairs can be specified as a list of two-element dictionaries of the form :python:`{"neuron": "neuron_model_name", "synapse": "synapse_model_name"}`, for example:

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp"}]})
Additionally, if the synapse requires it, specify the ``"post_ports"`` entry to connect the input port on the synapse with the right variable of the postsynaptic neuron:

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp",
"post_ports": ["post_spikes",
["I_post_dend", "I_dend"]]}]})
This specifies that the neuron ``iaf_psc_exp_dend`` has to be generated paired with the synapse ``third_factor_stdp``, and that the input ports ``post_spikes`` and ``I_post_dend`` in the synapse are to be connected to the postsynaptic partner. For the ``I_post_dend`` input port, the corresponding variable in the (postsynaptic) neuron is called ``I_dend``.

Simulation of volume-transmitted neuromodulation in NEST can be done using "volume transmitter" devices [5]_. These are event-based and should correspond to a "spike" type input port in NESTML. The code generator options keyword ``"vt_ports"`` can be used here.

.. code-block:: python
generate_target(...,
codegen_opts={...,
"neuron_synapse_pairs": [{"neuron": "iaf_psc_exp_dend",
"synapse": "third_factor_stdp",
"vt_ports": ["dopa_spikes"]}]})
Dendritic delay and synaptic weight
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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 the code generator options ``delay_variable`` and ``weight_variable``. For example, given the following model:

.. code:: nestml
synapse my_synapse:
state:
w real = 1.
parameters:
dend_delay ms = 1 ms
the variables might be specified as:

.. code-block:: python
generate_target(...,
codegen_opts={...,
"delay_variable": {"my_synapse": "dend_delay"},
"weight_variable": {"my_synapse": "w"}})
Custom templates
~~~~~~~~~~~~~~~~

See :ref:`Running NESTML with custom templates`.


Compatibility with different versions of NEST
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -182,9 +254,18 @@ To generate code that is compatible with particular versions of NEST Simulator,
- The default is the empty string, which causes the NEST version to be automatically identified from the ``nest`` Python module.
- ``"master"``: Latest NEST GitHub master branch version (https://github.com/nest/nest-simulator/).
- ``"v2.20.2"``: Latest NEST 2 release.
- ``"v3.0"``, ``"v3.1"``, ``"v3.2"``, ``"v3.3"``, ``"v3.4"``: NEST 3 release versions.
- ``"v3.0"``, ``"v3.1"``, ``"v3.2"``, etc.: NEST 3 release versions.

For a list of the corresponding NEST Simulator repository tags, please see https://github.com/nest/nest-simulator/tags.


Random numbers
--------------

In case random numbers are needed inside the synapse, the random number generator belonging to the postsynaptic target is used.


References
----------

.. [Hanuschkin2010] Alexander Hanuschkin and Susanne Kunkel and Moritz Helias and Abigail Morrison and Markus Diesmann. A General and Efficient Method for Incorporating Precise Spike Times in Globally Time-Driven Simulations. Frontiers in Neuroinformatics, 2010, Vol. 4
Loading

0 comments on commit fef2d71

Please sign in to comment.