1 /*
2 * pp_psc_delta.h
3 *
4 * This file is part of NEST.
5 *
6 * Copyright (C) 2004 The NEST Initiative
7 *
8 * NEST is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * NEST is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #ifndef PP_PSC_DELTA_H
24 #define PP_PSC_DELTA_H
25
26 // Includes from nestkernel:
27 #include "archiving_node.h"
28 #include "connection.h"
29 #include "event.h"
30 #include "nest_types.h"
31 #include "random_generators.h"
32 #include "ring_buffer.h"
33 #include "universal_data_logger.h"
34
35 namespace nest
36 {
37
38 /* BeginUserDocs: neuron, point process, current-based
39
40 Short description
41 +++++++++++++++++
42
43 Point process neuron with leaky integration of delta-shaped PSCs
44
45 Description
46 +++++++++++
47
48 pp_psc_delta is an implementation of a leaky integrator, where the potential
49 jumps on each spike arrival. It produces spike stochastically, and supports
50 spike-frequency adaptation, and other optional features.
51
52 Spikes are generated randomly according to the current value of the
53 transfer function which operates on the membrane potential. Spike
54 generation is followed by an optional dead time. Setting with_reset to
55 true will reset the membrane potential after each spike.
56
57 The transfer function can be chosen to be linear, exponential or a sum of
58 both by adjusting three parameters:
59
60 .. math::
61
62 rate = Rect[ c_1 * V' + c_2 * \exp(c_3 * V') ],
63
64 where the effective potential :math:`V' = V_m - E_{sfa}` and :math:`E_{sfa}`
65 is called the adaptive threshold. Here Rect means rectifier:
66 :math:`Rect(x) = {x \text{ if } x>=0, 0 \text{ else}}` (this is necessary
67 because
68 negative rates are not possible).
69
70 By setting c_3 = 0, c_2 can be used as an offset spike rate for an otherwise
71 linear rate model.
72
73 The dead time enables to include refractoriness. If dead time is 0, the
74 number of spikes in one time step might exceed one and is drawn from the
75 Poisson distribution accordingly. Otherwise, the probability for a spike
76 is given by :math:`1 - \exp(-rate*h)`, where h is the simulation time step. If
77 dead_time is smaller than the simulation resolution (time step), it is
78 internally set to the resolution.
79
80 Note that, even if non-refractory neurons are to be modeled, a small value
81 of dead_time, like dead_time=1e-8, might be the value of choice since it
82 uses faster uniform random numbers than dead_time=0, which draws Poisson
83 numbers. Only for very large spike rates (> 1 spike/time_step) this will
84 cause errors.
85
86 The model can optionally include an adaptive firing threshold.
87 If the neuron spikes, the threshold increases and the membrane potential
88 will take longer to reach it.
89 Here this is implemented by subtracting the value of the adaptive threshold
90 E_sfa from the membrane potential V_m before passing the potential to the
91 transfer function, see also above. E_sfa jumps by q_sfa when the neuron
92 fires a spike, and decays exponentially with the time constant tau_sfa
93 after (see [2]_ or [3]_). Thus, the E_sfa corresponds to the convolution of the
94 neuron's spike train with an exponential kernel.
95 This adaptation kernel may also be chosen as the sum of n exponential
96 kernels. To use this feature, q_sfa and tau_sfa have to be given as a list
97 of n values each.
98
99 The firing of pp_psc_delta is usually not a renewal process. For example,
100 its firing may depend on its past spikes if it has non-zero adaptation terms
101 (q_sfa). But if so, it will depend on all its previous spikes, not just the
102 last one -- so it is not a renewal process model. However, if "with_reset"
103 is True, and all adaptation terms (q_sfa) are 0, then it will reset
104 ("forget") its membrane potential each time a spike is emitted, which makes
105 it a renewal process model (where "rate" above is its hazard function,
106 also known as conditional intensity).
107
108 pp_psc_delta may also be called a spike-response model with escape-noise [6]_
109 (for vanishing, non-random dead_time). If c_1>0 and c_2==0, the rate is a
110 convolution of the inputs with exponential filters -- which is a model known
111 as a Hawkes point process (see [4]_). If instead c_1==0, then pp_psc_delta is
112 a point process generalized linear model (with the canonical link function,
113 and exponential input filters) (see [5,6]_).
114
115 This model has been adapted from iaf_psc_delta. The default parameters are
116 set to the mean values given in [2]_, which have been matched to spike-train
117 recordings. Due to the many features of pp_psc_delta and its versatility,
118 parameters should be set carefully and consciously.
119
120 Parameters
121 ++++++++++
122
123 The following parameters can be set in the status dictionary.
124
125
126 ================= ======= ===================================================
127 V_m mV Membrane potential
128 C_m pF Capacitance of the membrane
129 tau_m ms Membrane time constant
130 q_sfa mV Adaptive threshold jump
131 tau_sfa ms Adaptive threshold time constant
132 dead_time ms Duration of the dead time
133 dead_time_random boolean Should a random dead time be drawn after each
134 spike?
135 dead_time_shape integer Shape parameter of dead time gamma distribution
136 t_ref_remaining ms Remaining dead time at simulation start
137 with_reset boolean Should the membrane potential be reset after a
138 spike?
139 I_e pA Constant input current
140 c_1 Hz/mV Slope of linear part of transfer function in
141 Hz/mV
142 c_2 Hz Prefactor of exponential part of transfer function
143 c_3 1/mV Coefficient of exponential non-linearity of
144 transfer function
145 ================= ======= ===================================================
146
147
148 References
149 ++++++++++
150
151 .. [1] Cardanobile S, Rotter S (2010). Multiplicatively interacting point
152 processes and applications to neural modeling. Journal of
153 Computational Neuroscience 28(2):267-284
154 DOI: https://doi.org/10.1007/s10827-009-0204-0
155 .. [2] Jolivet R, Rauch A, Luescher H-R, Gerstner W. (2006). Predicting spike
156 timing of neocortical pyramidal neurons by simple threshold models.
157 Journal of Computational Neuroscience 21:35-49.
158 DOI: https://doi.org/10.1007/s10827-006-7074-5
159 .. [3] Pozzorini C, Naud R, Mensi S, Gerstner W (2013). Temporal whitening by
160 power-law adaptation in neocortical neurons. Nature Neuroscience
161 16:942-948. (Uses a similar model of multi-timescale adaptation)
162 DOI: https://doi.org/10.1038/nn.3431
163 .. [4] Grytskyy D, Tetzlaff T, Diesmann M, Helias M (2013). A unified view
164 on weakly correlated recurrent networks. Frontiers in Computational
165 Neuroscience, 7:131.
166 DOI: https://doi.org/10.3389/fncom.2013.00131
167 .. [5] Deger M, Schwalger T, Naud R, Gerstner W (2014). Fluctuations and
168 information filtering in coupled populations of spiking neurons with
169 adaptation. Physical Review E 90:6, 062704.
170 DOI: https://doi.org/10.1103/PhysRevE.90.062704
171 .. [6] Gerstner W, Kistler WM, Naud R, Paninski L (2014). Neuronal Dynamics:
172 From single neurons to networks and models of cognition.
173 Cambridge University Press
174
175
176 Sends
177 +++++
178
179 SpikeEvent
180
181 Receives
182 ++++++++
183
184 SpikeEvent, CurrentEvent, DataLoggingRequest
185
186 See also
187 ++++++++
188
189 pp_pop_psc_delta, iaf_psc_delta, iaf_psc_alpha, iaf_psc_exp, iaf_psc_delta_ps
190
191 EndUserDocs */
192
193 class pp_psc_delta : public ArchivingNode
194 {
195
196 public:
197 pp_psc_delta();
198 pp_psc_delta( const pp_psc_delta& );
199
200 /**
201 * Import sets of overloaded virtual functions.
202 * @see Technical Issues / Virtual Functions: Overriding, Overloading, and
203 * Hiding
204 */
205 using Node::handle;
206 using Node::handles_test_event;
207
208 port send_test_event( Node&, rport, synindex, bool );
209
210 void handle( SpikeEvent& );
211 void handle( CurrentEvent& );
212 void handle( DataLoggingRequest& );
213
214 port handles_test_event( SpikeEvent&, rport );
215 port handles_test_event( CurrentEvent&, rport );
216 port handles_test_event( DataLoggingRequest&, rport );
217
218
219 void get_status( DictionaryDatum& ) const;
220 void set_status( const DictionaryDatum& );
221
222 private:
223 void init_state_();
224 void init_buffers_();
225 void calibrate();
226
227 void update( Time const&, const long, const long );
228
229 // The next two classes need to be friends to access the State_ class/member
230 friend class RecordablesMap< pp_psc_delta >;
231 friend class UniversalDataLogger< pp_psc_delta >;
232
233 // ----------------------------------------------------------------
234
235 /**
236 * Independent parameters of the model.
237 */
238 struct Parameters_
239 {
240 /** Membrane time constant in ms. */
241 double tau_m_;
242
243 /** Membrane capacitance in pF. */
244 double c_m_;
245
246 /** Dead time in ms. */
247 double dead_time_;
248
249 /** Do we use random dead time? */
250 bool dead_time_random_;
251
252 /** Shape parameter of random dead time gamma distribution. */
253 unsigned long dead_time_shape_;
254
255 /** Do we reset the membrane potential after each spike? */
256 bool with_reset_;
257
258 /** List of adaptive threshold time constant in ms (for multi adaptation
259 * version). */
260 std::vector< double > tau_sfa_;
261
262 /** Adaptive threshold jump in mV (for multi adaptation version). */
263 std::vector< double > q_sfa_;
264
265 /** indicates multi parameter adaptation model **/
266 bool multi_param_;
267
268 /** Slope of the linear part of transfer function. */
269 double c_1_;
270
271 /** Prefactor of exponential part of transfer function. */
272 double c_2_;
273
274 /** Coefficient of exponential non-linearity of transfer function. */
275 double c_3_;
276
277 /** External DC current. */
278 double I_e_;
279
280 /** Dead time from simulation start. */
281 double t_ref_remaining_;
282
283 Parameters_(); //!< Sets default parameter values
284
285 void get( DictionaryDatum& ) const; //!< Store current values in dictionary
286 void set( const DictionaryDatum&, Node* node ); //!< Set values from dictionary
287 };
288
289 // ----------------------------------------------------------------
290
291 /**
292 * State variables of the model.
293 */
294 struct State_
295 {
296 double y0_; //!< This is piecewise constant external current
297 //! This is the membrane potential RELATIVE TO RESTING POTENTIAL.
298 double y3_;
299 double q_; //!< This is the change of the 'threshold' due to adaptation.
300
301 //! Vector of adaptation parameters. by Hesam
302 std::vector< double > q_elems_;
303
304 int r_; //!< Number of refractory steps remaining
305
306 bool initialized_; //!< it is true if the vectors are initialized
307
308 State_(); //!< Default initialization
309
310 void get( DictionaryDatum&, const Parameters_& ) const;
311 void set( const DictionaryDatum&, const Parameters_&, Node* );
312 };
313
314 // ----------------------------------------------------------------
315
316 /**
317 * Buffers of the model.
318 */
319 struct Buffers_
320 {
321 Buffers_( pp_psc_delta& );
322 Buffers_( const Buffers_&, pp_psc_delta& );
323
324 /** buffers and sums up incoming spikes/currents */
325 RingBuffer spikes_;
326 RingBuffer currents_;
327
328 //! Logger for all analog data
329 UniversalDataLogger< pp_psc_delta > logger_;
330 };
331
332 // ----------------------------------------------------------------
333
334 /**
335 * Internal variables of the model.
336 */
337 struct Variables_
338 {
339
340 double P30_;
341 double P33_;
342
343 std::vector< double > Q33_;
344
345 double h_; //!< simulation time step in ms
346 double dt_rate_; //!< rate parameter of dead time distribution
347
348 RngPtr rng_; //!< random number generator of my own thread
349 gamma_distribution gamma_dist_; //!< gamma distribution
350 poisson_distribution poisson_dist_; //!< poisson distribution
351
352 int DeadTimeCounts_;
353 };
354
355 // Access functions for UniversalDataLogger -----------------------
356
357 //! Read out the real membrane potential
358 double
get_V_m_()359 get_V_m_() const
360 {
361 return S_.y3_;
362 }
363
364 //! Read out the adaptive threshold potential
365 double
get_E_sfa_()366 get_E_sfa_() const
367 {
368 return S_.q_;
369 }
370
371 // ----------------------------------------------------------------
372
373 /**
374 * @defgroup iaf_psc_alpha_data
375 * Instances of private data structures for the different types
376 * of data pertaining to the model.
377 * @note The order of definitions is important for speed.
378 * @{
379 */
380 Parameters_ P_;
381 State_ S_;
382 Variables_ V_;
383 Buffers_ B_;
384 /** @} */
385
386 //! Mapping of recordables names to access functions
387 static RecordablesMap< pp_psc_delta > recordablesMap_;
388 };
389
390 inline port
send_test_event(Node & target,rport receptor_type,synindex,bool)391 pp_psc_delta::send_test_event( Node& target, rport receptor_type, synindex, bool )
392 {
393 SpikeEvent e;
394 e.set_sender( *this );
395
396 return target.handles_test_event( e, receptor_type );
397 }
398
399
400 inline port
handles_test_event(SpikeEvent &,rport receptor_type)401 pp_psc_delta::handles_test_event( SpikeEvent&, rport receptor_type )
402 {
403 if ( receptor_type != 0 )
404 {
405 throw UnknownReceptorType( receptor_type, get_name() );
406 }
407 return 0;
408 }
409
410 inline port
handles_test_event(CurrentEvent &,rport receptor_type)411 pp_psc_delta::handles_test_event( CurrentEvent&, rport receptor_type )
412 {
413 if ( receptor_type != 0 )
414 {
415 throw UnknownReceptorType( receptor_type, get_name() );
416 }
417 return 0;
418 }
419
420 inline port
handles_test_event(DataLoggingRequest & dlr,rport receptor_type)421 pp_psc_delta::handles_test_event( DataLoggingRequest& dlr, rport receptor_type )
422 {
423 if ( receptor_type != 0 )
424 {
425 throw UnknownReceptorType( receptor_type, get_name() );
426 }
427 return B_.logger_.connect_logging_device( dlr, recordablesMap_ );
428 }
429
430 inline void
get_status(DictionaryDatum & d)431 pp_psc_delta::get_status( DictionaryDatum& d ) const
432 {
433 P_.get( d );
434 S_.get( d, P_ );
435 ArchivingNode::get_status( d );
436 ( *d )[ names::recordables ] = recordablesMap_.get_list();
437 }
438
439 inline void
set_status(const DictionaryDatum & d)440 pp_psc_delta::set_status( const DictionaryDatum& d )
441 {
442 Parameters_ ptmp = P_; // temporary copy in case of errors
443 ptmp.set( d, this ); // throws if BadProperty
444 State_ stmp = S_; // temporary copy in case of errors
445 stmp.set( d, ptmp, this ); // throws if BadProperty
446
447 // We now know that (ptmp, stmp) are consistent. We do not
448 // write them back to (P_, S_) before we are also sure that
449 // the properties to be set in the parent class are internally
450 // consistent.
451 ArchivingNode::set_status( d );
452
453 // if we get here, temporaries contain consistent set of properties
454 P_ = ptmp;
455 S_ = stmp;
456 }
457
458 } // namespace
459
460 #endif /* #ifndef PP_PSC_DELTA_H */
461