/* * brunel.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/>. * */ /* Brunel Network The SLI code in this file creates a sparsely coupled network of excitatory and inhibitory neurons. Connections within and across both populations are created at random. Both neuron populations receive Poissonian background input. The spike output of 50 neurons from each population are recorded. Neurons are modeled as leaky integrate-and-fire neurons with current-injecting synapses (alpha functions). The model is based on Nicolas Brunel Dynamics of sparsely connected networks of excitatory and inhibitory spiking neurons Journal of Computational Neuroscience, 2000, vol 8, pp 183-208. There are two differences to Brunel's model: we use alpha functions instead of delta for synaptic currents, and our neurons reset to the resting potential (0 mv) instead of to half-way between resting potential and threshold. This example shows how to - organize subpopulations in subnets - instrument a network with injection and recording devices - record data to files - define own functions - set parameters in a simple way - communicate with the user in a simple way Abigail Morrison, Marc-Oliver Gewaltig, Hans Ekkehard Plesser */ %%% PARAMETER SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % define all relevant parameters: changes should be made here % all data is place in the userdict dictionary /order 2500 def % scales size of network (total 5*order neurons) % case C : asynchronous irregular /g 5.0 def % rel strength, inhibitory synapses /eta 2.0 def % nu_ext / nu_thresh % case D : slow oscillations %/g 4.5 def % rel strength, inhibitory synapses %/eta 0.95 def % nu_ext / nu_thresh /simtime 100.0 def % simulation time [ms] /dt 0.1 def % simulation step length [ms] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % NO USER-SERVICABLE PARTS BELOW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% FUNCTION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Take spike detector, find total number of spikes registered, % return average rate per neuron in Hz. % NOTE: If you are running with several MPI processes, this % function only gives an approximation to the true rate. % % spike_det ComputeRate -> rate /ComputeRate { << >> begin % anonymous dictionary for local variables /sdet Set % spike detector address % We need to guess how many neurons we record from. % This assumes an even distribution of nodes across % processes, as well as homogeneous activity in the % network. So this is really a hack. NEST needs better % support for rate calculations, such as giving the % number of neurons recorded from by each spike detector. userdict /Nrec get cvd NumProcesses div /nnrn Set sdet /n_events get nnrn userdict /simtime get mul div 1000 mul % convert from mHz to Hz, leave on stack end } bind % optional, improves performance def %%% PREPARATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /NE 4 order mul cvi def % number of excitatory neurons /NI 1 order mul cvi def % number of inhibitory neurons /N NI NE add def % total number of neurons /epsilon 0.1 def % connectivity /CE epsilon NE mul cvi def % number of excitatory synapses on neuron /CI epsilon NI mul cvi def % number of inhibitory synapses on neuron /C CE CI add def % total number of internal synapses per n. /Cext CE def % number of external synapses on neuron /tauMem 20.0 def % neuron membrane time constant [ms] /tauSyn 0.5 def % synaptic time constant [ms] /tauRef 2.0 def % refractory time [ms] /U0 0.0 def % resting potential [mV] /theta 20.0 def % threshold % synaptic weights, scaled for our alpha functions, such that % for constant membrane potential, charge J would be deposited /delay 1.5 def % synaptic delay, all connections [ms] /J 0.1 def % synaptic weight [mV] /fudge 0.41363506632638 def % ensures dV = J at V=0 /JE J tauSyn div fudge mul def /JI g JE mul neg def % inhibitory % threshold rate /nu_thresh theta J CE mul tauMem mul div def /nu_ext eta nu_thresh mul def % external rate per synapse /p_rate nu_ext Cext mul 1000. mul def % external input rate per neuron % must be given in Hz % number of neurons per population to record from /Nrec 50 def [0] << /resolution dt /overwrite_files true /print_time true >> SetStatus /sli_neuron GetDefaults begin /h 0.1 def /C_m 1.0 def /E_L 0.0 def /I_e 0.0 def /tau_minus 20.0 def /tau_m tauMem def /tau_syn tauSyn def /t_ref tauRef def /E_L U0 def /V_th theta def /C_m 1.0 def % Yes, capacitance is 1 in the Brunel model /t_spike -1.0 def /V_m U0 def /V_reset U0 def /V_th U0 theta add def /theta theta def /currents 0.0 def /y0 0.0 def /y1 0.0 def /y2 0.0 def /y3 0.0 def /r 0 def /update_template { r 0 eq { update_y3 /y3 Set } { r 1 sub /r Set } ifelse update_y2 /y2 Set y1 P11 mul /y1 Set y1 PSCInitialValue ex_spikes in_spikes add mul add /y1 Set y3 theta geq % voltage larger threshold? dup /spike Set % the return value { t_ref_steps /r Set V_reset /y3 Set % Reset the potential } if y3 E_L add /V_m Set currents /y0 Set } def /calibrate { GetResolution /h Set } /compile { (V_th - E_L) ExecMath /theta Set << >> /consts Set consts begin (exp(-h/tau_syn)) ExecMath /P11 Set (exp(-h/tau_m)) ExecMath /P33 Set (P11 * h) ExecMath /P21 Set ((1.0 - P33)*tau_m/C_m) ExecMath /P30 Set (1/ C_m * ((P11-P33)/(-1/tau_syn + 1/tau_m)- h*P11)/(-1/tau_m+1/tau_syn)) ExecMath /P31 Set (1/C_m*(P33-P11)/(-1/tau_m + 1/tau_syn)) ExecMath /P32 Set (exp(1.0)/tau_syn) ExecMath /PSCInitialValue Set t_ref h div 0.5 add floor cvi /t_ref_steps Set (P30*(y0 + I_e) + P31 * y1 + P32 * y2 + P33 *y3) CompileMath consts Inline /update_y3 Set (P21* y1 + P11 * y2) CompileMath consts Inline /update_y2 Set end /update_template load consts Inline /update Set } def end /sli_neuron GetDefaults /compile call {/sli_neuron GetDefaults /y3 known} assert %%% CONSTRUCTION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % set resolution and total/local number of threads tic % start timer on construction % Setting neuron default parameters (Configuring neuron parameters.) = (Creating the network.) = % show message /sli_neuron [NE] LayoutNetwork /E_net Set /sli_neuron [NI] LayoutNetwork /I_net Set % some connecting functions need lists (arrays) over all % neurons they should work on, so we need to extract these % lists from the subnetworks % obtain array with GIDs of all excitatory/inhibitory neurons /E_neurons E_net GetNodes def /I_neurons I_net GetNodes def % list of all neurons /allNeurons E_neurons I_neurons join def (Creating Poisson generators.) = /poisson_generator << % set firing rate /rate p_rate >> SetDefaults /expoisson /poisson_generator Create def /inpoisson /poisson_generator Create def % one detector would in principle be enough, % but by recording the populations separately, % we save us a lot of sorting work later (Creating excitatory spike detector.) = /exsd /spike_detector Create def exsd << /label (brunel-1-ex) /withtime true % record time of spikes /withgid true % record which neuron spiked /to_file true % write results to a file /to_memory false >> SetStatus (Creating inhibitory spike detector.) = /insd /spike_detector Create def insd << /label (brunel-1-in) /withtime true /withgid true /to_file true /to_memory false >> SetStatus % Create custom synapse types with appropriate values for % our excitatory and inhibitory connections /static_synapse << /delay delay >> SetDefaults /static_synapse /syn_ex << /weight JE >> CopyModel /static_synapse /syn_in << /weight JI >> CopyModel (Connecting excitatory population.) = % Connect Poisson generator to neurons expoisson E_neurons /syn_ex DivergentConnect E_neurons { % E -> E connections % the following is a single call to RandomConvergentConnect E_neurons % source population [we pick from this] exch % target neuron CE % number of source neurons to pick /syn_ex % the synapse model RandomConvergentConnect } bind % bind improves efficiency forall E_neurons { I_neurons exch CI /syn_in RandomConvergentConnect } bind forall (Connecting inhibitory population.) = % ... as above, just written more compact inpoisson I_neurons /syn_ex DivergentConnect I_neurons { E_neurons exch CE /syn_ex RandomConvergentConnect } bind forall I_neurons { I_neurons exch CI /syn_in RandomConvergentConnect } bind forall % Spike detectors are connected to the first Nrec neurons in each % population. Since neurons are equal and connectivity is homogeneously % randomized, this is equivalent to picking Nrec neurons at random % from each population (Connecting spike detectors.) = E_neurons Nrec Take exsd ConvergentConnect % pick the first 500 neurons I_neurons Nrec Take insd ConvergentConnect toc /BuildCPUTime Set /syn_ex GetDefaults /num_connections get /n_ex_syn Set /syn_in GetDefaults /num_connections get /n_in_syn Set %%% SIMULATION SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % run, measure computer time with tic-toc tic simtime Simulate toc /SimCPUTime Set % write a little report (\nBrunel Network Simulation) = (Number of Neurons : ) =only N = (Number of Synapses: ) =only 0 GetStatus /num_connections get = ( Excitatory : ) =only n_ex_syn = ( Inhibitory : ) =only n_in_syn = (Excitatory rate : ) =only exsd ComputeRate =only ( Hz) = (Inhibitory rate : ) =only insd ComputeRate =only ( Hz) = (Building time : ) =only BuildCPUTime =only ( s) = (Simulation time : ) =only SimCPUTime =only ( s\n) =