From 96a18d312cf6378c9e4a5fb129fafa0ea8ac6a30 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Mon, 20 Feb 2017 16:57:27 +0100 Subject: [PATCH 01/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/ac_generator.cpp | 71 ++++++++++++++++++++++++++++- models/ac_generator.h | 52 ++++++++++++++++++++++ models/dc_generator.cpp | 71 +++++++++++++++++++++++++++++ models/dc_generator.h | 65 +++++++++++++++++++++++++++ models/noise_generator.cpp | 74 ++++++++++++++++++++++++++++--- models/noise_generator.h | 39 ++++++++++++++++ models/step_current_generator.cpp | 69 ++++++++++++++++++++++++++++ models/step_current_generator.h | 58 ++++++++++++++++++++++++ nestkernel/nest_names.h | 2 +- 9 files changed, 493 insertions(+), 8 deletions(-) diff --git a/models/ac_generator.cpp b/models/ac_generator.cpp index dc3e918ba1..806f396b2e 100644 --- a/models/ac_generator.cpp +++ b/models/ac_generator.cpp @@ -31,6 +31,7 @@ // Includes from nestkernel: #include "event_delivery_manager_impl.h" #include "kernel_manager.h" +#include "universal_data_logger_impl.h" // Includes from sli: #include "dict.h" @@ -38,6 +39,18 @@ #include "doubledatum.h" #include "integerdatum.h" +namespace nest +{ +RecordablesMap< ac_generator > ac_generator::recordablesMap_; + +template <> +void +RecordablesMap< ac_generator >::create() +{ + insert_( Name( names::I ), &ac_generator::get_I_ ); +} +} + /* ---------------------------------------------------------------- * Default constructors defining default parameters and state * ---------------------------------------------------------------- */ @@ -50,12 +63,45 @@ nest::ac_generator::Parameters_::Parameters_() { } +nest::ac_generator::Parameters_::Parameters_( const Parameters_& p ) + : amp_( p.amp_ ) + , offset_( p.offset_ ) + , freq_( p.freq_ ) + , phi_deg_( p.phi_deg_ ) +{ +} + +nest::ac_generator::Parameters_& nest::ac_generator::Parameters_:: +operator=( const Parameters_& p ) +{ + if ( this == &p ) + return *this; + + amp_ = p.amp_; + offset_ = p.offset_; + freq_ = p.freq_; + phi_deg_ = p.phi_deg_; + + return *this; +} + nest::ac_generator::State_::State_() : y_0_( 0.0 ) , y_1_( 0.0 ) // pA + , I_( 0.0 ) // pA { } +nest::ac_generator::Buffers_::Buffers_( ac_generator& n ) + : logger_( n ) +{ +} + +nest::ac_generator::Buffers_::Buffers_( const Buffers_&, + ac_generator& n ) + : logger_( n ) +{ +} /* ---------------------------------------------------------------- * Parameter extraction and manipulation functions @@ -96,7 +142,9 @@ nest::ac_generator::ac_generator() , device_() , P_() , S_() + , B_( *this ) { + recordablesMap_.create(); } nest::ac_generator::ac_generator( const ac_generator& n ) @@ -104,6 +152,7 @@ nest::ac_generator::ac_generator( const ac_generator& n ) , device_( n.device_ ) , P_( n.P_ ) , S_( n.S_ ) + , B_( n.B_, *this ) { } @@ -125,11 +174,14 @@ void nest::ac_generator::init_buffers_() { device_.init_buffers(); + B_.logger_.reset(); } void nest::ac_generator::calibrate() { + B_.logger_.init(); + device_.calibrate(); const double h = Time::get_resolution().get_ms(); @@ -153,16 +205,33 @@ nest::ac_generator::calibrate() void nest::ac_generator::update( Time const& origin, const long from, const long to ) { + assert( + to >= 0 && ( delay ) from < kernel().connection_manager.get_min_delay() ); + assert( from < to ); + long start = origin.get_steps(); - CurrentEvent ce; for ( long lag = from; lag < to; ++lag ) + { + B_.logger_.record_data( origin.get_steps() + lag ); + S_.I_ = 0.0; + if ( device_.is_active( Time::step( start + lag ) ) ) { const double y_0 = S_.y_0_; S_.y_0_ = V_.A_00_ * y_0 + V_.A_01_ * S_.y_1_; S_.y_1_ = V_.A_10_ * y_0 + V_.A_11_ * S_.y_1_; + S_.I_ = S_.y_1_ + P_.offset_; + + CurrentEvent ce; ce.set_current( S_.y_1_ + P_.offset_ ); kernel().event_delivery_manager.send( *this, ce, lag ); } + } +} + +void +nest::ac_generator::handle( DataLoggingRequest& e ) +{ + B_.logger_.handle( e ); } diff --git a/models/ac_generator.h b/models/ac_generator.h index b747c510e5..775f3ca0bb 100644 --- a/models/ac_generator.h +++ b/models/ac_generator.h @@ -31,6 +31,7 @@ #include "nest_types.h" #include "node.h" #include "stimulating_device.h" +#include "universal_data_logger.h" /* BeginDocumentation Name: ac_generator - provides AC input current @@ -76,9 +77,23 @@ class ac_generator : public Node port send_test_event( Node&, rport, synindex, bool ); + using Node::handle; + using Node::handles_test_event; + + void handle( DataLoggingRequest& ); + + port handles_test_event( DataLoggingRequest&, rport ); + void get_status( DictionaryDatum& ) const; void set_status( const DictionaryDatum& ); + //! Allow multimeter to connect to local instances + bool + local_receiver() const + { + return true; + } + private: void init_state_( const Node& ); void init_buffers_(); @@ -97,6 +112,8 @@ class ac_generator : public Node double phi_deg_; //!< Phase of sine current (0-360 deg) Parameters_(); //!< Sets default parameter values + Parameters_( const Parameters_& ); + Parameters_& operator=( const Parameters_& p ); // Copy constructor EN void get( DictionaryDatum& ) const; //!< Store current values in dictionary void set( const DictionaryDatum& ); //!< Set values from dicitonary @@ -108,6 +125,7 @@ class ac_generator : public Node { double y_0_; double y_1_; + double I_; State_(); //!< Sets default parameter values @@ -116,6 +134,24 @@ class ac_generator : public Node // ------------------------------------------------------------ + // These friend declarations must be precisely here. + friend class RecordablesMap< ac_generator >; + friend class UniversalDataLogger< ac_generator >; + + // ------------------------------------------------------------ + + /** + * Buffers of the model. + */ + struct Buffers_ + { + Buffers_( ac_generator& ); + Buffers_( const Buffers_&, ac_generator& ); + UniversalDataLogger< ac_generator > logger_; + }; + + // ------------------------------------------------------------ + struct Variables_ { double omega_; //!< Angelfrequency i rad/s @@ -128,12 +164,20 @@ class ac_generator : public Node double A_11_; }; + double + get_I_() const + { + return S_.I_; + } + // ------------------------------------------------------------ StimulatingDevice< CurrentEvent > device_; + static RecordablesMap< ac_generator > recordablesMap_; Parameters_ P_; State_ S_; Variables_ V_; + Buffers_ B_; }; inline port @@ -150,6 +194,14 @@ ac_generator::send_test_event( Node& target, return target.handles_test_event( e, receptor_type ); } +inline port +ac_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +{ + if ( receptor_type != 0 ) + throw UnknownReceptorType( receptor_type, get_name() ); + return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); +} + inline void ac_generator::get_status( DictionaryDatum& d ) const { diff --git a/models/dc_generator.cpp b/models/dc_generator.cpp index 75edd41b9b..54ec1606de 100644 --- a/models/dc_generator.cpp +++ b/models/dc_generator.cpp @@ -25,6 +25,7 @@ // Includes from nestkernel: #include "event_delivery_manager_impl.h" #include "kernel_manager.h" +#include "universal_data_logger_impl.h" // Includes from sli: #include "dict.h" @@ -32,6 +33,17 @@ #include "doubledatum.h" #include "integerdatum.h" +namespace nest +{ +RecordablesMap< dc_generator > dc_generator::recordablesMap_; + +template <> +void +RecordablesMap< dc_generator >::create() +{ + insert_( Name( names::I ), &dc_generator::get_I_ ); +} +} /* ---------------------------------------------------------------- * Default constructors defining default parameter @@ -42,6 +54,38 @@ nest::dc_generator::Parameters_::Parameters_() { } +nest::dc_generator::Parameters_::Parameters_( const Parameters_& p ) + : amp_( p.amp_ ) +{ +} + +nest::dc_generator::Parameters_& nest::dc_generator::Parameters_:: +operator=( const Parameters_& p ) +{ + if ( this == &p ) + return *this; + + amp_ = p.amp_; + + return *this; +} + +nest::dc_generator::State_::State_() + : I_( 0.0 ) // pA +{ +} + + +nest::dc_generator::Buffers_::Buffers_( dc_generator& n ) + : logger_( n ) +{ +} + +nest::dc_generator::Buffers_::Buffers_( const Buffers_&, + dc_generator& n ) + : logger_( n ) +{ +} /* ---------------------------------------------------------------- * Parameter extraction and manipulation functions @@ -68,13 +112,18 @@ nest::dc_generator::dc_generator() : Node() , device_() , P_() + , S_() + , B_( *this ) { + recordablesMap_.create(); } nest::dc_generator::dc_generator( const dc_generator& n ) : Node( n ) , device_( n.device_ ) , P_( n.P_ ) + , S_( n.S_ ) + , B_( n.B_, *this ) { } @@ -89,17 +138,21 @@ nest::dc_generator::init_state_( const Node& proto ) const dc_generator& pr = downcast< dc_generator >( proto ); device_.init_state( pr.device_ ); + S_ = pr.S_; } void nest::dc_generator::init_buffers_() { device_.init_buffers(); + B_.logger_.reset(); } void nest::dc_generator::calibrate() { + B_.logger_.init(); + device_.calibrate(); } @@ -111,12 +164,30 @@ nest::dc_generator::calibrate() void nest::dc_generator::update( Time const& origin, const long from, const long to ) { + assert( + to >= 0 && ( delay ) from < kernel().connection_manager.get_min_delay() ); + assert( from < to ); + long start = origin.get_steps(); CurrentEvent ce; ce.set_current( P_.amp_ ); for ( long offs = from; offs < to; ++offs ) + { + B_.logger_.record_data( origin.get_steps() + offs ); + S_.I_ = 0.0; + if ( device_.is_active( Time::step( start + offs ) ) ) + { + S_.I_ = P_.amp_; kernel().event_delivery_manager.send( *this, ce, offs ); + } + } +} + +void +nest::dc_generator::handle( DataLoggingRequest& e ) +{ + B_.logger_.handle( e ); } diff --git a/models/dc_generator.h b/models/dc_generator.h index 4f36be48f3..d0bca0bd06 100644 --- a/models/dc_generator.h +++ b/models/dc_generator.h @@ -63,6 +63,7 @@ SeeAlso: Device, StimulatingDevice #include "node.h" #include "ring_buffer.h" #include "stimulating_device.h" +#include "universal_data_logger.h" namespace nest { @@ -86,9 +87,23 @@ class dc_generator : public Node port send_test_event( Node&, rport, synindex, bool ); + using Node::handle; + using Node::handles_test_event; + + void handle( DataLoggingRequest& ); + + port handles_test_event( DataLoggingRequest&, rport ); + void get_status( DictionaryDatum& ) const; void set_status( const DictionaryDatum& ); + //! Allow multimeter to connect to local instances + bool + local_receiver() const + { + return true; + } + private: void init_state_( const Node& ); void init_buffers_(); @@ -106,6 +121,8 @@ class dc_generator : public Node double amp_; //!< stimulation amplitude, in pA Parameters_(); //!< Sets default parameter values + Parameters_( const Parameters_& ); + Parameters_& operator=( const Parameters_& p ); // Copy constructor EN void get( DictionaryDatum& ) const; //!< Store current values in dictionary void set( const DictionaryDatum& ); //!< Set values from dicitonary @@ -113,8 +130,48 @@ class dc_generator : public Node // ------------------------------------------------------------ + struct State_ + { + double I_; + + State_(); //!< Sets default parameter values + + void get( DictionaryDatum& ) const; //!< Store current values in dictionary + }; + + // ------------------------------------------------------------ + + // These friend declarations must be precisely here. + friend class RecordablesMap< dc_generator >; + friend class UniversalDataLogger< dc_generator >; + + // ------------------------------------------------------------ + + /** + * Buffers of the model. + */ + struct Buffers_ + { + Buffers_( dc_generator& ); + Buffers_( const Buffers_&, dc_generator& ); + UniversalDataLogger< dc_generator > logger_; + }; + + // ------------------------------------------------------------ + + double + get_I_() const + { + return S_.I_; + } + + // ------------------------------------------------------------ + StimulatingDevice< CurrentEvent > device_; + static RecordablesMap< dc_generator > recordablesMap_; Parameters_ P_; + State_ S_; + Buffers_ B_; }; inline port @@ -131,6 +188,14 @@ dc_generator::send_test_event( Node& target, return target.handles_test_event( e, receptor_type ); } +inline port +dc_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +{ + if ( receptor_type != 0 ) + throw UnknownReceptorType( receptor_type, get_name() ); + return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); +} + inline void dc_generator::get_status( DictionaryDatum& d ) const { diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index 57d8fc3ba0..0fcfbf4f91 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -29,6 +29,7 @@ // Includes from nestkernel: #include "event_delivery_manager_impl.h" #include "kernel_manager.h" +#include "universal_data_logger_impl.h" // Includes from sli: #include "dict.h" @@ -36,6 +37,18 @@ #include "doubledatum.h" #include "integerdatum.h" +namespace nest +{ +RecordablesMap< noise_generator > noise_generator::recordablesMap_; + +template <> +void +RecordablesMap< noise_generator >::create() +{ + insert_( Name( names::I ), &noise_generator::get_I_ ); +} +} + /* ---------------------------------------------------------------- * Default constructors defining default parameter * ---------------------------------------------------------------- */ @@ -51,12 +64,6 @@ nest::noise_generator::Parameters_::Parameters_() { } -nest::noise_generator::State_::State_() - : y_0_( 0.0 ) - , y_1_( 0.0 ) // pA -{ -} - nest::noise_generator::Parameters_::Parameters_( const Parameters_& p ) : mean_( p.mean_ ) , std_( p.std_ ) @@ -71,6 +78,39 @@ nest::noise_generator::Parameters_::Parameters_( const Parameters_& p ) dt_.calibrate(); } +nest::noise_generator::Parameters_& nest::noise_generator::Parameters_:: +operator=( const Parameters_& p ) +{ + if ( this == &p ) + return *this; + + mean_ = p.mean_; + std_ = p.std_; + std_mod_ = p.std_mod_; + freq_ = p.freq_; + phi_deg_ = p.phi_deg_; + dt_ = p.dt_; + + return *this; +} + +nest::noise_generator::State_::State_() + : y_0_( 0.0 ) + , y_1_( 0.0 ) // pA + , I_( 0.0 ) // pA +{ +} + +nest::noise_generator::Buffers_::Buffers_( noise_generator& n ) + : logger_( n ) +{ +} + +nest::noise_generator::Buffers_::Buffers_( const Buffers_&, + noise_generator& n ) + : logger_( n ) +{ +} /* ---------------------------------------------------------------- * Parameter extraction and manipulation functions @@ -131,7 +171,10 @@ nest::noise_generator::noise_generator() : Node() , device_() , P_() + , S_() + , B_( *this ) { + recordablesMap_.create(); if ( !P_.dt_.is_step() ) throw InvalidDefaultResolution( get_name(), names::dt, P_.dt_ ); } @@ -140,6 +183,8 @@ nest::noise_generator::noise_generator( const noise_generator& n ) : Node( n ) , device_( n.device_ ) , P_( n.P_ ) + , S_( n.S_ ) + , B_( n.B_, *this ) { if ( !P_.dt_.is_step() ) throw InvalidTimeInModel( get_name(), names::dt, P_.dt_ ); @@ -162,6 +207,7 @@ void nest::noise_generator::init_buffers_() { device_.init_buffers(); + B_.logger_.reset(); B_.next_step_ = 0; B_.amps_.clear(); @@ -171,6 +217,8 @@ nest::noise_generator::init_buffers_() void nest::noise_generator::calibrate() { + B_.logger_.init(); + device_.calibrate(); if ( P_.num_targets_ != B_.amps_.size() ) { @@ -238,10 +286,17 @@ nest::noise_generator::update( Time const& origin, const long from, const long to ) { + assert( + to >= 0 && ( delay ) from < kernel().connection_manager.get_min_delay() ); + assert( from < to ); + const long start = origin.get_steps(); for ( long offs = from; offs < to; ++offs ) { + B_.logger_.record_data( origin.get_steps() + offs ); + S_.I_ = 0.0; + const long now = start + offs; if ( !device_.is_active( Time::step( now ) ) ) @@ -264,6 +319,7 @@ nest::noise_generator::update( Time const& origin, *it = P_.mean_ + std::sqrt( P_.std_ * P_.std_ + S_.y_1_ * P_.std_mod_ * P_.std_mod_ ) * V_.normal_dev_( kernel().rng_manager.get_rng( get_thread() ) ); + S_.I_ = *it; } // use now as reference, in case we woke up from inactive period @@ -287,3 +343,9 @@ nest::noise_generator::event_hook( DSCurrentEvent& e ) e.set_current( B_.amps_[ prt ] ); e.get_receiver().handle( e ); } + +void +nest::noise_generator::handle( DataLoggingRequest& e ) +{ + B_.logger_.handle( e ); +} diff --git a/models/noise_generator.h b/models/noise_generator.h index a5975dec9a..cac99a3071 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -35,6 +35,7 @@ #include "nest_types.h" #include "node.h" #include "stimulating_device.h" +#include "universal_data_logger.h" namespace nest { @@ -125,6 +126,8 @@ class noise_generator : public Node * @see Technical Issues / Virtual Functions: Overriding, Overloading, and * Hiding */ + using Node::handle; + using Node::handles_test_event; using Node::event_hook; using Node::sends_signal; @@ -132,9 +135,20 @@ class noise_generator : public Node SignalType sends_signal() const; + void handle( DataLoggingRequest& ); + + port handles_test_event( DataLoggingRequest&, rport ); + void get_status( DictionaryDatum& ) const; void set_status( const DictionaryDatum& ); + //! Allow multimeter to connect to local instances + bool + local_receiver() const + { + return true; + } + private: void init_state_( const Node& ); void init_buffers_(); @@ -174,6 +188,7 @@ class noise_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); + Parameters_& operator=( const Parameters_& p ); // Copy constructor EN void get( DictionaryDatum& ) const; //!< Store current values in dictionary //! Set values from dictionary @@ -186,6 +201,7 @@ class noise_generator : public Node { double y_0_; double y_1_; + double I_; State_(); //!< Sets default parameter values @@ -194,10 +210,19 @@ class noise_generator : public Node // ------------------------------------------------------------ + // These friend declarations must be precisely here. + friend class RecordablesMap< noise_generator >; + friend class UniversalDataLogger< noise_generator >; + + // ------------------------------------------------------------ + struct Buffers_ { long next_step_; //!< time step of next change in current AmpVec_ amps_; //!< amplitudes, one per target + Buffers_( noise_generator& ); + Buffers_( const Buffers_&, noise_generator& ); + UniversalDataLogger< noise_generator > logger_; }; // ------------------------------------------------------------ @@ -216,15 +241,29 @@ class noise_generator : public Node double A_11_; }; + double + get_I_() const + { + return S_.I_; + } + // ------------------------------------------------------------ StimulatingDevice< CurrentEvent > device_; + static RecordablesMap< noise_generator > recordablesMap_; Parameters_ P_; Variables_ V_; Buffers_ B_; State_ S_; }; +inline port +noise_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +{ + if ( receptor_type != 0 ) + throw UnknownReceptorType( receptor_type, get_name() ); + return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); +} inline void noise_generator::get_status( DictionaryDatum& d ) const diff --git a/models/step_current_generator.cpp b/models/step_current_generator.cpp index a4da4ff203..eeb4f6410b 100644 --- a/models/step_current_generator.cpp +++ b/models/step_current_generator.cpp @@ -25,6 +25,7 @@ // Includes from nestkernel: #include "event_delivery_manager_impl.h" #include "kernel_manager.h" +#include "universal_data_logger_impl.h" // Includes from sli: #include "dict.h" @@ -32,6 +33,18 @@ #include "doubledatum.h" #include "integerdatum.h" +namespace nest +{ +RecordablesMap< step_current_generator > step_current_generator::recordablesMap_; + +template <> +void +RecordablesMap< step_current_generator >::create() +{ + insert_( Name( names::I ), &step_current_generator::get_I_ ); +} +} + /* ---------------------------------------------------------------- * Default constructors defining default parameter * ---------------------------------------------------------------- */ @@ -42,6 +55,40 @@ nest::step_current_generator::Parameters_::Parameters_() { } +nest::step_current_generator::Parameters_::Parameters_( const Parameters_& p ) + : amp_times_( p.amp_times_ ) + , amp_values_( p.amp_values_ ) +{ +} + +nest::step_current_generator::Parameters_& nest::step_current_generator::Parameters_:: +operator=( const Parameters_& p ) +{ + if ( this == &p ) + return *this; + + amp_times_ = p.amp_times_; + amp_values_ = p.amp_values_; + + return *this; +} + +nest::step_current_generator::State_::State_() + : I_( 0.0 ) // pA +{ +} + +nest::step_current_generator::Buffers_::Buffers_( step_current_generator& n ) + : logger_( n ) +{ +} + +nest::step_current_generator::Buffers_::Buffers_( const Buffers_&, + step_current_generator& n ) + : logger_( n ) +{ +} + /* ---------------------------------------------------------------- * Parameter extraction and manipulation functions * ---------------------------------------------------------------- */ @@ -94,7 +141,10 @@ nest::step_current_generator::step_current_generator() : Node() , device_() , P_() + , S_() + , B_( *this ) { + recordablesMap_.create(); } nest::step_current_generator::step_current_generator( @@ -102,6 +152,8 @@ nest::step_current_generator::step_current_generator( : Node( n ) , device_( n.device_ ) , P_( n.P_ ) + , S_( n.S_ ) + , B_( n.B_, *this ) { } @@ -123,6 +175,7 @@ void nest::step_current_generator::init_buffers_() { device_.init_buffers(); + B_.logger_.reset(); B_.idx_ = 0; B_.amp_ = 0; @@ -131,6 +184,8 @@ nest::step_current_generator::init_buffers_() void nest::step_current_generator::calibrate() { + B_.logger_.init(); + device_.calibrate(); } @@ -144,6 +199,10 @@ nest::step_current_generator::update( Time const& origin, const long from, const long to ) { + assert( + to >= 0 && ( delay ) from < kernel().connection_manager.get_min_delay() ); + assert( from < to ); + assert( P_.amp_times_.size() == P_.amp_values_.size() ); const long t0 = origin.get_steps(); @@ -159,6 +218,9 @@ nest::step_current_generator::update( Time const& origin, { const long curr_time = t0 + offs; + B_.logger_.record_data( origin.get_steps() + offs ); + S_.I_ = 0.0; + // Keep the amplitude up-to-date at all times. // We need to change the amplitude one step ahead of time, see comment // on class SimulatingDevice. @@ -175,7 +237,14 @@ nest::step_current_generator::update( Time const& origin, { CurrentEvent ce; ce.set_current( B_.amp_ ); + S_.I_ = B_.amp_; kernel().event_delivery_manager.send( *this, ce, offs ); } } } + +void +nest::step_current_generator::handle( DataLoggingRequest& e ) +{ + B_.logger_.handle( e ); +} diff --git a/models/step_current_generator.h b/models/step_current_generator.h index 2ff87ad3f6..33ec2ca722 100644 --- a/models/step_current_generator.h +++ b/models/step_current_generator.h @@ -64,6 +64,7 @@ #include "node.h" #include "ring_buffer.h" #include "stimulating_device.h" +#include "universal_data_logger.h" namespace nest { @@ -82,9 +83,23 @@ class step_current_generator : public Node port send_test_event( Node&, rport, synindex, bool ); + using Node::handle; + using Node::handles_test_event; + + void handle( DataLoggingRequest& ); + + port handles_test_event( DataLoggingRequest&, rport ); + void get_status( DictionaryDatum& ) const; void set_status( const DictionaryDatum& ); + //! Allow multimeter to connect to local instances + bool + local_receiver() const + { + return true; + } + private: void init_state_( const Node& ); void init_buffers_(); @@ -104,6 +119,8 @@ class step_current_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_&, Buffers_& ); + Parameters_( const Parameters_& ); + Parameters_& operator=( const Parameters_& p ); // Copy constructor EN void get( DictionaryDatum& ) const; //!< Store current values in dictionary //! Set values from dictionary @@ -112,16 +129,49 @@ class step_current_generator : public Node // ------------------------------------------------------------ + struct State_ + { + double y_0_; + double y_1_; + double I_; + + State_(); //!< Sets default parameter values + + void get( DictionaryDatum& ) const; //!< Store current values in dictionary + }; + + // ------------------------------------------------------------ + + // These friend declarations must be precisely here. + friend class RecordablesMap< step_current_generator >; + friend class UniversalDataLogger< step_current_generator >; + + // ------------------------------------------------------------ + struct Buffers_ { size_t idx_; //!< index of current amplitude double amp_; //!< current amplitude + + Buffers_( step_current_generator& ); + Buffers_( const Buffers_&, step_current_generator& ); + UniversalDataLogger< step_current_generator > logger_; }; // ------------------------------------------------------------ + double + get_I_() const + { + return S_.I_; + } + + // ------------------------------------------------------------ + StimulatingDevice< CurrentEvent > device_; + static RecordablesMap< step_current_generator > recordablesMap_; Parameters_ P_; + State_ S_; Buffers_ B_; }; @@ -139,6 +189,14 @@ step_current_generator::send_test_event( Node& target, return target.handles_test_event( e, receptor_type ); } +inline port +step_current_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +{ + if ( receptor_type != 0 ) + throw UnknownReceptorType( receptor_type, get_name() ); + return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); +} + inline void step_current_generator::get_status( DictionaryDatum& d ) const { diff --git a/nestkernel/nest_names.h b/nestkernel/nest_names.h index 0863ca77ab..9a70e9ad6f 100644 --- a/nestkernel/nest_names.h +++ b/nestkernel/nest_names.h @@ -205,7 +205,7 @@ extern const Name histogram_correction; //!< Specific to correlation_detector extern const Name HMIN; //!< Smallest integration step for adaptive stepsize //!< (Brette & Gerstner 2005) -extern const Name I; //!< Specific to mirollo_strogatz_ps +extern const Name I; //!< mirollo_strogatz_ps, StimulatingDevice extern const Name I_adapt; //!< Goal of current homeostasis //!< (current homeostasis) extern const Name I_e; //!< Input current From a56636f8a97bc5220d8cbabb51cefcb1214cd37c Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Mon, 13 Mar 2017 17:39:15 +0100 Subject: [PATCH 02/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/ac_generator.cpp | 2 ++ models/ac_generator.h | 2 ++ models/dc_generator.cpp | 2 ++ models/dc_generator.h | 2 ++ models/noise_generator.cpp | 31 ++++++++++++++++++++++++++----- models/noise_generator.h | 2 ++ models/step_current_generator.cpp | 14 ++++++++++++++ models/step_current_generator.h | 2 ++ 8 files changed, 52 insertions(+), 5 deletions(-) diff --git a/models/ac_generator.cpp b/models/ac_generator.cpp index 806f396b2e..d0bcfc0281 100644 --- a/models/ac_generator.cpp +++ b/models/ac_generator.cpp @@ -75,7 +75,9 @@ nest::ac_generator::Parameters_& nest::ac_generator::Parameters_:: operator=( const Parameters_& p ) { if ( this == &p ) + { return *this; + } amp_ = p.amp_; offset_ = p.offset_; diff --git a/models/ac_generator.h b/models/ac_generator.h index 775f3ca0bb..edebb34ecc 100644 --- a/models/ac_generator.h +++ b/models/ac_generator.h @@ -198,7 +198,9 @@ inline port ac_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) { if ( receptor_type != 0 ) + { throw UnknownReceptorType( receptor_type, get_name() ); + } return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); } diff --git a/models/dc_generator.cpp b/models/dc_generator.cpp index 54ec1606de..5491fd41b0 100644 --- a/models/dc_generator.cpp +++ b/models/dc_generator.cpp @@ -63,7 +63,9 @@ nest::dc_generator::Parameters_& nest::dc_generator::Parameters_:: operator=( const Parameters_& p ) { if ( this == &p ) + { return *this; + } amp_ = p.amp_; diff --git a/models/dc_generator.h b/models/dc_generator.h index d0bca0bd06..61042fc825 100644 --- a/models/dc_generator.h +++ b/models/dc_generator.h @@ -192,7 +192,9 @@ inline port dc_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) { if ( receptor_type != 0 ) + { throw UnknownReceptorType( receptor_type, get_name() ); + } return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); } diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index 0fcfbf4f91..0e07c5ff6a 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -82,7 +82,9 @@ nest::noise_generator::Parameters_& nest::noise_generator::Parameters_:: operator=( const Parameters_& p ) { if ( this == &p ) + { return *this; + } mean_ = p.mean_; std_ = p.std_; @@ -145,21 +147,31 @@ nest::noise_generator::Parameters_::set( const DictionaryDatum& d, updateValue< double >( d, names::phase, phi_deg_ ); double dt; if ( updateValue< double >( d, names::dt, dt ) ) + { dt_ = Time::ms( dt ); + } if ( std_ < 0 ) + { throw BadProperty( "The standard deviation cannot be negative." ); + } if ( std_mod_ < 0 ) + { throw BadProperty( "The standard deviation cannot be negative." ); + } if ( std_mod_ > std_ ) + { throw BadProperty( "The modulation apmlitude must be smaller or equal to the baseline " "amplitude." ); + } - if ( !dt_.is_step() ) + if ( not dt_.is_step() ) + { throw StepMultipleRequired( n.get_name(), names::dt, dt_ ); + } } @@ -175,8 +187,10 @@ nest::noise_generator::noise_generator() , B_( *this ) { recordablesMap_.create(); - if ( !P_.dt_.is_step() ) + if ( not P_.dt_.is_step() ) + { throw InvalidDefaultResolution( get_name(), names::dt, P_.dt_ ); + } } nest::noise_generator::noise_generator( const noise_generator& n ) @@ -186,8 +200,10 @@ nest::noise_generator::noise_generator( const noise_generator& n ) , S_( n.S_ ) , B_( n.B_, *this ) { - if ( !P_.dt_.is_step() ) + if ( not P_.dt_.is_step() ) + { throw InvalidTimeInModel( get_name(), names::dt, P_.dt_ ); + } } @@ -273,7 +289,9 @@ nest::noise_generator::send_test_event( Node& target, e.set_sender( *this ); const port p = target.handles_test_event( e, receptor_type ); if ( p != invalid_port_ and not is_model_prototype() ) + { ++P_.num_targets_; + } return p; } } @@ -299,8 +317,10 @@ nest::noise_generator::update( Time const& origin, const long now = start + offs; - if ( !device_.is_active( Time::step( now ) ) ) + if ( not device_.is_active( Time::step( now ) ) ) + { continue; + } if ( P_.std_mod_ != 0. ) { @@ -319,8 +339,9 @@ nest::noise_generator::update( Time const& origin, *it = P_.mean_ + std::sqrt( P_.std_ * P_.std_ + S_.y_1_ * P_.std_mod_ * P_.std_mod_ ) * V_.normal_dev_( kernel().rng_manager.get_rng( get_thread() ) ); - S_.I_ = *it; + S_.I_ += *it; } + S_.I_ /= B_.amps_.size(); // use now as reference, in case we woke up from inactive period B_.next_step_ = now + V_.dt_steps_; diff --git a/models/noise_generator.h b/models/noise_generator.h index cac99a3071..94faf0eba4 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -261,7 +261,9 @@ inline port noise_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) { if ( receptor_type != 0 ) + { throw UnknownReceptorType( receptor_type, get_name() ); + } return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); } diff --git a/models/step_current_generator.cpp b/models/step_current_generator.cpp index eeb4f6410b..85009ceefd 100644 --- a/models/step_current_generator.cpp +++ b/models/step_current_generator.cpp @@ -65,7 +65,9 @@ nest::step_current_generator::Parameters_& nest::step_current_generator::Paramet operator=( const Parameters_& p ) { if ( this == &p ) + { return *this; + } amp_times_ = p.amp_times_; amp_values_ = p.amp_values_; @@ -112,10 +114,14 @@ nest::step_current_generator::Parameters_::set( const DictionaryDatum& d, updateValue< std::vector< double > >( d, "amplitude_values", amp_values_ ); if ( ut xor uv ) + { throw BadProperty( "Amplitude times and values must be reset together." ); + } if ( amp_times_.size() != amp_values_.size() ) + { throw BadProperty( "Amplitude times and values have to be the same size." ); + } // ensure amp times are strictly monotonically increasing if ( !amp_times_.empty() ) @@ -124,12 +130,18 @@ nest::step_current_generator::Parameters_::set( const DictionaryDatum& d, for ( std::vector< double >::const_iterator next = prev + 1; next != amp_times_.end(); ++next, ++prev ) + { if ( *prev >= *next ) + { throw BadProperty( "Amplitude times must strictly increasing." ); + } + } } if ( ut && uv ) + { b.idx_ = 0; // reset if we got new data + } } @@ -212,7 +224,9 @@ nest::step_current_generator::update( Time const& origin, const long first = t0 + from; while ( B_.idx_ < P_.amp_times_.size() && Time( Time::ms( P_.amp_times_[ B_.idx_ ] ) ).get_steps() <= first ) + { ++B_.idx_; + } for ( long offs = from; offs < to; ++offs ) { diff --git a/models/step_current_generator.h b/models/step_current_generator.h index 33ec2ca722..65b34b6c4b 100644 --- a/models/step_current_generator.h +++ b/models/step_current_generator.h @@ -193,7 +193,9 @@ inline port step_current_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) { if ( receptor_type != 0 ) + { throw UnknownReceptorType( receptor_type, get_name() ); + } return B_.logger_.connect_logging_device( dlr, recordablesMap_ ); } From 017c52c58cd501a520cb972f2cf6e011d918a62e Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Tue, 14 Mar 2017 13:39:56 +0100 Subject: [PATCH 03/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/ac_generator.cpp | 7 +++---- models/dc_generator.cpp | 9 ++++----- models/noise_generator.cpp | 3 +-- models/noise_generator.h | 3 ++- models/step_current_generator.cpp | 12 +++++++----- models/step_current_generator.h | 3 ++- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/models/ac_generator.cpp b/models/ac_generator.cpp index d0bcfc0281..95fd99d82c 100644 --- a/models/ac_generator.cpp +++ b/models/ac_generator.cpp @@ -71,8 +71,8 @@ nest::ac_generator::Parameters_::Parameters_( const Parameters_& p ) { } -nest::ac_generator::Parameters_& nest::ac_generator::Parameters_:: -operator=( const Parameters_& p ) +nest::ac_generator::Parameters_& nest::ac_generator::Parameters_::operator=( + const Parameters_& p ) { if ( this == &p ) { @@ -99,8 +99,7 @@ nest::ac_generator::Buffers_::Buffers_( ac_generator& n ) { } -nest::ac_generator::Buffers_::Buffers_( const Buffers_&, - ac_generator& n ) +nest::ac_generator::Buffers_::Buffers_( const Buffers_&, ac_generator& n ) : logger_( n ) { } diff --git a/models/dc_generator.cpp b/models/dc_generator.cpp index 5491fd41b0..cfa108d556 100644 --- a/models/dc_generator.cpp +++ b/models/dc_generator.cpp @@ -59,8 +59,8 @@ nest::dc_generator::Parameters_::Parameters_( const Parameters_& p ) { } -nest::dc_generator::Parameters_& nest::dc_generator::Parameters_:: -operator=( const Parameters_& p ) +nest::dc_generator::Parameters_& nest::dc_generator::Parameters_::operator=( + const Parameters_& p ) { if ( this == &p ) { @@ -73,7 +73,7 @@ operator=( const Parameters_& p ) } nest::dc_generator::State_::State_() - : I_( 0.0 ) // pA + : I_( 0.0 ) // pA { } @@ -83,8 +83,7 @@ nest::dc_generator::Buffers_::Buffers_( dc_generator& n ) { } -nest::dc_generator::Buffers_::Buffers_( const Buffers_&, - dc_generator& n ) +nest::dc_generator::Buffers_::Buffers_( const Buffers_&, dc_generator& n ) : logger_( n ) { } diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index 0e07c5ff6a..5bcba7f061 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -108,8 +108,7 @@ nest::noise_generator::Buffers_::Buffers_( noise_generator& n ) { } -nest::noise_generator::Buffers_::Buffers_( const Buffers_&, - noise_generator& n ) +nest::noise_generator::Buffers_::Buffers_( const Buffers_&, noise_generator& n ) : logger_( n ) { } diff --git a/models/noise_generator.h b/models/noise_generator.h index 94faf0eba4..bf3ae67a8a 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -258,7 +258,8 @@ class noise_generator : public Node }; inline port -noise_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +noise_generator::handles_test_event( DataLoggingRequest& dlr, + rport receptor_type ) { if ( receptor_type != 0 ) { diff --git a/models/step_current_generator.cpp b/models/step_current_generator.cpp index 85009ceefd..ddf5ca91dc 100644 --- a/models/step_current_generator.cpp +++ b/models/step_current_generator.cpp @@ -35,7 +35,8 @@ namespace nest { -RecordablesMap< step_current_generator > step_current_generator::recordablesMap_; +RecordablesMap< step_current_generator > + step_current_generator::recordablesMap_; template <> void @@ -61,8 +62,9 @@ nest::step_current_generator::Parameters_::Parameters_( const Parameters_& p ) { } -nest::step_current_generator::Parameters_& nest::step_current_generator::Parameters_:: -operator=( const Parameters_& p ) +nest::step_current_generator::Parameters_& + nest::step_current_generator::Parameters_:: + operator=( const Parameters_& p ) { if ( this == &p ) { @@ -76,7 +78,7 @@ operator=( const Parameters_& p ) } nest::step_current_generator::State_::State_() - : I_( 0.0 ) // pA + : I_( 0.0 ) // pA { } @@ -124,7 +126,7 @@ nest::step_current_generator::Parameters_::set( const DictionaryDatum& d, } // ensure amp times are strictly monotonically increasing - if ( !amp_times_.empty() ) + if ( not amp_times_.empty() ) { std::vector< double >::const_iterator prev = amp_times_.begin(); for ( std::vector< double >::const_iterator next = prev + 1; diff --git a/models/step_current_generator.h b/models/step_current_generator.h index 65b34b6c4b..eca8d84e9e 100644 --- a/models/step_current_generator.h +++ b/models/step_current_generator.h @@ -190,7 +190,8 @@ step_current_generator::send_test_event( Node& target, } inline port -step_current_generator::handles_test_event( DataLoggingRequest& dlr, rport receptor_type ) +step_current_generator::handles_test_event( DataLoggingRequest& dlr, + rport receptor_type ) { if ( receptor_type != 0 ) { From 0428cdd5e5900888d929bbc795af9b8c0bbfdb68 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 10:41:12 +0200 Subject: [PATCH 04/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/ac_generator.cpp | 6 +++--- models/ac_generator.h | 9 +++++---- models/dc_generator.cpp | 2 +- models/dc_generator.h | 9 +++++---- models/noise_generator.cpp | 13 +++++++------ models/noise_generator.h | 15 ++++++++++----- models/sinusoidal_gamma_generator.cpp | 2 +- models/sinusoidal_gamma_generator.h | 6 +++--- models/sinusoidal_poisson_generator.cpp | 5 ++--- models/sinusoidal_poisson_generator.h | 6 +++--- models/step_current_generator.cpp | 2 +- models/step_current_generator.h | 8 +++----- 12 files changed, 44 insertions(+), 39 deletions(-) diff --git a/models/ac_generator.cpp b/models/ac_generator.cpp index 95fd99d82c..f5bd5ea064 100644 --- a/models/ac_generator.cpp +++ b/models/ac_generator.cpp @@ -212,9 +212,9 @@ nest::ac_generator::update( Time const& origin, const long from, const long to ) long start = origin.get_steps(); + CurrentEvent ce; for ( long lag = from; lag < to; ++lag ) { - B_.logger_.record_data( origin.get_steps() + lag ); S_.I_ = 0.0; if ( device_.is_active( Time::step( start + lag ) ) ) @@ -224,10 +224,10 @@ nest::ac_generator::update( Time const& origin, const long from, const long to ) S_.y_1_ = V_.A_10_ * y_0 + V_.A_11_ * S_.y_1_; S_.I_ = S_.y_1_ + P_.offset_; - CurrentEvent ce; - ce.set_current( S_.y_1_ + P_.offset_ ); + ce.set_current( S_.I_ ); kernel().event_delivery_manager.send( *this, ce, lag ); } + B_.logger_.record_data( origin.get_steps() + lag ); } } diff --git a/models/ac_generator.h b/models/ac_generator.h index edebb34ecc..ba9b9feef1 100644 --- a/models/ac_generator.h +++ b/models/ac_generator.h @@ -113,10 +113,10 @@ class ac_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary - void set( const DictionaryDatum& ); //!< Set values from dicitonary + void set( const DictionaryDatum& ); //!< Set values from dictionary }; // ------------------------------------------------------------ @@ -125,7 +125,8 @@ class ac_generator : public Node { double y_0_; double y_1_; - double I_; + double I_; //!< Instantaneous current value; used for recording current + //!< Required to handle current values when device is inactive State_(); //!< Sets default parameter values @@ -134,7 +135,7 @@ class ac_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member friend class RecordablesMap< ac_generator >; friend class UniversalDataLogger< ac_generator >; diff --git a/models/dc_generator.cpp b/models/dc_generator.cpp index cfa108d556..909d12708d 100644 --- a/models/dc_generator.cpp +++ b/models/dc_generator.cpp @@ -176,7 +176,6 @@ nest::dc_generator::update( Time const& origin, const long from, const long to ) for ( long offs = from; offs < to; ++offs ) { - B_.logger_.record_data( origin.get_steps() + offs ); S_.I_ = 0.0; if ( device_.is_active( Time::step( start + offs ) ) ) @@ -184,6 +183,7 @@ nest::dc_generator::update( Time const& origin, const long from, const long to ) S_.I_ = P_.amp_; kernel().event_delivery_manager.send( *this, ce, offs ); } + B_.logger_.record_data( origin.get_steps() + offs ); } } diff --git a/models/dc_generator.h b/models/dc_generator.h index 61042fc825..1a0af7408c 100644 --- a/models/dc_generator.h +++ b/models/dc_generator.h @@ -122,17 +122,18 @@ class dc_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary - void set( const DictionaryDatum& ); //!< Set values from dicitonary + void set( const DictionaryDatum& ); //!< Set values from dictionary }; // ------------------------------------------------------------ struct State_ { - double I_; + double I_; //!< Instantaneous current value; used for recording current + //!< Required to handle current values when device is inactive State_(); //!< Sets default parameter values @@ -141,7 +142,7 @@ class dc_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member friend class RecordablesMap< dc_generator >; friend class UniversalDataLogger< dc_generator >; diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index 5bcba7f061..b7cef62860 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -45,7 +45,7 @@ template <> void RecordablesMap< noise_generator >::create() { - insert_( Name( names::I ), &noise_generator::get_I_ ); + insert_( Name( names::I ), &noise_generator::get_I_avg_ ); } } @@ -99,7 +99,7 @@ operator=( const Parameters_& p ) nest::noise_generator::State_::State_() : y_0_( 0.0 ) , y_1_( 0.0 ) // pA - , I_( 0.0 ) // pA + , I_avg_( 0.0 ) // pA { } @@ -311,13 +311,13 @@ nest::noise_generator::update( Time const& origin, for ( long offs = from; offs < to; ++offs ) { - B_.logger_.record_data( origin.get_steps() + offs ); - S_.I_ = 0.0; + S_.I_avg_ = 0.0; const long now = start + offs; if ( not device_.is_active( Time::step( now ) ) ) { + B_.logger_.record_data( origin.get_steps() + offs ); continue; } @@ -338,9 +338,10 @@ nest::noise_generator::update( Time const& origin, *it = P_.mean_ + std::sqrt( P_.std_ * P_.std_ + S_.y_1_ * P_.std_mod_ * P_.std_mod_ ) * V_.normal_dev_( kernel().rng_manager.get_rng( get_thread() ) ); - S_.I_ += *it; + S_.I_avg_ += *it; } - S_.I_ /= B_.amps_.size(); + S_.I_avg_ /= B_.amps_.size(); + B_.logger_.record_data( origin.get_steps() + offs ); // use now as reference, in case we woke up from inactive period B_.next_step_ = now + V_.dt_steps_; diff --git a/models/noise_generator.h b/models/noise_generator.h index bf3ae67a8a..565410ca0a 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -96,6 +96,10 @@ frequency double - Frequency of sine modulation in Hz To obtain comparable results for different values of dt, you must adapt std. + - As The noise generator provides a different current for each of its targets, + the current recorded represents the instantaneous average of all the + currents computed. When there exists only a single target, this would be + equivalent to the actual current provided to that target. Sends: CurrentEvent @@ -188,7 +192,7 @@ class noise_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary //! Set values from dictionary @@ -201,7 +205,8 @@ class noise_generator : public Node { double y_0_; double y_1_; - double I_; + double I_avg_; //!< Average of instantaneous currents computed + //!< Used for recording current State_(); //!< Sets default parameter values @@ -210,7 +215,7 @@ class noise_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member friend class RecordablesMap< noise_generator >; friend class UniversalDataLogger< noise_generator >; @@ -242,9 +247,9 @@ class noise_generator : public Node }; double - get_I_() const + get_I_avg_() const { - return S_.I_; + return S_.I_avg_; } // ------------------------------------------------------------ diff --git a/models/sinusoidal_gamma_generator.cpp b/models/sinusoidal_gamma_generator.cpp index 076dbb6197..f964d3408a 100644 --- a/models/sinusoidal_gamma_generator.cpp +++ b/models/sinusoidal_gamma_generator.cpp @@ -320,7 +320,6 @@ nest::sinusoidal_gamma_generator::update( Time const& origin, S_.rate_ = P_.rate_ + P_.amplitude_ * std::sin( P_.om_ * V_.t_ms_ + P_.phi_ ); - B_.logger_.record_data( origin.get_steps() + lag ); // t_steps_-1 since t_steps is end of interval, while activity det by start if ( P_.num_trains_ > 0 && S_.rate_ > 0 @@ -342,6 +341,7 @@ nest::sinusoidal_gamma_generator::update( Time const& origin, } } } + B_.logger_.record_data( origin.get_steps() + lag ); } } diff --git a/models/sinusoidal_gamma_generator.h b/models/sinusoidal_gamma_generator.h index ed559cfc01..8b5d359b32 100644 --- a/models/sinusoidal_gamma_generator.h +++ b/models/sinusoidal_gamma_generator.h @@ -208,12 +208,12 @@ class sinusoidal_gamma_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary /** - * Set values from dicitonary. + * Set values from dictionary. * @note State is passed so that the position can be reset if the * spike_times_ vector has been filled with new data. */ @@ -234,7 +234,7 @@ class sinusoidal_gamma_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member. friend class RecordablesMap< sinusoidal_gamma_generator >; friend class UniversalDataLogger< sinusoidal_gamma_generator >; diff --git a/models/sinusoidal_poisson_generator.cpp b/models/sinusoidal_poisson_generator.cpp index 93fd54e70f..6f371215aa 100644 --- a/models/sinusoidal_poisson_generator.cpp +++ b/models/sinusoidal_poisson_generator.cpp @@ -264,9 +264,6 @@ nest::sinusoidal_poisson_generator::update( Time const& origin, if ( S_.rate_ < 0 ) S_.rate_ = 0; - // store rate in Hz - B_.logger_.record_data( origin.get_steps() + lag ); - // create spikes if ( S_.rate_ > 0 && device_.is_active( Time::step( start + lag ) ) ) { @@ -284,6 +281,8 @@ nest::sinusoidal_poisson_generator::update( Time const& origin, kernel().event_delivery_manager.send( *this, se, lag ); } } + // store rate in Hz + B_.logger_.record_data( origin.get_steps() + lag ); } } diff --git a/models/sinusoidal_poisson_generator.h b/models/sinusoidal_poisson_generator.h index 97c494fe59..fa9f66464c 100644 --- a/models/sinusoidal_poisson_generator.h +++ b/models/sinusoidal_poisson_generator.h @@ -151,12 +151,12 @@ class sinusoidal_poisson_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary /** - * Set values from dicitonary. + * Set values from dictionary. * @note State is passed so that the position can be reset if the * spike_times_ vector has been filled with new data. */ @@ -180,7 +180,7 @@ class sinusoidal_poisson_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member friend class RecordablesMap< sinusoidal_poisson_generator >; friend class UniversalDataLogger< sinusoidal_poisson_generator >; diff --git a/models/step_current_generator.cpp b/models/step_current_generator.cpp index ddf5ca91dc..7143f4f2f4 100644 --- a/models/step_current_generator.cpp +++ b/models/step_current_generator.cpp @@ -234,7 +234,6 @@ nest::step_current_generator::update( Time const& origin, { const long curr_time = t0 + offs; - B_.logger_.record_data( origin.get_steps() + offs ); S_.I_ = 0.0; // Keep the amplitude up-to-date at all times. @@ -256,6 +255,7 @@ nest::step_current_generator::update( Time const& origin, S_.I_ = B_.amp_; kernel().event_delivery_manager.send( *this, ce, offs ); } + B_.logger_.record_data( origin.get_steps() + offs ); } } diff --git a/models/step_current_generator.h b/models/step_current_generator.h index eca8d84e9e..cb2a830598 100644 --- a/models/step_current_generator.h +++ b/models/step_current_generator.h @@ -120,7 +120,7 @@ class step_current_generator : public Node Parameters_(); //!< Sets default parameter values Parameters_( const Parameters_&, Buffers_& ); Parameters_( const Parameters_& ); - Parameters_& operator=( const Parameters_& p ); // Copy constructor EN + Parameters_& operator=( const Parameters_& p ); void get( DictionaryDatum& ) const; //!< Store current values in dictionary //! Set values from dictionary @@ -131,9 +131,7 @@ class step_current_generator : public Node struct State_ { - double y_0_; - double y_1_; - double I_; + double I_; //!< Instantaneous current value; used for recording current State_(); //!< Sets default parameter values @@ -142,7 +140,7 @@ class step_current_generator : public Node // ------------------------------------------------------------ - // These friend declarations must be precisely here. + // The next two classes need to be friends to access the State_ class/member friend class RecordablesMap< step_current_generator >; friend class UniversalDataLogger< step_current_generator >; From 549f8db310a8325b7360527adce712199b149cd7 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 11:24:23 +0200 Subject: [PATCH 05/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/noise_generator.cpp | 4 ++-- models/step_current_generator.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/models/noise_generator.cpp b/models/noise_generator.cpp index b7cef62860..3c5d37d361 100644 --- a/models/noise_generator.cpp +++ b/models/noise_generator.cpp @@ -98,8 +98,8 @@ operator=( const Parameters_& p ) nest::noise_generator::State_::State_() : y_0_( 0.0 ) - , y_1_( 0.0 ) // pA - , I_avg_( 0.0 ) // pA + , y_1_( 0.0 ) // pA + , I_avg_( 0.0 ) // pA { } diff --git a/models/step_current_generator.h b/models/step_current_generator.h index cb2a830598..da8b9c6782 100644 --- a/models/step_current_generator.h +++ b/models/step_current_generator.h @@ -131,7 +131,7 @@ class step_current_generator : public Node struct State_ { - double I_; //!< Instantaneous current value; used for recording current + double I_; //!< Instantaneous current value; used for recording current State_(); //!< Sets default parameter values From cbde8eaa81ac330d1200c3fd0bc23a8a4bb2b7a1 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 17:52:28 +0200 Subject: [PATCH 06/13] Fixes #658: Implements recording of current generated by stimulating devices --- models/noise_generator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/noise_generator.h b/models/noise_generator.h index 565410ca0a..e7ea79ee98 100644 --- a/models/noise_generator.h +++ b/models/noise_generator.h @@ -96,7 +96,7 @@ frequency double - Frequency of sine modulation in Hz To obtain comparable results for different values of dt, you must adapt std. - - As The noise generator provides a different current for each of its targets, + - As the noise generator provides a different current for each of its targets, the current recorded represents the instantaneous average of all the currents computed. When there exists only a single target, this would be equivalent to the actual current provided to that target. From 9d275c7c14a8dc97359582ea361832288762fe41 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 17:53:40 +0200 Subject: [PATCH 07/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../test_current_recording_generators.py | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 pynest/nest/tests/test_current_recording_generators.py diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py new file mode 100644 index 0000000000..a17f5547e4 --- /dev/null +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +# +# test_current_recording_generators.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 . + +""" +Test if currents from generators are being recorded properly +""" + +import numpy +import unittest +import nest + + +@nest.check_stack +class CurrentRecordingGeneratorTestCase(unittest.TestCase): + """ + Test if currents from generators are being recorded properly. Specifically: + 1) Length of current vector should be one less than length of membrane + potential vector + 2) Value of current should be equal to zero when device is inactive + """ + + def setUp(self): + nest.set_verbosity('M_WARNING') + nest.ResetKernel() + + #setting up the neuron and the generators + self.neuron = nest.Create('iaf_cond_alpha', params = {'V_reset': -65.0}) + + self.t_origin = 5.0 + self.t_start = 2.5 + self.t_stop = 40.0 + + self.ac = nest.Create('ac_generator', 1, + params = {'amplitude': 500.0, 'offset': 50.0, 'frequency': 50.0, + 'phase': 45.0, 'origin': self.t_origin, + 'start': self.t_start, 'stop': self.t_stop}) + nest.Connect(self.ac, self.neuron) + + self.dc = nest.Create('dc_generator', 1, + params = {'amplitude': 500.0, 'origin': self.t_origin, + 'start': self.t_start, 'stop': self.t_stop}) + nest.Connect(self.dc, self.neuron) + + times = [0.0, 25.0, 50.0] + currents = [400.0, 250.0, 500.0] + params = {"amplitude_times": times, "amplitude_values": currents, + 'origin': self.t_origin, 'start': self.t_start, 'stop': self.t_stop} + self.step = nest.Create("step_current_generator", 1, params) + nest.Connect(self.step, self.neuron) + + self.noise = nest.Create('noise_generator', 1, + params = {'mean': 450.0, 'std': 50.0, 'dt': 0.1, 'std_mod': 25.0, + 'phase': 45.0, 'frequency': 50.0, 'origin': self.t_origin, + 'start': self.t_start, 'stop': self.t_stop}) + nest.Connect(self.noise, self.neuron) + + def test_RecordedCurrentVectors(self): + """Check the length and contents of recorded current vectors""" + + # setting up multimeters + m_Vm = nest.Create('multimeter', + params = {'record_from': ['V_m'], 'interval' :0.1}) + nest.Connect(m_Vm, self.neuron) + + m_ac = nest.Create('multimeter', + params = {'record_from': ['I'], 'interval' :0.1}) + nest.Connect(m_ac, self.ac) + + m_dc = nest.Create('multimeter', + params = {'record_from': ['I'], 'interval' :0.1}) + nest.Connect(m_dc, self.dc) + + m_step = nest.Create('multimeter', + params = {'record_from': ['I'], 'interval' :0.1}) + nest.Connect(m_step, self.step) + + m_noise = nest.Create('multimeter', + params = {'record_from': ['I'], 'interval' :0.1}) + nest.Connect(m_noise, self.noise) + + # run simulation + nest.Simulate(50) + + # retrieve vectors + events_Vm = nest.GetStatus(m_Vm)[0]['events'] + t_Vm = events_Vm['times']; + v_Vm = events_Vm['V_m'] + + events_ac = nest.GetStatus(m_ac)[0]['events'] + t_ac = events_ac['times']; + i_ac = events_ac['I'] + + events_dc = nest.GetStatus(m_dc)[0]['events'] + t_dc = events_dc['times']; + i_dc = events_dc['I'] + + events_step = nest.GetStatus(m_step)[0]['events'] + t_step = events_step['times']; + i_step = events_step['I'] + + events_noise = nest.GetStatus(m_noise)[0]['events'] + t_noise = events_noise['times']; + i_noise = events_noise['I'] + + # Test the length of current vectors + assert len(i_ac) == len(v_Vm), \ + "Incorrect current vector length for AC generator" + assert len(i_dc) == len(v_Vm), \ + "Incorrect current vector length for DC generator" + assert len(i_step) == len(v_Vm), \ + "Incorrect current vector length for step current generator" + assert len(i_noise) == len(v_Vm), \ + "Incorrect current vector length for noise generator" + + # Test to ensure current = 0 when device is inactive + t_start_ind = numpy.where(t_ac == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] + assert (numpy.all(i_ac[:t_start_ind]) == 0 + and numpy.all(i_ac[t_stop_ind:]) == 0), \ + "Current not zero when AC generator inactive" + + t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] + assert (numpy.all(i_dc[:t_start_ind]) == 0 + and numpy.all(i_dc[t_stop_ind:]) == 0), \ + "Current not zero when DC generator inactive" + + t_start_ind = numpy.where(t_step == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_step == self.t_stop+self.t_origin)[0][0] + assert (numpy.all(i_step[:t_start_ind]) == 0 + and numpy.all(i_step[t_stop_ind:]) == 0), \ + "Current not zero when step current generator inactive" + + t_start_ind = numpy.where(t_noise == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] + assert (numpy.all(i_noise[:t_start_ind]) == 0 + and numpy.all(i_noise[t_stop_ind:]) == 0), \ + "Current not zero when noise generator inactive" + + +def suite(): + return unittest.makeSuite(CurrentRecordingGeneratorTestCase, "test") + + +def run(): + runner = unittest.TextTestRunner(verbosity=2) + runner.run(suite()) + +if __name__ == "__main__": + run() From 151dc1a504cbeaba85c2211b476e864710820886 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 18:27:27 +0200 Subject: [PATCH 08/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../test_current_recording_generators.py | 128 +++++++++--------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index a17f5547e4..47c1195149 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -42,83 +42,85 @@ def setUp(self): nest.ResetKernel() #setting up the neuron and the generators - self.neuron = nest.Create('iaf_cond_alpha', params = {'V_reset': -65.0}) + self.neuron=nest.Create('iaf_cond_alpha', params={'V_reset': -65.0}) - self.t_origin = 5.0 - self.t_start = 2.5 - self.t_stop = 40.0 + self.t_origin=5.0 + self.t_start=2.5 + self.t_stop=40.0 - self.ac = nest.Create('ac_generator', 1, - params = {'amplitude': 500.0, 'offset': 50.0, 'frequency': 50.0, - 'phase': 45.0, 'origin': self.t_origin, - 'start': self.t_start, 'stop': self.t_stop}) + self.ac=nest.Create('ac_generator', 1, + params={'amplitude': 500.0, 'offset': 50.0, 'frequency': 50.0, + 'phase': 45.0, 'origin': self.t_origin, + 'start': self.t_start, 'stop': self.t_stop}) nest.Connect(self.ac, self.neuron) - self.dc = nest.Create('dc_generator', 1, - params = {'amplitude': 500.0, 'origin': self.t_origin, - 'start': self.t_start, 'stop': self.t_stop}) + self.dc=nest.Create('dc_generator', 1, + params={'amplitude': 500.0, 'origin': self.t_origin, + 'start': self.t_start, 'stop': self.t_stop}) nest.Connect(self.dc, self.neuron) - times = [0.0, 25.0, 50.0] - currents = [400.0, 250.0, 500.0] - params = {"amplitude_times": times, "amplitude_values": currents, - 'origin': self.t_origin, 'start': self.t_start, 'stop': self.t_stop} - self.step = nest.Create("step_current_generator", 1, params) + times=[0.0, 25.0, 50.0] + currents=[400.0, 250.0, 500.0] + params={'amplitude_times': times, 'amplitude_values': currents, + 'origin': self.t_origin, 'start': self.t_start, + 'stop': self.t_stop} + self.step=nest.Create("step_current_generator", 1, params) nest.Connect(self.step, self.neuron) - self.noise = nest.Create('noise_generator', 1, - params = {'mean': 450.0, 'std': 50.0, 'dt': 0.1, 'std_mod': 25.0, - 'phase': 45.0, 'frequency': 50.0, 'origin': self.t_origin, - 'start': self.t_start, 'stop': self.t_stop}) + self.noise=nest.Create('noise_generator', 1, + params={'mean': 450.0, 'std': 50.0, 'dt': 0.1, 'std_mod': 25.0, + 'phase': 45.0, 'frequency': 50.0, + 'origin': self.t_origin, 'start': self.t_start, + 'stop': self.t_stop}) nest.Connect(self.noise, self.neuron) def test_RecordedCurrentVectors(self): """Check the length and contents of recorded current vectors""" # setting up multimeters - m_Vm = nest.Create('multimeter', - params = {'record_from': ['V_m'], 'interval' :0.1}) + m_Vm=nest.Create('multimeter', + params={'record_from': ['V_m'], 'interval': 0.1}) nest.Connect(m_Vm, self.neuron) - m_ac = nest.Create('multimeter', - params = {'record_from': ['I'], 'interval' :0.1}) + m_ac=nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_ac, self.ac) - m_dc = nest.Create('multimeter', - params = {'record_from': ['I'], 'interval' :0.1}) + m_dc=nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_dc, self.dc) - m_step = nest.Create('multimeter', - params = {'record_from': ['I'], 'interval' :0.1}) + m_step=nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_step, self.step) - m_noise = nest.Create('multimeter', - params = {'record_from': ['I'], 'interval' :0.1}) + m_noise=nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_noise, self.noise) # run simulation nest.Simulate(50) # retrieve vectors - events_Vm = nest.GetStatus(m_Vm)[0]['events'] - t_Vm = events_Vm['times']; - v_Vm = events_Vm['V_m'] + events_Vm=nest.GetStatus(m_Vm)[0]['events'] + t_Vm=events_Vm['times'] + v_Vm=events_Vm['V_m'] - events_ac = nest.GetStatus(m_ac)[0]['events'] - t_ac = events_ac['times']; - i_ac = events_ac['I'] + events_ac=nest.GetStatus(m_ac)[0]['events'] + t_ac=events_ac['times'] + i_ac=events_ac['I'] - events_dc = nest.GetStatus(m_dc)[0]['events'] - t_dc = events_dc['times']; - i_dc = events_dc['I'] + events_dc=nest.GetStatus(m_dc)[0]['events'] + t_dc=events_dc['times'] + i_dc=events_dc['I'] - events_step = nest.GetStatus(m_step)[0]['events'] - t_step = events_step['times']; - i_step = events_step['I'] + events_step=nest.GetStatus(m_step)[0]['events'] + t_step=events_step['times'] + i_step=events_step['I'] - events_noise = nest.GetStatus(m_noise)[0]['events'] - t_noise = events_noise['times']; - i_noise = events_noise['I'] + events_noise=nest.GetStatus(m_noise)[0]['events'] + t_noise=events_noise['times'] + i_noise=events_noise['I'] # Test the length of current vectors assert len(i_ac) == len(v_Vm), \ @@ -130,30 +132,30 @@ def test_RecordedCurrentVectors(self): assert len(i_noise) == len(v_Vm), \ "Incorrect current vector length for noise generator" - # Test to ensure current = 0 when device is inactive - t_start_ind = numpy.where(t_ac == self.t_start+self.t_origin)[0][0] - t_stop_ind = numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] + # Test to ensure current=0 when device is inactive + t_start_ind=numpy.where(t_ac == self.t_start+self.t_origin)[0][0] + t_stop_ind=numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_ac[:t_start_ind]) == 0 - and numpy.all(i_ac[t_stop_ind:]) == 0), \ - "Current not zero when AC generator inactive" + and numpy.all(i_ac[t_stop_ind:]) == 0), \ + "Current not zero when AC generator inactive" - t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] - t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] + t_start_ind=numpy.where(t_dc == self.t_start+self.t_origin)[0][0] + t_stop_ind=numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_dc[:t_start_ind]) == 0 - and numpy.all(i_dc[t_stop_ind:]) == 0), \ - "Current not zero when DC generator inactive" + and numpy.all(i_dc[t_stop_ind:]) == 0), \ + "Current not zero when DC generator inactive" - t_start_ind = numpy.where(t_step == self.t_start+self.t_origin)[0][0] - t_stop_ind = numpy.where(t_step == self.t_stop+self.t_origin)[0][0] + t_start_ind=numpy.where(t_step == self.t_start+self.t_origin)[0][0] + t_stop_ind=numpy.where(t_step == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_step[:t_start_ind]) == 0 - and numpy.all(i_step[t_stop_ind:]) == 0), \ - "Current not zero when step current generator inactive" + and numpy.all(i_step[t_stop_ind:]) == 0), \ + "Current not zero when step current generator inactive" - t_start_ind = numpy.where(t_noise == self.t_start+self.t_origin)[0][0] - t_stop_ind = numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] + t_start_ind=numpy.where(t_noise == self.t_start+self.t_origin)[0][0] + t_stop_ind=numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_noise[:t_start_ind]) == 0 - and numpy.all(i_noise[t_stop_ind:]) == 0), \ - "Current not zero when noise generator inactive" + and numpy.all(i_noise[t_stop_ind:]) == 0), \ + "Current not zero when noise generator inactive" def suite(): @@ -161,7 +163,7 @@ def suite(): def run(): - runner = unittest.TextTestRunner(verbosity=2) + runner=unittest.TextTestRunner(verbosity=2) runner.run(suite()) if __name__ == "__main__": From 16a4df9249707f9aeacf3d89a2739ed56541b399 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 19:00:53 +0200 Subject: [PATCH 09/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../test_current_recording_generators.py | 126 +++++++++--------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index 47c1195149..64566b15dd 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -42,85 +42,91 @@ def setUp(self): nest.ResetKernel() #setting up the neuron and the generators - self.neuron=nest.Create('iaf_cond_alpha', params={'V_reset': -65.0}) - - self.t_origin=5.0 - self.t_start=2.5 - self.t_stop=40.0 - - self.ac=nest.Create('ac_generator', 1, - params={'amplitude': 500.0, 'offset': 50.0, 'frequency': 50.0, - 'phase': 45.0, 'origin': self.t_origin, - 'start': self.t_start, 'stop': self.t_stop}) + self.neuron = nest.Create('iaf_cond_alpha', params={'V_reset': -65.0}) + + self.t_origin = 5.0 + self.t_start = 2.5 + self.t_stop = 40.0 + + self.ac = nest.Create('ac_generator', 1, + params={'amplitude': 500.0, 'offset': 50.0, + 'frequency': 50.0, 'phase': 45.0, + 'origin': self.t_origin, + 'start': self.t_start, + 'stop': self.t_stop}) nest.Connect(self.ac, self.neuron) - self.dc=nest.Create('dc_generator', 1, - params={'amplitude': 500.0, 'origin': self.t_origin, - 'start': self.t_start, 'stop': self.t_stop}) + self.dc = nest.Create('dc_generator', 1, + params={'amplitude': 500.0, + 'origin': self.t_origin, + 'start': self.t_start, + 'stop': self.t_stop}) nest.Connect(self.dc, self.neuron) - times=[0.0, 25.0, 50.0] - currents=[400.0, 250.0, 500.0] - params={'amplitude_times': times, 'amplitude_values': currents, + times = [0.0, 25.0, 50.0] + currents = [400.0, 250.0, 500.0] + params = {'amplitude_times': times, 'amplitude_values': currents, 'origin': self.t_origin, 'start': self.t_start, 'stop': self.t_stop} - self.step=nest.Create("step_current_generator", 1, params) + self.step = nest.Create("step_current_generator", 1, params) nest.Connect(self.step, self.neuron) - self.noise=nest.Create('noise_generator', 1, - params={'mean': 450.0, 'std': 50.0, 'dt': 0.1, 'std_mod': 25.0, - 'phase': 45.0, 'frequency': 50.0, - 'origin': self.t_origin, 'start': self.t_start, - 'stop': self.t_stop}) + self.noise = nest.Create('noise_generator', 1, + params={'mean': 450.0, 'std': 50.0, + 'dt': 0.1, 'std_mod': 25.0, + 'phase': 45.0, 'frequency': 50.0, + 'origin': self.t_origin, + 'start': self.t_start, + 'stop': self.t_stop}) nest.Connect(self.noise, self.neuron) def test_RecordedCurrentVectors(self): """Check the length and contents of recorded current vectors""" # setting up multimeters - m_Vm=nest.Create('multimeter', - params={'record_from': ['V_m'], 'interval': 0.1}) + m_Vm = nest.Create('multimeter', + params={'record_from': ['V_m'], 'interval': 0.1}) nest.Connect(m_Vm, self.neuron) - m_ac=nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + m_ac = nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_ac, self.ac) - m_dc=nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + m_dc = nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_dc, self.dc) - m_step=nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + m_step = nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_step, self.step) - m_noise=nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + m_noise = nest.Create('multimeter', + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_noise, self.noise) # run simulation nest.Simulate(50) # retrieve vectors - events_Vm=nest.GetStatus(m_Vm)[0]['events'] - t_Vm=events_Vm['times'] - v_Vm=events_Vm['V_m'] + events_Vm = nest.GetStatus(m_Vm)[0]['events'] + t_Vm = events_Vm['times'] + v_Vm = events_Vm['V_m'] - events_ac=nest.GetStatus(m_ac)[0]['events'] - t_ac=events_ac['times'] - i_ac=events_ac['I'] + events_ac = nest.GetStatus(m_ac)[0]['events'] + t_ac = events_ac['times'] + i_ac = events_ac['I'] - events_dc=nest.GetStatus(m_dc)[0]['events'] - t_dc=events_dc['times'] - i_dc=events_dc['I'] + events_dc = nest.GetStatus(m_dc)[0]['events'] + t_dc = events_dc['times'] + i_dc = events_dc['I'] - events_step=nest.GetStatus(m_step)[0]['events'] - t_step=events_step['times'] - i_step=events_step['I'] + events_step = nest.GetStatus(m_step)[0]['events'] + t_step = events_step['times'] + i_step = events_step['I'] - events_noise=nest.GetStatus(m_noise)[0]['events'] - t_noise=events_noise['times'] - i_noise=events_noise['I'] + events_noise = nest.GetStatus(m_noise)[0]['events'] + t_noise = events_noise['times'] + i_noise = events_noise['I'] # Test the length of current vectors assert len(i_ac) == len(v_Vm), \ @@ -133,29 +139,29 @@ def test_RecordedCurrentVectors(self): "Incorrect current vector length for noise generator" # Test to ensure current=0 when device is inactive - t_start_ind=numpy.where(t_ac == self.t_start+self.t_origin)[0][0] - t_stop_ind=numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] + t_start_ind = numpy.where(t_ac == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_ac[:t_start_ind]) == 0 and numpy.all(i_ac[t_stop_ind:]) == 0), \ - "Current not zero when AC generator inactive" + "Current not zero when AC generator inactive" - t_start_ind=numpy.where(t_dc == self.t_start+self.t_origin)[0][0] - t_stop_ind=numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] + t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_dc[:t_start_ind]) == 0 and numpy.all(i_dc[t_stop_ind:]) == 0), \ - "Current not zero when DC generator inactive" + "Current not zero when DC generator inactive" - t_start_ind=numpy.where(t_step == self.t_start+self.t_origin)[0][0] - t_stop_ind=numpy.where(t_step == self.t_stop+self.t_origin)[0][0] + t_start_ind = numpy.where(t_step == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_step == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_step[:t_start_ind]) == 0 and numpy.all(i_step[t_stop_ind:]) == 0), \ - "Current not zero when step current generator inactive" + "Current not zero when step current generator inactive" - t_start_ind=numpy.where(t_noise == self.t_start+self.t_origin)[0][0] - t_stop_ind=numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] + t_start_ind = numpy.where(t_noise == self.t_start+self.t_origin)[0][0] + t_stop_ind = numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_noise[:t_start_ind]) == 0 and numpy.all(i_noise[t_stop_ind:]) == 0), \ - "Current not zero when noise generator inactive" + "Current not zero when noise generator inactive" def suite(): @@ -163,7 +169,7 @@ def suite(): def run(): - runner=unittest.TextTestRunner(verbosity=2) + runner = unittest.TextTestRunner(verbosity=2) runner.run(suite()) if __name__ == "__main__": From bfc6f8cab50ff7ff54aadf8ba25fdc8bab4e25e8 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Wed, 5 Apr 2017 19:16:53 +0200 Subject: [PATCH 10/13] Fixes #658: Implements recording of current generated by stimulating devices --- pynest/nest/tests/test_current_recording_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index 64566b15dd..964de5fc28 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -97,11 +97,11 @@ def test_RecordedCurrentVectors(self): nest.Connect(m_dc, self.dc) m_step = nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_step, self.step) m_noise = nest.Create('multimeter', - params={'record_from': ['I'], 'interval': 0.1}) + params={'record_from': ['I'], 'interval': 0.1}) nest.Connect(m_noise, self.noise) # run simulation From 16f3fd0c2c4d09d9bfb99c79df41c43dcc0370f0 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Thu, 6 Apr 2017 14:08:49 +0200 Subject: [PATCH 11/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../test_current_recording_generators.py | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index 964de5fc28..aaa9180ffe 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -27,29 +27,33 @@ import unittest import nest - @nest.check_stack class CurrentRecordingGeneratorTestCase(unittest.TestCase): """ - Test if currents from generators are being recorded properly. Specifically: - 1) Length of current vector should be one less than length of membrane + Test if currents from generators are recorded properly. Specifically: + 1) Length of current vector should be equal to length of membrane potential vector 2) Value of current should be equal to zero when device is inactive + 3) Check if value of current recorded as expected during active period """ def setUp(self): nest.set_verbosity('M_WARNING') nest.ResetKernel() - #setting up the neuron and the generators - self.neuron = nest.Create('iaf_cond_alpha', params={'V_reset': -65.0}) + # setting up the neuron and the generators + self.neuron = nest.Create('iaf_psc_alpha', params={'V_reset': -65.0}) self.t_origin = 5.0 self.t_start = 2.5 self.t_stop = 40.0 + self.t_next = 25.0 + self.i_amp = 500.0 + self.i_off = 50.0 self.ac = nest.Create('ac_generator', 1, - params={'amplitude': 500.0, 'offset': 50.0, + params={'amplitude': self.i_amp, + 'offset': self.i_off, 'frequency': 50.0, 'phase': 45.0, 'origin': self.t_origin, 'start': self.t_start, @@ -57,14 +61,14 @@ def setUp(self): nest.Connect(self.ac, self.neuron) self.dc = nest.Create('dc_generator', 1, - params={'amplitude': 500.0, + params={'amplitude': self.i_amp, 'origin': self.t_origin, 'start': self.t_start, 'stop': self.t_stop}) nest.Connect(self.dc, self.neuron) - times = [0.0, 25.0, 50.0] - currents = [400.0, 250.0, 500.0] + times = [self.t_start, self.t_next] + currents = [self.i_amp/4, self.i_amp/2] params = {'amplitude_times': times, 'amplitude_values': currents, 'origin': self.t_origin, 'start': self.t_start, 'stop': self.t_stop} @@ -72,8 +76,8 @@ def setUp(self): nest.Connect(self.step, self.neuron) self.noise = nest.Create('noise_generator', 1, - params={'mean': 450.0, 'std': 50.0, - 'dt': 0.1, 'std_mod': 25.0, + params={'mean': self.i_amp, 'std': 0.0, + 'dt': 0.1, 'std_mod': 0.0, 'phase': 45.0, 'frequency': 50.0, 'origin': self.t_origin, 'start': self.t_start, @@ -128,7 +132,7 @@ def test_RecordedCurrentVectors(self): t_noise = events_noise['times'] i_noise = events_noise['I'] - # Test the length of current vectors + # test the length of current vectors assert len(i_ac) == len(v_Vm), \ "Incorrect current vector length for AC generator" assert len(i_dc) == len(v_Vm), \ @@ -138,36 +142,53 @@ def test_RecordedCurrentVectors(self): assert len(i_noise) == len(v_Vm), \ "Incorrect current vector length for noise generator" - # Test to ensure current=0 when device is inactive + # test to ensure current = 0 when device is inactive + # and also to check current recorded when device is active t_start_ind = numpy.where(t_ac == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_ac == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_ac[:t_start_ind]) == 0 and numpy.all(i_ac[t_stop_ind:]) == 0), \ "Current not zero when AC generator inactive" + self.assertAlmostEqual (numpy.amax(i_ac[t_start_ind:t_stop_ind]), + self.i_amp + self.i_off, msg= ("Current not" + " correct when AC generator active")) + self.assertAlmostEqual (numpy.amin(i_ac[t_start_ind:t_stop_ind]), + -self.i_amp + self.i_off, msg= ("Current not" + " correct when AC generator active")) t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_dc[:t_start_ind]) == 0 and numpy.all(i_dc[t_stop_ind:]) == 0), \ "Current not zero when DC generator inactive" + assert (numpy.allclose(i_dc[t_start_ind:t_stop_ind], self.i_amp)), \ + "Current not correct when DC generator active" t_start_ind = numpy.where(t_step == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_step == self.t_stop+self.t_origin)[0][0] + t_next_ind = numpy.where(t_step == self.t_next)[0][0] assert (numpy.all(i_step[:t_start_ind]) == 0 and numpy.all(i_step[t_stop_ind:]) == 0), \ "Current not zero when step current generator inactive" + assert (numpy.allclose(i_step[t_start_ind:t_next_ind], + self.i_amp/4) and + numpy.allclose(i_step[t_next_ind:t_stop_ind], + self.i_amp/2)), \ + "Current not correct when step current generator active" t_start_ind = numpy.where(t_noise == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_noise == self.t_stop+self.t_origin)[0][0] assert (numpy.all(i_noise[:t_start_ind]) == 0 and numpy.all(i_noise[t_stop_ind:]) == 0), \ "Current not zero when noise generator inactive" + assert (numpy.allclose(i_noise[t_start_ind:t_stop_ind], + self.i_amp)), \ + "Current not correct when noise generator active" def suite(): return unittest.makeSuite(CurrentRecordingGeneratorTestCase, "test") - def run(): runner = unittest.TextTestRunner(verbosity=2) runner.run(suite()) From 97264aa4b21be48625bf11e8ba9f40c604434292 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Thu, 6 Apr 2017 14:35:40 +0200 Subject: [PATCH 12/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../tests/test_current_recording_generators.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index aaa9180ffe..7b77e03f90 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -27,6 +27,7 @@ import unittest import nest + @nest.check_stack class CurrentRecordingGeneratorTestCase(unittest.TestCase): """ @@ -149,12 +150,14 @@ def test_RecordedCurrentVectors(self): assert (numpy.all(i_ac[:t_start_ind]) == 0 and numpy.all(i_ac[t_stop_ind:]) == 0), \ "Current not zero when AC generator inactive" - self.assertAlmostEqual (numpy.amax(i_ac[t_start_ind:t_stop_ind]), - self.i_amp + self.i_off, msg= ("Current not" - " correct when AC generator active")) - self.assertAlmostEqual (numpy.amin(i_ac[t_start_ind:t_stop_ind]), - -self.i_amp + self.i_off, msg= ("Current not" - " correct when AC generator active")) + self.assertAlmostEqual(numpy.amax(i_ac[t_start_ind:t_stop_ind]), + self.i_amp + self.i_off, + msg=("Current not correct " + "when AC generator active")) + self.assertAlmostEqual(numpy.amin(i_ac[t_start_ind:t_stop_ind]), + -self.i_amp + self.i_off, + msg=("Current not correct " + "when AC generator active")) t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0] @@ -189,6 +192,7 @@ def test_RecordedCurrentVectors(self): def suite(): return unittest.makeSuite(CurrentRecordingGeneratorTestCase, "test") + def run(): runner = unittest.TextTestRunner(verbosity=2) runner.run(suite()) From d5a021aff056f2d7ea78514d3ce83c45c4588fb3 Mon Sep 17 00:00:00 2001 From: appukuttan-shailesh Date: Thu, 6 Apr 2017 15:27:02 +0200 Subject: [PATCH 13/13] Fixes #658: Implements recording of current generated by stimulating devices --- .../nest/tests/test_current_recording_generators.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pynest/nest/tests/test_current_recording_generators.py b/pynest/nest/tests/test_current_recording_generators.py index 7b77e03f90..2f3c794089 100644 --- a/pynest/nest/tests/test_current_recording_generators.py +++ b/pynest/nest/tests/test_current_recording_generators.py @@ -151,13 +151,13 @@ def test_RecordedCurrentVectors(self): and numpy.all(i_ac[t_stop_ind:]) == 0), \ "Current not zero when AC generator inactive" self.assertAlmostEqual(numpy.amax(i_ac[t_start_ind:t_stop_ind]), - self.i_amp + self.i_off, - msg=("Current not correct " - "when AC generator active")) + self.i_amp + self.i_off, + msg=("Current not correct " + "when AC generator active")) self.assertAlmostEqual(numpy.amin(i_ac[t_start_ind:t_stop_ind]), - -self.i_amp + self.i_off, - msg=("Current not correct " - "when AC generator active")) + -self.i_amp + self.i_off, + msg=("Current not correct " + "when AC generator active")) t_start_ind = numpy.where(t_dc == self.t_start+self.t_origin)[0][0] t_stop_ind = numpy.where(t_dc == self.t_stop+self.t_origin)[0][0]