/*
 *  tsodyks_shortterm_bursts.sli
 *
 *  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/>.
 *
 */

/* BeginDocumentation
Name: test_tsodyks_shortterm - sli script for testing Tsodyks short term plastic synapses.

Synopsis: (test_tsodyks_shortterm) run


Description:
Script to test Tsodyks short term plasticity depressing/facilitating synapses according to
'Synchrony Generation in Recurrent Networks with Frequency-Dependent Synapses'
Tsodyks, Uziel, Markram
JNeuroSci, Vol. 20 RC50 p. 1--5, (2000)

author:  Moritz Helias
date:    March 2006

see also: brunel.sli
see also: http://ken.brainworks.uni-freiburg.de/nestwiki/index.php/Network_burst_generation_by_short-term_plasticity
*/


ResetKernel      % clear all existing network elements


/createSynapseTypes
{
    userdict begin

      % set delay of static synapse to appropriate value
      % (needed for spike detector)
      /static_synapse
      <<
          /delay delay
          /weight 1.0
      >> SetDefaults

      % use tsodyks type synapses
      % configure all different synapses
      % set all parameters here, which are
      % not specifically set for each connection
      /tsodyks_synapse
      <<
          /tau_psc Tau_psc
          /delay delay
          /u 0.0
          /x 0.0
      >> SetDefaults

    end
} def

%%
%% I_mean delta_I N BackgroundInput
%%
/BackgroundInput
{
    /N Set
    /delta_I Set
    /I_mean Set

    []
    N
    {
        myrng drand 0.5 sub delta_I mul I_mean add
        append
    } repeat

    Sort %% sort in ascending order
} def


% initialize an array of neurons
% calling sequence:
% [gids] params initNeurons
/initNeurons
{
    /params Set
    /neurons Set

    %% random background current
    I0_dc deltaI neurons length BackgroundInput /i0s Set

    neurons
    {
        /i Set
        /gid Set

        params
        <<
            /V_m myrng drand Theta mul %% random initial membrane potential [0, Theta]
            /I_e i0s i get             %% i0 = i0s[i]
        >>
        join

        gid params SetStatus

    } forallindexed

} def

/createNeurons
{
    userdict begin

        [0] ChangeSubnet             % return to full network

        /E_net /subnet Create def    % create subnet
        E_net ChangeSubnet           % enter subnet
        /iaf_tum_2000 Ne Create      % create neurons in subnet
        pop                          % pop gids returned by Create

        %% obtain array with GIDs of all excitatory neurons
        /E_neurons E_net GetNodes def

        /E_params <<
            /tau_m   Tau
            /tau_syn_ex  Tau_psc
            /tau_syn_in  Tau_psc
            /E_L     U0
            /V_m     U0
            /V_reset Vreset
            /V_th    Theta
            /C_m     C
            /t_ref_abs tau_ref_abs_e
            /t_ref_tot tau_ref_abs_e
        >> def

        (Configuring excitatory neuron parameters.) =
        E_neurons E_params initNeurons

        [0] ChangeSubnet             % return to full network

        /I_net /subnet Create def    % create subnet
        I_net ChangeSubnet           % enter subnet
        /iaf_tum_2000 Ni Create      % create neurons in subnet
        pop                          % pop gids returned by Create

        % obtain array with GIDs of all excitatory neurons
        /I_neurons I_net GetNodes def

        /I_params <<
                /tau_m    Tau
                /tau_syn_ex   Tau_psc
                /tau_syn_in   Tau_psc
                /E_L      U0
                /V_m      U0
                /V_reset  Vreset
                /V_th     Theta
                /C_m      C
                /t_ref_abs tau_ref_abs_i
                /t_ref_tot tau_ref_abs_i
        >> def

        (Configuring inhibitory neuron parameters.) =
        I_neurons I_params initNeurons

    end % userdict
} def


