/*
 *       File name:  libcn/hosted-synapses.cc
 *         Project:  cnrun
 *          Author:  Andrei Zavada <johnhommer@gmail.com>
 *                   building on original work by Thomas Nowotny <tnowotny@ucsd.edu>
 * Initial version:  2009-04-03
 *
 *         Purpose:  hosted synapse classes (those having their
 *                   state vars on parent model's integration vectors)
 *
 *         License:  GPL-2+
 */

#if HAVE_CONFIG_H && !defined(VERSION)
#  include "config.h"
#endif

#include <iostream>

#include "hosted-synapses.hh"

#include "types.hh"
#include "model.hh"

using namespace std;


// the base synapse here
cnrun::C_HostedSynapse::
C_HostedSynapse (const TUnitType type_,
                 C_BaseNeuron *source_, C_BaseNeuron *target_,
                 const double g_, CModel *M_, int s_mask,
                 TIncludeOption include_option)
      : C_BaseSynapse (type_, source_, target_, g_, M_, s_mask),
        C_HostedAttributes()
{
        if ( M )
                M->include_unit( this, include_option);
        else
                idx = (unsigned long)-1;
}





// -- parameters

const char* const cnrun::CN_ParamNames_SynapseAB_dd[] = {
//        "Synaptic strength g, " CN_PU_CONDUCTANCE,
        "Reversal potential Esyn, " CN_PU_POTENTIAL,
        "Presyn threshold potential Epre, " CN_PU_POTENTIAL,
        "Rise rate α, " CN_PU_RATE,
        "Decay rate β, " CN_PU_RATE,
        "Time of transmitter release, " CN_PU_TIME,
//        "Noise level \317\203",
};
const char* const cnrun::CN_ParamSyms_SynapseAB_dd[] = {
//        "gsyn",
        "Esyn",
        "Epre",
        "alpha",
        "beta",
        "trel",
//        "sigma",
};

const double cnrun::CN_Params_SynapseAB_dd[] = {
//        0.12,
        0,
      -20,
        0.5,
        0.05,
        5.0,
//        0.
};

const double cnrun::CN_Params_SynapseABMinus_dd[] = {
//        0.12,
        0,
      -20,
        0.27785150819749,
        0.05,
        5.0,
//        0.
};

const double cnrun::CN_Params_SynapseMxAB_dd[] = {
//        0.12,
        0,
      -20,
        0.27785150819749,  // the only parameter differing from its AB namesake,
                           // which is also by principle the same as in the ABMinus variation
        0.05,
        5.0,
//        0.
};


const char* const cnrun::CN_ParamNames_SynapseAB_dr[] = {
//        "Synaptic strength g, " CN_PU_CONDUCTANCE,
        "Assumed (target->E - Esyn), " CN_PU_POTENTIAL,
        "Presyn threshold potential Epre, " CN_PU_POTENTIAL,
        "Rise rate α, " CN_PU_RATE,
        "Decay rate β, " CN_PU_RATE,
        "Time of transmitter release, " CN_PU_TIME,
//        "Noise level \317\203",
};
const char* const cnrun::CN_ParamSyms_SynapseAB_dr[] = {
//        "gsyn",
        "Ediff",
        "Epre",
        "alpha",
        "beta",
        "trel",
//        "sigma",
};


const double cnrun::CN_Params_SynapseMxAB_dr[] = {
//        0.12,
      -60 - 0,  // Ediff: a reasonable Esyn - target->E, the latter being -60 mV at rest
      -20,
        0.27785150819749,
        0.05,
        5.0,
//        0.
};







const char* const cnrun::CN_ParamNames_SynapseAB_rr[] = {
//        "Synaptic strength g, " CN_PU_CONDUCTANCE,
        "Assumed (target->E - Esyn), " CN_PU_VOLTAGE,
        "Rise rate α, " CN_PU_RATE,
        "Decay rate β, " CN_PU_RATE,
        "Refractory period T, " CN_PU_TIME,
//        "Noise level \317\203",
};
const char* const cnrun::CN_ParamSyms_SynapseAB_rr[] = {
//        "gsyn",
        "Ediff",
        "alpha",
        "beta",
        "T",
//        "sigma",
};
const double cnrun::CN_Params_SynapseAB_rr[] = {
//        0.12,
      -60 - 0,
        0.27785150819749,
        0.05,
        5,
//        0.
};



const char* const cnrun::CN_ParamNames_SynapseRall_dd[] = {
//        "Synaptic strength g, " CN_PU_CONDUCTANCE,
        "Reversal potential, " CN_PU_POTENTIAL,
        "Presynaptic threshold potential, " CN_PU_POTENTIAL,
        "τ, " CN_PU_RATE,
//        "Noise level \317\203",
};
const char* const cnrun::CN_ParamSyms_SynapseRall_dd[] = {
//        "gsyn",
        "Esyn",
        "Epre",
        "tau",
//        "sigma",
};
const double cnrun::CN_Params_SynapseRall_dd[] = {
//        0.12,
        0,
      -20,
        2,
//        0.
};




