def pulse_ode_call(model_function, ic, t_max, parameter_name, value): """Handle the decision making for how to call odeint when parameter is v_clamp or not. Swaps model_function for voltage_clap when clamping and passes the model function in arguments :param model_function: Either function to pulse or function to clamp and clamp is pulsed :param ic: Initial conditions :param t_max: Simulation end_time :param parameter_name: Name of parameter or flag to v_clamp :param value: Value of parameter or clamp potential :return: ODE solution """ # v_clamp the ic, set voltage_clamp to be solved and pass the model function in args if parameter_name is "v_clamp": ic[0] = value ode_function = voltage_clamp add_param = (model_function, ) kwargs = {} else: # Pass parameters as args and solve the specified function ode_function = model_function add_param = () kwargs = {parameter_name: value} t, sol = solve_ode( model=ode_function, ic=ic, t_max=t_max, additional_params=add_param, **kwargs, ) return sol
def steady_state_when_clamped(v_clamp): """Determine the steady-state of ode_3d when clamped to a voltage. :param v_clamp: Voltage to clamp to :return: Steady state of the neuron at v_clamp """ _, state = solve_ode(model=voltage_clamp, ic=[v_clamp, 1, 1], t_max=500, additional_params=(ode_3d, )) return state[-1, :]
def figure1d(title, panel=0, use_modified_tau_n=True): """Show waveforms for 5d (ix=0) or 3d (ix=1) models. :param title: Plot title (panel label) :param panel: Set the model to use 5d/3d (panel=0/1) :param use_modified_tau_n: Optional parameter to use the original tau_n which does not work. Defaults to our tau_n :return: None """ # Select appropriate model depending on the panel model = [ode_5d, ode_3d][panel] # Run the simulation for 4200ms and start at an arbitrary point "close" to the limit cycle initial_condition = [-55 * ureg.mV, 0, 0] initial_condition = resize_initial_condition(initial_condition, model, fill=0) # Solve 5d model with appropriate tau_n if model == ode_5d: model = partial(ode_5d, use_modified_tau_n=use_modified_tau_n) t, sol = solve_ode(model, initial_condition, t_max=4200 * ureg.ms, rtol=1e-3) # Throw away the first 1000ms of the simulation t_throw_away = np.where(t > 1000)[0][0] sol = sol[t_throw_away:, :] t = t[t_throw_away:] - t[t_throw_away] # set new t[0]=0 # Plot voltage trace plt.plot(t, sol[:, 0], "k") y_label = "V (mV)" if panel == 0 else "" y_tick_label = None if panel == 0 else [] # Plot properties set_properties( title, x_label="Time (ms)", y_label=y_label, y_tick=[-80, -40, 0], y_limits=[-80, 20], y_ticklabel=y_tick_label, x_tick=[0, 1000, 2000, 3000], x_limits=[0, 3000], )
def figure_1c(title, use_modified_tau_n=True): """Compute limit cycle in n,h phase space for the 5d model and compute the approximation n=f(h) for 1C. :param title: Plot title (panel label) :param use_modified_tau_n: Optional parameter to use the original tau_n which does not work. Defaults to our tau_n :return: None """ initial_condition = [ -55 * ureg.mV, 0, 0, 0, 0, ] # Does not need to lie on limit cycle since we throw away transient # Solve 5d model with appropriate tau_n partial_5d = partial(ode_5d, use_modified_tau_n=use_modified_tau_n) t, sol = solve_ode(partial_5d, initial_condition, t_max=4200 * ureg.ms, rtol=1e-3) # Extract h and n and discard the first half due to transient ix_half_time = int(len(t) / 2) h = sol[ix_half_time:, 1] n = sol[ix_half_time:, 4] fit_f_approx(h, n) # Plot limit cycle in phase plane plt.plot(h, n, c="grey") plt.plot(h, f_approx(h), "k") # Plot properties plt.legend(["n", "n=f(h)"], loc="center left", bbox_to_anchor=(0.3, 1.05)) set_properties( title, x_label="h", y_label="n", x_tick=[0, 0.2, 0.4, 0.6], y_tick=np.arange(0, 1, 0.2), x_limits=[0, 0.7], )
def figure3c(title): """Perform bifurcation analysis of 3D system for 3C. :param title: Plot title (panel label) :return: None """ # Compute contunuation and plot bifurcation diagram figure3c_continuation() ic = [-60 * ureg.mV, 0, 1] # solve system and overlay hs,v trajectory - zorder plotting behind bifuraction diagram t, sol = solve_ode(model=ode_3d, ic=ic, t_max=10000, i_app=0.16) plt.plot(sol[:, 2], sol[:, 0], c="grey", zorder=-1e5, linewidth=0.5) set_properties( title, y_label="V (mV)", x_limits=[0, 1], x_tick=[0, 0.5, 1], y_tick=[-80, -40, 0, 40], x_label="hs", )
def current_voltage_curve(model, clamp_range, t_max, ic, follow=False, **kwargs): """Compute IV curve in either follow mode or peak mode. In follow mode a traditional IV curve is computed where the I(V) is the steady state current at a clamped voltage for efficiency the initial condition of the next voltage level is the steady state of the present clamp. In peak mode (follow = False) the voltage is held at some reset voltage. The voltage is the clamped at the voltage for the IV curve and the peak (transient) current is used :param model: The function to call for voltage_clamp (the model used) :param clamp_range: Upper and lower range of voltage to clamp during the IV curve :param t_max: Time to run clamp for to equilibrate :param ic: Initial condition or reset condition :param follow: Optional flag is follow model or peak mode is used: defaults to peak mode, follow=False :param kwargs: Optional settings for the parameters such as g_na or i_leak :return: I(V) """ # Initialize IV curve parameters = default_parameters(**kwargs) voltage = np.arange(*map(strip_dimension, clamp_range)) current = np.zeros(voltage.shape) state = np.array([list(map(strip_dimension, ic)) ]) # inital state is ic; array([ic]) gives a 2d array # Update model inital state according to IV curve type, run voltage clamp and save I(V) for ix, v in enumerate(voltage): ic = update_ic(v, ic, state, follow) _, state = solve_ode(model=voltage_clamp, ic=ic, t_max=t_max, additional_params=(model, )) current[ix] = compute_iv_current(state, parameters, follow) return current, voltage