An electrophysiological model of GABAergic double bouquet cells (Chrysanthidis et al. 2019)

 Download zip file 
Help downloading and running models
Accession:257610
We present an electrophysiological model of double bouquet cells (DBCs) and integrate them into an established cortical columnar microcircuit model that implements a BCPNN (Bayesian Confidence Propagation Neural Network) learning rule. The proposed architecture effectively solves the problem of duplexed learning of inhibition and excitation by replacing recurrent inhibition between pyramidal cells in functional columns of different stimulus selectivity with a plastic disynaptic pathway. The introduction of DBCs improves the biological plausibility of our model, without affecting the model's spiking activity, basic operation, and learning abilities.
Reference:
1 . Chrysanthidis N, Fiebig F, Lansner A (2019) Introducing double bouquet cells into a modular cortical associative memory model Journal of Computational Neuroscience
Citations  Citation Browser
Model Information (Click on a link to find other models with that property)
Model Type: Realistic Network;
Brain Region(s)/Organism:
Cell Type(s): Neocortex U1 interneuron basket PV GABA cell; Neocortex U1 L2/6 pyramidal intratelencephalic GLU cell; Abstract integrate-and-fire adaptive exponential (AdEx) neuron; Neocortex layer 2-3 interneuron; Neocortex bitufted interneuron;
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: NEST;
Model Concept(s): Learning;
Implementer(s): Chrysanthidis, Nikolaos [nchr at kth.se]; Fiebig, Florian [fiebig at kth.se]; Lansner, Anders [ala at kth.se];
Search NeuronDB for information about:  Neocortex U1 L2/6 pyramidal intratelencephalic GLU cell; Neocortex U1 interneuron basket PV GABA cell;
/
ChrysanthidisEtAl2019
BCPNN_NEST_Module
bootstrap-module-100725
module-100725
autom4te.cache
libltdl
sli
aclocal.m4 *
aeif_cond_exp_multisynapse.cpp *
aeif_cond_exp_multisynapse.h *
bcpnn_connection.cpp *
bcpnn_connection.h *
bcpnn_connection_backup.cpp *
bcpnn_connection_backup.h *
bootstrap.sh *
compile *
config.guess *
config.sub *
configure *
configure.ac *
depcomp *
iaf_cond_alpha_bias.cpp *
iaf_cond_alpha_bias.h *
iaf_cond_exp_bias.cpp *
iaf_cond_exp_bias.h *
install-sh *
ltmain.sh *
Makefile.am *
Makefile.in *
missing *
pt_module.cpp *
pt_module.h *
pt_module_config.h.in *
pt_module_names.cpp *
pt_module_names.h *
                            
/*
 *  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