def test_function_dependencies_numpy(): if prefs.codegen.target != 'numpy': pytest.skip('numpy-only test') @implementation('cpp', ''' float foo(float x) { return 42*0.001; }''') @check_units(x=volt, result=volt) def foo(x): return 42 * mV # Second function with an independent implementation for C++ and an # implementation for numpy that makes use of the previous function. # Note that we don't need to use the explicit dependencies mechanism for # numpy, since the Python function stores a reference to the referenced # function directly @implementation('cpp', ''' float bar(float x) { return 84*0.001; }''') @check_units(x=volt, result=volt) def bar(x): return 2 * foo(x) G = NeuronGroup(5, 'v : volt') G.run_regularly('v = bar(v)') net = Network(G) net.run(defaultclock.dt) assert_allclose(G.v_[:], 84 * 0.001)
def test_math_functions(func, needs_c99_support): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. ''' if not get_device() == RuntimeDevice or prefs.codegen.target != 'numpy': if needs_c99_support and not compiler_supports_c99(): pytest.skip('Support for function "{}" needs a compiler with C99 ' 'support.') test_array = np.array([-1, -0.5, 0, 0.5, 1]) with catch_logs() as _: # Let's suppress warnings about illegal values # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup( len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(defaultclock.dt) assert_allclose( numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_timedarray_with_units(): ta = TimedArray(np.arange(10) * amp, dt=0.1 * ms) G = NeuronGroup(1, 'value = ta(t) + 2*nA: amp', dt=0.1 * ms) mon = StateMonitor(G, 'value', record=True, dt=0.1 * ms) run(1.1 * ms) assert_allclose(mon[0].value, np.clip(np.arange(len(mon[0].t)), 0, 9) * amp + 2 * nA)
def test_state_monitor_indexing(): # Check indexing semantics G = NeuronGroup(10, 'v:volt') G.v = np.arange(10) * volt mon = StateMonitor(G, 'v', record=[5, 6, 7]) run(2 * defaultclock.dt) assert_array_equal(mon.v, np.array([[5, 5], [6, 6], [7, 7]]) * volt) assert_array_equal(mon.v_, np.array([[5, 5], [6, 6], [7, 7]])) assert_array_equal(mon[5].v, mon.v[0]) assert_array_equal(mon[7].v, mon.v[2]) assert_array_equal(mon[[5, 7]].v, mon.v[[0, 2]]) assert_array_equal(mon[np.array([5, 7])].v, mon.v[[0, 2]]) assert_allclose(mon.t[1:], Quantity([defaultclock.dt])) with pytest.raises(IndexError): mon[8] with pytest.raises(TypeError): mon['string'] with pytest.raises(TypeError): mon[5.0] with pytest.raises(TypeError): mon[[5.0, 6.0]]
def test_function_dependencies_cython_rename(): if prefs.codegen.target != 'cython': pytest.skip('cython-only test') @implementation('cython', ''' cdef float _foo(float x): return 42*0.001 ''', name='_foo') @check_units(x=volt, result=volt) def foo(x): return 42 * mV # Second function with an independent implementation for numpy and an # implementation for C++ that makes use of the previous function. @implementation('cython', ''' cdef float bar(float x): return 2*my_foo(x) ''', dependencies={'my_foo': foo}) @check_units(x=volt, result=volt) def bar(x): return 84 * mV G = NeuronGroup(5, 'v : volt') G.run_regularly('v = bar(v)') net = Network(G) net.run(defaultclock.dt) assert_allclose(G.v_[:], 84 * 0.001)
def test_refractoriness_repeated(): # Create a group that spikes whenever it can group = NeuronGroup(1, '', threshold='True', refractory=10*defaultclock.dt) spike_mon = SpikeMonitor(group) run(10000*defaultclock.dt) assert spike_mon.t[0] == 0*ms assert_allclose(np.diff(spike_mon.t), 10*defaultclock.dt)
def test_rate_monitor_2(): G = NeuronGroup(10, 'v : 1', threshold='v>1') # no reset G.v['i<5'] = 1.1 # Half of the neurons fire every time step rate_mon = PopulationRateMonitor(G) net = Network(G, rate_mon) net.run(10*defaultclock.dt) assert_allclose(rate_mon.rate, 0.5 * np.ones(10) / defaultclock.dt) assert_allclose(rate_mon.rate_, 0.5 *np.asarray(np.ones(10) / defaultclock.dt_))
def test_timedarray_no_upsampling(): # Test a TimedArray where no upsampling is necessary because the monitor's # dt is bigger than the TimedArray's ta = TimedArray(np.arange(10), dt=0.01 * ms) G = NeuronGroup(1, 'value = ta(t): 1', dt=0.1 * ms) mon = StateMonitor(G, 'value', record=True, dt=1 * ms) run(2.1 * ms) assert_allclose(mon[0].value, [0, 9, 9])
def test_timedarray_semantics(): # Make sure that timed arrays are interpreted as specifying the values # between t and t+dt (not between t-dt/2 and t+dt/2 as in angela1) ta = TimedArray(array([0, 1]), dt=0.4 * ms) G = NeuronGroup(1, 'value = ta(t) : 1', dt=0.1 * ms) mon = StateMonitor(G, 'value', record=0) run(0.8 * ms) assert_allclose(mon[0].value, [0, 0, 0, 0, 1, 1, 1, 1]) assert_allclose(mon[0].value, ta(mon.t))
def test_refractoriness_threshold_basic(): G = NeuronGroup(1, ''' dv/dt = 199.99*Hz : 1 ''', threshold='v > 1', reset='v=0', refractory=10*ms) # The neuron should spike after 5ms but then not spike for the next # 10ms. The state variable should continue to integrate so there should # be a spike after 15ms spike_mon = SpikeMonitor(G) run(16*ms) assert_allclose(spike_mon.t, [5, 15] * ms)
def test_constants_values(): ''' Make sure that symbolic constants use the correct values in code ''' G = NeuronGroup(3, 'v : 1') G.v[0] = 'pi' G.v[1] = 'e' G.v[2] = 'inf' run(0 * ms) assert_allclose(G.v[:], [np.pi, np.e, np.inf])
def test_pure_noise_deterministic(fake_randn_randn_fixture): sigma = 3 eqs = Equations('dx/dt = sigma*xi/sqrt(ms) : 1') dt = 0.1 * ms for method in ['euler', 'heun', 'milstein']: G = NeuronGroup(1, eqs, dt=dt, method=method) run(10 * dt) assert_allclose(G.x, sqrt(dt) * sigma * 0.5 / sqrt(1 * ms) * 10, err_msg='method %s did not give the expected result' % method)
def test_spikegenerator_restore(): # Check whether SpikeGeneratorGroup works with store/restore # See github issue #1084 gen = SpikeGeneratorGroup(1, [0, 0, 0], [0, 1, 2]*ms) mon = SpikeMonitor(gen) store() run(3*ms) assert_array_equal(mon.i, [0, 0, 0]) assert_allclose(mon.t, [0, 1, 2] * ms) restore() run(3 * ms) assert_array_equal(mon.i, [0, 0, 0]) assert_allclose(mon.t, [0, 1, 2]*ms)
def test_active_flag(): G = NeuronGroup(1, 'dv/dt = 1/ms : 1') mon = StateMonitor(G, 'v', record=0) mon.active = False run(1 * ms) mon.active = True G.active = False run(1 * ms) device.build(direct_call=False, **device.build_options) # Monitor should start recording at 1ms # Neurongroup should not integrate after 1ms (but should have integrated before) assert_allclose(mon[0].t[0], 1 * ms) assert_allclose(mon[0].v, 1.0)
def test_spikegenerator_period(): ''' Basic test for `SpikeGeneratorGroup`. ''' indices = np.array([3, 2, 1, 1, 2, 3, 3, 2, 1]) times = np.array([1, 4, 4, 3, 2, 4, 2, 3, 2]) * ms SG = SpikeGeneratorGroup(5, indices, times, period=5*ms) s_mon = SpikeMonitor(SG) run(10*ms) for idx in range(5): generator_spikes = sorted([(idx, time) for time in times[indices==idx]] + [(idx, time+5*ms) for time in times[indices==idx]]) recorded_spikes = sorted([(idx, time) for time in s_mon.t[s_mon.i==idx]]) assert_allclose(generator_spikes, recorded_spikes)
def test_spikegenerator_extreme_period(): ''' Basic test for `SpikeGeneratorGroup`. ''' indices = np.array([0, 1, 2]) times = np.array([0, 1, 2]) * ms SG = SpikeGeneratorGroup(5, indices, times, period=1e6*second) s_mon = SpikeMonitor(SG) with catch_logs() as l: run(10*ms) assert_equal(s_mon.i, np.array([0, 1, 2])) assert_allclose(s_mon.t, [0, 1, 2]*ms) assert len(l) == 1 and l[0][1].endswith('spikegenerator_long_period')
def test_spatialneuron_capacitive_currents(): if prefs.core.default_float_dtype is np.float32: pytest.skip('Need double precision for this test') defaultclock.dt = 0.1 * ms morpho = Cylinder(x=[0, 10] * cm, diameter=2 * 238 * um, n=200, type='axon') El = 10.613 * mV ENa = 115 * mV EK = -12 * mV gl = 0.3 * msiemens / cm**2 gNa0 = 120 * msiemens / cm**2 gK = 36 * msiemens / cm**2 # Typical equations eqs = ''' # The same equations for the whole neuron, but possibly different parameter values # distributed transmembrane current Im = gl * (El-v) + gNa * m**3 * h * (ENa-v) + gK * n**4 * (EK-v) : amp/meter**2 I : amp (point current) # applied current dm/dt = alpham * (1-m) - betam * m : 1 dn/dt = alphan * (1-n) - betan * n : 1 dh/dt = alphah * (1-h) - betah * h : 1 alpham = (0.1/mV) * (-v+25*mV) / (exp((-v+25*mV) / (10*mV)) - 1)/ms : Hz betam = 4 * exp(-v/(18*mV))/ms : Hz alphah = 0.07 * exp(-v/(20*mV))/ms : Hz betah = 1/(exp((-v+30*mV) / (10*mV)) + 1)/ms : Hz alphan = (0.01/mV) * (-v+10*mV) / (exp((-v+10*mV) / (10*mV)) - 1)/ms : Hz betan = 0.125*exp(-v/(80*mV))/ms : Hz gNa : siemens/meter**2 ''' neuron = SpatialNeuron(morphology=morpho, model=eqs, Cm=1 * uF / cm**2, Ri=35.4 * ohm * cm, method="exponential_euler") mon = StateMonitor(neuron, ['Im', 'Ic'], record=True, when='end') run(10 * ms) neuron.I[0] = 1 * uA # current injection at one end run(3 * ms) neuron.I = 0 * amp run(10 * ms) device.build(direct_call=False, **device.build_options) assert_allclose((mon.Im - mon.Ic).sum(axis=0) / (mA / cm**2), np.zeros(230), atol=1e6)
def test_state_variables_string_indices(): ''' Test accessing subgroups with string indices. ''' G = NeuronGroup(10, 'v : volt') SG = G[4:9] assert len(SG.v['i>3']) == 1 G.v = np.arange(10) * mV assert len(SG.v['v>7.5*mV']) == 1 # Combined string indexing and assignment SG.v['i > 3'] = 'i*10*mV' assert_allclose(G.v[:], [0, 1, 2, 3, 4, 5, 6, 7, 40, 9] * mV)
def test_long_timedarray(): ''' Use a very long timedarray (with a big dt), where the upsampling can lead to integer overflow. ''' ta = TimedArray(np.arange(16385), dt=1 * second) G = NeuronGroup(1, 'value = ta(t) : 1') mon = StateMonitor(G, 'value', record=True) net = Network(G, mon) # We'll start the simulation close to the critical boundary # FIXME: setting the time like this does not work for standalone net.t_ = float(16384 * second - 5 * ms) net.run(10 * ms) assert_allclose(mon[0].value[mon.t < 16384 * second], 16383) assert_allclose(mon[0].value[mon.t >= 16384 * second], 16384)
def test_state_monitor_record_single_timestep(): G = NeuronGroup(1, 'dv/dt = -v/(5*ms) : 1') G.v = 1 mon = StateMonitor(G, 'v', record=True) # Recording before a run should not work with pytest.raises(TypeError): mon.record_single_timestep() run(0.5*ms) mon.record_single_timestep() device.build(direct_call=False, **device.build_options) assert mon.t[0] == 0*ms assert mon[0].v[0] == 1 assert_allclose(mon.t[-1], 0.5*ms) assert len(mon.t) == 6 assert mon[0].v[-1] == G.v
def test_poissoninput_refractory(): eqs = ''' dv/dt = 0/second : 1 (unless refractory) ''' G = NeuronGroup(10, eqs, reset='v=0', threshold='v>4.5', refractory=5 * defaultclock.dt) # Will increase the value by 1.0 at each time step P = PoissonInput(G, 'v', 1, 1 / defaultclock.dt, weight=1.0) mon = StateMonitor(G, 'v', record=5) run(10 * defaultclock.dt) expected = np.arange(10, dtype=np.float) expected[6 - int(schedule_propagation_offset() / defaultclock.dt):] = 0 assert_allclose(mon[5].v[:], expected)
def test_refractoriness_repeated_legacy(): if prefs.core.default_float_dtype == np.float32: pytest.skip('Not testing legacy refractory mechanism with single ' 'precision floats.') # Switch on behaviour from versions <= 2.1.2 prefs.legacy.refractory_timing = True # Create a group that spikes whenever it can group = NeuronGroup(1, '', threshold='True', refractory=10*defaultclock.dt) spike_mon = SpikeMonitor(group) run(10000*defaultclock.dt) assert spike_mon.t[0] == 0*ms # Empirical values from running with earlier angela versions assert_allclose(np.diff(spike_mon.t)[:10], [1.1, 1, 1.1, 1, 1.1, 1.1, 1.1, 1.1, 1, 1.1]*ms) steps = Counter(np.diff(np.int_(np.round(spike_mon.t / defaultclock.dt)))) assert len(steps) == 2 and steps[10] == 899 and steps[11] == 91 prefs.legacy.refractory_timing = False
def test_timedarray_direct_use(): ta = TimedArray(np.linspace(0, 10, 11), 1 * ms) assert ta(-1 * ms) == 0 assert ta(5 * ms) == 5 assert ta(10 * ms) == 10 assert ta(15 * ms) == 10 ta = TimedArray(np.linspace(0, 10, 11) * amp, 1 * ms) assert ta(-1 * ms) == 0 * amp assert ta(5 * ms) == 5 * amp assert ta(10 * ms) == 10 * amp assert ta(15 * ms) == 10 * amp ta2d = TimedArray((np.linspace(0, 11, 12) * amp).reshape(4, 3), 1 * ms) assert ta2d(-1 * ms, 0) == 0 * amp assert ta2d(0 * ms, 0) == 0 * amp assert ta2d(0 * ms, 1) == 1 * amp assert ta2d(1 * ms, 1) == 4 * amp assert_allclose(ta2d(1 * ms, [0, 1, 2]), [3, 4, 5] * amp) assert_allclose(ta2d(15 * ms, [0, 1, 2]), [9, 10, 11] * amp)
def test_refractory_stochastic(fake_randn_randn_fixture): eqs_base = 'dv/dt = -v/(10*ms) + second**-.5*xi : 1' for method in ['euler', 'heun', 'milstein']: G_no_ref = NeuronGroup(10, eqs_base, method=method) G_no_ref.v = '(i+1)/11.' G_ref = NeuronGroup(10, eqs_base + ' (unless refractory)', refractory=1 * ms, method=method) G_ref.v = '(i+1)/11.' net = Network(G_ref, G_no_ref) net.run(10 * ms) assert_allclose(G_no_ref.v[:], G_ref.v[:], err_msg=('Results with and without refractoriness ' 'differ for method %s.') % method)
def test_synapses_state_monitor(): G = NeuronGroup(2, '') S = Synapses(G, G, 'w: siemens') S.connect(True) S.w = 'j*nS' # record from a Synapses object (all synapses connecting to neuron 1) synapse_mon = StateMonitor(S, 'w', record=S[:, 1]) synapse_mon2 = StateMonitor(S, 'w', record=S['j==1']) net = Network(G, S, synapse_mon, synapse_mon2) net.run(10*ms) # Synaptic variables assert_allclose(synapse_mon[S[0, 1]].w, 1*nS) assert_allclose(synapse_mon.w[1], 1*nS) assert_allclose(synapse_mon2[S[0, 1]].w, 1*nS) assert_allclose(synapse_mon2[S['i==0 and j==1']].w, 1*nS) assert_allclose(synapse_mon2.w[1], 1*nS)
def test_rate_monitor_subgroups_2(): G = NeuronGroup(6, '''do_spike : boolean''', threshold='do_spike') G.do_spike = [True, False, False, False, True, True] rate_all = PopulationRateMonitor(G) rate_1 = PopulationRateMonitor(G[:2]) rate_2 = PopulationRateMonitor(G[2:4]) rate_3 = PopulationRateMonitor(G[4:]) run(2*defaultclock.dt) assert_allclose(rate_all.rate, 0.5 / defaultclock.dt) assert_allclose(rate_1.rate, 0.5 / defaultclock.dt) assert_allclose(rate_2.rate, 0*Hz) assert_allclose(rate_3.rate, 1 / defaultclock.dt)
def test_custom_events(): # Set (could be moved in a setup) EL = -65 * mV gL = 0.0003 * siemens / cm**2 ev = ''' Im = gL * (EL - v) : amp/meter**2 event_time1 : second ''' # Create a three compartments morphology morpho = Soma(diameter=10 * um) morpho.dend1 = Cylinder(n=1, diameter=1 * um, length=10 * um) morpho.dend2 = Cylinder(n=1, diameter=1 * um, length=10 * um) G = SpatialNeuron(morphology=morpho, model=ev, events={'event1': 't>=i*ms and t<i*ms+dt'}) G.run_on_event('event1', 'event_time1 = 0.1*ms') run(0.2 * ms) # Event has size three now because there are three compartments assert_allclose(G.event_time1[:], [0.1, 0, 0] * ms)
def test_refractoriness_threshold(ref_time): # Try a quantity, a string evaluating to a quantity, and an explicit boolean # condition -- all should do the same thing G = NeuronGroup(1, ''' dv/dt = 199.999*Hz : 1 ref : second ref_no_unit : 1 ''', threshold='v > 1', reset='v=0', refractory=ref_time, dtype={'ref': defaultclock.variables['t'].dtype, 'ref_no_unit': defaultclock.variables['t'].dtype}) G.ref = 10*ms G.ref_no_unit = 10 # The neuron should spike after 5ms but then not spike for the next # 10ms. The state variable should continue to integrate so there should # be a spike after 15ms spike_mon = SpikeMonitor(G) run(16*ms) assert_allclose(spike_mon.t, [5, 15] * ms)
def test_infinitecable(): ''' Test simulation of an infinite cable vs. theory for current pulse (Green function) ''' angelaLogger.suppress_name('resolution_conflict') defaultclock.dt = 0.001 * ms # Morphology diameter = 1 * um Cm = 1 * uF / cm**2 Ri = 100 * ohm * cm N = 500 morpho = Cylinder(diameter=diameter, length=3 * mm, n=N) # Passive channels gL = 1e-4 * siemens / cm**2 eqs = ''' Im=-gL*v : amp/meter**2 I : amp (point current) ''' neuron = SpatialNeuron(morphology=morpho, model=eqs, Cm=Cm, Ri=Ri) # Monitors mon = StateMonitor(neuron, 'v', record=N / 2 - 20) neuron.I[len(neuron) // 2] = 1 * nA # injecting in the middle run(0.02 * ms) neuron.I = 0 * amp run(3 * ms) t = mon.t v = mon[N // 2 - 20].v # Theory (incorrect near cable ends) x = 20 * morpho.length[0] la = neuron.space_constant[0] taum = Cm / gL # membrane time constant theory = 1./(la*Cm*pi*diameter)*sqrt(taum/(4*pi*(t+defaultclock.dt)))*\ exp(-(t+defaultclock.dt)/taum-taum/(4*(t+defaultclock.dt))*(x/la)**2) theory = theory * 1 * nA * 0.02 * ms assert_allclose( v[t > 0.5 * ms], theory[t > 0.5 * ms], atol=float(6.32 * uvolt) ) # high error tolerance (not exact because not infinite cable)
def test_multiple_noise_variables_extended(): # Some actual simulations with multiple noise variables eqs = '''dx/dt = y : 1 dy/dt = - 1*ms**-1*y - 40*ms**-2*x : Hz ''' all_eqs_noise = [ '''dx/dt = y : 1 dy/dt = noise_factor*ms**-1.5*xi_1 + noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz ''', '''dx/dt = y + noise_factor*ms**-0.5*xi_1: 1 dy/dt = noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz ''' ] G = NeuronGroup(2, eqs, method='euler') G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10 * ms) no_noise_x, no_noise_y = mon.x[:], mon.y[:] for eqs_noise in all_eqs_noise: for method_name, method in [('euler', euler), ('heun', heun)]: with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) # We run it deterministically, but still we'd detect major errors (e.g. # non-stochastic terms that are added twice, see #330 net.run(10 * ms, namespace={'noise_factor': 0}) assert_allclose(mon.x[:], no_noise_x, err_msg='Method %s gave incorrect results' % method_name) assert_allclose(mon.y[:], no_noise_y, err_msg='Method %s gave incorrect results' % method_name)