Skip to content

Commit

Permalink
Merge pull request #964 from steffengraber/gh-pages-model-conversion-5g
Browse files Browse the repository at this point in the history
NEST Developer Space: Add instructions for updating models to NEST 2.16
  • Loading branch information
heplesser committed Jun 14, 2018
2 parents bb51eee + 1b31003 commit 08844a5
Show file tree
Hide file tree
Showing 3 changed files with 314 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
_site
Gemfile.lock
doc/_build
.idea
13 changes: 12 additions & 1 deletion index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,23 @@ can either be static or implement synaptic plasticity rules such as
* [Synapses in NEST: An overview](synapses_overview)
* [Developing synapse models](synapse_models)

## Updating models to 2.16

With the introduction of the new connection infrastructure of the [5g kernel](https://www.frontiersin.org/articles/10.3389/fninf.2018.00002/full),
rate neuron, synapse and device models need to be slightly adapted from prior
versions to be compatible with the latest release (2.16). In the following we describe
all necessary changes:

* [How to update models from NEST 2.14 or prior to 2.16](model_conversion_5g)

## Updating models to 2.6 or later

If you find models written for NEST version 2.4 and prior not
working anymore in newer versions, it is most likely due to recent
updates to the API for neuron and synapse models. We've put together
a conversion guide to make the transition of models easier for you:

* [Updating models for NEST 2.4 or prior to 2.6 or later](model_conversion_3g_4g)
* [How to update models from NEST 2.4 or prior to 2.6 or later](model_conversion_3g_4g)

# Dig deeper!

Expand Down
300 changes: 300 additions & 0 deletions model_conversion_5g.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
---
layout: index
---

[« Back to the index](index)

<hr>

# Updating models from 2.14 or prior to 2.16

With the introduction of the new connection infrastructure of the
[5g kernel](https://www.frontiersin.org/articles/10.3389/fninf.2018.00002/full),
rate neuron, synapse and device models need to be slightly adapted from prior
versions to be compatible with the latest release (2.16). The following
describes all necessary changes. If you still encounter issues after
following these instructions, please contact the
[NEST User mailing list](http://mail.nest-initiative.org/cgi-bin/mailman/listinfo/nest_user),
create an [issue on GitHub](https://github.com/nest/nest-simulator/issues), or
directly submit a pull request, updating these instructions.

## Converting rate-neuron models

Since events are now delivered in the same timestep as they are communicated,
there is no need to correct for the min-delay duration in the `handle`
functions of rate neuron models. Remove `- kernel().connection_manager
.get_min_delay()` in the `handle(...)` functions of all rate models. There is
no need to adapt spiking models, since these carry the correct time stamp.

```diff
diff --git a/models/rate_neuron_ipn_impl.h b/models/rate_neuron_ipn_impl.h
index 8da17690f..3f7feac63 100644
--- a/models/rate_neuron_ipn_impl.h
+++ b/models/rate_neuron_ipn_impl.h
@@ -444,28 +444,24 @@ nest::rate_neuron_ipn< TNonlinearities >::handle(
if ( e.get_weight() >= 0.0 )
{
B_.delayed_rates_ex_.add_value(
- e.get_delay() - kernel().connection_manager.get_min_delay() + i,
- e.get_weight() * e.get_coeffvalue( it ) );
+ e.get_delay() + i, e.get_weight() * e.get_coeffvalue( it ) );
}
else
{
B_.delayed_rates_in_.add_value(
- e.get_delay() - kernel().connection_manager.get_min_delay() + i,
- e.get_weight() * e.get_coeffvalue( it ) );
+ e.get_delay() + i, e.get_weight() * e.get_coeffvalue( it ) );
}
}
else
{
if ( e.get_weight() >= 0.0 )
{
- B_.delayed_rates_ex_.add_value(
- e.get_delay() - kernel().connection_manager.get_min_delay() + i,
+ B_.delayed_rates_ex_.add_value( e.get_delay() + i,
e.get_weight() * nonlinearities_.input( e.get_coeffvalue( it ) ) );
}
else
{
- B_.delayed_rates_in_.add_value(
- e.get_delay() - kernel().connection_manager.get_min_delay() + i,
+ B_.delayed_rates_in_.add_value( e.get_delay() + i,
e.get_weight() * nonlinearities_.input( e.get_coeffvalue( it ) ) );
}
}
```

## Converting synapse models

The time of the last spike going through a particular connection
(`t_lastspike`) is now stored directly in the corresponding synapse objects.
Remove the `t_lastspike` argument from the `check_connection` and `send`
functions of connections and add a new private member `t_lastspike` for
connections requiring spike-timing information. Make sure to initialize this
new variable in the constructor and set it to the spike time (typically
`t_spike`) at the end of `send(...)`.

```diff
diff --git a/models/stdp_connection.h b/models/stdp_connection.h
index f46ccb6c8..4056563b9 100644
--- a/models/stdp_connection.h
+++ b/models/stdp_connection.h
@@ -134,13 +134,9 @@ public:
/**
* Send an event to the receiver of this connection.
* \param e The event to send
- * \param t_lastspike Point in time of last spike sent.
* \param cp common properties of all synapses (empty).
*/
- void send( Event& e,
- thread t,
- double t_lastspike,
- const CommonSynapseProperties& cp );
+ void send( Event& e, thread t, const CommonSynapseProperties& cp );
class ConnTestDummyNode : public ConnTestDummyNodeBase
@@ -160,14 +156,13 @@ public:
check_connection( Node& s,
Node& t,
rport receptor_type,
- double t_lastspike,
const CommonPropertiesType& )
{
ConnTestDummyNode dummy_target;
ConnectionBase::check_connection_( dummy_target, s, t, receptor_type );
- t.register_stdp_connection( t_lastspike - get_delay() );
+ t.register_stdp_connection( t_lastspike_ - get_delay() );
}
void
@@ -202,6 +197,8 @@ private:
double mu_minus_;
double Wmax_;
double Kplus_;
+
+ double t_lastspike_;
};
@@ -209,18 +206,16 @@ private:
* Send an event to the receiver of this connection.
* \param e The event to send
* \param t The thread on which this connection is stored.
- * \param t_lastspike Time point of last spike emitted
* \param cp Common properties object, containing the stdp parameters.
*/
template < typename targetidentifierT >
inline void
STDPConnection< targetidentifierT >::send( Event& e,
thread t,
- double t_lastspike,
const CommonSynapseProperties& )
{
// synapse STDP depressing/facilitation dynamics
- // if(t_lastspike >0) {std::cout << "last spike " << t_lastspike <<
+ // if(t_lastspike_ >0) {std::cout << "last spike " << t_lastspike <<
// std::endl ;}
double t_spike = e.get_stamp().get_ms();
// t_lastspike_ = 0 initially
@@ -234,7 +229,7 @@ STDPConnection< targetidentifierT >::send( Event& e,
std::deque< histentry >::iterator start;
std::deque< histentry >::iterator finish;
- // For a new synapse, t_lastspike contains the point in time of the last
+ // For a new synapse, t_lastspike_ contains the point in time of the last
// spike. So we initially read the
// history(t_last_spike - dendritic_delay, ..., T_spike-dendritic_delay]
// which increases the access counter for these entries.
@@ -242,13 +237,15 @@ STDPConnection< targetidentifierT >::send( Event& e,
// history[0, ..., t_last_spike - dendritic_delay] have been
// incremented by Archiving_Node::register_stdp_connection(). See bug #218 for
// details.
- target->get_history(
- t_lastspike - dendritic_delay, t_spike - dendritic_delay, &start, &finish );
+ target->get_history( t_lastspike_ - dendritic_delay,
+ t_spike - dendritic_delay,
+ &start,
+ &finish );
// facilitation due to post-synaptic spikes since last pre-synaptic spike
double minus_dt;
while ( start != finish )
{
- minus_dt = t_lastspike - ( start->t_ + dendritic_delay );
+ minus_dt = t_lastspike_ - ( start->t_ + dendritic_delay );
++start;
// get_history() should make sure that
// start->t_ > t_lastspike - dendritic_delay, i.e. minus_dt < 0
@@ -268,7 +265,9 @@ STDPConnection< targetidentifierT >::send( Event& e,
e.set_rport( get_rport() );
e();
- Kplus_ = Kplus_ * std::exp( ( t_lastspike - t_spike ) / tau_plus_ ) + 1.0;
+ Kplus_ = Kplus_ * std::exp( ( t_lastspike_ - t_spike ) / tau_plus_ ) + 1.0;
+
+ t_lastspike_ = t_spike;
}
@@ -283,6 +282,7 @@ STDPConnection< targetidentifierT >::STDPConnection()
, mu_minus_( 1.0 )
, Wmax_( 100.0 )
, Kplus_( 0.0 )
+ , t_lastspike_( 0.0 )
{
}
@@ -298,6 +298,7 @@ STDPConnection< targetidentifierT >::STDPConnection(
, mu_minus_( rhs.mu_minus_ )
, Wmax_( rhs.Wmax_ )
, Kplus_( rhs.Kplus_ )
+ , t_lastspike_( rhs.t_lastspike_ )
{
}
```

All connections transmitting secondary events now need to tell the
ModelManager whether they support waveform relaxation when registering the
model. Make sure to add the corresponding argument in
`register_secondary_connection_model` (see modelsmodule.cpp, e.g.,
`gap_junction`).

```diff
diff --git a/models/modelsmodule.cpp b/models/modelsmodule.cpp
index 29ba57575..04eaef056 100644
--- a/models/modelsmodule.cpp
+++ b/models/modelsmodule.cpp
@@ -477,19 +499,31 @@ ModelsModule::init( SLIInterpreter* )
kernel()
.model_manager
.register_secondary_connection_model< GapJunction< TargetIdentifierPtrRport > >(
- "gap_junction", /*has_delay=*/false, /*requires_symmetric=*/true );
+ "gap_junction",
+ /*has_delay=*/false,
+ /*requires_symmetric=*/true,
+ /*supports_wfr=*/true );
kernel()
.model_manager
.register_secondary_connection_model< RateConnectionInstantaneous< TargetIdentifierPtrRport > >(
- "rate_connection_instantaneous", /*has_delay=*/false );
+ "rate_connection_instantaneous",
+ /*has_delay=*/false,
+ /*requires_symmetric=*/false,
+ /*supports_wfr=*/true );
kernel()
.model_manager
.register_secondary_connection_model< RateConnectionDelayed< TargetIdentifierPtrRport > >(
- "rate_connection_delayed" );
+ "rate_connection_delayed",
+ /*has_delay=*/true,
+ /*requires_symmetric=*/false,
+ /*supports_wfr=*/false );
kernel()
.model_manager
.register_secondary_connection_model< DiffusionConnection< TargetIdentifierPtrRport > >(
- "diffusion_connection", /*has_delay=*/false );
+ "diffusion_connection",
+ /*has_delay=*/false,
+ /*requires_symmetric=*/false,
+ /*supports_wfr=*/true );
```

## Converting devices

All devices are now subclasses of a new class `DeviceNode` which takes care
of additional infrastructure information. In all devices models, include
`device_node.h` instead of `node.h` and replace all `Node` with `DeviceNode`.

```diff
diff --git a/models/multimeter.h b/models/multimeter.h
index fe2f7c147..b0573d541 100644
--- a/models/multimeter.h
+++ b/models/multimeter.h
@@ -30,7 +30,7 @@
#include "connection.h"
#include "exceptions.h"
#include "kernel_manager.h"
-#include "node.h"
+#include "device_node.h"
#include "recording_device.h"
#include "sibling_container.h"
@@ -155,7 +155,7 @@ namespace nest
* @ingroup Devices
* @see UniversalDataLogger
*/
-class Multimeter : public Node
+class Multimeter : public DeviceNode
{
public:
```

```diff
diff --git a/models/multimeter.cpp b/models/multimeter.cpp
index 00f39ac57..4822e3d20 100644
--- a/models/multimeter.cpp
+++ b/models/multimeter.cpp
@@ -28,7 +28,7 @@
namespace nest
{
Multimeter::Multimeter()
- : Node()
+ : DeviceNode()
, device_( *this, RecordingDevice::MULTIMETER, "dat", true, true )
, P_()
, S_()
@@ -38,7 +38,7 @@ Multimeter::Multimeter()
}
Multimeter::Multimeter( const Multimeter& n )
- : Node( n )
+ : DeviceNode( n )
, device_( *this, n.device_ )
, P_( n.P_ )
, S_()
```

0 comments on commit 08844a5

Please sign in to comment.