/*
 *  issue-77.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/>.
 *
 */

/*
 * Regression test for Ticket #77 (GitHub).
 *
 * Ensure that all neuron models register outgoing 
 * spikes with archiving node. The test sends a very 
 * high-rate Poisson spike train into the neuron that
 * should make any type of model neuron fire and checks
 * both `t_spike` entry of the neuron (>0 if neuron has
 * spiked) and checks that the connection weight differs
 * from the initial value 1.0.
 *
 * Hans Ekkehard Plesser, 2015-08-14 
 *
 */

(unittest) run
/unittest using

M_ERROR setverbosity

/* We first need to test the parrot_neuron_ps, since we should use that in tests below.
 */
{
  /sg /spike_generator << /spike_times [ 10.0 ] /precise_times true >> Create  def
  /pn /parrot_neuron_ps Create def
  
  sg pn Connect
  20 Simulate
  
  pn /t_spike get 11.0 eq
} assert_or_die
  


% The following models will not be tested:
/skip_list [ 
             /ginzburg_neuron             % binary neuron
             /mcculloch_pitts_neuron      % binary neuron
             /pp_pop_psc_delta            % population model, not suitable for STDP
             /lin_rate_ipn                % rate neuron
             /lin_rate_opn                % rate neuron
             /tanh_rate_ipn               % rate neuron
             /tanh_rate_opn               % rate neuron
             /threshold_lin_rate_ipn      % rate neuron
             /threshold_lin_rate_opn      % rate neuron
             /siegert_neuron              % rate neuron
             /music_event_out_proxy       % MUSIC port
             /music_event_in_proxy        % MUSIC port
             /music_message_in_proxy      % MUSIC port
             /music_cont_out_proxy        % MUSIC port
             /music_cont_in_proxy         % MUSIC port
           ] def    

% The following models require connections to rport 1 or other specific parameters:
/extra_params <<
   /aeif_psc_alpha << /initial_weight 80.0 >>
   /aeif_psc_exp << /initial_weight 80.0 >>
   /gif_psc_exp_multisynapse << /params << /tau_syn [ 1.0 ] >>
                                  /receptor_type 1 >>
   /gif_cond_exp_multisynapse << /params << /tau_syn [ 1.0 ] >>
                                  /receptor_type 1 >>
   /iaf_psc_alpha_multisynapse << /params << /tau_syn [ 1.0 ] >>
                                  /receptor_type 1 >>
   /iaf_psc_exp_multisynapse << /params << /tau_syn [ 1.0 ] >>
                                  /receptor_type 1 >>
   /aeif_cond_alpha_multisynapse << /params << /tau_syn [ 1.0 ] >>
                                  /receptor_type 1 >>
   /aeif_cond_beta_multisynapse << /params << /E_rev [ 0.0 ] 
                                              /tau_rise [ 1.0 ]
                                              /tau_decay [ 1.0 ] >>
                                  /receptor_type 1 >>
   /iaf_cond_alpha_mc << /receptor_type 1 >>
   /ht_neuron << /receptor_type 1 >>
   /sli_neuron << /params << /calibrate { }
                             /update { /spike ex_spikes 10. gt def } 
                          >>
               >> 
   >>
   def
                                     

{
  % apply to all models of element_type neuron
  modeldict keys {
    /model Set
    
    model skip_list exch MemberQ not
    model GetDefaults /element_type get /neuron eq and
    {
      ResetKernel
      /n model Create def
      extra_params model known
      {
         extra_params model get /params known
         {
           extra_params model get /params get
           n exch
           SetStatus
         } if 
      } if   
      
      /pg /poisson_generator << /rate 1e5 >> Create def
      /parrot /parrot_neuron_ps Create def
      /sd /spike_detector << /withtime false /withgid false >> Create def
      
      pg parrot Connect   % need to connect via parrot since generators cannot connect with
                          % plastic synapses.

      /initial_weight 10.0 def
      /syn_spec << /model /stdp_synapse
                   /weight
                     extra_params model known
                     {
                        extra_params model get /initial_weight known
                        {
                           extra_params model get /initial_weight get
                        }
                        {
                           initial_weight
                        } ifelse
                     }
                     {
                        initial_weight
                     } ifelse
                   /receptor_type 
                     extra_params model known
                     {
                       extra_params model get /receptor_type known
                       {
                         extra_params model get /receptor_type get
                       } 
                       {
                         0
                       } ifelse
                     }
                     {
                       0
                     } ifelse
                >> def  

      [ parrot ] [ n ] /one_to_one syn_spec Connect
      n sd Connect
            
      100 Simulate

      /neuron_spiked sd /n_events get 0 gt def
      /t_spike_set n /t_spike get 0 gt def
      /weight_changed
        << /source [ parrot ] >> GetConnections 0 get /weight get  
        initial_weight neq def 

      neuron_spiked t_spike_set weight_changed and and
      dup not {
       (FAILED: ) model cvs join == 
       (  events ) =only sd /n_events get =
       (  tspike ) =only n /t_spike get =
       (  weight ) =only  << /source [ parrot ] >> GetConnections 0 get /weight get ==
      } if      
    }
    { true }
    ifelse
  }
  Map

  % see if all entries are true
  true exch { and } Fold

} 
assert_or_die

endusing
