/*
 *  test_iaf_ps_psp_poisson_generator_accuracy.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::test_iaf_ps_psp_poisson_generator_accuracy - test precise poisson generator input to neuron model

Synopsis: (test_iaf_ps_psp_poisson_generator_accuracy) run -> compare with analytical solution

Description:
The tests generates a poisson spike train using the poisson generator
for precise spike times. In a second step this spike train is supplied
to a neuron model and the resulting subthreshold membrane potential
fluctuations are compared to the analytical solution.  Thus, in
contrast to the more advanced test_iaf_ps_psp_poisson_accuracy, this
test does not require the interaction of the generator and the neuron
model to work and does not require the availability of a parrot
neuron.  In contrast to test_iaf_ps_psp_poisson_accuracy the DC
required to maintain a subthreshold membrane potential is generated by
a dc generator not a property of the neuron model.  The
spike_generator used to supply the neuron model with spikes,
constraints spike times to the tic grid of the simulation kernel. This
is the temporal resolution in which the computation step size and
simulation times are expressed. Therefore, the results of simulations
at different computation step sizes only differ because of limited
machine precision.  The difference between the analytical result and
the simulation, however, is dictated by the number of tics per
millisecond.

Author:  May 2005, March 2009 Diesmann
References:
 [1] Morrison A, Straube S, Plesser H E, & Diesmann M (2007) Exact Subthreshold 
     Integration with Continuous Spike Times in Discrete Time Neural Network 
     Simulations. Neural Computation 19:47--79
SeeAlso: testsuite::test_iaf_ps_psp_accuracy, testsuite::test_iaf_ps_psp_poisson_accuracy,testsuite::test_iaf_ps_psp_poisson_spike_accuracy 
*/

(unittest) run
/unittest using

M_ERROR setverbosity


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Parameters of simulation schedule.
%
-10                         /min_exponent Set
1.0                         /delay Set          % in ms 
65.0                        /weight Set         % in pA
-530.0                      /I0  Set            % in pA 
[-4 min_exponent -2] Range  /hlist Set
1e-13                       /tolerance Set      % in mV
1e-4                        /tic_tolerance Set  % in mV

100.0                         /T     Set



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Parameters of neuron model.
%


<<
  /E_L         0.0      % resting potential in mV 
  /V_m         0.0      % initial membrane potential in mV  
  /V_reset     0.0
  /V_th     1000.0      % spike threshold in mV
  /tau_m      10.0      % membrane time constant in ms
  /tau_syn     0.3      % PSC rise time in ms
  /C_m       250.0      % membrane capacity in pF
>> /params Set

/rate 16.0 def               % in spikes/ms 



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Reference value
%
% The function /potential computes the exact value of the membrane
% potential at the end of the simulation for a given input spike train.       
%

/psp 
 [/t]
 ( 
  UnitStep(t)*weight * E/tau_syn * 1/C_m 
    * ( (exp(-t/tau_m)-exp(-t/tau_syn))/(1/tau_syn - 1/tau_m)^2 - t*exp(-t/tau_syn)/(1/tau_syn - 1/tau_m) ) 
 )
 Function
def


/dc
 [/t]
 ( I0*tau_m/C_m*(1-exp(-t/tau_m)) )
 Function 
def


/potential
{                  % argument is the input spike train
 params begin

  ( psp(T-t-delay) ) /t Function Map

  Sort Total       % the present Total does not control accuracy 

  ( dc(T-2*delay) ) ExecMath add 

 end
} def



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Create the input spike train
%

/CreateSpikeTrain
{
 0 dexp /h Set    % any computation time step is ok

 ResetKernel


 0 << /tics_per_ms min_exponent neg dexp /resolution h >> SetStatus

 /poisson_generator_ps Create /pg Set
 pg << /rate  rate 1000.0 mul >> SetStatus      % in Hz 


 /spike_detector Create /sd Set
 sd << /precise_times true >> SetStatus

 pg sd Connect 

 T Simulate

 sd [/events /times] get cva   % return value is spike train in ms
} def 



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Simulation for a given computation step size
%
/AlignedImpact
[/i /model /s]
{
 i dexp /h Set        % computation step size in ms  

 ResetKernel
 0 << /tics_per_ms min_exponent neg dexp /resolution h  >> SetStatus

 /dc_generator Create /dc Set
 dc <<    
       /start  1.0      % in ms 
       /amplitude I0    % in pA 
    >> SetStatus               

 /spike_generator Create /sg Set
 sg <<
      /start 0.0          % in ms 
      /spike_times s      % in ms
      /precise_times true % interpret times as precise points
    >> SetStatus

 model Create /n Set
 n params SetStatus


 sg n weight delay Connect
 dc n              Connect


 T Simulate

 n /V_m get     % potential in mV at end of simulation
} 
Function
def



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Perform simulations at all resolutions and collect results
%

CreateSpikeTrain /s Set
s potential      /V Set  % potential from closed form expression

[/iaf_psc_alpha_presc /iaf_psc_alpha_canon] /models Set 


{
hlist
{
 /i Set
 [ 
  i 
  models 
  {
   i exch s AlignedImpact dup V sub abs 
  } forall
 ]

}
Map

%dup print_details   % uncomment for debugging
 
Transpose 
Rest 2 Partition 
dup 

 [/All 1] Part Flatten 
 dup Rest exch First sub       % check whether simulation results are 
 {tolerance lt} Map                     % identical for all resolutions
  true exch {and} Fold
  exch

 [/All 2] Part Flatten                            % check whether individual simulation results 
 {tic_tolerance lt} Map                     % are identical to analytical solution
 true exch {and} Fold

 and
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% print results
%
/print_details
{
cout default 15 setprecision 

endl
endl
(Exact value of membrane potential after ) <-
T <- ( ms is ) <-
V <- ( mV.) <- endl 

endl

(               h in ms    ) <-
(     simul. potential [mV]) <-
(        error         [mV]) <-
(     simul. potential [mV]) <-
(        error         [mV]) <- 
endl
(--------------------------) <-
(--------------------------) <-
(--------------------------) <-
(--------------------------) <-
(--------------------------) <-
endl

r
{
 {
  exch 24 setw exch <- (  ) <-
 }
 forall
 endl
}
forall 
;
} 
def




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RPN expression for the reference value
%
% Below is the code used to compute the reference value before
% the compiler for infix mathematical notation became available.
%
% V is the exact value of the membrane potential at the end 
% of the simulation.       
%

%params begin
%userdict begin
% << >> begin
%
% s
% {
%  T exch sub delay sub /t Set
%
%  t 0.0 geq 
%  {
%   TauSyn inv Tau inv sub /dti Set
%   weight C inv mul
%   E TauSyn div mul
%   t neg Tau div exp t neg TauSyn div exp sub
%   dti dup mul div
%   t t neg TauSyn div exp mul
%   dti div
%   sub mul
%  }
%  { 0.0 }
%  ifelse
% } Map
%
% Sort
% 0 exch {add} forall
%
% % I0 Tau/C (1 -e^-T/Tau)
% 
% I0 Tau C div mul 1.0 T 2.0 sub neg Tau div exp sub mul
% add 
%
% end
%end
%end
%
%/V Set


assert_or_die
