#ifndef PIF_PSC_ALPHA_H
#define PIF_PSC_ALPHA_H
/*
* pif_psc_alpha.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/>.
*
*/
#include "nest.h"
#include "event.h"
#include "node.h"
#include "ring_buffer.h"
#include "connection.h"
#include "universal_data_logger.h"
#include "dictdatum.h"
namespace mynest {
/* BeginDocumentation
Name: pif_psc_alpha - Perfect integrate-and-fire neuron model with alpha PSC synapse.
Description:
pif_psc_alpha implements a non-leaky integrate-and-fire neuron with
with alpha-function shaped synaptic currents. The threshold crossing is
followed by an absolute refractory period during which the membrane potential
is clamped to the resting potential, while synaptic currents evolve normally.
The dynamics of the neuron are defined by
C_m dV/dt = I_syn(t) + I_e
I_syn(t) = Sum_{t_{j,k} < t} w_j x (t-t_{j,k}) x e/tau_syn x e^{-(t-t_{j,k})/tau_syn}
where t_{j,k} is the time of the k-th spike arriving from neuron j, and w_j is
the weight of the synapse from neuron j onto the present neuron. The alpha function
is normalized by amplitude, i.e., the maximum input current for any spike is w_j.
Parameters:
C_m double - Membrane capacitance, in pF
I_e double - Intrinsic DC current, in nA
tau_syn double - Synaptic time constant, in ms
t_ref double - Duration of refractory period in ms.
V_th double - Spike threshold in mV.
V_reset double - Reset potential of the membrane in mV.
Remarks:
The linear subthresold dynamics is integrated by the Exact
Integration scheme [1]. The neuron dynamics is solved on the time
grid given by the computation step size. Incoming as well as emitted
spikes are forced to that grid.
References:
[1] Rotter S & Diesmann M (1999) Exact simulation of time-invariant linear
systems with applications to neuronal modeling. Biologial Cybernetics
81:381-402.
Sends: SpikeEvent
Receives: SpikeEvent, CurrentEvent, DataLoggingRequest
Author:
Hans Ekkehard Plesser, based on iaf_psc_alpha
SeeAlso:
iaf_psc_delta, iaf_psc_exp, iaf_psc_alpha
*/
/**
* Non-leaky integrate-and-fire neuron with alpha-shaped PSCs.
*/
class pif_psc_alpha : public nest::Node
{
public:
/**
* The constructor is only used to create the model prototype in the model manager.
*/
pif_psc_alpha();
/**
* The copy constructor is used to create model copies and instances of the model.
* @node The copy constructor needs to initialize the parameters and the state.
* Initialization of buffers and interal variables is deferred to
* @c init_buffers_() and @c calibrate().
*/
pif_psc_alpha(const pif_psc_alpha&);
/**
* Import sets of overloaded virtual functions.
* This is necessary to ensure proper overload and overriding resolution.
* @see http://www.gotw.ca/gotw/005.htm.
*/
using nest::Node::connect_sender;
using nest::Node::handle;
/**
* Used to validate that we can send SpikeEvent to desired target:port.
*/
nest::port check_connection(nest::Connection&, nest::port);
/**
* @defgroup mynest_handle Functions handling incoming events.
* We tell nest that we can handle incoming events of various types by
* defining @c handle() and @c connect_sender() for the given event.
* @{
*/
void handle(nest::SpikeEvent &); //! accept spikes
void handle(nest::CurrentEvent &); //! accept input current
void handle(nest::DataLoggingRequest &);//! allow recording with multimeter
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:
//! Reset parameters and state of neuron.
//! Reset state of neuron.
void init_state_(const Node& proto);
//! Reset internal buffers of neuron.
void init_buffers_();
//! Initialize auxiliary quantities, leave parameters and state untouched.
void calibrate();
//! Take neuron through given time interval
void update(nest::Time const &, const nest::long_t, const nest::long_t);
// The next two classes need to be friends to access the State_ class/member
friend class nest::RecordablesMap<pif_psc_alpha>;
friend class nest::UniversalDataLogger<pif_psc_alpha>;
/**
* Free parameters of the neuron.
*
* These are the parameters that can be set by the user through @c SetStatus.
* They are initialized from the model prototype when the node is created.
* Parameters do not change during calls to @c update() and are not reset by
* @c ResetNetwork.
*
* @note Parameters_ need neither copy constructor nor @c operator=(), since
* all its members are copied properly by the default copy constructor
* and assignment operator. Important:
* - If Parameters_ contained @c Time members, you need to define the
* assignment operator to recalibrate all members of type @c Time . You
* may also want to define the assignment operator.
* - If Parameters_ contained members that cannot copy themselves, such
* as C-style arrays, you need to define the copy constructor and
* assignment operator to copy those members.
*/
struct Parameters_ {
double C_m; //!< Membrane capacitance, in pF.
double I_e; //!< Intrinsic DC current, in nA.
double tau_syn; //!< Synaptic time constant, in ms.
double V_th; //!< Spike threshold, in mV.
double V_reset; //!< Reset potential of the membrane, in mV.
double t_ref; //!< Duration of refractory period, in ms.
//! Initialize parameters to their default values.
Parameters_();
//! Store parameter values in dictionary.
void get(DictionaryDatum&) const;
//! Set parameter values from dictionary.
void set(const DictionaryDatum&);
};
/**
* Dynamic state of the neuron.
*
* These are the state variables that are advanced in time by calls to
* @c update(). In many models, some or all of them can be set by the user
* through @c SetStatus. The state variables are initialized from the model
* prototype when the node is created. State variables are reset by @c ResetNetwork.
*
* @note State_ need neither copy constructor nor @c operator=(), since
* all its members are copied properly by the default copy constructor
* and assignment operator. Important:
* - If State_ contained @c Time members, you need to define the
* assignment operator to recalibrate all members of type @c Time . You
* may also want to define the assignment operator.
* - If State_ contained members that cannot copy themselves, such
* as C-style arrays, you need to define the copy constructor and
* assignment operator to copy those members.
*/
struct State_ {
double V_m; //!< Membrane potential, in mV.
double dI_syn; //!< Derivative of synaptic current, in nA/ms.
double I_syn; //!< Synaptic current, in nA.
double I_ext; //!< External current, in nA.
long refr_count; //!< Number of steps neuron is still refractory for
/**
* Construct new default State_ instance based on values in Parameters_.
* This c'tor is called by the no-argument c'tor of the neuron model. It
* takes a reference to the parameters instance of the model, so that the
* state can be initialized in accordance with parameters, e.g., initializing
* the membrane potential with the resting potential.
*/
State_(const Parameters_&);
/** Store state values in dictionary. */
void get(DictionaryDatum&) const;
/**
* Set membrane potential from dictionary.
* @note Receives Parameters_ so it can test that the new membrane potential
* is below threshold.
*/
void set(const DictionaryDatum&, const Parameters_&);
};
/**
* Buffers of the neuron.
* Ususally buffers for incoming spikes and data logged for analog recorders.
* Buffers must be initialized by @c init_buffers_(), which is called before
* @c calibrate() on the first call to @c Simulate after the start of NEST,
* ResetKernel or ResetNetwork.
* @node Buffers_ needs neither constructor, copy constructor or assignment operator,
* since it is initialized by @c init_nodes_(). If Buffers_ has members that
* cannot destroy themselves, Buffers_ will need a destructor.
*/
struct Buffers_ {
Buffers_(pif_psc_alpha&);
Buffers_(const Buffers_ &, pif_psc_alpha&);
nest::RingBuffer spikes; //!< Buffer incoming spikes through delay, as sum
nest::RingBuffer currents; //!< Buffer incoming currents through delay, as sum
//! Logger for all analog data
nest::UniversalDataLogger<pif_psc_alpha> logger_;
};
/**
* Internal variables of the neuron.
* These variables must be initialized by @c calibrate, which is called before
* the first call to @c update() upon each call to @c Simulate.
* @node Variables_ needs neither constructor, copy constructor or assignment operator,
* since it is initialized by @c calibrate(). If Variables_ has members that
* cannot destroy themselves, Variables_ will need a destructor.
*/
struct Variables_ {
double P11;
double P21;
double P22;
double P31;
double P32;
double P30;
double P33;
double pscInitialValue;
long t_ref_steps; //!< Duration of refractory period, in steps.
};
/**
* @defgroup Access functions for UniversalDataLogger.
* @{
*/
//! Read out the real membrane potential
nest::double_t get_V_m_() const { return S_.V_m; }
/** @} */
/**
* @defgroup pif_members Member variables of neuron model.
* Each model neuron should have precisely the following four data members,
* which are one instance each of the parameters, state, buffers and variables
* structures. Experience indicates that the state and variables member should
* be next to each other to achieve good efficiency (caching).
* @note Devices require one additional data member, an instance of the @c Device
* child class they belong to.
* @{
*/
Parameters_ P_; //!< Free parameters.
State_ S_; //!< Dynamic state.
Variables_ V_; //!< Internal Variables
Buffers_ B_; //!< Buffers.
//! Mapping of recordables names to access functions
static nest::RecordablesMap<pif_psc_alpha> recordablesMap_;
/** @} */
};
inline
nest::port mynest::pif_psc_alpha::check_connection(nest::Connection& c, nest::port receptor_type)
{
// You should usually not change the code in this function.
// It confirms that the target of connection @c c accepts @c SpikeEvent on
// the given @c 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 mynest::pif_psc_alpha::connect_sender(nest::SpikeEvent&, nest::port receptor_type)
{
// You should usually not change the code in this function.
// It confirms to the connection management system that we are able
// to handle @c SpikeEvent on port 0. You need to extend the function
// if you want to differentiate between input ports.
if (receptor_type != 0)
throw nest::UnknownReceptorType(receptor_type, get_name());
return 0;
}
inline
nest::port mynest::pif_psc_alpha::connect_sender(nest::CurrentEvent&, nest::port receptor_type)
{
// You should usually not change the code in this function.
// It confirms to the connection management system that we are able
// to handle @c CurrentEvent on port 0. You need to extend the function
// if you want to differentiate between input ports.
if (receptor_type != 0)
throw nest::UnknownReceptorType(receptor_type, get_name());
return 0;
}
inline
nest::port mynest::pif_psc_alpha::connect_sender(nest::DataLoggingRequest& dlr,
nest::port receptor_type)
{
// You should usually not change the code in this function.
// It confirms to the connection management system that we are able
// to handle @c DataLoggingRequest on port 0.
// The function also tells the built-in UniversalDataLogger that this node
// is recorded from and that it thus needs to collect data during simulation.
if (receptor_type != 0)
throw nest::UnknownReceptorType(receptor_type, get_name());
return B_.logger_.connect_logging_device(dlr, recordablesMap_);
}
inline
void pif_psc_alpha::get_status(DictionaryDatum &d) const
{
P_.get(d);
S_.get(d);
(*d)[nest::names::recordables] = recordablesMap_.get_list();
}
inline
void pif_psc_alpha::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
// if we get here, temporaries contain consistent set of properties
P_ = ptmp;
S_ = stmp;
}
} // namespace
#endif /* #ifndef PIF_PSC_ALPHA_H */