/*
* aeif_cond_exp_multisynapse.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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef AEIF_COND_EXP_MULTISYNAPSE_H
#define AEIF_COND_EXP_MULTISYNAPSE_H
#include "config.h"
#ifdef HAVE_GSL_1_11
#include "nest.h"
#include "event.h"
#include "archiving_node.h"
#include "ring_buffer.h"
#include "connection.h"
#include "universal_data_logger.h"
#include "recordables_map.h"
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv.h>
/* BeginDocumentation
Name: aeif_cond_exp_multisynapse - Conductance based exponential integrate-and-fire neuron model according to Brette and Gerstner (2005).
Description:
aeif_cond_exp_multisynapse is the adaptive exponential integrate and fire neuron
according to Brette and Gerstner (2005), with post-synaptic
conductances in the form of truncated exponentials.
This implementation uses the embedded 4th order Runge-Kutta-Fehlberg
solver with adaptive stepsize to integrate the differential equation.
The membrane potential is given by the following differential equation:
C dV/dt= -g_L(V-E_L)+g_L*Delta_T*exp((V-V_T)/Delta_T)-g_e(t)(V-E_e) -g_i(t)(V-E_i)-w +I_e
and
tau_w * dw/dt= a(V-E_L) -W
Note that the spike detection threshold V_peak is automatically set to
V_th+10 mV to avoid numerical instabilites that may result from
setting V_peak too high.
Parameters:
The following parameters can be set in the status dictionary.
Dynamic state variables:
V_m double - Membrane potential in mV
g_ex double - Excitatory synaptic conductance in nS.
g_in double - Inhibitory synaptic conductance in nS.
w double - Spike-adaptation current in pA.
Membrane Parameters:
C_m double - Capacity of the membrane in pF
t_ref double - Duration of refractory period in ms.
V_reset double - Reset value for V_m after a spike. In mV.
E_L double - Leak reversal potential in mV.
g_L double - Leak conductance in nS.
I_e double - Constant external input current in pA.
Spike adaptation parameters:
a double - Subthreshold adaptation in nS.
b double - Spike-triggered adaptation in pA.
Delta_T double - Slope factor in mV
tau_w double - Adaptation time constant in ms
V_t double - Spike initiation threshold in mV
V_peak double - Spike detection threshold in mV.
Synaptic parameters
E_ex double - Excitatory reversal potential in mV.
tau_syn_ex double - Rise time of excitatory synaptic conductance in ms (exp function).
E_in double - Inhibitory reversal potential in mV.
tau_syn_in double - Rise time of the inhibitory synaptic conductance in ms (exp function).
Integration parameters
gsl_error_tol double - This parameter controls the admissible error of the GSL integrator.
Reduce it if NEST complains about numerical instabilities.
Author: Adapted from aeif_cond_alpha by Lyle Muller
Sends: SpikeEvent
Receives: SpikeEvent, CurrentEvent, DataLoggingRequest
References: Brette R and Gerstner W (2005) Adaptive Exponential Integrate-and-Fire Model as
an Effective Description of Neuronal Activity. J Neurophysiol 94:3637-3642
SeeAlso: iaf_cond_exp, aeif_cond_alpha
*/
namespace mynest
{
/**
* Function computing right-hand side of ODE for GSL solver.
* @note Must be declared here so we can befriend it in class.
* @note Must have C-linkage for passing to GSL. Internally, it is
* a first-class C++ function, but cannot be a member function
* because of the C-linkage.
* @note No point in declaring it inline, since it is called
* through a function pointer.
* @param void* Pointer to model neuron instance.
*/
extern "C"
int aeif_cond_exp_multisynapse_dynamics (double, const double*, double*, void*);
class aeif_cond_exp_multisynapse:
public nest::Archiving_Node
{
public:
aeif_cond_exp_multisynapse();
aeif_cond_exp_multisynapse(const aeif_cond_exp_multisynapse&);
~aeif_cond_exp_multisynapse();
/**
* Import sets of overloaded virtual functions.
* We need to explicitly include sets of overloaded
* virtual functions into the current scope.
* According to the SUN C++ FAQ, this is the correct
* way of doing things, although all other compilers
* happily live without.
*/
using nest::Node::connect_sender;
using nest::Node::handle;
nest::port check_connection(nest::Connection &, nest::port);
void handle(nest::SpikeEvent &);
void handle(nest::CurrentEvent &);
void handle(nest::DataLoggingRequest &);
nest::port connect_sender(nest::SpikeEvent &, nest::port);
nest::port connect_sender(nest::CurrentEvent &, nest::port);
nest::port connect_sender(nest::DataLoggingRequest &, nest::port);
void get_status(DictionaryDatum &) const;
void set_status(const DictionaryDatum &);
private:
void init_state_(const Node &proto);
void init_buffers_();
void calibrate();
void update(const nest::Time &, const nest::long_t, const nest::long_t);
static const nest::port MIN_SPIKE_RECEPTOR = 1;
enum SpikeSynapseTypes { AMPA=MIN_SPIKE_RECEPTOR, NMDA, GABA, SUP_SPIKE_RECEPTOR };
static const nest::size_t NUM_SPIKE_RECEPTORS = SUP_SPIKE_RECEPTOR - MIN_SPIKE_RECEPTOR;
static const nest::port MIN_CURR_RECEPTOR = SUP_SPIKE_RECEPTOR;
enum CurrentSynapseTypes { CURR = MIN_CURR_RECEPTOR, SUP_CURR_RECEPTOR };
static const nest::size_t NUM_CURR_RECEPTORS = SUP_CURR_RECEPTOR - MIN_CURR_RECEPTOR;
// END Boilerplate function declarations ----------------------------
// Friends --------------------------------------------------------
// make dynamics function quasi-member
friend int mynest::aeif_cond_exp_multisynapse_dynamics(double, const double*, double*, void*);
// The next two classes need to be friends to access the State_ class/member
friend class nest::RecordablesMap<aeif_cond_exp_multisynapse>;
friend class nest::UniversalDataLogger<aeif_cond_exp_multisynapse>;
private:
// ----------------------------------------------------------------
//! Independent parameters
struct Parameters_
{
nest::double_t V_peak_; //!< Spike detection threshold in mV
nest::double_t V_reset_; //!< Reset Potential in mV
nest::double_t t_ref_; //!< Refractory period in ms
nest::double_t g_L; //!< Leak Conductance in nS
nest::double_t C_m; //!< Membrane Capacitance in pF
nest::double_t E_L; //!< Leak reversal Potential (aka resting potential) in mV
nest::double_t Delta_T; //!< Slope faktor in ms.
nest::double_t tau_w; //!< adaptation time-constant in ms.
nest::double_t a; //!< Subthreshold adaptation in nS.
nest::double_t b; //!< Spike-triggered adaptation in pA
nest::double_t V_th; //!< Spike threshold in mV.
nest::double_t t_ref; //!< Refractory period in ms.
nest::double_t I_e; //!< Intrinsic current in pA.
nest::double_t AMPA_E_rev; //!< AMPA reversal Potential in mV
nest::double_t AMPA_Tau_decay; //!< Synaptic Time Constant AMPA Synapse in ms
nest::double_t NMDA_E_rev; //!< NMDA reversal Potential in mV
nest::double_t NMDA_NEG_E_rev; //!< NMDA reversal Potential in mV
nest::double_t AMPA_NEG_E_rev; //!< NMDA reversal Potential in mV
nest::double_t NMDA_Tau_decay; //!< Synaptic Time Constant NMDA Synapse in ms
nest::double_t GABA_E_rev; //!< GABAA reversal Potential in mV
nest::double_t GABA_Tau_decay; //!< Rise Time Constant GABAA Synapse in ms
nest::double_t tau_j;
nest::double_t tau_e;
nest::double_t tau_p;
nest::double_t bias;
nest::double_t fmax;
nest::double_t gain;
nest::double_t epsilon;
nest::double_t kappa;
nest::double_t gsl_error_tol; //!< error bound for GSL integrator
Parameters_(); //!< Sets default parameter values
void get(DictionaryDatum &) const; //!< Store current values in dictionary
void set(const DictionaryDatum &); //!< Set values from dicitonary
};
public:
// ----------------------------------------------------------------
/**
* State variables of the model.
* @note Copy constructor and assignment operator required because
* of C-style array.
*/
struct State_
{
/**
* Enumeration identifying elements in state array State_::y_.
* The state vector must be passed to GSL as a C array. This enum
* identifies the elements of the vector. It must be public to be
* accessible from the iteration function.
*/
enum StateVecElems
{
V_M = 0,
W , // 3
G_AMPA ,
G_NMDA ,
G_NMDA_NEG ,
G_AMPA_NEG ,
G_GABA ,
Z_J ,
E_J ,
P_J ,
STATE_VEC_SIZE
};
nest::double_t y_[STATE_VEC_SIZE]; //!< neuron state, must be C-array for GSL solver
nest::int_t r_; //!< number of refractory steps remaining
nest::double_t I_AMPA_; //!< AMPA current; member only to allow recording
nest::double_t I_NMDA_; //!< NMDA current; member only to allow recording
nest::double_t I_NMDA_NEG_; //!< NMDA current; member only to allow recording
nest::double_t I_AMPA_NEG_; //!< NMDA current; member only to allow recording
nest::double_t I_GABA_; //!< GABAA current; member only to allow recording
nest::double_t bias;
nest::double_t epsilon;
nest::double_t kappa;
State_(const Parameters_ &); //!< Default initialization
State_(const State_ &);
State_& operator = (const State_ &);
void get(DictionaryDatum &) const;
void set(const DictionaryDatum &, const Parameters_ &);
};
// ----------------------------------------------------------------
/**
* Buffers of the model.
*/
struct Buffers_
{
Buffers_(aeif_cond_exp_multisynapse &); //!<Sets buffer pointers to 0
Buffers_(const Buffers_ &, aeif_cond_exp_multisynapse &); //!<Sets buffer pointers to 0
//! Logger for all analog data
nest::UniversalDataLogger<aeif_cond_exp_multisynapse> logger_;
/** buffers and sums up incoming spikes/currents */
nest::RingBuffer spikes_AMPA_;
nest::RingBuffer spikes_NMDA_;
nest::RingBuffer spikes_NMDA_NEG_;
nest::RingBuffer spikes_AMPA_NEG_;
nest::RingBuffer spikes_GABA_;
nest::RingBuffer currents_;
/** GSL ODE stuff */
gsl_odeiv_step* s_; //!< stepping function
gsl_odeiv_control* c_; //!< adaptive stepsize control function
gsl_odeiv_evolve* e_; //!< evolution function
gsl_odeiv_system sys_; //!< struct describing system
// IntergrationStep_ should be reset with the neuron on ResetNetwork,
// but remain unchanged during calibration. Since it is initialized with
// step_, and the resolution cannot change after nodes have been created,
// it is safe to place both here.
nest::double_t step_; //!< step size in ms
double IntegrationStep_; //!< current integration time step, updated by GSL
/**
* Input current injected by CurrentEvent.
* This variable is used to transport the current applied into the
* _dynamics function computing the derivative of the state vector.
* It must be a part of Buffers_, since it is initialized once before
* the first simulation, but not modified before later Simulate calls.
*/
nest::double_t I_stim_;
};
// ----------------------------------------------------------------
/**
* Internal variables of the model.
*/
struct Variables_
{
nest::double_t PSConInit_AMPA;
nest::double_t PSConInit_NMDA;
nest::double_t PSConInit_NMDA_NEG;
nest::double_t PSConInit_AMPA_NEG;
nest::double_t PSConInit_GABA;
nest::int_t RefractoryCounts_;
};
// Access functions for UniversalDataLogger -------------------------------
//! Read out state vector elements, used by UniversalDataLogger
template <State_::StateVecElems elem>
nest::double_t get_y_elem_() const { return S_.y_[elem]; }
nest::double_t get_I_AMPA_() const { return S_.I_AMPA_; }
nest::double_t get_I_NMDA_() const { return S_.I_NMDA_; }
nest::double_t get_I_NMDA_NEG_() const { return S_.I_NMDA_NEG_; }
nest::double_t get_I_AMPA_NEG_() const { return S_.I_AMPA_NEG_; }
nest::double_t get_I_GABA_() const { return S_.I_GABA_; }
nest::double_t get_bias_() const { return S_.bias; }
nest::double_t get_epsilon_() const { return S_.epsilon; }
nest::double_t get_kappa_() const { return S_.kappa; }
// ----------------------------------------------------------------
Parameters_ P_;
State_ S_;
Variables_ V_;
Buffers_ B_;
//! Mapping of recordables names to access functions
static nest::RecordablesMap<aeif_cond_exp_multisynapse> recordablesMap_;
};
inline
nest::port aeif_cond_exp_multisynapse::check_connection(nest::Connection &c, nest::port receptor_type)
{
nest::SpikeEvent e;
e.set_sender(*this);
c.check_event(e);
return c.get_target()->connect_sender(e, receptor_type);
}
inline
nest::port aeif_cond_exp_multisynapse::connect_sender(nest::SpikeEvent &, nest::port receptor_type)
{
// If receptor type is less than 1 =(MIN_SPIKE_RECEPTOR) or greater or equal to 4
// (=SUP_SPIKE_RECEPTOR) then provided receptor type is not a spike receptor.
if ( receptor_type < MIN_SPIKE_RECEPTOR || receptor_type >= SUP_SPIKE_RECEPTOR )
// Unknown receptor type is less than 0 or greater than 6
// (SUP_CURR_RECEPTOR).
if ( receptor_type < 0 || receptor_type >= SUP_CURR_RECEPTOR )
throw nest::UnknownReceptorType(receptor_type, get_name());
// Otherwise it is a current receptor or receptor 0 (data logging request
// not used here and therefore incompatible.
else
throw nest::IncompatibleReceptorType(receptor_type, get_name(), "SpikeEvent");
// If we arrive here the receptor type is a spike receptor and either 1, 2 or 3 e.i.
// greater or equal to MIN_SPIKE_RECEPTOR = 1, and less than SUP_SPIKE_RECEPTOR
// = 4. Then 0, 1, or 2 is returned.
return receptor_type - MIN_SPIKE_RECEPTOR;
}
inline
nest::port aeif_cond_exp_multisynapse::connect_sender(nest::DataLoggingRequest& dlr,
nest::port receptor_type)
{
// If receptor type does not equal 0 then it is not a data logging request
// receptor.
if ( receptor_type != 0 )
// If not a spike or current receptor that is less than 0 or greater or
// equal to 4 (SUP_CURR_RECEPTOR).
if ( receptor_type < 0 || receptor_type >= SUP_CURR_RECEPTOR )
throw nest::UnknownReceptorType(receptor_type, get_name());
// Otherwise it is a spike or current receptor type.
else
throw nest::IncompatibleReceptorType(receptor_type, get_name(), "DataLoggingRequest");
// CHANGED
//B_.logger_.connect_logging_device(dlr, recordablesMap_);
//return 0;
// TO
return B_.logger_.connect_logging_device(dlr, recordablesMap_);
}
inline
nest::port aeif_cond_exp_multisynapse::connect_sender(nest::CurrentEvent &, nest::port receptor_type)
{
// If receptor type is less than 4 (MIN_CURR_RECEPTOR) or greater or equal
// to 5 (SUP_CURR_RECEPTOR) the provided receptor type is not current
// receptor.
if ( receptor_type < MIN_CURR_RECEPTOR || receptor_type >= SUP_CURR_RECEPTOR )
// If receptor is not a current receptor but still a receptor type that is
// the receptor type is greater or equal to 0 or less than 3
// (MIN_CURR_RECEPTOR).
if ( receptor_type >= 0 && receptor_type < MIN_CURR_RECEPTOR )
throw nest::IncompatibleReceptorType(receptor_type, get_name(), "CurrentEvent");
// Otherwise unknown receptor type.
else
throw nest::UnknownReceptorType(receptor_type, get_name());
//MIN_CURR_RECEPTOR =4, If here receptor type equals 4 and 0 is returned.
return receptor_type - MIN_CURR_RECEPTOR;
}
inline
void aeif_cond_exp_multisynapse::get_status(DictionaryDatum &d) const
{
P_.get(d);
S_.get(d);
nest::Archiving_Node::get_status(d);
(*d)[nest::names::recordables] = recordablesMap_.get_list();
}
inline
void aeif_cond_exp_multisynapse::set_status(const DictionaryDatum &d)
{
Parameters_ ptmp = P_; // temporary copy in case of errors
ptmp.set(d); // throws if BadProperty
State_ stmp = S_; // temporary copy in case of errors
stmp.set(d, ptmp); // throws if BadProperty
// We now know that (ptmp, stmp) are consistent. We do not
// write them back to (P_, S_) before we are also sure that
// the properties to be set in the parent class are internally
// consistent.
nest::Archiving_Node::set_status(d);
// if we get here, temporaries contain consistent set of properties
P_ = ptmp;
S_ = stmp;
}
} // namespace
#endif // HAVE_GSL_1_11
#endif // AEIF_COND_EXP_MULTISYNAPSE_H