%%
%% connect randomly chosen neurons from population [sources] to target neuron
%%
%% N_conn sources target A_mean Tau_rec_mean Tau_fac_mean U_mean U_min U_max connectIncoming
%%
/connectIncoming
{
    << >> begin
        /U_max Set
        /U_min Set
        /U_mean Set
        /Tau_fac_mean Set
        /Tau_rec_mean Set
        /A_mean Set
        /target Set
        /sources Set
        /N_conn Set


        % draw weights from clipped Gaussian distribution
        % with mean = A_mean, std = 0.5 A_mean
        % clipping bounds: min = min(0.2 A_mean, 2.0 A_mean)
        %                  max = max(0.2 A_mean, 2.0 A_mean)
        normal_c
        <<
            /mu A_mean
            /std A_mean 0.5 mul
            /min A_mean dup 0.2 mul exch 2.0 mul min
            /max A_mean dup 0.2 mul exch 2.0 mul max
        >>
        SetStatus

        % draw weight for each connection
        normal_c N_conn RandomArray /weights Set


        % draw random values for tau_rec from left-clipped Gaussian distribution
        normal_cl
        <<
            /mu Tau_rec_mean
            /std Tau_rec_mean 0.5 mul
            /min Tau_min
        >>
        SetStatus

        % draw Tau_rec for each connection
        normal_cl N_conn RandomArray /tau_recs Set


        % draw random values for tau_fac from left-clipped Gaussian distribution

        %% create a copy of normal_cl

        Tau_fac_mean 0.0 gt
        {
            normal_cl
            <<
                /mu Tau_fac_mean
                /std Tau_fac_mean 0.5 mul
                /min Tau_min
            >>
            SetStatus

            % draw Tau_fac for each connection
            normal_cl N_conn RandomArray
        }
        {
            []
        }
        ifelse
        /tau_facs Set


        % draw random values for U from clipped Gaussian distribution
        % create copy of normal_c


        normal_c
        <<
            /mu U_mean
            /std U_mean 0.5 mul
            /min U_min
            /max U_max
        >>
        SetStatus

        % draw U for each connection
        normal_c N_conn RandomArray /Us Set


        %% create a dictionary containing the parameters for all synapses
        %% and an initialization function InitSynapse, which will be called
        %% by RandomConvergentConnect before each connection to be established.
        /init_dict
        <<

            /weights weights
            /tau_recs tau_recs
            /tau_facs tau_facs
            /Us Us

            /facil Tau_fac_mean 0.0 gt

            /InitSynapse
            { % call: i InitSynapse
                /i Set
                /tsodyks_synapse
                <<
                    /weight weights i get
                    /U Us i get
                    /tau_rec tau_recs i get
                    /tau_fac facil { tau_facs i get } { 0.0 } ifelse
                >> SetDefaults
            }

        >> def

        sources     % source population [we pick from this]
        target      % target neuron
        N_conn      % number of source neurons to pick
        init_dict   % initialization dictionary
        RandomConvergentConnect

    end
} def


/connectNeurons
{
    userdict begin
      % Gaussian distribution, mean = 1, std = 1
      myrng rdevdict /normal get CreateRDV /normal_tot Set

      % Gaussian distribution left/right clipped
      myrng rdevdict /normal_clipped get CreateRDV /normal_c Set

      % Gaussian distribution, left clipped
      myrng rdevdict /normal_clipped_left get CreateRDV /normal_cl Set


      % set options of RandomConvergentConnect to forbid autapses/multapses
      /RandomConvergentConnect
      <<
          /allow_multapses false
          /allow_autapses false
      >>
      SetOptions

      % use predefined tsodyks short term plasticity synapse for all
      % subsequent connections
      /Connect << /synapse_model /tsodyks_synapse >> SetOptions

      (Connecting inputs to excitatory neurons.) =

      % loop through all exc neurons
      E_neurons
      {
        /target Set

        % number of source neurons from Gaussian distribution
        normal_tot Random Indegree_std mul Indegree_mean add round int /Ctot Set

        % 80 per cent excitatory incoming connections, 20 per cent inhibitory
        Ctot 0.8 mul round int /CE Set
        Ctot CE sub /CI Set

        CE
        E_neurons
        target
        A_ee
        Tau_rec_ee
        0.0 % =Tau_fac_ee
        U_ee
        U_ee_min
        U_ee_max
        connectIncoming


        CI
        I_neurons
        target
        A_ei
        Tau_rec_ei
        0.0 % =Tau_fac_ei
        U_ee
        U_ee_min
        U_ee_max
        connectIncoming

      } bind % bind improves efficiency
      forall

      (Connecting inputs to inhibitory neurons.) =

      % loop through all inh neurons
      I_neurons
      {
        /target Set

        % number of source neurons from Gaussian distribution
        normal_tot Random 5.0 mul 50.0 add round int /Ctot Set
        % 80 per cent exc. input, 20 per cent inh. input
        Ctot 0.8 mul round int /CE Set
        Ctot CE sub /CI Set

        CI
        I_neurons
        target
        A_ii
        Tau_rec_ii
        Tau_fac_ii
        U_ii
        U_ii_min
        U_ii_max
        connectIncoming


        CE
        E_neurons
        target
        A_ie
        Tau_rec_ie
        Tau_fac_ie
        U_ii
        U_ii_min
        U_ii_max
        connectIncoming

      } bind % bind improves efficiency
      forall

    end
} def