// -- variables

const char* const cnrun::CN_VarNames_SynapseAB[] = {
        "Amount of neurotransmitter released S"
};
const char* const cnrun::CN_VarSyms_SynapseAB[] = {
        "S"
};
const double cnrun::CN_Vars_SynapseAB[] = {
        0.
};


const char* const cnrun::CN_VarNames_SynapseRall[] = {
        "Amount of neurotransmitter released S",
        "Amount of neurotransmitter absorbed R",
};
const char* const cnrun::CN_VarSyms_SynapseRall[] = {
        "S",
        "R",
};
const double cnrun::CN_Vars_SynapseRall[] = {
        0.,
        0.
};







void
cnrun::CSynapseAB_dd::
derivative( vector<double>& x, vector<double>& dx)
{
        if ( x[0] - t_last_release_started <= P[_rtime_] ) {
              // continue release from an old spike
                dS(dx) = P[_alpha_] * (1 - S(x)) - P[_beta_] * S(x);
        } else
                if ( _source->E(x) > P[_Epre_] ) {
                      // new spike ... start releasing
                        t_last_release_started = x[0];
                        dS(dx) = P[_alpha_] * (1 - S(x)) - P[_beta_] * S(x);
                } else {
                      // no release
                        dS(dx) = -P[_beta_] * S(x);
                }
}




void
cnrun::CSynapseABMinus_dd::
derivative( vector<double>& x, vector<double>& dx)
{
        if ( x[0] - t_last_release_started <= P[_rtime_] ) {
              // continue release from an old spike
                dS(dx) = P[_alpha_] * 1 - P[_beta_] * S(x);
        } else
                if ( _source->E(x) > P[_Epre_] ) {
                      // new spike ... start releasing
                        t_last_release_started = x[0];
                        dS(dx) = P[_alpha_] * 1 - P[_beta_] * S(x);
                } else {
                      // no release
                        dS(dx) = -P[_beta_] * S(x);
                }
}




// -------- Multiplexing AB

void
cnrun::CSynapseMxAB_dd::
derivative( vector<double>& x, vector<double>& dx)
{
//        printf( "%s %lu %d %g\n", _source->label, _source->serial_id, _source->idx, _source->E(x));

        if ( q() > 0 ) {
                size_t effective_q = q();
              // as we nudge along a little within RK's operational
              // dt, some spikes can expire in that brief while:
              // decrement q then, just for this while
                while ( effective_q  &&  M->model_time(x) - _kq[q()-effective_q] > P[_rtime_] )
                        --effective_q;
#ifdef CN_MORECODE__
                if ( effective_q < q() )
                        M->vp( 6, "YMxAB %s smacks %zu spike(s) of %zu at %g(+%g)\n", label,
                               (size_t)q() - effective_q, (size_t)q(),
                               M->model_time(),
                               M->model_time(x) - M->model_time());
#endif
                dS(dx) = P[_alpha_] * effective_q - P[_beta_] * S(x);
        } else
              // no release, decay
                dS(dx) = -P[_beta_] * S(x);
}



void
cnrun::CSynapseMxAB_dd::
update_queue()
{
        size_t k = _source -> n_spikes_in_last_dt();
        while ( k-- )
                _kq.push_back( model_time());

      // see if the oldest spike has gone past synapse release time
      // disregard spike duration, measure time from saved spike_start
      // (which is == spike_end)
        while ( true ) {
                if ( q() > 0 && model_time() - _kq.front() > P[_rtime_] )
                        _kq.erase( _kq.begin());
                else
                        break;
        }
}










void
cnrun::CSynapseAB_rr::
derivative( vector<double>& x, vector<double>& dx)
{
        // if ( source()->F(x) > 0 )
        //         printf( "%s->F(x) = %g\n", _source->label, source()->F(x));
        dS(dx) = -P[_beta_] * S(x)
                + P[_alpha_] * _numerator / (exp( P[_beta_] / source()->F(x)) + 1);
}







inline int Heaviside( double val)  { return (val >= 0) ? 1 : 0; }

void
cnrun::CSynapseRall_dd::
derivative( vector<double>& x, vector<double>& dx)
{
        dR(dx) = 1 / P[_tau_] * (-R(x) + Heaviside( _source->E(x) - P[_Epre_]));
        dS(dx) = 1 / P[_tau_] * (-S(x) + R(x));
}

// Local Variables:
// Mode: c++
// indent-tabs-mode: nil
// tab-width: 8
// c-basic-offset: 8
// End:
