2020#
2121
2222import numpy as np
23+ import pytest
2324from scipy .integrate import odeint
2425
2526import odetoolbox
2930
3031try :
3132 import matplotlib as mpl
32- mpl .use (' Agg' )
33+ mpl .use (" Agg" )
3334 import matplotlib .pyplot as plt
3435 INTEGRATION_TEST_DEBUG_PLOTS = True
3536except ImportError :
3940class TestDoubleExponential :
4041 r"""Test propagators generation for double exponential"""
4142
42- def test_double_exponential (self ):
43- r"""Test propagators generation for double exponential"""
43+ @pytest .mark .parametrize ("tau_1, tau_2" , [(10. , 2. ), (10. , 10. )])
44+ def test_double_exponential (self , tau_1 , tau_2 ):
45+ r"""Test propagators generation for double exponential
46+
47+ Test for a case where tau_1 != tau_2 and where tau_1 == tau_2; this tests handling of numerical singularities.
48+
49+ tau_1: decay time constant (ms)
50+ tau_2: rise time constant (ms)
51+ """
4452
4553 def time_to_max (tau_1 , tau_2 ):
4654 r"""
4755 Time of maximum.
4856 """
49- tmax = (np .log (tau_1 ) - np .log (tau_2 )) / (1. / tau_2 - 1. / tau_1 )
50- return tmax
57+ if tau_1 == tau_2 :
58+ return tau_1
59+
60+ return (np .log (tau_1 ) - np .log (tau_2 )) / (1. / tau_2 - 1. / tau_1 )
5161
5262 def unit_amplitude (tau_1 , tau_2 ):
5363 r"""
5464 Scaling factor ensuring that amplitude of solution is one.
5565 """
5666 tmax = time_to_max (tau_1 , tau_2 )
57- alpha = 1. / ( np . exp ( - tmax / tau_1 ) - np . exp ( - tmax / tau_2 ))
58- return alpha
67+
68+ return 1. / ( np . exp ( - tmax / tau_1 ) - np . exp ( - tmax / tau_2 ))
5969
6070 def flow (y , t , tau_1 , tau_2 , alpha , dt ):
6171 r"""
@@ -66,26 +76,27 @@ def flow(y, t, tau_1, tau_2, alpha, dt):
6676
6777 return np .array ([dy1dt , dy2dt ])
6878
79+ if tau_1 == tau_2 :
80+ alpha = 1.
81+ else :
82+ alpha = unit_amplitude (tau_1 = tau_1 , tau_2 = tau_2 )
83+
6984 indict = {"dynamics" : [{"expression" : "I_aux' = -I_aux / tau_1" ,
7085 "initial_values" : {"I_aux" : "0." }},
7186 {"expression" : "I' = I_aux - I / tau_2" ,
7287 "initial_values" : {"I" : "0" }}],
7388 "options" : {"output_timestep_symbol" : "__h" },
74- "parameters" : {"tau_1" : "10" ,
75- "tau_2" : "2" ,
89+ "parameters" : {"tau_1" : str ( tau_1 ) ,
90+ "tau_2" : str ( tau_2 ) ,
7691 "w" : "3.14" ,
77- "alpha" : str (unit_amplitude ( tau_1 = 10. , tau_2 = 2. ) ),
92+ "alpha" : str (alpha ),
7893 "weighted_input_spikes" : "0." }}
7994
8095 w = 3.14 # weight (amplitude; pA)
81- tau_1 = 10. # decay time constant (ms)
82- tau_2 = 2. # rise time constant (ms)
8396 dt = .125 # time resolution (ms)
8497 T = 500. # simulation time (ms)
8598 input_spike_times = np .array ([100. , 300. ]) # array of input spike times (ms)
8699
87- alpha = unit_amplitude (tau_1 , tau_2 )
88-
89100 stimuli = [{"type" : "list" ,
90101 "list" : " " .join ([str (el ) for el in input_spike_times ]),
91102 "variables" : ["I_aux" ]}]
@@ -103,7 +114,7 @@ def flow(y, t, tau_1, tau_2, alpha, dt):
103114 N = int (np .ceil (T / dt ) + 1 )
104115 timevec = np .linspace (0. , T , N )
105116 analytic_integrator = AnalyticIntegrator (solver_dict , spike_times )
106- analytic_integrator .shape_starting_values ["I_aux" ] = w * alpha * ( 1. / tau_2 - 1. / tau_1 )
117+ analytic_integrator .shape_starting_values ["I_aux" ] = w * alpha
107118 analytic_integrator .set_initial_values (ODE_INITIAL_VALUES )
108119 analytic_integrator .reset ()
109120 state = {"timevec" : [], "I" : [], "I_aux" : []}
@@ -119,24 +130,24 @@ def flow(y, t, tau_1, tau_2, alpha, dt):
119130 ts2 = np .arange (input_spike_times [1 ], T + dt , dt )
120131
121132 y_ = odeint (flow , [0. , 0. ], ts0 , args = (tau_1 , tau_2 , alpha , dt ))
122- y_ = np .vstack ([y_ , odeint (flow , [y_ [- 1 , 0 ] + w * alpha * ( 1. / tau_2 - 1. / tau_1 ) , y_ [- 1 , 1 ]], ts1 , args = (tau_1 , tau_2 , alpha , dt ))])
123- y_ = np .vstack ([y_ , odeint (flow , [y_ [- 1 , 0 ] + w * alpha * ( 1. / tau_2 - 1. / tau_1 ) , y_ [- 1 , 1 ]], ts2 , args = (tau_1 , tau_2 , alpha , dt ))])
133+ y_ = np .vstack ([y_ , odeint (flow , [y_ [- 1 , 0 ] + w * alpha , y_ [- 1 , 1 ]], ts1 , args = (tau_1 , tau_2 , alpha , dt ))])
134+ y_ = np .vstack ([y_ , odeint (flow , [y_ [- 1 , 0 ] + w * alpha , y_ [- 1 , 1 ]], ts2 , args = (tau_1 , tau_2 , alpha , dt ))])
124135
125- rec_I_interp = np .interp (np .hstack ([ts0 , ts1 , ts2 ]), timevec , state ['I' ])
126- rec_I_aux_interp = np .interp (np .hstack ([ts0 , ts1 , ts2 ]), timevec , state [' I_aux' ])
136+ rec_I_interp = np .interp (np .hstack ([ts0 , ts1 , ts2 ]), timevec , state ["I" ])
137+ rec_I_aux_interp = np .interp (np .hstack ([ts0 , ts1 , ts2 ]), timevec , state [" I_aux" ])
127138
128139 if INTEGRATION_TEST_DEBUG_PLOTS :
129140 tmax = time_to_max (tau_1 , tau_2 )
130- mpl .rcParams [' text.usetex' ] = True
141+ mpl .rcParams [" text.usetex" ] = True
131142
132143 fig , ax = plt .subplots (nrows = 2 , figsize = (5 , 4 ), dpi = 300 )
133- ax [0 ].plot (timevec , state [' I_aux' ], '--' , lw = 3 , color = 'k' , label = r' $I_\mathsf{aux}(t)$ (NEST)' )
134- ax [0 ].plot (timevec , state ['I' ], '-' , lw = 3 , color = 'k' , label = r' $I(t)$ (NEST)' )
135- ax [0 ].plot (np .hstack ([ts0 , ts1 , ts2 ]), y_ [:, 0 ], '--' , lw = 2 , color = 'r' , label = r' $I_\mathsf{aux}(t)$ (odeint)' )
136- ax [0 ].plot (np .hstack ([ts0 , ts1 , ts2 ]), y_ [:, 1 ], '-' , lw = 2 , color = 'r' , label = r' $I(t)$ (odeint)' )
144+ ax [0 ].plot (timevec , state [" I_aux" ], "--" , lw = 3 , color = "k" , label = r" $I_\mathsf{aux}(t)$ (ODEtb)" )
145+ ax [0 ].plot (timevec , state ["I" ], "-" , lw = 3 , color = "k" , label = r" $I(t)$ (ODEtb)" )
146+ ax [0 ].plot (np .hstack ([ts0 , ts1 , ts2 ]), y_ [:, 0 ], "--" , lw = 2 , color = "r" , label = r" $I_\mathsf{aux}(t)$ (odeint)" )
147+ ax [0 ].plot (np .hstack ([ts0 , ts1 , ts2 ]), y_ [:, 1 ], "-" , lw = 2 , color = "r" , label = r" $I(t)$ (odeint)" )
137148
138149 for tin in input_spike_times :
139- ax [0 ].vlines (tin + tmax , ax [0 ].get_ylim ()[0 ], ax [0 ].get_ylim ()[1 ], colors = 'k' , linestyles = ':' )
150+ ax [0 ].vlines (tin + tmax , ax [0 ].get_ylim ()[0 ], ax [0 ].get_ylim ()[1 ], colors = "k" , linestyles = ":" )
140151
141152 ax [1 ].semilogy (np .hstack ([ts0 , ts1 , ts2 ]), np .abs (y_ [:, 1 ] - rec_I_interp ), label = "I" )
142153 ax [1 ].semilogy (np .hstack ([ts0 , ts1 , ts2 ]), np .abs (y_ [:, 0 ] - rec_I_aux_interp ), linestyle = "--" , label = "I_aux" )
@@ -146,9 +157,9 @@ def flow(y, t, tau_1, tau_2, alpha, dt):
146157 _ax .set_xlim (0. , T + dt )
147158 _ax .legend ()
148159
149- ax [- 1 ].set_xlabel (r' time (ms)' )
160+ ax [- 1 ].set_xlabel (r" time (ms)" )
150161
151- fig .savefig ('double_exp_test .png' )
162+ fig .savefig ("double_exp_test_[tau_1=" + str ( tau_1 ) + "]_[tau_2=" + str ( tau_2 ) + "] .png" )
152163
153164 np .testing .assert_allclose (y_ [:, 1 ], rec_I_interp , atol = 1E-7 )
154165
0 commit comments