/*
 *  issue-368.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: testsuite::issue-368

Synopsis: (issue-368) run -> NEST exits if test fails

Description:
This test ensures that models with precise timing handle input spikes
arriving at exactly the same times correctly.

Author: Hans Ekkehard Plesser
FirstVersion: August 2017
*/

(unittest) run
/unittest using

M_ERROR setverbosity

% Test 1: Linear summation of input, all models
%
% n1 receives single spike with weight 2 * w1
% n2 receives two spikes at same time with weight w1 each
% Both must have same V_m after simulation
%
% n3 receives single spike with weight w1 + w2
% n4 receives one spike with weight w1, one at same time with weight w2
% Both must have same V_m after simulation

[ /iaf_psc_alpha_canon /iaf_psc_alpha_presc /iaf_psc_delta_canon
  /iaf_psc_exp_ps
]
{
  ResetKernel
  
  /model Set
  model ==

  ResetKernel
  0 << /tics_per_ms 1024. /resolution 0.25 >> SetStatus

  % simpler to do it always than to protect by if-else
  /iaf_psc_exp_ps << /tau_syn_ex 2.0 /tau_syn_in 2.0 >> SetDefaults

  /t_spike1 2.375 def % 2.5 - 0.125 offset
  /w1   5. def   % sufficiently small to avoid psc_delta spikes
  /w2 -10. def
  
  /sg /spike_generator << /precise_times true 
          /spike_times [ t_spike1 ] >> Create def
  /n1 model Create def
  /n2 model Create def  
  /n3 model Create def
  /n4 model Create def

  % single connection, double weight  
  [ sg ] [ n1 ] /one_to_one << /weight w1 2 mul >> Connect

  % two connections, single weight
  [ sg ] [ n2 ] /one_to_one << /weight w1       >> Connect
  [ sg ] [ n2 ] /one_to_one << /weight w1       >> Connect

  % single connection, combined weight
  [ sg ] [ n3 ] /one_to_one << /weight w1 w2 add >> Connect
  
  % two connections, different weigths
  [ sg ] [ n4 ] /one_to_one << /weight w1        >> Connect
  [ sg ] [ n4 ] /one_to_one << /weight w2        >> Connect

  4 Simulate
  n1 /V_m get n2 /V_m get sub 
  abs 1e-15 lt 
  n3 /V_m get n4 /V_m get sub
  abs 1e-15 lt
  and
  assert_or_die
} forall


% Test 2: Linear summation, models with two time constants
%
% n1 receives one excitatory spike
% n2 receives one inhibitory spike at the same time
% n3 receives both spikes
%
% Let V0 == E_L be the membrane potential at t0 (same for all)
% Let V1, V2, V3 be the potentials of n1, n2, n3 after simulation
% 
% Then we expect due to linearity
% ( V1 - V0 ) + ( V2 - V0 ) == V3 - V0 

[ /iaf_psc_exp_ps
]
{
  ResetKernel
  
  /model Set
  model ==

  ResetKernel
  0 << /tics_per_ms 1024. /resolution 0.25 >> SetStatus

  model << /tau_syn_ex 5.0 /tau_syn_in 1.0 >> SetDefaults

  /t_spike1 2.375 def % 2.5 - 0.125 offset
  /w1 1000. def
  
  /sg /spike_generator << /precise_times true 
          /spike_times [ t_spike1 ] >> Create def
  /n1 model Create def
  /n2 model Create def  
  /n3 model Create def

  % excitatory connection only  
  [ sg ] [ n1 ] /one_to_one << /weight w1     >> Connect

  % inhibitory connection only
  [ sg ] [ n2 ] /one_to_one << /weight w1 neg >> Connect
  
  % excitatory and inhbitory connection
  [ sg ] [ n3 ] /one_to_one << /weight w1     >> Connect
  [ sg ] [ n3 ] /one_to_one << /weight w1 neg >> Connect

  % assume that neurons are initialized at equilibrium
  /V0 n1 /V_m get def  
  V0 n1 /E_L get eq assert  % sanity check for test
  
  4 Simulate
  /V1 n1 /V_m get def
  /V2 n2 /V_m get def
  /V3 n3 /V_m get def

  V1 V2 add V0 sub 
  V3 sub 
  abs 1e-15 lt
  assert_or_die
} forall

endusing
