diff --git a/nestkernel/CMakeLists.txt b/nestkernel/CMakeLists.txt
index 1ce5df272c..f2cc4deef7 100644
--- a/nestkernel/CMakeLists.txt
+++ b/nestkernel/CMakeLists.txt
@@ -113,6 +113,10 @@ set ( nestkernel_sources
position.h
spatial.h spatial.cpp
stimulation_backend.h
+ vectorized_node.h vectorized_node.cpp
+ jit_node.h jit_node.cpp
+ structural_plasticity_vector.h structural_plasticity_vector.cpp
+ archiving_vector.h archiving_vector.cpp
)
diff --git a/nestkernel/archiving_vector.cpp b/nestkernel/archiving_vector.cpp
new file mode 100644
index 0000000000..e6def109b3
--- /dev/null
+++ b/nestkernel/archiving_vector.cpp
@@ -0,0 +1,283 @@
+/*
+ * archiving_vector.cpp
+ *
+ * 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 .
+ *
+ */
+#include "archiving_vector.h"
+
+// Includes from nestkernel:
+#include "kernel_manager.h"
+
+// Includes from sli:
+#include "dictutils.h"
+#include "structural_plasticity_node.h"
+
+namespace nest
+{
+
+nest::ArchivingVector::ArchivingVector()
+ : n_incoming_( 0 )
+ , Kminus_( 0 )
+ , Kminus_triplet_( 0 )
+ , tau_minus_( 0 )
+ , tau_minus_inv_( 0 )
+ , tau_minus_triplet_( 0 )
+ , tau_minus_triplet_inv_( 0 )
+ , max_delay_( 0 )
+ , trace_( 0 )
+ , last_spike_( 0 )
+ , history_( 0 )
+{
+}
+// nest::ArchivingVector::ArchivingVector( const ArchivingVector& n ) : StructuralPlasticityVector(n)
+// {
+// throw std::runtime_error( "ArchivingVector shouldn't be cloned" );
+// }
+
+void
+ArchivingVector::resize( index extended_space, index thread_id )
+{
+ index total_space = size();
+
+ n_incoming_.resize( total_space, 0 );
+ Kminus_triplet_.resize( total_space, 0.0 );
+ Kminus_.resize( total_space, 0.0 );
+ tau_minus_.resize( total_space, 20.0 );
+ tau_minus_inv_.resize( total_space, 1 / 20.0 );
+ tau_minus_triplet_.resize( total_space, 110.0 );
+ tau_minus_triplet_inv_.resize( total_space, 1 / 110.0 );
+ max_delay_.resize( total_space, 0.0 );
+ trace_.resize( total_space, 0.0 );
+ last_spike_.resize( total_space, -1.0 );
+ history_.resize( total_space, std::deque< histentry >() );
+
+
+ StructuralPlasticityVector::resize( extended_space, thread_id );
+}
+
+void
+nest::ArchivingVector::register_stdp_connection( double t_first_read, double delay, index local_id )
+{
+ for ( std::deque< histentry >::iterator runner = history_.at( local_id ).begin();
+ runner != history_.at( local_id ).end()
+ and ( t_first_read - runner->t_ > -1.0 * kernel().connection_manager.get_stdp_eps() );
+ ++runner )
+ {
+ ( runner->access_counter_ )++;
+ }
+
+ n_incoming_.at( local_id )++;
+
+ max_delay_.at( local_id ) = std::max( delay, max_delay_.at( local_id ) );
+}
+double
+nest::ArchivingVector::get_K_value( double t, index local_id )
+{
+ // case when the neuron has not yet spiked
+ if ( history_.at( local_id ).empty() )
+ {
+ trace_.at( local_id ) = 0.;
+ return trace_.at( local_id );
+ }
+
+ // search for the latest post spike in the history buffer that came strictly
+ // before `t`
+ int i = history_.at( local_id ).size() - 1;
+ while ( i >= 0 )
+ {
+ if ( t - history_.at( local_id )[ i ].t_ > kernel().connection_manager.get_stdp_eps() )
+ {
+ trace_.at( local_id ) = ( history_.at( local_id )[ i ].Kminus_
+ * std::exp( ( history_.at( local_id )[ i ].t_ - t ) * tau_minus_inv_.at( local_id ) ) );
+ return trace_.at( local_id );
+ }
+ --i;
+ }
+
+ // this case occurs when the trace was requested at a time precisely at or
+ // before the first spike in the history
+ trace_.at( local_id ) = 0.;
+ return trace_.at( local_id );
+}
+void
+nest::ArchivingVector::get_K_values( double t,
+ double& K_value,
+ double& nearest_neighbor_K_value,
+ double& K_triplet_value,
+ index local_id )
+{
+ // case when the neuron has not yet spiked
+ if ( history_.at( local_id ).empty() )
+ {
+ K_triplet_value = Kminus_triplet_.at( local_id );
+ nearest_neighbor_K_value = Kminus_.at( local_id );
+ K_value = Kminus_.at( local_id );
+ return;
+ }
+
+ // search for the latest post spike in the history buffer that came strictly
+ // before `t`
+ int i = history_.at( local_id ).size() - 1;
+ while ( i >= 0 )
+ {
+ if ( t - history_.at( local_id )[ i ].t_ > kernel().connection_manager.get_stdp_eps() )
+ {
+ K_triplet_value = ( history_.at( local_id )[ i ].Kminus_triplet_
+ * std::exp( ( history_.at( local_id )[ i ].t_ - t ) * tau_minus_triplet_inv_.at( local_id ) ) );
+ K_value = ( history_.at( local_id )[ i ].Kminus_
+ * std::exp( ( history_.at( local_id )[ i ].t_ - t ) * tau_minus_inv_.at( local_id ) ) );
+ nearest_neighbor_K_value = std::exp( ( history_.at( local_id )[ i ].t_ - t ) * tau_minus_inv_.at( local_id ) );
+ return;
+ }
+ --i;
+ }
+
+ // this case occurs when the trace was requested at a time precisely at or
+ // before the first spike in the history
+ K_triplet_value = 0.0;
+ nearest_neighbor_K_value = 0.0;
+ K_value = 0.0;
+}
+void
+nest::ArchivingVector::get_history( double t1,
+ double t2,
+ std::deque< histentry >::iterator* start,
+ std::deque< histentry >::iterator* finish,
+ index local_id )
+{
+ *finish = history_.at( local_id ).end();
+ if ( history_.at( local_id ).empty() )
+ {
+ *start = *finish;
+ return;
+ }
+ std::deque< histentry >::reverse_iterator runner = history_.at( local_id ).rbegin();
+ const double t2_lim = t2 + kernel().connection_manager.get_stdp_eps();
+ const double t1_lim = t1 + kernel().connection_manager.get_stdp_eps();
+ while ( runner != history_.at( local_id ).rend() and runner->t_ >= t2_lim )
+ {
+ ++runner;
+ }
+ *finish = runner.base();
+ while ( runner != history_.at( local_id ).rend() and runner->t_ >= t1_lim )
+ {
+ runner->access_counter_++;
+ ++runner;
+ }
+ *start = runner.base();
+}
+
+
+void
+nest::ArchivingVector::set_spiketime( const Time& t_sp, index local_id, double offset )
+{
+ StructuralPlasticityVector::set_spiketime( t_sp, local_id, offset );
+
+ const double t_sp_ms = t_sp.get_ms() - offset;
+
+ if ( n_incoming_.at( local_id ) )
+ {
+ // prune all spikes from history which are no longer needed
+ // only remove a spike if:
+ // - its access counter indicates it has been read out by all connected
+ // STDP synapses, and
+ // - there is another, later spike, that is strictly more than
+ // (max_delay_ + eps) away from the new spike (at t_sp_ms)
+ while ( history_.at( local_id ).size() > 1 )
+ {
+ const double next_t_sp = history_.at( local_id )[ 1 ].t_;
+ if ( history_.at( local_id ).front().access_counter_ >= n_incoming_.at( local_id )
+ and t_sp_ms - next_t_sp > max_delay_.at( local_id ) + kernel().connection_manager.get_stdp_eps() )
+ {
+ history_.at( local_id ).pop_front();
+ }
+ else
+ {
+ break;
+ }
+ }
+ // update spiking history
+ Kminus_.at( local_id ) =
+ Kminus_.at( local_id ) * std::exp( ( last_spike_.at( local_id ) - t_sp_ms ) * tau_minus_inv_.at( local_id ) )
+ + 1.0;
+ Kminus_triplet_.at( local_id ) = Kminus_triplet_.at( local_id )
+ * std::exp( ( last_spike_.at( local_id ) - t_sp_ms ) * tau_minus_triplet_inv_.at( local_id ) )
+ + 1.0;
+ last_spike_.at( local_id ) = t_sp_ms;
+ history_.at( local_id )
+ .push_back( histentry( last_spike_.at( local_id ), Kminus_.at( local_id ), Kminus_triplet_.at( local_id ), 0 ) );
+ }
+ else
+ {
+ last_spike_.at( local_id ) = t_sp_ms;
+ }
+}
+void
+nest::ArchivingVector::get_status( DictionaryDatum& d, index local_id ) const
+{
+ def< double >( d, names::t_spike, get_spiketime_ms( local_id ) );
+ def< double >( d, names::tau_minus, tau_minus_.at( local_id ) );
+ def< double >( d, names::tau_minus_triplet, tau_minus_triplet_.at( local_id ) );
+ def< double >( d, names::post_trace, trace_.at( local_id ) );
+#ifdef DEBUG_ARCHIVER
+ def< int >( d, names::archiver_length, history_.at( local_id ).size() );
+#endif
+
+ // add status dict items from the parent class
+ StructuralPlasticityVector::get_status( d, local_id );
+}
+void
+nest::ArchivingVector::set_status( const DictionaryDatum& d, index local_id )
+{
+ // We need to preserve values in case invalid values are set
+ double new_tau_minus = tau_minus_.at( local_id );
+ double new_tau_minus_triplet = tau_minus_triplet_.at( local_id );
+ updateValue< double >( d, names::tau_minus, new_tau_minus );
+ updateValue< double >( d, names::tau_minus_triplet, new_tau_minus_triplet );
+
+ if ( new_tau_minus <= 0.0 or new_tau_minus_triplet <= 0.0 )
+ {
+ throw BadProperty( "All time constants must be strictly positive." );
+ }
+
+ StructuralPlasticityVector::set_status( d, local_id );
+
+ // do the actual update
+ tau_minus_.at( local_id ) = new_tau_minus;
+ tau_minus_triplet_.at( local_id ) = new_tau_minus_triplet;
+ tau_minus_inv_.at( local_id ) = 1. / new_tau_minus;
+ tau_minus_triplet_inv_.at( local_id ) = 1. / new_tau_minus_triplet;
+
+ // check, if to clear spike history and K_minus
+ bool clear = false;
+ updateValue< bool >( d, names::clear, clear );
+ if ( clear )
+ {
+ clear_history( local_id );
+ }
+}
+void
+nest::ArchivingVector::clear_history( index local_id )
+{
+ last_spike_.at( local_id ) = -1.0;
+ Kminus_.at( local_id ) = 0.0;
+ Kminus_triplet_.at( local_id ) = 0.0;
+ history_.at( local_id ).clear();
+}
+} // end of namespace nest
diff --git a/nestkernel/archiving_vector.h b/nestkernel/archiving_vector.h
new file mode 100644
index 0000000000..9fac3f1152
--- /dev/null
+++ b/nestkernel/archiving_vector.h
@@ -0,0 +1,196 @@
+/*
+ * archiving_vector.h
+ *
+ * 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 .
+ *
+ */
+
+#ifndef ARCHIVING_VECTOR_H
+#define ARCHIVING_VECTOR_H
+
+// C++ includes:
+#include
+#include
+
+// Includes from nestkernel:
+#include "histentry.h"
+#include "nest_time.h"
+#include "nest_types.h"
+#include "node.h"
+#include "structural_plasticity_vector.h"
+
+// Includes from sli:
+#include "dictdatum.h"
+
+#define DEBUG_ARCHIVER 1
+
+namespace nest
+{
+class ArchivingVector : public StructuralPlasticityVector
+{
+public:
+ /**
+ * \fn ArchivingVector()
+ * Constructor.
+ */
+ ArchivingVector();
+
+ /**
+ * \fn ArchivingNode()
+ * Copy Constructor.
+ */
+ ArchivingVector( const ArchivingVector& ) = delete;
+
+ ~ArchivingVector()
+ {
+ Kminus_.clear();
+ Kminus_triplet_.clear();
+ tau_minus_.clear();
+ tau_minus_inv_.clear();
+ tau_minus_triplet_.clear();
+ tau_minus_triplet_inv_.clear();
+ max_delay_.clear();
+ trace_.clear();
+ last_spike_.clear();
+ history_.clear();
+ }
+ /**
+ * \fn double get_K_value(long t)
+ * return the Kminus (synaptic trace) value at t (in ms). When the trace is
+ * requested at the exact same time that the neuron emits a spike, the trace
+ * value as it was just before the spike is returned.
+ */
+ double get_K_value( double t, index local_id );
+
+ /**
+ * \fn void get_K_values( double t,
+ * double& Kminus,
+ * double& nearest_neighbor_Kminus,
+ * double& Kminus_triplet )
+ * write the Kminus (eligibility trace for STDP),
+ * nearest_neighbour_Kminus (eligibility trace for nearest-neighbour STDP:
+ * like Kminus, but increased to 1, rather than by 1, on a spike
+ * occurrence),
+ * and Kminus_triplet
+ * values at t (in ms) to the provided locations.
+ * @throws UnexpectedEvent
+ */
+ void
+ get_K_values( double t, double& Kminus, double& nearest_neighbor_Kminus, double& Kminus_triplet, index local_id );
+
+ /**
+ * \fn void get_K_values( double t,
+ * double& Kminus,
+ * double& Kminus_triplet )
+ * The legacy version of the function, kept for compatibility
+ * after changing the function signature in PR #865.
+ * @throws UnexpectedEvent
+ */
+ void
+ get_K_values( double t, double& Kminus, double& Kminus_triplet, index local_id )
+ {
+ double nearest_neighbor_Kminus_to_discard;
+ get_K_values( t, Kminus, nearest_neighbor_Kminus_to_discard, Kminus_triplet, local_id );
+ }
+
+ /**
+ * \fn double get_K_triplet_value(std::deque::iterator &iter)
+ * return the triplet Kminus value for the associated iterator.
+ */
+ double get_K_triplet_value( const std::deque< histentry >::iterator& iter, index local_id );
+
+ /**
+ * \fn void get_history(long t1, long t2,
+ * std::deque::iterator* start,
+ * std::deque::iterator* finish)
+ * return the spike times (in steps) of spikes which occurred in the range
+ * (t1,t2].
+ */
+ void get_history( double t1,
+ double t2,
+ std::deque< histentry >::iterator* start,
+ std::deque< histentry >::iterator* finish,
+ index local_id );
+
+ /**
+ * Register a new incoming STDP connection.
+ *
+ * t_first_read: The newly registered synapse will read the history entries
+ * with t > t_first_read.
+ */
+ void register_stdp_connection( double t_first_read, double delay, index local_id );
+
+ void get_status( DictionaryDatum& d, index local_id ) const;
+ void set_status( const DictionaryDatum& d, index local_id );
+
+ void resize( index extended_space, index thread_id = 0 );
+
+protected:
+ /**
+ * \fn void set_spiketime(Time const & t_sp, double offset)
+ * record spike history
+ */
+ void set_spiketime( Time const&, index, double = 0.0 );
+
+ /**
+ * \fn double get_spiketime()
+ * return most recent spike time in ms
+ */
+ inline double get_spiketime_ms( index local_id ) const;
+
+ /**
+ * \fn void clear_history()
+ * clear spike history
+ */
+ void clear_history( index local_id );
+
+ // number of incoming connections from stdp connectors.
+ // needed to determine, if every incoming connection has
+ // read the spikehistory for a given point in time
+ std::vector< size_t > n_incoming_;
+
+private:
+ // sum exp(-(t-ti)/tau_minus)
+ std::vector< double > Kminus_;
+
+ // sum exp(-(t-ti)/tau_minus_triplet)
+ std::vector< double > Kminus_triplet_;
+
+ std::vector< double > tau_minus_;
+ std::vector< double > tau_minus_inv_;
+
+ // time constant for triplet low pass filtering of "post" spike train
+ std::vector< double > tau_minus_triplet_;
+ std::vector< double > tau_minus_triplet_inv_;
+
+ std::vector< double > max_delay_;
+ std::vector< double > trace_;
+
+ std::vector< double > last_spike_;
+
+ // spiking history needed by stdp synapses
+ std::vector< std::deque< histentry > > history_;
+};
+inline double
+ArchivingVector::get_spiketime_ms( index local_id ) const
+{
+ return last_spike_.at( local_id );
+}
+
+}
+#endif // ARCHIVING_VECTOR_H
diff --git a/nestkernel/exceptions.cpp b/nestkernel/exceptions.cpp
index b8f7456c73..ae4afb9deb 100644
--- a/nestkernel/exceptions.cpp
+++ b/nestkernel/exceptions.cpp
@@ -178,6 +178,13 @@ nest::UnknownPort::message() const
}
return out.str();
}
+std::string
+nest::VectorizedExpected::message() const
+{
+ std::ostringstream out;
+ out << "Instance must be derived from VectorizedExpected";
+ return out.str();
+}
std::string
nest::IllegalConnection::message() const
@@ -472,4 +479,4 @@ std::string
nest::LayerNodeExpected::message() const
{
return std::string();
-}
+}
\ No newline at end of file
diff --git a/nestkernel/exceptions.h b/nestkernel/exceptions.h
index 752f4193bc..828f171889 100644
--- a/nestkernel/exceptions.h
+++ b/nestkernel/exceptions.h
@@ -414,6 +414,23 @@ class UnknownPort : public KernelException
std::string message() const override;
};
+class VectorizedExpected : public KernelException
+{
+
+public:
+ VectorizedExpected()
+ : KernelException( "VectorizedExpected" )
+ {
+ }
+
+ ~VectorizedExpected() throw()
+ {
+ }
+
+ std::string message() const;
+};
+
+
/**
* To be thrown if a connection is not possible.
* This exception is e.g. thrown if a connection was attempted with
diff --git a/nestkernel/genericmodel.h b/nestkernel/genericmodel.h
index dada55f7a8..770bd67d2e 100644
--- a/nestkernel/genericmodel.h
+++ b/nestkernel/genericmodel.h
@@ -94,6 +94,19 @@ class GenericModel : public Model
void deprecation_warning( const std::string& ) override;
+
+ std::shared_ptr< VectorizedNode >
+ get_container() override
+ {
+ return proto_.get_container();
+ }
+ void
+ clone_container( std::shared_ptr< VectorizedNode > container ) override
+ {
+ proto_.clone_container( container );
+ }
+
+
private:
void set_status_( DictionaryDatum ) override;
DictionaryDatum get_status_() override;
@@ -110,6 +123,7 @@ class GenericModel : public Model
*/
ElementT proto_;
+
/**
* String containing deprecation information; empty if model not deprecated.
*/
diff --git a/nestkernel/jit_node.cpp b/nestkernel/jit_node.cpp
new file mode 100644
index 0000000000..6a35d61bb9
--- /dev/null
+++ b/nestkernel/jit_node.cpp
@@ -0,0 +1,511 @@
+/*
+ * jit_node.cpp
+ *
+ * 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 .
+ *
+ */
+
+#include "jit_node.h"
+
+// Includes from sli:
+#include "dictdatum.h"
+#include "dictutils.h"
+
+
+// Includes from libnestutil:
+#include "compose.hpp"
+#include "event.h"
+
+namespace nest
+{
+
+JitNode::JitNode()
+ : local_id_( -1 )
+{
+}
+
+JitNode::~JitNode()
+{
+ container_->reset();
+}
+
+JitNode::JitNode( const JitNode& n )
+ : Node( n )
+ , local_id_( -1 )
+ , container_( n.container_ )
+{
+}
+
+
+std::map< std::string, const std::vector< double >& >
+JitNode::get_recordables() const
+{
+ return container_->get_recordables();
+}
+void
+JitNode::reset_node()
+{
+ local_id_ = -1;
+ container_->reset();
+}
+bool
+JitNode::supports_urbanczik_archiving() const
+{
+ return false;
+}
+bool
+JitNode::local_receiver() const
+{
+ return false;
+}
+bool
+JitNode::one_node_per_process() const
+{
+ return false;
+}
+bool
+JitNode::is_off_grid() const
+{
+ return false;
+}
+bool
+JitNode::is_proxy() const
+{
+ return false;
+}
+
+index
+JitNode::get_node_id() const
+{
+ return container_->get_global_id( local_id_ );
+}
+
+
+bool
+JitNode::is_frozen() const
+{
+ return container_->is_frozen( local_id_ );
+}
+bool
+JitNode::node_uses_wfr() const
+{
+ return container_->node_uses_wfr( local_id_ );
+}
+void
+JitNode::set_node_uses_wfr( const bool value )
+{
+ container_->set_node_uses_wfr( value, local_id_ );
+}
+void
+JitNode::init()
+{
+ container_->init( local_id_ );
+}
+void
+JitNode::pre_run_hook()
+{
+ container_->calibrate( local_id_ );
+}
+
+void
+JitNode::calibrate_time( const TimeConverter& time_converter )
+{
+ container_->calibrate_time( time_converter, local_id_ );
+}
+void
+JitNode::post_run_cleanup()
+{
+ container_->post_run_cleanup( local_id_ );
+}
+void
+JitNode::finalize()
+{
+ container_->finalize( local_id_ );
+}
+void
+JitNode::update( const Time& network_time, const long initial_step, const long post_final )
+{
+ container_->update( network_time, initial_step, post_final, local_id_ );
+}
+bool
+JitNode::wfr_update( const Time& network_time, const long initial_step, const long post_final )
+{
+ return container_->wfr_update( network_time, initial_step, post_final, local_id_ );
+}
+void
+JitNode::set_status( const DictionaryDatum& d )
+{
+ container_->set_status( d, local_id_ );
+}
+void
+JitNode::get_status( DictionaryDatum& d ) const
+{
+ ( *d )[ Name( "is_vectorized" ) ] = true;
+ container_->get_status( d, local_id_ );
+}
+port
+JitNode::send_test_event( Node& receiving_node, rport receptor_type, synindex syn_id, bool dummy_target )
+{
+ return container_->send_test_event( receiving_node, receptor_type, syn_id, dummy_target, local_id_ );
+}
+
+port
+JitNode::handles_test_event( SpikeEvent& spike, rport receptor_type )
+{
+ return container_->handles_test_event( spike, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( WeightRecorderEvent& weightRecorder, rport receptor_type )
+{
+ return container_->handles_test_event( weightRecorder, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( RateEvent& rate, rport receptor_type )
+{
+ return container_->handles_test_event( rate, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DataLoggingRequest& dataLogging_request, rport receptor_type )
+{
+ return container_->handles_test_event( dataLogging_request, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( CurrentEvent& current, rport receptor_type )
+{
+ return container_->handles_test_event( current, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( ConductanceEvent& conductance, rport receptor_type )
+{
+ return container_->handles_test_event( conductance, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DoubleDataEvent& double_data, rport receptor_type )
+{
+ return container_->handles_test_event( double_data, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DSCurrentEvent& ds_current, rport receptor_type )
+{
+ return container_->handles_test_event( ds_current, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DSSpikeEvent& ds_spike, rport receptor_type )
+{
+ return container_->handles_test_event( ds_spike, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( GapJunctionEvent& gap_junction, rport receptor_type )
+{
+ return container_->handles_test_event( gap_junction, receptor_type, local_id_ );
+}
+
+port
+JitNode::handles_test_event( InstantaneousRateConnectionEvent& instantaneous_rate_connection, rport receptor_type )
+{
+ return container_->handles_test_event( instantaneous_rate_connection, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DiffusionConnectionEvent& diffusion_connection, rport receptor_type )
+{
+ return container_->handles_test_event( diffusion_connection, receptor_type, local_id_ );
+}
+port
+JitNode::handles_test_event( DelayedRateConnectionEvent& delayed_rate_connection, rport receptor_type )
+{
+ return container_->handles_test_event( delayed_rate_connection, receptor_type, local_id_ );
+}
+void
+JitNode::sends_secondary_event( GapJunctionEvent& ge )
+{
+ container_->sends_secondary_event( ge, local_id_ );
+}
+void
+JitNode::sends_secondary_event( InstantaneousRateConnectionEvent& re )
+{
+ container_->sends_secondary_event( re, local_id_ );
+}
+void
+JitNode::sends_secondary_event( DelayedRateConnectionEvent& re )
+{
+ container_->sends_secondary_event( re, local_id_ );
+}
+
+void
+JitNode::sends_secondary_event( DiffusionConnectionEvent& de )
+{
+ container_->sends_secondary_event( de, local_id_ );
+}
+void
+JitNode::register_stdp_connection( double a, double b )
+{
+ container_->register_stdp_connection( a, b, local_id_ );
+}
+
+void
+JitNode::handle( RateEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( SpikeEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( CurrentEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( DoubleDataEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( ConductanceEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( DataLoggingReply& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( GapJunctionEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( DataLoggingRequest& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( WeightRecorderEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( DiffusionConnectionEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( DelayedRateConnectionEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+void
+JitNode::handle( InstantaneousRateConnectionEvent& e )
+{
+ container_->handle( e, local_id_ );
+}
+
+double
+JitNode::get_Ca_minus() const
+{
+ return container_->get_Ca_minus( local_id_ );
+}
+double
+JitNode::get_synaptic_elements( Name name ) const
+{
+ return container_->get_synaptic_elements( name, local_id_ );
+}
+
+int
+JitNode::get_synaptic_elements_vacant( Name name ) const
+{
+ return container_->get_synaptic_elements_vacant( name, local_id_ );
+}
+int
+JitNode::get_synaptic_elements_connected( Name name ) const
+{
+ return container_->get_synaptic_elements_connected( name, local_id_ );
+}
+std::map< Name, double >
+JitNode::get_synaptic_elements() const
+{
+ return container_->get_synaptic_elements( local_id_ );
+}
+void
+JitNode::update_synaptic_elements( double value )
+{
+ container_->update_synaptic_elements( value, local_id_ );
+}
+void
+JitNode::decay_synaptic_elements_vacant()
+{
+ container_->decay_synaptic_elements_vacant( local_id_ );
+}
+void
+JitNode::connect_synaptic_element( Name name, int number )
+{
+ container_->connect_synaptic_element( name, number, local_id_ );
+}
+double
+JitNode::get_K_value( double t )
+{
+ return container_->get_K_value( t, local_id_ );
+}
+double
+JitNode::get_LTD_value( double t )
+{
+ return container_->get_LTD_value( t, local_id_ );
+}
+void
+JitNode::get_K_values( double t, double& Kminus, double& nearest_neighbor_Kminus, double& Kminus_triplet )
+{
+ container_->get_K_values( t, Kminus, nearest_neighbor_Kminus, Kminus_triplet, local_id_ );
+}
+void
+JitNode::get_history( double t1,
+ double t2,
+ std::deque< histentry >::iterator* start,
+ std::deque< histentry >::iterator* finish )
+{
+ container_->get_history( t1, t2, start, finish, local_id_ );
+}
+void
+JitNode::get_LTP_history( double t1,
+ double t2,
+ std::deque< histentry_extended >::iterator* start,
+ std::deque< histentry_extended >::iterator* finish )
+{
+ container_->get_LTP_history( t1, t2, start, finish, local_id_ );
+}
+
+void
+JitNode::get_urbanczik_history( double t1,
+ double t2,
+ std::deque< histentry_extended >::iterator* start,
+ std::deque< histentry_extended >::iterator* finish,
+ int value )
+{
+ container_->get_urbanczik_history( t1, t2, start, finish, value, local_id_ );
+}
+double
+JitNode::get_C_m( int comp )
+{
+ return container_->get_C_m( comp, local_id_ );
+}
+double
+JitNode::get_g_L( int comp )
+{
+ return container_->get_g_L( comp, local_id_ );
+}
+double
+JitNode::get_tau_L( int comp )
+{
+ return container_->get_tau_L( comp, local_id_ );
+}
+double
+JitNode::get_tau_s( int comp )
+{
+ return container_->get_tau_s( comp, local_id_ );
+}
+double
+JitNode::get_tau_syn_ex( int comp )
+{
+ return container_->get_tau_syn_ex( comp, local_id_ );
+}
+double
+JitNode::get_tau_syn_in( int comp )
+{
+ return container_->get_tau_syn_in( comp, local_id_ );
+}
+void
+JitNode::event_hook( DSSpikeEvent& ds_spike )
+{
+ container_->event_hook( ds_spike, local_id_ );
+}
+void
+JitNode::event_hook( DSCurrentEvent& ds_current )
+{
+ container_->event_hook( ds_current, local_id_ );
+}
+void
+JitNode::set_initialized_()
+{
+ container_->set_initialized_( local_id_ );
+}
+void
+JitNode::set_frozen_( bool frozen )
+{
+ container_->set_frozen_( frozen, local_id_ );
+}
+
+
+void
+JitNode::set_node_id_( index id )
+{
+ container_->insert_global_id( id );
+ local_id_ = container_->size() - 1;
+}
+
+void
+JitNode::clone_container( std::shared_ptr< VectorizedNode > container )
+{
+ container_ = container->clone();
+}
+
+void
+JitNode::set_container( std::shared_ptr< VectorizedNode > container )
+{
+ container_ = container;
+}
+
+SignalType
+JitNode::sends_signal() const
+{
+ return container_->sends_signal( local_id_ );
+}
+SignalType
+JitNode::receives_signal() const
+{
+ return container_->receives_signal( local_id_ );
+}
+void
+JitNode::set_status_base( const DictionaryDatum& dict )
+{
+ try
+ {
+ set_status( dict );
+ }
+ catch ( BadProperty& e )
+ {
+ throw BadProperty(
+ String::compose( "Setting status of a '%1' with node ID %2: %3", get_name(), get_node_id(), e.message() ) );
+ }
+ bool value = container_->is_frozen( local_id_ );
+ updateValue< bool >( dict, names::frozen, value );
+ container_->set_frozen_( value, local_id_ );
+}
+void
+JitNode::init_state_()
+{
+ container_->init_state_( local_id_ );
+}
+
+void
+JitNode::init_buffers_()
+{
+ container_->init_buffers_( local_id_ );
+}
+}
diff --git a/nestkernel/jit_node.h b/nestkernel/jit_node.h
new file mode 100644
index 0000000000..d41c2e97cc
--- /dev/null
+++ b/nestkernel/jit_node.h
@@ -0,0 +1,246 @@
+/*
+ * jit_node.h
+ *
+ * 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 .
+ *
+ */
+
+#ifndef JITNODE_H
+#define JITNODE_H
+
+#include "node.h"
+#include "vectorized_node.h"
+
+
+namespace nest
+{
+
+class JitNode : public Node
+{
+private:
+ index local_id_;
+
+
+public:
+ std::shared_ptr< VectorizedNode > container_;
+
+ JitNode();
+ ~JitNode();
+
+ JitNode( JitNode const& );
+
+ void reset_node();
+
+
+ std::shared_ptr< VectorizedNode >
+ get_container()
+ {
+ return container_;
+ }
+
+ void clone_container( std::shared_ptr< VectorizedNode > container );
+
+ std::map< std::string, const std::vector< double >& > get_recordables() const;
+
+
+ index get_pos_in_thread() const;
+
+ void set_pos_in_thread( index pos );
+
+ bool supports_urbanczik_archiving() const;
+
+ bool local_receiver() const;
+
+ bool one_node_per_process() const;
+
+ bool is_off_grid() const;
+
+ bool is_proxy() const;
+
+ index get_node_id() const;
+
+ index
+ get_node_local_id() const
+ {
+ return this->local_id_;
+ }
+
+ bool is_frozen() const;
+
+ bool node_uses_wfr() const;
+
+ void set_node_uses_wfr( const bool );
+
+ void init();
+
+ void pre_run_hook();
+
+ void calibrate_time( const TimeConverter& );
+
+ void post_run_cleanup();
+
+ void finalize();
+
+ void update( Time const&, const long, const long );
+
+ bool wfr_update( Time const&, const long, const long );
+
+ void set_status( const DictionaryDatum& );
+
+ void get_status( DictionaryDatum& ) const;
+
+ void set_container( std::shared_ptr< VectorizedNode > container );
+
+ port send_test_event( Node& receiving_node, rport receptor_type, synindex syn_id, bool dummy_target );
+
+ port handles_test_event( SpikeEvent&, rport receptor_type );
+
+ port handles_test_event( WeightRecorderEvent&, rport receptor_type );
+
+ port handles_test_event( RateEvent&, rport receptor_type );
+
+ port handles_test_event( DataLoggingRequest&, rport receptor_type );
+
+ port handles_test_event( CurrentEvent&, rport receptor_type );
+
+ port handles_test_event( ConductanceEvent&, rport receptor_type );
+
+ port handles_test_event( DoubleDataEvent&, rport receptor_type );
+
+ port handles_test_event( DSSpikeEvent&, rport receptor_type );
+
+ port handles_test_event( DSCurrentEvent&, rport receptor_type );
+
+ port handles_test_event( GapJunctionEvent&, rport receptor_type );
+
+ port handles_test_event( InstantaneousRateConnectionEvent&, rport receptor_type );
+
+ port handles_test_event( DiffusionConnectionEvent&, rport receptor_type );
+
+ port handles_test_event( DelayedRateConnectionEvent&, rport receptor_type );
+
+ void sends_secondary_event( GapJunctionEvent& ge );
+
+ void sends_secondary_event( InstantaneousRateConnectionEvent& re );
+
+ void sends_secondary_event( DelayedRateConnectionEvent& re );
+
+ void sends_secondary_event( DiffusionConnectionEvent& de );
+
+ void register_stdp_connection( double, double );
+
+ void handle( SpikeEvent& e );
+
+ void handle( WeightRecorderEvent& e );
+
+ void handle( RateEvent& e );
+
+ void handle( DataLoggingRequest& e );
+
+ void handle( DataLoggingReply& e );
+
+ void handle( CurrentEvent& e );
+
+ void handle( ConductanceEvent& e );
+
+ void handle( DoubleDataEvent& e );
+
+ void handle( GapJunctionEvent& e );
+
+ void handle( InstantaneousRateConnectionEvent& e );
+
+ void handle( DiffusionConnectionEvent& e );
+
+ void handle( DelayedRateConnectionEvent& e );
+
+ double get_Ca_minus() const;
+
+ double get_synaptic_elements( Name ) const;
+
+ int get_synaptic_elements_vacant( Name ) const;
+
+ int get_synaptic_elements_connected( Name ) const;
+
+ std::map< Name, double > get_synaptic_elements() const;
+
+ void update_synaptic_elements( double );
+
+ void decay_synaptic_elements_vacant();
+
+ void connect_synaptic_element( Name, int );
+
+ double get_K_value( double t );
+
+ double get_LTD_value( double t );
+
+ void get_K_values( double t, double& Kminus, double& nearest_neighbor_Kminus, double& Kminus_triplet );
+
+ void get_history( double t1,
+ double t2,
+ std::deque< histentry >::iterator* start,
+ std::deque< histentry >::iterator* finish );
+
+
+ void get_LTP_history( double t1,
+ double t2,
+ std::deque< histentry_extended >::iterator* start,
+ std::deque< histentry_extended >::iterator* finish );
+
+ void get_urbanczik_history( double t1,
+ double t2,
+ std::deque< histentry_extended >::iterator* start,
+ std::deque< histentry_extended >::iterator* finish,
+ int value );
+
+ double get_C_m( int comp );
+
+ double get_g_L( int comp );
+
+ double get_tau_L( int comp );
+
+ double get_tau_s( int comp );
+
+ double get_tau_syn_ex( int comp );
+
+ double get_tau_syn_in( int comp );
+
+ void event_hook( DSSpikeEvent& );
+
+ void event_hook( DSCurrentEvent& );
+
+
+ SignalType sends_signal() const;
+
+ SignalType receives_signal() const;
+
+ void set_status_base( const DictionaryDatum& );
+
+private:
+ void set_node_id_( index );
+
+protected:
+ void init_state_();
+
+ void init_buffers_();
+
+ void set_initialized_();
+
+ void set_frozen_( bool frozen );
+};
+}
+#endif // JITNODE_H
diff --git a/nestkernel/model.cpp b/nestkernel/model.cpp
index 0e52e2b3b4..56e7d0b889 100644
--- a/nestkernel/model.cpp
+++ b/nestkernel/model.cpp
@@ -42,9 +42,19 @@ Model::Model( const std::string& name )
: name_( name )
, type_id_( 0 )
, memory_()
+ , uses_vectors( false )
+ , thread_to_node( kernel().vp_manager.get_num_threads() )
{
}
+Model::Model( const Model& m )
+ : name_( m.name_ )
+ , type_id_( m.type_id_ )
+ , memory_( m.memory_ )
+ , uses_vectors( m.uses_vectors )
+ , thread_to_node( kernel().vp_manager.get_num_threads() )
+{
+}
void
Model::set_threads()
{
diff --git a/nestkernel/model.h b/nestkernel/model.h
index a478660ecd..b52e1bf8d3 100644
--- a/nestkernel/model.h
+++ b/nestkernel/model.h
@@ -24,6 +24,8 @@
#define MODEL_H
// C++ includes:
+#include
+#include