/*
* test_multimeter_accu.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_multimeter_accu - test support for multimeter accumulation mode
Synopsis: (test_multimeter_accu.sli) run -> dies if assertion fails
Description:
1. Test that all recording flags incompatible with /to_accumulator are set to false
2. Simulate iaf_cond_alpha net with poisson input and record detailed and accumulated
potentials, compare.
3. Run network for different thread numbers to check accumulation across threads.
Author: Plesser
FirstVersion: 2011-02-11
*/
% The following test needs the model iaf_cond_alpha,
% which is only compiled if we have the GSL
statusdict/have_gsl :: {
/unittest (8831) require
/unittest using
/arr (9161) require
M_ERROR setverbosity
/clear_error
{
counttomark npop % pop all but mark
errordict begin /newerror false def end
} def
% integer_data --- return array with only unique entries in ascending order
% data must be intergers
%
/unique_ascending
{
/d << >> def
{ cvs cvlit d exch 0 put } forall
d keys { cvs cvi } Map Sort
}
def
% times data --- times and data have corresponding entries; entries in
% data with equalt times are summed.
/sum_by_times
{
/data Set
dup { cvs cvlit } Map /times Set
unique_ascending { cvs cvlit } Map /utimes Set
/res << >> def
utimes { res exch 0 put } forall
[ data times ] { /key Set res key get add res exch key exch put } ScanThread
[ ] utimes { res exch get append } forall
}
def
% first test:
% make sure that to_accumulator forces all conflicting options to false
{
<< >> begin
/mm /multimeter << /to_accumulator true >> Create def
/mms mm GetStatus def
true [ /to_file /to_screen /to_memory /withgid /withweight ]
{ mms exch get not and } Fold
end
} assert_or_die
% second test:
% connect normal and accumulating multimeter, simulate, compare
{
ResetKernel
<< >> begin
/recvars [ /g_in ] def
/N 100 def
/nnet /subnet Create def
nnet ChangeSubnet
/iaf_cond_alpha N Create ;
0 ChangeSubnet
/nrns nnet GetGlobalLeaves def
/multimeter << /record_from recvars /withgid false /withtime true
/interval 0.7 /start 4.8 /stop 233.1 /time_in_steps true >> SetDefaults
/mm /multimeter Create def
/ac /multimeter << /to_memory false /to_accumulator true >> Create def
mm nrns DivergentConnect
ac nrns DivergentConnect
/pg /poisson_generator << /rate 1000. >> Create def
/static_synapse /exc << /weight 1.0 >> CopyModel
/static_synapse /inh << /weight -1.0 >> CopyModel
pg nrns /exc DivergentConnect
pg nrns /inh DivergentConnect
250. Simulate
/detevs mm /events get def
/dettimes detevs /times get cva def
/accevs ac /events get def
/acctimes accevs /times get cva def
recvars
{
/var Set
% get data from individual recordings
detevs var get cva
% compute mean for error estimate
dup Mean /varmean Set
% sum results for equal times
dettimes exch sum_by_times
% data from accumulated recording
accevs var get cva
% test difference relative to mean
sub true exch { varmean div abs 1e-15 lt and } Fold
} Map
true exch { and } Fold
% check that times are equal
dettimes unique_ascending acctimes eq and
end
} assert_or_die
% third test:
% as second test, but with three threads (NB: thread number should NOT divide number of neurons)
% since we know from the previous test that accumulation works on a single thread, we can
% test against single-thread accumulated results. This saves us a lot of work in matching
% gids to threads.
/run_mma
{
<< >> begin
/n_threads Set
/N 100 def % should not be divisible by thread number
ResetKernel
0 /num_processes get 1 eq assert % distributed setting not covered
0 << /local_num_threads n_threads >> SetStatus
% actual neurons, placed in subnet
/nnet /subnet Create def
nnet ChangeSubnet
/iaf_cond_alpha N << /I_e 40. >> Create ;
0 ChangeSubnet
/nrns nnet GetGlobalLeaves def
nrns { dup /global_id get 1 sub 30. N div mul -90. add
/foo << >> def foo exch /V_m exch put foo SetStatus } forall
% multimeter for accumulated recording
/ac /multimeter << /record_from [ /V_m ] /withgid false
/to_memory false /to_accumulator true >> Create def
ac nrns DivergentConnect
250. Simulate
% obtain data
ac /events get /V_m get cva
end
}
def
{
<< >> begin
1 run_mma dup % run with single thread
Mean /mn Set % store mean
3 run_mma % run with three threads
sub mn div true exch { abs 1e-14 lt and } Fold
end
} assert_or_die
endusing
} if % have_gsl