/connectSpikeDetectors
{
    userdict begin

        [0] ChangeSubnet

        % select standard synapse

        % one detector would in principle be enough,
        % but by recording the populations separately,
        % we save us a lot of sorting work later
        (Creating and connecting spike detector.) =
        /spike_detector Create /sd Set

        sd
        <<
            /withtime true   % record time of spikes
            /withpath true   % record which neuron spiked
            /to_file true    % write results to a file
        >> SetStatus

        % select the standard synapse model for subsequent connections
        /Connect << /synapse_model /static_synapse >> SetOptions

        % connect all exc neurons to it
        E_neurons
        {
            % stack: neuronaddress
            sd         % stack: neuronaddress SDaddress
            Connect    % defaults
        } bind forall

        % connect all inh neurons to it
        I_neurons
        {
            % stack: neuronaddress
            sd         % stack: neuronaddress SDaddress
            Connect    % defaults
        } bind forall

    end
} def


userdict begin

      % global parameters
      1 /local_num_threads Set
      8 /total_num_virtual_procs Set
      0.25 /h Set

      /Ne 400 def               % number of excitatory neurons
      /Ni 100 def               % number of inhibitory neurons

      %/Pc 0.1 def              % connection probability of 2 neurons
      /Indegree_mean 50.0 def   % mean number of incoming connections per neuron
      /Indegree_std 5.0 def     % std of incoming connections per neuron

      % excitatory neurons
      /Tau 30.0 def             % membrane time constant of ex./inh. neurons in ms
      /U0 0.0 def               % resting potential of Vm for exc./inh.
      /Theta 15.0 def           % threshold for exc. neuron
      /Vreset 13.5 def          % reset potential of Vm after a spike
      /R 1.0 def                % membrane resistance 1 GOhm
      /C Tau R div def          % Tau [ms] / R [GOhm] = C [pF] in NEST units
      /Tau_psc 3.0 def          % time constant of PSC in ms (=Tau_inact=Tau_I)


      % refractory times
      /tau_ref_abs_e 3.0 def
      /tau_ref_abs_i 2.0 def


      % parameters of synapses
      /Tau_rec_ee 800.0 def      % recovery time e->e
      /Tau_rec_ei Tau_rec_ee def % recovery time i->e
      /Tau_rec_ii 100.0 def      % recovery time i->i
      /Tau_rec_ie Tau_rec_ii def % recovery time e->i

      /Tau_fac_ee 0.0 def        % facilitation time e->e
      /Tau_fac_ei Tau_fac_ee def % facilitation time i->e
      /Tau_fac_ii 1000.0 def     % facilitation time i->i
      /Tau_fac_ie Tau_fac_ii def % facilitation time e->i

      /Tau_min 5.0 def           % minimum value for Tau_rec/Tau_fac

      /U_ee 0.5 def              % facilitation parameter U e->e, i->e
      /U_ee_min 0.1 def
      /U_ee_max 0.9 def

      /U_ii 0.04 def             % facilitation parameter U i->i, e->i
      /U_ii_min 0.001 def
      /U_ii_max 0.07 def


      /A 1.8 def
      /A_ee A R div def              % PSC weight e->e given in mV converted to pA
      /A_ie A 4.0 mul R div def      % PSC weight e->i given in mV converted to pA
      /A_ii A neg 4 mul R div def    % PSC weight i->i given in mV converted to pA
      /A_ei A neg 3 mul R div def    % PSC weight i->e given in mV converted to pA

      /delay 0.25 def                % synapse delay

      /Tend 10000.0 def              % simulation time


      %% background dc input: mean = I0_dc, 2 std = deltaI
      %% equally distributed around threshold Theta
      /I0_dc Theta R div def
      /deltaI 0.025 2 Theta mul mul R div def

      % set resolution and limits on delays
      % limits must be set BEFORE connecting any elements
      [0]
      <<
        /resolution h
        /local_num_threads local_num_threads
        /overwrite_files true
%       /total_num_virtual_procs total_num_virtual_procs
      >> SetStatus

      % all floeating numbers will be printed with 6 digits
      cout 6 setprecision

      % create one single random number generator
      rngdict /knuthlfg get 238 CreateRNG /myrng Set

      % normal distribution to draw several quantities from
      myrng rdevdict /normal get CreateRDV /normal_dv Set

      % create specific synapse types syn_ee, syn_ie, syn_ei, syn_ii
      createSynapseTypes

      % create exc/inh neuron populations
      createNeurons

      % connect the neurons among each other
      connectNeurons

      % create and connect spike detectors
      connectSpikeDetectors

      Tend Simulate
end