def _numba_dfun(S, c, ae, be, de, ge, te, wp, we, jn, ai, bi, di, gi, ti, wi, ji, g, l, io, dx): "Gufunc for reduced Wong-Wang model equations." cc = g[0] * jn[0] * c[0] if S[0] < 0.0: S_e = 0.0 # - S[0] # TODO: clarify the boundary to be reflective or saturated!!! elif S[0] > 1.0: S_e = 1.0 # - S[0] # TODO: clarify the boundary to be reflective or saturated!!! else: S_e = S[0] if S[1] < 0.0: S_i = 0.0 # - S[1] TODO: clarify the boundary to be reflective or saturated!!! elif S[1] > 1.0: S_i = 1.0 # - S[1] TODO: clarify the boundary to be reflective or saturated!!! else: S_i = S[1] jnSe = jn[0] * S_e x = wp[0] * jnSe - ji[0] * S_i + we[0] * io[0] + cc x = ae[0] * x - be[0] h = x / (1 - numpy.exp(-de[0] * x)) dx[0] = -(S_e / te[0]) + (1.0 - S_e) * h * ge[0] x = jnSe - S_i + wi[0] * io[0] + l[0] * cc x = ai[0] * x - bi[0] h = x / (1 - numpy.exp(-di[0] * x)) dx[1] = -(S_i / ti[0]) + h * gi[0]
def _numba_update_non_state_variables_before_integration( S, c, ae, be, de, wp, we, jn, re, ai, bi, di, wi, ji, ri, g, l, io, ie, newS): "Gufunc for reduced Wong-Wang model equations." newS[0] = S[0] # S_e newS[1] = S[1] # S_i cc = g[0] * jn[0] * c[0] jnSe = jn[0] * S[0] # S_i newS[6] = wp[0] * jnSe - ji[0] * S[1] + we[0] * io[0] + cc + ie[0] # I_e if re[0] <= 0.0: # TVB computation x = ae[0] * newS[6] - be[0] h = x / (1 - numpy.exp(-de[0] * x)) newS[2] = h # R_e newS[4] = 0.0 # Rin_e else: # Updating from spiking network newS[2] = S[2] # R_e newS[4] = S[4] # Rin_e # S_i newS[7] = jnSe - S[1] + wi[0] * io[0] + l[0] * cc # I_i if ri[0] <= 0.0: # TVB computation x = ai[0] * newS[7] - bi[0] h = x / (1 - numpy.exp(-di[0] * x)) newS[3] = h # R_i newS[5] = 0.0 # Rin_i else: newS[3] = S[3] # R_i newS[5] = S[5] # Rin_i
def update_non_state_variables(self, state_variables, coupling, local_coupling=0.0, use_numba=True): if use_numba: _numba_update_non_state_variables( state_variables.reshape(state_variables.shape[:-1]).T, coupling.reshape(coupling.shape[:-1]).T + local_coupling * state_variables[0], self.a_e, self.b_e, self.d_e, self.w_p, self.W_e, self.J_N, self.R_e, self.a_i, self.b_i, self.d_i, self.W_i, self.J_i, self.R_i, self.G, self.lamda, self.I_o) return state_variables # In this case, rates (H_e, H_i) are non-state variables, # i.e., they form part of state_variables but have no dynamics assigned on them # Most of the computations of this dfun aim at computing rates, including coupling considerations. # Therefore, we compute and update them only once a new state is computed, # and we consider them constant for any subsequent possible call to this function, # by any integration scheme S = state_variables[:2, :] # synaptic gating dynamics R = state_variables[2:, :] # rates c_0 = coupling[0, :] # if applicable lc_0 = local_coupling * S[0] coupling = self.G * self.J_N * (c_0 + lc_0) J_N_S_e = self.J_N * S[0] # TODO: Confirm that this computation is correct for this model depending on the r_e and r_i values! x_e = self.w_p * J_N_S_e - self.J_i * S[ 1] + self.W_e * self.I_o + coupling x_e = self.a_e * x_e - self.b_e # Only rates with r_e < 0 will be updated by TVB. H_e = numpy.where(self.R_e >= 0, R[0], x_e / (1 - numpy.exp(-self.d_e * x_e))) x_i = J_N_S_e - S[1] + self.W_i * self.I_o + self.lamda * coupling x_i = self.a_i * x_i - self.b_i # Only rates with r_i < 0 will be updated by TVB. H_i = numpy.where(self.R_i >= 0, R[1], x_i / (1 - numpy.exp(-self.d_i * x_i))) # We now update the state_variable vector with the new rates: state_variables[2, :] = H_e state_variables[3, :] = H_i return state_variables
def _numpy_dfun(self, state_variables, coupling, local_coupling=0.0): r""" Equations taken from [DPA_2013]_ , page 11242 .. math:: x_{ek} &= w_p\,J_N \, S_{ek} - J_iS_{ik} + W_eI_o + GJ_N \mathbf\Gamma(S_{ek}, S_{ej}, u_{kj}),\\ H(x_{ek}) &= \dfrac{a_ex_{ek}- b_e}{1 - \exp(-d_e(a_ex_{ek} -b_e))},\\ \dot{S}_{ek} &= -\dfrac{S_{ek}}{\tau_e} + (1 - S_{ek}) \, \gammaH(x_{ek}) \, x_{ik} &= J_N \, S_{ek} - S_{ik} + W_iI_o + \lambdaGJ_N \mathbf\Gamma(S_{ik}, S_{ej}, u_{kj}),\\ H(x_{ik}) &= \dfrac{a_ix_{ik} - b_i}{1 - \exp(-d_i(a_ix_{ik} -b_i))},\\ \dot{S}_{ik} &= -\dfrac{S_{ik}}{\tau_i} + \gamma_iH(x_{ik}) \, """ S = state_variables[:, :] S[S < 0] = 0.0 S[S > 1] = 1.0 c_0 = coupling[0, :] # if applicable lc_0 = local_coupling * S[0] coupling = self.G * self.J_N * (c_0 + lc_0) J_N_S_e = self.J_N * S[0] # TODO: Confirm that this combutation is correct for this model depending on the r_e and r_i values! x_e = self.w_p * J_N_S_e - self.J_i * S[ 1] + self.W_e * self.I_o + coupling x_e = self.a_e * x_e - self.b_e H_e = numpy.where(self.r_e >= 0, self.r_e, x_e / (1 - numpy.exp(-self.d_e * x_e))) dS_e = -(S[0] / self.tau_e) + (1 - S[0]) * H_e * self.gamma_e x_i = J_N_S_e - S[1] + self.W_i * self.I_o + self.lamda * coupling x_i = self.a_i * x_i - self.b_i H_i = numpy.where(self.r_i >= 0, self.r_i, x_i / (1 - numpy.exp(-self.d_i * x_i))) dS_i = -(S[1] / self.tau_i) + H_i * self.gamma_i derivative = numpy.array([dS_e, dS_i]) return derivative
def _numba_update_non_state_variables_before_integration( S, c, a, b, d, w, jn, r, g, io, newS): "Gufunc for reduced Wong-Wang model equations." newS[0] = S[0] # S newS[1] = S[1] # Rint cc = g[0] * jn[0] * c[0] newS[4] = w[0] * jn[0] * S[0] + io[0] + cc # I if r[0] <= 0.0: # R computed in TVB x = a[0] * newS[4] - b[0] h = x / (1 - numpy.exp(-d[0] * x)) newS[2] = h # R newS[3] = 0.0 # Rin else: # R updated from Spiking Network model # Rate has to be scaled down from the Spiking neural model rate range to the TVB one if S[1] < 40.0: # Rint # For low activity R = numpy.sqrt(S[1]) else: # For high activity R = 0.0000050 * g[0] * S[1]**2 newS[2] = R newS[3] = S[3] # Rin
def update_state_variables_before_integration(self, state_variables, coupling, local_coupling=0.0, stimulus=0.0): if self.use_numba: state_variables = \ _numba_update_non_state_variables(state_variables.reshape(state_variables.shape[:-1]).T, coupling.reshape(coupling.shape[:-1]).T + local_coupling * state_variables[0], self.a, self.b, self.d, self.w, self.J_N, self.Rin, self.G, self.I_o) return state_variables.T[..., numpy.newaxis] # In this case, rates (H_e, H_i) are non-state variables, # i.e., they form part of state_variables but have no dynamics assigned on them # Most of the computations of this dfun aim at computing rates, including coupling considerations. # Therefore, we compute and update them only once a new state is computed, # and we consider them constant for any subsequent possible call to this function, # by any integration scheme S = state_variables[0, :] # synaptic gating dynamics Rint = state_variables[1, :] # Rates from Spiking Network, integrated Rin = state_variables[3, :] # Input rates from Spiking Network c_0 = coupling[0, :] # if applicable lc_0 = local_coupling * S[0] coupling = self.G * self.J_N * (c_0 + lc_0) # Currents I = self.w * self.J_N * S + self.I_o + coupling x = self.a * I - self.b # Rates # Only rates with _Rin <= 0 0 will be updated by TVB. # The rest, are updated from the Spiking Network R = numpy.where(self._Rin, Rint, x / (1 - numpy.exp(-self.d * x))) Rin = numpy.where( self._Rin, Rin, 0.0) # Reset to 0 the Rin for nodes not updated by Spiking Network # We now update the state_variable vector with the new rates and currents: state_variables[2, :] = R state_variables[3, :] = Rin state_variables[4, :] = I # Keep them here so that they are not recomputed in the dfun self._R = numpy.copy(R) self._Rin = numpy.copy(Rin) return state_variables
def _numba_dfun(S, c, ae, be, de, ge, te, wp, we, jn, re, ai, bi, di, gi, ti, wi, ji, ri, g, l, io, dx): "Gufunc for reduced Wong-Wang model equations." cc = g[0] * jn[0] * c[0] if S[0] < 0.0: S_e = 0.0 elif S[0] > 1.0: S_e = 1.0 else: S_e = S[0] jnSe = jn[0] * S_e if S[1] < 0.0: S_i = 0.0 elif S[1] > 1.0: S_i = 1.0 else: S_i = S[1] if re[0] < 0.0: x = wp[0] * jnSe - ji[0] * S_i + we[0] * io[0] + cc x = ae[0] * x - be[0] h = x / (1 - numpy.exp(-de[0] * x)) else: h = re[0] dx[0] = -(S_e / te[0]) + (1.0 - S_e) * h * ge[0] if ri[0] < 0.0: x = jnSe - S_i + wi[0] * io[0] + l[0] * cc x = ai[0] * x - bi[0] h = x / (1 - numpy.exp(-di[0] * x)) else: h = ri[0] dx[1] = -(S_i / ti[0]) + h * gi[0]
def _numba_update_non_state_variables(S, c, ae, be, de, wp, we, jn, re, ai, bi, di, wi, ji, ri, g, l, io, newS): "Gufunc for reduced Wong-Wang model equations." cc = g[0] * jn[0] * c[0] jnSe = jn[0] * S[0] if re[0] < 0.0: x = wp[0] * jnSe - ji[0] * S[1] + we[0] * io[0] + cc x = ae[0] * x - be[0] h = x / (1 - numpy.exp(-de[0] * x)) S[2] = h if ri[0] < 0.0: x = jnSe - S[1] + wi[0] * io[0] + l[0] * cc x = ai[0] * x - bi[0] h = x / (1 - numpy.exp(-di[0] * x)) S[3] = h newS[0] = S[0] newS[1] = S[1] newS[3] = S[2] newS[4] = S[4]
def update_state_variables_before_integration(self, state_variables, coupling, local_coupling=0.0, stimulus=0.0, use_numba=False): for ii in range(state_variables[0].shape[0]): _E = self._E(ii) # excitatory neurons'/modes' indices _I = self._I(ii) # inhibitory neurons'/modes' indices # Make sure that all empty positions are set to 0.0, if any: self._zero_empty_positions(state_variables, _E, _I, ii) # Set inhibitory synapses for excitatory neurons & excitatory synapses for inhibitory neurons to 0.0... self._zero_cross_synapses(state_variables, _E, _I, ii) # compute large scale coupling_ij = sum(C_ij * S_e(t-t_ij)) large_scale_coupling = numpy.sum(coupling[0, ii, :self._N_E_max]) if ii in self._spiking_regions_inds: # -----------------------------------Updates after previous iteration:---------------------------------- # Refractory neurons from past spikes if 6. t_ref > 0.0 self._refractory_neurons_E[ii] = state_variables[6, ii, _E] > 0.0 self._refractory_neurons_I[ii] = state_variables[6, ii, _I] > 0.0 # set 5. V_m for refractory neurons to V_reset state_variables[5, ii, _E] = numpy.where( self._refractory_neurons_E[ii], self._x_E(self.V_reset, ii), state_variables[5, ii, _E]) state_variables[5, ii, _I] = numpy.where( self._refractory_neurons_I[ii], self._x_I(self.V_reset, ii), state_variables[5, ii, _I]) # Compute spikes sent at time t: # 8. spikes state_variables[8, ii, _E] = numpy.where( state_variables[5, ii, _E] > self._x_E(self.V_thr, ii), 1.0, 0.0) state_variables[8, ii, _I] = numpy.where( state_variables[5, ii, _I] > self._x_I(self.V_thr, ii), 1.0, 0.0) self._spikes_E[ii] = state_variables[8, ii, _E] > 0.0 self._spikes_I[ii] = state_variables[8, ii, _I] > 0.0 # set 5. V_m for spiking neurons to V_reset state_variables[5, ii, _E] = numpy.where(self._spikes_E[ii], self._x_E(self.V_reset, ii), state_variables[5, ii, _E]) state_variables[5, ii, _I] = numpy.where(self._spikes_I[ii], self._x_I(self.V_reset, ii), state_variables[5, ii, _I]) # set 6. t_ref to tau_ref for spiking neurons state_variables[6, ii, _E] = numpy.where( self._spikes_E[ii], self._x_E(self.tau_ref_E, ii), state_variables[6, ii, _E]) state_variables[6, ii, _I] = numpy.where( self._spikes_I[ii], self._x_I(self.tau_ref_I, ii), state_variables[6, ii, _I]) # Refractory neurons including current spikes sent at time t self._refractory_neurons_E[ii] = numpy.logical_or( self._refractory_neurons_E[ii], self._spikes_E[ii]) self._refractory_neurons_I[ii] = numpy.logical_or( self._refractory_neurons_I[ii], self._spikes_I[ii]) # 9. rate # Compute the average population rate sum_of_population_spikes / number_of_population_neurons # separately for excitatory and inhibitory populations, # and set it at the first position of each population, similarly to the mean-field region nodes state_variables[9, ii, _E] = 0.0 state_variables[9, ii, _I] = 0.0 state_variables[9, ii, 0] = numpy.sum( state_variables[8, ii, _E]) / self._n_E(ii) state_variables[9, ii, self._N_E_max] = numpy.sum( state_variables[8, ii, _I]) / self._n_I(ii) # -------------------------------------Updates before next iteration:--------------------------------------- # ----------------------------------First deal with inputs at time t:--------------------------------------- # Collect external spikes received at time t, and update the incoming s_AMPA_ext synapse: # 7. spikes_ext # get external spike stimulus 7. spike_ext, if any: state_variables[7, ii, _E] = self._x_E(self.spikes_ext, ii) state_variables[7, ii, _I] = self._x_I(self.spikes_ext, ii) # 4. s_AMPA_ext # ds_AMPA_ext/dt = -1/tau_AMPA * (s_AMPA_exc + spikes_ext) # Add the spike at this point to s_AMPA_ext state_variables[4, ii, _E] += state_variables[7, ii, _E] # spikes_ext state_variables[4, ii, _I] += state_variables[7, ii, _I] # spikes_ext # Compute currents based on synaptic gating variables at time t: # V_E_E = V_m - V_E V_E_E = state_variables[5, ii, _E] - self._x_E(self.V_E, ii) V_E_I = state_variables[5, ii, _I] - self._x_I(self.V_E, ii) # 10. I_syn = I_L + I_AMPA + I_NMDA + I_GABA + I_AMPA_EXT state_variables[10, ii, _E] = numpy.sum(state_variables[10:, ii, _E], axis=0) state_variables[10, ii, _I] = numpy.sum(state_variables[10:, ii, _I], axis=0) # 11. I_L = g_m * (V_m - V_E) state_variables[11, ii, _E] = \ self._x_E(self.g_m_E, ii) * (state_variables[5, ii, _E] - self._x_E(self.V_L, ii)) state_variables[11, ii, _I] = \ self._x_I(self.g_m_I, ii) * (state_variables[5, ii, _I] - self._x_I(self.V_L, ii)) w_EE = self._x_E(self.w_EE, ii) w_EI = self._x_E(self.w_EI, ii) # 12. I_AMPA = g_AMPA * (V_m - V_E) * sum(w * s_AMPA_k) coupling_AMPA_E, coupling_AMPA_I = \ self._compute_region_exc_population_coupling(state_variables[0, ii, _E], w_EE, w_EI) state_variables[12, ii, _E] = self._x_E( self.g_AMPA_E, ii) * V_E_E * coupling_AMPA_E # s_AMPA state_variables[12, ii, _I] = self._x_I( self.g_AMPA_I, ii) * V_E_I * coupling_AMPA_I # 13. I_NMDA = g_NMDA * (V_m - V_E) / (1 + lamda_NMDA * exp(-beta*V_m)) * sum(w * s_NMDA_k) coupling_NMDA_E, coupling_NMDA_I = \ self._compute_region_exc_population_coupling(state_variables[2, ii, _E], w_EE, w_EI) state_variables[13, ii, _E] = \ self._x_E(self.g_NMDA_E, ii) * V_E_E \ / (self._x_E(self.lamda_NMDA, ii) * numpy.exp(-self._x_E(self.beta, ii) * state_variables[5, ii, _E])) \ * coupling_NMDA_E # s_NMDA state_variables[13, ii, _I] = \ self._x_I(self.g_NMDA_I, ii) * V_E_I \ / (self._x_I(self.lamda_NMDA, ii) * numpy.exp(-self._x_I(self.beta, ii) * state_variables[5, ii, _I])) \ * coupling_NMDA_I # s_NMDA # 14. I_GABA = g_GABA * (V_m - V_I) * sum(w_ij * s_GABA_k) w_IE = self._x_I(self.w_IE, ii) w_II = self._x_I(self.w_II, ii) coupling_GABA_E, coupling_GABA_I = \ self._compute_region_inh_population_coupling(state_variables[3, ii, _I], w_IE, w_II) state_variables[14, ii, _E] = self._x_E(self.g_GABA_E, ii) * \ (state_variables[5, ii, _E] - self._x_E(self.V_I, ii)) * \ coupling_GABA_E # s_GABA state_variables[14, ii, _I] = self._x_I(self.g_GABA_I, ii) * \ (state_variables[5, ii, _I] - self._x_I(self.V_I, ii)) * \ coupling_GABA_I # s_GABA # 15. I_AMPA_ext = g_AMPA_ext * (V_m - V_E) * ( G*sum{c_ij sum{s_AMPA_j(t-delay_ij)}} + s_AMPA_ext) # Compute large scale coupling_ij = sum(c_ij * S_e(t-t_ij)) large_scale_coupling += numpy.sum(local_coupling * state_variables[0, ii, _E]) state_variables[15, ii, _E] = self._x_E(self.g_AMPA_ext_E, ii) * V_E_E * \ (self._x_E(self.G, ii) * large_scale_coupling + state_variables[4, ii, _E]) # # feedforward inhibition state_variables[15, ii, _I] = self._x_I(self.g_AMPA_ext_I, ii) * V_E_I * \ (self._x_I(self.G, ii) * self._x_I(self.lamda, ii) * large_scale_coupling + state_variables[4, ii, _I]) else: # For mean field modes: # Given that the 3rd dimension corresponds to neurons, not modes, # we use only the first element of its population, i.e., 0 and _I[0], # and consider all the rest to be identical # Similarly, we assume that all parameters are of of these shapes: # (1, ), (1, 1), (number_of_regions, ), (number_of_regions, 1) # S_e = s_AMPA = s_NMDA # S_i = s_GABA # 1. s_NMDA # = s_AMPA for excitatory mean field models state_variables[1, ii, _E] = state_variables[0, ii, 0] # 1. x_NMDA, 4. s_AMPA_ext, 5. V_m, 6. t_ref, 7. spikes_ext, 8. spikes, 11. I_L # are 0 for mean field models: state_variables[[1, 4, 5, 6, 7, 8, 11], ii] = 0.0 # J_N is indexed by the receiver node J_N_E = self._region(self.J_N, ii) J_N_I = self._region(self.J_N, ii) # 12. I_AMPA # = w+ * J_N * S_e state_variables[12, ii, _E] = self._region( self.w_p, ii) * J_N_E * state_variables[0, ii, 0] # = J_N * S_e state_variables[12, ii, _I] = J_N_I * state_variables[0, ii, 0] # 13. I_NMDA = I_AMPA for mean field models state_variables[13, ii] = state_variables[13, ii] # 14. I_GABA # 3. s_GABA state_variables[14, ii, _E] = -self._x_E( self.J_i, ii) * state_variables[3, ii, _I[0]] # = -J_i*S_i state_variables[14, ii, _I] = -state_variables[3, ii, _I[0]] # = - S_i # 15. I_AMPA_ext large_scale_coupling += local_coupling * state_variables[0, ii, 0] # = G * J_N * coupling_ij = G * J_N * sum(C_ij * S_e(t-t_ij)) state_variables[15, ii, _E] = self._x_E( self.G, ii)[0] * J_N_E * large_scale_coupling # = lamda * G * J_N * coupling_ij = lamda * G * J_N * sum(C_ij * S_e(t-t_ij)) state_variables[15, ii, _I] = \ self._x_I(self.G, ii)[0] * self._x_I(self.lamda, ii)[0] * J_N_I * large_scale_coupling # 8. I_syn = I_E(NMDA) + I_I(GABA) + I_AMPA_ext # Note measuring twice I_AMPA and I_NMDA though, as they count as a single excitatory current: state_variables[10, ii, _E] = numpy.sum(state_variables[13:, ii, 0], axis=0) state_variables[10, ii, _I] = numpy.sum(state_variables[13:, ii, _I[0]], axis=0) # 6. rate sigmoidal of total current = I_syn + I_o total_current = \ state_variables[10, ii, 0] + self._region(self.W_e, ii) * self._region(self.I_o, ii) # Sigmoidal activation: (a*I_tot_current - b) / ( 1 - exp(-d*(a*I_tot_current - b))) total_current = self._region( self.a_e, ii) * total_current - self._region(self.b_e, ii) state_variables[9, ii, _E] = \ total_current / (1 - numpy.exp(-self._region(self.d_e, ii) * total_current)) total_current = \ state_variables[10, ii, _I[0]] + self._region(self.W_i, ii) * self._region(self.I_o, ii) # Sigmoidal activation: total_current = self._region( self.a_i, ii) * total_current - self._region(self.b_i, ii) state_variables[9, ii, _I] = \ total_current / (1 - numpy.exp(-self._region(self.d_i, ii) * total_current)) return state_variables
def update_state_variables_before_integration(self, state_variables, coupling, local_coupling=0.0, stimulus=0.0): if self._n_regions == 0: self._n_regions = state_variables.shape[1] self._prepare_indices() for ii in range(self._n_regions): # For every region node.... _E = self._E(ii) # excitatory neurons' indices _I = self._I(ii) # inhibitory neurons' indices # Make sure that all empty positions are set to 0.0, if any: self._zero_empty_positions(state_variables, _E, _I, ii) # Set inhibitory synapses for excitatory neurons & excitatory synapses for inhibitory neurons to 0.0... self._zero_cross_synapses(state_variables, _E, _I, ii) # -----------------------------------Updates after previous iteration:-------------------------------------- # Refractory neurons from past spikes if 6. t_ref > 0.0 self._refractory_neurons_E[ii] = state_variables[6, ii, _E] > 0.0 self._refractory_neurons_I[ii] = state_variables[6, ii, _I] > 0.0 # set 5. V_m for refractory neurons to V_reset state_variables[5, ii, _E] = numpy.where(self._refractory_neurons_E[ii], self._x_E(self.V_reset, ii), state_variables[5, ii, _E]) state_variables[5, ii, _I] = numpy.where(self._refractory_neurons_I[ii], self._x_I(self.V_reset, ii), state_variables[5, ii, _I]) # Compute spikes sent at time t: # 8. spikes state_variables[8, ii, _E] = numpy.where( state_variables[5, ii, _E] > self._x_E(self.V_thr, ii), 1.0, 0.0) state_variables[8, ii, _I] = numpy.where( state_variables[5, ii, _I] > self._x_I(self.V_thr, ii), 1.0, 0.0) exc_spikes = state_variables[8, ii, _E] # excitatory spikes inh_spikes = state_variables[8, ii, _I] # inhibitory spikes self._spikes_E[ii] = exc_spikes > 0.0 self._spikes_I[ii] = inh_spikes > 0.0 # set 5. V_m for spiking neurons to V_reset state_variables[5, ii, _E] = numpy.where(self._spikes_E[ii], self._x_E(self.V_reset, ii), state_variables[5, ii, _E]) state_variables[5, ii, _I] = numpy.where(self._spikes_I[ii], self._x_I(self.V_reset, ii), state_variables[5, ii, _I]) # set 6. t_ref to tau_ref for spiking neurons state_variables[6, ii, _E] = numpy.where(self._spikes_E[ii], self._x_E(self.tau_ref_E, ii), state_variables[6, ii, _E]) state_variables[6, ii, _I] = numpy.where(self._spikes_I[ii], self._x_I(self.tau_ref_I, ii), state_variables[6, ii, _I]) # Refractory neurons including current spikes sent at time t self._refractory_neurons_E[ii] = numpy.logical_or( self._refractory_neurons_E[ii], self._spikes_E[ii]) self._refractory_neurons_I[ii] = numpy.logical_or( self._refractory_neurons_I[ii], self._spikes_I[ii]) # -------------------------------------Updates before next iteration:--------------------------------------- # ----------------------------------First deal with inputs at time t:--------------------------------------- # Collect external spikes received at time t, and update the incoming s_AMPA_ext synapse: # 7. spikes_ext # get external spike stimulus 7. spike_ext, if any: state_variables[7, ii, _E] = self._x_E(self.spikes_ext, ii) state_variables[7, ii, _I] = self._x_I(self.spikes_ext, ii) # 4. s_AMPA_ext # ds_AMPA_ext/dt = -1/tau_AMPA * (s_AMPA_exc + spikes_ext) # Add the spike at this point to s_AMPA_ext state_variables[4, ii, _E] += state_variables[7, ii, _E] # spikes_ext state_variables[4, ii, _I] += state_variables[7, ii, _I] # spikes_ext # Compute currents based on synaptic gating variables at time t: # V_E_E = V_m - V_E V_E_E = state_variables[5, ii, _E] - self._x_E(self.V_E, ii) V_E_I = state_variables[5, ii, _I] - self._x_I(self.V_E, ii) # 9. I_L = g_m * (V_m - V_E) state_variables[9, ii, _E] = \ self._x_E(self.g_m_E, ii) * (state_variables[5, ii, _E] - self._x_E(self.V_L, ii)) state_variables[9, ii, _I] = \ self._x_I(self.g_m_I, ii) * (state_variables[5, ii, _I] - self._x_I(self.V_L, ii)) w_EE = self._x_E(self.w_EE, ii) w_EI = self._x_E(self.w_EI, ii) # 10. I_AMPA = g_AMPA * (V_m - V_E) * sum(w * s_AMPA_k) coupling_AMPA_E, coupling_AMPA_I = \ self._compute_region_exc_population_coupling(state_variables[0, ii, _E], w_EE, w_EI) state_variables[10, ii, _E] = self._x_E( self.g_AMPA_E, ii) * V_E_E * coupling_AMPA_E # s_AMPA state_variables[10, ii, _I] = self._x_I( self.g_AMPA_I, ii) * V_E_I * coupling_AMPA_I # 11. I_NMDA = g_NMDA * (V_m - V_E) / (1 + lamda_NMDA * exp(-beta*V_m)) * sum(w * s_NMDA_k) coupling_NMDA_E, coupling_NMDA_I = \ self._compute_region_exc_population_coupling(state_variables[2, ii, _E], w_EE, w_EI) state_variables[11, ii, _E] = \ self._x_E(self.g_NMDA_E, ii) * V_E_E \ / (self._x_E(self.lamda_NMDA, ii) * numpy.exp(-self._x_E(self.beta, ii) * state_variables[5, ii, _E])) \ * coupling_NMDA_E # s_NMDA state_variables[11, ii, _I] = \ self._x_I(self.g_NMDA_I, ii) * V_E_I \ / (self._x_I(self.lamda_NMDA, ii) * numpy.exp(-self._x_I(self.beta, ii) * state_variables[5, ii, _I])) \ * coupling_NMDA_I # s_NMDA # 0. s_AMPA # s_AMPA += exc_spikes state_variables[0, ii, _E] += exc_spikes # 1. x_NMDA # x_NMDA += exc_spikes state_variables[1, ii, _E] += exc_spikes # 12. I_GABA = g_GABA * (V_m - V_I) * sum(w_ij * s_GABA_k) w_IE = self._x_I(self.w_IE, ii) w_II = self._x_I(self.w_II, ii) coupling_GABA_E, coupling_GABA_I = \ self._compute_region_inh_population_coupling(state_variables[3, ii, _I], w_IE, w_II) state_variables[12, ii, _E] = self._x_E(self.g_GABA_E, ii) * \ (state_variables[5, ii, _E] - self._x_E(self.V_I, ii)) * \ coupling_GABA_E # s_GABA state_variables[12, ii, _I] = self._x_I(self.g_GABA_I, ii) * \ (state_variables[5, ii, _I] - self._x_I(self.V_I, ii)) * \ coupling_GABA_I # s_GABA # 3. s_GABA += inh_spikes state_variables[3, ii, _I] += inh_spikes # 13. I_AMPA_ext = g_AMPA_ext * (V_m - V_E) * ( G*sum{c_ij sum{s_AMPA_j(t-delay_ij)}} + s_AMPA_ext) # Compute large scale coupling_ij = sum(c_ij * S_e(t-t_ij)) large_scale_coupling = numpy.sum(coupling[0, ii, :self._N_E_max]) large_scale_coupling += numpy.sum(local_coupling * state_variables[0, ii, _E]) state_variables[13, ii, _E] = self._x_E(self.g_AMPA_ext_E, ii) * V_E_E * \ ( self._x_E(self.G, ii) * large_scale_coupling + state_variables[4, ii, _E] ) # # feedforward inhibition state_variables[13, ii, _I] = self._x_I(self.g_AMPA_ext_I, ii) * V_E_I * \ ( self._x_I(self.G, ii) * self._x_I(self.lamda, ii) * large_scale_coupling + state_variables[4, ii, _I] ) self._non_integrated_variables = state_variables[ self._non_integrated_variables_inds] return state_variables
def update_state_variables_before_integration(self, state_variables, coupling, local_coupling=0.0, stimulus=0.0): self._stimulus = stimulus if self.use_numba: state_variables = \ _numba_update_non_state_variables_before_integration( state_variables.reshape(state_variables.shape[:-1]).T, coupling.reshape(coupling.shape[:-1]).T + local_coupling * state_variables[0], self.a_e, self.b_e, self.d_e, self.w_p, self.W_e, self.J_N, self.Rin_e, self.a_i, self.b_i, self.d_i, self.W_i, self.J_i, self.Rin_i, self.G, self.lamda, self.I_o, self.I_ext) return state_variables.T[..., numpy.newaxis] # In this case, rates (H_e, H_i) are non-state variables, # i.e., they form part of state_variables but have no dynamics assigned on them # Most of the computations of this dfun aim at computing rates, including coupling considerations. # Therefore, we compute and update them only once a new state is computed, # and we consider them constant for any subsequent possible call to this function, # by any integration scheme S = state_variables[:2, :] # synaptic gating dynamics R = state_variables[2:4, :] # Rates Rin = state_variables[4:6, :] # Input rates from spiking network c_0 = coupling[0, :] # if applicable lc_0 = local_coupling * S[0] coupling = self.G * self.J_N * (c_0 + lc_0) J_N_S_e = self.J_N * S[0] # TODO: Confirm that this computation is correct for this model depending on the r_e and r_i values! I_e = self.w_p * J_N_S_e - self.J_i * S[ 1] + self.W_e * self.I_o + coupling + self.I_ext x_e = self.a_e * I_e - self.b_e # Only rates with R_e <= 0 0 will be updated by TVB. R_e = numpy.where(self._Rin_e_mask, R[0], x_e / (1 - numpy.exp(-self.d_e * x_e))) # ...and their Rin_e should be zero: Rin_e = numpy.where(self._Rin_e_mask, Rin[0], 0.0) I_i = J_N_S_e - S[1] + self.W_i * self.I_o + self.lamda * coupling x_i = self.a_i * I_i - self.b_i # Only rates with R_i < 0 will be updated by TVB. R_i = numpy.where(self._Rin_i_mask, R[1], x_i / (1 - numpy.exp(-self.d_i * x_i))) # ...and their Rin_i should be zero: Rin_i = numpy.where(self._Rin_i_mask, Rin[1], 0.0) # We now update the state_variable vector with the new rates: state_variables[2, :] = R_e state_variables[3, :] = R_i state_variables[4, :] = Rin_e state_variables[5, :] = Rin_i state_variables[6, :] = I_e state_variables[7, :] = I_i # Keep them here so that they are not recomputed in the dfun self._Rin = numpy.copy(state_variables[4:6]) return state_variables